更新
This commit is contained in:
@@ -215,9 +215,9 @@
|
||||
<string name="setting_privacy_rate">应用评价</string>
|
||||
<string name="setting_privacy_rate_desc">如果喜欢,欢迎在商店留下五星好评</string>
|
||||
<string name="setting_about_app">关于应用</string>
|
||||
<string name="app_version_code">100001</string>
|
||||
<string name="app_version_name">1.0.1</string>
|
||||
<string name="setting_about_app_desc">版本 1.0.1</string>
|
||||
<string name="app_version_code">100002</string>
|
||||
<string name="app_version_name">1.0.2</string>
|
||||
<string name="setting_about_app_desc">版本 1.0.2</string>
|
||||
|
||||
<!-- 反馈与帮助 -->
|
||||
<string name="title_feedback">意见反馈</string>
|
||||
|
||||
@@ -216,9 +216,9 @@
|
||||
<string name="setting_privacy_rate">App Review</string>
|
||||
<string name="setting_privacy_rate_desc">If you like it, please leave a five-star review in the store</string>
|
||||
<string name="setting_about_app">About the App</string>
|
||||
<string name="app_version_code">100001</string>
|
||||
<string name="app_version_name">1.0.1</string>
|
||||
<string name="setting_about_app_desc">Version 1.0.1</string>
|
||||
<string name="app_version_code">100002</string>
|
||||
<string name="app_version_name">1.0.2</string>
|
||||
<string name="setting_about_app_desc">Version 1.0.2</string>
|
||||
|
||||
<!-- Feedback & Help -->
|
||||
<string name="title_feedback">Feedback</string>
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.taskttl.core.analytics
|
||||
|
||||
/**
|
||||
* Facebook 标准事件定义(官方事件名 + 必填字段)
|
||||
* https://developers.facebook.com/docs/app-events/reference
|
||||
*/
|
||||
sealed class FacebookEvent(
|
||||
val eventName: String,
|
||||
val requiredKeys: List<String> = emptyList(),
|
||||
) {
|
||||
/**
|
||||
* 参数
|
||||
* @return [Map<String, Any?>]
|
||||
*/
|
||||
abstract fun params(): Map<String, Any?>
|
||||
|
||||
data class Login(
|
||||
val method: String? = null
|
||||
) : FacebookEvent("fb_mobile_login", listOf("method")) {
|
||||
override fun params() = mapOf("method" to method)
|
||||
}
|
||||
|
||||
// 内容类 / 电商类
|
||||
data class ViewContent(
|
||||
val contentId: String,
|
||||
val contentType: String? = null,
|
||||
val value: Double? = null,
|
||||
val currency: String? = null
|
||||
) : FacebookEvent("fb_mobile_content_view", listOf("content_id")) {
|
||||
override fun params() = mapOf(
|
||||
"content_id" to contentId,
|
||||
"content_type" to contentType,
|
||||
"value" to value,
|
||||
"currency" to currency
|
||||
)
|
||||
}
|
||||
|
||||
// 游戏 / 广告类
|
||||
data class AchieveLevel(val level: Int) :
|
||||
FacebookEvent("fb_mobile_level_achieved", listOf("level")) {
|
||||
override fun params() = mapOf("level" to level)
|
||||
}
|
||||
|
||||
/**
|
||||
* 广告次数
|
||||
* @author admin
|
||||
* @date 2025/10/19
|
||||
* @constructor 创建[AdImpression]
|
||||
* @param [adPlatform] 广告平台 如 "AdMob", "ironSource", "AppLovin" 等
|
||||
* @param [adSource] 广告来源或网络,如 "admob_banner", "admob_interstitial"
|
||||
* @param [adFormat] 广告类型,如 "banner", "interstitial", "rewarded_video"
|
||||
* @param [adPlacementId] 广告位 ID
|
||||
* @param [value] 收益金额
|
||||
* @param [currency] 收益货币(ISO 代码,如 "USD")
|
||||
* @param [placement] 自定义广告位名称
|
||||
*/
|
||||
data class AdImpression(
|
||||
val adPlatform: String,
|
||||
val adSource: String,
|
||||
val adFormat: String,
|
||||
val adPlacementId: String,
|
||||
val currency: String,
|
||||
val value: Double,
|
||||
val placement: String? = null
|
||||
) : FacebookEvent(
|
||||
"ad_impression",
|
||||
listOf("ad_platform", "ad_format", "ad_placement_id", "currency", "value")
|
||||
) {
|
||||
override fun params() = mapOf(
|
||||
"ad_platform" to adPlatform,
|
||||
"ad_source" to adSource,
|
||||
"ad_format" to adFormat,
|
||||
"ad_placement_id" to adPlacementId,
|
||||
"currency" to currency,
|
||||
"value" to value,
|
||||
"placement" to placement
|
||||
)
|
||||
}
|
||||
|
||||
data class AddToCart(
|
||||
val contentId: String,
|
||||
val value: Double,
|
||||
val currency: String
|
||||
) : FacebookEvent("fb_mobile_add_to_cart", listOf("content_id", "value", "currency")) {
|
||||
override fun params() = mapOf(
|
||||
"content_id" to contentId,
|
||||
"value" to value,
|
||||
"currency" to currency
|
||||
)
|
||||
}
|
||||
|
||||
data class Purchase(
|
||||
val value: Double,
|
||||
val currency: String,
|
||||
val contentId: String? = null
|
||||
) : FacebookEvent("fb_mobile_purchase", listOf("value", "currency")) {
|
||||
override fun params() = mapOf(
|
||||
"value" to value,
|
||||
"currency" to currency,
|
||||
"content_id" to contentId
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 订阅 / 试用类
|
||||
* @author admin
|
||||
* @date 2025/10/19
|
||||
* @constructor 创建[StartTrial]
|
||||
* @param [trialName] 试验名称
|
||||
*/
|
||||
data class StartTrial(val trialName: String? = null) :
|
||||
FacebookEvent("start_trial") {
|
||||
override fun params() = mapOf("trial_name" to trialName)
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅
|
||||
* @author admin
|
||||
* @date 2025/10/19
|
||||
* @constructor 创建[Subscribe]
|
||||
* @param [plan] 计划
|
||||
*/
|
||||
data class Subscribe(val plan: String? = null) :
|
||||
FacebookEvent("subscribe") {
|
||||
override fun params() = mapOf("plan" to plan)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.taskttl.core.analytics
|
||||
|
||||
/**
|
||||
* 统一事件接口
|
||||
*/
|
||||
expect object FacebookEventTracker {
|
||||
fun logEvent(event: FacebookEvent, params: Map<String, Any?> = emptyMap())
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.taskttl.core.analytics
|
||||
|
||||
/**
|
||||
* facebook事件验证器
|
||||
* @author admin
|
||||
* @date 2025/10/19
|
||||
*/
|
||||
object FacebookEventValidator {
|
||||
|
||||
/**
|
||||
* 验证
|
||||
* @param [event] 事件
|
||||
* @return [String?]
|
||||
*/
|
||||
fun validate(event: FacebookEvent): String? {
|
||||
val params = event.params()
|
||||
val missing = event.requiredKeys.filter { key ->
|
||||
val v = params[key]
|
||||
v == null || (v is String && v.isBlank())
|
||||
}
|
||||
return if (missing.isNotEmpty()) {
|
||||
"⚠️ Missing required fields for ${event.eventName}: ${missing.joinToString()}"
|
||||
} else null
|
||||
}
|
||||
}
|
||||
@@ -81,4 +81,12 @@ object DateUtils {
|
||||
CountdownTime(days, hours, minutes, seconds, isExpired = false)
|
||||
}
|
||||
}
|
||||
|
||||
fun LocalDateTime.toEpochMillis(): Long {
|
||||
return this.toInstant(TimeZone.currentSystemDefault()).toEpochMilliseconds()
|
||||
}
|
||||
|
||||
fun Long.toLocalDateTime(): LocalDateTime {
|
||||
return Instant.fromEpochMilliseconds(this).toLocalDateTime(TimeZone.currentSystemDefault())
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.taskttl.data.di
|
||||
|
||||
import com.taskttl.core.notification.NotificationManager
|
||||
import com.taskttl.data.repository.OnboardingRepository
|
||||
import com.taskttl.data.repository.SettingsRepository
|
||||
import com.taskttl.data.repository.impl.OnboardingRepositoryImpl
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.taskttl.data.state
|
||||
|
||||
import com.taskttl.core.notification.NotificationPermissionManager
|
||||
import com.taskttl.core.viewmodel.BaseUiState
|
||||
|
||||
/**
|
||||
@@ -14,6 +15,7 @@ data class SettingsState(
|
||||
override val isLoading: Boolean = false,
|
||||
override val isProcessing: Boolean = false,
|
||||
override val error: String? = null,
|
||||
val isNotification: Boolean = NotificationPermissionManager.verifyPermission(),
|
||||
) : BaseUiState()
|
||||
|
||||
/**
|
||||
@@ -38,6 +40,17 @@ sealed class SettingsIntent {
|
||||
* @param [url] 网址
|
||||
*/
|
||||
class OpenUrl(val url: String) : SettingsIntent()
|
||||
|
||||
object RequestPermission : SettingsIntent()
|
||||
|
||||
/**
|
||||
* 更新通知状态
|
||||
* @author DevTTL
|
||||
* @date 2025/10/17
|
||||
* @constructor 创建[UpdateNotificationStatus]
|
||||
* @param [status] 状态
|
||||
*/
|
||||
class UpdateNotificationStatus(val status: Boolean) : SettingsIntent()
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ data class TaskState(
|
||||
* @constructor 创建[TaskIntent]
|
||||
*/
|
||||
sealed class TaskIntent {
|
||||
|
||||
/**
|
||||
* 加载任务
|
||||
* @author admin
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package com.taskttl.data.viewmodel
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.taskttl.core.notification.NotificationManager
|
||||
import com.taskttl.core.notification.NotificationPayload
|
||||
import com.taskttl.core.notification.NotificationRepeatType
|
||||
import com.taskttl.core.utils.DateUtils.toEpochMillis
|
||||
import com.taskttl.core.viewmodel.BaseViewModel
|
||||
import com.taskttl.data.local.model.Category
|
||||
import com.taskttl.data.local.model.CategoryType
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package com.taskttl.data.viewmodel
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.taskttl.core.notification.NotificationPermissionCallback
|
||||
import com.taskttl.core.notification.NotificationPermissionManager
|
||||
import com.taskttl.core.utils.ExternalAppLauncher
|
||||
import com.taskttl.core.utils.LogUtils
|
||||
import com.taskttl.core.viewmodel.BaseViewModel
|
||||
import com.taskttl.data.state.SettingsEffect
|
||||
import com.taskttl.data.state.SettingsIntent
|
||||
@@ -22,6 +25,8 @@ class SettingsViewModel() :
|
||||
when (intent) {
|
||||
is SettingsIntent.OpenAppRating -> openAppRating()
|
||||
is SettingsIntent.OpenUrl -> openUrl(intent.url)
|
||||
is SettingsIntent.RequestPermission -> requestPermission()
|
||||
is SettingsIntent.UpdateNotificationStatus -> updateNotificationStatus(intent.status)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +42,25 @@ class SettingsViewModel() :
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestPermission() {
|
||||
viewModelScope.launch {
|
||||
if (NotificationPermissionManager.verifyPermission()) {
|
||||
NotificationPermissionManager.disablePermission()
|
||||
} else {
|
||||
NotificationPermissionManager.requestPermission(
|
||||
object : NotificationPermissionCallback {
|
||||
override fun onGranted() = updateState { copy(isNotification = true) }
|
||||
override fun onDenied() = LogUtils.e("DevTTL", "❌ Android 通知权限被拒绝")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateNotificationStatus(status: Boolean) {
|
||||
updateState { copy(isNotification = status) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除错误
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package com.taskttl.data.viewmodel
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.taskttl.core.utils.LogUtils
|
||||
import com.taskttl.core.notification.NotificationManager
|
||||
import com.taskttl.core.notification.NotificationPayload
|
||||
import com.taskttl.core.notification.NotificationRepeatType
|
||||
import com.taskttl.core.utils.DateUtils.toEpochMillis
|
||||
import com.taskttl.core.viewmodel.BaseViewModel
|
||||
import com.taskttl.data.local.model.Category
|
||||
import com.taskttl.data.local.model.CategoryType
|
||||
@@ -24,6 +27,8 @@ import taskttl.composeapp.generated.resources.task_status_update_failed
|
||||
import taskttl.composeapp.generated.resources.task_status_update_success
|
||||
import taskttl.composeapp.generated.resources.task_update_failed
|
||||
import taskttl.composeapp.generated.resources.task_update_success
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.ExperimentalTime
|
||||
|
||||
/**
|
||||
* 任务视图模型
|
||||
@@ -87,10 +92,7 @@ class TaskViewModel(
|
||||
try {
|
||||
launch {
|
||||
categoryRepository.getCategoriesByType(CategoryType.TASK)
|
||||
.collect { categories ->
|
||||
LogUtils.e("DevTTL", categories.toString())
|
||||
updateState { copy(categories = categories) }
|
||||
}
|
||||
.collect { categories -> updateState { copy(categories = categories) } }
|
||||
}
|
||||
launch {
|
||||
taskRepository.getAllTasks().collect { tasks ->
|
||||
@@ -104,7 +106,6 @@ class TaskViewModel(
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
LogUtils.e("DevTTL", e.message.toString())
|
||||
val errStr = getString(Res.string.task_load_failed)
|
||||
updateState { copy(isLoading = false, error = e.message ?: errStr) }
|
||||
}
|
||||
@@ -131,19 +132,36 @@ class TaskViewModel(
|
||||
* 添加任务
|
||||
* @param [task] 任务
|
||||
*/
|
||||
@OptIn(ExperimentalTime::class)
|
||||
private fun addTask(task: Task) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
if (state.value.isProcessing) return@launch
|
||||
updateState { copy(isLoading = false, isProcessing = true) }
|
||||
// 1️⃣ 插入任务
|
||||
taskRepository.insertTask(task)
|
||||
|
||||
// 2️⃣ 创建通知
|
||||
task.dueDate?.let {
|
||||
NotificationManager.scheduleNotification(
|
||||
NotificationPayload(
|
||||
id = task.id,
|
||||
title = task.title,
|
||||
message = task.description,
|
||||
triggerTimeMillis = task.dueDate.toEpochMillis(),
|
||||
repeatType = NotificationRepeatType.NONE
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// 3️⃣ UI 提示
|
||||
sendEvent(TaskEffect.ShowMessage(getString(Res.string.task_add_success)))
|
||||
sendEvent(TaskEffect.NavigateBack)
|
||||
} catch (e: Exception) {
|
||||
val errStr = getString(Res.string.task_add_failed)
|
||||
updateState { copy(error = e.message ?: errStr) }
|
||||
} finally {
|
||||
updateState { copy(isLoading = false,isProcessing = false) }
|
||||
updateState { copy(isLoading = false, isProcessing = false) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,13 +176,27 @@ class TaskViewModel(
|
||||
if (state.value.isProcessing) return@launch
|
||||
updateState { copy(isLoading = false, isProcessing = true) }
|
||||
taskRepository.updateTask(task)
|
||||
|
||||
NotificationManager.cancelNotification(task.id)
|
||||
task.dueDate?.let {
|
||||
NotificationManager.scheduleNotification(
|
||||
NotificationPayload(
|
||||
id = task.id,
|
||||
title = task.title,
|
||||
message = task.description,
|
||||
triggerTimeMillis = task.dueDate.toEpochMillis(),
|
||||
repeatType = NotificationRepeatType.NONE
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
sendEvent(TaskEffect.ShowMessage(getString(Res.string.task_update_success)))
|
||||
sendEvent(TaskEffect.NavigateBack)
|
||||
} catch (e: Exception) {
|
||||
val errStr = getString(Res.string.task_update_failed)
|
||||
updateState { copy(error = e.message ?: errStr) }
|
||||
} finally {
|
||||
updateState { copy(isLoading = false,isProcessing = false) }
|
||||
updateState { copy(isLoading = false, isProcessing = false) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,12 +211,13 @@ class TaskViewModel(
|
||||
if (state.value.isProcessing) return@launch
|
||||
updateState { copy(isLoading = false, isProcessing = true) }
|
||||
taskRepository.deleteTask(taskId)
|
||||
NotificationManager.cancelNotification(taskId)
|
||||
sendEvent(TaskEffect.ShowMessage(getString(Res.string.task_delete_success)))
|
||||
} catch (e: Exception) {
|
||||
val errStr = getString(Res.string.task_delete_failed)
|
||||
updateState { copy(error = e.message ?: errStr) }
|
||||
} finally {
|
||||
updateState { copy(isLoading = false,isProcessing = false) }
|
||||
updateState { copy(isLoading = false, isProcessing = false) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,10 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.taskttl.core.notification.NotificationPermissionCallback
|
||||
import com.taskttl.core.notification.NotificationPermissionManager
|
||||
import com.taskttl.core.routes.Routes
|
||||
import com.taskttl.core.utils.LogUtils
|
||||
import com.taskttl.data.local.model.OnboardingPage
|
||||
import com.taskttl.data.state.OnboardingEffect
|
||||
import com.taskttl.data.state.OnboardingIntent
|
||||
@@ -63,6 +66,16 @@ fun OnboardingScreen(
|
||||
val pagerState =
|
||||
rememberPagerState(0, initialPageOffsetFraction = 0f, pageCount = { onboardingPages.size })
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
kotlinx.coroutines.delay(300)
|
||||
NotificationPermissionManager.requestPermission(
|
||||
object : NotificationPermissionCallback {
|
||||
override fun onGranted() = LogUtils.e("DevTTL", "✅ Android 通知权限已授予")
|
||||
override fun onDenied() = LogUtils.e("DevTTL", "❌ Android 通知权限被拒绝")
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.effects.collectLatest { event ->
|
||||
when (event) {
|
||||
|
||||
@@ -21,17 +21,15 @@ import androidx.compose.material.icons.automirrored.filled.Help
|
||||
import androidx.compose.material.icons.filled.ChevronRight
|
||||
import androidx.compose.material.icons.filled.Person
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material.icons.filled.Share
|
||||
import androidx.compose.material.icons.filled.Storage
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@@ -40,8 +38,8 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavHostController
|
||||
import com.taskttl.core.notification.NotificationPermissionManager
|
||||
import com.taskttl.core.routes.Routes
|
||||
import com.taskttl.core.utils.ExternalAppLauncher
|
||||
import com.taskttl.data.state.SettingsIntent
|
||||
import com.taskttl.data.viewmodel.SettingsViewModel
|
||||
import com.taskttl.ui.components.AppHeader
|
||||
@@ -53,29 +51,18 @@ import taskttl.composeapp.generated.resources.Res
|
||||
import taskttl.composeapp.generated.resources.section_data_management
|
||||
import taskttl.composeapp.generated.resources.section_general_settings
|
||||
import taskttl.composeapp.generated.resources.section_help_feedback
|
||||
import taskttl.composeapp.generated.resources.section_social_share
|
||||
import taskttl.composeapp.generated.resources.setting_about_app
|
||||
import taskttl.composeapp.generated.resources.setting_about_app_desc
|
||||
import taskttl.composeapp.generated.resources.setting_category_management
|
||||
import taskttl.composeapp.generated.resources.setting_category_management_desc
|
||||
import taskttl.composeapp.generated.resources.setting_dark_mode
|
||||
import taskttl.composeapp.generated.resources.setting_dark_mode_desc
|
||||
import taskttl.composeapp.generated.resources.setting_data_management
|
||||
import taskttl.composeapp.generated.resources.setting_data_management_desc
|
||||
import taskttl.composeapp.generated.resources.setting_feedback
|
||||
import taskttl.composeapp.generated.resources.setting_feedback_desc
|
||||
import taskttl.composeapp.generated.resources.setting_invite_friend
|
||||
import taskttl.composeapp.generated.resources.setting_invite_friend_desc
|
||||
import taskttl.composeapp.generated.resources.setting_language
|
||||
import taskttl.composeapp.generated.resources.setting_language_desc
|
||||
import taskttl.composeapp.generated.resources.setting_privacy_policy
|
||||
import taskttl.composeapp.generated.resources.setting_privacy_policy_desc
|
||||
import taskttl.composeapp.generated.resources.setting_privacy_rate
|
||||
import taskttl.composeapp.generated.resources.setting_privacy_rate_desc
|
||||
import taskttl.composeapp.generated.resources.setting_push_notification
|
||||
import taskttl.composeapp.generated.resources.setting_push_notification_desc
|
||||
import taskttl.composeapp.generated.resources.setting_share_achievement
|
||||
import taskttl.composeapp.generated.resources.setting_share_achievement_desc
|
||||
import taskttl.composeapp.generated.resources.title_app_settings
|
||||
|
||||
/**
|
||||
@@ -86,8 +73,21 @@ import taskttl.composeapp.generated.resources.title_app_settings
|
||||
@Preview
|
||||
fun SettingsScreen(
|
||||
navController: NavHostController,
|
||||
viewModel: SettingsViewModel = koinViewModel()
|
||||
viewModel: SettingsViewModel = koinViewModel(),
|
||||
) {
|
||||
val state by viewModel.state.collectAsState()
|
||||
|
||||
// 轮询监听权限状态变化
|
||||
LaunchedEffect(Unit) {
|
||||
while (true) {
|
||||
val current = NotificationPermissionManager.verifyPermission()
|
||||
if (state.isNotification != current) {
|
||||
viewModel.handleIntent(SettingsIntent.UpdateNotificationStatus(current))
|
||||
}
|
||||
kotlinx.coroutines.delay(2000)
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
@@ -151,16 +151,15 @@ fun SettingsScreen(
|
||||
|
||||
|
||||
// 通用设置
|
||||
// SectionTitle(Icons.Default.Settings, Res.string.section_general_settings)
|
||||
SectionTitle(Icons.Default.Settings, Res.string.section_general_settings)
|
||||
|
||||
// var notificationEnabled by remember { mutableStateOf(true) }
|
||||
// SettingItem(
|
||||
// titleRes = Res.string.setting_push_notification,
|
||||
// descriptionRes = Res.string.setting_push_notification_desc,
|
||||
// showSwitch = true,
|
||||
// switchState = notificationEnabled,
|
||||
// onSwitchChanged = { notificationEnabled = it }
|
||||
// )
|
||||
SettingItem(
|
||||
titleRes = Res.string.setting_push_notification,
|
||||
descriptionRes = Res.string.setting_push_notification_desc,
|
||||
showSwitch = true,
|
||||
switchState = state.isNotification,
|
||||
onSwitchChanged = { viewModel.handleIntent(SettingsIntent.RequestPermission) }
|
||||
)
|
||||
|
||||
// var darkMode by remember { mutableStateOf(false) }
|
||||
//
|
||||
@@ -291,7 +290,7 @@ fun SettingItem(
|
||||
onSwitchChanged: ((Boolean) -> Unit)? = null,
|
||||
showArrow: Boolean = false,
|
||||
modifier: Modifier = Modifier,
|
||||
onClick: (() -> Unit)? = null
|
||||
onClick: (() -> Unit)? = null,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
|
||||
@@ -55,7 +55,6 @@ import com.taskttl.core.routes.Routes
|
||||
import com.taskttl.core.ui.ActionButtonListItem
|
||||
import com.taskttl.core.ui.ErrorDialog
|
||||
import com.taskttl.core.ui.LoadingOverlay
|
||||
|
||||
import com.taskttl.core.utils.ToastUtils
|
||||
import com.taskttl.data.local.model.Task
|
||||
import com.taskttl.data.state.TaskEffect
|
||||
@@ -245,7 +244,6 @@ fun TaskScreen(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 悬浮按钮
|
||||
FloatingActionButton(
|
||||
onClick = { navController.navigate(Routes.Main.Task.AddTask) },
|
||||
|
||||
Reference in New Issue
Block a user