From d7f87c7c55e5cba44aa4c2b29bc8475be74aa6da Mon Sep 17 00:00:00 2001 From: zhong <2724770085@qq.com> Date: Fri, 31 Oct 2025 11:57:49 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=81=8A=E5=A4=A9=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E9=A1=B5=E9=9D=A2=EF=BC=9B=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E8=83=8C=E6=99=AFUI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/aiosman/ravenow/ui/Navi.kt | 10 + .../aiosman/ravenow/ui/chat/ChatAiScreen.kt | 33 +- .../com/aiosman/ravenow/ui/chat/ChatScreen.kt | 31 +- .../ravenow/ui/chat/ChatSettingScreen.kt | 356 ++++++++++++++++++ .../ravenow/ui/index/tabs/moment/Moment.kt | 3 +- app/src/main/res/values-ja/strings.xml | 12 + app/src/main/res/values-zh/strings.xml | 10 + app/src/main/res/values/strings.xml | 13 + 8 files changed, 407 insertions(+), 61 deletions(-) create mode 100644 app/src/main/java/com/aiosman/ravenow/ui/chat/ChatSettingScreen.kt diff --git a/app/src/main/java/com/aiosman/ravenow/ui/Navi.kt b/app/src/main/java/com/aiosman/ravenow/ui/Navi.kt index badb13e..63af769 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/Navi.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/Navi.kt @@ -41,6 +41,7 @@ import com.aiosman.ravenow.ui.agent.AddAgentScreen import com.aiosman.ravenow.ui.agent.AgentImageCropScreen import com.aiosman.ravenow.ui.group.CreateGroupChatScreen import com.aiosman.ravenow.ui.chat.ChatAiScreen +import com.aiosman.ravenow.ui.chat.ChatSettingScreen import com.aiosman.ravenow.ui.chat.ChatScreen import com.aiosman.ravenow.ui.chat.GroupChatScreen import com.aiosman.ravenow.ui.comment.CommentsScreen @@ -106,6 +107,7 @@ sealed class NavigationRoute( data object FavouriteList : NavigationRoute("FavouriteList") data object Chat : NavigationRoute("Chat/{id}") data object ChatAi : NavigationRoute("ChatAi/{id}") + data object ChatSetting : NavigationRoute("ChatSetting") data object ChatGroup : NavigationRoute("ChatGroup/{id}/{name}/{avatar}") data object CommentNoticeScreen : NavigationRoute("CommentNoticeScreen") data object ImageCrop : NavigationRoute("ImageCrop") @@ -491,6 +493,14 @@ fun NavigationController( } } + composable(route = NavigationRoute.ChatSetting.route) { + CompositionLocalProvider( + LocalAnimatedContentScope provides this, + ) { + ChatSettingScreen() + } + } + composable( route = NavigationRoute.ChatGroup.route, arguments = listOf(navArgument("id") { type = NavType.StringType }, diff --git a/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatAiScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatAiScreen.kt index 38121bb..6fb338e 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatAiScreen.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatAiScreen.kt @@ -79,11 +79,10 @@ import com.aiosman.ravenow.R import com.aiosman.ravenow.entity.ChatItem import com.aiosman.ravenow.exp.formatChatTime import com.aiosman.ravenow.ui.composables.CustomAsyncImage -import com.aiosman.ravenow.ui.composables.DropdownMenu -import com.aiosman.ravenow.ui.composables.MenuItem import com.aiosman.ravenow.ui.composables.StatusBarSpacer import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.utils.NetworkUtils +import com.aiosman.ravenow.ui.NavigationRoute import io.openim.android.sdk.enums.MessageType import kotlinx.coroutines.launch import java.util.UUID @@ -91,7 +90,6 @@ import java.util.UUID @Composable fun ChatAiScreen(userId: String) { - var isMenuExpanded by remember { mutableStateOf(false) } val navController = LocalNavController.current val context = LocalNavController.current.context val AppColors = LocalAppTheme.current @@ -213,39 +211,12 @@ fun ChatAiScreen(userId: String) { modifier = Modifier .size(28.dp) .noRippleClickable { - isMenuExpanded = true + navController.navigate(NavigationRoute.ChatSetting.route) }, contentDescription = null, colorFilter = ColorFilter.tint( AppColors.text) ) - DropdownMenu( - expanded = isMenuExpanded, - onDismissRequest = { - isMenuExpanded = false - }, - menuItems = listOf( - MenuItem( - title = if (viewModel.notificationStrategy == "mute") "Unmute" else "Mute", - icon = if (viewModel.notificationStrategy == "mute") R.drawable.rider_pro_notice_mute else R.drawable.rider_pro_notice_active, - ) { - - isMenuExpanded = false - if (NetworkUtils.isNetworkAvailable(context)) { - viewModel.viewModelScope.launch { - if (viewModel.notificationStrategy == "mute") { - viewModel.updateNotificationStrategy("active") - } else { - viewModel.updateNotificationStrategy("mute") - } - } - } else { - android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show() - } - } - ), - - ) } } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatScreen.kt index 374878c..8cf76de 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatScreen.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatScreen.kt @@ -78,6 +78,7 @@ import com.aiosman.ravenow.LocalNavController import com.aiosman.ravenow.R import com.aiosman.ravenow.entity.ChatItem import com.aiosman.ravenow.exp.formatChatTime +import com.aiosman.ravenow.ui.NavigationRoute import com.aiosman.ravenow.ui.composables.CustomAsyncImage import com.aiosman.ravenow.ui.composables.DropdownMenu import com.aiosman.ravenow.ui.composables.MenuItem @@ -91,7 +92,6 @@ import java.util.UUID @Composable fun ChatScreen(userId: String) { - var isMenuExpanded by remember { mutableStateOf(false) } val navController = LocalNavController.current val context = LocalNavController.current.context val AppColors = LocalAppTheme.current @@ -214,39 +214,12 @@ fun ChatScreen(userId: String) { modifier = Modifier .size(28.dp) .noRippleClickable { - isMenuExpanded = true + navController.navigate(NavigationRoute.ChatSetting.route) }, contentDescription = null, colorFilter = ColorFilter.tint( AppColors.text) ) - DropdownMenu( - expanded = isMenuExpanded, - onDismissRequest = { - isMenuExpanded = false - }, - menuItems = listOf( - MenuItem( - title = if (viewModel.notificationStrategy == "mute") "取消静音" else "静音", - icon = if (viewModel.notificationStrategy == "mute") R.drawable.rider_pro_notice_mute else R.drawable.rider_pro_notice_active, - ) { - - isMenuExpanded = false - if (NetworkUtils.isNetworkAvailable(context)) { - viewModel.viewModelScope.launch { - if (viewModel.notificationStrategy == "mute") { - viewModel.updateNotificationStrategy("active") - } else { - viewModel.updateNotificationStrategy("mute") - } - } - } else { - android.widget.Toast.makeText(context, "网络连接异常,请检查网络设置", android.widget.Toast.LENGTH_SHORT).show() - } - } - ), - - ) } } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatSettingScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatSettingScreen.kt new file mode 100644 index 0000000..56c2698 --- /dev/null +++ b/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatSettingScreen.kt @@ -0,0 +1,356 @@ +package com.aiosman.ravenow.ui.chat + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.SheetState +import androidx.compose.material3.rememberModalBottomSheetState +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.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.aiosman.ravenow.LocalAppTheme +import com.aiosman.ravenow.LocalNavController +import com.aiosman.ravenow.R +import com.aiosman.ravenow.ui.composables.StatusBarSpacer +import com.aiosman.ravenow.ui.comment.NoticeScreenHeader +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.IconButton +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.text.style.TextAlign +import com.aiosman.ravenow.ui.composables.CustomAsyncImage + +@Composable +fun ChatSettingScreen() { + val appColors = LocalAppTheme.current + val navController = LocalNavController.current + var showThemeSheet by remember { mutableStateOf(false) } + + Column( + modifier = Modifier + .fillMaxSize() + .background(appColors.secondaryBackground) + ) { + StatusBarSpacer() + Box(modifier = Modifier.padding(horizontal = 24.dp, vertical = 16.dp)) { + NoticeScreenHeader(title = stringResource(R.string.chat_settings), moreIcon = false) + } + + Column(modifier = Modifier.padding(horizontal = 16.dp)) { + SettingCard( + title = stringResource(R.string.chat_theme_settings), + onClick = { showThemeSheet = true } + ) + Spacer(modifier = Modifier.height(12.dp)) + SettingCard( + title = stringResource(R.string.report), + onClick = { /* TODO: 跳转举报 */ } + ) + } + } + + if (showThemeSheet) { + ThemePickerSheet(onClose = { showThemeSheet = false }) + } +} + +@Composable +private fun SettingCard(title: String, onClick: () -> Unit) { + val appColors = LocalAppTheme.current + Box( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(12.dp)) + .background(appColors.background) + .clickable { onClick() } + .padding(horizontal = 12.dp, vertical = 14.dp) + ) { + Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) { + Text( + text = title, + color = appColors.text, + fontSize = 16.sp, + fontWeight = FontWeight.W500, + modifier = Modifier.weight(1f) + ) + Icon( + painter = painterResource(id = R.drawable.rave_now_nav_right), + contentDescription = null, + tint = appColors.text, + modifier = Modifier.size(20.dp) + ) + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun ThemePickerSheet(onClose: () -> Unit) { + val appColors = LocalAppTheme.current + val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + val configuration = LocalConfiguration.current + val screenHeight = configuration.screenHeightDp.dp + val sheetHeight = screenHeight * 0.9f + var previewUrl by remember { mutableStateOf(null) } + ModalBottomSheet( + onDismissRequest = onClose, + sheetState = sheetState, + containerColor = appColors.secondaryBackground, + dragHandle = null, + modifier = Modifier + .fillMaxWidth() + .height(sheetHeight), + ) { + Column(modifier = Modifier.padding(horizontal = 16.dp)) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 4.dp, bottom = 8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Spacer(modifier = Modifier.size(24.dp)) + Text( + text = stringResource(R.string.custom_background), + color = appColors.text, + fontSize = 16.sp, + fontWeight = FontWeight.W600, + modifier = Modifier.weight(1f).padding(start = 100.dp), + ) + IconButton(onClick = onClose) { + Icon( + painter = painterResource(id = R.drawable.rider_pro_close), + contentDescription = "close", + tint = appColors.text + ) + } + } + + // 从相册选择 + Row( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(12.dp)) + .background(appColors.background) + .clickable { /* TODO: 打开相册选择 */ } + .padding(horizontal = 16.dp, vertical = 14.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text(text = stringResource(R.string.select_from_gallery), color = appColors.text, fontSize = 15.sp, modifier = Modifier.weight(1f)) + Icon( + painter = painterResource(id = R.drawable.group_info_edit), + contentDescription = null, + tint = appColors.text, + modifier = Modifier.size(20.dp) + ) + } + + Spacer(modifier = Modifier.height(12.dp)) + Text(text = stringResource(R.string.featured_backgrounds), color = appColors.text, fontSize = 12.sp) + Spacer(modifier = Modifier.height(8.dp)) + + val presets = remember { + listOf( + "https://picsum.photos/seed/ai1/400/600", + "https://picsum.photos/seed/ai2/400/600", + "https://picsum.photos/seed/ai3/400/600", + "https://picsum.photos/seed/ai4/400/600", + "https://picsum.photos/seed/ai5/400/600", + "https://picsum.photos/seed/ai6/400/600", + "https://picsum.photos/seed/ai7/400/600", + "https://picsum.photos/seed/ai8/400/600", + "https://picsum.photos/seed/ai9/400/600", + "https://picsum.photos/seed/ai10/400/600", + "https://picsum.photos/seed/ai11/400/600", + "https://picsum.photos/seed/ai12/400/600", + "https://picsum.photos/seed/ai13/400/600", + "https://picsum.photos/seed/ai14/400/600", + "https://picsum.photos/seed/ai15/400/600", + ) + } + + LazyVerticalGrid( + columns = GridCells.Fixed(3), + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), + modifier = Modifier + .fillMaxWidth() + ) { + items(presets) { url -> + Column( + modifier = Modifier + .fillMaxWidth() + .clickable { previewUrl = url } + ) { + Box( + modifier = Modifier + .clip(RoundedCornerShape(12.dp)) + .background(appColors.decentBackground) + ) { + CustomAsyncImage( + imageUrl = url, + modifier = Modifier + .fillMaxWidth() + .aspectRatio(3f / 4f), + contentDescription = "preset", + contentScale = ContentScale.Crop + ) + } + Spacer(modifier = Modifier.height(6.dp)) + Text( + text = "Heart Drive", + color = appColors.text, + fontSize = 12.sp + ) + } + } + } + + // 预览自定义背景弹窗 + if (previewUrl != null) { + ModalBottomSheet( + onDismissRequest = { previewUrl = null }, + sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), + containerColor = appColors.secondaryBackground, + dragHandle = null, + modifier = Modifier + .fillMaxWidth() + .height(sheetHeight) + ) { + Box(modifier = Modifier.fillMaxSize()) { + CustomAsyncImage( + imageUrl = previewUrl!!, + modifier = Modifier.fillMaxSize(), + contentDescription = "preview_bg", + contentScale = ContentScale.Crop + ) + + Column(modifier = Modifier + .fillMaxSize() + .padding(horizontal = 16.dp, vertical = 8.dp)) { + Box( + modifier = Modifier + .align(Alignment.CenterHorizontally) + .padding(horizontal = 12.dp, vertical = 16.dp) + ) { + Text(text = stringResource(R.string.previewing_custom_background), color = Color.White, fontSize = 15.sp) + } + + + Column(modifier = Modifier.padding(8.dp)) { + Row { + Box( + modifier = Modifier + .clip(RoundedCornerShape(24.dp)) + .background(Color.White) + .padding(horizontal = 14.dp, vertical = 8.dp) + ) { + Text(text = stringResource(R.string.each_theme_unique_experience), color = Color.Black, fontSize = 12.sp) + } + } + Spacer(modifier = Modifier.height(12.dp)) + Row { + Box( + modifier = Modifier + .clip(RoundedCornerShape(24.dp)) + .background(Color.White) + .padding(horizontal = 14.dp, vertical = 8.dp) + ) { + Text(text = stringResource(R.string.select_apply_to_use_theme), color = Color.Black, fontSize = 12.sp) + } + } + Spacer(modifier = Modifier.height(12.dp)) + Row { + Spacer(modifier = Modifier.weight(1f)) + Box( + modifier = Modifier + .clip(RoundedCornerShape(20.dp)) + .background(Color(0xFF7C4DFF)) + .padding(horizontal = 16.dp, vertical = 8.dp) + ) { + Text(text = stringResource(R.string.tap_cancel_to_preview_other_themes), color = Color.White, fontSize = 12.sp) + } + } + } + + Spacer(modifier = Modifier.weight(1f)) + + // 底部按钮 + Row( + modifier = Modifier.fillMaxWidth() + .padding(bottom = 60.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .weight(1f) + .clip(RoundedCornerShape(12.dp)) + .background(Color.White) + .clickable { previewUrl = null } + .padding(vertical = 12.dp), + contentAlignment = Alignment.Center + ) { + Text(text = stringResource(R.string.cancel), color = Color.Black, fontSize = 14.sp) + } + Spacer(modifier = Modifier.size(12.dp)) + Box( + modifier = Modifier + .weight(1f) + .clip(RoundedCornerShape(12.dp)) + .background( + brush = Brush.horizontalGradient( + colors = listOf( + Color(0xFFEE2A33), + Color(0xFFD80264), + Color(0xFF664C92) + ) + ) + ) + .clickable { } + .padding(vertical = 12.dp), + contentAlignment = Alignment.Center + ) { + Text(text = stringResource(R.string.moment_ai_apply), color = Color.White, fontSize = 14.sp) + } + } + } + } + } + } + } + } +} + + diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/Moment.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/Moment.kt index 6cb0026..665c1a3 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/Moment.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/Moment.kt @@ -230,9 +230,10 @@ fun MomentsList() { when (it) { 0 -> { // 推荐页面 + NewsScreen() } 1 -> { - // 短视频页面 + // 短视频页面 } 2 -> { // 动态页面 - 暂时显示时间线内容 diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 0d5200f..d849e3a 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -236,5 +236,17 @@ 相手はあなたにメッセージを送信したり、あなたのプロフィールやコンテンツを見つけることができなくなります 相手はあなたにブロックされた通知を受け取りません 「設定」でいつでもブロックを解除できます + + + チャット設定 + チャットテーマを設定 + カスタム背景 + ギャラリーから選択 + おすすめ背景 + カスタム背景をプレビュー中 + 各テーマには独自の体験があります + 「適用」を選択してこのテーマを使用 + 「キャンセル」をタップして他のテーマをプレビュー + diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index dd637d7..2ce035d 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -240,4 +240,14 @@ 对方不会收到自己被你拉黑的通知 你可以随时"设置"中取消拉黑TA + + 聊天设置 + 设置聊天主题 + 自定义背景 + 从相册选择 + 精选背景 + 正在预览自定义背景 + 每个主题都有自己独特的体验 + 选择"应用"可选中这个主题 + 轻触"取消"可预览其他主题 \ 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 bb229c8..02549e6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -234,4 +234,17 @@ They won\'t be able to send you messages or find your profile or content They won\'t receive a notification that you blocked them You can unblock them anytime in "Settings" + + + Chat Settings + Set Chat Theme + Custom Background + Select from Gallery + Featured Backgrounds + Previewing Custom Background + Each theme has its own unique experience + Select "Apply" to use this theme + Tap "Cancel" to preview other themes + + \ No newline at end of file