Fix missing notification settings
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
package io.nekohasekai.sfa.compose.screen.settings
|
package io.nekohasekai.sfa.compose.screen.settings
|
||||||
|
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
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.Download
|
||||||
import androidx.compose.material.icons.outlined.Info
|
import androidx.compose.material.icons.outlined.Info
|
||||||
import androidx.compose.material.icons.outlined.NewReleases
|
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.Refresh
|
||||||
import androidx.compose.material.icons.outlined.Settings
|
import androidx.compose.material.icons.outlined.Settings
|
||||||
|
import androidx.compose.material.icons.outlined.Speed
|
||||||
import androidx.compose.material.icons.outlined.SystemUpdateAlt
|
import androidx.compose.material.icons.outlined.SystemUpdateAlt
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Badge
|
import androidx.compose.material3.Badge
|
||||||
@@ -62,6 +66,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.compose.LifecycleEventEffect
|
import androidx.lifecycle.compose.LifecycleEventEffect
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
|
import io.nekohasekai.sfa.Application
|
||||||
import io.nekohasekai.sfa.BuildConfig
|
import io.nekohasekai.sfa.BuildConfig
|
||||||
import io.nekohasekai.sfa.R
|
import io.nekohasekai.sfa.R
|
||||||
import io.nekohasekai.sfa.compose.component.UpdateAvailableDialog
|
import io.nekohasekai.sfa.compose.component.UpdateAvailableDialog
|
||||||
@@ -121,13 +126,30 @@ fun AppSettingsScreen(navController: NavController) {
|
|||||||
var downloadError by remember { mutableStateOf<String?>(null) }
|
var downloadError by remember { mutableStateOf<String?>(null) }
|
||||||
var showUpdateAvailableDialog by remember { mutableStateOf(false) }
|
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) {
|
LaunchedEffect(Unit) {
|
||||||
HookStatusClient.refresh()
|
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) {
|
LifecycleEventEffect(Lifecycle.Event.ON_RESUME) {
|
||||||
HookStatusClient.refresh()
|
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) {
|
if (silentInstallEnabled) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
val success = withContext(Dispatchers.IO) {
|
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) {
|
if (showUpdateAvailableDialog && updateInfo != null) {
|
||||||
UpdateAvailableDialog(
|
UpdateAvailableDialog(
|
||||||
updateInfo = updateInfo!!,
|
updateInfo = updateInfo!!,
|
||||||
@@ -319,6 +386,91 @@ fun AppSettingsScreen(navController: NavController) {
|
|||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
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(
|
||||||
text = stringResource(R.string.update_settings),
|
text = stringResource(R.string.update_settings),
|
||||||
style = MaterialTheme.typography.labelLarge,
|
style = MaterialTheme.typography.labelLarge,
|
||||||
|
|||||||
@@ -199,6 +199,11 @@
|
|||||||
<string name="disable_deprecated_warnings">غیرفعالکردن هشدارهای منسوخ</string>
|
<string name="disable_deprecated_warnings">غیرفعالکردن هشدارهای منسوخ</string>
|
||||||
<string name="ignore_memory_limit">نادیده گرفتن محدودیت حافظه</string>
|
<string name="ignore_memory_limit">نادیده گرفتن محدودیت حافظه</string>
|
||||||
<string name="ignore_memory_limit_description">محدودیت حافظه روی sing-box اعمال نشود.</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">تغییر مسیر خودکار</string>
|
||||||
<string name="auto_redirect_description">نیازمند دسترسی ROOT</string>
|
<string name="auto_redirect_description">نیازمند دسترسی ROOT</string>
|
||||||
<string name="system_http_proxy">پراکسی HTTP سیستم</string>
|
<string name="system_http_proxy">پراکسی HTTP سیستم</string>
|
||||||
|
|||||||
@@ -199,6 +199,11 @@
|
|||||||
<string name="disable_deprecated_warnings">Отключить предупреждения об устаревании</string>
|
<string name="disable_deprecated_warnings">Отключить предупреждения об устаревании</string>
|
||||||
<string name="ignore_memory_limit">Игнорировать ограничение памяти</string>
|
<string name="ignore_memory_limit">Игнорировать ограничение памяти</string>
|
||||||
<string name="ignore_memory_limit_description">Не применять ограничения по памяти для sing-box.</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">Автоматическое перенаправление</string>
|
||||||
<string name="auto_redirect_description">Требуются права ROOT</string>
|
<string name="auto_redirect_description">Требуются права ROOT</string>
|
||||||
<string name="system_http_proxy">Системный HTTP-прокси</string>
|
<string name="system_http_proxy">Системный HTTP-прокси</string>
|
||||||
|
|||||||
@@ -199,6 +199,11 @@
|
|||||||
<string name="disable_deprecated_warnings">禁用弃用警告</string>
|
<string name="disable_deprecated_warnings">禁用弃用警告</string>
|
||||||
<string name="ignore_memory_limit">忽略内存限制</string>
|
<string name="ignore_memory_limit">忽略内存限制</string>
|
||||||
<string name="ignore_memory_limit_description">不对 sing-box 强制执行内存限制。</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">自动重定向</string>
|
||||||
<string name="auto_redirect_description">需要 ROOT 权限</string>
|
<string name="auto_redirect_description">需要 ROOT 权限</string>
|
||||||
<string name="system_http_proxy">系统 HTTP 代理</string>
|
<string name="system_http_proxy">系统 HTTP 代理</string>
|
||||||
|
|||||||
@@ -199,6 +199,11 @@
|
|||||||
<string name="disable_deprecated_warnings">停用過時警告</string>
|
<string name="disable_deprecated_warnings">停用過時警告</string>
|
||||||
<string name="ignore_memory_limit">忽略記憶體限制</string>
|
<string name="ignore_memory_limit">忽略記憶體限制</string>
|
||||||
<string name="ignore_memory_limit_description">不對 sing-box 強制執行記憶體限制。</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">自動重定向</string>
|
||||||
<string name="auto_redirect_description">需要 ROOT 權限</string>
|
<string name="auto_redirect_description">需要 ROOT 權限</string>
|
||||||
<string name="system_http_proxy">系統 HTTP 代理</string>
|
<string name="system_http_proxy">系統 HTTP 代理</string>
|
||||||
|
|||||||
@@ -199,6 +199,11 @@
|
|||||||
<string name="disable_deprecated_warnings">Disable Deprecated Warnings</string>
|
<string name="disable_deprecated_warnings">Disable Deprecated Warnings</string>
|
||||||
<string name="ignore_memory_limit">Ignore Memory Limit</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="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">Auto Redirect</string>
|
||||||
<string name="auto_redirect_description">ROOT permission required</string>
|
<string name="auto_redirect_description">ROOT permission required</string>
|
||||||
<string name="system_http_proxy">System HTTP Proxy</string>
|
<string name="system_http_proxy">System HTTP Proxy</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user