更新
This commit is contained in:
@@ -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<String, Any> = mapOf(
|
||||
"eventName" to eventName,
|
||||
"eventCode" to eventCode,
|
||||
)
|
||||
fun toMap(): Map<String, Any> = mapOf("eventName" to eventName, "eventCode" to eventCode)
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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<Color>,
|
||||
) {
|
||||
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)
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
// enum class LogLevel { DEBUG, INFO, WARN, ERROR }
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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<SettingsState> = _state.asStateFlow()
|
||||
|
||||
private val _effects = MutableSharedFlow<SettingsEffect>()
|
||||
val effects: SharedFlow<SettingsEffect> = _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)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user