diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts
index a3411d2..a1c7b31 100644
--- a/composeApp/build.gradle.kts
+++ b/composeApp/build.gradle.kts
@@ -62,7 +62,7 @@ kotlin {
implementation(project.dependencies.platform(libs.firebase.bom))
implementation(libs.firebase.analytics)
// facebook
- implementation(libs.android.facebook.android.sdk)
+ // implementation(libs.android.facebook.android.sdk)
// mmkv
implementation(libs.android.mmkv)
@@ -143,8 +143,8 @@ android {
applicationId = "com.taskttl"
minSdk = libs.versions.android.minSdk.get().toInt()
targetSdk = libs.versions.android.targetSdk.get().toInt()
- versionCode = 1
- versionName = "1.0"
+ versionCode = libs.versions.android.versionCode.get().toInt()
+ versionName = libs.versions.android.versionName.get().toString()
buildConfigField("String", "APP_NAME", "\"TaskTTL\"")
diff --git a/composeApp/release/composeApp-release.aab b/composeApp/release/composeApp-release.aab
new file mode 100644
index 0000000..10660f9
Binary files /dev/null and b/composeApp/release/composeApp-release.aab differ
diff --git a/composeApp/src/androidMain/AndroidManifest.xml b/composeApp/src/androidMain/AndroidManifest.xml
index 1d92678..1e6bea8 100644
--- a/composeApp/src/androidMain/AndroidManifest.xml
+++ b/composeApp/src/androidMain/AndroidManifest.xml
@@ -15,8 +15,6 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
- android:usesCleartextTraffic="true"
- android:networkSecurityConfig="@xml/network_security_config"
android:theme="@android:style/Theme.Material.Light.NoActionBar">
+
+
+
+
+
+
+
+
+
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/composeApp/src/androidMain/kotlin/com/taskttl/core/utils/DeviceUtils.android.kt b/composeApp/src/androidMain/kotlin/com/taskttl/core/utils/DeviceUtils.android.kt
index 4b95135..2943523 100644
--- a/composeApp/src/androidMain/kotlin/com/taskttl/core/utils/DeviceUtils.android.kt
+++ b/composeApp/src/androidMain/kotlin/com/taskttl/core/utils/DeviceUtils.android.kt
@@ -67,7 +67,7 @@ actual object DeviceUtils {
uniqueId = getUniqueId(),
deviceInfo = Build.MODEL ?: "0",
deviceVersion = Build.VERSION.RELEASE,
- language = ""
+ language = Localization.getDeviceLanguage()
)
}
diff --git a/composeApp/src/androidMain/kotlin/com/taskttl/core/utils/ExternalAppLauncher.android.kt b/composeApp/src/androidMain/kotlin/com/taskttl/core/utils/ExternalAppLauncher.android.kt
new file mode 100644
index 0000000..e739b4c
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/com/taskttl/core/utils/ExternalAppLauncher.android.kt
@@ -0,0 +1,78 @@
+package com.taskttl.core.utils
+
+import android.content.Context
+import android.content.Intent
+import androidx.core.net.toUri
+import com.taskttl.MainApplication
+
+actual object ExternalAppLauncher {
+ private val appContext: Context
+ get() = MainApplication.instance.applicationContext
+
+ private val packageName = appContext.packageName
+
+ /**
+ * 打开应用程序评级
+ */
+ actual suspend fun openAppRating() {
+ val webUrl = "https://play.google.com/store/apps/details?id=$packageName"
+ try {
+ // 尝试打开 Google Play 应用
+ val marketUri = "market://details?id=$packageName"
+ if (openUriWithFallback(marketUri, webUrl)) {
+ return
+ }
+
+ // 如果前面的方法都失败,直接打开网页版
+ openWebUrl(webUrl)
+ } catch (e: Exception) {
+ // Log.e(TAG, getString(Res.string.external_app_launcher_open_rating_failed), e)
+ openWebUrl(webUrl)
+ }
+ }
+
+ actual suspend fun openUrl(url: String) {
+ openWebUrl(url)
+ }
+
+ /**
+ * 尝试打开URI,打开指定的应用包名
+ * @return 是否成功打开
+ */
+ private fun openUriWithFallback(uri: String, packageName: String): Boolean {
+ try {
+ val intent = Intent(Intent.ACTION_VIEW, uri.toUri())
+ intent.setPackage(packageName)
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+ // 检查是否有应用可以处理此Intent
+ if (isIntentResolvable(intent)) {
+ appContext.startActivity(intent)
+ return true
+ }
+ } catch (e: Exception) {
+ // Log.w(TAG, getString(Res.string.external_app_launcher_open_uri_failed, uri), e)
+ }
+ return false
+ }
+
+ /**
+ * 打开网页URL
+ */
+ private fun openWebUrl(url: String) {
+ try {
+ val intent = Intent(Intent.ACTION_VIEW, url.toUri())
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ appContext.startActivity(intent)
+ } catch (e: Exception) {
+ // Log.e(TAG, getString(Res.string.external_app_launcher_open_web_failed, url), e)
+ }
+ }
+
+ /**
+ * 检查Intent是否可以被解析
+ */
+ private fun isIntentResolvable(intent: Intent): Boolean {
+ return intent.resolveActivity(appContext.packageManager) != null
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/androidMain/kotlin/com/taskttl/core/utils/Localization.android.kt b/composeApp/src/androidMain/kotlin/com/taskttl/core/utils/Localization.android.kt
new file mode 100644
index 0000000..bcc6537
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/com/taskttl/core/utils/Localization.android.kt
@@ -0,0 +1,32 @@
+package com.taskttl.core.utils
+
+import android.content.Context
+import android.os.LocaleList
+import com.taskttl.MainApplication
+import java.util.Locale
+
+/**
+ * 本地化
+ * @author DevTTL
+ * @date 2025/10/14
+ */
+actual object Localization {
+ private val appContext: Context
+ get() = MainApplication.instance.applicationContext
+
+ actual fun applyLanguage(iso: String) {
+ val locale = Locale.forLanguageTag(iso)
+ Locale.setDefault(locale)
+ val config = appContext.resources.configuration
+ // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ config.setLocales(LocaleList(locale))
+ // } else {
+ // config.setLocale(locale)
+ // }
+ appContext.createConfigurationContext(config)
+ }
+
+ actual fun getDeviceLanguage(): String {
+ return Locale.getDefault().language
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml b/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml
deleted file mode 100644
index eca70cf..0000000
--- a/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml b/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml
deleted file mode 100644
index eca70cf..0000000
--- a/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png b/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index a571e60..0000000
Binary files a/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png b/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png
deleted file mode 100644
index 61da551..0000000
Binary files a/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ
diff --git a/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png b/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png
index c41dd28..3a91ec6 100644
Binary files a/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png and b/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png b/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png
index db5080a..4f8e01c 100644
Binary files a/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png and b/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png b/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png
index 6dba46d..ffb521a 100644
Binary files a/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png and b/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png b/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png
index da31a87..2fb7570 100644
Binary files a/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png and b/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png b/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png
index 15ac681..d41d6c2 100644
Binary files a/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png and b/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png b/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png
index b216f2d..cf60cf1 100644
Binary files a/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png and b/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png b/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png
index f25a419..bac6ce2 100644
Binary files a/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png and b/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png b/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png
index e96783c..b7e48a8 100644
Binary files a/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png and b/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml
index 6d453db..1f53858 100644
--- a/composeApp/src/commonMain/composeResources/values/strings.xml
+++ b/composeApp/src/commonMain/composeResources/values/strings.xml
@@ -1,313 +1,317 @@
- 继续
- 跳过
- 开始使用
+ Continue
+ Skip
+ Get Started
- 欢迎使用 TaskTTL
- 一个简洁而强大的任务管理工具,帮助您高效管理日常任务和重要日期
- 智能任务管理
- 创建、分类和跟踪您的任务。设置优先级,添加截止日期,让工作更有条理
- 重要日期提醒
- 设置重要日期的倒数计时,永远不会错过生日、纪念日或重要的截止日期
- 准备就绪!
- 现在您可以开始创建第一个任务,让我们一起提高工作效率吧!
+ Welcome to TaskTTL
+ A simple yet powerful task management tool that helps you efficiently manage your daily tasks and important dates
+ Smart Task Management
+ Create, categorize, and track your tasks. Set priorities and add due dates for better organization
+ Important Date Reminders
+ Set countdowns to important dates and never miss a birthday, anniversary, or important deadline
+ Ready!
+ Now you can start creating your first task. Let's improve your productivity together!
-
+
TaskTTL
- 任务管理与倒数日应用
- 让每一天都更有意义
- 版本
- 构建版本
+ Task Management and Countdown App
+ Make Every Day More Meaningful
+ Version
+ Build Version
-
- 待办
- 倒数日
- 统计
- 设置
+
+ To Do
+ Countdown
+ Statistics
+ Settings
-
- 搜索任务...
- 我的任务
- 任务详情
- 添加任务
- 编辑任务
+
+ Search Tasks...
+ My Tasks
+ Task Details
+ Add Task
- 任务列表
- 显示已完成
- 暂无任务
- 点击右下角按钮添加新任务
- 已完成
- 未完成
+ Edit Task
- 任务标题
- 任务描述
- 选择分类
- 优先级
- 截止日期(可选)
- 选择日期
- 标签(用逗号分隔)
- 例如:重要,紧急,工作
+ Task List
+ Show Completed
+ No Tasks
+ Click the button in the lower right corner to add a new task
+ Completed
+ Incomplete
- 任务不存在
- 截止日期:
- 无
- 创建时间:
- 任务描述
+ Task Title
+ Task Description
+ Select Category
+ Priority
+ Due Date (Optional)
+ Select a date
+ Tags (comma-separated)
+ Example: Important, Urgent, Work
- 任务添加成功
- 添加任务失败
- 任务更新成功
- 更新任务失败
- 任务删除成功
- 删除任务失败
- 加载任务失败
- 查询任务失败
- 更新任务状态成功
- 更新任务状态失败
+ Task does not exist
+ Due date:
+ None
+ Creation time:
+ Task description
-
- 倒数日
- 倒数日详情
- 添加倒数日
- 编辑倒数日
+ Task added successfully
+ Task addition failed
+ Task updated successfully
+ Task update failed
+ Task deleted successfully
+ Task deletion failed
+ Task loading failed
+ Task query failed
+ Task status update successful
+ Task status update failed
- 倒数日列表
- 天
- 暂无倒数日
- 点击右下角按钮添加新的倒数日
- 添加倒数日
+
+ Countdown
+ Countdown Details
+ Add Countdown
+ Edit Countdown
- 倒数日标题
- 倒数日描述
- 目标日期
- 通知设置
- 倒数日不存在
- 事件描述
- 详细信息
- 提醒
+ Countdown List
+ Days
+ No Countdown
+ Click the button in the lower right corner to add a new countdown
+ Add Countdown
- 倒数日添加成功
- 添加倒数日失败
- 倒数日更新成功
- 更新倒数日失败
- 倒数日删除成功
- 删除倒数日失败
- 加载倒数日失败
- 查询倒数日失败
+ Countdown Title
+ Countdown Description
+ Target Date
+ Notification settings
+ Countdown day does not exist
+ Event description
+ Detailed information
+ Reminder
-
- 统计
- 总览
- 分类统计
- 总任务
- 已完成
- 完成率
- 倒数日总数
- 活跃中
+ Countdown day added successfully
+ Countdown day added failed
+ Countdown day updated successfully
+ Countdown day updated failed
+ Countdown day deleted successfully
+ Countdown day deleted failed
+ Countdown day loaded failed
+ Countdown query failed
-
- 任务
- 倒数日
+
+ Statistics
+ Overview
+ Category statistics
+ Total tasks
+ Completed
+ Completion rate
+ Total countdown days
+ Active
- 分类管理
- 添加分类
- 编辑分类
- 暂无分类
- 点击右下角按钮添加新分类
- 分类名称
- 输入分类名称...
- 分类类型
- 选择颜色
- 选择图标
- 任务分类
- 倒数日分类
+
+ Task
+ Countdown
- %1$d 个任务
- %1$d 个倒数日
+ Category Management
+ Add Category
+ Edit Category
+ No Category
+ Click the button in the lower right corner to add a new category
+ Category Name
+ Enter Category Name...
+ Category Type
+ Select Color
+ Select Icon
+ Task Category
+ Countdown Category
-
- 分类添加成功
- 添加分类失败
- 分类更新成功
- 更新分类失败
- 分类删除成功
- 删除分类失败
- 加载分类失败
- 加载统计数据失败
- 默认分类初始化成功
- 初始化默认分类失败
- 查询分类失败
- 更新分类计数失败
+ %1$d tasks
+ %1$d countdown days
-
- 进入
- 编辑
- 取消
- 确定
- 删除
- 导出
- 导入
- 返回
- 操作
- 搜索
- 清除
- 全部
- 重试
- 选择文件
- 错误
- 加载失败,请检查网络连接
+
+ Category added successfully
+ Category added failed
+ Category updated successfully
+ Category updated failed
+ Category deleted successfully
+ Category deleted failed
+ Category loaded failed
+ Statistics loaded failed
+ Default category initialized successfully
+ Default category initialized failed
+ Category query failed
+ Category count update failed
+
+
+ Enter
+ Edit
+ Cancel
+ Confirm
+ Delete
+ Export
+ Import
+ Back
+ Action
+ Search
+ Clear
+ All
+ Retry
+ Choose File
+ Error
+ Loading...
+ Loading failed, please check your network connection
-
- 数据管理
- 导出数据
- 将所有任务和倒数日导出为文件
- 导入数据
- 从文件导入任务和倒数日
- 自动备份
- 定期自动备份数据到云端
- 清除所有数据
- 删除所有任务、倒数日和设置
- 此操作将删除所有任务、倒数日和设置,且无法恢复。
- 清理已完成任务
- 清理过期倒数日
- 删除所有已完成的任务
- 删除所有已过期的倒数日
+
+ Data Management
+ Export Data
+ Export all tasks and countdowns to a file
+ Import Data
+ Import tasks and countdowns from a file
+ Auto Backup
+ Regularly and automatically back up data to the cloud
+ Clear All Data
+ Delete all tasks, countdowns, and settings
+ This operation will delete all tasks, countdowns, and settings and cannot be restored.
+ Clear completed tasks
+ Clear expired countdowns
+ Delete all completed tasks
+ Delete all expired countdowns
- 备份与恢复
- 数据清理
- 选择要导入的文件
- 选择文件
- 选择导出格式
- JSON格式
- CSV格式
+ Backup and restore
+ Data cleanup
+ Select the file to import
+ Select a file
+ Select the export format
+ JSON format
+ CSV format
-
- 应用设置
- 通用设置
- 数据管理
- 社交分享
- 帮助与反馈
+
+ App Settings
+ General Settings
+ Data Management
+ Social Sharing
+ Help and Feedback
- 推送通知
- 接收任务和倒数日提醒
- 深色模式
- 使用深色主题
- 语言设置
- 简体中文
+ Push Notifications
+ Receive Task and Countdown Reminders
+ Dark Mode
+ Use Dark Theme
+ Language Settings
+ Simplified Chinese
- 分类管理
- 管理分类
- 数据管理
- 备份和恢复数据
+ Management
+ Manage categories
+ Data management
+ Backup and restore data
- 分享成就
- 分享任务完成成就
- 推荐给朋友
- 邀请朋友使用 TaskMaster
+ Share achievements
+ Share task completion achievements
+ Recommend to a friend
+ Invite a friend to use TaskMaster
- 意见反馈
- 告诉我们您的想法
- 隐私政策
- 了解我们如何保护您的数据
- 关于应用
- 版本 1.0.0
+ Feedback
+ Tell us what you think
+ Privacy Policy
+ Learn how we protect your data
+ App Review
+ If you like it, please leave a five-star review in the store
+ About the App
+ 100001
+ 1.0.1
+ Version 1.0.1
-
- 意见反馈
- 反馈类型
- 问题反馈
- 功能建议
- 问题描述
- 请详细描述您遇到的问题或建议...
- 联系方式(可选)
- 您的邮箱地址,方便我们回复
- 感谢您的反馈!我们会尽快处理。
- 请填写反馈内容
- 发送反馈
+
+ Feedback
+ Feedback Type
+ Issue Feedback
+ Feature Suggestion
+ Issue Description
+ Please describe your problem or suggestion in detail...
+ Contact Information (optional)
+ Your email address for our response
+ Thank you for your feedback! We will address it as soon as possible.
+ Please fill in your feedback
+ Send Feedback
-
- 关于
- 应用介绍
-
- TaskTTL 是一款现代化的任务管理与倒数日应用,
- 支持分类管理、优先级设置与统计分析,让生活更有条理。
-
+
+ About
+ App Introduction
+ TaskTTL is a modern task management and countdown app.\nIt supports category management, priority setting, and statistical analysis, making your life more organized.
- 隐私协议
+ Privacy Policy
- 技术栈
- Kotlin Multiplatform(跨平台开发框架)
- Jetpack Compose(现代化 UI 框架)
- Room Database(本地存储)
- Koin(依赖注入框架)
- Ktor(网络请求)
- MVI Architecture(响应式架构模式)
+ Technology Stack
+ Kotlin Multiplatform (Cross-Platform Development Framework)
+ Jetpack Compose (Modern UI Framework)
+ Room Database (Local Storage)
+ Koin (Dependency Injection Framework)
+ Ktor (Network Request)
+ MVI Architecture (Responsive Architecture Pattern)
- 开发者
- DevTTL 团队
- 联系我们
- 电子邮箱
+ Developer
+ DevTTL Team
+ Contact Us
+ Email
+ mailto:%1$s
admin@devttl.com
- 官方网站
+ Official Website
https://devttl.com
2025
- 保留所有权利
+ All Rights Reserved
- 低
- 中
- 高
- 紧急
+ Low
+ Medium
+ High
+ Urgent
- 一次
- 每天
- 每周
- 每月
- 关闭
+ Once
+ Daily
+ Weekly
+ Monthly
+ Off
-
- 工作
- 学习
- 考试
- 项目
+
+ Work
+ Study
+ Exam
+ Project
-
- 家庭
- 休闲
- 购物
- 美食
- 家务
+
+ Family
+ Leisure
+ Shopping
+ Food
+ Housework
-
- 健康
- 健身
- 作息
+
+ Health
+ Fitness
+ Days and Nights
-
- 音乐
- 娱乐
- 摄影
- 影视
+
+ Music
+ Entertainment
+ Photography
+ Movies
-
- 出行
- 旅行
- 步行
+
+ Travel
+ Travel
+ Walk
-
- 生日
- 节日
- 纪念日
+
+ Birthday
+ Festival
+ Anniversary
-
- 理财
- 目标
- 提醒
+
+ Financial Planning
+ Goal
+ Reminder
https://sites.google.com/view/taskttl/privacy
- 反馈成功
- 反馈失败,请检查网络连接或稍后重试
+ Feedback successful
+ Feedback failed. Please check your network connection or try again later.
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/core/domain/constant/PointEvent.kt b/composeApp/src/commonMain/kotlin/com/taskttl/core/domain/constant/PointEvent.kt
index dbf499b..a2a38db 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/core/domain/constant/PointEvent.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/core/domain/constant/PointEvent.kt
@@ -41,8 +41,5 @@ enum class PointEvent(val eventName: String, val eventCode: Int) {
AdShownBanner("ad_shown_banner", 9001),
AdClickReward("ad_click_reward", 9002);
- fun toMap(): Map = mapOf(
- "eventName" to eventName,
- "eventCode" to eventCode,
- )
+ fun toMap(): Map = mapOf("eventName" to eventName, "eventCode" to eventCode)
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/core/network/ApiConfig.kt b/composeApp/src/commonMain/kotlin/com/taskttl/core/network/ApiConfig.kt
index beef5b8..666fdaa 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/core/network/ApiConfig.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/core/network/ApiConfig.kt
@@ -7,8 +7,8 @@ package com.taskttl.core.network
*/
object ApiConfig {
/** 基本地址 */
- const val BASE_URL = "http://10.0.0.5:8888/api/v1"
- // const val BASE_URL = "https://api.tikttl.com/api/v1"
+ // const val BASE_URL = "http://10.0.0.5:8888/api/v1"
+ const val BASE_URL = "https://api.taskttl.com/api/v1"
/** 反馈地址 */
const val FEEDBACK_URL = "$BASE_URL/feedback"
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/core/ui/LoadingOverlay.kt b/composeApp/src/commonMain/kotlin/com/taskttl/core/ui/LoadingOverlay.kt
new file mode 100644
index 0000000..6f363ad
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/core/ui/LoadingOverlay.kt
@@ -0,0 +1,131 @@
+package com.taskttl.core.ui
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.animateFloat
+import androidx.compose.animation.core.infiniteRepeatable
+import androidx.compose.animation.core.rememberInfiniteTransition
+import androidx.compose.animation.core.tween
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+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.draw.blur
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.StrokeCap
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import kotlinx.coroutines.delay
+import org.jetbrains.compose.resources.StringResource
+import org.jetbrains.compose.resources.stringResource
+import org.jetbrains.compose.ui.tooling.preview.Preview
+import taskttl.composeapp.generated.resources.Res
+import taskttl.composeapp.generated.resources.loading
+
+@Composable
+fun LoadingOverlay(
+ visible: Boolean,
+ messageRes: StringResource = Res.string.loading,
+) {
+ AnimatedVisibility(
+ visible = visible,
+ enter = fadeIn(animationSpec = tween(300)),
+ exit = fadeOut(animationSpec = tween(300))
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(Color.Black.copy(alpha = 0.4f))
+ .blur(8.dp)
+ // 拦截所有点击事件,防止点击到底层
+ .clickable(
+ indication = null, // 无点击动画
+ interactionSource = remember { MutableInteractionSource() }
+ ) { },
+ contentAlignment = Alignment.Center
+ ) {
+ Column(horizontalAlignment = Alignment.CenterHorizontally) {
+ RotatingGradientRing(
+ size = 56.dp,
+ stroke = 6.dp,
+ gradientColors = listOf(
+ Color(0xFF4285F4),
+ Color(0xFF73A7F9),
+ Color(0xFF4285F4)
+ )
+ )
+ Spacer(Modifier.height(16.dp))
+ Text(
+ text = stringResource(messageRes),
+ color = MaterialTheme.colorScheme.onSurface,
+ fontSize = 15.sp
+ )
+ }
+
+ // CircularProgressIndicator(
+ // modifier = Modifier.size(48.dp),
+ // strokeWidth = 4.dp,
+ // color = MaterialTheme.colorScheme.primary
+ // )
+ }
+ }
+}
+
+@Composable
+private fun RotatingGradientRing(
+ size: Dp,
+ stroke: Dp,
+ gradientColors: List,
+) {
+ val rotation by rememberInfiniteTransition(label = "").animateFloat(
+ initialValue = 0f,
+ targetValue = 360f,
+ animationSpec = infiniteRepeatable(
+ animation = tween(1200, easing = LinearEasing)
+ ), label = ""
+ )
+
+ Canvas(
+ modifier = Modifier
+ .size(size)
+ .graphicsLayer(rotationZ = rotation)
+ ) {
+ drawCircle(
+ brush = Brush.sweepGradient(gradientColors),
+ style = Stroke(width = stroke.toPx(), cap = StrokeCap.Round)
+ )
+ }
+}
+
+@Preview
+@Composable
+private fun PreviewTaskTTLLoading() {
+ var show by remember { mutableStateOf(true) }
+ LaunchedEffect(Unit) {
+ delay(3000)
+ show = false
+ }
+ LoadingOverlay(visible = show)
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/core/ui/LoadingScreen.kt b/composeApp/src/commonMain/kotlin/com/taskttl/core/ui/LoadingScreen.kt
deleted file mode 100644
index 0090c4b..0000000
--- a/composeApp/src/commonMain/kotlin/com/taskttl/core/ui/LoadingScreen.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.taskttl.core.ui
-
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.interaction.MutableInteractionSource
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.material3.CircularProgressIndicator
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-
-@Composable
-fun LoadingScreen() {
- Box(
- modifier = Modifier
- .fillMaxSize()
- .background(Color(0x88000000))
- // 拦截所有点击事件,防止点击到底层
- .clickable(
- indication = null, // 无点击动画
- interactionSource = remember { MutableInteractionSource() }
- ) { },
- contentAlignment = Alignment.Center
- ) {
- CircularProgressIndicator()
- }
-}
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/core/utils/ExternalAppLauncher.kt b/composeApp/src/commonMain/kotlin/com/taskttl/core/utils/ExternalAppLauncher.kt
new file mode 100644
index 0000000..c5295df
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/core/utils/ExternalAppLauncher.kt
@@ -0,0 +1,22 @@
+package com.taskttl.core.utils
+
+/**
+ * 外部应用程序启动器
+ * @author DevTTL
+ * @date 2025/03/08
+ * @constructor 创建[ExternalAppLauncher]
+ */
+expect object ExternalAppLauncher {
+
+ /**
+ * 打开应用程序评级
+ */
+ suspend fun openAppRating()
+
+ /**
+ * 打开网址
+ * @param [url] 网址
+ */
+ suspend fun openUrl(url: String)
+
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/core/utils/Localization.kt b/composeApp/src/commonMain/kotlin/com/taskttl/core/utils/Localization.kt
new file mode 100644
index 0000000..660e9af
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/core/utils/Localization.kt
@@ -0,0 +1,20 @@
+package com.taskttl.core.utils
+
+/**
+ * 本地化
+ * @author DevTTL
+ * @date 2025/10/14
+ */
+expect object Localization {
+ /**
+ * 应用语言
+ * @param [iso]
+ */
+ fun applyLanguage(iso: String)
+
+ /**
+ * 获取设备当前语言
+ * @return 设备语言代码,例如"zh"、"en"等
+ */
+ fun getDeviceLanguage(): String
+}
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/core/utils/LogUtils.kt b/composeApp/src/commonMain/kotlin/com/taskttl/core/utils/LogUtils.kt
index 4a9c1c5..8954770 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/core/utils/LogUtils.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/core/utils/LogUtils.kt
@@ -1,8 +1,5 @@
package com.taskttl.core.utils
-import io.ktor.client.plugins.logging.Logger
-
-enum class LogLevel { DEBUG, INFO, WARN, ERROR }
/**
* 日志工具类
@@ -14,4 +11,6 @@ expect object LogUtils {
fun i(tag: String, message: String)
fun w(tag: String, message: String)
fun e(tag: String, message: String, throwable: Throwable? = null)
-}
\ No newline at end of file
+}
+
+// enum class LogLevel { DEBUG, INFO, WARN, ERROR }
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/data/di/KoinModels.kt b/composeApp/src/commonMain/kotlin/com/taskttl/data/di/KoinModels.kt
index e332bee..35fc2ab 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/data/di/KoinModels.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/data/di/KoinModels.kt
@@ -8,6 +8,7 @@ import com.taskttl.data.viewmodel.CategoryViewModel
import com.taskttl.data.viewmodel.CountdownViewModel
import com.taskttl.data.viewmodel.FeedbackViewModel
import com.taskttl.data.viewmodel.OnboardingViewModel
+import com.taskttl.data.viewmodel.SettingsViewModel
import com.taskttl.data.viewmodel.SplashViewModel
import com.taskttl.data.viewmodel.TaskViewModel
import org.koin.core.KoinApplication
@@ -44,5 +45,6 @@ val viewModelModule = module {
viewModelOf(::TaskViewModel)
viewModelOf(::CategoryViewModel)
viewModelOf(::CountdownViewModel)
+ viewModelOf(::SettingsViewModel)
viewModelOf(::FeedbackViewModel)
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/data/repository/impl/CategoryRepositoryImpl.kt b/composeApp/src/commonMain/kotlin/com/taskttl/data/repository/impl/CategoryRepositoryImpl.kt
index 762a3ad..878c2a6 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/data/repository/impl/CategoryRepositoryImpl.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/data/repository/impl/CategoryRepositoryImpl.kt
@@ -3,18 +3,28 @@ package com.taskttl.data.repository.impl
import com.taskttl.data.local.dao.CategoryDao
import com.taskttl.data.local.dao.CountdownDao
import com.taskttl.data.local.dao.TaskDao
-import com.taskttl.data.mapper.CategoryMapper
import com.taskttl.data.local.model.Category
import com.taskttl.data.local.model.CategoryColor
import com.taskttl.data.local.model.CategoryIcon
import com.taskttl.data.local.model.CategoryStatistics
import com.taskttl.data.local.model.CategoryType
+import com.taskttl.data.mapper.CategoryMapper
import com.taskttl.data.repository.CategoryRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime
+import org.jetbrains.compose.resources.getString
+import taskttl.composeapp.generated.resources.Res
+import taskttl.composeapp.generated.resources.category_birthday
+import taskttl.composeapp.generated.resources.category_book
+import taskttl.composeapp.generated.resources.category_briefcase
+import taskttl.composeapp.generated.resources.category_exam
+import taskttl.composeapp.generated.resources.category_festival
+import taskttl.composeapp.generated.resources.category_goal
+import taskttl.composeapp.generated.resources.category_heart
+import taskttl.composeapp.generated.resources.category_home
import kotlin.time.Clock
import kotlin.time.ExperimentalTime
import kotlin.uuid.ExperimentalUuidApi
@@ -123,7 +133,7 @@ class CategoryRepositoryImpl(
val defaultTaskCategories = listOf(
Category(
id = Uuid.random().toString(),
- name = "工作",
+ name = getString(Res.string.category_briefcase),
color = CategoryColor.BLUE,
icon = CategoryIcon.BRIEFCASE,
type = CategoryType.TASK,
@@ -132,7 +142,7 @@ class CategoryRepositoryImpl(
),
Category(
id = Uuid.random().toString(),
- name = "生活",
+ name = getString(Res.string.category_home),
color = CategoryColor.GREEN,
icon = CategoryIcon.HOME,
type = CategoryType.TASK,
@@ -141,7 +151,7 @@ class CategoryRepositoryImpl(
),
Category(
id = Uuid.random().toString(),
- name = "健康",
+ name = getString(Res.string.category_heart),
color = CategoryColor.ORANGE,
icon = CategoryIcon.HEART,
type = CategoryType.TASK,
@@ -150,7 +160,7 @@ class CategoryRepositoryImpl(
),
Category(
id = Uuid.random().toString(),
- name = "学习",
+ name = getString(Res.string.category_book),
color = CategoryColor.PURPLE,
icon = CategoryIcon.BOOK,
type = CategoryType.TASK,
@@ -163,7 +173,7 @@ class CategoryRepositoryImpl(
val defaultCountdownCategories = listOf(
Category(
id = Uuid.random().toString(),
- name = "生日",
+ name = getString(Res.string.category_birthday),
color = CategoryColor.PINK,
icon = CategoryIcon.BIRTHDAY,
type = CategoryType.COUNTDOWN,
@@ -172,7 +182,7 @@ class CategoryRepositoryImpl(
),
Category(
id = Uuid.random().toString(),
- name = "节日",
+ name = getString(Res.string.category_festival),
color = CategoryColor.CYAN,
icon = CategoryIcon.FESTIVAL,
type = CategoryType.COUNTDOWN,
@@ -181,7 +191,7 @@ class CategoryRepositoryImpl(
),
Category(
id = Uuid.random().toString(),
- name = "目标",
+ name = getString(Res.string.category_goal),
color = CategoryColor.YELLOW,
icon = CategoryIcon.GOAL,
type = CategoryType.COUNTDOWN,
@@ -190,7 +200,7 @@ class CategoryRepositoryImpl(
),
Category(
id = Uuid.random().toString(),
- name = "考试",
+ name = getString(Res.string.category_exam),
color = CategoryColor.GREEN,
icon = CategoryIcon.EXAM,
type = CategoryType.COUNTDOWN,
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/data/state/SettingsState.kt b/composeApp/src/commonMain/kotlin/com/taskttl/data/state/SettingsState.kt
new file mode 100644
index 0000000..6ab1314
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/data/state/SettingsState.kt
@@ -0,0 +1,63 @@
+package com.taskttl.data.state
+
+/**
+ * 设置状态
+ * @author DevTTL
+ * @date 2025/10/14
+ * @constructor 创建[SettingsState]
+ * @param [isLoading] 正在加载
+ * @param [error] 错误
+ */
+data class SettingsState(
+ val isLoading: Boolean = false,
+ val error: String? = null,
+)
+
+/**
+ * 设置意图
+ * @author DevTTL
+ * @date 2025/10/14
+ * @constructor 创建[SettingsIntent]
+ */
+sealed class SettingsIntent {
+ /**
+ * 打开应用评分
+ * @author DevTTL
+ * @date 2025/10/14
+ */
+ object OpenAppRating: SettingsIntent()
+
+ /**
+ * 打开网址
+ * @author DevTTL
+ * @date 2025/10/14
+ * @constructor 创建[OpenUrl]
+ * @param [url] 网址
+ */
+ class OpenUrl(val url:String): SettingsIntent()
+}
+
+
+/**
+ * 设置效果
+ * @author DevTTL
+ * @date 2025/10/14
+ * @constructor 创建[SettingsEffect]
+ */
+sealed class SettingsEffect {
+ /**
+ * 导航返回
+ * @author admin
+ * @date 2025/10/12
+ */
+ object NavigateBack : SettingsEffect()
+
+ /**
+ * 显示消息
+ * @author admin
+ * @date 2025/10/12
+ * @constructor 创建[ShowMessage]
+ * @param [message] 消息
+ */
+ data class ShowMessage(val message: String) : SettingsEffect()
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/data/viewmodel/SettingsViewModel.kt b/composeApp/src/commonMain/kotlin/com/taskttl/data/viewmodel/SettingsViewModel.kt
new file mode 100644
index 0000000..669989f
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/data/viewmodel/SettingsViewModel.kt
@@ -0,0 +1,58 @@
+package com.taskttl.data.viewmodel
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.taskttl.core.utils.ExternalAppLauncher
+import com.taskttl.data.state.SettingsEffect
+import com.taskttl.data.state.SettingsIntent
+import com.taskttl.data.state.SettingsState
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asSharedFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+
+/**
+ * 反馈视图模型
+ * @author admin
+ * @date 2025/10/12
+ * @constructor 创建[SettingsViewModel]
+ */
+class SettingsViewModel() : ViewModel() {
+
+ private val _state = MutableStateFlow(SettingsState())
+ val state: StateFlow = _state.asStateFlow()
+
+ private val _effects = MutableSharedFlow()
+ val effects: SharedFlow = _effects.asSharedFlow()
+
+
+ fun handleIntent(intent: SettingsIntent) {
+ when (intent) {
+ is SettingsIntent.OpenAppRating -> openAppRating()
+ is SettingsIntent.OpenUrl -> openUrl(intent.url)
+ }
+ }
+
+ private fun openAppRating() {
+ viewModelScope.launch {
+ ExternalAppLauncher.openAppRating()
+ }
+ }
+
+ private fun openUrl(url:String) {
+ viewModelScope.launch {
+ ExternalAppLauncher.openUrl(url)
+ }
+ }
+
+ /**
+ * 清除错误
+ */
+ private fun clearError() {
+ _state.value = _state.value.copy(error = null)
+ }
+
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/category/CategoryEditorScreen.kt b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/category/CategoryEditorScreen.kt
index 5693d72..6b5eae4 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/category/CategoryEditorScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/category/CategoryEditorScreen.kt
@@ -17,9 +17,6 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.grid.GridCells
-import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
-import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
@@ -48,7 +45,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
-import com.taskttl.core.ui.LoadingScreen
+import com.taskttl.core.ui.LoadingOverlay
import com.taskttl.core.utils.ToastUtils
import com.taskttl.data.local.model.Category
import com.taskttl.data.local.model.CategoryColor
@@ -56,7 +53,6 @@ import com.taskttl.data.local.model.CategoryIcon
import com.taskttl.data.local.model.CategoryType
import com.taskttl.data.state.CategoryEffect
import com.taskttl.data.state.CategoryIntent
-import com.taskttl.data.state.TaskEffect
import com.taskttl.data.viewmodel.CategoryViewModel
import com.taskttl.ui.components.AppHeader
import kotlinx.datetime.TimeZone
@@ -89,7 +85,7 @@ import kotlin.uuid.Uuid
fun CategoryEditScreen(
categoryId: String? = null,
onNavigateBack: () -> Unit,
- viewModel: CategoryViewModel = koinViewModel()
+ viewModel: CategoryViewModel = koinViewModel(),
) {
LaunchedEffect(Unit) {
viewModel.effects.collect { effect ->
@@ -173,6 +169,7 @@ fun CategoryEditScreen(
LazyColumn(
modifier = Modifier
.fillMaxSize()
+ .background(MaterialTheme.colorScheme.background)
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(24.dp)
) {
@@ -257,7 +254,7 @@ fun CategoryEditScreen(
verticalArrangement = Arrangement.spacedBy(4.dp),
modifier = Modifier.fillMaxWidth()
) {
- CategoryIcon.entries.forEach {item ->
+ CategoryIcon.entries.forEach { item ->
IconOption(
item = item,
selected = icon == item,
@@ -283,7 +280,7 @@ fun CategoryEditScreen(
}
}
}
- if (state.isLoading) LoadingScreen()
+ LoadingOverlay(state.isLoading)
}
}
@@ -296,7 +293,7 @@ private fun CategoryTypeOption(
icon: ImageVector,
text: String,
selected: Boolean,
- onClick: () -> Unit
+ onClick: () -> Unit,
) {
Card(
modifier = modifier
@@ -367,7 +364,7 @@ private fun ColorOption(
colorLong: CategoryColor,
selected: Boolean,
onClick: () -> Unit,
- modifier: Modifier
+ modifier: Modifier,
) {
Box(
modifier = modifier
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/category/CategoryScreen.kt b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/category/CategoryScreen.kt
index ffd5793..a057b69 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/category/CategoryScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/category/CategoryScreen.kt
@@ -56,7 +56,8 @@ import androidx.navigation.NavHostController
import com.taskttl.core.routes.Routes.Main
import com.taskttl.core.ui.ActionButtonListItem
import com.taskttl.core.ui.ErrorDialog
-import com.taskttl.core.ui.LoadingScreen
+import com.taskttl.core.ui.LoadingOverlay
+
import com.taskttl.core.utils.ToastUtils
import com.taskttl.data.local.model.Category
import com.taskttl.data.local.model.CategoryType
@@ -127,7 +128,7 @@ fun CategoryScreen(
Column(
modifier = Modifier
.fillMaxSize()
- .background(Color(0xFFF5F5F5))
+ .background(MaterialTheme.colorScheme.background)
.padding(16.dp)
) {
@@ -210,7 +211,7 @@ fun CategoryScreen(
contentDescription = stringResource(Res.string.title_add_category)
)
}
- if (state.isLoading) LoadingScreen()
+ LoadingOverlay(state.isLoading)
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/countdown/CountdownDetailScreen.kt b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/countdown/CountdownDetailScreen.kt
index 94fd294..5308d34 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/countdown/CountdownDetailScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/countdown/CountdownDetailScreen.kt
@@ -20,6 +20,7 @@ import androidx.compose.material.icons.filled.CalendarToday
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@@ -33,7 +34,8 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.taskttl.core.ui.Chip
-import com.taskttl.core.ui.LoadingScreen
+import com.taskttl.core.ui.LoadingOverlay
+
import com.taskttl.core.utils.DateUtils
import com.taskttl.data.state.CountdownEffect
import com.taskttl.data.viewmodel.CountdownViewModel
@@ -104,7 +106,7 @@ fun CountdownDetailScreen(
Column(
modifier = Modifier
.fillMaxSize()
- .background(Color(0xFFF5F5F5))
+ .background(MaterialTheme.colorScheme.background)
.padding(16.dp)
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
@@ -234,7 +236,7 @@ fun CountdownDetailScreen(
}
}
}
- if (state.isLoading) LoadingScreen()
+ LoadingOverlay(state.isLoading)
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/countdown/CountdownEditorScreen.kt b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/countdown/CountdownEditorScreen.kt
index 66ec587..4e0d4f7 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/countdown/CountdownEditorScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/countdown/CountdownEditorScreen.kt
@@ -1,5 +1,6 @@
package com.taskttl.presentation.countdown
+import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -40,7 +41,8 @@ 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.ui.LoadingScreen
+import com.taskttl.core.ui.LoadingOverlay
+
import com.taskttl.core.utils.ToastUtils
import com.taskttl.data.local.model.Category
import com.taskttl.data.local.model.Countdown
@@ -163,6 +165,7 @@ fun CountdownEditScreen(
Column(
modifier = Modifier
.fillMaxSize()
+ .background(MaterialTheme.colorScheme.background)
.verticalScroll(rememberScrollState())
.padding(16.dp),
) {
@@ -283,6 +286,6 @@ fun CountdownEditScreen(
}
}
}
- if (state.isLoading) LoadingScreen()
+ LoadingOverlay(state.isLoading)
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/countdown/CountdownScreen.kt b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/countdown/CountdownScreen.kt
index 079bb70..6e51e65 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/countdown/CountdownScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/countdown/CountdownScreen.kt
@@ -58,12 +58,10 @@ import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import com.taskttl.core.routes.Routes
import com.taskttl.core.ui.ErrorDialog
-import com.taskttl.core.ui.LoadingScreen
+import com.taskttl.core.ui.LoadingOverlay
import com.taskttl.core.utils.DateUtils
import com.taskttl.core.utils.ToastUtils
import com.taskttl.data.local.model.Countdown
-import com.taskttl.data.state.CategoryEffect
-import com.taskttl.data.state.CategoryIntent
import com.taskttl.data.state.CountdownEffect
import com.taskttl.data.state.CountdownIntent
import com.taskttl.data.viewmodel.CountdownViewModel
@@ -75,19 +73,18 @@ import org.koin.compose.viewmodel.koinViewModel
import taskttl.composeapp.generated.resources.Res
import taskttl.composeapp.generated.resources.delete
import taskttl.composeapp.generated.resources.desc_add_countdown
+import taskttl.composeapp.generated.resources.edit
import taskttl.composeapp.generated.resources.label_countdown_list
import taskttl.composeapp.generated.resources.label_days
-import taskttl.composeapp.generated.resources.edit
import taskttl.composeapp.generated.resources.text_add_countdown_tip
import taskttl.composeapp.generated.resources.text_no_countdowns
import taskttl.composeapp.generated.resources.title_countdown
-import taskttl.composeapp.generated.resources.title_edit_countdown
@Composable
@Preview
fun CountdownScreen(
navController: NavHostController,
- viewModel: CountdownViewModel = koinViewModel()
+ viewModel: CountdownViewModel = koinViewModel(),
) {
val state by viewModel.state.collectAsState()
@@ -97,6 +94,7 @@ fun CountdownScreen(
is CountdownEffect.ShowMessage -> {
ToastUtils.show(effect.message)
}
+
is CountdownEffect.NavigateBack -> {
navController.popBackStack()
}
@@ -125,7 +123,7 @@ fun CountdownScreen(
Column(
modifier = Modifier
.fillMaxSize()
- .background(Color(0xFFF5F5F5))
+ .background(MaterialTheme.colorScheme.background)
.padding(16.dp)
) {
// 分类筛选
@@ -220,7 +218,7 @@ fun CountdownScreen(
contentDescription = stringResource(Res.string.desc_add_countdown)
)
}
- if (state.isLoading) LoadingScreen()
+ LoadingOverlay(state.isLoading)
}
}
@@ -229,7 +227,7 @@ fun CountdownCard(
countdown: Countdown,
onEdit: () -> Unit = {},
onDelete: () -> Unit = {},
- onCardClick: () -> Unit = {}
+ onCardClick: () -> Unit = {},
) {
val countdownTime = DateUtils.calculateCountdownTime(countdown.targetDate)
countdown.category
@@ -422,7 +420,7 @@ fun IconBut(onClick: () -> Unit = {}, icon: ImageVector) {
@Composable
fun ReminderDialog(
onDismiss: () -> Unit,
- onSave: (String) -> Unit
+ onSave: (String) -> Unit,
) {
var isEnabled by remember { mutableStateOf(true) }
var timeBefore by remember { mutableStateOf("1天前") }
@@ -490,7 +488,7 @@ fun MoreActionsDialog(
onDismiss: () -> Unit,
onEdit: () -> Unit,
onShare: () -> Unit,
- onDelete: () -> Unit
+ onDelete: () -> Unit,
) {
AlertDialog(
onDismissRequest = { onDismiss() },
@@ -521,7 +519,7 @@ private fun ActionItem(
text: String,
icon: ImageVector,
danger: Boolean = false,
- onClick: () -> Unit
+ onClick: () -> Unit,
) {
Row(
modifier = Modifier
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/AboutScreen.kt b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/AboutScreen.kt
index 0f087b5..80fefda 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/AboutScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/AboutScreen.kt
@@ -1,6 +1,7 @@
package com.taskttl.presentation.settings
import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -31,15 +32,20 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
+import com.taskttl.data.state.SettingsIntent
+import com.taskttl.data.viewmodel.SettingsViewModel
import com.taskttl.ui.components.AppHeader
import org.jetbrains.compose.resources.StringResource
import org.jetbrains.compose.resources.stringResource
+import org.koin.compose.viewmodel.koinViewModel
import taskttl.composeapp.generated.resources.Res
import taskttl.composeapp.generated.resources.all_rights_reserved
import taskttl.composeapp.generated.resources.app_intro_content
import taskttl.composeapp.generated.resources.app_intro_title
import taskttl.composeapp.generated.resources.app_name
import taskttl.composeapp.generated.resources.app_name_description
+import taskttl.composeapp.generated.resources.app_version_code
+import taskttl.composeapp.generated.resources.app_version_name
import taskttl.composeapp.generated.resources.build_version
import taskttl.composeapp.generated.resources.contact_us
import taskttl.composeapp.generated.resources.copyright_year
@@ -47,6 +53,7 @@ import taskttl.composeapp.generated.resources.developer_text
import taskttl.composeapp.generated.resources.devttl_team
import taskttl.composeapp.generated.resources.email
import taskttl.composeapp.generated.resources.email_text
+import taskttl.composeapp.generated.resources.setting_privacy_email_uri
import taskttl.composeapp.generated.resources.tech_stack
import taskttl.composeapp.generated.resources.tech_stack_compose
import taskttl.composeapp.generated.resources.tech_stack_kmp
@@ -62,7 +69,8 @@ import taskttl.composeapp.generated.resources.web_url
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AboutScreen(
- onNavigateBack: () -> Unit
+ onNavigateBack: () -> Unit,
+ viewModel: SettingsViewModel = koinViewModel(),
) {
Box(modifier = Modifier.fillMaxSize()) {
Column(
@@ -77,7 +85,7 @@ fun AboutScreen(
Column(
modifier = Modifier
.fillMaxSize()
- .background(Color(0xFFF5F5F5))
+ .background(MaterialTheme.colorScheme.background)
.verticalScroll(rememberScrollState())
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
@@ -118,9 +126,15 @@ fun AboutScreen(
Column(
modifier = Modifier.padding(16.dp)
) {
- AboutInfoRow(labelRes = Res.string.version, value = "1.0.0")
+ AboutInfoRow(
+ labelRes = Res.string.version,
+ valueRes = Res.string.app_version_name
+ )
Spacer(modifier = Modifier.height(8.dp))
- AboutInfoRow(labelRes = Res.string.build_version, value = "1")
+ AboutInfoRow(
+ labelRes = Res.string.build_version,
+ valueRes = Res.string.app_version_code
+ )
}
}
Spacer(modifier = Modifier.height(16.dp))
@@ -148,29 +162,29 @@ fun AboutScreen(
}
Spacer(modifier = Modifier.height(16.dp))
// 技术栈
- Card(
- modifier = Modifier.fillMaxWidth()
- ) {
- Column(
- modifier = Modifier.padding(16.dp)
- ) {
- Text(
- text = stringResource(Res.string.tech_stack),
- style = MaterialTheme.typography.titleMedium,
- fontWeight = FontWeight.Medium
- )
-
- Spacer(modifier = Modifier.height(12.dp))
-
- TechStackItem("Kotlin Multiplatform", Res.string.tech_stack_kmp)
- TechStackItem("Jetpack Compose", Res.string.tech_stack_compose)
- TechStackItem("Room Database", Res.string.tech_stack_room)
- TechStackItem("Koin", Res.string.tech_stack_koin)
- TechStackItem("Ktor", Res.string.tech_stack_ktor)
- TechStackItem("MVI Architecture", Res.string.tech_stack_mvi)
- }
- }
- Spacer(modifier = Modifier.height(16.dp))
+ // Card(
+ // modifier = Modifier.fillMaxWidth()
+ // ) {
+ // Column(
+ // modifier = Modifier.padding(16.dp)
+ // ) {
+ // Text(
+ // text = stringResource(Res.string.tech_stack),
+ // style = MaterialTheme.typography.titleMedium,
+ // fontWeight = FontWeight.Medium
+ // )
+ //
+ // Spacer(modifier = Modifier.height(12.dp))
+ //
+ // TechStackItem("Kotlin Multiplatform", Res.string.tech_stack_kmp)
+ // TechStackItem("Jetpack Compose", Res.string.tech_stack_compose)
+ // TechStackItem("Room Database", Res.string.tech_stack_room)
+ // TechStackItem("Koin", Res.string.tech_stack_koin)
+ // TechStackItem("Ktor", Res.string.tech_stack_ktor)
+ // TechStackItem("MVI Architecture", Res.string.tech_stack_mvi)
+ // }
+ // }
+ // Spacer(modifier = Modifier.height(16.dp))
// 开发者信息
Card(
modifier = Modifier.fillMaxWidth()
@@ -208,18 +222,22 @@ fun AboutScreen(
Spacer(modifier = Modifier.height(12.dp))
+ val email = stringResource(Res.string.email)
+ val emailUrl = stringResource(Res.string.setting_privacy_email_uri, email)
ContactItem(
icon = Icons.Default.Email,
labelRes = Res.string.email_text,
- valueRes = Res.string.email
+ valueRes = Res.string.email,
+ onClick = { viewModel.handleIntent(SettingsIntent.OpenUrl(emailUrl)) }
)
Spacer(modifier = Modifier.height(8.dp))
-
+ val url = stringResource(Res.string.web_url)
ContactItem(
icon = Icons.Default.Language,
labelRes = Res.string.web_text,
- valueRes = Res.string.web_url
+ valueRes = Res.string.web_url,
+ onClick = { viewModel.handleIntent(SettingsIntent.OpenUrl(url)) }
)
}
}
@@ -243,7 +261,7 @@ fun AboutScreen(
@Composable
private fun AboutInfoRow(
labelRes: StringResource,
- value: String
+ valueRes: StringResource,
) {
Row(
modifier = Modifier.fillMaxWidth(),
@@ -255,7 +273,7 @@ private fun AboutInfoRow(
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
- text = value,
+ text = stringResource(valueRes),
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.Medium
)
@@ -265,7 +283,7 @@ private fun AboutInfoRow(
@Composable
private fun TechStackItem(
name: String,
- descriptionRes: StringResource
+ descriptionRes: StringResource,
) {
Column {
Text(
@@ -286,10 +304,13 @@ private fun TechStackItem(
private fun ContactItem(
icon: ImageVector,
labelRes: StringResource,
- valueRes: StringResource
+ valueRes: StringResource,
+ onClick: (() -> Unit)? = null,
) {
Row(
- verticalAlignment = Alignment.CenterVertically
+ modifier = Modifier.fillMaxWidth()
+ .clickable(enabled = onClick != null) { onClick?.invoke() },
+ verticalAlignment = Alignment.CenterVertically,
) {
Icon(
imageVector = icon,
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/DataManagementScreen.kt b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/DataManagementScreen.kt
index 1fb8de8..380d30c 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/DataManagementScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/DataManagementScreen.kt
@@ -100,7 +100,7 @@ fun DataManagementScreen(
LazyColumn(
modifier = Modifier
.fillMaxSize()
- .background(Color(0xFFF5F5F5))
+ .background(MaterialTheme.colorScheme.background)
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/FeedbackScreen.kt b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/FeedbackScreen.kt
index 84e1abb..a90e46d 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/FeedbackScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/FeedbackScreen.kt
@@ -42,7 +42,8 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.taskttl.core.domain.FeedbackType
import com.taskttl.core.ui.ErrorDialog
-import com.taskttl.core.ui.LoadingScreen
+import com.taskttl.core.ui.LoadingOverlay
+
import com.taskttl.core.utils.ToastUtils
import com.taskttl.data.network.domain.req.FeedbackReq
import com.taskttl.data.state.FeedbackEffect
@@ -110,7 +111,7 @@ fun FeedbackScreen(
Column(
modifier = Modifier
.fillMaxSize()
- .background(Color(0xFFF5F5F5))
+ .background(MaterialTheme.colorScheme.background)
.verticalScroll(rememberScrollState())
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
@@ -218,7 +219,7 @@ fun FeedbackScreen(
Spacer(modifier = Modifier.height(32.dp))
}
}
- if (state.isLoading) LoadingScreen()
+ LoadingOverlay(state.isLoading)
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/PrivacyScreen.kt b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/PrivacyScreen.kt
index 33b0ff7..5737786 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/PrivacyScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/PrivacyScreen.kt
@@ -4,6 +4,7 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -29,7 +30,7 @@ fun PrivacyScreen(onNavigateBack: () -> Unit) {
Column(
modifier = Modifier
.fillMaxSize()
- .background(Color(0xFFF5F5F5)),
+ .background(MaterialTheme.colorScheme.background),
) {
DevTTLWebView(
modifier = Modifier.fillMaxSize(),
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/SettingsScreen.kt b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/SettingsScreen.kt
index 449f1ba..26b47b1 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/SettingsScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/settings/SettingsScreen.kt
@@ -24,6 +24,7 @@ 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
@@ -40,10 +41,14 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
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
import org.jetbrains.compose.resources.StringResource
import org.jetbrains.compose.resources.stringResource
import org.jetbrains.compose.ui.tooling.preview.Preview
+import org.koin.compose.viewmodel.koinViewModel
import taskttl.composeapp.generated.resources.Res
import taskttl.composeapp.generated.resources.section_data_management
import taskttl.composeapp.generated.resources.section_general_settings
@@ -65,6 +70,8 @@ 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
@@ -79,6 +86,7 @@ import taskttl.composeapp.generated.resources.title_app_settings
@Preview
fun SettingsScreen(
navController: NavHostController,
+ viewModel: SettingsViewModel = koinViewModel()
) {
Box(
modifier = Modifier
@@ -96,7 +104,7 @@ fun SettingsScreen(
Column(
modifier = Modifier
.fillMaxSize()
- .background(Color(0xFFF5F5F5))
+ .background(MaterialTheme.colorScheme.background)
.verticalScroll(rememberScrollState())
.padding(16.dp)
) {
@@ -218,13 +226,18 @@ fun SettingsScreen(
showArrow = true,
onClick = { navController.navigate(Routes.Main.Settings.Privacy) }
)
+ SettingItem(
+ titleRes = Res.string.setting_privacy_rate,
+ descriptionRes = Res.string.setting_privacy_rate_desc,
+ showArrow = true,
+ onClick = { viewModel.handleIntent(SettingsIntent.OpenAppRating) }
+ )
SettingItem(
titleRes = Res.string.setting_about_app,
descriptionRes = Res.string.setting_about_app_desc,
showArrow = true,
onClick = { navController.navigate(Routes.Main.Settings.About) }
)
-
Spacer(modifier = Modifier.height(24.dp))
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/statistics/StatisticsScreen.kt b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/statistics/StatisticsScreen.kt
index e6eb763..894f70a 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/statistics/StatisticsScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/statistics/StatisticsScreen.kt
@@ -44,7 +44,7 @@ import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import com.taskttl.core.routes.Routes
import com.taskttl.core.ui.Chip
-import com.taskttl.core.ui.LoadingScreen
+
import com.taskttl.data.local.model.Category
import com.taskttl.data.state.CountdownIntent
import com.taskttl.data.state.TaskIntent
@@ -95,7 +95,7 @@ fun StatisticsScreen(
LazyColumn(
modifier = Modifier
.fillMaxSize()
- .background(Color(0xFFF5F5F5))
+ .background(MaterialTheme.colorScheme.background)
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/task/TaskDetailScreen.kt b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/task/TaskDetailScreen.kt
index 606dfca..a81e8a2 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/task/TaskDetailScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/task/TaskDetailScreen.kt
@@ -37,7 +37,8 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
-import com.taskttl.core.ui.LoadingScreen
+import com.taskttl.core.ui.LoadingOverlay
+
import com.taskttl.data.state.TaskEffect
import com.taskttl.data.state.TaskIntent
import com.taskttl.data.viewmodel.TaskViewModel
@@ -111,6 +112,7 @@ fun TaskDetailScreen(
Column(
modifier = Modifier
.fillMaxSize()
+ .background(MaterialTheme.colorScheme.background)
.verticalScroll(rememberScrollState())
.padding(16.dp),
verticalArrangement = Arrangement.Top
@@ -229,6 +231,6 @@ fun TaskDetailScreen(
}
}
- if (state.isLoading) LoadingScreen()
+ LoadingOverlay(state.isLoading)
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/task/TaskEditorScreen.kt b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/task/TaskEditorScreen.kt
index e2b42a7..8ff1d08 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/task/TaskEditorScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/task/TaskEditorScreen.kt
@@ -1,5 +1,6 @@
package com.taskttl.presentation.task
+import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -39,7 +40,8 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.taskttl.core.routes.Routes
-import com.taskttl.core.ui.LoadingScreen
+import com.taskttl.core.ui.LoadingOverlay
+
import com.taskttl.core.utils.ToastUtils
import com.taskttl.data.local.model.Category
import com.taskttl.data.local.model.Task
@@ -168,6 +170,7 @@ fun TaskEditorScreen(
Column(
modifier = Modifier
.fillMaxSize()
+ .background(MaterialTheme.colorScheme.background)
.verticalScroll(rememberScrollState())
.padding(16.dp),
) {
@@ -292,6 +295,6 @@ fun TaskEditorScreen(
)
}
}
- if (state.isLoading) LoadingScreen()
+ LoadingOverlay(state.isLoading)
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/task/TaskScreen.kt b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/task/TaskScreen.kt
index cd0b7ea..34c4f88 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/presentation/task/TaskScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/presentation/task/TaskScreen.kt
@@ -54,7 +54,8 @@ import androidx.navigation.NavHostController
import com.taskttl.core.routes.Routes
import com.taskttl.core.ui.ActionButtonListItem
import com.taskttl.core.ui.ErrorDialog
-import com.taskttl.core.ui.LoadingScreen
+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
@@ -129,7 +130,7 @@ fun TaskScreen(
Column(
modifier = Modifier
.fillMaxSize()
- .background(Color(0xFFF5F5F5))
+ .background(MaterialTheme.colorScheme.background)
.padding(16.dp)
) {
if (state.isSearch) {
@@ -258,7 +259,7 @@ fun TaskScreen(
contentDescription = stringResource(Res.string.title_add_task)
)
}
- if (state.isLoading) LoadingScreen()
+ LoadingOverlay(state.isLoading)
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/ui/components/AppHeader.kt b/composeApp/src/commonMain/kotlin/com/taskttl/ui/components/AppHeader.kt
index 4883abd..7a54f50 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/ui/components/AppHeader.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/ui/components/AppHeader.kt
@@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@@ -39,16 +40,19 @@ fun AppHeader(
showBack: Boolean = false,
onBackClick: (() -> Unit)? = null,
trailingIcon: ImageVector? = null,
- onTrailingClick: (() -> Unit)? = null
+ onTrailingClick: (() -> Unit)? = null,
) {
+ val gradient = Brush.linearGradient(
+ colors = listOf(
+ MaterialTheme.colorScheme.primary,
+ MaterialTheme.colorScheme.secondary
+ )
+ )
+
Row(
modifier = Modifier
.fillMaxWidth()
- .background(
- Brush.linearGradient(
- colors = listOf(Color(0xFF667EEA), Color(0xFF764BA2))
- )
- )
+ .background(brush = gradient)
.padding(horizontal = 20.dp, vertical = 15.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
diff --git a/composeApp/src/commonMain/kotlin/com/taskttl/ui/theme/Theme.kt b/composeApp/src/commonMain/kotlin/com/taskttl/ui/theme/Theme.kt
index d314011..b201f86 100644
--- a/composeApp/src/commonMain/kotlin/com/taskttl/ui/theme/Theme.kt
+++ b/composeApp/src/commonMain/kotlin/com/taskttl/ui/theme/Theme.kt
@@ -9,11 +9,11 @@ import androidx.compose.ui.graphics.Color
/** 浅色方案 */
private val LightColorScheme = lightColorScheme(
- primary = Color(0xFF6750A4),
+ primary = Color(0xFF667EEA),
onPrimary = Color(0xFFFFFFFF),
primaryContainer = Color(0xFFEADDFF),
onPrimaryContainer = Color(0xFF21005D),
- secondary = Color(0xFF625B71),
+ secondary = Color(0xFF764BA2),
onSecondary = Color(0xFFFFFFFF),
secondaryContainer = Color(0xFFE8DEF8),
onSecondaryContainer = Color(0xFF1D192B),
@@ -25,7 +25,7 @@ private val LightColorScheme = lightColorScheme(
onError = Color(0xFFFFFFFF),
errorContainer = Color(0xFFFFDAD6),
onErrorContainer = Color(0xFF410002),
- background = Color(0xFFFFFBFE),
+ background = Color(0xFFF5F5F5),
onBackground = Color(0xFF1C1B1F),
surface = Color(0xFFFFFBFE),
onSurface = Color(0xFF1C1B1F),
diff --git a/composeApp/src/iosMain/kotlin/com/taskttl/core/utils/Localization.ios.kt b/composeApp/src/iosMain/kotlin/com/taskttl/core/utils/Localization.ios.kt
new file mode 100644
index 0000000..c1bec28
--- /dev/null
+++ b/composeApp/src/iosMain/kotlin/com/taskttl/core/utils/Localization.ios.kt
@@ -0,0 +1,14 @@
+package com.taskttl.core.utils
+
+import platform.Foundation.NSLocale
+
+@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
+actual object Localization {
+ actual fun applyLanguage(iso: String) {
+ NSUserDefaults.standardUserDefaults.setObject(arrayListOf(iso), "AppleLanguages")
+ }
+
+ actual fun getDeviceLanguage(): String {
+ return NSLocale.currentLocale.languageCode ?: "en"
+ }
+}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index eafaac5..c975786 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -37,8 +37,8 @@ android-compileSdk = "36"
android-minSdk = "24"
android-targetSdk = "36"
-android-versionCode = "100000"
-android-versionName = "1.0.0"
+android-versionCode = "100001"
+android-versionName = "1.0.1"
android-facebookAppId = "1203530117944408"
android-facebookClientToken = "1ee2da9430c1a589e8aa623bfaaaa586"