添加对话列表、导出数据、订单和升级计划等新功能
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
package com.huaga.life_echo.ui.icons
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material.icons.outlined.*
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
|
||||
/**
|
||||
* 应用图标常量文件
|
||||
* 统一管理应用中使用的所有图标
|
||||
*/
|
||||
object AppIcons {
|
||||
// 导航栏图标
|
||||
val Chat = Icons.Default.Chat
|
||||
val Memoir = Icons.Default.MenuBook
|
||||
val Profile = Icons.Default.Person
|
||||
|
||||
// 聊天界面图标
|
||||
val ArrowBack = Icons.Default.ArrowBack
|
||||
val Mic = Icons.Default.Mic
|
||||
val MicOff = Icons.Default.MicOff
|
||||
val SentimentSatisfied = Icons.Default.SentimentSatisfied
|
||||
val Add = Icons.Default.Add
|
||||
val Send = Icons.Default.Send
|
||||
val Book = Icons.Default.MenuBook
|
||||
|
||||
// 对话列表图标
|
||||
val Conversation = Icons.Default.ChatBubble
|
||||
val DateRange = Icons.Default.DateRange
|
||||
val History = Icons.Default.History
|
||||
|
||||
// 回忆录界面图标
|
||||
val Chapter = Icons.Default.Book
|
||||
val Reading = Icons.Default.MenuBook
|
||||
val ChevronRight = Icons.Default.ChevronRight
|
||||
val Edit = Icons.Default.Edit
|
||||
val Share = Icons.Default.Share
|
||||
val Download = Icons.Default.Download
|
||||
|
||||
// 个人设置界面图标
|
||||
val Person = Icons.Default.Person
|
||||
val Upgrade = Icons.Default.Star
|
||||
val Receipt = Icons.Default.Receipt
|
||||
val FileDownload = Icons.Default.FileDownload
|
||||
val AccessTime = Icons.Default.AccessTime
|
||||
val FormatSize = Icons.Default.FormatSize
|
||||
val Brightness2 = Icons.Default.Brightness2
|
||||
val Settings = Icons.Default.Settings
|
||||
val Help = Icons.Default.Help
|
||||
val Info = Icons.Default.Info
|
||||
|
||||
// 其他常用图标
|
||||
val Check = Icons.Default.Check
|
||||
val Close = Icons.Default.Close
|
||||
val Delete = Icons.Default.Delete
|
||||
val MoreVert = Icons.Default.MoreVert
|
||||
val Search = Icons.Default.Search
|
||||
val Filter = Icons.Default.FilterList
|
||||
val Refresh = Icons.Default.Refresh
|
||||
val Favorite = Icons.Default.Favorite
|
||||
val FavoriteBorder = Icons.Default.FavoriteBorder
|
||||
val Star = Icons.Default.Star
|
||||
val StarBorder = Icons.Default.StarBorder
|
||||
|
||||
// 状态图标
|
||||
val Online = Icons.Default.Circle
|
||||
val Offline = Icons.Outlined.Circle
|
||||
val CheckCircle = Icons.Default.CheckCircle
|
||||
val Error = Icons.Default.Error
|
||||
val Warning = Icons.Default.Warning
|
||||
val InfoCircle = Icons.Default.Info
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
package com.huaga.life_echo.ui.screens
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.*
|
||||
import com.huaga.life_echo.ui.icons.AppIcons
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.huaga.life_echo.data.database.Conversation
|
||||
import com.huaga.life_echo.ui.theme.LightPurple
|
||||
import com.huaga.life_echo.ui.viewmodel.ConversationListViewModel
|
||||
import com.huaga.life_echo.ui.viewmodel.ViewModelFactory
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
@Composable
|
||||
fun ConversationListScreen(
|
||||
onConversationClick: (String) -> Unit = {},
|
||||
viewModel: ConversationListViewModel = viewModel(
|
||||
factory = ViewModelFactory(LocalContext.current)
|
||||
)
|
||||
) {
|
||||
val conversations by viewModel.conversations.collectAsState(initial = emptyList())
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
// 浅紫色标题栏
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
color = LightPurple
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.windowInsetsPadding(WindowInsets.statusBars)
|
||||
.padding(top = 16.dp, bottom = 24.dp, start = 16.dp, end = 16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text(
|
||||
text = "往事拾遗",
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = Color.White
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
text = "用对话,留住珍贵的记忆",
|
||||
fontSize = 14.sp,
|
||||
color = Color.White.copy(alpha = 0.9f)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 对话列表区域
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
) {
|
||||
Text(
|
||||
text = "我的对话",
|
||||
modifier = Modifier.padding(16.dp, 16.dp, 16.dp, 8.dp),
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
|
||||
if (conversations.isEmpty()) {
|
||||
// 空状态 - 显示示例对话项
|
||||
ConversationItem(
|
||||
conversation = Conversation(
|
||||
id = "demo",
|
||||
userId = "user",
|
||||
startedAt = System.currentTimeMillis(),
|
||||
endedAt = null,
|
||||
durationSeconds = 0,
|
||||
summary = "您想从哪里开始呢?可以聊聊童年...",
|
||||
currentTopic = null,
|
||||
conversationStage = null
|
||||
),
|
||||
onClick = { onConversationClick("demo") }
|
||||
)
|
||||
} else {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
items(conversations) { conversation ->
|
||||
ConversationItem(
|
||||
conversation = conversation,
|
||||
onClick = { onConversationClick(conversation.id) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ConversationItem(
|
||||
conversation: Conversation,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
val timeText = if (conversation.endedAt != null) {
|
||||
val date = Date(conversation.endedAt)
|
||||
val now = Date()
|
||||
val diff = now.time - date.time
|
||||
when {
|
||||
diff < 60000 -> "刚刚"
|
||||
diff < 3600000 -> "${diff / 60000}分钟前"
|
||||
diff < 86400000 -> "${diff / 3600000}小时前"
|
||||
else -> SimpleDateFormat("MM月dd日", Locale.getDefault()).format(date)
|
||||
}
|
||||
} else {
|
||||
"刚刚"
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { onClick() }
|
||||
.padding(vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// 浅紫色图标背景
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.background(LightPurple),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Icon(
|
||||
imageVector = AppIcons.Conversation,
|
||||
contentDescription = "对话",
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
|
||||
// 对话信息
|
||||
Column(
|
||||
modifier = Modifier.weight(1f)
|
||||
) {
|
||||
Text(
|
||||
text = "回忆录助手",
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
text = conversation.summary ?: conversation.currentTopic ?: "您想从哪里开始呢?可以聊聊童年...",
|
||||
fontSize = 14.sp,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
maxLines = 1
|
||||
)
|
||||
}
|
||||
|
||||
// 时间戳
|
||||
Text(
|
||||
text = timeText,
|
||||
fontSize = 12.sp,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(start = 8.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package com.huaga.life_echo.ui.screens
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.CheckCircle
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
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.huaga.life_echo.ui.icons.AppIcons
|
||||
import com.huaga.life_echo.ui.theme.LightPurple
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ExportDataScreen(
|
||||
navController: androidx.navigation.NavHostController? = null
|
||||
) {
|
||||
var isExporting by remember { mutableStateOf(false) }
|
||||
var exportCompleted by remember { mutableStateOf(false) }
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text("导出所有数据") },
|
||||
navigationIcon = {
|
||||
IconButton(onClick = { navController?.popBackStack() }) {
|
||||
Icon(
|
||||
imageVector = AppIcons.ArrowBack,
|
||||
contentDescription = "返回"
|
||||
)
|
||||
}
|
||||
},
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = LightPurple,
|
||||
titleContentColor = Color.White,
|
||||
navigationIconContentColor = Color.White
|
||||
)
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
// 说明信息
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "导出说明",
|
||||
fontSize = 18.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Text(
|
||||
text = "导出数据将包含:",
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
listOf(
|
||||
"所有对话记录",
|
||||
"回忆录内容",
|
||||
"章节信息",
|
||||
"用户设置"
|
||||
).forEach { item ->
|
||||
Row(
|
||||
modifier = Modifier.padding(vertical = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "• ",
|
||||
fontSize = 14.sp,
|
||||
color = LightPurple,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Text(
|
||||
text = item,
|
||||
fontSize = 14.sp,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 导出格式选择
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "选择导出格式",
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
listOf("JSON", "CSV", "PDF").forEach { format ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
RadioButton(
|
||||
selected = false, // TODO: 管理选中状态
|
||||
onClick = { /* TODO */ }
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = format,
|
||||
fontSize = 14.sp,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
// 导出按钮
|
||||
Button(
|
||||
onClick = {
|
||||
isExporting = true
|
||||
// TODO: 执行导出操作
|
||||
// 模拟导出完成
|
||||
scope.launch {
|
||||
delay(2000)
|
||||
isExporting = false
|
||||
exportCompleted = true
|
||||
}
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
enabled = !isExporting && !exportCompleted,
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = LightPurple
|
||||
)
|
||||
) {
|
||||
if (isExporting) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(20.dp),
|
||||
color = Color.White
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text("导出中...", color = Color.White)
|
||||
} else if (exportCompleted) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.CheckCircle,
|
||||
contentDescription = "完成",
|
||||
tint = Color.White
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text("导出完成", color = Color.White)
|
||||
} else {
|
||||
Text("开始导出", color = Color.White)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
package com.huaga.life_echo.ui.screens
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
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.huaga.life_echo.ui.icons.AppIcons
|
||||
import com.huaga.life_echo.ui.theme.LightPurple
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun MyOrdersScreen(
|
||||
navController: androidx.navigation.NavHostController? = null
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text("我的订单") },
|
||||
navigationIcon = {
|
||||
IconButton(onClick = { navController?.popBackStack() }) {
|
||||
Icon(
|
||||
imageVector = AppIcons.ArrowBack,
|
||||
contentDescription = "返回"
|
||||
)
|
||||
}
|
||||
},
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = LightPurple,
|
||||
titleContentColor = Color.White,
|
||||
navigationIconContentColor = Color.White
|
||||
)
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
.background(MaterialTheme.colorScheme.background),
|
||||
contentPadding = PaddingValues(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
// 示例订单
|
||||
item {
|
||||
OrderCard(
|
||||
orderId = "ORD20240101001",
|
||||
planName = "高级版",
|
||||
price = "¥29",
|
||||
date = "2024年1月1日",
|
||||
status = "已完成"
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
OrderCard(
|
||||
orderId = "ORD20231215002",
|
||||
planName = "专业版",
|
||||
price = "¥99",
|
||||
date = "2023年12月15日",
|
||||
status = "已完成"
|
||||
)
|
||||
}
|
||||
|
||||
// 空状态提示
|
||||
if (false) { // 当没有订单时显示
|
||||
item {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 64.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text(
|
||||
text = "暂无订单",
|
||||
fontSize = 18.sp,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = "升级套餐后,订单将显示在这里",
|
||||
fontSize = 14.sp,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun OrderCard(
|
||||
orderId: String,
|
||||
planName: String,
|
||||
price: String,
|
||||
date: String,
|
||||
status: String
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = planName,
|
||||
fontSize = 18.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
Text(
|
||||
text = status,
|
||||
fontSize = 14.sp,
|
||||
color = LightPurple,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Text(
|
||||
text = "订单号: $orderId",
|
||||
fontSize = 12.sp,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
|
||||
Text(
|
||||
text = "日期: $date",
|
||||
fontSize = 12.sp,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "金额",
|
||||
fontSize = 14.sp,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
Text(
|
||||
text = price,
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = LightPurple
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
package com.huaga.life_echo.ui.screens
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.CheckCircle
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
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.huaga.life_echo.ui.icons.AppIcons
|
||||
import com.huaga.life_echo.ui.theme.LightPurple
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun UpgradePlanScreen(
|
||||
navController: androidx.navigation.NavHostController? = null
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text("升级套餐") },
|
||||
navigationIcon = {
|
||||
IconButton(onClick = { navController?.popBackStack() }) {
|
||||
Icon(
|
||||
imageVector = AppIcons.ArrowBack,
|
||||
contentDescription = "返回"
|
||||
)
|
||||
}
|
||||
},
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = LightPurple,
|
||||
titleContentColor = Color.White,
|
||||
navigationIconContentColor = Color.White
|
||||
)
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
.background(MaterialTheme.colorScheme.background),
|
||||
contentPadding = PaddingValues(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
item {
|
||||
Text(
|
||||
text = "选择套餐",
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
|
||||
// 免费版
|
||||
item {
|
||||
PlanCard(
|
||||
title = "免费体验版",
|
||||
price = "免费",
|
||||
features = listOf(
|
||||
"基础对话功能",
|
||||
"每月3次对话",
|
||||
"基础回忆录整理"
|
||||
),
|
||||
isSelected = true,
|
||||
onClick = { }
|
||||
)
|
||||
}
|
||||
|
||||
// 高级版
|
||||
item {
|
||||
PlanCard(
|
||||
title = "高级版",
|
||||
price = "¥29/月",
|
||||
features = listOf(
|
||||
"无限对话次数",
|
||||
"完整回忆录导出",
|
||||
"PDF格式导出",
|
||||
"优先客服支持",
|
||||
"数据云端同步"
|
||||
),
|
||||
isSelected = false,
|
||||
onClick = { /* TODO: 购买 */ }
|
||||
)
|
||||
}
|
||||
|
||||
// 专业版
|
||||
item {
|
||||
PlanCard(
|
||||
title = "专业版",
|
||||
price = "¥99/月",
|
||||
features = listOf(
|
||||
"高级版所有功能",
|
||||
"AI智能整理",
|
||||
"多格式导出(PDF、Word、EPUB)",
|
||||
"专属客服支持",
|
||||
"无限云端存储",
|
||||
"多设备同步"
|
||||
),
|
||||
isSelected = false,
|
||||
onClick = { /* TODO: 购买 */ }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PlanCard(
|
||||
title: String,
|
||||
price: String,
|
||||
features: List<String>,
|
||||
isSelected: Boolean,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = if (isSelected) LightPurple.copy(alpha = 0.1f) else MaterialTheme.colorScheme.surface
|
||||
),
|
||||
border = if (isSelected) {
|
||||
androidx.compose.foundation.BorderStroke(2.dp, LightPurple)
|
||||
} else null
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(20.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
if (isSelected) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.CheckCircle,
|
||||
contentDescription = "当前套餐",
|
||||
tint = LightPurple,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Text(
|
||||
text = price,
|
||||
fontSize = 18.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = LightPurple
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
features.forEach { feature ->
|
||||
Row(
|
||||
modifier = Modifier.padding(vertical = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "• ",
|
||||
fontSize = 16.sp,
|
||||
color = LightPurple,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Text(
|
||||
text = feature,
|
||||
fontSize = 14.sp,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (!isSelected) {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Button(
|
||||
onClick = onClick,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = LightPurple
|
||||
)
|
||||
) {
|
||||
Text("立即升级", color = Color.White)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.huaga.life_echo.ui.settings
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
|
||||
/**
|
||||
* 应用设置管理
|
||||
*/
|
||||
object AppSettings {
|
||||
// 语速设置:慢速、标准、快速
|
||||
enum class SpeechRate(val label: String, val multiplier: Float) {
|
||||
SLOW("慢速", 0.75f),
|
||||
STANDARD("标准", 1.0f),
|
||||
FAST("快速", 1.5f)
|
||||
}
|
||||
|
||||
private val _speechRate = mutableStateOf(SpeechRate.STANDARD)
|
||||
var speechRate: SpeechRate
|
||||
get() = _speechRate.value
|
||||
set(value) { _speechRate.value = value }
|
||||
|
||||
private val _largeFontMode = mutableStateOf(false)
|
||||
var largeFontMode: Boolean
|
||||
get() = _largeFontMode.value
|
||||
set(value) { _largeFontMode.value = value }
|
||||
|
||||
private val _darkMode = mutableStateOf(false)
|
||||
var darkMode: Boolean
|
||||
get() = _darkMode.value
|
||||
set(value) { _darkMode.value = value }
|
||||
|
||||
// 用于在Compose中观察设置变化 - 直接返回mutableStateOf的值
|
||||
@Composable
|
||||
fun rememberDarkMode(): Boolean {
|
||||
return remember { _darkMode }.value
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun rememberLargeFontMode(): Boolean {
|
||||
return remember { _largeFontMode }.value
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun rememberSpeechRate(): SpeechRate {
|
||||
return remember { _speechRate }.value
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.huaga.life_echo.ui.viewmodel
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.huaga.life_echo.data.repository.ConversationRepository
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
class ConversationListViewModel(
|
||||
conversationRepository: ConversationRepository
|
||||
) : ViewModel() {
|
||||
|
||||
val conversations = conversationRepository.getAllConversations()
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5000),
|
||||
initialValue = emptyList()
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user