feat: 常驻通知+灵动岛自检(无需传输任务),设置页通知自检,enableFloat 修正
This commit is contained in:
@@ -13,8 +13,8 @@ android {
|
|||||||
applicationId = "com.smbfast.app"
|
applicationId = "com.smbfast.app"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 23
|
versionCode = 24
|
||||||
versionName = "1.19.2"
|
versionName = "1.20.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.smbfast.app
|
|||||||
import android.app.Application
|
import android.app.Application
|
||||||
import com.smbfast.app.smb.SmbClientPool
|
import com.smbfast.app.smb.SmbClientPool
|
||||||
import com.smbfast.app.transfer.TransferManager
|
import com.smbfast.app.transfer.TransferManager
|
||||||
|
import com.smbfast.app.transfer.TransferService
|
||||||
import com.smbfast.app.util.CrashLog
|
import com.smbfast.app.util.CrashLog
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||||
import java.security.Security
|
import java.security.Security
|
||||||
@@ -21,6 +22,10 @@ class App : Application() {
|
|||||||
Security.addProvider(BouncyCastleProvider())
|
Security.addProvider(BouncyCastleProvider())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 常驻前台通知:应用一开就显示(含灵动岛自检),无任务时保持"就绪",
|
||||||
|
// 不再要求必须有传输任务才能看到岛。后台进程被拉起时启动前台服务会被
|
||||||
|
// 系统拒绝,静默忽略即可(用户打开应用时自然会成功)。
|
||||||
|
runCatching { TransferService.startPersistent(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTerminate() {
|
override fun onTerminate() {
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ import org.json.JSONObject
|
|||||||
/**
|
/**
|
||||||
* 传输前台服务:应用退到后台时保活进程并持有 WiFi/CPU 锁,
|
* 传输前台服务:应用退到后台时保活进程并持有 WiFi/CPU 锁,
|
||||||
* 避免系统省电机制掐断 SMB 连接(SocketException: Software caused connection abort)。
|
* 避免系统省电机制掐断 SMB 连接(SocketException: Software caused connection abort)。
|
||||||
* 有任务时由 TransferManager 调用方 start(),全部结束(或取消)后自动 stopSelf()。
|
* 常驻模式(startPersistent,应用启动即拉起):无任务时显示"就绪"通知并保持服务,
|
||||||
|
* 用于常显灵动岛/通知自检;普通模式(start)全部任务结束后自动 stopSelf()。
|
||||||
*/
|
*/
|
||||||
class TransferService : Service() {
|
class TransferService : Service() {
|
||||||
|
|
||||||
@@ -43,24 +44,37 @@ class TransferService : Service() {
|
|||||||
private var lastNotify = 0L
|
private var lastNotify = 0L
|
||||||
private var firstIslandNotify = true
|
private var firstIslandNotify = true
|
||||||
|
|
||||||
|
/** 常驻模式:无任务时保留前台通知(灵动岛/通知自检用),不自动停服 */
|
||||||
|
@Volatile private var persistent = false
|
||||||
|
private var locksHeld = false
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
createChannel()
|
createChannel()
|
||||||
val type = if (Build.VERSION.SDK_INT >= 29) ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC else 0
|
val type = if (Build.VERSION.SDK_INT >= 29) ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC else 0
|
||||||
ServiceCompat.startForeground(this, NOTIF_ID, buildNotification(null), type)
|
val initial = App.transferManager.items.value.filter { it.status == Status.RUNNING }
|
||||||
|
ServiceCompat.startForeground(this, NOTIF_ID, buildNotification(initial.ifEmpty { null }), type)
|
||||||
acquireLocks()
|
acquireLocks()
|
||||||
val tm = App.transferManager
|
val tm = App.transferManager
|
||||||
scope.launch {
|
scope.launch {
|
||||||
tm.items.collect { items ->
|
tm.items.collect { items ->
|
||||||
val running = items.filter { it.status == Status.RUNNING }
|
val running = items.filter { it.status == Status.RUNNING }
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
if (running.isEmpty()) {
|
if (running.isEmpty()) {
|
||||||
firstIslandNotify = true
|
firstIslandNotify = true
|
||||||
releaseLocks()
|
releaseLocks()
|
||||||
stopSelf()
|
if (!persistent) {
|
||||||
|
stopSelf()
|
||||||
|
return@collect
|
||||||
|
}
|
||||||
|
if (now - lastNotify >= NOTIFY_INTERVAL_MS) {
|
||||||
|
lastNotify = now
|
||||||
|
notify(buildNotification(null))
|
||||||
|
}
|
||||||
return@collect
|
return@collect
|
||||||
}
|
}
|
||||||
|
acquireLocks()
|
||||||
// 限频刷新:高频 notify 会不停触发横幅/岛动画
|
// 限频刷新:高频 notify 会不停触发横幅/岛动画
|
||||||
val now = System.currentTimeMillis()
|
|
||||||
if (now - lastNotify >= NOTIFY_INTERVAL_MS) {
|
if (now - lastNotify >= NOTIFY_INTERVAL_MS) {
|
||||||
lastNotify = now
|
lastNotify = now
|
||||||
notify(buildNotification(running))
|
notify(buildNotification(running))
|
||||||
@@ -70,8 +84,14 @@ class TransferService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
if (intent?.action == ACTION_CANCEL_ALL) {
|
when (intent?.action) {
|
||||||
App.transferManager.cancelAllRunning()
|
ACTION_PERSISTENT -> {
|
||||||
|
persistent = true
|
||||||
|
// 用当前设置立即重发一条,便于开关岛后即时验证
|
||||||
|
val running = App.transferManager.items.value.filter { it.status == Status.RUNNING }
|
||||||
|
notify(buildNotification(running.ifEmpty { null }))
|
||||||
|
}
|
||||||
|
ACTION_CANCEL_ALL -> App.transferManager.cancelAllRunning()
|
||||||
}
|
}
|
||||||
return START_STICKY
|
return START_STICKY
|
||||||
}
|
}
|
||||||
@@ -107,13 +127,13 @@ class TransferService : Service() {
|
|||||||
val down = running?.count { it.direction == Direction.DOWNLOAD } ?: 0
|
val down = running?.count { it.direction == Direction.DOWNLOAD } ?: 0
|
||||||
val speed = running?.sumOf { it.speedBps } ?: 0L
|
val speed = running?.sumOf { it.speedBps } ?: 0L
|
||||||
val title = when {
|
val title = when {
|
||||||
running.isNullOrEmpty() -> "正在准备传输…"
|
running.isNullOrEmpty() -> "SMBFast 常驻服务"
|
||||||
up > 0 && down > 0 -> "后台传输中(↑$up ↓$down)"
|
up > 0 && down > 0 -> "后台传输中(↑$up ↓$down)"
|
||||||
up > 0 -> "后台上传中 ×$up"
|
up > 0 -> "后台上传中 ×$up"
|
||||||
else -> "后台下载中 ×$down"
|
else -> "后台下载中 ×$down"
|
||||||
}
|
}
|
||||||
val text = when {
|
val text = when {
|
||||||
running.isNullOrEmpty() -> "SMB 传输服务已就绪"
|
running.isNullOrEmpty() -> "灵动岛/通知自检 · 等待传输任务"
|
||||||
running.size == 1 -> "${running[0].name} · ${human(speed)}"
|
running.size == 1 -> "${running[0].name} · ${human(speed)}"
|
||||||
else -> "${running[0].name} 等 ${running.size} 个任务 · ${human(speed)}"
|
else -> "${running[0].name} 等 ${running.size} 个任务 · ${human(speed)}"
|
||||||
}
|
}
|
||||||
@@ -138,18 +158,19 @@ class TransferService : Service() {
|
|||||||
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
|
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
|
||||||
)
|
)
|
||||||
b.addAction(NotificationCompat.Action(android.R.drawable.ic_delete, "全部停止", stopIntent))
|
b.addAction(NotificationCompat.Action(android.R.drawable.ic_delete, "全部停止", stopIntent))
|
||||||
if (islandOn()) {
|
}
|
||||||
runCatching {
|
if (islandOn()) {
|
||||||
val extras = Bundle()
|
runCatching {
|
||||||
extras.putBundle("miui.focus.pics", islandPics())
|
val extras = Bundle()
|
||||||
b.addExtras(extras)
|
extras.putBundle("miui.focus.pics", islandPics())
|
||||||
}
|
b.addExtras(extras)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val n = b.build()
|
val n = b.build()
|
||||||
if (!running.isNullOrEmpty() && islandOn()) {
|
if (islandOn()) {
|
||||||
// 小米 HyperOS 焦点通知/超级岛:客户端本地上岛(官方 extras 协议)。
|
// 小米 HyperOS 焦点通知/超级岛:客户端本地上岛(官方 extras 协议)。
|
||||||
// 非小米系统会直接忽略该字段,不影响普通通知展示。
|
// 注意:HyperOS 对焦点通知有系统级白名单,侧载应用携带岛参数时可能被
|
||||||
|
// 系统整体过滤(岛和通知都不显示)——在设置里关岛开关即可恢复普通通知。
|
||||||
// islandFirstFloat 只在第一条通知为 true,否则每次更新都会重新弹出岛。
|
// islandFirstFloat 只在第一条通知为 true,否则每次更新都会重新弹出岛。
|
||||||
val first = firstIslandNotify
|
val first = firstIslandNotify
|
||||||
runCatching { n.extras.putString("miui.focus.param", islandParam(running, first)) }
|
runCatching { n.extras.putString("miui.focus.param", islandParam(running, first)) }
|
||||||
@@ -173,29 +194,34 @@ class TransferService : Service() {
|
|||||||
* 超级岛/焦点通知参数(miui.focus.param):
|
* 超级岛/焦点通知参数(miui.focus.param):
|
||||||
* - HyperOS 3 读 param_v2.param_island(屏幕顶部大/小岛)
|
* - HyperOS 3 读 param_v2.param_island(屏幕顶部大/小岛)
|
||||||
* - HyperOS 2 读 param.baseInfo(状态栏焦点)
|
* - HyperOS 2 读 param.baseInfo(状态栏焦点)
|
||||||
* 双轨根节点同时携带,由系统按版本自行取用。
|
* 空闲(无任务)时展示"就绪"岛,让常驻通知不传文件也能上岛。
|
||||||
* 每次更新同一通知 id + sequence 递增即可刷新岛内容。
|
* 每次更新同一通知 id + sequence 递增即可刷新岛内容。
|
||||||
*/
|
*/
|
||||||
private fun islandParam(running: List<TransferItem>, firstFloat: Boolean): String {
|
private fun islandParam(running: List<TransferItem>?, firstFloat: Boolean): String {
|
||||||
islandSequence += 1
|
islandSequence += 1
|
||||||
val up = running.count { it.direction == Direction.UPLOAD }
|
val idle = running.isNullOrEmpty()
|
||||||
val down = running.count { it.direction == Direction.DOWNLOAD }
|
val up = running?.count { it.direction == Direction.UPLOAD } ?: 0
|
||||||
val speed = running.sumOf { it.speedBps }
|
val down = running?.count { it.direction == Direction.DOWNLOAD } ?: 0
|
||||||
val total = running.sumOf { it.total }
|
val speed = running?.sumOf { it.speedBps } ?: 0L
|
||||||
val done = running.sumOf { it.done }
|
val total = running?.sumOf { it.total } ?: 0L
|
||||||
|
val done = running?.sumOf { it.done } ?: 0L
|
||||||
|
val size = running?.size ?: 0
|
||||||
val pct = if (total > 0) ((done.toDouble() / total).coerceIn(0.0, 1.0) * 100).toInt() else 0
|
val pct = if (total > 0) ((done.toDouble() / total).coerceIn(0.0, 1.0) * 100).toInt() else 0
|
||||||
val dirText = when {
|
val dirText = when {
|
||||||
|
idle -> "SMBFast"
|
||||||
up > 0 && down > 0 -> "SMB 传输中"
|
up > 0 && down > 0 -> "SMB 传输中"
|
||||||
up > 0 -> "SMB 上传中"
|
up > 0 -> "SMB 上传中"
|
||||||
else -> "SMB 下载中"
|
else -> "SMB 下载中"
|
||||||
}
|
}
|
||||||
val speedText = human(speed)
|
val speedText = human(speed)
|
||||||
val first = running.first().name
|
val islandTitle = if (idle) "就绪" else "$pct%"
|
||||||
|
val islandContent = if (idle) "后台就绪 · 等待任务" else "$speedText · $size 个任务"
|
||||||
|
val first = running?.firstOrNull()?.name ?: "SMBFast"
|
||||||
|
|
||||||
val textInfo = JSONObject()
|
val textInfo = JSONObject()
|
||||||
.put("frontTitle", dirText)
|
.put("frontTitle", dirText)
|
||||||
.put("title", "$pct%")
|
.put("title", islandTitle)
|
||||||
.put("content", "$speedText · ${running.size} 个任务")
|
.put("content", islandContent)
|
||||||
.put("useHighLight", false)
|
.put("useHighLight", false)
|
||||||
|
|
||||||
val picInfo = JSONObject().put("type", 1).put("pic", "miui.focus.pic_imageText")
|
val picInfo = JSONObject().put("type", 1).put("pic", "miui.focus.pic_imageText")
|
||||||
@@ -211,7 +237,7 @@ class TransferService : Service() {
|
|||||||
|
|
||||||
val baseInfo = JSONObject()
|
val baseInfo = JSONObject()
|
||||||
.put("title", dirText)
|
.put("title", dirText)
|
||||||
.put("content", "$first · $pct% · $speedText")
|
.put("content", if (idle) "后台就绪" else "$first · $pct% · $speedText")
|
||||||
.put("colorTitle", "#22D3EE")
|
.put("colorTitle", "#22D3EE")
|
||||||
.put("type", 2)
|
.put("type", 2)
|
||||||
|
|
||||||
@@ -219,11 +245,11 @@ class TransferService : Service() {
|
|||||||
.put("protocol", 1)
|
.put("protocol", 1)
|
||||||
.put("business", "smbfast_transfer")
|
.put("business", "smbfast_transfer")
|
||||||
.put("updatable", true)
|
.put("updatable", true)
|
||||||
.put("enableFloat", false) // 进度高频刷新,不自动展开,避免打扰
|
.put("enableFloat", true) // 启用浮动(胶囊/浮窗形态);false 会压住岛不展示
|
||||||
.put("islandFirstFloat", firstFloat) // 仅首条通知展开一次
|
.put("islandFirstFloat", firstFloat) // 仅首条通知展开一次
|
||||||
.put("sequence", islandSequence)
|
.put("sequence", islandSequence)
|
||||||
.put("ticker", "$dirText $pct% · $speedText")
|
.put("ticker", if (idle) "SMBFast 就绪" else "$dirText $pct% · $speedText")
|
||||||
.put("aodTitle", "$dirText $pct% · $speedText")
|
.put("aodTitle", if (idle) "SMBFast 就绪" else "$dirText $pct% · $speedText")
|
||||||
.put("tickerPic", "miui.focus.pic_ticker")
|
.put("tickerPic", "miui.focus.pic_ticker")
|
||||||
.put("aodPic", "miui.focus.pic_ticker")
|
.put("aodPic", "miui.focus.pic_ticker")
|
||||||
.put("param_island", paramIsland)
|
.put("param_island", paramIsland)
|
||||||
@@ -235,6 +261,8 @@ class TransferService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun acquireLocks() {
|
private fun acquireLocks() {
|
||||||
|
if (locksHeld) return
|
||||||
|
locksHeld = true
|
||||||
runCatching {
|
runCatching {
|
||||||
val pm = getSystemService(Context.POWER_SERVICE) as PowerManager
|
val pm = getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||||
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "smbfast:transfer").apply {
|
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "smbfast:transfer").apply {
|
||||||
@@ -254,6 +282,7 @@ class TransferService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun releaseLocks() {
|
private fun releaseLocks() {
|
||||||
|
locksHeld = false
|
||||||
runCatching { wakeLock?.release() }
|
runCatching { wakeLock?.release() }
|
||||||
wakeLock = null
|
wakeLock = null
|
||||||
runCatching { wifiLock?.release() }
|
runCatching { wifiLock?.release() }
|
||||||
@@ -277,10 +306,19 @@ class TransferService : Service() {
|
|||||||
private const val NOTIF_ID = 1001
|
private const val NOTIF_ID = 1001
|
||||||
private const val NOTIFY_INTERVAL_MS = 1500L
|
private const val NOTIFY_INTERVAL_MS = 1500L
|
||||||
const val ACTION_CANCEL_ALL = "com.smbfast.app.transfer.CANCEL_ALL"
|
const val ACTION_CANCEL_ALL = "com.smbfast.app.transfer.CANCEL_ALL"
|
||||||
|
const val ACTION_PERSISTENT = "com.smbfast.app.transfer.PERSISTENT"
|
||||||
|
|
||||||
/** 有任务入队时调用;须在应用处于前台时启动(前台服务启动限制) */
|
/** 有任务入队时调用;须在应用处于前台时启动(前台服务启动限制) */
|
||||||
fun start(ctx: Context) {
|
fun start(ctx: Context) {
|
||||||
ContextCompat.startForegroundService(ctx, Intent(ctx, TransferService::class.java))
|
ContextCompat.startForegroundService(ctx, Intent(ctx, TransferService::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 应用启动即拉起常驻前台通知(含灵动岛自检),无需有传输任务 */
|
||||||
|
fun startPersistent(ctx: Context) {
|
||||||
|
ContextCompat.startForegroundService(
|
||||||
|
ctx,
|
||||||
|
Intent(ctx, TransferService::class.java).setAction(ACTION_PERSISTENT),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ import java.io.File
|
|||||||
fun SettingsScreen(vm: AppViewModel) {
|
fun SettingsScreen(vm: AppViewModel) {
|
||||||
val s by vm.settings.collectAsStateWithLifecycle()
|
val s by vm.settings.collectAsStateWithLifecycle()
|
||||||
var showLog by remember { mutableStateOf(false) }
|
var showLog by remember { mutableStateOf(false) }
|
||||||
|
val ctx = LocalContext.current
|
||||||
|
|
||||||
AuroraBackground {
|
AuroraBackground {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
@@ -162,7 +163,9 @@ fun SettingsScreen(vm: AppViewModel) {
|
|||||||
icon = Icons.Default.Notifications,
|
icon = Icons.Default.Notifications,
|
||||||
brush = Neon.Primary,
|
brush = Neon.Primary,
|
||||||
title = "灵动岛 / 焦点通知",
|
title = "灵动岛 / 焦点通知",
|
||||||
subtitle = "传输时在小米 HyperOS 岛区域显示进度(其他品牌无影响)。若岛不出现或通知异常,可关闭后退回普通通知",
|
subtitle = "在小米 HyperOS 岛区域显示进度(其他品牌无影响)。注意:HyperOS 对焦点通知" +
|
||||||
|
"有系统级白名单,侧载应用带岛参数时可能被系统整体过滤(岛和通知都不显示)——" +
|
||||||
|
"遇到这种情况关闭本开关即可恢复普通通知",
|
||||||
) {
|
) {
|
||||||
Spacer(Modifier.height(6.dp))
|
Spacer(Modifier.height(6.dp))
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
@@ -170,6 +173,10 @@ fun SettingsScreen(vm: AppViewModel) {
|
|||||||
checked = s.islandOn,
|
checked = s.islandOn,
|
||||||
onCheckedChange = { checked ->
|
onCheckedChange = { checked ->
|
||||||
vm.updateSettings { it.copy(islandOn = checked) }
|
vm.updateSettings { it.copy(islandOn = checked) }
|
||||||
|
// 用新设置立即重发常驻通知,便于当场验证岛参数是否被系统过滤
|
||||||
|
runCatching {
|
||||||
|
com.smbfast.app.transfer.TransferService.startPersistent(ctx)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
colors = SwitchDefaults.colors(
|
colors = SwitchDefaults.colors(
|
||||||
checkedThumbColor = Color(0xFF04121E),
|
checkedThumbColor = Color(0xFF04121E),
|
||||||
@@ -186,6 +193,8 @@ fun SettingsScreen(vm: AppViewModel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NotificationDiagCard()
|
||||||
|
|
||||||
UpdateSection(vm = vm, currentName = currentVersionName(), currentCode = currentVersionCode())
|
UpdateSection(vm = vm, currentName = currentVersionName(), currentCode = currentVersionCode())
|
||||||
|
|
||||||
SectionCard(
|
SectionCard(
|
||||||
@@ -271,6 +280,60 @@ private fun currentVersionCode(): Long {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 通知系统自检:应用通知权限/通道被关是"通知和灵动岛全都不显示"的最常见原因 */
|
||||||
|
@Composable
|
||||||
|
private fun NotificationDiagCard() {
|
||||||
|
val ctx = LocalContext.current
|
||||||
|
val (enabled, hasChannel, importance) = remember {
|
||||||
|
val nm = androidx.core.app.NotificationManagerCompat.from(ctx)
|
||||||
|
val ch = nm.getNotificationChannel("smbfast_transfers")
|
||||||
|
Triple(nm.areNotificationsEnabled(), ch != null, ch?.importance ?: -1)
|
||||||
|
}
|
||||||
|
val impText = when {
|
||||||
|
!hasChannel -> "未创建"
|
||||||
|
importance == -1 -> "未创建"
|
||||||
|
importance == 0 -> "已屏蔽(不显示)"
|
||||||
|
importance == 1 -> "MIN(通知栏不显示)"
|
||||||
|
importance == 2 -> "LOW(静默显示在通知栏,无横幅)"
|
||||||
|
importance == 3 -> "DEFAULT"
|
||||||
|
else -> "HIGH(会弹横幅)"
|
||||||
|
}
|
||||||
|
SectionCard(
|
||||||
|
icon = Icons.Default.Notifications,
|
||||||
|
brush = Neon.File,
|
||||||
|
title = "通知系统自检",
|
||||||
|
subtitle = "系统通知权限:" + if (enabled) "已授予" else "已被关闭!通知与灵动岛都不会显示" +
|
||||||
|
"\n通知通道「传输进度」:" + impText,
|
||||||
|
) {
|
||||||
|
if (!enabled) {
|
||||||
|
Spacer(Modifier.height(8.dp))
|
||||||
|
MiniChip("去开启通知权限") {
|
||||||
|
runCatching {
|
||||||
|
ctx.startActivity(
|
||||||
|
android.content.Intent(
|
||||||
|
android.provider.Settings.ACTION_APP_NOTIFICATION_SETTINGS,
|
||||||
|
).putExtra(android.provider.Settings.EXTRA_APP_PACKAGE, ctx.packageName),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasChannel && importance == 0) {
|
||||||
|
Spacer(Modifier.height(8.dp))
|
||||||
|
MiniChip("去修复通知通道") {
|
||||||
|
runCatching {
|
||||||
|
ctx.startActivity(
|
||||||
|
android.content.Intent(
|
||||||
|
android.provider.Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS,
|
||||||
|
)
|
||||||
|
.putExtra(android.provider.Settings.EXTRA_APP_PACKAGE, ctx.packageName)
|
||||||
|
.putExtra(android.provider.Settings.EXTRA_CHANNEL_ID, "smbfast_transfers"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun currentVersionName(): String {
|
private fun currentVersionName(): String {
|
||||||
val ctx = LocalContext.current
|
val ctx = LocalContext.current
|
||||||
|
|||||||
Reference in New Issue
Block a user