dm-144
This commit is contained in:
parent
207f16c787
commit
e4db01d592
1 changed files with 152 additions and 84 deletions
|
|
@ -73,8 +73,10 @@ import androidx.compose.foundation.layout.WindowInsets
|
|||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.layout.windowInsetsTopHeight
|
||||
import androidx.compose.foundation.layout.statusBars // 如果要使用 statusBars 也需要這個
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.icons.filled.Call
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material.icons.filled.PlayArrow
|
||||
import com.example.login_v3.data.api.api_class.CallLogInfo
|
||||
import com.example.login_v3.home.Message.UI.Detail.Message_Component.CallLogBubble
|
||||
import com.example.login_v3.home.Message.UI.Detail.Message_Component.ImageLightbox
|
||||
|
|
@ -561,13 +563,20 @@ fun MessageRow(
|
|||
val isImage = isAttachmentImage || isLegacyImage
|
||||
val rawContent = message.content ?: ""
|
||||
|
||||
// 🌟 2. 影片判斷
|
||||
val isAttachmentVideo = message.attachment?.mimeType?.startsWith("video/") == true
|
||||
val videoExtensions = listOf(".mp4", ".mov", ".mkv", ".avi", ".3gp", ".webm")
|
||||
val isLegacyVideo = videoExtensions.any { contentLowerCase.contains(it) }
|
||||
val isVideo = isAttachmentVideo || isLegacyVideo
|
||||
|
||||
val callLog = message.callLogInfo
|
||||
|
||||
val finalImageModel = remember(message) {
|
||||
val rawPath = if (isAttachmentImage && !message.attachment?.filename.isNullOrBlank()) {
|
||||
message.attachment!!.filename
|
||||
} else {
|
||||
message.content ?: ""
|
||||
// 🌟 3. 計算媒體 URL (將原本的圖片 URL 邏輯通用化至媒體檔案)
|
||||
val finalMediaUrl = remember(message, isImage, isVideo) {
|
||||
val rawPath = when {
|
||||
isAttachmentImage && !message.attachment?.filename.isNullOrBlank() -> message.attachment!!.filename
|
||||
isAttachmentVideo && !message.attachment?.filename.isNullOrBlank() -> message.attachment!!.filename
|
||||
else -> message.content ?: ""
|
||||
}
|
||||
val baseUrl = "https://tg.technologia-tw.com"
|
||||
when {
|
||||
|
|
@ -632,32 +641,30 @@ fun MessageRow(
|
|||
Column(
|
||||
horizontalAlignment = if (isMe) Alignment.End else Alignment.Start
|
||||
) {
|
||||
|
||||
// 核心分流:如果是圖片,不穿氣泡外衣,直接渲染
|
||||
if (isImage) {
|
||||
when {
|
||||
// 核心分流 1:圖片處理
|
||||
isImage -> {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.widthIn(max = 240.dp) // 限制圖片最大寬度
|
||||
.widthIn(max = 240.dp)
|
||||
.combinedClickable(
|
||||
onLongClick = { onReplyClick(message) },
|
||||
onClick = { onRowClick(message) }
|
||||
),
|
||||
horizontalAlignment = if (isMe) Alignment.End else Alignment.Start
|
||||
) {
|
||||
// 1. 如果有被回覆的訊息,依然顯示在圖片上方(可選,如果不需要也可以移進去文字氣泡)
|
||||
message.repliedMessage?.let { replied ->
|
||||
RepliedMessagePreview(replied, isMe, partnerDisplayName, currentUserId)
|
||||
}
|
||||
|
||||
// 2. 獨立的圖片元件(完全沒有外層氣泡背景色與 Padding)
|
||||
AsyncImage(
|
||||
model = finalImageModel,
|
||||
model = finalMediaUrl,
|
||||
contentDescription = "聊天圖片",
|
||||
contentScale = ContentScale.Fit,
|
||||
modifier = Modifier
|
||||
.padding(top = 4.dp)
|
||||
.sizeIn(maxWidth = 240.dp, maxHeight = 300.dp)
|
||||
.clip(RoundedCornerShape(12.dp)) // 圖片自帶圓角,更美觀
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.border(
|
||||
width = 0.5.dp,
|
||||
color = Color.LightGray.copy(alpha = 0.4f),
|
||||
|
|
@ -669,13 +676,71 @@ fun MessageRow(
|
|||
}
|
||||
)
|
||||
}
|
||||
} else if (callLog != null) {
|
||||
// 🌟 🎯 改造 2:通話紀錄渲染優化
|
||||
// 移除原本包裹在外層、帶有背景與 Padding 的 Box,改由長按/點擊事件的容器包住 CallLogBubble
|
||||
}
|
||||
|
||||
// 🌟 核心分流 2:影片處理 (新增)
|
||||
isVideo -> {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.widthIn(max = 240.dp)
|
||||
.combinedClickable(
|
||||
onLongClick = { onReplyClick(message) },
|
||||
onClick = { onRowClick(message) } // 點擊時可以在此觸發開啟影片播放器
|
||||
),
|
||||
horizontalAlignment = if (isMe) Alignment.End else Alignment.Start
|
||||
) {
|
||||
message.repliedMessage?.let { replied ->
|
||||
RepliedMessagePreview(replied, isMe, partnerDisplayName, currentUserId)
|
||||
}
|
||||
|
||||
// 影片佈局:使用 Box 將「播放圖示」疊加在預覽圖(或黑色背景)上方
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(top = 4.dp)
|
||||
.size(width = 240.dp, height = 160.dp) // 給予影片固定的預覽比例
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(Color.Black) // 預防沒載入圖時顯示黑色底
|
||||
.border(
|
||||
width = 0.5.dp,
|
||||
color = Color.LightGray.copy(alpha = 0.4f),
|
||||
shape = RoundedCornerShape(12.dp)
|
||||
),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
// 💡 注意:這裡 model 給 finalMediaUrl。
|
||||
// 如果後端支援,通常會另外傳一個 video_thumbnail_url;
|
||||
// 如果直接給影片 URL,部分圖片載入庫(如 Coil 搭配 VideoFrameDecoder)可以直接擷取第一幀。
|
||||
AsyncImage(
|
||||
model = finalMediaUrl,
|
||||
contentDescription = "影片預覽",
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
alpha = 0.8f // 稍微壓暗,讓播放按鈕更明顯
|
||||
)
|
||||
|
||||
// 播放圖示容器
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.background(Color.Black.copy(alpha = 0.5f), CircleShape),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Icon(
|
||||
imageVector = androidx.compose.material.icons.Icons.Default.PlayArrow,
|
||||
contentDescription = "播放影片",
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(28.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 核心分流 3:通話紀錄
|
||||
callLog != null -> {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.widthIn(max = 280.dp)
|
||||
// 讓通話紀錄一樣能響應點擊與長按(如刪除、回覆)
|
||||
.combinedClickable(
|
||||
onLongClick = { onReplyClick(message) },
|
||||
onClick = { onRowClick(message) }
|
||||
|
|
@ -688,8 +753,10 @@ fun MessageRow(
|
|||
partnerDisplayName = partnerDisplayName
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// 🌟 文字訊息:維持原本的 Box 氣泡樣式
|
||||
}
|
||||
|
||||
// 核心分流 4:純文字訊息
|
||||
else -> {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.widthIn(max = 280.dp)
|
||||
|
|
@ -719,8 +786,9 @@ fun MessageRow(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 按讚/反應功能(無論文字或圖片都靠下對齊顯示)
|
||||
// 3. 按讚/反應功能
|
||||
if (!message.reactions.isNullOrEmpty()) {
|
||||
ReactionRow(
|
||||
reactions = message.reactions,
|
||||
|
|
|
|||
Loading…
Reference in a new issue