From cff6b78c307205b9c1eb71a9b5ff77ec3859c8ee Mon Sep 17 00:00:00 2001 From: zhong <2724770085@qq.com> Date: Tue, 4 Nov 2025 18:28:24 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E8=AE=B0=E5=BF=86=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ravenow/ui/group/GroupChatInfoScreen.kt | 741 +++++++++++++++--- .../ui/group/GroupChatInfoViewModel.kt | 208 +++++ .../ui/group/GroupMemoryManageScreen.kt | 267 +++++++ app/src/main/res/mipmap-hdpi/icons_brain.png | Bin 0 -> 551 bytes app/src/main/res/mipmap-mdpi/icons_brain.png | Bin 0 -> 419 bytes app/src/main/res/mipmap-xhdpi/icons_brain.png | Bin 0 -> 718 bytes .../main/res/mipmap-xxhdpi/icons_brain.png | Bin 0 -> 980 bytes .../main/res/mipmap-xxxhdpi/icons_brain.png | Bin 0 -> 1276 bytes 8 files changed, 1121 insertions(+), 95 deletions(-) create mode 100644 app/src/main/java/com/aiosman/ravenow/ui/group/GroupMemoryManageScreen.kt create mode 100644 app/src/main/res/mipmap-hdpi/icons_brain.png create mode 100644 app/src/main/res/mipmap-mdpi/icons_brain.png create mode 100644 app/src/main/res/mipmap-xhdpi/icons_brain.png create mode 100644 app/src/main/res/mipmap-xxhdpi/icons_brain.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/icons_brain.png diff --git a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoScreen.kt index 37654cf..c20ee48 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoScreen.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoScreen.kt @@ -7,19 +7,27 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material3.BottomSheetDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Switch import androidx.compose.material3.SwitchDefaults import androidx.compose.material3.Text +import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.scale +import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -37,6 +45,7 @@ import com.aiosman.ravenow.ui.index.NavItem import com.aiosman.ravenow.ui.modifiers.noRippleClickable import kotlinx.coroutines.launch +@OptIn(ExperimentalMaterial3Api::class) @Composable fun GroupChatInfoScreen(groupId: String) { val navController = LocalNavController.current @@ -52,6 +61,11 @@ fun GroupChatInfoScreen(groupId: String) { } ) + var showAddMemoryDialog by remember { mutableStateOf(false) } + var showMemoryManageDialog by remember { mutableStateOf(false) } + val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + val memoryManageSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + Column( modifier = Modifier .fillMaxSize() @@ -67,7 +81,7 @@ fun GroupChatInfoScreen(groupId: String) { Row( modifier = Modifier .fillMaxWidth() - .padding(vertical = 16.dp, horizontal = 16.dp), + .padding(vertical = 12.dp, horizontal = 12.dp), horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.CenterVertically ) { @@ -81,26 +95,25 @@ fun GroupChatInfoScreen(groupId: String) { contentDescription = null, colorFilter = ColorFilter.tint(AppColors.text) ) - Spacer(modifier = Modifier.width(138.dp)) + Spacer(modifier = Modifier.width(8.dp)) Text( modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Start, - text = stringResource(R.string.group_info), + text = "群聊信息", style = androidx.compose.ui.text.TextStyle( color = AppColors.text, - fontSize = 17.sp, + fontSize = 16.sp, fontWeight = FontWeight.Bold ) ) - Spacer(modifier = Modifier.width(40.dp)) } } // 内容区域 LazyColumn( modifier = Modifier.fillMaxSize(), - contentPadding = PaddingValues(16.dp) + contentPadding = PaddingValues(12.dp) ) { // 群聊头像和名称 item { @@ -112,7 +125,7 @@ fun GroupChatInfoScreen(groupId: String) { CustomAsyncImage( imageUrl = viewModel.groupInfo!!.groupAvatar, modifier = Modifier - .size(80.dp) + .size(64.dp) .clip(RoundedCornerShape(12.dp)), contentDescription = "群聊头像" ) @@ -120,7 +133,7 @@ fun GroupChatInfoScreen(groupId: String) { Box( modifier = Modifier .size(80.dp) - .clip(CircleShape) + .clip(RoundedCornerShape(12.dp)) .background(AppColors.decentBackground), contentAlignment = Alignment.Center ) { @@ -135,22 +148,39 @@ fun GroupChatInfoScreen(groupId: String) { } } - Spacer(modifier = Modifier.height(16.dp)) + Spacer(modifier = Modifier.height(8.dp)) Text( - text = viewModel.groupInfo?.groupName ?: "群聊", + text = viewModel.groupInfo?.groupName ?: "_feiye,Rita 米小离儿", style = androidx.compose.ui.text.TextStyle( color = AppColors.text, - fontSize = 18.sp, + fontSize = 16.sp, fontWeight = FontWeight.Bold ) ) + Spacer(modifier = Modifier.height(4.dp)) + Row(verticalAlignment = Alignment.CenterVertically) { + Image( + painter = painterResource(R.drawable.group_info_users), + modifier = Modifier.size(12.dp), + contentDescription = null, + colorFilter = ColorFilter.tint(AppColors.text.copy(alpha = 0.7f)) + ) + Spacer(modifier = Modifier.width(4.dp)) + Text( + text = "4人", + style = androidx.compose.ui.text.TextStyle( + color = AppColors.text.copy(alpha = 0.7f), + fontSize = 11.sp + ) + ) + } } } // 操作按钮 item { - Spacer(modifier = Modifier.height(32.dp)) + Spacer(modifier = Modifier.height(10.dp)) Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly @@ -164,24 +194,24 @@ fun GroupChatInfoScreen(groupId: String) { ) { Box( modifier = Modifier - .size(48.dp) + .size(30.dp) .clip(CircleShape), contentAlignment = Alignment.Center ) { Image( painter = painterResource(R.drawable.rider_pro_add_other), - modifier = Modifier.size(24.dp), + modifier = Modifier.size(20.dp), contentDescription = null, colorFilter = ColorFilter.tint( AppColors.text) ) } - Spacer(modifier = Modifier.height(8.dp)) + Spacer(modifier = Modifier.height(5.dp)) Text( - text = stringResource(R.string.group_info_add_other), + text = "添加成员", style = androidx.compose.ui.text.TextStyle( color = AppColors.text, - fontSize = 12.sp + fontSize = 11.sp ) ) } @@ -201,24 +231,24 @@ fun GroupChatInfoScreen(groupId: String) { ) { Box( modifier = Modifier - .size(48.dp) + .size(30.dp) .clip(CircleShape), contentAlignment = Alignment.Center ) { Image( painter = painterResource(if (viewModel.notificationStrategy == "mute") R.drawable.rider_pro_notice_mute else R.drawable.rider_pro_notice_active,), - modifier = Modifier.size(24.dp), + modifier = Modifier.size(20.dp), contentDescription = null, colorFilter = ColorFilter.tint( AppColors.text) ) } - Spacer(modifier = Modifier.height(8.dp)) + Spacer(modifier = Modifier.height(5.dp)) Text( - text = stringResource(R.string.group_info_notice_setting), + text = "通知", style = androidx.compose.ui.text.TextStyle( color = AppColors.text, - fontSize = 12.sp + fontSize = 11.sp ) ) } @@ -232,41 +262,145 @@ fun GroupChatInfoScreen(groupId: String) { ) { Box( modifier = Modifier - .size(48.dp) + .size(30.dp) .clip(CircleShape), contentAlignment = Alignment.Center ) { Image( - painter = painterResource(R.drawable.group_info_exit - ), - modifier = Modifier.size(24.dp), + painter = painterResource(R.drawable.group_info_edit), + modifier = Modifier.size(20.dp), contentDescription = null, - colorFilter = ColorFilter.tint( - AppColors.text) + colorFilter = ColorFilter.tint(AppColors.text) ) } - Spacer(modifier = Modifier.height(8.dp)) + Spacer(modifier = Modifier.height(5.dp)) Text( - text = stringResource(R.string.group_info_exit), + text = "分享", style = androidx.compose.ui.text.TextStyle( color = AppColors.text, - fontSize = 12.sp + fontSize = 11.sp ) ) } } } - + + // 解锁群扩展 横幅 + item { + Spacer(modifier = Modifier.height(12.dp)) + Box( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(10.dp)) + .background(AppColors.decentBackground.copy(alpha = 0.35f)) + .padding(horizontal = 10.dp, vertical = 10.dp), + contentAlignment = Alignment.CenterStart + ) { + Text( + text = "解锁群扩展", + style = androidx.compose.ui.text.TextStyle( + color = AppColors.main, + fontSize = 12.sp, + fontWeight = FontWeight.Medium + ) + ) + } + } + + // 群记忆 卡片 + item { + Spacer(modifier = Modifier.height(12.dp)) + Column( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(12.dp)) + .background(AppColors.decentBackground.copy(alpha = 0.28f)) + .padding(12.dp) + ) { + Row(verticalAlignment = Alignment.CenterVertically) { + Image( + painter = painterResource(R.drawable.group_info_edit), + modifier = Modifier.size(16.dp), + contentDescription = null, + colorFilter = ColorFilter.tint(AppColors.text) + ) + Spacer(modifier = Modifier.width(6.dp)) + Column(modifier = Modifier.weight(1f)) { + Text( + text = "群记忆", + style = androidx.compose.ui.text.TextStyle( + color = AppColors.text, + fontSize = 15.sp, + fontWeight = FontWeight.Bold + ) + ) + Spacer(modifier = Modifier.height(2.dp)) + Text( + text = "AI 会根据记忆在群聊里更懂你", + style = androidx.compose.ui.text.TextStyle( + color = AppColors.text.copy(alpha = 0.6f), + fontSize = 11.sp + ) + ) + } + } + Spacer(modifier = Modifier.height(8.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Box( + modifier = Modifier + .weight(1f) + .clip(RoundedCornerShape(20.dp)) + .background(AppColors.background) + .padding(vertical = 8.dp) + .noRippleClickable { + showAddMemoryDialog = true + }, + contentAlignment = Alignment.Center + ) { + Text( + text = "添加记忆", + style = androidx.compose.ui.text.TextStyle( + color = AppColors.text, + fontSize = 13.sp + ) + ) + } + Box( + modifier = Modifier + .weight(1f) + .clip(RoundedCornerShape(20.dp)) + .background(AppColors.background) + .padding(vertical = 8.dp) + .noRippleClickable { + showMemoryManageDialog = true + }, + contentAlignment = Alignment.Center + ) { + Text( + text = "记忆管理", + style = androidx.compose.ui.text.TextStyle( + color = AppColors.text, + fontSize = 13.sp + ) + ) + } + } + } + } + // 设置选项 item { - Spacer(modifier = Modifier.height(32.dp)) + Spacer(modifier = Modifier.height(13.dp)) // 设置聊天主题 Row( modifier = Modifier .fillMaxWidth() .clip(RoundedCornerShape(8.dp)) - .padding(16.dp) + .padding(12.dp) .noRippleClickable { // TODO: 实现设置聊天主题功能 }, @@ -274,104 +408,521 @@ fun GroupChatInfoScreen(groupId: String) { ) { Image( painter = painterResource(R.drawable.group_info_edit), - modifier = Modifier.size(24.dp), + modifier = Modifier.size(20.dp), contentDescription = null, colorFilter = ColorFilter.tint( AppColors.text) ) - Spacer(modifier = Modifier.width(12.dp)) + Spacer(modifier = Modifier.width(10.dp)) Text( - text = stringResource(R.string.group_info_edit), + text = "群资料设置", style = androidx.compose.ui.text.TextStyle( color = AppColors.text, - fontSize = 16.sp + fontSize = 15.sp ), modifier = Modifier.weight(1f) ) Image( painter = painterResource(R.drawable.rave_now_nav_right), - modifier = Modifier.size(18.dp), + modifier = Modifier.size(16.dp), contentDescription = null, ) } - Spacer(modifier = Modifier.height(1.dp)) - - // 群聊成员 + // 群可见性 Row( modifier = Modifier .fillMaxWidth() .clip(RoundedCornerShape(8.dp)) - .padding(16.dp) + .padding(12.dp) .noRippleClickable { - // TODO: 实现查看群聊成员功能 - }, - verticalAlignment = Alignment.CenterVertically - ) { - Image( - painter = painterResource(R.drawable.group_info_users), - modifier = Modifier.size(24.dp), - contentDescription = null, - colorFilter = ColorFilter.tint( - AppColors.text) - ) - Spacer(modifier = Modifier.width(12.dp)) - Text( - text = "群聊成员 (${viewModel.groupInfo?.memberCount ?: 0})", - style = androidx.compose.ui.text.TextStyle( - color = AppColors.text, - fontSize = 16.sp - ), - modifier = Modifier.weight(1f) - ) - Image( - painter = painterResource(R.drawable.rave_now_nav_right), - modifier = Modifier.size(18.dp), - contentDescription = null, - ) - } - - Spacer(modifier = Modifier.height(1.dp)) - //仅自己可见 - Row( - modifier = Modifier - .fillMaxWidth() - .clip(RoundedCornerShape(8.dp)) - .padding(16.dp) - .noRippleClickable { - // TODO: 实现仅自己可见功能 }, verticalAlignment = Alignment.CenterVertically ) { Image( painter = painterResource(R.mipmap.rider_pro_change_password), - modifier = Modifier.size(24.dp), + modifier = Modifier.size(20.dp), + contentDescription = null, + colorFilter = ColorFilter.tint(AppColors.text) + ) + Spacer(modifier = Modifier.width(10.dp)) + Text( + text = "群可见性", + style = androidx.compose.ui.text.TextStyle( + color = AppColors.text, + fontSize = 15.sp + ), + modifier = Modifier.weight(1f) + ) + Text( + text = "待解锁", + style = androidx.compose.ui.text.TextStyle( + color = AppColors.text.copy(alpha = 0.5f), + fontSize = 11.sp + ) + ) + Image( + painter = painterResource(R.drawable.rave_now_nav_right), + modifier = Modifier.size(16.dp), + contentDescription = null, + ) + } + + // 成员管理 + Row( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(8.dp)) + .padding(12.dp) + .noRippleClickable { + // 静态占位 + }, + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.group_info_users), + modifier = Modifier.size(20.dp), contentDescription = null, colorFilter = ColorFilter.tint( AppColors.text) ) - Spacer(modifier = Modifier.width(12.dp)) + Spacer(modifier = Modifier.width(10.dp)) Text( - text = "仅自己可见", + text = "成员管理", style = androidx.compose.ui.text.TextStyle( color = AppColors.text, - fontSize = 16.sp + fontSize = 15.sp ), modifier = Modifier.weight(1f) ) - Switch( - checked = true, - onCheckedChange = { - // TODO: 实现群聊仅自己可见功能 - }, - colors = SwitchDefaults.colors( - checkedThumbColor = Color.White, - checkedTrackColor = Color.Green, - uncheckedThumbColor = Color.White, - uncheckedTrackColor = AppColors.main.copy(alpha = 0.5f), - uncheckedBorderColor = Color.Transparent + Image( + painter = painterResource(R.drawable.rave_now_nav_right), + modifier = Modifier.size(16.dp), + contentDescription = null, + ) + } + // 群聊壁纸 + Row( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(8.dp)) + .padding(12.dp) + .noRippleClickable { }, + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.group_info_edit), + modifier = Modifier.size(20.dp), + contentDescription = null, + colorFilter = ColorFilter.tint( + AppColors.text) + ) + Spacer(modifier = Modifier.width(10.dp)) + Text( + text = "群聊壁纸", + style = androidx.compose.ui.text.TextStyle( + color = AppColors.text, + fontSize = 15.sp ), - modifier = Modifier.scale(1f).height(18.dp) + modifier = Modifier.weight(1f) + ) + Image( + painter = painterResource(R.drawable.rave_now_nav_right), + modifier = Modifier.size(18.dp), + contentDescription = null, + ) + } + // 解散群聊 + Row( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(8.dp)) + .padding(12.dp) + .noRippleClickable { }, + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.group_info_exit), + modifier = Modifier.size(20.dp), + contentDescription = null, + colorFilter = ColorFilter.tint(Color(0xFFFF3B30)) + ) + Spacer(modifier = Modifier.width(10.dp)) + Text( + text = "解散群聊", + style = androidx.compose.ui.text.TextStyle( + color = Color(0xFFFF3B30), + fontSize = 15.sp + ), + modifier = Modifier.weight(1f) + ) + Image( + painter = painterResource(R.drawable.rave_now_nav_right), + modifier = Modifier.size(18.dp), + contentDescription = null, + colorFilter = ColorFilter.tint(Color(0xFFFF3B30)) + ) + } + } + } + } + + // 添加群记忆弹窗 + if (showAddMemoryDialog) { + ModalBottomSheet( + onDismissRequest = { showAddMemoryDialog = false }, + sheetState = sheetState, + containerColor = Color(0xFFFAF9FB), + dragHandle = { + Box( + modifier = Modifier + .width(36.dp) + .height(5.dp) + .padding(top = 5.dp) + .background( + Color(0xFFCCCCCC), + RoundedCornerShape(100.dp) + ) + ) + }, + shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) + ) { + AddGroupMemoryDialog( + groupInfo = viewModel.groupInfo, + viewModel = viewModel, + onDismiss = { showAddMemoryDialog = false }, + onAddMemory = { memoryText -> + viewModel.addGroupMemory(memoryText) + } + ) + } + } + + // 记忆管理弹窗 + if (showMemoryManageDialog) { + ModalBottomSheet( + onDismissRequest = { showMemoryManageDialog = false }, + sheetState = memoryManageSheetState, + containerColor = Color(0xFFFAF9FB), + dragHandle = { + Box( + modifier = Modifier + .width(36.dp) + .height(5.dp) + .padding(top = 5.dp) + .background( + Color(0xFFCCCCCC), + RoundedCornerShape(100.dp) + ) + ) + }, + shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) + ) { + GroupMemoryManageContent( + groupId = groupId, + viewModel = viewModel, + onAddMemoryClick = { + showMemoryManageDialog = false + showAddMemoryDialog = true + } + ) + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun AddGroupMemoryDialog( + groupInfo: com.aiosman.ravenow.entity.GroupInfo?, + viewModel: GroupChatInfoViewModel, + onDismiss: () -> Unit, + onAddMemory: (String) -> Unit +) { + val AppColors = LocalAppTheme.current + val context = LocalContext.current + var memoryText by remember { mutableStateOf("") } + val maxLength = 500 + + // 监听添加记忆的结果 + LaunchedEffect(viewModel.addMemorySuccess) { + if (viewModel.addMemorySuccess) { + android.widget.Toast.makeText(context, "群记忆添加成功", android.widget.Toast.LENGTH_SHORT).show() + memoryText = "" // 清空输入框 + onDismiss() + viewModel.addMemorySuccess = false + } + } + + LaunchedEffect(viewModel.addMemoryError) { + viewModel.addMemoryError?.let { error -> + android.widget.Toast.makeText(context, error, android.widget.Toast.LENGTH_SHORT).show() + viewModel.addMemoryError = null + } + } + + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + .padding(bottom = 40.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + // 顶部标题栏 + Row( + modifier = Modifier + .fillMaxWidth() + .height(44.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Spacer(modifier = Modifier.width(24.dp)) + Text( + text = "添加群记忆", + style = TextStyle( + fontSize = 17.sp, + fontWeight = FontWeight.SemiBold, + color = Color.Black + ), + modifier = Modifier.weight(1f), + textAlign = TextAlign.Center + ) + Image( + painter = painterResource(R.drawable.rider_pro_close), + contentDescription = "关闭", + modifier = Modifier + .size(24.dp) + .noRippleClickable { onDismiss() }, + colorFilter = ColorFilter.tint(Color.Black) + ) + } + + Spacer(modifier = Modifier.height(10.dp)) + + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + // 群信息卡片 + Row( + modifier = Modifier + .fillMaxWidth() + .height(80.dp) + .clip(RoundedCornerShape(16.dp)) + .background(Color.White) + .padding(horizontal = 12.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + if (groupInfo?.groupAvatar?.isNotEmpty() == true) { + CustomAsyncImage( + imageUrl = groupInfo.groupAvatar, + modifier = Modifier + .size(48.dp) + .clip(RoundedCornerShape(12.dp)), + contentDescription = "群头像" + ) + } else { + Box( + modifier = Modifier + .size(48.dp) + .clip(RoundedCornerShape(12.dp)) + .background(AppColors.decentBackground), + contentAlignment = Alignment.Center + ) { + Text( + text = groupInfo?.groupName?.firstOrNull()?.toString() ?: "", + style = TextStyle( + fontSize = 20.sp, + fontWeight = FontWeight.Bold, + color = AppColors.text + ) + ) + } + } + + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text( + text = groupInfo?.groupName ?: "创意项目讨论组", + style = TextStyle( + fontSize = 15.sp, + fontWeight = FontWeight.SemiBold, + color = Color.Black + ) + ) + Text( + text = "${groupInfo?.memberCount ?: 32} 位成员", + style = TextStyle( + fontSize = 12.sp, + color = Color(0xFF3C3C43).copy(alpha = 0.6f) + ) + ) + } + } + + // 输入框卡片 + Box( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(16.dp)) + .background(Color.White) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(12.dp) + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(84.dp), + contentAlignment = Alignment.TopStart + ) { + BasicTextField( + value = memoryText, + onValueChange = { newText -> + if (newText.length <= maxLength) { + memoryText = newText + } + }, + cursorBrush = SolidColor(Color.Black), + modifier = Modifier.fillMaxWidth(), + maxLines = 6, + textStyle = TextStyle( + fontSize = 15.sp, + color = Color.Black, + lineHeight = 20.sp + ), + decorationBox = { innerTextField -> + Box( + modifier = Modifier.fillMaxWidth(), + contentAlignment = Alignment.TopStart + ) { + innerTextField() + if (memoryText.isEmpty()) { + Text( + text = "这里的内容超过输入框自动换行", + style = TextStyle( + fontSize = 15.sp, + color = Color.Black.copy(alpha = 0.3f) + ) + ) + } + } + } + ) + } + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.End + ) { + Text( + text = "${memoryText.length}/$maxLength", + style = TextStyle( + fontSize = 12.sp, + color = Color(0xFF3C3C43).copy(alpha = 0.3f) + ) + ) + } + } + } + + // 提示信息卡片 + Column( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(16.dp)) + .background(Color(0xFFFBF8EF)) + .padding(horizontal = 16.dp, vertical = 12.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text( + text = "⭐", + fontSize = 13.sp + ) + Text( + text = "添加记忆需消耗 20 派币", + style = TextStyle( + fontSize = 13.sp, + color = Color.Black + ) + ) + } + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text( + text = "🤖", + fontSize = 13.sp + ) + Text( + text = "AI 将基于记忆优化回复", + style = TextStyle( + fontSize = 13.sp, + color = Color.Black + ) + ) + } + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text( + text = "✏️", + fontSize = 13.sp + ) + Text( + text = "可随时编辑或删除", + style = TextStyle( + fontSize = 13.sp, + color = Color.Black + ) + ) + } + } + + // 添加记忆按钮 + Box( + modifier = Modifier + .fillMaxWidth() + .height(50.dp) + .clip(RoundedCornerShape(1000.dp)) + .background( + brush = Brush.horizontalGradient( + colors = listOf( + Color(0xFF7C45ED), // 紫色 + Color(0xFF7C57EE), // 浅紫色 + Color(0xFF7BD8F8) // 蓝色 + ) + ) + ) + .noRippleClickable { + if (memoryText.isNotEmpty() && !viewModel.isAddingMemory) { + onAddMemory(memoryText) + } + }, + contentAlignment = Alignment.Center + ) { + if (viewModel.isAddingMemory) { + androidx.compose.material3.CircularProgressIndicator( + modifier = Modifier.size(20.dp), + color = Color.White + ) + } else { + Text( + text = "添加记忆", + style = TextStyle( + fontSize = 17.sp, + color = Color.White + ) ) } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoViewModel.kt b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoViewModel.kt index bdc7fcf..70cc8e7 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoViewModel.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoViewModel.kt @@ -1,5 +1,6 @@ package com.aiosman.ravenow.ui.group +import android.util.Log import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue @@ -8,6 +9,10 @@ import androidx.lifecycle.viewModelScope import com.aiosman.ravenow.AppStore import com.aiosman.ravenow.ChatState import com.aiosman.ravenow.data.api.ApiClient +import com.aiosman.ravenow.data.api.CreatePromptRuleRequestBody +import com.aiosman.ravenow.data.api.PromptRule +import com.aiosman.ravenow.data.api.PromptRuleQuota +import com.aiosman.ravenow.data.parseErrorResponse import com.aiosman.ravenow.entity.ChatNotification import com.aiosman.ravenow.entity.GroupInfo import com.aiosman.ravenow.entity.GroupMember @@ -22,9 +27,36 @@ class GroupChatInfoViewModel( var isLoading by mutableStateOf(false) var error by mutableStateOf(null) var chatNotification by mutableStateOf(null) + var isAddingMemory by mutableStateOf(false) + var addMemoryError by mutableStateOf(null) + var addMemorySuccess by mutableStateOf(false) val notificationStrategy get() = chatNotification?.strategy ?: "default" + + // 记忆管理相关状态 + var memoryQuota by mutableStateOf(null) + var memoryList by mutableStateOf>(emptyList()) + var isLoadingMemory by mutableStateOf(false) + var memoryError by mutableStateOf(null) + var promptOpenId by mutableStateOf(null) init { loadGroupInfo() + loadPromptOpenId() + } + + /** + * 获取群聊中智能体的 OpenID + */ + private fun loadPromptOpenId() { + viewModelScope.launch { + try { + val response = ApiClient.api.createGroupChatAi(trtcGroupId = groupId) + val groupChatResponse = response.body()?.data + val prompts = groupChatResponse?.prompts + promptOpenId = prompts?.firstOrNull()?.openId + } catch (e: Exception) { + Log.e("GroupChatInfoViewModel", "获取智能体OpenID失败: ${e.message}", e) + } + } } suspend fun updateNotificationStrategy(strategy: String) { val result = ChatState.updateChatNotification(groupId.hashCode(), strategy) @@ -71,4 +103,180 @@ class GroupChatInfoViewModel( } } } + + /** + * 添加群记忆 + * @param memoryText 记忆内容 + * @param promptOpenId 智能体的 OpenID(可选),如果不提供则从群聊信息中获取 + */ + fun addGroupMemory(memoryText: String, promptOpenId: String? = null) { + viewModelScope.launch { + try { + isAddingMemory = true + addMemoryError = null + addMemorySuccess = false + + // 如果没有提供 promptOpenId,需要先获取群聊的智能体信息 + val openId = promptOpenId ?: run { + // 通过 createGroupChatAi 接口获取群聊详细信息(包含 prompts) + val response = ApiClient.api.createGroupChatAi(trtcGroupId = groupId) + val groupChatResponse = response.body()?.data + val prompts = groupChatResponse?.prompts + + if (prompts.isNullOrEmpty()) { + throw Exception("群聊中没有找到智能体,无法添加记忆") + } + + // 使用第一个智能体的 openId + prompts.firstOrNull()?.openId + ?: throw Exception("无法获取智能体信息") + } + + if (openId.isBlank()) { + throw Exception("智能体ID不能为空") + } + + // 创建智能体规则(群记忆) + val requestBody = CreatePromptRuleRequestBody( + rule = memoryText, + openId = openId + ) + + val response = ApiClient.api.createPromptRule(requestBody) + + if (response.isSuccessful) { + addMemorySuccess = true + Log.d("GroupChatInfoViewModel", "群记忆添加成功") + // 刷新记忆列表和配额 + loadMemoryQuota(openId) + loadMemoryList(openId) + } else { + val errorResponse = parseErrorResponse(response.errorBody()) + val errorMessage = errorResponse?.toServiceException()?.message + ?: "添加群记忆失败: ${response.code()}" + throw Exception(errorMessage) + } + } catch (e: Exception) { + addMemoryError = e.message ?: "添加群记忆失败" + Log.e("GroupChatInfoViewModel", "添加群记忆失败: ${e.message}", e) + } finally { + isAddingMemory = false + } + } + } + + /** + * 获取记忆配额信息 + */ + fun loadMemoryQuota(openId: String? = null) { + viewModelScope.launch { + try { + isLoadingMemory = true + memoryError = null + + val targetOpenId = openId ?: promptOpenId + if (targetOpenId.isNullOrBlank()) { + // 如果还没有获取到 openId,先获取 + val response = ApiClient.api.createGroupChatAi(trtcGroupId = groupId) + val groupChatResponse = response.body()?.data + val prompts = groupChatResponse?.prompts + val fetchedOpenId = prompts?.firstOrNull()?.openId + ?: throw Exception("无法获取智能体信息") + + promptOpenId = fetchedOpenId + val quotaResponse = ApiClient.api.getPromptRuleQuota(fetchedOpenId) + if (quotaResponse.isSuccessful) { + memoryQuota = quotaResponse.body()?.data + } else { + throw Exception("获取配额信息失败: ${quotaResponse.code()}") + } + } else { + val quotaResponse = ApiClient.api.getPromptRuleQuota(targetOpenId) + if (quotaResponse.isSuccessful) { + memoryQuota = quotaResponse.body()?.data + } else { + throw Exception("获取配额信息失败: ${quotaResponse.code()}") + } + } + } catch (e: Exception) { + memoryError = e.message ?: "获取配额信息失败" + Log.e("GroupChatInfoViewModel", "获取配额信息失败: ${e.message}", e) + } finally { + isLoadingMemory = false + } + } + } + + /** + * 获取记忆列表 + */ + fun loadMemoryList(openId: String? = null, page: Int = 1, pageSize: Int = 20) { + viewModelScope.launch { + try { + isLoadingMemory = true + memoryError = null + + val targetOpenId = openId ?: promptOpenId + if (targetOpenId.isNullOrBlank()) { + // 如果还没有获取到 openId,先获取 + val response = ApiClient.api.createGroupChatAi(trtcGroupId = groupId) + val groupChatResponse = response.body()?.data + val prompts = groupChatResponse?.prompts + val fetchedOpenId = prompts?.firstOrNull()?.openId + ?: throw Exception("无法获取智能体信息") + + promptOpenId = fetchedOpenId + val listResponse = ApiClient.api.getPromptRuleList(fetchedOpenId, page = page, pageSize = pageSize) + if (listResponse.isSuccessful) { + memoryList = listResponse.body()?.data?.list ?: emptyList() + } else { + throw Exception("获取记忆列表失败: ${listResponse.code()}") + } + } else { + val listResponse = ApiClient.api.getPromptRuleList(targetOpenId, page = page, pageSize = pageSize) + if (listResponse.isSuccessful) { + memoryList = listResponse.body()?.data?.list ?: emptyList() + } else { + throw Exception("获取记忆列表失败: ${listResponse.code()}") + } + } + } catch (e: Exception) { + memoryError = e.message ?: "获取记忆列表失败" + Log.e("GroupChatInfoViewModel", "获取记忆列表失败: ${e.message}", e) + } finally { + isLoadingMemory = false + } + } + } + + /** + * 删除记忆 + */ + fun deleteMemory(ruleId: Int) { + viewModelScope.launch { + try { + isLoadingMemory = true + memoryError = null + + val response = ApiClient.api.deletePromptRule(ruleId) + if (response.isSuccessful) { + // 刷新记忆列表和配额 + promptOpenId?.let { openId -> + loadMemoryQuota(openId) + loadMemoryList(openId) + } + } else { + val errorResponse = parseErrorResponse(response.errorBody()) + val errorMessage = errorResponse?.toServiceException()?.message + ?: "删除记忆失败: ${response.code()}" + throw Exception(errorMessage) + } + } catch (e: Exception) { + memoryError = e.message ?: "删除记忆失败" + Log.e("GroupChatInfoViewModel", "删除记忆失败: ${e.message}", e) + } finally { + isLoadingMemory = false + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupMemoryManageScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupMemoryManageScreen.kt new file mode 100644 index 0000000..a6370f2 --- /dev/null +++ b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupMemoryManageScreen.kt @@ -0,0 +1,267 @@ +package com.aiosman.ravenow.ui.group + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +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.graphics.ColorFilter +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.aiosman.ravenow.LocalAppTheme +import com.aiosman.ravenow.R +import com.aiosman.ravenow.ui.modifiers.noRippleClickable +import androidx.compose.foundation.Image + +@Composable +fun GroupMemoryManageContent( + groupId: String, + viewModel: GroupChatInfoViewModel, + onAddMemoryClick: () -> Unit = {} +) { + val AppColors = LocalAppTheme.current + val configuration = LocalConfiguration.current + val screenHeight = configuration.screenHeightDp.dp + val sheetHeight = screenHeight * 0.9f + + // 加载配额和列表数据 + LaunchedEffect(Unit) { + viewModel.loadMemoryQuota() + viewModel.loadMemoryList() + } + + val quota = viewModel.memoryQuota + val memoryList = viewModel.memoryList + val isLoading = viewModel.isLoadingMemory + + Column( + modifier = Modifier + .fillMaxWidth() + .height(sheetHeight) + .background(Color(0xFFFAF9FB)) + ) { + // 顶部栏:标题 + 加号(适配弹窗) + Row( + modifier = Modifier + .fillMaxWidth() + .height(44.dp) + .padding(horizontal = 16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Box(modifier = Modifier.weight(1f), contentAlignment = Alignment.Center) { + Text( + text = "记忆管理", + style = TextStyle(color = Color.Black, fontSize = 17.sp, fontWeight = FontWeight.SemiBold), + textAlign = TextAlign.Center + ) + } + + // 右上角 + 按钮 + Row( + modifier = Modifier + .clip(RoundedCornerShape(296.dp)) + .noRippleClickable { onAddMemoryClick() } + .padding(10.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text(text = "+", style = TextStyle(color = Color.Black, fontSize = 20.sp, fontWeight = FontWeight.Medium)) + } + } + + // 浅黄色提示栏 - 显示真实的配额数据 + Row( + modifier = Modifier + .fillMaxWidth() + .background(Color(0xFFFBF8EF)) + .padding(horizontal = 16.dp, vertical = 12.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row(horizontalArrangement = Arrangement.spacedBy(16.dp), verticalAlignment = Alignment.CenterVertically) { + Row(verticalAlignment = Alignment.CenterVertically) { + Text("已付费:", style = TextStyle(color = Color(0x993C3C43), fontSize = 13.sp)) + Spacer(Modifier.width(3.dp)) + Text( + "${quota?.purchasedCount ?: 0}", + style = TextStyle(color = Color(0xFFFF8D28), fontSize = 13.sp) + ) + } + Row(verticalAlignment = Alignment.CenterVertically) { + Text("已使用:", style = TextStyle(color = Color(0x993C3C43), fontSize = 13.sp)) + Spacer(Modifier.width(3.dp)) + Text( + "${quota?.currentCount ?: 0}", + style = TextStyle(color = Color(0xFFFF8D28), fontSize = 13.sp) + ) + } + } + Row(verticalAlignment = Alignment.CenterVertically) { + Text("可用上限:", style = TextStyle(color = Color(0x993C3C43), fontSize = 13.sp)) + Spacer(Modifier.width(3.dp)) + Text( + "${quota?.totalMaxCount ?: 0}", + style = TextStyle(color = Color(0xFFFF8D28), fontSize = 13.sp) + ) + } + } + + // 记忆列表或空状态 + Box( + modifier = Modifier + .fillMaxWidth() + .weight(1f) + ) { + if (isLoading) { + // 加载中状态 + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + modifier = Modifier.size(40.dp), + color = Color(0xFFFF8D28) + ) + } + } else if (memoryList.isNotEmpty()) { + // 显示记忆列表 + LazyColumn( + modifier = Modifier.fillMaxSize(), + contentPadding = PaddingValues(horizontal = 16.dp, vertical = 12.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + items(memoryList) { memory -> + MemoryItem( + memory = memory, + onDelete = { + viewModel.deleteMemory(memory.id) + } + ) + } + } + } else { + // 空状态 + Column( + modifier = Modifier + .fillMaxSize() + .padding(vertical = 60.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + // 简化的图形占位:橙色与紫色对话气泡 + Box(contentAlignment = Alignment.Center) { + Box( + modifier = Modifier + .size(74.dp) + .clip(RoundedCornerShape(20.dp)) + .background(Color(0xFFD4D4FC)) + .offset(x = 26.dp, y = (-18).dp) + ) + Row( + modifier = Modifier + .height(72.dp) + .clip(RoundedCornerShape(20.dp)) + .background(Color(0xFFFA8334)) + .padding(horizontal = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .size(22.dp) + .clip(CircleShape) + .background(Color.White) + ) + Spacer(Modifier.width(12.dp)) + Box( + modifier = Modifier + .size(22.dp) + .clip(CircleShape) + .background(Color.White) + ) + } + } + + Spacer(Modifier.height(24.dp)) + Text( + text = "暂无记忆", + style = TextStyle(color = Color.Black, fontSize = 16.sp, fontWeight = FontWeight.SemiBold) + ) + Spacer(Modifier.height(6.dp)) + Text( + text = "点击上方按钮添加群记忆", + style = TextStyle(color = Color.Black, fontSize = 14.sp, fontWeight = FontWeight.Normal) + ) + } + } + } + } +} + +/** + * 记忆项组件 + */ +@Composable +fun MemoryItem( + memory: com.aiosman.ravenow.data.api.PromptRule, + onDelete: () -> Unit +) { + val AppColors = LocalAppTheme.current + + Row( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(12.dp)) + .background(Color.White) + .padding(16.dp), + verticalAlignment = Alignment.Top + ) { + // 记忆内容 + Column( + modifier = Modifier.weight(1f) + ) { + Text( + text = memory.rule, + style = TextStyle( + color = Color.Black, + fontSize = 14.sp, + lineHeight = 20.sp + ), + maxLines = 3, + overflow = TextOverflow.Ellipsis + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = "创建于 ${if (memory.createdAt.length >= 10) memory.createdAt.substring(0, 10) else memory.createdAt}", + style = TextStyle( + color = Color(0x993C3C43), + fontSize = 12.sp + ) + ) + } + + // 删除按钮 + Image( + painter = painterResource(R.drawable.rider_pro_close), + contentDescription = "删除", + modifier = Modifier + .size(20.dp) + .noRippleClickable { onDelete() }, + colorFilter = ColorFilter.tint(Color(0x993C3C43)) + ) + } +} + diff --git a/app/src/main/res/mipmap-hdpi/icons_brain.png b/app/src/main/res/mipmap-hdpi/icons_brain.png new file mode 100644 index 0000000000000000000000000000000000000000..0e45348ad585839973a9400d57a7278f204e5d3d GIT binary patch literal 551 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k3?#4J%UA`ZSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skg2l#}z*0{W>c6;04^}fdSEfl%EbuaKia9yC{wQg@9g0CmYgDes#3Gxfp zjF)JfwBQ`WBj=9+>vK)_?O2c(0<@;g)5S5w;`G)jw%=he9J|Nqw63|u>| zUD?OO9~|iKJIRmz*U#e%^&QfR?;W!)`N(>Tv+73A1{+20C7(GyMVs(QCB-k~{m|N> z)ZDna{iKe-;{{cVmOQfFVl2{lW8Vb!ZE{v0c;0&aWlnv-Repfy#D}R(8PXG4-nF$z zzEtzLl{3XDh)sEl`W35QUZaMoUKZ;oct4ORFguay$j8C0!drZ0dBj47_4;@Bm8Gv0 z6A006Y%{3p`+D(lz=@u7QPbvq7y9ytS#+-U9qBFcQa{s#Hb@7rn!t1Y*n+K-Yy5&H zmvjXOpT51IXi}EsuZTY{ySxPYC)|D$V=5ZT-P7|q;)-DDv5>PRJ6|%2YF_+)^W^3gU9qVI8D9uc{*kAPV~EE2xk0xl zwJPvzc33DXQ2Ocr{avhk-o8G`Y|*xbGc~gA$f~KIHnFUFWxv0;#bty2fj|fSg&#Cq zc`r;7N~~qMkis!x-_jd-N+pesuWoSs6f(G@(q^D}%dSIB>7lC4qc`=3SPxbTYj1OS zA(Zrb_qWY5xti;4zevpT5$2Ow=Px6Fh<{9 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/icons_brain.png b/app/src/main/res/mipmap-xhdpi/icons_brain.png new file mode 100644 index 0000000000000000000000000000000000000000..817c2871140d697d633ee159b55fde1f46a42269 GIT binary patch literal 718 zcmV;<0x|uGP)Px#Fi=cXMSMi;M{rDhMeTe=?tDef%V59a2G8En?o>_ z!f9zCr;S!3hgevM7h9WDHWrG7tq6jRpziIt7s=)8%`_7W{ zmqGs=xL=l6#6DSi{Tpx}072bx@&IaCaG3)LcFc;wu@uY!iw`}_`{>_3fqr)ka;Om% z+5v(l(Iea&gN_8~GqAv>fFB8PvB?3N1cZ~>NWdKCB~WgU#84whz&_m6h^Gr_0$mH9 z;jTu^Kur$kV&EFP!h$Jm#-IvZ&jKGf98us6eY{V>dDPmWfN3o32F@m6 zC$R2ET?Tt`iaPvQki!kli=5|t-r{0UfSjXpvd1;J#h}$EJK7u8DdG@=HzWI6KxDl# zzBBNXc{%8pbnVY9_yBBK*ZU@0#iyeSa;^7cU$^?&ru3T9QRdk1v}2cQ~At2@bCt}&S5O(+Yz2$5U;wRmbg!jXtJ5 zc!}SyagNi5<7cw%Tv>Xhoww)H@|FMf%h*1C0Vb_1D|1NIG5`Po07*qoM6N<$f-E9I Awg3PC literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/icons_brain.png b/app/src/main/res/mipmap-xxhdpi/icons_brain.png new file mode 100644 index 0000000000000000000000000000000000000000..1555215d5d92ae60233fb3ff21494e34d464f591 GIT binary patch literal 980 zcmV;_11tQAP)Px#Gf+%aMSMi;fJpCrMD2V=?tDe;d`0bjM(sy%OngP{ zd`0bjMeck>?R-V;d`0ejM(uq@?R-V;n?fZx0000GbW%=JDH*TJUq(Ct;eMf$@xE@Z zip=Hk0009cNklOH2gBk}5f!EMCeOa`|FHpaw98wwGF;U~)!8WF zNrUj!2Wy92a1zPWAeeSA7M&*yv#6b>K>B{_`W;M$SK_yyK3VUrpvRTr^E-TR*H%mxwBS9+E6|x$RjnS$s1hG}^3Ns<6*kw7$ z8kbhHr8_s(dJ($_@{5eqrx8OuMBP*d@!irCRK!zVlJ^Z_%hc7UTDg(eWsuse%-0BP z-eWUJ(;!u^?gt=RHPc-AmQ<|=&4;a}=&yUDW)N;I=3l)~i7*dvE7fHIK{D|9wtBEu z00frms2rtvyKC)Pf{o>?+D8kCR_6PEEE$UROygcc$M~t9ja-SpzKaZDN~}d-Nidky z-YB=Iv4*Z~p?6_p3~sCt)CIw?#Q>^vPT*t_ks zP&>Tb`5jm1cjksL$PfM6+=;Gw(ctB#gXC^po{M`qz6034IqsVEaMYHJcWtvb{Bz%L zMZOJnFRna%`miARvriiML4z-!T-6%?{p|DKfc^mcK!;-rJ)5ln0000Px#Fi=cXMSMi;M{rDhMeTe=?R-V;d`0biMeTq{?|en= zd`0YjM(lh>?tDe=eMaqmMeTe=?G3Q7bN~PV4|GyaQz-!IM}3*y8?RqB%fD_g6%XjW z000C}Nklv> zhadY7{DnaCr}KQziGmVGPUZRKV=Dkx@*KZPhQywf5HA+ufDRe}gcvd^CH^f2Xe+4^ z{0D9?rNzN$;3_v?Uotshq#zRowB;?JlH6cPyc`9H1zwD^eK*AtpK<0l>BQby{4o~+ zpaw4)e2Js*YY{a#iDF&R(Lw{8a3f57byD5kB-V>9h5+2rVH&}nlB#Jbc7sp|0TX%w z*pygehm_Xg5=TM+oKdF&*aQN-TFi02(+8Si#9cjNE$&E5Y>KYZ0pQq|&4@-c2qQLd zzTgAx&IkrdlpVh61FdlM764~|)<_BKm=v&$^Cb%aHD9?4`oMM0=dBT7c{eN(jxgf_ zZL_}uhFk#ec_|)%Ed}>%K$!MoEKp~eI5VbQi3RF~X%#G>=oniFSY0|`}GgPw5!@>YAa1j1pE1(U8&IZ)tKm?FD1U(B#l@-teEorA&7{Cox(`e$to)~#&S-O5_7$}jqqTBXKph&&b+?c4l!g8Aa zpOXNvZ?Wq`qz+R&5Z(>P_?>`e?Y|HDt&`Np`ks7!HCP(~9gaKGH*3cb?bsCpT3owR z=DFy#HNm_Dw1+$EdE_Jk0j*Ai(B>ITdX01u0IYYNO&*eov~DC|B4EsWtBcs`?=v3{ zOmW|#R$d_?lh=h9Af)t|%7wkZ1tcEnT)5oN+;~aHy3vi)DLZ}cnzZksYTtC-xb5&M z@?z~E_r*=u2-t+Slqd#o)%Cyxa1pmDLrbr_VA;}Eyj8HpE)4{|Xx?K6$kT|j@rS!P zbx~la!AbIm{mKPV-x=c%=yAvOWYc_CzjB~YdEslqJ-3**$*j8{wd8_z!vWwLb0`x;-m&zya2w2hZ|}(u-U2jWWKW-vg#UC zHRIh}&MOS?kiI*>fD_)E=-J?g|051C?AUiV_Y6L3iar*qyeW8B?Ijvh=9$8*+Wwa8 z$7nHFvN8m!bj|~?psCUxL~NZKHqm&@lvf52MO<(v&GsFoM-ZC4)liOn4ww%N?Tam| z643&jC(sVRVJPBBGithPg~$f~S@u=0PnMs2s2Zx7=$B%TobID)cq|(-ac|L)(|LaB mjP>-qh7BhQ|DX8(0PqtPoZ?O|G`O4q00002vFDn literal 0 HcmV?d00001 From 4a1c15747c5fc0a30db80c4a89bbdddf90f44fad Mon Sep 17 00:00:00 2001 From: zhong <2724770085@qq.com> Date: Tue, 4 Nov 2025 19:01:11 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E6=96=87=E6=9C=AC=E8=B5=84=E6=BA=90?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=9B=BF=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ravenow/ui/group/GroupChatInfoScreen.kt | 91 +++++++++---------- app/src/main/res/values-ja/strings.xml | 24 ++++- app/src/main/res/values-zh/strings.xml | 30 +++++- app/src/main/res/values/strings.xml | 29 +++++- 4 files changed, 120 insertions(+), 54 deletions(-) diff --git a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoScreen.kt index c20ee48..847661c 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoScreen.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoScreen.kt @@ -51,7 +51,7 @@ fun GroupChatInfoScreen(groupId: String) { val navController = LocalNavController.current val context = LocalContext.current val AppColors = LocalAppTheme.current - + val viewModel = viewModel( key = "GroupChatInfoViewModel_$groupId", factory = object : ViewModelProvider.Factory { @@ -60,12 +60,12 @@ fun GroupChatInfoScreen(groupId: String) { } } ) - + var showAddMemoryDialog by remember { mutableStateOf(false) } var showMemoryManageDialog by remember { mutableStateOf(false) } val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) val memoryManageSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - + Column( modifier = Modifier .fillMaxSize() @@ -99,17 +99,16 @@ fun GroupChatInfoScreen(groupId: String) { Text( modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Start, - text = "群聊信息", + text = stringResource(R.string.group_chat_info_title), style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 16.sp, fontWeight = FontWeight.Bold ) - ) } } - + // 内容区域 LazyColumn( modifier = Modifier.fillMaxSize(), @@ -147,11 +146,11 @@ fun GroupChatInfoScreen(groupId: String) { ) } } - + Spacer(modifier = Modifier.height(8.dp)) - + Text( - text = viewModel.groupInfo?.groupName ?: "_feiye,Rita 米小离儿", + text = viewModel.groupInfo?.groupName ?: "", style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 16.sp, @@ -177,7 +176,7 @@ fun GroupChatInfoScreen(groupId: String) { } } } - + // 操作按钮 item { Spacer(modifier = Modifier.height(10.dp)) @@ -208,14 +207,14 @@ fun GroupChatInfoScreen(groupId: String) { } Spacer(modifier = Modifier.height(5.dp)) Text( - text = "添加成员", + text = stringResource(R.string.group_chat_info_add_member), style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 11.sp ) ) } - + // 通知设置 Column( horizontalAlignment = Alignment.CenterHorizontally, @@ -245,14 +244,14 @@ fun GroupChatInfoScreen(groupId: String) { } Spacer(modifier = Modifier.height(5.dp)) Text( - text = "通知", + text = stringResource(R.string.group_chat_info_notification), style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 11.sp ) ) } - + // 退出群聊 Column( horizontalAlignment = Alignment.CenterHorizontally, @@ -275,7 +274,7 @@ fun GroupChatInfoScreen(groupId: String) { } Spacer(modifier = Modifier.height(5.dp)) Text( - text = "分享", + text = stringResource(R.string.group_chat_info_share), style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 11.sp @@ -297,7 +296,7 @@ fun GroupChatInfoScreen(groupId: String) { contentAlignment = Alignment.CenterStart ) { Text( - text = "解锁群扩展", + text = stringResource(R.string.group_chat_info_unlock_extension), style = androidx.compose.ui.text.TextStyle( color = AppColors.main, fontSize = 12.sp, @@ -327,7 +326,7 @@ fun GroupChatInfoScreen(groupId: String) { Spacer(modifier = Modifier.width(6.dp)) Column(modifier = Modifier.weight(1f)) { Text( - text = "群记忆", + text = stringResource(R.string.group_chat_info_group_memory), style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 15.sp, @@ -336,7 +335,7 @@ fun GroupChatInfoScreen(groupId: String) { ) Spacer(modifier = Modifier.height(2.dp)) Text( - text = "AI 会根据记忆在群聊里更懂你", + text = stringResource(R.string.group_chat_info_memory_description), style = androidx.compose.ui.text.TextStyle( color = AppColors.text.copy(alpha = 0.6f), fontSize = 11.sp @@ -361,7 +360,7 @@ fun GroupChatInfoScreen(groupId: String) { contentAlignment = Alignment.Center ) { Text( - text = "添加记忆", + text = stringResource(R.string.group_chat_info_add_memory), style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 13.sp @@ -380,7 +379,7 @@ fun GroupChatInfoScreen(groupId: String) { contentAlignment = Alignment.Center ) { Text( - text = "记忆管理", + text = stringResource(R.string.group_chat_info_memory_manage), style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 13.sp @@ -394,7 +393,7 @@ fun GroupChatInfoScreen(groupId: String) { // 设置选项 item { Spacer(modifier = Modifier.height(13.dp)) - + // 设置聊天主题 Row( modifier = Modifier @@ -415,7 +414,7 @@ fun GroupChatInfoScreen(groupId: String) { ) Spacer(modifier = Modifier.width(10.dp)) Text( - text = "群资料设置", + text = stringResource(R.string.group_chat_info_group_settings), style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 15.sp @@ -428,7 +427,7 @@ fun GroupChatInfoScreen(groupId: String) { contentDescription = null, ) } - + // 群可见性 Row( modifier = Modifier @@ -447,7 +446,7 @@ fun GroupChatInfoScreen(groupId: String) { ) Spacer(modifier = Modifier.width(10.dp)) Text( - text = "群可见性", + text = stringResource(R.string.group_chat_info_group_visibility), style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 15.sp @@ -455,7 +454,7 @@ fun GroupChatInfoScreen(groupId: String) { modifier = Modifier.weight(1f) ) Text( - text = "待解锁", + text = stringResource(R.string.group_chat_info_locked), style = androidx.compose.ui.text.TextStyle( color = AppColors.text.copy(alpha = 0.5f), fontSize = 11.sp @@ -488,7 +487,7 @@ fun GroupChatInfoScreen(groupId: String) { ) Spacer(modifier = Modifier.width(10.dp)) Text( - text = "成员管理", + text = stringResource(R.string.group_chat_info_member_manage), style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 15.sp @@ -519,7 +518,7 @@ fun GroupChatInfoScreen(groupId: String) { ) Spacer(modifier = Modifier.width(10.dp)) Text( - text = "群聊壁纸", + text = stringResource(R.string.group_chat_info_wallpaper), style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 15.sp @@ -549,7 +548,7 @@ fun GroupChatInfoScreen(groupId: String) { ) Spacer(modifier = Modifier.width(10.dp)) Text( - text = "解散群聊", + text = stringResource(R.string.group_chat_info_dissolve), style = androidx.compose.ui.text.TextStyle( color = Color(0xFFFF3B30), fontSize = 15.sp @@ -566,7 +565,7 @@ fun GroupChatInfoScreen(groupId: String) { } } } - + // 添加群记忆弹窗 if (showAddMemoryDialog) { ModalBottomSheet( @@ -597,7 +596,7 @@ fun GroupChatInfoScreen(groupId: String) { ) } } - + // 记忆管理弹窗 if (showMemoryManageDialog) { ModalBottomSheet( @@ -642,7 +641,7 @@ fun AddGroupMemoryDialog( val context = LocalContext.current var memoryText by remember { mutableStateOf("") } val maxLength = 500 - + // 监听添加记忆的结果 LaunchedEffect(viewModel.addMemorySuccess) { if (viewModel.addMemorySuccess) { @@ -652,14 +651,14 @@ fun AddGroupMemoryDialog( viewModel.addMemorySuccess = false } } - + LaunchedEffect(viewModel.addMemoryError) { viewModel.addMemoryError?.let { error -> android.widget.Toast.makeText(context, error, android.widget.Toast.LENGTH_SHORT).show() viewModel.addMemoryError = null } } - + Column( modifier = Modifier .fillMaxWidth() @@ -677,7 +676,7 @@ fun AddGroupMemoryDialog( ) { Spacer(modifier = Modifier.width(24.dp)) Text( - text = "添加群记忆", + text = stringResource(R.string.group_chat_info_add_group_memory), style = TextStyle( fontSize = 17.sp, fontWeight = FontWeight.SemiBold, @@ -695,9 +694,9 @@ fun AddGroupMemoryDialog( colorFilter = ColorFilter.tint(Color.Black) ) } - + Spacer(modifier = Modifier.height(10.dp)) - + Column( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, @@ -740,7 +739,7 @@ fun AddGroupMemoryDialog( ) } } - + Column( modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp) @@ -754,7 +753,7 @@ fun AddGroupMemoryDialog( ) ) Text( - text = "${groupInfo?.memberCount ?: 32} 位成员", + text = stringResource(R.string.group_chat_info_member_count, groupInfo?.memberCount ?: 32), style = TextStyle( fontSize = 12.sp, color = Color(0xFF3C3C43).copy(alpha = 0.6f) @@ -762,7 +761,7 @@ fun AddGroupMemoryDialog( ) } } - + // 输入框卡片 Box( modifier = Modifier @@ -804,7 +803,7 @@ fun AddGroupMemoryDialog( innerTextField() if (memoryText.isEmpty()) { Text( - text = "这里的内容超过输入框自动换行", + text = stringResource(R.string.group_chat_info_memory_input_hint), style = TextStyle( fontSize = 15.sp, color = Color.Black.copy(alpha = 0.3f) @@ -829,7 +828,7 @@ fun AddGroupMemoryDialog( } } } - + // 提示信息卡片 Column( modifier = Modifier @@ -848,7 +847,7 @@ fun AddGroupMemoryDialog( fontSize = 13.sp ) Text( - text = "添加记忆需消耗 20 派币", + text = stringResource(R.string.group_chat_info_memory_cost), style = TextStyle( fontSize = 13.sp, color = Color.Black @@ -864,7 +863,7 @@ fun AddGroupMemoryDialog( fontSize = 13.sp ) Text( - text = "AI 将基于记忆优化回复", + text = stringResource(R.string.group_chat_info_memory_optimization), style = TextStyle( fontSize = 13.sp, color = Color.Black @@ -880,7 +879,7 @@ fun AddGroupMemoryDialog( fontSize = 13.sp ) Text( - text = "可随时编辑或删除", + text = stringResource(R.string.group_chat_info_memory_editable), style = TextStyle( fontSize = 13.sp, color = Color.Black @@ -888,7 +887,7 @@ fun AddGroupMemoryDialog( ) } } - + // 添加记忆按钮 Box( modifier = Modifier @@ -918,7 +917,7 @@ fun AddGroupMemoryDialog( ) } else { Text( - text = "添加记忆", + text = stringResource(R.string.group_chat_info_add_memory), style = TextStyle( fontSize = 17.sp, color = Color.White diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index d849e3a..bab4a9e 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -230,7 +230,7 @@ おすすめ ショート動画 ニュース - + %1$sをブロックしますか? 相手はあなたにメッセージを送信したり、あなたのプロフィールやコンテンツを見つけることができなくなります @@ -248,5 +248,27 @@ 「適用」を選択してこのテーマを使用 「キャンセル」をタップして他のテーマをプレビュー + + グループチャット情報 + メンバーを追加 + 通知 + 共有 + グループ拡張機能を解除 + グループメモリ + AIは記憶に基づいてグループチャットであなたをより理解します + メモリを追加 + メモリ管理 + グループ設定 + グループの可視性 + ロック中 + メンバー管理 + グループチャット壁紙 + グループチャットを解散 + グループメモリを追加 + %d人のメンバー + ここに入力した内容は入力ボックスを超えると自動的に折り返されます + メモリを追加すると20コインを消費します + AIは記憶に基づいて返信を最適化します + いつでも編集または削除できます diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 2ce035d..ac2e155 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -225,15 +225,15 @@ 掉线啦... 确认一下网络,连接这个宇宙 重新加载 - + 加入派派,一起狂欢 - + 推荐 短视频 新闻 - + 确认拉黑%s? 对方将无法发消息给你,也无法找到你的主页或内容 @@ -250,4 +250,28 @@ 每个主题都有自己独特的体验 选择"应用"可选中这个主题 轻触"取消"可预览其他主题 + + + 群聊信息 + 添加成员 + 通知 + 分享 + 解锁群扩展 + 群记忆 + AI 会根据记忆在群聊里更懂你 + 添加记忆 + 记忆管理 + 群资料设置 + 群可见性 + 待解锁 + 成员管理 + 群聊壁纸 + 解散群聊 + 添加群记忆 + %d 位成员 + 这里的内容超过输入框自动换行 + 添加记忆需消耗 20 派币 + AI 将基于记忆优化回复 + 可随时编辑或删除 + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 02549e6..260074f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -220,15 +220,15 @@ Offline… Check your network to connect to this universe Reload - + Join the party, let\'s celebrate together - + Recommend Short Video News - + Confirm block %1$s? They won\'t be able to send you messages or find your profile or content @@ -246,5 +246,26 @@ Select "Apply" to use this theme Tap "Cancel" to preview other themes - + + Group Chat Info + Add Member + Notification + Share + Unlock Group Extension + Group Memory + AI will understand you better in group chat based on memory + Add Memory + Memory Management + Group Settings + Group Visibility + Locked + Member Management + Group Chat Wallpaper + Dissolve Group Chat + Add Group Memory + %d members + Content here will automatically wrap when it exceeds the input box + Adding memory consumes 20 coins + AI will optimize replies based on memory + Can be edited or deleted at any time \ No newline at end of file From 9ea03cee3434f2265404cc8cf7628e0f19cdb708 Mon Sep 17 00:00:00 2001 From: zhong <2724770085@qq.com> Date: Wed, 5 Nov 2025 21:29:18 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E7=BE=A4=E8=AE=B0=E5=BF=86=E9=A1=B9?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E5=8A=9F=E8=83=BD=EF=BC=9B=E7=BE=A4=E6=9D=83?= =?UTF-8?q?=E9=99=90=E8=AE=BE=E7=BD=AEUI=EF=BC=9B=E7=BE=A4=E8=AE=B0?= =?UTF-8?q?=E5=BF=86=E7=AE=A1=E7=90=86=E7=BC=BA=E7=9C=81=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ravenow/ui/group/GroupChatInfoScreen.kt | 314 +++++++++-- .../ui/group/GroupChatInfoViewModel.kt | 38 ++ .../ui/group/GroupMemoryManageScreen.kt | 520 +++++++++++++++--- app/src/main/res/mipmap-xhdpi/group.png | Bin 0 -> 1534 bytes app/src/main/res/mipmap-xhdpi/iconsdelete.png | Bin 0 -> 312 bytes app/src/main/res/mipmap-xxhdpi/group.png | Bin 0 -> 2767 bytes .../main/res/mipmap-xxhdpi/iconsdelete.png | Bin 0 -> 438 bytes app/src/main/res/mipmap-xxxhdpi/group.png | Bin 0 -> 3783 bytes .../main/res/mipmap-xxxhdpi/iconsdelete.png | Bin 0 -> 575 bytes app/src/main/res/values-ja/strings.xml | 13 +- app/src/main/res/values-zh/strings.xml | 13 +- app/src/main/res/values/strings.xml | 13 +- 12 files changed, 792 insertions(+), 119 deletions(-) create mode 100644 app/src/main/res/mipmap-xhdpi/group.png create mode 100644 app/src/main/res/mipmap-xhdpi/iconsdelete.png create mode 100644 app/src/main/res/mipmap-xxhdpi/group.png create mode 100644 app/src/main/res/mipmap-xxhdpi/iconsdelete.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/group.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/iconsdelete.png diff --git a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoScreen.kt index 847661c..a035a5f 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoScreen.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoScreen.kt @@ -51,7 +51,7 @@ fun GroupChatInfoScreen(groupId: String) { val navController = LocalNavController.current val context = LocalContext.current val AppColors = LocalAppTheme.current - + val viewModel = viewModel( key = "GroupChatInfoViewModel_$groupId", factory = object : ViewModelProvider.Factory { @@ -60,12 +60,13 @@ fun GroupChatInfoScreen(groupId: String) { } } ) - + var showAddMemoryDialog by remember { mutableStateOf(false) } var showMemoryManageDialog by remember { mutableStateOf(false) } + var showVisibilityDialog by remember { mutableStateOf(false) } val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) val memoryManageSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - + Column( modifier = Modifier .fillMaxSize() @@ -108,7 +109,7 @@ fun GroupChatInfoScreen(groupId: String) { ) } } - + // 内容区域 LazyColumn( modifier = Modifier.fillMaxSize(), @@ -146,11 +147,11 @@ fun GroupChatInfoScreen(groupId: String) { ) } } - + Spacer(modifier = Modifier.height(8.dp)) - + Text( - text = viewModel.groupInfo?.groupName ?: "", + text = viewModel.groupInfo?.groupName ?: stringResource(R.string.group_info_edit), style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 16.sp, @@ -167,7 +168,7 @@ fun GroupChatInfoScreen(groupId: String) { ) Spacer(modifier = Modifier.width(4.dp)) Text( - text = "4人", + text = "${viewModel.groupInfo?.memberCount ?: 0}人", style = androidx.compose.ui.text.TextStyle( color = AppColors.text.copy(alpha = 0.7f), fontSize = 11.sp @@ -176,7 +177,7 @@ fun GroupChatInfoScreen(groupId: String) { } } } - + // 操作按钮 item { Spacer(modifier = Modifier.height(10.dp)) @@ -214,7 +215,7 @@ fun GroupChatInfoScreen(groupId: String) { ) ) } - + // 通知设置 Column( horizontalAlignment = Alignment.CenterHorizontally, @@ -251,7 +252,7 @@ fun GroupChatInfoScreen(groupId: String) { ) ) } - + // 退出群聊 Column( horizontalAlignment = Alignment.CenterHorizontally, @@ -393,7 +394,7 @@ fun GroupChatInfoScreen(groupId: String) { // 设置选项 item { Spacer(modifier = Modifier.height(13.dp)) - + // 设置聊天主题 Row( modifier = Modifier @@ -427,7 +428,7 @@ fun GroupChatInfoScreen(groupId: String) { contentDescription = null, ) } - + // 群可见性 Row( modifier = Modifier @@ -435,6 +436,7 @@ fun GroupChatInfoScreen(groupId: String) { .clip(RoundedCornerShape(8.dp)) .padding(12.dp) .noRippleClickable { + showVisibilityDialog = true }, verticalAlignment = Alignment.CenterVertically ) { @@ -565,7 +567,34 @@ fun GroupChatInfoScreen(groupId: String) { } } } - + + // 群可见性弹窗 + if (showVisibilityDialog) { + val visibilitySheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + ModalBottomSheet( + onDismissRequest = { showVisibilityDialog = false }, + sheetState = visibilitySheetState, + containerColor = Color(0xFFFAF9FB), + dragHandle = { + Box( + modifier = Modifier + .width(36.dp) + .height(5.dp) + .padding(top = 5.dp) + .background( + Color(0xFFCCCCCC), + RoundedCornerShape(100.dp) + ) + ) + }, + shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) + ) { + GroupVisibilityDialog( + onDismiss = { showVisibilityDialog = false } + ) + } + } + // 添加群记忆弹窗 if (showAddMemoryDialog) { ModalBottomSheet( @@ -596,7 +625,7 @@ fun GroupChatInfoScreen(groupId: String) { ) } } - + // 记忆管理弹窗 if (showMemoryManageDialog) { ModalBottomSheet( @@ -623,6 +652,9 @@ fun GroupChatInfoScreen(groupId: String) { onAddMemoryClick = { showMemoryManageDialog = false showAddMemoryDialog = true + }, + onDismiss = { + showMemoryManageDialog = false } ) } @@ -641,24 +673,24 @@ fun AddGroupMemoryDialog( val context = LocalContext.current var memoryText by remember { mutableStateOf("") } val maxLength = 500 - + // 监听添加记忆的结果 LaunchedEffect(viewModel.addMemorySuccess) { if (viewModel.addMemorySuccess) { - android.widget.Toast.makeText(context, "群记忆添加成功", android.widget.Toast.LENGTH_SHORT).show() + android.widget.Toast.makeText(context, context.getString(R.string.group_chat_info_memory_add_success), android.widget.Toast.LENGTH_SHORT).show() memoryText = "" // 清空输入框 onDismiss() viewModel.addMemorySuccess = false } } - + LaunchedEffect(viewModel.addMemoryError) { viewModel.addMemoryError?.let { error -> android.widget.Toast.makeText(context, error, android.widget.Toast.LENGTH_SHORT).show() viewModel.addMemoryError = null } } - + Column( modifier = Modifier .fillMaxWidth() @@ -694,9 +726,9 @@ fun AddGroupMemoryDialog( colorFilter = ColorFilter.tint(Color.Black) ) } - + Spacer(modifier = Modifier.height(10.dp)) - + Column( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, @@ -739,13 +771,13 @@ fun AddGroupMemoryDialog( ) } } - + Column( modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp) ) { Text( - text = groupInfo?.groupName ?: "创意项目讨论组", + text = groupInfo?.groupName ?: "", style = TextStyle( fontSize = 15.sp, fontWeight = FontWeight.SemiBold, @@ -761,7 +793,7 @@ fun AddGroupMemoryDialog( ) } } - + // 输入框卡片 Box( modifier = Modifier @@ -828,7 +860,7 @@ fun AddGroupMemoryDialog( } } } - + // 提示信息卡片 Column( modifier = Modifier @@ -887,24 +919,39 @@ fun AddGroupMemoryDialog( ) } } - + // 添加记忆按钮 + val isButtonEnabled = memoryText.isNotEmpty() && !viewModel.isAddingMemory Box( modifier = Modifier .fillMaxWidth() .height(50.dp) .clip(RoundedCornerShape(1000.dp)) - .background( - brush = Brush.horizontalGradient( - colors = listOf( - Color(0xFF7C45ED), // 紫色 - Color(0xFF7C57EE), // 浅紫色 - Color(0xFF7BD8F8) // 蓝色 + .then( + if (isButtonEnabled) { + Modifier.background( + brush = Brush.horizontalGradient( + colors = listOf( + Color(0xFF7C45ED), + Color(0x997C57EE), + Color(0x887BD8F8) + ) + ) ) - ) + } else { + Modifier.background( + brush = Brush.horizontalGradient( + colors = listOf( + Color(0x337C45ED), + Color(0x337C57EE), + Color(0x337BD8F8) + ) + ) + ) + } ) .noRippleClickable { - if (memoryText.isNotEmpty() && !viewModel.isAddingMemory) { + if (isButtonEnabled) { onAddMemory(memoryText) } }, @@ -920,7 +967,7 @@ fun AddGroupMemoryDialog( text = stringResource(R.string.group_chat_info_add_memory), style = TextStyle( fontSize = 17.sp, - color = Color.White + color = if (isButtonEnabled) Color.White else Color.White.copy(alpha = 0.6f) ) ) } @@ -928,3 +975,200 @@ fun AddGroupMemoryDialog( } } } + +@Composable +fun GroupVisibilityDialog( + onDismiss: () -> Unit +) { + val AppColors = LocalAppTheme.current + var isPrivate by remember { mutableStateOf(false) } + val balance = 482 + val unlockCost = 500 + + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + .padding(bottom = 32.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + // 顶部标题 + Row( + modifier = Modifier + .fillMaxWidth() + .height(44.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Spacer(modifier = Modifier.width(24.dp)) + Text( + text = stringResource(R.string.group_chat_info_permission_settings), + style = TextStyle( + fontSize = 17.sp, + fontWeight = FontWeight.SemiBold, + color = Color.Black + ), + modifier = Modifier.weight(1f), + textAlign = TextAlign.Center + ) + Image( + painter = painterResource(R.drawable.rider_pro_close), + contentDescription = "关闭", + modifier = Modifier + .size(24.dp) + .noRippleClickable { onDismiss() }, + colorFilter = ColorFilter.tint(Color.Black) + ) + } + + Spacer(modifier = Modifier.height(6.dp)) + + // 公开群组 + VisibilityOptionItem( + title = stringResource(R.string.group_chat_info_public_group), + desc = stringResource(R.string.group_chat_info_public_group_desc), + badge = null, + selected = !isPrivate, + onClick = { isPrivate = false } + ) + + Spacer(modifier = Modifier.height(16.dp)) + + // 私密群组 + VisibilityOptionItem( + title = stringResource(R.string.group_chat_info_private_group), + desc = stringResource(R.string.group_chat_info_private_group_desc), + badge = stringResource(R.string.group_chat_info_private_group_cost), + selected = isPrivate, + onClick = { isPrivate = true } + ) + + Spacer(modifier = Modifier.height(16.dp)) + + // 余额与费用 + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = stringResource(R.string.group_chat_info_balance, balance), + style = TextStyle( + fontSize = 13.sp, + color = Color(0x993C3C43) + ) + ) + Text( + text = stringResource(R.string.group_chat_info_unlock_cost, unlockCost), + style = TextStyle( + fontSize = 13.sp, + color = Color(0xFF9284BD) + ) + ) + } + + Spacer(modifier = Modifier.height(8.dp)) + + // 完成按钮 + Box( + modifier = Modifier + .fillMaxWidth() + .height(50.dp) + .clip(RoundedCornerShape(1000.dp)) + .background( + brush = Brush.horizontalGradient( + colors = listOf( + Color(0xFF7C45ED), + Color(0xFF7C57EE), + Color(0xFF7BD8F8) + ) + ) + ) + .noRippleClickable { onDismiss() }, + contentAlignment = Alignment.Center + ) { + Text( + text = stringResource(R.string.group_chat_info_done), + style = TextStyle(fontSize = 17.sp, color = Color.White) + ) + } + + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = stringResource(R.string.group_chat_info_recharge_hint), + style = TextStyle(fontSize = 12.sp, color = Color(0x4D3C3C43)), + textAlign = TextAlign.Center + ) + } +} + +@Composable +private fun VisibilityOptionItem( + title: String, + desc: String, + badge: String?, + selected: Boolean, + onClick: () -> Unit +) { + val borderColor = Color(0x1F7D767F) + Row( + modifier = Modifier + .fillMaxWidth() + .height(68.dp) + .clip(RoundedCornerShape(16.dp)) + .background(Color.White) + .padding(horizontal = 12.dp) + .noRippleClickable { onClick() }, + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Row(verticalAlignment = Alignment.CenterVertically) { + Box( + modifier = Modifier + .size(32.dp) + .clip(RoundedCornerShape(10.dp)) + .background(Color(0x0F7C45ED)), + contentAlignment = Alignment.Center + ) { + Text(text = if (title.contains("私密")) "🔒" else "🌐", fontSize = 16.sp) + } + Spacer(modifier = Modifier.width(10.dp)) + Column(modifier = Modifier.widthIn(max = 240.dp)) { + Text(text = title, style = TextStyle(fontSize = 15.sp, color = Color.Black)) + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = desc, + style = TextStyle(fontSize = 12.sp, color = Color(0x993C3C43)) + ) + } + } + Spacer(modifier = Modifier.weight(1f)) + Row(verticalAlignment = Alignment.CenterVertically) { + if (badge != null) { + Box( + modifier = Modifier + .clip(RoundedCornerShape(8.dp)) + .background(Color(0x1AFEBC2F)) + .padding(horizontal = 10.dp, vertical = 4.dp) + ) { + Text( + text = badge, + style = TextStyle(fontSize = 15.sp, color = Color(0xFF008D28)) + ) + } + Spacer(modifier = Modifier.width(8.dp)) + } + if (selected) { + Box( + modifier = Modifier + .size(22.dp) + .clip(CircleShape) + .background(Color(0xFF34C759)), + contentAlignment = Alignment.Center + ) { + Text(text = "✓", color = Color.White, fontSize = 14.sp) + } + } + } + } +} diff --git a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoViewModel.kt b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoViewModel.kt index 70cc8e7..2dd62b2 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoViewModel.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoViewModel.kt @@ -279,4 +279,42 @@ class GroupChatInfoViewModel( } } } + + /** + * 更新记忆 + */ + fun updateMemory(ruleId: Int, newRuleText: String, targetOpenId: String? = null) { + viewModelScope.launch { + try { + isLoadingMemory = true + memoryError = null + + val openId = targetOpenId ?: promptOpenId + ?: throw Exception("无法获取智能体ID") + + val requestBody = com.aiosman.ravenow.data.api.UpdatePromptRuleRequestBody( + id = ruleId, + rule = newRuleText, + openId = openId + ) + + val response = ApiClient.api.updatePromptRule(requestBody) + if (response.isSuccessful) { + // 刷新记忆列表和配额 + loadMemoryQuota(openId) + loadMemoryList(openId) + } else { + val errorResponse = parseErrorResponse(response.errorBody()) + val errorMessage = errorResponse?.toServiceException()?.message + ?: "更新记忆失败: ${response.code()}" + throw Exception(errorMessage) + } + } catch (e: Exception) { + memoryError = e.message ?: "更新记忆失败" + Log.e("GroupChatInfoViewModel", "更新记忆失败: ${e.message}", e) + } finally { + isLoadingMemory = false + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupMemoryManageScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupMemoryManageScreen.kt index a6370f2..47af95c 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupMemoryManageScreen.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupMemoryManageScreen.kt @@ -27,17 +27,34 @@ import com.aiosman.ravenow.LocalAppTheme import com.aiosman.ravenow.R import com.aiosman.ravenow.ui.modifiers.noRippleClickable import androidx.compose.foundation.Image +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.platform.LocalContext +import android.widget.Toast +import androidx.compose.ui.graphics.Brush @Composable fun GroupMemoryManageContent( groupId: String, viewModel: GroupChatInfoViewModel, - onAddMemoryClick: () -> Unit = {} + onAddMemoryClick: () -> Unit = {}, + onDismiss: () -> Unit = {} ) { val AppColors = LocalAppTheme.current val configuration = LocalConfiguration.current val screenHeight = configuration.screenHeightDp.dp - val sheetHeight = screenHeight * 0.9f + val sheetHeight = screenHeight * 0.95f + val context = LocalContext.current + + // 编辑记忆的状态 - 存储正在编辑的记忆ID + var editingMemoryId by remember { mutableStateOf(null) } // 加载配额和列表数据 LaunchedEffect(Unit) { @@ -55,31 +72,70 @@ fun GroupMemoryManageContent( .height(sheetHeight) .background(Color(0xFFFAF9FB)) ) { - // 顶部栏:标题 + 加号(适配弹窗) - Row( + // 顶部栏:返回按钮 + 标题 + 加号按钮 + Box( modifier = Modifier .fillMaxWidth() .height(44.dp) - .padding(horizontal = 16.dp), - verticalAlignment = Alignment.CenterVertically + .padding(horizontal = 16.dp) ) { - Box(modifier = Modifier.weight(1f), contentAlignment = Alignment.Center) { + // 中间标题 - 绝对居中,不受其他组件影响 + Text( + text = "记忆管理", + style = TextStyle( + color = Color.Black, + fontSize = 17.sp, + fontWeight = FontWeight.SemiBold + ), + modifier = Modifier.align(Alignment.Center), + textAlign = TextAlign.Center + ) + + // 左侧返回按钮 + Row( + modifier = Modifier + .align(Alignment.CenterStart) + .clip(RoundedCornerShape(296.dp)) + .background(Color.White) // 浅灰色背景 + .noRippleClickable { onDismiss() } + .padding(horizontal = 12.dp, vertical = 8.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(4.dp) + ) { + Image( + painter = painterResource(R.drawable.rider_pro_back_icon), + contentDescription = "返回", + modifier = Modifier.size(16.dp), + colorFilter = ColorFilter.tint(Color.Black) + ) Text( - text = "记忆管理", - style = TextStyle(color = Color.Black, fontSize = 17.sp, fontWeight = FontWeight.SemiBold), - textAlign = TextAlign.Center + text = "返回", + style = TextStyle( + color = Color.Black, + fontSize = 15.sp, + fontWeight = FontWeight.Normal + ) ) } - // 右上角 + 按钮 - Row( + // 右侧圆形加号按钮 + Box( modifier = Modifier - .clip(RoundedCornerShape(296.dp)) - .noRippleClickable { onAddMemoryClick() } - .padding(10.dp), - verticalAlignment = Alignment.CenterVertically + .align(Alignment.CenterEnd) + .size(32.dp) + .clip(CircleShape) + .background(Color.White) + .noRippleClickable { onAddMemoryClick() }, + contentAlignment = Alignment.Center ) { - Text(text = "+", style = TextStyle(color = Color.Black, fontSize = 20.sp, fontWeight = FontWeight.Medium)) + Text( + text = "+", + style = TextStyle( + color = Color.Black, + fontSize = 20.sp, + fontWeight = FontWeight.Medium + ) + ) } } @@ -114,7 +170,7 @@ fun GroupMemoryManageContent( Text("可用上限:", style = TextStyle(color = Color(0x993C3C43), fontSize = 13.sp)) Spacer(Modifier.width(3.dp)) Text( - "${quota?.totalMaxCount ?: 0}", + "50", style = TextStyle(color = Color(0xFFFF8D28), fontSize = 13.sp) ) } @@ -147,6 +203,17 @@ fun GroupMemoryManageContent( items(memoryList) { memory -> MemoryItem( memory = memory, + isEditing = editingMemoryId == memory.id, + onEdit = { + editingMemoryId = memory.id + }, + onCancel = { + editingMemoryId = null + }, + onSave = { newText -> + viewModel.updateMemory(memory.id, newText) + editingMemoryId = null + }, onDelete = { viewModel.deleteMemory(memory.id) } @@ -154,7 +221,6 @@ fun GroupMemoryManageContent( } } } else { - // 空状态 Column( modifier = Modifier .fillMaxSize() @@ -162,40 +228,14 @@ fun GroupMemoryManageContent( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { - // 简化的图形占位:橙色与紫色对话气泡 - Box(contentAlignment = Alignment.Center) { - Box( - modifier = Modifier - .size(74.dp) - .clip(RoundedCornerShape(20.dp)) - .background(Color(0xFFD4D4FC)) - .offset(x = 26.dp, y = (-18).dp) - ) - Row( - modifier = Modifier - .height(72.dp) - .clip(RoundedCornerShape(20.dp)) - .background(Color(0xFFFA8334)) - .padding(horizontal = 12.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier - .size(22.dp) - .clip(CircleShape) - .background(Color.White) - ) - Spacer(Modifier.width(12.dp)) - Box( - modifier = Modifier - .size(22.dp) - .clip(CircleShape) - .background(Color.White) - ) - } - } + Image( + painter = painterResource(id = R.mipmap.group), + contentDescription = "暂无记忆", + modifier = Modifier + .height(150.dp).width(180.dp) + ) - Spacer(Modifier.height(24.dp)) + Spacer(Modifier.height(10.dp)) Text( text = "暂无记忆", style = TextStyle(color = Color.Black, fontSize = 16.sp, fontWeight = FontWeight.SemiBold) @@ -211,57 +251,375 @@ fun GroupMemoryManageContent( } } +/** + * 编辑记忆对话框 + */ +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun EditGroupMemoryDialog( + memory: com.aiosman.ravenow.data.api.PromptRule, + viewModel: GroupChatInfoViewModel, + onDismiss: () -> Unit, + onUpdateMemory: (String) -> Unit +) { + val AppColors = LocalAppTheme.current + val context = LocalContext.current + var memoryText by remember { mutableStateOf(memory.rule) } + val maxLength = 500 + val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + + val gradientColors = listOf( + Color(0xFF7C45ED), + Color(0xFF7C57EE), + Color(0xFF7BD8F8) + ) + val gradientBrush = Brush.horizontalGradient(colors = gradientColors) + + ModalBottomSheet( + onDismissRequest = onDismiss, + sheetState = sheetState, + containerColor = Color(0xFFFAF9FB), + dragHandle = { + Box( + modifier = Modifier + .width(36.dp) + .height(5.dp) + .padding(top = 5.dp) + .background( + Color(0xFFCCCCCC), + RoundedCornerShape(100.dp) + ) + ) + }, + shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp, vertical = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(88.dp) + ) { + Box( + modifier = Modifier + .fillMaxSize() + .clip(RoundedCornerShape(16.dp)) + .background(brush = gradientBrush) + ) + + Box( + modifier = Modifier + .fillMaxSize() + .padding(1.dp) + .clip(RoundedCornerShape(15.dp)) + .background(Color.White) + .padding(12.dp), + contentAlignment = Alignment.TopStart + ) { + BasicTextField( + value = memoryText, + onValueChange = { newText -> + if (newText.length <= maxLength) { + memoryText = newText + } + }, + cursorBrush = SolidColor(Color.Black), + modifier = Modifier.fillMaxWidth(), + textStyle = TextStyle( + fontSize = 13.sp, + color = Color.Black, + lineHeight = 18.sp + ), + decorationBox = { innerTextField -> + Box( + modifier = Modifier.fillMaxWidth(), + contentAlignment = Alignment.TopStart + ) { + innerTextField() + } + } + ) + } + } + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + // 取消按钮 + Box( + modifier = Modifier + .weight(1f) + .height(34.dp) + .clip(RoundedCornerShape(653.8.dp)) + .background(Color(0x147C7480)) + .noRippleClickable { onDismiss() }, + contentAlignment = Alignment.Center + ) { + Text( + text = "取消", + style = TextStyle( + fontSize = 15.sp, + color = Color.Black + ) + ) + } + + // 保存按钮 + Box( + modifier = Modifier + .weight(1f) + .height(34.dp) + .clip(RoundedCornerShape(653.8.dp)) + .background(Color(0xFF110C13)) + .noRippleClickable { + if (memoryText.isNotBlank() && memoryText != memory.rule) { + onUpdateMemory(memoryText) + Toast.makeText(context, "记忆更新成功", Toast.LENGTH_SHORT).show() + } + }, + contentAlignment = Alignment.Center + ) { + Text( + text = "保存", + style = TextStyle( + fontSize = 15.sp, + color = Color.White + ) + ) + } + } + } + } +} + /** * 记忆项组件 */ @Composable fun MemoryItem( memory: com.aiosman.ravenow.data.api.PromptRule, + isEditing: Boolean = false, + onEdit: () -> Unit = {}, + onCancel: () -> Unit = {}, + onSave: (String) -> Unit = {}, onDelete: () -> Unit ) { val AppColors = LocalAppTheme.current + val context = LocalContext.current + var memoryText by remember { mutableStateOf(memory.rule) } + val maxLength = 500 - Row( - modifier = Modifier - .fillMaxWidth() - .clip(RoundedCornerShape(12.dp)) - .background(Color.White) - .padding(16.dp), - verticalAlignment = Alignment.Top - ) { - // 记忆内容 + // 渐变边框颜色 + val gradientColors = listOf( + Color(0xFF7C45ED), + Color(0xFF7C57EE), + Color(0xFF7BD8F8) + ) + val gradientBrush = Brush.horizontalGradient(colors = gradientColors) + + // 当进入编辑模式时,重置文本 + LaunchedEffect(isEditing) { + if (isEditing) { + memoryText = memory.rule + } + } + + if (isEditing) { + // 编辑模式:显示编辑界面 Column( - modifier = Modifier.weight(1f) + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(16.dp)) + .background(Color.White) + .padding(horizontal = 12.dp, vertical = 16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) ) { + // 文本输入框 - 带渐变边框 + Box( + modifier = Modifier + .fillMaxWidth() + .height(88.dp) + ) { + // 渐变边框层 + Box( + modifier = Modifier + .fillMaxSize() + .clip(RoundedCornerShape(16.dp)) + .background(brush = gradientBrush) + ) + + // 内容层 - 白色背景,通过padding形成边框效果 + Box( + modifier = Modifier + .fillMaxSize() + .padding(1.dp) + .clip(RoundedCornerShape(15.dp)) + .background(Color.White) + .padding(12.dp), + contentAlignment = Alignment.TopStart + ) { + BasicTextField( + value = memoryText, + onValueChange = { newText -> + if (newText.length <= maxLength) { + memoryText = newText + } + }, + cursorBrush = SolidColor(Color.Black), + modifier = Modifier.fillMaxWidth(), + textStyle = TextStyle( + fontSize = 13.sp, + color = Color.Black, + lineHeight = 18.sp + ), + decorationBox = { innerTextField -> + Box( + modifier = Modifier.fillMaxWidth(), + contentAlignment = Alignment.TopStart + ) { + innerTextField() + } + } + ) + } + } + + // 按钮行:取消和保存 + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + // 取消按钮 + Box( + modifier = Modifier + .weight(1f) + .height(34.dp) + .clip(RoundedCornerShape(653.8.dp)) + .background(Color(0x147C7480)) + .noRippleClickable { onCancel() }, + contentAlignment = Alignment.Center + ) { + Text( + text = "取消", + style = TextStyle( + fontSize = 15.sp, + color = Color.Black + ) + ) + } + + // 保存按钮 + Box( + modifier = Modifier + .weight(1f) + .height(34.dp) + .clip(RoundedCornerShape(653.8.dp)) + .background(Color(0xFF110C13)) + .noRippleClickable { + if (memoryText.isNotBlank() && memoryText != memory.rule) { + onSave(memoryText) + Toast.makeText(context, "记忆更新成功", Toast.LENGTH_SHORT).show() + } + }, + contentAlignment = Alignment.Center + ) { + Text( + text = "保存", + style = TextStyle( + fontSize = 15.sp, + color = Color.White + ) + ) + } + } + } + } else { + // 显示模式:显示记忆内容 + // 格式化日期:从 "2025-10-20T10:30:00Z" 格式转换为 "2025年10月20日" + val formattedDate = try { + if (memory.createdAt.length >= 10) { + val dateStr = memory.createdAt.substring(0, 10) + val parts = dateStr.split("-") + if (parts.size == 3) { + "${parts[0]}年${parts[1].toInt()}月${parts[2].toInt()}日" + } else { + dateStr + } + } else { + memory.createdAt + } + } catch (e: Exception) { + if (memory.createdAt.length >= 10) memory.createdAt.substring(0, 10) else memory.createdAt + } + + Column( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(16.dp)) + .background(Color.White) + .padding(horizontal = 12.dp, vertical = 16.dp) + ) { + // 主文本 - 顶部 Text( text = memory.rule, style = TextStyle( color = Color.Black, - fontSize = 14.sp, - lineHeight = 20.sp + fontSize = 13.sp, + lineHeight = 18.sp ), maxLines = 3, overflow = TextOverflow.Ellipsis ) - Spacer(modifier = Modifier.height(8.dp)) - Text( - text = "创建于 ${if (memory.createdAt.length >= 10) memory.createdAt.substring(0, 10) else memory.createdAt}", - style = TextStyle( - color = Color(0x993C3C43), - fontSize = 12.sp + + Spacer(modifier = Modifier.height(16.dp)) + + // 底部行:日期 + 编辑删除按钮 + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.Bottom + ) { + // 日期文本 - 左侧 + Text( + text = formattedDate, + style = TextStyle( + color = Color(0x993C3C43), + fontSize = 11.sp + ) ) - ) + + // 编辑和删除图标 - 右侧 + Row( + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + // 编辑图标 + Image( + painter = painterResource(R.mipmap.icons_infor_edit), + contentDescription = "编辑", + modifier = Modifier + .size(20.dp) + .noRippleClickable { onEdit() }, + colorFilter = ColorFilter.tint(Color.Black) + ) + + Image( + painter = painterResource(R.mipmap.iconsdelete), + contentDescription = "删除", + modifier = Modifier + .size(20.dp) + .noRippleClickable { onDelete() }, + colorFilter = ColorFilter.tint(Color(0xFFEE2A33)) + ) + } + } } - - // 删除按钮 - Image( - painter = painterResource(R.drawable.rider_pro_close), - contentDescription = "删除", - modifier = Modifier - .size(20.dp) - .noRippleClickable { onDelete() }, - colorFilter = ColorFilter.tint(Color(0x993C3C43)) - ) } } diff --git a/app/src/main/res/mipmap-xhdpi/group.png b/app/src/main/res/mipmap-xhdpi/group.png new file mode 100644 index 0000000000000000000000000000000000000000..8da6990def2f416b92d92008852cd49f51a7f0ab GIT binary patch literal 1534 zcmVPx#hfqvZMMrQ<`-3y*uc-QjGu74m*Vpva)cpK{G}hJl z`-C&p)cg8_H2Q)x)z$pg)%yB_Hq_Mo-`m{vnP1=B-QV2Z-rU^O)cpE`H2?qq-`w3J z7!}>!{q*$y`}6JS=>7b)hW*8#{^8I4(zg4QQ2eB6I4vtzPE7lYL8YOfetCDgx3-at zipa*r&51E90000MbW%=J0C^CYctg4)CFtJ4Tbf`$@8gTLpoMu9*7^Vd1oKHmK~#9! z?VQx}-3TxjOvQ|G7EtyX2V5)u*; z5)u*;68ay=P+g^#s~Q|ZtB&Rey?o74`JhIiJ8c~3fmgL)LYfQN*pt`~bf{66oZyKR znBm?8PqhIUbkz@DkPj}wD8Y+TIOPUL?gk44C@&gIxC7tdDW71uMFIlu1Pi5cXz)fb zk|ND0akASb8EmsqGvV%`40KN1OmfeV`w~cp#~t_%aL8!^Pj*j3&OEVD&z=E18NStB zlEi=#%gm?w(1SJW_Ys5fiZ*NU#w!WA5ddD1FyJi7Vgfut;*GnWZC+9FGpBI_MjFRE zTwTl!AQm5JV+=e?aP9;~b*s>PO`y`b0|!K57|+4d9L^eC8)fdvP{+i1q(K1Bp2s?_ z-IN8;z~krOzz%(f_HjNjH!SeRF3IZwXZ&$0Sl5$baZjjO5J<7&PM248>oyl~#^oVd z)n=Hjlew~-@$HH~R~W|AMhSdiWi3%nC6jFs>lR3vY<}7@Fpgo~AWG9FpT84get|gY zm1LINVa<)U61Z0~=$CNXL|&P{umy0FrP5sgX2V~6%?xBFp)BPF zGr!Wf97xO44E;fn;jk^i>9lEU+oe{gw?&YEG*|zO@xa$FN9JY4gZ zQTmWepuWuW=}?x3{D?!I^0FvOVwH8sJrw(pwnLF3N3e@-R8kxPxg2r$DMe+eEfdq1i~x&lu;gL zIa7Ai{34ip#U=wDU2f43^3$-1+ofCYQ;WqATqYgJMc8R{oFw#1pLl@ zy+!E=oZYGKkx8XJgZ%I9{w zjiT-L07*qoM6N<$f>USr5dZ)H literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/iconsdelete.png b/app/src/main/res/mipmap-xhdpi/iconsdelete.png new file mode 100644 index 0000000000000000000000000000000000000000..c8d38c225fe4bce2171eaf35ccd2c9763ceae689 GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM3?#3wJbMaAv7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgB04)6(abuaMwpl0w+%jmtP@f%fxcbZ1;fou)K_ZlXjR1My18^6;ud=C@^ zA`PIF@jESJ_gg!(f!YO1g8YIR^xv-+h`(y@AisZq{UrbVWuFh;0?M^}x;TbtoZlLB zQRuJ&N3g@H*}MMyzn=GYE7x5A-O=-kT!dVlf3R=6c4}3ey^lz zpe?aIS2=x_Z`QC@Y?^01<;Ay%rM6`S-S+<*%yW`h3$Hv)o)2^qgQu&X%Q~loCIAK0 Bdj|jj literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/group.png b/app/src/main/res/mipmap-xxhdpi/group.png new file mode 100644 index 0000000000000000000000000000000000000000..6e33cc845b127ac99c63c7015cc9c11cc49751fb GIT binary patch literal 2767 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/iconsdelete.png b/app/src/main/res/mipmap-xxxhdpi/iconsdelete.png new file mode 100644 index 0000000000000000000000000000000000000000..1cfe5284807092284d255869318d601be0c40663 GIT binary patch literal 575 zcmV-F0>J%=P)Px#El^BUMMrQLvYGVvxc?Z0^7 z5DP9Y;^L?%wMne<{TocumU8zluhm6Czsn=Xhs(X(_uY$O{OgBxQ5#?F#VjGvjh@Lk zA>>xI&=n%R>lo7p_ND-TUIPsSyN0m_Tx+0ZxIqrnK~q~&BV3BwqRvqYmkM@tg&#*1 zo42#Spsm*7n4~;`au8J~(6$VDU(aMsN}A4pXMaNvWfpi;{Zc`e29j784DiZr(-0uK zm0-hl1T9@_x(Vsc{2bR00Zo~6Rh@xczXVNvCt6-;#*ce zNhF6uz5uZ{D7|cVy`*)8WU>_ZSKIhadN92B8Qwin(k#EEMcCr4kN`HjPiGK}88yp4 zD$GSHY&lZv)Vb-2V=PUftUT;Us{Od@XT|9t?nya*axSzAU;IlyIiEVKGZ1|bO7Q>y N002ovPDHLkV1h8{^iTi* literal 0 HcmV?d00001 diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index bab4a9e..9c5838d 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -266,9 +266,20 @@ グループチャットを解散 グループメモリを追加 %d人のメンバー - ここに入力した内容は入力ボックスを超えると自動的に折り返されます + グループの記憶内容を入力、例えば、グループのメンバーは科学技術と設計を議論するのが好きである.... メモリを追加すると20コインを消費します AIは記憶に基づいて返信を最適化します いつでも編集または削除できます + グループメモリが正常に追加されました + グループ権限設定 + 公開グループ + 誰でも検索して参加できます + プライベートグループ + 招待のみ + 50コイン + 残高: %1$dコイン + アンロック費用: %1$dコイン + 完了 + チャージしてより多くのコインを獲得できます diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index ac2e155..0abc1b7 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -269,9 +269,20 @@ 解散群聊 添加群记忆 %d 位成员 - 这里的内容超过输入框自动换行 + 输入群记忆内容,例如:群成员喜欢讨论科技和设计.... 添加记忆需消耗 20 派币 AI 将基于记忆优化回复 可随时编辑或删除 + 群记忆添加成功 + 群权限设置 + 公开群组 + 任何人都可搜索并加入 + 私密群组 + 仅限邀请加入 + 50 派币 + 余额: %1$d 派币 + 解锁费用: %1$d 派币 + 完成 + 可通过充值获得更多派币 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 260074f..eb1d2df 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -264,8 +264,19 @@ Dissolve Group Chat Add Group Memory %d members - Content here will automatically wrap when it exceeds the input box + Input group memory content, for example: Group members enjoy discussing technology and design … Adding memory consumes 20 coins AI will optimize replies based on memory Can be edited or deleted at any time + Group memory added successfully + Group Permission Settings + Public Group + Anyone can search and join + Private Group + Invitation only + 50 coins + Balance: %1$d coins + Unlock cost: %1$d coins + Done + You can recharge to get more coins \ No newline at end of file From f90bfbfa0f210a74319605a83470c27516e337da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E5=B8=86?= <3031465419@qq.com> Date: Wed, 5 Nov 2025 21:31:11 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B7=B1=E8=89=B2?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E7=BC=BA=E7=9C=81=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/deploymentTargetSelector.xml | 4 +- .../main/java/com/aiosman/ravenow/store.kt | 25 ++++ .../main/java/com/aiosman/ravenow/ui/Navi.kt | 10 ++ .../ui/account/AccountEditViewModel.kt | 16 +++ .../ravenow/ui/account/MbtiSelectScreen.kt | 136 ++++++++++++++++++ .../ravenow/ui/account/ZodiacSelectScreen.kt | 132 +++++++++++++++++ .../ui/comment/notice/CommentNotice.kt | 7 +- .../ravenow/ui/favourite/FavouriteListPage.kt | 4 +- .../ravenow/ui/follower/FollowerList.kt | 10 +- .../ravenow/ui/follower/FollowerNotice.kt | 11 +- .../ravenow/ui/follower/FollowingList.kt | 8 +- .../tabs/message/tab/AgentChatListScreen.kt | 30 ++-- .../tabs/message/tab/AllChatListScreen.kt | 6 +- .../tabs/message/tab/FriendChatListScreen.kt | 30 ++-- .../tabs/message/tab/GroupChatListScreen.kt | 30 ++-- .../tabs/profile/composable/GalleryItem.kt | 9 +- .../tabs/profile/composable/UserAgentsList.kt | 5 +- .../com/aiosman/ravenow/ui/like/LikePage.kt | 9 +- .../com/aiosman/ravenow/ui/splash/splash.kt | 2 +- app/src/main/res/mipmap-hdpi/ai_dark.png | Bin 0 -> 2480 bytes app/src/main/res/mipmap-hdpi/fei_dark.png | Bin 0 -> 3213 bytes app/src/main/res/mipmap-hdpi/frame_3.png | Bin 0 -> 3874 bytes app/src/main/res/mipmap-hdpi/frame_4.png | Bin 0 -> 2128 bytes app/src/main/res/mipmap-hdpi/invalid_dark.png | Bin 0 -> 1654 bytes app/src/main/res/mipmap-hdpi/juhao_dark.png | Bin 0 -> 1713 bytes app/src/main/res/mipmap-hdpi/piao_dark.png | Bin 0 -> 2465 bytes app/src/main/res/mipmap-hdpi/sanqiu_dark.png | Bin 0 -> 3184 bytes app/src/main/res/mipmap-hdpi/shuihu_dark.png | Bin 0 -> 2085 bytes app/src/main/res/mipmap-hdpi/tietie_dark.png | Bin 0 -> 4073 bytes app/src/main/res/mipmap-mdpi/ai_dark.png | Bin 0 -> 1723 bytes app/src/main/res/mipmap-mdpi/fei_dark.png | Bin 0 -> 2332 bytes app/src/main/res/mipmap-mdpi/frame_3.png | Bin 0 -> 2586 bytes app/src/main/res/mipmap-mdpi/frame_4.png | Bin 0 -> 1523 bytes app/src/main/res/mipmap-mdpi/invalid_dark.png | Bin 0 -> 1185 bytes app/src/main/res/mipmap-mdpi/juhao_dark.png | Bin 0 -> 1291 bytes app/src/main/res/mipmap-mdpi/piao_dark.png | Bin 0 -> 1846 bytes app/src/main/res/mipmap-mdpi/sanqiu_dark.png | Bin 0 -> 2265 bytes app/src/main/res/mipmap-mdpi/shuihu_dark.png | Bin 0 -> 1488 bytes app/src/main/res/mipmap-mdpi/tietie_dark.png | Bin 0 -> 2822 bytes app/src/main/res/mipmap-xhdpi/ai_dark.png | Bin 1366 -> 2999 bytes app/src/main/res/mipmap-xhdpi/fei_dark.png | Bin 0 -> 4158 bytes app/src/main/res/mipmap-xhdpi/frame_3.png | Bin 0 -> 4972 bytes app/src/main/res/mipmap-xhdpi/frame_4.png | Bin 0 -> 2605 bytes .../main/res/mipmap-xhdpi/invalid_dark.png | Bin 1107 -> 2108 bytes app/src/main/res/mipmap-xhdpi/juhao_dark.png | Bin 0 -> 2168 bytes app/src/main/res/mipmap-xhdpi/piao_dark.png | Bin 0 -> 3244 bytes app/src/main/res/mipmap-xhdpi/sanqiu_dark.png | Bin 0 -> 4029 bytes app/src/main/res/mipmap-xhdpi/shuihu_dark.png | Bin 0 -> 2668 bytes app/src/main/res/mipmap-xhdpi/tietie_dark.png | Bin 0 -> 4969 bytes app/src/main/res/mipmap-xxhdpi/ai_dark.png | Bin 2888 -> 4434 bytes app/src/main/res/mipmap-xxhdpi/fei_dark.png | Bin 0 -> 6020 bytes app/src/main/res/mipmap-xxhdpi/frame_3.png | Bin 0 -> 7534 bytes app/src/main/res/mipmap-xxhdpi/frame_4.png | Bin 0 -> 3648 bytes .../main/res/mipmap-xxhdpi/invalid_dark.png | Bin 2066 -> 3082 bytes app/src/main/res/mipmap-xxhdpi/juhao_dark.png | Bin 0 -> 2921 bytes app/src/main/res/mipmap-xxhdpi/piao_dark.png | Bin 0 -> 4716 bytes .../main/res/mipmap-xxhdpi/sanqiu_dark.png | Bin 0 -> 5947 bytes .../main/res/mipmap-xxhdpi/shuihu_dark.png | Bin 0 -> 3983 bytes .../main/res/mipmap-xxhdpi/tietie_dark.png | Bin 0 -> 7497 bytes app/src/main/res/mipmap-xxxhdpi/ai_dark.png | Bin 3510 -> 5545 bytes app/src/main/res/mipmap-xxxhdpi/fei_dark.png | Bin 0 -> 7788 bytes app/src/main/res/mipmap-xxxhdpi/frame_3.png | Bin 0 -> 9776 bytes app/src/main/res/mipmap-xxxhdpi/frame_4.png | Bin 0 -> 4713 bytes .../main/res/mipmap-xxxhdpi/invalid_dark.png | Bin 2602 -> 3801 bytes .../main/res/mipmap-xxxhdpi/juhao_dark.png | Bin 0 -> 3915 bytes app/src/main/res/mipmap-xxxhdpi/piao_dark.png | Bin 0 -> 6297 bytes .../main/res/mipmap-xxxhdpi/sanqiu_dark.png | Bin 0 -> 7667 bytes .../main/res/mipmap-xxxhdpi/shuihu_dark.png | Bin 0 -> 5100 bytes .../main/res/mipmap-xxxhdpi/tietie_dark.png | Bin 0 -> 9862 bytes app/src/main/res/values-zh/strings.xml | 19 ++- app/src/main/res/values/strings.xml | 7 + 71 files changed, 424 insertions(+), 86 deletions(-) create mode 100644 app/src/main/java/com/aiosman/ravenow/ui/account/MbtiSelectScreen.kt create mode 100644 app/src/main/java/com/aiosman/ravenow/ui/account/ZodiacSelectScreen.kt create mode 100644 app/src/main/res/mipmap-hdpi/ai_dark.png create mode 100644 app/src/main/res/mipmap-hdpi/fei_dark.png create mode 100644 app/src/main/res/mipmap-hdpi/frame_3.png create mode 100644 app/src/main/res/mipmap-hdpi/frame_4.png create mode 100644 app/src/main/res/mipmap-hdpi/invalid_dark.png create mode 100644 app/src/main/res/mipmap-hdpi/juhao_dark.png create mode 100644 app/src/main/res/mipmap-hdpi/piao_dark.png create mode 100644 app/src/main/res/mipmap-hdpi/sanqiu_dark.png create mode 100644 app/src/main/res/mipmap-hdpi/shuihu_dark.png create mode 100644 app/src/main/res/mipmap-hdpi/tietie_dark.png create mode 100644 app/src/main/res/mipmap-mdpi/ai_dark.png create mode 100644 app/src/main/res/mipmap-mdpi/fei_dark.png create mode 100644 app/src/main/res/mipmap-mdpi/frame_3.png create mode 100644 app/src/main/res/mipmap-mdpi/frame_4.png create mode 100644 app/src/main/res/mipmap-mdpi/invalid_dark.png create mode 100644 app/src/main/res/mipmap-mdpi/juhao_dark.png create mode 100644 app/src/main/res/mipmap-mdpi/piao_dark.png create mode 100644 app/src/main/res/mipmap-mdpi/sanqiu_dark.png create mode 100644 app/src/main/res/mipmap-mdpi/shuihu_dark.png create mode 100644 app/src/main/res/mipmap-mdpi/tietie_dark.png create mode 100644 app/src/main/res/mipmap-xhdpi/fei_dark.png create mode 100644 app/src/main/res/mipmap-xhdpi/frame_3.png create mode 100644 app/src/main/res/mipmap-xhdpi/frame_4.png create mode 100644 app/src/main/res/mipmap-xhdpi/juhao_dark.png create mode 100644 app/src/main/res/mipmap-xhdpi/piao_dark.png create mode 100644 app/src/main/res/mipmap-xhdpi/sanqiu_dark.png create mode 100644 app/src/main/res/mipmap-xhdpi/shuihu_dark.png create mode 100644 app/src/main/res/mipmap-xhdpi/tietie_dark.png create mode 100644 app/src/main/res/mipmap-xxhdpi/fei_dark.png create mode 100644 app/src/main/res/mipmap-xxhdpi/frame_3.png create mode 100644 app/src/main/res/mipmap-xxhdpi/frame_4.png create mode 100644 app/src/main/res/mipmap-xxhdpi/juhao_dark.png create mode 100644 app/src/main/res/mipmap-xxhdpi/piao_dark.png create mode 100644 app/src/main/res/mipmap-xxhdpi/sanqiu_dark.png create mode 100644 app/src/main/res/mipmap-xxhdpi/shuihu_dark.png create mode 100644 app/src/main/res/mipmap-xxhdpi/tietie_dark.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/fei_dark.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/frame_3.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/frame_4.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/juhao_dark.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/piao_dark.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/sanqiu_dark.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/shuihu_dark.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/tietie_dark.png diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml index 826cbf2..fc1e130 100644 --- a/.idea/deploymentTargetSelector.xml +++ b/.idea/deploymentTargetSelector.xml @@ -4,10 +4,10 @@