diff --git a/app/src/main/java/com/example/login_v3/data/repository/dm/DM_Basic_Repository.kt b/app/src/main/java/com/example/login_v3/data/repository/dm/DM_Basic_Repository.kt index 5a4f229..b123c3d 100644 --- a/app/src/main/java/com/example/login_v3/data/repository/dm/DM_Basic_Repository.kt +++ b/app/src/main/java/com/example/login_v3/data/repository/dm/DM_Basic_Repository.kt @@ -1,6 +1,7 @@ package com.example.login_v3.data.repository.dm import com.example.login_v3.data.api.TecnologiaApi +import com.example.login_v3.data.api.api_class.ChatRoom import com.example.login_v3.data.api.api_class.MessageResponse import com.example.login_v3.data.api.api_class.RoomListResponse import javax.inject.Inject @@ -48,4 +49,19 @@ class ChatRoomsRepository @Inject constructor( Result.failure(e) } } + + // 在 ChatRoomsRepository 裡面加入: + suspend fun getChatRoom(roomId: String): Result { + return try { + // 呼叫你原本就有的 fetchRooms() 獲取所有房間 + val responseResult = fetchRooms() + + responseResult.map { roomListResponse -> + // 從列表裡面找出 roomId 相同的那間房間 + roomListResponse.rooms.find { it.roomId == roomId } + } + } catch (e: Exception) { + Result.failure(e) + } + } } \ No newline at end of file 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 10a3fdf..10e4cc8 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 @@ -10,12 +10,18 @@ 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.size import androidx.compose.foundation.layout.widthIn 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.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold @@ -30,18 +36,17 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -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.home.Message.ViewModel.UserStatus import com.example.login_v3.navigation.Screen @OptIn(ExperimentalMaterial3Api::class) @Composable fun MessageMessaging( roomId: String, - roomName: String, navController: NavController, onBackClick: () -> Unit, viewModel: ChatViewModel = hiltViewModel() @@ -51,12 +56,47 @@ fun MessageMessaging( LaunchedEffect(roomId) { viewModel.loadMessages(roomId) } + // 根據目前的 uiState 來動態決定 TopBar 要顯示什麼文字 + val topBarTitle = when (val state = uiState) { + is MessagesUiState.Success -> state.roomTitle + is MessagesUiState.Error -> "載入失敗" + is MessagesUiState.Loading -> "載入中..." + } Scaffold( topBar = { TopAppBar( - //need to be sender id - title = { Text(roomName) }, + title = { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text(text = topBarTitle) + + // ✨ 如果是 Success 狀態,且對方是在線狀態(ONLINE),就顯示綠色小圓點 + if (uiState is MessagesUiState.Success) { + val successState = uiState as MessagesUiState.Success + if (successState.partnerStatus == UserStatus.ONLINE) { + Box( + modifier = Modifier + .size(10.dp) + .background( + color = UserStatus.ONLINE.color, + shape = CircleShape + ) + ) + } + } + } + }, + navigationIcon = { + IconButton(onClick = onBackClick) { + Icon( + imageVector = Icons.Default.ArrowBack, + contentDescription = "返回" + ) + } + } ) } ) { innerPadding -> @@ -66,6 +106,7 @@ fun MessageMessaging( .padding(innerPadding), contentAlignment = Alignment.Center ) { + // 根據不同的狀態渲染主畫面內容 when (val state = uiState) { is MessagesUiState.Loading -> { CircularProgressIndicator() @@ -74,6 +115,7 @@ fun MessageMessaging( if (state.messages.isEmpty()) { Text("目前沒有新訊息") } else { + // ⚠️ 記得把原來的 state.messages 傳進去 MessageList(messages = state.messages) } } 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 81d2d80..8d89b3c 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 @@ -79,6 +79,7 @@ import com.example.login_v3.home.Message.UI.Detail.Message_add_contact import com.example.login_v3.home.Message.UI.Detail.Message_contact_list import com.example.login_v3.home.Message.UI.Detail.Scan_QRcode import com.example.login_v3.home.Message.ViewModel.ChatRoomsViewModel +import com.example.login_v3.home.Message.ViewModel.UserStatus import com.example.login_v3.navigation.BottomBarViewModel @@ -87,9 +88,9 @@ 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?roomId={roomId}&roomName={roomName}") { - fun createRoute(roomId: String, roomName: String): String { - return "message_messaging?roomId=$roomId&roomName=$roomName" + object MessageMessaging : Screen("message_messaging?roomId={roomId}") { + fun createRoute(roomId: String): String { + return "message_messaging?roomId=$roomId" } } } @@ -108,9 +109,9 @@ fun Tg_Message( composable(Screen.Messages.route) { Loaded_Tg_Message( navController = navController, - // 🚀 完美接起傳出來的兩個參數,不再發生 No value passed 的狀況! - onRoomClick = { roomId, roomName -> - val route = Screen.MessageMessaging.createRoute(roomId, roomName) + // ✨ 2. 這裡的點擊事件如果原本有傳 roomName,現在直接忽略,只傳 roomId 給路由 + onRoomClick = { roomId, _ -> + val route = Screen.MessageMessaging.createRoute(roomId) navController.navigate(route) } ) @@ -138,26 +139,19 @@ fun Tg_Message( composable( route = Screen.MessageMessaging.route, arguments = listOf( + // ✨ 3. 只保留 roomId 的參數宣告,完全刪除 roomName 的 navArgument navArgument("roomId") { type = NavType.StringType nullable = true defaultValue = "" - }, - // 🚀 修正:新增接收 roomName 的導航參數 - navArgument("roomName") { - type = NavType.StringType - nullable = true - defaultValue = "聊天室" } ) ) { backStackEntry -> val roomId = backStackEntry.arguments?.getString("roomId").orEmpty() - // 🚀 修正:抓取名字 - val roomName = backStackEntry.arguments?.getString("roomName") ?: "聊天室" + // ✨ 4. 呼叫新版的 MessageMessaging,不再傳入 roomName 參數 MessageMessaging( roomId = roomId, - roomName = roomName, // 🚀 傳入 UI 中 navController = navController, onBackClick = { navController.popBackStack() @@ -461,21 +455,3 @@ fun RoomItem( } } } - -enum class UserStatus(val color: Color) { - ONLINE(Color.Green), - AWAY(Color.Yellow), - OFFLINE(Color.Gray), - UNKNOWN(Color.DarkGray); - - companion object { - fun fromString(status: String?): UserStatus { - return when (status?.lowercase()) { - "online" -> ONLINE - "away" -> AWAY - "offline" -> OFFLINE - else -> UNKNOWN - } - } - } -} diff --git a/app/src/main/java/com/example/login_v3/home/Message/ViewModel/Detail/Message_Messaging_ViewModel.kt b/app/src/main/java/com/example/login_v3/home/Message/ViewModel/Detail/Message_Messaging_ViewModel.kt index bdc7878..cc48e73 100644 --- a/app/src/main/java/com/example/login_v3/home/Message/ViewModel/Detail/Message_Messaging_ViewModel.kt +++ b/app/src/main/java/com/example/login_v3/home/Message/ViewModel/Detail/Message_Messaging_ViewModel.kt @@ -9,6 +9,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject import com.example.login_v3.data.api.api_class.Message +import com.example.login_v3.home.Message.ViewModel.UserStatus import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -16,7 +17,11 @@ import kotlinx.coroutines.flow.asStateFlow sealed interface MessagesUiState { object Loading : MessagesUiState - data class Success(val messages: List) : MessagesUiState + data class Success( + val roomTitle: String, + val partnerStatus: UserStatus, + val messages: List + ) : MessagesUiState data class Error(val message: String) : MessagesUiState } @@ -29,19 +34,40 @@ class ChatViewModel @Inject constructor( val uiState: StateFlow = _uiState.asStateFlow() fun loadMessages(roomId: String) { - viewModelScope.launch { _uiState.value = MessagesUiState.Loading - repository.getChatMessages(roomId) - .onSuccess { response -> + // 1. 同時獲取房間資訊與訊息列表 + val roomResult = repository.getChatRoom(roomId) // ⚠️ 需確保 Repository 有提供此方法 + val messagesResult = repository.getChatMessages(roomId) - _uiState.value = MessagesUiState.Success(messages = response.messages) - } - .onFailure { exception -> + if (messagesResult.isSuccess) { + val messagesResponse = messagesResult.getOrNull()!! - _uiState.value = MessagesUiState.Error(message = exception.message ?: "未知錯誤") + // 2. 根據房間資訊決定標題邏輯 + val room = roomResult.getOrNull() + val (title, status) = if (room != null) { + if (room.roomType == "DM") { + val name = room.partner?.displayName ?: room.partner?.username ?: "未知用戶" + val userStatus = UserStatus.fromString(room.partner?.status) + Pair(name, userStatus) + } else { + Pair(room.roomName ?: "未命名群組", UserStatus.UNKNOWN) + } + } else { + // 如果真的拿不到房間資訊,給個安全預設值 + Pair("聊天室", UserStatus.UNKNOWN) } + + _uiState.value = MessagesUiState.Success( + roomTitle = title, + partnerStatus = status, + messages = messagesResponse.messages + ) + } else { + val exception = messagesResult.exceptionOrNull() + _uiState.value = MessagesUiState.Error(message = exception?.message ?: "未知錯誤") + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/login_v3/home/Message/ViewModel/Message_ViewModel.kt b/app/src/main/java/com/example/login_v3/home/Message/ViewModel/Message_ViewModel.kt index 213ce87..4e4bc70 100644 --- a/app/src/main/java/com/example/login_v3/home/Message/ViewModel/Message_ViewModel.kt +++ b/app/src/main/java/com/example/login_v3/home/Message/ViewModel/Message_ViewModel.kt @@ -2,6 +2,7 @@ package com.example.login_v3.home.Message.ViewModel import android.util.Log +import androidx.compose.ui.graphics.Color import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.example.login_v3.R @@ -41,3 +42,22 @@ class ChatRoomsViewModel @Inject constructor( } } +enum class UserStatus(val color: Color) { + ONLINE(Color.Green), + OFFLINE(Color.Gray), + UNKNOWN(Color.Transparent); // 或者是你原本設定的顏色 + + companion object { + fun fromString(status: String?): UserStatus { + if (status == null) return UNKNOWN + + // 使用 try-catch 或者是 safe valueOf 確保絕對不閃退 + return try { + // uppercase() 預防後端一下給大寫一下給小寫 (例如 "online" vs "ONLINE") + valueOf(status.uppercase()) + } catch (e: IllegalArgumentException) { + UNKNOWN // 找不到對應的狀態就安全地回傳 UNKNOWN + } + } + } +}