refactor: 优化前端功能屏幕
- 优化ConversationListScreen对话列表页面 - 优化CreateMemoryScreen创建回忆页面 - 优化MyMemoirScreen我的回忆录页面 - 优化ProfileScreen个人资料页面 - 优化ExportDataScreen导出数据页面 - 优化AboutScreen关于页面
This commit is contained in:
@@ -160,7 +160,7 @@ fun AboutScreen(
|
|||||||
|
|
||||||
// 版权信息
|
// 版权信息
|
||||||
Text(
|
Text(
|
||||||
text = "© 2024 Life Echo. All rights reserved.",
|
text = "© 2026 Life Echo. All rights reserved.",
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
modifier = Modifier.padding(top = 16.dp)
|
modifier = Modifier.padding(top = 16.dp)
|
||||||
|
|||||||
@@ -1,22 +1,26 @@
|
|||||||
package com.huaga.life_echo.ui.screens
|
package com.huaga.life_echo.ui.screens
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.huaga.life_echo.data.database.Conversation
|
|
||||||
import com.huaga.life_echo.network.models.ConversationListItemDto
|
import com.huaga.life_echo.network.models.ConversationListItemDto
|
||||||
import com.huaga.life_echo.ui.components.common.EmptyStateView
|
import com.huaga.life_echo.ui.components.common.EmptyStateView
|
||||||
import com.huaga.life_echo.ui.components.common.LoadingIndicator
|
import com.huaga.life_echo.ui.components.common.LoadingIndicator
|
||||||
@@ -24,6 +28,7 @@ import com.huaga.life_echo.ui.components.conversation.ConversationListHeader
|
|||||||
import com.huaga.life_echo.ui.components.conversation.ConversationListItem
|
import com.huaga.life_echo.ui.components.conversation.ConversationListItem
|
||||||
import com.huaga.life_echo.ui.viewmodel.ConversationListViewModel
|
import com.huaga.life_echo.ui.viewmodel.ConversationListViewModel
|
||||||
import com.huaga.life_echo.ui.viewmodel.ViewModelFactory
|
import com.huaga.life_echo.ui.viewmodel.ViewModelFactory
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ConversationListScreen(
|
fun ConversationListScreen(
|
||||||
@@ -41,11 +46,26 @@ fun ConversationListScreen(
|
|||||||
viewModel.refreshConversations()
|
viewModel.refreshConversations()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
// 处理新建对话
|
||||||
|
val handleCreateConversation: () -> Unit = {
|
||||||
|
scope.launch {
|
||||||
|
val result = viewModel.createConversation()
|
||||||
|
result.fold(
|
||||||
|
onSuccess = { conversationId ->
|
||||||
|
onConversationClick(conversationId)
|
||||||
|
},
|
||||||
|
onFailure = { exception ->
|
||||||
|
// 错误处理可以在这里添加
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
// 使用新的头部组件
|
|
||||||
ConversationListHeader()
|
|
||||||
|
|
||||||
// 对话列表区域
|
// 对话列表区域
|
||||||
Column(
|
Column(
|
||||||
@@ -53,6 +73,7 @@ fun ConversationListScreen(
|
|||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.background(MaterialTheme.colorScheme.background)
|
.background(MaterialTheme.colorScheme.background)
|
||||||
) {
|
) {
|
||||||
|
ConversationListHeader(onCreateConversation = handleCreateConversation)
|
||||||
Text(
|
Text(
|
||||||
text = "我的对话",
|
text = "我的对话",
|
||||||
modifier = Modifier.padding(16.dp, 16.dp, 16.dp, 8.dp),
|
modifier = Modifier.padding(16.dp, 16.dp, 16.dp, 8.dp),
|
||||||
@@ -66,12 +87,20 @@ fun ConversationListScreen(
|
|||||||
LoadingIndicator()
|
LoadingIndicator()
|
||||||
}
|
}
|
||||||
error != null -> {
|
error != null -> {
|
||||||
// 即使有错误,也显示默认对话
|
// 显示错误信息
|
||||||
DefaultConversationItem(onClick = { onConversationClick("demo") })
|
EmptyStateView(
|
||||||
|
title = "加载失败",
|
||||||
|
message = error ?: "未知错误",
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
conversations.isEmpty() -> {
|
conversations.isEmpty() -> {
|
||||||
// 空状态 - 显示默认对话
|
// 空状态 - 提示用户创建新对话
|
||||||
DefaultConversationItem(onClick = { onConversationClick("demo") })
|
EmptyStateView(
|
||||||
|
title = "还没有对话",
|
||||||
|
message = "点击上方「新建对话」按钮开始您的回忆录之旅",
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
@@ -92,7 +121,12 @@ fun ConversationListScreen(
|
|||||||
)
|
)
|
||||||
ConversationListItem(
|
ConversationListItem(
|
||||||
conversation = dto,
|
conversation = dto,
|
||||||
onClick = { onConversationClick(conversation.id) }
|
onClick = { onConversationClick(conversation.id) },
|
||||||
|
onDelete = {
|
||||||
|
scope.launch {
|
||||||
|
viewModel.deleteConversation(conversation.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,19 +136,3 @@ fun ConversationListScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun DefaultConversationItem(onClick: () -> Unit) {
|
|
||||||
val defaultDto = ConversationListItemDto(
|
|
||||||
id = "demo",
|
|
||||||
title = "回忆录助手",
|
|
||||||
avatarUrl = null,
|
|
||||||
latestMessagePreview = "您想从哪里开始呢?可以聊聊童年...",
|
|
||||||
latestMessageTime = System.currentTimeMillis(),
|
|
||||||
unreadCount = 0,
|
|
||||||
isDefaultAssistant = true
|
|
||||||
)
|
|
||||||
ConversationListItem(
|
|
||||||
conversation = defaultDto,
|
|
||||||
onClick = onClick
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
|||||||
import com.huaga.life_echo.data.database.Message
|
import com.huaga.life_echo.data.database.Message
|
||||||
import com.huaga.life_echo.network.models.MessageDto
|
import com.huaga.life_echo.network.models.MessageDto
|
||||||
import com.huaga.life_echo.ui.components.chat.*
|
import com.huaga.life_echo.ui.components.chat.*
|
||||||
|
import com.huaga.life_echo.ui.components.debug.WebSocketDebugPanel
|
||||||
import com.huaga.life_echo.ui.theme.LightPurple
|
import com.huaga.life_echo.ui.theme.LightPurple
|
||||||
import com.huaga.life_echo.ui.viewmodel.CreateMemoryViewModel
|
import com.huaga.life_echo.ui.viewmodel.CreateMemoryViewModel
|
||||||
import com.huaga.life_echo.ui.viewmodel.ViewModelFactory
|
import com.huaga.life_echo.ui.viewmodel.ViewModelFactory
|
||||||
@@ -39,32 +40,58 @@ fun CreateMemoryScreen(
|
|||||||
val agentResponse by viewModel.agentResponse.collectAsState()
|
val agentResponse by viewModel.agentResponse.collectAsState()
|
||||||
val connectionStatus by viewModel.connectionStatus.collectAsState()
|
val connectionStatus by viewModel.connectionStatus.collectAsState()
|
||||||
val userMessages by viewModel.userMessages.collectAsState()
|
val userMessages by viewModel.userMessages.collectAsState()
|
||||||
|
val historyMessages by viewModel.historyMessages.collectAsState()
|
||||||
val isStreaming by viewModel.isStreaming.collectAsState()
|
val isStreaming by viewModel.isStreaming.collectAsState()
|
||||||
val streamingText by viewModel.streamingText.collectAsState()
|
val streamingText by viewModel.streamingText.collectAsState()
|
||||||
val isTyping by viewModel.isTyping.collectAsState()
|
val isTyping by viewModel.isTyping.collectAsState()
|
||||||
|
|
||||||
|
// 调试信息
|
||||||
|
val wsIsConnected by viewModel.wsIsConnected.collectAsState()
|
||||||
|
val lastMessageType by viewModel.lastMessageType.collectAsState()
|
||||||
|
val lastMessageTime by viewModel.lastMessageTime.collectAsState()
|
||||||
|
val errorMessages by viewModel.errorMessages.collectAsState()
|
||||||
|
val messageCount by viewModel.messageCount.collectAsState()
|
||||||
|
val conversationIdState by viewModel.conversationId.collectAsState()
|
||||||
|
|
||||||
|
// 初始化对话
|
||||||
|
LaunchedEffect(conversationId) {
|
||||||
|
if (conversationId != "new") {
|
||||||
|
viewModel.initializeConversation(conversationId)
|
||||||
|
} else {
|
||||||
|
// 如果是新建对话,启动新对话
|
||||||
|
viewModel.startConversation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 输入框状态
|
// 输入框状态
|
||||||
var inputText by remember { mutableStateOf("") }
|
var inputText by remember { mutableStateOf("") }
|
||||||
val keyboardController = LocalSoftwareKeyboardController.current
|
val keyboardController = LocalSoftwareKeyboardController.current
|
||||||
|
|
||||||
// 构建消息列表
|
// 构建消息列表(包含历史消息和当前消息)
|
||||||
val messages = remember(userMessages, agentResponse) {
|
val messages = remember(historyMessages, userMessages, agentResponse) {
|
||||||
buildList {
|
buildList {
|
||||||
// 添加用户消息
|
// 先添加历史消息
|
||||||
|
addAll(historyMessages)
|
||||||
|
|
||||||
|
// 添加当前会话的用户消息(排除已存在的)
|
||||||
|
val existingUserMessageIds = historyMessages.filter { it.senderType == "user" }.map { it.content }.toSet()
|
||||||
userMessages.forEachIndexed { index, text ->
|
userMessages.forEachIndexed { index, text ->
|
||||||
add(MessageDto(
|
if (!existingUserMessageIds.contains(text)) {
|
||||||
id = "user_$index",
|
add(MessageDto(
|
||||||
conversationId = conversationId,
|
id = "user_${historyMessages.size + index}",
|
||||||
content = text,
|
conversationId = conversationId,
|
||||||
senderType = "user",
|
content = text,
|
||||||
timestamp = System.currentTimeMillis() - (userMessages.size - index) * 1000L,
|
senderType = "user",
|
||||||
messageType = "text"
|
timestamp = System.currentTimeMillis() - (userMessages.size - index) * 1000L,
|
||||||
))
|
messageType = "text"
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 添加AI回复
|
|
||||||
if (agentResponse.isNotEmpty()) {
|
// 添加AI回复(如果不在历史消息中)
|
||||||
|
if (agentResponse.isNotEmpty() && !historyMessages.any { it.content == agentResponse && it.senderType == "assistant" }) {
|
||||||
add(MessageDto(
|
add(MessageDto(
|
||||||
id = "ai_response",
|
id = "ai_response_${historyMessages.size + userMessages.size}",
|
||||||
conversationId = conversationId,
|
conversationId = conversationId,
|
||||||
content = agentResponse,
|
content = agentResponse,
|
||||||
senderType = "assistant",
|
senderType = "assistant",
|
||||||
@@ -72,7 +99,7 @@ fun CreateMemoryScreen(
|
|||||||
messageType = "text"
|
messageType = "text"
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}.sortedBy { it.timestamp } // 按时间排序
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
@@ -85,6 +112,22 @@ fun CreateMemoryScreen(
|
|||||||
onBackClick = { navController?.popBackStack() }
|
onBackClick = { navController?.popBackStack() }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// WebSocket调试面板(开发测试用)
|
||||||
|
WebSocketDebugPanel(
|
||||||
|
connectionStatus = connectionStatus,
|
||||||
|
conversationId = conversationIdState,
|
||||||
|
isConnected = wsIsConnected,
|
||||||
|
isStreaming = isStreaming,
|
||||||
|
isTyping = isTyping,
|
||||||
|
lastMessageType = lastMessageType,
|
||||||
|
lastMessageTime = lastMessageTime,
|
||||||
|
errorMessages = errorMessages,
|
||||||
|
messageCount = messageCount,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
|
)
|
||||||
|
|
||||||
// 使用新的MessageList组件(包含所有消息、流式内容和输入指示器)
|
// 使用新的MessageList组件(包含所有消息、流式内容和输入指示器)
|
||||||
MessageList(
|
MessageList(
|
||||||
messages = messages,
|
messages = messages,
|
||||||
|
|||||||
@@ -149,42 +149,40 @@ fun ExportDataScreen(
|
|||||||
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
// 导出按钮
|
// 导出按钮 - 显示开发中提示
|
||||||
|
var showDevDialog by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
isExporting = true
|
showDevDialog = true
|
||||||
// TODO: 执行导出操作
|
|
||||||
// 模拟导出完成
|
|
||||||
scope.launch {
|
|
||||||
delay(2000)
|
|
||||||
isExporting = false
|
|
||||||
exportCompleted = true
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
enabled = !isExporting && !exportCompleted,
|
|
||||||
colors = ButtonDefaults.buttonColors(
|
colors = ButtonDefaults.buttonColors(
|
||||||
containerColor = LightPurple
|
containerColor = LightPurple
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
if (isExporting) {
|
Text("开始导出", color = Color.White)
|
||||||
CircularProgressIndicator(
|
}
|
||||||
modifier = Modifier.size(20.dp),
|
|
||||||
color = Color.White
|
// 开发中提示对话框
|
||||||
)
|
if (showDevDialog) {
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
AlertDialog(
|
||||||
Text("导出中...", color = Color.White)
|
onDismissRequest = { showDevDialog = false },
|
||||||
} else if (exportCompleted) {
|
title = { Text("功能开发中") },
|
||||||
Icon(
|
text = {
|
||||||
imageVector = Icons.Default.CheckCircle,
|
Text(
|
||||||
contentDescription = "完成",
|
text = "导出所有数据功能正在开发中,敬请期待!",
|
||||||
tint = Color.White
|
modifier = Modifier.wrapContentHeight()
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
},
|
||||||
Text("导出完成", color = Color.White)
|
confirmButton = {
|
||||||
} else {
|
TextButton(
|
||||||
Text("开始导出", color = Color.White)
|
onClick = { showDevDialog = false }
|
||||||
}
|
) {
|
||||||
|
Text("确定", color = LightPurple)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.huaga.life_echo.ui.screens
|
package com.huaga.life_echo.ui.screens
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.compose.animation.*
|
import androidx.compose.animation.*
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
@@ -18,21 +20,33 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
|
||||||
import com.huaga.life_echo.data.database.Chapter
|
import com.huaga.life_echo.data.database.Chapter
|
||||||
import com.huaga.life_echo.network.models.ChapterContentDto
|
import com.huaga.life_echo.network.models.ChapterContentDto
|
||||||
import com.huaga.life_echo.network.models.ChapterDto
|
import com.huaga.life_echo.network.models.ChapterDto
|
||||||
import com.huaga.life_echo.ui.components.memoir.*
|
import com.huaga.life_echo.ui.components.memoir.*
|
||||||
|
import com.huaga.life_echo.ui.components.common.EmptyStateView
|
||||||
import com.huaga.life_echo.ui.theme.LightPurple
|
import com.huaga.life_echo.ui.theme.LightPurple
|
||||||
import com.huaga.life_echo.ui.viewmodel.MyMemoirViewModel
|
import com.huaga.life_echo.ui.viewmodel.MyMemoirViewModel
|
||||||
import com.huaga.life_echo.ui.viewmodel.ViewModelFactory
|
import com.huaga.life_echo.ui.viewmodel.ViewModelFactory
|
||||||
|
import com.huaga.life_echo.ui.viewmodel.ConversationListViewModel
|
||||||
import com.huaga.life_echo.ui.icons.AppIcons
|
import com.huaga.life_echo.ui.icons.AppIcons
|
||||||
|
import com.huaga.life_echo.network.models.ConversationListItemDto
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
@Composable
|
@Composable
|
||||||
fun MyMemoirScreen(
|
fun MyMemoirScreen(
|
||||||
navController: androidx.navigation.NavHostController? = null,
|
navController: androidx.navigation.NavHostController? = null,
|
||||||
viewModel: MyMemoirViewModel = viewModel(
|
viewModel: MyMemoirViewModel = viewModel(
|
||||||
factory = ViewModelFactory(LocalContext.current)
|
factory = ViewModelFactory(LocalContext.current)
|
||||||
|
),
|
||||||
|
conversationListViewModel: ConversationListViewModel = viewModel(
|
||||||
|
factory = ViewModelFactory(LocalContext.current)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
val chapters by viewModel.chapters.collectAsState(initial = emptyList())
|
val chapters by viewModel.chapters.collectAsState(initial = emptyList())
|
||||||
@@ -40,7 +54,53 @@ fun MyMemoirScreen(
|
|||||||
val isLoading by viewModel.isLoading.collectAsState()
|
val isLoading by viewModel.isLoading.collectAsState()
|
||||||
val bookInfo by viewModel.bookInfo.collectAsState()
|
val bookInfo by viewModel.bookInfo.collectAsState()
|
||||||
val showFullTextReading by viewModel.showFullTextReading.collectAsState()
|
val showFullTextReading by viewModel.showFullTextReading.collectAsState()
|
||||||
var selectedTab by remember { mutableStateOf(0) }
|
|
||||||
|
// 整理对话相关状态
|
||||||
|
var showOrganizeDialog by remember { mutableStateOf(false) }
|
||||||
|
var showOrganizeSuccessDialog by remember { mutableStateOf(false) }
|
||||||
|
val conversations by conversationListViewModel.conversations.collectAsState(initial = emptyList())
|
||||||
|
val conversationsLoading by conversationListViewModel.isLoading.collectAsState()
|
||||||
|
val isOrganizing by viewModel.isOrganizing.collectAsState()
|
||||||
|
val organizingProgress by viewModel.organizingProgress.collectAsState()
|
||||||
|
val organizingStatus by viewModel.organizingStatus.collectAsState()
|
||||||
|
|
||||||
|
// 下拉刷新状态
|
||||||
|
var isRefreshing by remember { mutableStateOf(false) }
|
||||||
|
val refreshScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
// 下拉刷新处理
|
||||||
|
fun handleRefresh() {
|
||||||
|
refreshScope.launch {
|
||||||
|
isRefreshing = true
|
||||||
|
viewModel.refreshChapters()
|
||||||
|
viewModel.loadBookInfo()
|
||||||
|
// 等待刷新完成
|
||||||
|
kotlinx.coroutines.delay(500)
|
||||||
|
isRefreshing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载对话列表(转换为ConversationListItemDto格式)
|
||||||
|
val conversationDtos = remember(conversations) {
|
||||||
|
conversations.map { conv ->
|
||||||
|
ConversationListItemDto(
|
||||||
|
id = conv.id,
|
||||||
|
title = conv.title ?: "回忆录助手",
|
||||||
|
avatarUrl = conv.avatarUrl,
|
||||||
|
latestMessagePreview = conv.latestMessagePreview,
|
||||||
|
latestMessageTime = conv.latestMessageTime ?: conv.startedAt,
|
||||||
|
unreadCount = 0,
|
||||||
|
isDefaultAssistant = conv.title == null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载对话列表
|
||||||
|
LaunchedEffect(showOrganizeDialog) {
|
||||||
|
if (showOrganizeDialog) {
|
||||||
|
conversationListViewModel.refreshConversations()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 加载书籍信息
|
// 加载书籍信息
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
@@ -104,31 +164,18 @@ fun MyMemoirScreen(
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Column(modifier = Modifier.fillMaxSize()) {
|
Column(modifier = Modifier.fillMaxSize()) {
|
||||||
// 顶部标签页
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
|
||||||
) {
|
|
||||||
TabButton(
|
|
||||||
text = "目录",
|
|
||||||
selected = selectedTab == 0,
|
|
||||||
onClick = { selectedTab = 0 },
|
|
||||||
modifier = Modifier.padding(end = 24.dp)
|
|
||||||
)
|
|
||||||
TabButton(
|
|
||||||
text = "正在阅读",
|
|
||||||
selected = selectedTab == 1,
|
|
||||||
onClick = { selectedTab = 1 }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedChapter == null) {
|
if (selectedChapter == null) {
|
||||||
// 目录视图
|
// 目录视图(带下拉刷新)
|
||||||
LazyColumn(
|
PullToRefreshBox(
|
||||||
modifier = Modifier.fillMaxSize(),
|
isRefreshing = isRefreshing,
|
||||||
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 16.dp)
|
onRefresh = { handleRefresh() },
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 16.dp),
|
||||||
|
state = rememberLazyListState()
|
||||||
|
) {
|
||||||
// 书籍信息卡片
|
// 书籍信息卡片
|
||||||
item {
|
item {
|
||||||
bookInfo?.let { book ->
|
bookInfo?.let { book ->
|
||||||
@@ -160,62 +207,150 @@ fun MyMemoirScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 「阅读全文」浮动按钮区域
|
// 操作按钮区域
|
||||||
item {
|
item {
|
||||||
Row(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 16.dp),
|
.padding(vertical = 16.dp)
|
||||||
horizontalArrangement = Arrangement.Center
|
|
||||||
) {
|
) {
|
||||||
FloatingActionButton(
|
// 整理进度条(如果正在整理)
|
||||||
onClick = { viewModel.toggleFullTextReading() },
|
if (isOrganizing) {
|
||||||
containerColor = LightPurple
|
Card(
|
||||||
) {
|
modifier = Modifier
|
||||||
Icon(
|
.fillMaxWidth()
|
||||||
imageVector = AppIcons.Reading,
|
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||||
contentDescription = "阅读全文",
|
shape = RoundedCornerShape(12.dp),
|
||||||
tint = Color.White
|
colors = CardDefaults.cardColors(
|
||||||
)
|
containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f)
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
)
|
||||||
Text("阅读全文", color = Color.White)
|
) {
|
||||||
}
|
Column(
|
||||||
}
|
modifier = Modifier
|
||||||
}
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp)
|
||||||
// 章节列表
|
) {
|
||||||
items(chapterDtos.sortedBy { it.order_index }, key = { it.id }) { chapterDto ->
|
Text(
|
||||||
ChapterCard(
|
text = organizingStatus.ifEmpty { "正在整理对话..." },
|
||||||
chapter = chapterDto,
|
fontSize = 14.sp,
|
||||||
onClick = {
|
fontWeight = FontWeight.Medium,
|
||||||
// 查找对应的Chapter实体
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
chapters.find { it.id == chapterDto.id }?.let { chapter ->
|
modifier = Modifier.padding(bottom = 8.dp)
|
||||||
viewModel.selectChapter(chapter)
|
)
|
||||||
|
LinearProgressIndicator(
|
||||||
|
progress = organizingProgress,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
color = LightPurple,
|
||||||
|
trackColor = MaterialTheme.colorScheme.surfaceVariant
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
Text(
|
||||||
|
text = "${(organizingProgress * 100).toInt()}%",
|
||||||
|
fontSize = 12.sp,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
modifier = Modifier.align(Alignment.End)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
// 操作按钮
|
||||||
}
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
// 如果没有章节,显示示例
|
.fillMaxWidth()
|
||||||
if (chapterDtos.isEmpty()) {
|
.padding(horizontal = 16.dp),
|
||||||
item {
|
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
// 显示示例章节
|
) {
|
||||||
val now = java.time.Instant.now().toString()
|
// 整理对话按钮(改进样式)
|
||||||
listOf(
|
Button(
|
||||||
ChapterDto("demo1", "童年与家庭", "", 1, "completed", "childhood", emptyList(), now, false, emptyList()),
|
onClick = { showOrganizeDialog = true },
|
||||||
ChapterDto("demo2", "上学的日子", "", 2, "partial", "education", emptyList(), now, false, emptyList()),
|
modifier = Modifier.weight(1f),
|
||||||
ChapterDto("demo3", "工作与事业", "", 3, "pending", "career", emptyList(), now, true, emptyList()),
|
enabled = !isOrganizing,
|
||||||
ChapterDto("demo4", "爱情与婚姻", "", 4, "pending", "family", emptyList(), now, true, emptyList())
|
colors = ButtonDefaults.buttonColors(
|
||||||
).forEach { chapterDto ->
|
containerColor = LightPurple
|
||||||
ChapterCard(
|
),
|
||||||
chapter = chapterDto,
|
shape = RoundedCornerShape(12.dp)
|
||||||
onClick = { }
|
) {
|
||||||
)
|
Row(
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = AppIcons.Edit,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = Color.White,
|
||||||
|
modifier = Modifier.size(20.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Text(
|
||||||
|
"整理对话",
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 14.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 「阅读全文」按钮 - 只在有章节时显示
|
||||||
|
if (chapterDtos.isNotEmpty()) {
|
||||||
|
Button(
|
||||||
|
onClick = { viewModel.toggleFullTextReading() },
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = LightPurple
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(12.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = AppIcons.Reading,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = Color.White,
|
||||||
|
modifier = Modifier.size(20.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Text(
|
||||||
|
"阅读全文",
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 14.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果没有章节,显示空状态
|
||||||
|
if (chapterDtos.isEmpty()) {
|
||||||
|
item {
|
||||||
|
EmptyStateView(
|
||||||
|
title = "还没有章节",
|
||||||
|
message = "开始对话,让AI帮您整理回忆录章节",
|
||||||
|
icon = "📖",
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(top = 48.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 章节列表
|
||||||
|
items(chapterDtos.sortedBy { it.order_index }, key = { it.id }) { chapterDto ->
|
||||||
|
ChapterCard(
|
||||||
|
chapter = chapterDto,
|
||||||
|
onClick = {
|
||||||
|
// 查找对应的Chapter实体
|
||||||
|
chapters.find { it.id == chapterDto.id }?.let { chapter ->
|
||||||
|
viewModel.selectChapter(chapter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 章节阅读视图
|
// 章节阅读视图
|
||||||
@@ -261,30 +396,48 @@ fun MyMemoirScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
// 整理对话对话框
|
||||||
|
if (showOrganizeDialog) {
|
||||||
@Composable
|
OrganizeConversationDialog(
|
||||||
fun TabButton(
|
conversations = conversationDtos,
|
||||||
text: String,
|
isLoading = conversationsLoading,
|
||||||
selected: Boolean,
|
onDismiss = { showOrganizeDialog = false },
|
||||||
onClick: () -> Unit,
|
onSelectConversation = { conversationId ->
|
||||||
modifier: Modifier = Modifier
|
viewModel.organizeConversation(
|
||||||
) {
|
conversationId = conversationId,
|
||||||
Column(modifier = modifier.clickable { onClick() }) {
|
onSuccess = {
|
||||||
Text(
|
showOrganizeSuccessDialog = true
|
||||||
text = text,
|
},
|
||||||
fontSize = 16.sp,
|
onError = { errorMsg ->
|
||||||
fontWeight = if (selected) FontWeight.Bold else FontWeight.Normal,
|
// 错误处理可以在这里添加
|
||||||
color = if (selected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
|
}
|
||||||
)
|
)
|
||||||
if (selected) {
|
}
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
)
|
||||||
Box(
|
}
|
||||||
modifier = Modifier
|
|
||||||
.height(2.dp)
|
// 整理成功对话框
|
||||||
.fillMaxWidth()
|
if (showOrganizeSuccessDialog) {
|
||||||
.background(LightPurple)
|
AlertDialog(
|
||||||
|
onDismissRequest = { showOrganizeSuccessDialog = false },
|
||||||
|
title = { Text("整理成功") },
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
text = "对话内容正在整理中,请稍后刷新查看章节。",
|
||||||
|
modifier = Modifier.wrapContentHeight()
|
||||||
|
)
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
TextButton(
|
||||||
|
onClick = {
|
||||||
|
showOrganizeSuccessDialog = false
|
||||||
|
viewModel.refreshChapters()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text("确定", color = LightPurple)
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ import com.huaga.life_echo.ui.viewmodel.PaymentViewModel
|
|||||||
import com.huaga.life_echo.ui.viewmodel.ProfileViewModel
|
import com.huaga.life_echo.ui.viewmodel.ProfileViewModel
|
||||||
import com.huaga.life_echo.ui.viewmodel.ViewModelFactory
|
import com.huaga.life_echo.ui.viewmodel.ViewModelFactory
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ProfileScreen(
|
fun ProfileScreen(
|
||||||
@@ -73,11 +76,30 @@ fun ProfileScreen(
|
|||||||
var speechRate by remember { mutableStateOf(AppSettings.speechRate) }
|
var speechRate by remember { mutableStateOf(AppSettings.speechRate) }
|
||||||
var showSpeechRateDialog by remember { mutableStateOf(false) }
|
var showSpeechRateDialog by remember { mutableStateOf(false) }
|
||||||
var showLogoutDialog by remember { mutableStateOf(false) }
|
var showLogoutDialog by remember { mutableStateOf(false) }
|
||||||
|
var showUpgradePlanDialog by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val isLoggedIn by authViewModel.isLoggedIn.collectAsState()
|
val isLoggedIn by authViewModel.isLoggedIn.collectAsState()
|
||||||
val currentUser by authViewModel.currentUser.collectAsState()
|
val currentUser by authViewModel.currentUser.collectAsState()
|
||||||
val userProfile by profileViewModel.userProfile.collectAsState()
|
val userProfile by profileViewModel.userProfile.collectAsState()
|
||||||
val currentPlan by paymentViewModel.currentPlan.collectAsState()
|
val currentPlan by paymentViewModel.currentPlan.collectAsState()
|
||||||
|
val isLoading by authViewModel.isLoading.collectAsState()
|
||||||
|
|
||||||
|
// 图片选择器
|
||||||
|
val imagePickerLauncher = rememberLauncherForActivityResult(
|
||||||
|
contract = ActivityResultContracts.GetContent()
|
||||||
|
) { uri ->
|
||||||
|
uri?.let {
|
||||||
|
// 将URI转换为File并上传
|
||||||
|
val inputStream = context.contentResolver.openInputStream(uri)
|
||||||
|
val tempFile = File(context.cacheDir, "temp_avatar.jpg")
|
||||||
|
inputStream?.use { input ->
|
||||||
|
tempFile.outputStream().use { output ->
|
||||||
|
input.copyTo(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
authViewModel.uploadAvatar(tempFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化TokenManager
|
// 初始化TokenManager
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
@@ -97,42 +119,22 @@ fun ProfileScreen(
|
|||||||
AppSettings.speechRate = speechRate
|
AppSettings.speechRate = speechRate
|
||||||
}
|
}
|
||||||
|
|
||||||
// 语速选择对话框
|
// 语速选择对话框 - 显示开发中提示
|
||||||
if (showSpeechRateDialog) {
|
if (showSpeechRateDialog) {
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = { showSpeechRateDialog = false },
|
onDismissRequest = { showSpeechRateDialog = false },
|
||||||
title = { Text("选择语速") },
|
title = { Text("提示") },
|
||||||
text = {
|
text = {
|
||||||
Column(
|
Text(
|
||||||
|
text = "语音模块正在开发中,敬请期待!",
|
||||||
modifier = Modifier.wrapContentHeight()
|
modifier = Modifier.wrapContentHeight()
|
||||||
) {
|
)
|
||||||
AppSettings.SpeechRate.entries.forEach { rate ->
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.clickable {
|
|
||||||
speechRate = rate
|
|
||||||
showSpeechRateDialog = false
|
|
||||||
}
|
|
||||||
.padding(vertical = 8.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
RadioButton(
|
|
||||||
selected = speechRate == rate,
|
|
||||||
onClick = {
|
|
||||||
speechRate = rate
|
|
||||||
showSpeechRateDialog = false
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
|
||||||
Text(rate.label)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
TextButton(onClick = { showSpeechRateDialog = false }) {
|
TextButton(
|
||||||
Text("取消")
|
onClick = { showSpeechRateDialog = false }
|
||||||
|
) {
|
||||||
|
Text("确定", color = LightPurple)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -153,14 +155,7 @@ fun ProfileScreen(
|
|||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
if (isLoggedIn && currentUser != null) {
|
if (isLoggedIn && currentUser != null) {
|
||||||
// 已登录:显示用户信息
|
// 已登录:显示用户信息(暂时不显示头像)
|
||||||
// 使用新的UserAvatar组件
|
|
||||||
com.huaga.life_echo.ui.components.profile.UserAvatar(
|
|
||||||
avatarUrl = userProfile?.avatarUrl ?: currentUser!!.avatar_url,
|
|
||||||
modifier = Modifier.size(80.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = userProfile?.nickname ?: currentUser!!.nickname,
|
text = userProfile?.nickname ?: currentUser!!.nickname,
|
||||||
@@ -169,7 +164,26 @@ fun ProfileScreen(
|
|||||||
color = MaterialTheme.colorScheme.onSurface
|
color = MaterialTheme.colorScheme.onSurface
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
// 显示邮箱
|
||||||
|
if (!currentUser!!.email.isNullOrBlank()) {
|
||||||
|
Text(
|
||||||
|
text = currentUser!!.email ?: "",
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示手机号
|
||||||
|
Text(
|
||||||
|
text = currentUser!!.phone,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
// 使用新的PlanStatusBadge组件
|
// 使用新的PlanStatusBadge组件
|
||||||
com.huaga.life_echo.ui.components.profile.PlanStatusBadge(
|
com.huaga.life_echo.ui.components.profile.PlanStatusBadge(
|
||||||
@@ -270,9 +284,9 @@ fun ProfileScreen(
|
|||||||
SettingItem(
|
SettingItem(
|
||||||
icon = AppIcons.Upgrade,
|
icon = AppIcons.Upgrade,
|
||||||
title = "升级/管理套餐",
|
title = "升级/管理套餐",
|
||||||
subtitle = "解锁完整导出与更多功能",
|
subtitle = "功能开发中",
|
||||||
onClick = {
|
onClick = {
|
||||||
navController?.navigate(com.huaga.life_echo.navigation.Screen.UpgradePlan.route)
|
showUpgradePlanDialog = true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp))
|
HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp))
|
||||||
@@ -329,30 +343,15 @@ fun ProfileScreen(
|
|||||||
SettingItem(
|
SettingItem(
|
||||||
icon = AppIcons.AccessTime,
|
icon = AppIcons.AccessTime,
|
||||||
title = "语速",
|
title = "语速",
|
||||||
subtitle = speechRate.label,
|
subtitle = "正在开发语音模块",
|
||||||
onClick = {
|
onClick = {
|
||||||
// 显示语速选择对话框
|
// 显示提示对话框
|
||||||
showSpeechRateDialog = true
|
showSpeechRateDialog = true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp))
|
// 大字模式暂时不开放
|
||||||
SettingItem(
|
// HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp))
|
||||||
icon = AppIcons.FormatSize,
|
// SettingItem(...)
|
||||||
title = "大字模式",
|
|
||||||
trailing = {
|
|
||||||
Switch(
|
|
||||||
checked = largeFontMode,
|
|
||||||
onCheckedChange = { largeFontMode = it },
|
|
||||||
colors = SwitchDefaults.colors(
|
|
||||||
checkedThumbColor = Color.White,
|
|
||||||
checkedTrackColor = LightPurple,
|
|
||||||
uncheckedThumbColor = Color.White,
|
|
||||||
uncheckedTrackColor = Color(0xFFE0E0E0)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
onClick = { largeFontMode = !largeFontMode }
|
|
||||||
)
|
|
||||||
HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp))
|
HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp))
|
||||||
SettingItem(
|
SettingItem(
|
||||||
icon = AppIcons.Brightness2,
|
icon = AppIcons.Brightness2,
|
||||||
@@ -397,6 +396,27 @@ fun ProfileScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 升级套餐提示对话框
|
||||||
|
if (showUpgradePlanDialog) {
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = { showUpgradePlanDialog = false },
|
||||||
|
title = { Text("功能开发中") },
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
text = "升级/管理套餐功能正在开发中,敬请期待!",
|
||||||
|
modifier = Modifier.wrapContentHeight()
|
||||||
|
)
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
TextButton(
|
||||||
|
onClick = { showUpgradePlanDialog = false }
|
||||||
|
) {
|
||||||
|
Text("确定", color = LightPurple)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// 登出确认对话框
|
// 登出确认对话框
|
||||||
if (showLogoutDialog) {
|
if (showLogoutDialog) {
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
|
|||||||
Reference in New Issue
Block a user