From 6d48ad74effd3acc10e8bf9c09fc168887f30ce7 Mon Sep 17 00:00:00 2001 From: Eric85710 Date: Wed, 10 Jun 2026 15:58:09 +0800 Subject: [PATCH] dm-111 --- .../Message/UI/Detail/Message_Messaging.kt | 311 +++++++++--------- .../home/Message/UI/Detail/Message_list.kt | 227 +++++++------ .../login_v3/home/Message/UI/Message.kt | 117 +++---- 3 files changed, 342 insertions(+), 313 deletions(-) diff --git a/app/src/main/java/com/example/login_v3/home/Message/UI/Detail/Message_Messaging.kt b/app/src/main/java/com/example/login_v3/home/Message/UI/Detail/Message_Messaging.kt index 189d1b6..3db86b3 100644 --- a/app/src/main/java/com/example/login_v3/home/Message/UI/Detail/Message_Messaging.kt +++ b/app/src/main/java/com/example/login_v3/home/Message/UI/Detail/Message_Messaging.kt @@ -7,6 +7,8 @@ import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.AnimatedVisibilityScope +import androidx.compose.animation.SharedTransitionScope import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable @@ -105,6 +107,8 @@ fun MessageMessaging( roomId: String, navController: NavController, onBackClick: () -> Unit, + sharedTransitionScope: SharedTransitionScope, + animatedVisibilityScope: AnimatedVisibilityScope, viewModel: ChatViewModel = hiltViewModel(), bottomBarViewModel: BottomBarViewModel ) { @@ -175,172 +179,177 @@ fun MessageMessaging( is MessagesUiState.Loading -> "載入中..." } - Scaffold( - modifier = Modifier - .fillMaxSize() - .background( - brush = Brush.verticalGradient( - colors = listOf - (Color(0xFFDA7029), - Color(0xFF777777), - Color(0xFFB34800)) + + with(sharedTransitionScope){ + Scaffold( + modifier = Modifier + .fillMaxSize() + .background( + brush = Brush.verticalGradient( + colors = listOf + (Color(0xFFDA7029), + Color(0xFF777777), + Color(0xFFB34800)) + ) + ), + containerColor = Color.Transparent, + topBar = { + TopAppBar( + title = { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + val currentState = uiState + if (currentState is MessagesUiState.Success) { + UserAvatar( + avatarUrl = currentState.partnerAvatarUrl, + modifier = Modifier.size(36.dp) + ) + } + + Text(text = topBarTitle) + + if (currentState is MessagesUiState.Success) { + if (currentState.partnerStatus == UserStatus.ONLINE) { + Box( + modifier = Modifier + .size(10.dp) + .background( + color = UserStatus.ONLINE.color, + shape = CircleShape + ) + ) + } + } + } + }, + // 🌟 關鍵修改 1:設定半透明背景色 + colors = TopAppBarDefaults.topAppBarColors( + // 這裡可以用 Surface 色加上 0.6 的透明度,或者直接用自訂顏色如 Color.White.copy(0.5f) + containerColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.4f) + ) ) - ), - containerColor = Color.Transparent, - topBar = { - TopAppBar( - title = { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - val currentState = uiState - if (currentState is MessagesUiState.Success) { - UserAvatar( - avatarUrl = currentState.partnerAvatarUrl, - modifier = Modifier.size(36.dp) + }, + bottomBar = { + // 👈 使用我們定義的 sealed interface 狀態機 + AnimatedContent( + targetState = bottomBarState, + label = "BottomBarSwitchAnimation" + ) { currentState -> + when (currentState) { + is BottomBarState.Input -> { + MessageInputBar( + isLoading = sendStatus is SendMessageState.Loading, + replyingMessage = replyingMessage, + onCancelReply = { viewModel.setReplyingMessage(null) }, + onSendClick = { content -> viewModel.sendMessage(roomId, content) }, + onImageSelected = { uri -> viewModel.uploadAttachment(roomId, uri) }, ) } - Text(text = topBarTitle) + is BottomBarState.ActionMenu -> { + val currentActionMessage = currentState.message + val currentUserId = (uiState as? MessagesUiState.Success)?.currentUserId + val isOwnMessage = currentActionMessage.senderId == currentUserId - if (currentState is MessagesUiState.Success) { - if (currentState.partnerStatus == UserStatus.ONLINE) { - Box( - modifier = Modifier - .size(10.dp) - .background( - color = UserStatus.ONLINE.color, - shape = CircleShape - ) - ) - } + MessageActionMenuRow( + message = currentActionMessage, + isOwnMessage = isOwnMessage, + onCancel = { viewModel.clearActionMessage() }, + onReplyClick = { msg -> + viewModel.setReplyingMessage(msg) + viewModel.clearActionMessage() + }, + onDeleteClick = { msg -> + // 🌟 核心防呆:如果訊息還在發送中(SENDING),禁止點擊刪除,避免 tempId 送給後端造成 404 + if (msg.status == MessageStatus.SENDING) { + // 可以選擇在這裡彈出一個短暫的 Toast 提示使用者 + Toast.makeText(context, "訊息發送中,請稍後再操作", Toast.LENGTH_SHORT).show() + } else { + // 正常訊息,呼叫樂觀更新刪除 + viewModel.deleteMessage(roomId, msg.id) + } + } + ) } - } - }, - // 🌟 關鍵修改 1:設定半透明背景色 - colors = TopAppBarDefaults.topAppBarColors( - // 這裡可以用 Surface 色加上 0.6 的透明度,或者直接用自訂顏色如 Color.White.copy(0.5f) - containerColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.6f) - ) - ) - }, - bottomBar = { - // 👈 使用我們定義的 sealed interface 狀態機 - AnimatedContent( - targetState = bottomBarState, - label = "BottomBarSwitchAnimation" - ) { currentState -> - when (currentState) { - is BottomBarState.Input -> { - MessageInputBar( - isLoading = sendStatus is SendMessageState.Loading, - replyingMessage = replyingMessage, - onCancelReply = { viewModel.setReplyingMessage(null) }, - onSendClick = { content -> viewModel.sendMessage(roomId, content) }, - onImageSelected = { uri -> viewModel.uploadAttachment(roomId, uri) }, - ) - } - is BottomBarState.ActionMenu -> { - val currentActionMessage = currentState.message - val currentUserId = (uiState as? MessagesUiState.Success)?.currentUserId - val isOwnMessage = currentActionMessage.senderId == currentUserId - - MessageActionMenuRow( - message = currentActionMessage, - isOwnMessage = isOwnMessage, - onCancel = { viewModel.clearActionMessage() }, - onReplyClick = { msg -> - viewModel.setReplyingMessage(msg) - viewModel.clearActionMessage() - }, - onDeleteClick = { msg -> - // 🌟 核心防呆:如果訊息還在發送中(SENDING),禁止點擊刪除,避免 tempId 送給後端造成 404 - if (msg.status == MessageStatus.SENDING) { - // 可以選擇在這裡彈出一個短暫的 Toast 提示使用者 - Toast.makeText(context, "訊息發送中,請稍後再操作", Toast.LENGTH_SHORT).show() - } else { - // 正常訊息,呼叫樂觀更新刪除 - viewModel.deleteMessage(roomId, msg.id) + is BottomBarState.EmojiMenu -> { + // 👈 渲染全新設計的獨立 Emoji Bar + val currentEmojiMessage = currentState.message + MessageEmojiBar( + // 🌟 移除了 commonEmojis 參數,變得非常清爽! + onEmojiClick = { emoji -> + val targetReaction = currentEmojiMessage.reactions?.find { it.emoji == emoji } + if (targetReaction?.meReacted == true) { + viewModel.removeMessageReaction(roomId, currentEmojiMessage.id, emoji) + } else { + viewModel.addMessageReaction(roomId, currentEmojiMessage.id, emoji) + } + emojiTargetMessage = null // 點完後自動關閉 + }, + onCancel = { + emojiTargetMessage = null // 點擊關閉 } - } - ) - } - - is BottomBarState.EmojiMenu -> { - // 👈 渲染全新設計的獨立 Emoji Bar - val currentEmojiMessage = currentState.message - MessageEmojiBar( - // 🌟 移除了 commonEmojis 參數,變得非常清爽! - onEmojiClick = { emoji -> - val targetReaction = currentEmojiMessage.reactions?.find { it.emoji == emoji } - if (targetReaction?.meReacted == true) { - viewModel.removeMessageReaction(roomId, currentEmojiMessage.id, emoji) - } else { - viewModel.addMessageReaction(roomId, currentEmojiMessage.id, emoji) - } - emojiTargetMessage = null // 點完後自動關閉 - }, - onCancel = { - emojiTargetMessage = null // 點擊關閉 - } - ) + ) + } } } } - } - ) { innerPadding -> - Box( - modifier = Modifier - .fillMaxSize() - .padding(innerPadding) - , - contentAlignment = Alignment.Center - ) { - // 根據不同的狀態渲染主畫面內容 - when (val state = uiState) { - is MessagesUiState.Loading -> { - CircularProgressIndicator() - } - is MessagesUiState.Success -> { - if (state.messages.isEmpty()) { - Text("目前沒有新訊息") - } else { - MessageList( - currentUserId = state.currentUserId, - messages = state.messages, - partnerAvatarUrl = state.partnerAvatarUrl, - partnerDisplayName = state.roomTitle, - activeEmojiMessageId = emojiTargetMessage?.id, // ✨ 新增短按目標 ID - activeActionMessageId = actionMessage?.id, - onReplyClick = { message -> - emojiTargetMessage = null - viewModel.setActionMessage(message) - }, - // 💡 單擊事件:開啟 Emoji 選單,同時清空長按選單 - onRowClick = { message -> - viewModel.clearActionMessage() - emojiTargetMessage = message - }, - onReactionClick = { message, emoji -> - // 這是訊息氣泡下方既有 Reaction 小標籤的點擊事件,保持原樣即可 - val targetReaction = message.reactions?.find { it.emoji == emoji } - if (targetReaction?.meReacted == true) { - viewModel.removeMessageReaction(roomId, message.id, emoji) - } else { - viewModel.addMessageReaction(roomId, message.id, emoji) + ) { innerPadding -> + Box( + modifier = Modifier + .fillMaxSize() + .padding(innerPadding), + contentAlignment = Alignment.Center + ) { + // 根據不同的狀態渲染主畫面內容 + when (val state = uiState) { + is MessagesUiState.Loading -> { + CircularProgressIndicator() + } + + is MessagesUiState.Success -> { + if (state.messages.isEmpty()) { + Text("目前沒有新訊息") + } else { + MessageList( + currentUserId = state.currentUserId, + messages = state.messages, + partnerAvatarUrl = state.partnerAvatarUrl, + partnerDisplayName = state.roomTitle, + activeEmojiMessageId = emojiTargetMessage?.id, // ✨ 新增短按目標 ID + activeActionMessageId = actionMessage?.id, + onReplyClick = { message -> + emojiTargetMessage = null + viewModel.setActionMessage(message) + }, + // 💡 單擊事件:開啟 Emoji 選單,同時清空長按選單 + onRowClick = { message -> + viewModel.clearActionMessage() + emojiTargetMessage = message + }, + onReactionClick = { message, emoji -> + // 這是訊息氣泡下方既有 Reaction 小標籤的點擊事件,保持原樣即可 + val targetReaction = + message.reactions?.find { it.emoji == emoji } + if (targetReaction?.meReacted == true) { + viewModel.removeMessageReaction(roomId, message.id, emoji) + } else { + viewModel.addMessageReaction(roomId, message.id, emoji) + } } - } + ) + } + } + + is MessagesUiState.Error -> { + Text( + text = "載入失敗:${state.message}", + color = MaterialTheme.colorScheme.error ) } } - is MessagesUiState.Error -> { - Text( - text = "載入失敗:${state.message}", - color = MaterialTheme.colorScheme.error - ) - } } } } diff --git a/app/src/main/java/com/example/login_v3/home/Message/UI/Detail/Message_list.kt b/app/src/main/java/com/example/login_v3/home/Message/UI/Detail/Message_list.kt index 3b95892..cfc5a59 100644 --- a/app/src/main/java/com/example/login_v3/home/Message/UI/Detail/Message_list.kt +++ b/app/src/main/java/com/example/login_v3/home/Message/UI/Detail/Message_list.kt @@ -1,5 +1,7 @@ package com.example.login_v3.home.Message.UI.Detail +import androidx.compose.animation.AnimatedVisibilityScope +import androidx.compose.animation.SharedTransitionScope import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable @@ -76,6 +78,8 @@ val ChatRoom?.displayTitle: String fun Loaded_Tg_Message( navController: NavController, viewModel: ChatRoomsViewModel = hiltViewModel(), + sharedTransitionScope: SharedTransitionScope, + animatedVisibilityScope: AnimatedVisibilityScope, onRoomClick: (String, String) -> Unit = { _, _ -> } ) { var expanded by remember { mutableStateOf(false) } @@ -191,11 +195,13 @@ fun Loaded_Tg_Message( LazyColumn(modifier = Modifier.padding(innerPadding)) { items( items = rooms, - key = { it.roomId } // 增加效能,防止列表閃爍 + key = { it.roomId } ) { room -> RoomItem( navController = navController, room = room, + sharedTransitionScope = sharedTransitionScope, // 傳下去 + animatedVisibilityScope = animatedVisibilityScope, // 傳下去 onClick = { roomId, roomName -> onRoomClick(roomId, roomName) } @@ -215,142 +221,149 @@ fun Loaded_Tg_Message( fun RoomItem( navController: NavController, room: ChatRoom, + sharedTransitionScope: SharedTransitionScope, + animatedVisibilityScope: AnimatedVisibilityScope, // 🚀 修正 2:onClick 改成攜帶兩個參數 (roomId, roomName) onClick: (String, String) -> Unit ) { val title = room.displayTitle - Card( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 12.dp, vertical = 6.dp) // 增加外邊距,讓 Card 之間有呼吸感 - .clickable { - // 🚀 修正:直接呼叫傳進來的 lambda 函式即可,不要包含 createRoute 唷! - onClick(room.roomId, room.displayTitle) - } - , - shape = RoundedCornerShape(16.dp), // 較大的圓角看起來更現代 - colors = CardDefaults.cardColors( - containerColor = Color.Transparent // ✅ 透明背景 - ), - elevation = CardDefaults.cardElevation( - defaultElevation = 0.dp // 增加輕微陰影 - ) - ) { - Box( + with(sharedTransitionScope){ + Card( modifier = Modifier - .fillMaxSize() - ){ - //glass effect + .fillMaxWidth() + .padding(horizontal = 12.dp, vertical = 6.dp) + .clickable { onClick(room.roomId, room.displayTitle) } + // 🌟 關鍵:把共享元素鎖定在整個外層 Container 上! + .sharedElement( + rememberSharedContentState(key = "container_${room.roomId}"), + animatedVisibilityScope = animatedVisibilityScope + ) + , + shape = RoundedCornerShape(16.dp), // 較大的圓角看起來更現代 + colors = CardDefaults.cardColors( + containerColor = Color.Transparent // ✅ 透明背景 + ), + elevation = CardDefaults.cardElevation( + defaultElevation = 0.dp // 增加輕微陰影 + ) + ) { Box( modifier = Modifier - .matchParentSize() - .blur(10.dp) - ) - Box( - modifier = Modifier - .matchParentSize() - .background( - color = MaterialTheme.colorScheme.primary, - RoundedCornerShape(16.dp) - ) - .border( - 1.dp, - Color.White.copy(alpha = 0.3f), - RoundedCornerShape(16.dp) - ) - ) - - - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding(12.dp), - ) { - // 1. 頭像 - val imageUrl = room.roomIconUrl ?: room.partner?.fullContactAvatarUrl - AsyncImage( - model = imageUrl, - contentDescription = "Avatar", - contentScale = ContentScale.Crop, + .fillMaxSize() + ){ + //glass effect + Box( modifier = Modifier - .size(56.dp) // 稍微加大一點 - .clip(CircleShape) - .border(1.dp, Color.White, CircleShape) // 頭像加個細白邊 - .background(Color.LightGray) + .matchParentSize() + .blur(10.dp) + ) + Box( + modifier = Modifier + .matchParentSize() + .background( + color = MaterialTheme.colorScheme.primary, + RoundedCornerShape(16.dp) + ) + .border( + 1.dp, + Color.White.copy(alpha = 0.3f), + RoundedCornerShape(16.dp) + ) ) - Spacer(modifier = Modifier.width(16.dp)) - // 2. 中間內容 - Column( - modifier = Modifier.weight(1f) + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(12.dp), ) { - Text( - text = room.roomName.orEmpty().ifEmpty { - room.partner?.displayName ?: "Unknown" - }, - style = MaterialTheme.typography.titleMedium, - fontWeight = FontWeight.Bold, - color = Color(0xFF333333), - maxLines = 1, - overflow = TextOverflow.Ellipsis + // 1. 頭像 + val imageUrl = room.roomIconUrl ?: room.partner?.fullContactAvatarUrl + AsyncImage( + model = imageUrl, + contentDescription = "Avatar", + contentScale = ContentScale.Crop, + modifier = Modifier + .size(56.dp) // 稍微加大一點 + .clip(CircleShape) + .border(1.dp, Color.White, CircleShape) // 頭像加個細白邊 + .background(Color.LightGray) ) - Spacer(modifier = Modifier.height(4.dp)) + Spacer(modifier = Modifier.width(16.dp)) - val lastMsgText = when { - room.lastMessage?.isDeleted == true -> "訊息已刪除" - room.lastMessage?.content != null -> room.lastMessage.content - room.lastMessage?.attachment != null -> "[檔案] ${room.lastMessage.attachment.filename}" - else -> "尚未有訊息" - } - - Row() { + // 2. 中間內容 + Column( + modifier = Modifier.weight(1f) + ) { Text( - text = lastMsgText, - style = MaterialTheme.typography.bodyMedium, - color = Color.Gray, + text = room.roomName.orEmpty().ifEmpty { + room.partner?.displayName ?: "Unknown" + }, + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.Bold, + color = Color(0xFF333333), maxLines = 1, overflow = TextOverflow.Ellipsis ) - Spacer(modifier = Modifier.width(6.dp)) + Spacer(modifier = Modifier.height(4.dp)) - if (room.unreadCount > 0) { - Badge( - containerColor = Color(0xFFDA7029), // 使用你的主橘色 - contentColor = Color.White - ) { - Text( - text = if (room.unreadCount > 99) "99+" else room.unreadCount.toString(), - modifier = Modifier.padding(horizontal = 4.dp) - ) + val lastMsgText = when { + room.lastMessage?.isDeleted == true -> "訊息已刪除" + room.lastMessage?.content != null -> room.lastMessage.content + room.lastMessage?.attachment != null -> "[檔案] ${room.lastMessage.attachment.filename}" + else -> "尚未有訊息" + } + + Row() { + Text( + text = lastMsgText, + style = MaterialTheme.typography.bodyMedium, + color = Color.Gray, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + + Spacer(modifier = Modifier.width(6.dp)) + + if (room.unreadCount > 0) { + Badge( + containerColor = Color(0xFFDA7029), // 使用你的主橘色 + contentColor = Color.White + ) { + Text( + text = if (room.unreadCount > 99) "99+" else room.unreadCount.toString(), + modifier = Modifier.padding(horizontal = 4.dp) + ) + } } } + + Spacer(modifier = Modifier.width(2.dp)) + } + + + //online status + val partner = room.partner // 先從 room 取得 partner + if (partner != null) { + val status = UserStatus.fromString(partner.status) + if (status != UserStatus.UNKNOWN) { + Box( + modifier = Modifier + .size(14.dp) + .background(status.color, CircleShape) // 直接設定圓形背景 + .border(2.dp, Color.White, CircleShape) // 白色外圈邊線 + ) + } } - Spacer(modifier = Modifier.width(2.dp)) + Spacer(modifier = Modifier.width(10.dp)) } - //online status - val partner = room.partner // 先從 room 取得 partner - if (partner != null) { - val status = UserStatus.fromString(partner.status) - if (status != UserStatus.UNKNOWN) { - Box( - modifier = Modifier - .size(14.dp) - .background(status.color, CircleShape) // 直接設定圓形背景 - .border(2.dp, Color.White, CircleShape) // 白色外圈邊線 - ) - } - } - - Spacer(modifier = Modifier.width(10.dp)) } - - } + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/login_v3/home/Message/UI/Message.kt b/app/src/main/java/com/example/login_v3/home/Message/UI/Message.kt index eba9ce4..2645fd1 100644 --- a/app/src/main/java/com/example/login_v3/home/Message/UI/Message.kt +++ b/app/src/main/java/com/example/login_v3/home/Message/UI/Message.kt @@ -1,5 +1,6 @@ package com.example.login_v3.home.Message.UI +import androidx.compose.animation.SharedTransitionLayout import androidx.compose.runtime.Composable import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavType @@ -33,66 +34,72 @@ fun Tg_Message( ) { val navController = rememberNavController() - NavHost( - navController = navController, - startDestination = Screen.Messages.route, - ) { - // 你的訊息主頁面 - composable(Screen.Messages.route) { - Loaded_Tg_Message( - navController = navController, - // ✨ 2. 這裡的點擊事件如果原本有傳 roomName,現在直接忽略,只傳 roomId 給路由 - onRoomClick = { roomId, _ -> - val route = Screen.MessageMessaging.createRoute(roomId) - navController.navigate(route) - } - ) - } + SharedTransitionLayout{ + NavHost( + navController = navController, + startDestination = Screen.Messages.route, + ) { + // 你的訊息主頁面 + // 訊息主頁面 + composable(Screen.Messages.route) { + Loaded_Tg_Message( + navController = navController, + // 2. 傳入 sharedTransitionScope (this@SharedTransitionLayout) + sharedTransitionScope = this@SharedTransitionLayout, + // 3. 傳入 animatedVisibilityScope (this@composable) + animatedVisibilityScope = this@composable, + onRoomClick = { roomId, _ -> + val route = Screen.MessageMessaging.createRoute(roomId) + navController.navigate(route) + } + ) + } - // 新建聯絡頁面 - composable(Screen.CreateContact.route) { - Message_add_contact(navController) - } + // 新建聯絡頁面 + composable(Screen.CreateContact.route) { + Message_add_contact(navController) + } - // 好友列表頁面 - composable(Screen.FriendsList.route) { - Message_contact_list( - navController, - bottomBarViewModel = bottomBarViewModel - ) - } + // 好友列表頁面 + composable(Screen.FriendsList.route) { + Message_contact_list( + navController, + bottomBarViewModel = bottomBarViewModel + ) + } - //QR code - composable(Screen.ScanQRcode.route) { - Scan_QRcode( - navController, - bottomBarViewModel = bottomBarViewModel - ) - } + //QR code + composable(Screen.ScanQRcode.route) { + Scan_QRcode( + navController, + bottomBarViewModel = bottomBarViewModel + ) + } - //Message detail - composable( - route = Screen.MessageMessaging.route, - arguments = listOf( - // ✨ 3. 只保留 roomId 的參數宣告,完全刪除 roomName 的 navArgument - navArgument("roomId") { - type = NavType.StringType - nullable = true - defaultValue = "" - } - ) - ) { backStackEntry -> - val roomId = backStackEntry.arguments?.getString("roomId").orEmpty() + //Message detail + composable( + route = Screen.MessageMessaging.route, + arguments = listOf( + navArgument("roomId") { + type = NavType.StringType + nullable = true + defaultValue = "" + } + ) + ) { backStackEntry -> + val roomId = backStackEntry.arguments?.getString("roomId").orEmpty() + + MessageMessaging( + roomId = roomId, + navController = navController, + // 4. 同樣把這兩個 Scope 傳入詳情頁 + sharedTransitionScope = this@SharedTransitionLayout, + animatedVisibilityScope = this@composable, + onBackClick = { navController.popBackStack() }, + bottomBarViewModel = bottomBarViewModel + ) + } - // ✨ 4. 呼叫新版的 MessageMessaging,不再傳入 roomName 參數 - MessageMessaging( - roomId = roomId, - navController = navController, - onBackClick = { - navController.popBackStack() - }, - bottomBarViewModel = bottomBarViewModel - ) } }