This commit is contained in:
2025-10-19 21:51:36 +08:00
parent c7d738ccce
commit 5f07605a06
22 changed files with 447 additions and 67 deletions

View File

@@ -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

View File

@@ -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()
}

View File

@@ -39,6 +39,7 @@ data class TaskState(
* @constructor 创建[TaskIntent]
*/
sealed class TaskIntent {
/**
* 加载任务
* @author admin

View File

@@ -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

View File

@@ -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) }
}
/**
* 清除错误
*/

View File

@@ -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) }
}
}
}