Fix missing notification settings
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package io.nekohasekai.sfa.compose.screen.settings
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
@@ -25,8 +27,10 @@ import androidx.compose.material.icons.outlined.Autorenew
|
||||
import androidx.compose.material.icons.outlined.Download
|
||||
import androidx.compose.material.icons.outlined.Info
|
||||
import androidx.compose.material.icons.outlined.NewReleases
|
||||
import androidx.compose.material.icons.outlined.Notifications
|
||||
import androidx.compose.material.icons.outlined.Refresh
|
||||
import androidx.compose.material.icons.outlined.Settings
|
||||
import androidx.compose.material.icons.outlined.Speed
|
||||
import androidx.compose.material.icons.outlined.SystemUpdateAlt
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Badge
|
||||
@@ -62,6 +66,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.compose.LifecycleEventEffect
|
||||
import androidx.navigation.NavController
|
||||
import io.nekohasekai.sfa.Application
|
||||
import io.nekohasekai.sfa.BuildConfig
|
||||
import io.nekohasekai.sfa.R
|
||||
import io.nekohasekai.sfa.compose.component.UpdateAvailableDialog
|
||||
@@ -121,13 +126,30 @@ fun AppSettingsScreen(navController: NavController) {
|
||||
var downloadError by remember { mutableStateOf<String?>(null) }
|
||||
var showUpdateAvailableDialog by remember { mutableStateOf(false) }
|
||||
|
||||
var notificationEnabled by remember { mutableStateOf(true) }
|
||||
var dynamicNotification by remember { mutableStateOf(Settings.dynamicNotification) }
|
||||
var showDisableNotificationDialog by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
HookStatusClient.refresh()
|
||||
}
|
||||
|
||||
// Re-check method availability when returning from background (e.g., after granting permission)
|
||||
// Re-check states when returning from background (e.g., after granting permission)
|
||||
LifecycleEventEffect(Lifecycle.Event.ON_RESUME) {
|
||||
HookStatusClient.refresh()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
Application.notification.createNotificationChannel(
|
||||
NotificationChannel(
|
||||
"service",
|
||||
"Service Notifications",
|
||||
NotificationManager.IMPORTANCE_LOW,
|
||||
),
|
||||
)
|
||||
val channel = Application.notification.getNotificationChannel("service")
|
||||
notificationEnabled = channel?.importance != NotificationManager.IMPORTANCE_NONE
|
||||
} else {
|
||||
notificationEnabled = Application.notification.areNotificationsEnabled()
|
||||
}
|
||||
if (silentInstallEnabled) {
|
||||
scope.launch {
|
||||
val success = withContext(Dispatchers.IO) {
|
||||
@@ -239,6 +261,51 @@ fun AppSettingsScreen(navController: NavController) {
|
||||
)
|
||||
}
|
||||
|
||||
if (showDisableNotificationDialog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showDisableNotificationDialog = false },
|
||||
title = { Text(stringResource(R.string.enable_notification)) },
|
||||
text = {
|
||||
Text(
|
||||
stringResource(
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
R.string.disable_notification_description
|
||||
} else {
|
||||
R.string.disable_notification_description_legacy
|
||||
},
|
||||
),
|
||||
)
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = {
|
||||
showDisableNotificationDialog = false
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startActivity(
|
||||
Intent(AndroidSettings.ACTION_CHANNEL_NOTIFICATION_SETTINGS).apply {
|
||||
putExtra(AndroidSettings.EXTRA_APP_PACKAGE, context.packageName)
|
||||
putExtra(AndroidSettings.EXTRA_CHANNEL_ID, "service")
|
||||
},
|
||||
)
|
||||
} else {
|
||||
context.startActivity(
|
||||
Intent(
|
||||
AndroidSettings.ACTION_APPLICATION_DETAILS_SETTINGS,
|
||||
Uri.parse("package:${context.packageName}"),
|
||||
),
|
||||
)
|
||||
}
|
||||
}) {
|
||||
Text(stringResource(R.string.ok))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { showDisableNotificationDialog = false }) {
|
||||
Text(stringResource(android.R.string.cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if (showUpdateAvailableDialog && updateInfo != null) {
|
||||
UpdateAvailableDialog(
|
||||
updateInfo = updateInfo!!,
|
||||
@@ -319,6 +386,91 @@ fun AppSettingsScreen(navController: NavController) {
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.notification_settings),
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.padding(horizontal = 32.dp, vertical = 8.dp),
|
||||
)
|
||||
|
||||
Card(
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
colors =
|
||||
CardDefaults.cardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceContainer,
|
||||
),
|
||||
) {
|
||||
Column {
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
stringResource(R.string.enable_notification),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
)
|
||||
},
|
||||
leadingContent = {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Notifications,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
},
|
||||
trailingContent = {
|
||||
Switch(
|
||||
checked = notificationEnabled,
|
||||
onCheckedChange = null,
|
||||
)
|
||||
},
|
||||
modifier =
|
||||
Modifier
|
||||
.clip(RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp))
|
||||
.clickable { showDisableNotificationDialog = true },
|
||||
colors =
|
||||
ListItemDefaults.colors(
|
||||
containerColor = Color.Transparent,
|
||||
),
|
||||
)
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
stringResource(R.string.dynamic_notification),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
)
|
||||
},
|
||||
leadingContent = {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Speed,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
},
|
||||
trailingContent = {
|
||||
Switch(
|
||||
checked = dynamicNotification,
|
||||
onCheckedChange = { checked ->
|
||||
dynamicNotification = checked
|
||||
scope.launch(Dispatchers.IO) {
|
||||
Settings.dynamicNotification = checked
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
modifier =
|
||||
Modifier
|
||||
.clip(RoundedCornerShape(bottomStart = 12.dp, bottomEnd = 12.dp)),
|
||||
colors =
|
||||
ListItemDefaults.colors(
|
||||
containerColor = Color.Transparent,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.update_settings),
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
|
||||
@@ -199,6 +199,11 @@
|
||||
<string name="disable_deprecated_warnings">غیرفعالکردن هشدارهای منسوخ</string>
|
||||
<string name="ignore_memory_limit">نادیده گرفتن محدودیت حافظه</string>
|
||||
<string name="ignore_memory_limit_description">محدودیت حافظه روی sing-box اعمال نشود.</string>
|
||||
<string name="notification_settings">اعلانها</string>
|
||||
<string name="enable_notification">فعالکردن اعلان</string>
|
||||
<string name="dynamic_notification">نمایش سرعت بلادرنگ در اعلان</string>
|
||||
<string name="disable_notification_description">به دلیل محدودیتهای اندروید، ابتدا باید مجوز اعلان را بدهید، سپس دستهبندی اعلان را در تنظیمات غیرفعال کنید.</string>
|
||||
<string name="disable_notification_description_legacy">به دلیل محدودیتهای اندروید، ابتدا باید مجوز اعلان را بدهید، سپس اعلانها را در اطلاعات برنامه غیرفعال کنید.</string>
|
||||
<string name="auto_redirect">تغییر مسیر خودکار</string>
|
||||
<string name="auto_redirect_description">نیازمند دسترسی ROOT</string>
|
||||
<string name="system_http_proxy">پراکسی HTTP سیستم</string>
|
||||
|
||||
@@ -199,6 +199,11 @@
|
||||
<string name="disable_deprecated_warnings">Отключить предупреждения об устаревании</string>
|
||||
<string name="ignore_memory_limit">Игнорировать ограничение памяти</string>
|
||||
<string name="ignore_memory_limit_description">Не применять ограничения по памяти для sing-box.</string>
|
||||
<string name="notification_settings">Уведомления</string>
|
||||
<string name="enable_notification">Включить уведомления</string>
|
||||
<string name="dynamic_notification">Отображать скорость в реальном времени в уведомлении</string>
|
||||
<string name="disable_notification_description">Из-за ограничений Android необходимо сначала предоставить разрешение на уведомления, а затем отключить категорию уведомлений в настройках.</string>
|
||||
<string name="disable_notification_description_legacy">Из-за ограничений Android необходимо сначала предоставить разрешение на уведомления, а затем отключить уведомления в сведениях о приложении.</string>
|
||||
<string name="auto_redirect">Автоматическое перенаправление</string>
|
||||
<string name="auto_redirect_description">Требуются права ROOT</string>
|
||||
<string name="system_http_proxy">Системный HTTP-прокси</string>
|
||||
|
||||
@@ -199,6 +199,11 @@
|
||||
<string name="disable_deprecated_warnings">禁用弃用警告</string>
|
||||
<string name="ignore_memory_limit">忽略内存限制</string>
|
||||
<string name="ignore_memory_limit_description">不对 sing-box 强制执行内存限制。</string>
|
||||
<string name="notification_settings">通知</string>
|
||||
<string name="enable_notification">启用通知</string>
|
||||
<string name="dynamic_notification">在通知中显示实时网速</string>
|
||||
<string name="disable_notification_description">由于 Android 限制,您需要先授权通知权限,然后前往系统设置中关闭通知类别。</string>
|
||||
<string name="disable_notification_description_legacy">由于 Android 限制,您需要先授权通知权限,然后前往应用信息中关闭通知。</string>
|
||||
<string name="auto_redirect">自动重定向</string>
|
||||
<string name="auto_redirect_description">需要 ROOT 权限</string>
|
||||
<string name="system_http_proxy">系统 HTTP 代理</string>
|
||||
|
||||
@@ -199,6 +199,11 @@
|
||||
<string name="disable_deprecated_warnings">停用過時警告</string>
|
||||
<string name="ignore_memory_limit">忽略記憶體限制</string>
|
||||
<string name="ignore_memory_limit_description">不對 sing-box 強制執行記憶體限制。</string>
|
||||
<string name="notification_settings">通知</string>
|
||||
<string name="enable_notification">啟用通知</string>
|
||||
<string name="dynamic_notification">在通知中顯示即時網速</string>
|
||||
<string name="disable_notification_description">由於 Android 限制,您需要先授權通知權限,然後前往系統設定中關閉通知類別。</string>
|
||||
<string name="disable_notification_description_legacy">由於 Android 限制,您需要先授權通知權限,然後前往應用程式資訊中關閉通知。</string>
|
||||
<string name="auto_redirect">自動重定向</string>
|
||||
<string name="auto_redirect_description">需要 ROOT 權限</string>
|
||||
<string name="system_http_proxy">系統 HTTP 代理</string>
|
||||
|
||||
@@ -199,6 +199,11 @@
|
||||
<string name="disable_deprecated_warnings">Disable Deprecated Warnings</string>
|
||||
<string name="ignore_memory_limit">Ignore Memory Limit</string>
|
||||
<string name="ignore_memory_limit_description">Do not enforce memory limits on sing-box.</string>
|
||||
<string name="notification_settings">Notification</string>
|
||||
<string name="enable_notification">Enable Notification</string>
|
||||
<string name="dynamic_notification">Display realtime speed in notification</string>
|
||||
<string name="disable_notification_description">Due to Android restrictions, you must first grant notification permission, then go to Settings to disable the notification category.</string>
|
||||
<string name="disable_notification_description_legacy">Due to Android restrictions, you must first grant notification permission, then go to App Info to disable notifications.</string>
|
||||
<string name="auto_redirect">Auto Redirect</string>
|
||||
<string name="auto_redirect_description">ROOT permission required</string>
|
||||
<string name="system_http_proxy">System HTTP Proxy</string>
|
||||
|
||||
Reference in New Issue
Block a user