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 edfcb01..bcac31c 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 @@ -1,23 +1,149 @@ package com.example.login_v3.home.Message.UI.Detail +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController +import com.example.login_v3.data.api.api_class.Message +import com.example.login_v3.home.Message.ViewModel.Detail.ChatViewModel +import com.example.login_v3.home.Message.ViewModel.Detail.MessagesUiState +import com.example.login_v3.navigation.Screen +@OptIn(ExperimentalMaterial3Api::class) @Composable fun MessageMessaging( - navController: NavController -){ - Column( - modifier = Modifier - .fillMaxSize() - , - horizontalAlignment = Alignment.CenterHorizontally + roomId: String, + navController: NavController, + onBackClick: () -> Unit, + viewModel: ChatViewModel = viewModel() +) { + val uiState by viewModel.uiState + + LaunchedEffect(roomId) { + viewModel.loadMessages(roomId) + } + + Scaffold( + topBar = { + TopAppBar( + title = { Text("聊天室 ($roomId)") }, + navigationIcon = { + IconButton(onClick = onBackClick) { + Text("<") + } + } + ) + } + ) { 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(messages = state.messages) + } + } + is MessagesUiState.Error -> { + Text( + text = "載入失敗:${state.message}", + color = MaterialTheme.colorScheme.error + ) + } + } + } + } +} + +@Composable +fun MessageList( + messages: List, // 這裡是正確的 Message + modifier: Modifier = Modifier +) { + val currentUserId = "user_123" + + LazyColumn( + modifier = modifier.fillMaxSize(), + contentPadding = PaddingValues(16.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) ) { - Text(text = "MessageMessaging") + // items 內部拿到的 message 會依循 List 的型態 + items(messages) { message -> + val isMe = message.senderId == currentUserId + MessageRow(message = message, isMe = isMe) + } + } +} + +@Composable +fun MessageRow( + message: Message, // ✅ 修正這裡:將 Screen.Message 改為 Message + isMe: Boolean +) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = if (isMe) Arrangement.End else Arrangement.Start + ) { + Box( + modifier = Modifier + .widthIn(max = 280.dp) + .background( + color = if (isMe) Color(0xFFDCF8C6) else Color(0xFFECEFF1), + shape = RoundedCornerShape( + topStart = 12.dp, + topEnd = 12.dp, + bottomStart = if (isMe) 12.dp else 0.dp, + bottomEnd = if (isMe) 0.dp else 12.dp + ) + ) + .padding(horizontal = 12.dp, vertical = 8.dp) + ) { + Column { + if (!isMe) { + Text( + text = message.senderId, // ✅ 這樣型態對了,就能抓到欄位了! + style = MaterialTheme.typography.labelSmall, + color = Color.Gray + ) + } + Text( + text = message.content, // ✅ 這樣型態對了,就能抓到欄位了! + style = MaterialTheme.typography.bodyMedium + ) + } + } } } \ 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 c0071d1..b8b8a80 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 android.R.attr.type import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.core.tween import androidx.compose.foundation.Canvas @@ -65,9 +66,11 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController +import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController +import androidx.navigation.navArgument import coil.compose.AsyncImage import com.example.login_v3.data.api.api_class.ChatRoom import com.example.login_v3.data.api.api_class.fullContactAvatarUrl @@ -84,7 +87,14 @@ sealed class Screen(val route: String) { object CreateContact : Screen("create_contact") object FriendsList : Screen("friends_list") object ScanQRcode : Screen("scan_QRcode") - object MessageMessaging : Screen("Message_Messaging") + object MessageMessaging : Screen("message_messaging/{roomId}") { + // 這是給上一頁 Loaded_Tg_Message 跳轉時產生的真實路徑 + fun createRoute(roomId: String): String { + // 建議加上 URL 編碼,防止 roomId 含有斜線或特殊字元導致二次閃退 + val encodedId = java.net.URLEncoder.encode(roomId, "UTF-8") + return "message_messaging/$encodedId" + } + } } @Composable @@ -94,6 +104,7 @@ fun Tg_Message( val navController = rememberNavController() NavHost( + navController = navController, startDestination = Screen.Messages.route, // 進入時的動畫(新頁面出現) @@ -149,9 +160,25 @@ fun Tg_Message( } //Message detail - composable(Screen.MessageMessaging.route) { - MessageMessaging(navController) + // 這樣寫就完全沒問題了!因為 route 內部已經包含了 /{roomId} + composable( + route = Screen.MessageMessaging.route, + arguments = listOf( + navArgument("roomId") { type = NavType.StringType } + ) + ) { backStackEntry -> + // 安全取出參數 + val roomId = backStackEntry.arguments?.getString("roomId").orEmpty() + + MessageMessaging( + roomId = roomId, + navController = navController, + onBackClick = { + navController.popBackStack() + } + ) } + } } @@ -279,10 +306,10 @@ fun Loaded_Tg_Message( key = { it.roomId } // 增加效能,防止列表閃爍 ) { room -> RoomItem( + navController = navController, room = room, onClick = { - onRoomClick(room.roomId) // 執行原本的點擊邏輯 (依你的定義傳入對應的 String) - navController.navigate(Screen.MessageMessaging.route) // 執行導頁 + onRoomClick(room.roomId) } ) Spacer(modifier = Modifier.height(6.dp)) @@ -298,6 +325,7 @@ fun Loaded_Tg_Message( @Composable fun RoomItem( + navController: NavController, room: ChatRoom, onClick: (String) -> Unit ) { @@ -305,7 +333,10 @@ fun RoomItem( modifier = Modifier .fillMaxWidth() .padding(horizontal = 12.dp, vertical = 6.dp) // 增加外邊距,讓 Card 之間有呼吸感 - .clickable { onClick(room.roomId) }, + .clickable { + // 💡 修改這裡:動態帶入真實的 roomId + navController.navigate(Screen.MessageMessaging.createRoute(room.roomId)) + }, shape = RoundedCornerShape(16.dp), // 較大的圓角看起來更現代 colors = CardDefaults.cardColors( containerColor = Color.Transparent // ✅ 透明背景