This commit is contained in:
Eric85710 2026-06-21 14:31:22 +08:00
parent f753659a6e
commit 37d7eb6528
2 changed files with 95 additions and 3 deletions

View file

@ -0,0 +1,48 @@
package com.example.login_v3.home.Message.UI.Detail.Message_Component
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import coil.compose.AsyncImage
@Composable
fun ImageLightbox(
imageUrl: String,
onDismiss: () -> Unit
) {
// 使用 Dialog 才能真正做到全螢幕蓋住 TopBar 與 BottomBar
Dialog(
onDismissRequest = onDismiss,
properties = DialogProperties(
usePlatformDefaultWidth = false // 關閉預設寬度限制,達到真正全螢幕
)
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Black.copy(alpha = 0.9f)) // 質感黑半透明背景
.clickable { onDismiss() }, // 點擊背景任何地方都能關閉
contentAlignment = Alignment.Center
) {
AsyncImage(
model = imageUrl,
contentDescription = "放大檢視圖片",
contentScale = ContentScale.Fit, // 確保整張圖片能完整塞進螢幕
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(0.85f) // 留一點上下操作空間
.clickable(enabled = false) { } // 阻止點擊圖片本身時觸發關閉
)
}
}
}

View file

@ -77,6 +77,7 @@ import androidx.compose.material.icons.filled.Call
import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.MoreVert
import com.example.login_v3.data.api.api_class.CallLogInfo 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.CallLogBubble
import com.example.login_v3.home.Message.UI.Detail.Message_Component.ImageLightbox
import com.example.login_v3.home.Message.UI.Detail.Message_Component.UserStatusDot import com.example.login_v3.home.Message.UI.Detail.Message_Component.UserStatusDot
@ -112,6 +113,9 @@ fun MessageMessaging(
var emojiTargetMessage by remember { mutableStateOf<Message?>(null) } var emojiTargetMessage by remember { mutableStateOf<Message?>(null) }
//inspect image
var lightboxImageUrl by remember { mutableStateOf<String?>(null) }
// 🌟 核心:使用 derivedStateOf 統一控管狀態權限(長按優先權通常大於單擊) // 🌟 核心:使用 derivedStateOf 統一控管狀態權限(長按優先權通常大於單擊)
val bottomBarState by remember { val bottomBarState by remember {
derivedStateOf { derivedStateOf {
@ -236,7 +240,7 @@ fun MessageMessaging(
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
fontSize = 24.sp, fontSize = 24.sp,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
color = Color(0xFF333333), color = MaterialTheme.colorScheme.onBackground,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
@ -425,8 +429,41 @@ fun MessageMessaging(
}, },
// 💡 單擊事件:開啟 Emoji 選單,同時清空長按選單 // 💡 單擊事件:開啟 Emoji 選單,同時清空長按選單
onRowClick = { message -> onRowClick = { message ->
val isAttachmentImage = message.attachment?.mimeType?.startsWith("image/") == true
val contentLowerCase = (message.content ?: "").lowercase()
val imageExtensions = listOf(".jpg", ".jpeg", ".png", ".webp", ".heic", ".heif")
val isLegacyImage = imageExtensions.any { contentLowerCase.contains(it) }
if (isAttachmentImage || isLegacyImage) {
// 🎯 A 狀態:這是圖片,計算圖片完整 URL 並塞入 lightbox 狀態觸發放大
val rawPath = if (isAttachmentImage && !message.attachment?.filename.isNullOrBlank()) {
message.attachment!!.filename
} else {
message.content ?: ""
}
val baseUrl = "https://tg.technologia-tw.com"
val finalUrl = when {
rawPath.isBlank() -> ""
rawPath.startsWith("http") -> rawPath
else -> {
val cleanPath = rawPath.removePrefix("/").removePrefix("uploads/")
if (cleanPath.startsWith("attachment/")) {
"$baseUrl/uploads/$cleanPath"
} else {
"$baseUrl/uploads/attachment/$cleanPath"
}
}
}
// 關閉可能開啟的選單,並打開大圖
viewModel.clearActionMessage()
emojiTargetMessage = null
lightboxImageUrl = finalUrl
} else {
// 🎯 B 狀態:一般文字或通話,維持原本點擊叫出 Emoji Bar 的邏輯
viewModel.clearActionMessage() viewModel.clearActionMessage()
emojiTargetMessage = message emojiTargetMessage = message
}
}, },
onReactionClick = { message, emoji -> onReactionClick = { message, emoji ->
// 這是訊息氣泡下方既有 Reaction 小標籤的點擊事件,保持原樣即可 // 這是訊息氣泡下方既有 Reaction 小標籤的點擊事件,保持原樣即可
@ -452,6 +489,13 @@ fun MessageMessaging(
} }
} }
} }
lightboxImageUrl?.let { url ->
ImageLightbox(
imageUrl = url,
onDismiss = { lightboxImageUrl = null }
)
}
} }
@Composable @Composable