From 37d7eb6528eb328f3c4a4a5bc03cfc4dea52d961 Mon Sep 17 00:00:00 2001 From: Eric85710 Date: Sun, 21 Jun 2026 14:31:22 +0800 Subject: [PATCH] dm-138 --- .../Detail/Message_Component/ImageLightbox.kt | 48 ++++++++++++++++++ .../Message/UI/Detail/Message_Messaging.kt | 50 +++++++++++++++++-- 2 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/com/example/login_v3/home/Message/UI/Detail/Message_Component/ImageLightbox.kt diff --git a/app/src/main/java/com/example/login_v3/home/Message/UI/Detail/Message_Component/ImageLightbox.kt b/app/src/main/java/com/example/login_v3/home/Message/UI/Detail/Message_Component/ImageLightbox.kt new file mode 100644 index 0000000..46a4e2f --- /dev/null +++ b/app/src/main/java/com/example/login_v3/home/Message/UI/Detail/Message_Component/ImageLightbox.kt @@ -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) { } // 阻止點擊圖片本身時觸發關閉 + ) + } + } +} \ 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 038a2b7..3d16ffc 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 @@ -77,6 +77,7 @@ import androidx.compose.material.icons.filled.Call import androidx.compose.material.icons.filled.MoreVert 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 import com.example.login_v3.home.Message.UI.Detail.Message_Component.UserStatusDot @@ -112,6 +113,9 @@ fun MessageMessaging( var emojiTargetMessage by remember { mutableStateOf(null) } + //inspect image + var lightboxImageUrl by remember { mutableStateOf(null) } + // 🌟 核心:使用 derivedStateOf 統一控管狀態權限(長按優先權通常大於單擊) val bottomBarState by remember { derivedStateOf { @@ -236,7 +240,7 @@ fun MessageMessaging( style = MaterialTheme.typography.titleMedium, fontSize = 24.sp, fontWeight = FontWeight.Bold, - color = Color(0xFF333333), + color = MaterialTheme.colorScheme.onBackground, maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier.weight(1f) @@ -425,8 +429,41 @@ fun MessageMessaging( }, // 💡 單擊事件:開啟 Emoji 選單,同時清空長按選單 onRowClick = { message -> - viewModel.clearActionMessage() - emojiTargetMessage = 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() + emojiTargetMessage = message + } }, onReactionClick = { message, emoji -> // 這是訊息氣泡下方既有 Reaction 小標籤的點擊事件,保持原樣即可 @@ -452,6 +489,13 @@ fun MessageMessaging( } } } + + lightboxImageUrl?.let { url -> + ImageLightbox( + imageUrl = url, + onDismiss = { lightboxImageUrl = null } + ) + } } @Composable