This commit is contained in:
Eric85710 2026-05-23 14:24:38 +08:00
parent a4aeb6696f
commit aefe861a44
2 changed files with 65 additions and 16 deletions

View file

@ -1,6 +1,7 @@
package com.example.login_v3.home.Message.UI.Detail package com.example.login_v3.home.Message.UI.Detail
import android.util.Log import android.util.Log
import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
@ -18,6 +19,7 @@ import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
@ -32,11 +34,15 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController import androidx.navigation.NavController
import coil.compose.AsyncImage
import com.example.login_v3.R
import com.example.login_v3.data.api.api_class.Message 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.ChatViewModel
import com.example.login_v3.home.Message.ViewModel.Detail.MessagesUiState import com.example.login_v3.home.Message.ViewModel.Detail.MessagesUiState
@ -71,6 +77,15 @@ fun MessageMessaging(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp) horizontalArrangement = Arrangement.spacedBy(8.dp)
) { ) {
//avatar
if (uiState is MessagesUiState.Success) {
val successState = uiState as MessagesUiState.Success
UserAvatar(
avatarUrl = successState.partnerAvatarUrl,
modifier = Modifier.size(36.dp) // 適中的 TopBar 頭像大小
)
}
Text(text = topBarTitle) Text(text = topBarTitle)
// ✨ 如果是 Success 狀態,且對方是在線狀態(ONLINE),就顯示綠色小圓點 // ✨ 如果是 Success 狀態,且對方是在線狀態(ONLINE),就顯示綠色小圓點
@ -88,14 +103,6 @@ fun MessageMessaging(
} }
} }
} }
},
navigationIcon = {
IconButton(onClick = onBackClick) {
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = "返回"
)
}
} }
) )
} }
@ -115,8 +122,10 @@ fun MessageMessaging(
if (state.messages.isEmpty()) { if (state.messages.isEmpty()) {
Text("目前沒有新訊息") Text("目前沒有新訊息")
} else { } else {
// ⚠️ 記得把原來的 state.messages 傳進去 MessageList(
MessageList(messages = state.messages) messages = state.messages,
partnerAvatarUrl = state.partnerAvatarUrl
)
} }
} }
is MessagesUiState.Error -> { is MessagesUiState.Error -> {
@ -132,6 +141,7 @@ fun MessageMessaging(
@Composable @Composable
fun MessageList( fun MessageList(
partnerAvatarUrl: Any?,
messages: List<Message>, messages: List<Message>,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
@ -144,7 +154,11 @@ fun MessageList(
) { ) {
items(messages) { message -> items(messages) { message ->
val isMe = message.senderId == currentUserId val isMe = message.senderId == currentUserId
MessageRow(message = message, isMe = isMe) MessageRow(
message = message,
partnerAvatarUrl = partnerAvatarUrl,
isMe = isMe
)
} }
} }
} }
@ -152,12 +166,23 @@ fun MessageList(
@Composable @Composable
fun MessageRow( fun MessageRow(
message: Message, message: Message,
isMe: Boolean isMe: Boolean,
partnerAvatarUrl: Any?
) { ) {
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = if (isMe) Arrangement.End else Arrangement.Start horizontalArrangement = if (isMe) Arrangement.End else Arrangement.Start
) { ) {
// ✨ 如果是對方發的訊息,在對話框左邊顯示頭像
if (!isMe) {
UserAvatar(
avatarUrl = partnerAvatarUrl,
modifier = Modifier
.padding(end = 8.dp)
.size(32.dp) // 訊息旁的頭像稍微小一點
)
}
Box( Box(
modifier = Modifier modifier = Modifier
.widthIn(max = 280.dp) .widthIn(max = 280.dp)
@ -187,4 +212,20 @@ fun MessageRow(
} }
} }
} }
}
@Composable
fun UserAvatar(
avatarUrl: Any?, // ✨ 改成 Any?
modifier: Modifier = Modifier
) {
AsyncImage(
model = avatarUrl ?: R.drawable.avatar_v1, // 如果為 null,就用預設圖
contentDescription = "用戶頭像",
modifier = modifier
.background(Color.LightGray, shape = CircleShape)
.clip(CircleShape),
contentScale = ContentScale.Crop
)
} }

View file

@ -4,11 +4,13 @@ package com.example.login_v3.home.Message.ViewModel.Detail
import android.util.Log import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.example.login_v3.R
import com.example.login_v3.data.repository.dm.ChatRoomsRepository import com.example.login_v3.data.repository.dm.ChatRoomsRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
import com.example.login_v3.data.api.api_class.Message import com.example.login_v3.data.api.api_class.Message
import com.example.login_v3.data.api.api_class.fullContactAvatarUrl
import com.example.login_v3.home.Message.ViewModel.UserStatus import com.example.login_v3.home.Message.ViewModel.UserStatus
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@ -20,8 +22,10 @@ sealed interface MessagesUiState {
data class Success( data class Success(
val roomTitle: String, val roomTitle: String,
val partnerStatus: UserStatus, val partnerStatus: UserStatus,
val partnerAvatarUrl: Any?,
val messages: List<Message> val messages: List<Message>
) : MessagesUiState ) : MessagesUiState
data class Error(val message: String) : MessagesUiState data class Error(val message: String) : MessagesUiState
} }
@ -46,18 +50,22 @@ class ChatViewModel @Inject constructor(
// 2. 根據房間資訊決定標題邏輯 // 2. 根據房間資訊決定標題邏輯
val room = roomResult.getOrNull() val room = roomResult.getOrNull()
val (title, status) = if (room != null) { // ✨ 這裡改用 Any? 來接收擴充屬性的結果
val (title, status, avatarUrl: Any?) = if (room != null) {
val name = room.partner?.displayName ?: room.partner?.username ?: "未知用戶" val name = room.partner?.displayName ?: room.partner?.username ?: "未知用戶"
val userStatus = UserStatus.fromString(room.partner?.status) val userStatus = UserStatus.fromString(room.partner?.status)
Pair(name, userStatus) // 👇 直接呼叫你寫好的擴充屬性
val avatar = room.partner?.fullContactAvatarUrl
Triple(name, userStatus, avatar)
} else { } else {
// 如果真的拿不到房間資訊,給個安全預設值 // 如果沒有房間資訊,就給預設的頭像資源
Pair("聊天室", UserStatus.UNKNOWN) Triple("聊天室", UserStatus.UNKNOWN, R.drawable.avatar_v1)
} }
_uiState.value = MessagesUiState.Success( _uiState.value = MessagesUiState.Success(
roomTitle = title, roomTitle = title,
partnerStatus = status, partnerStatus = status,
partnerAvatarUrl = avatarUrl, // ✨ 這裡就會是完整的網址或 R.drawable.avatar_v1
messages = messagesResponse.messages messages = messagesResponse.messages
) )