dm-25
This commit is contained in:
parent
a4aeb6696f
commit
aefe861a44
2 changed files with 65 additions and 16 deletions
|
|
@ -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)
|
||||||
|
|
@ -188,3 +213,19 @@ 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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue