diff --git a/app/src/main/java/com/example/login_v3/data/api/api_class/DM_Basic.kt b/app/src/main/java/com/example/login_v3/data/api/api_class/DM_Basic.kt index 44447ec..b349b72 100644 --- a/app/src/main/java/com/example/login_v3/data/api/api_class/DM_Basic.kt +++ b/app/src/main/java/com/example/login_v3/data/api/api_class/DM_Basic.kt @@ -135,34 +135,51 @@ data class Message( // --- 🚀 新增:全域媒體屬性,讓 UI 秒讀不塞車 --- val isImage: Boolean get() = type == "image" || attachment?.mimeType?.startsWith("image/") == true || - content.lowercase().let { it.endsWith(".jpg") || it.endsWith(".jpeg") || it.endsWith(".png") || it.endsWith(".webp") || it.endsWith(".heic") || it.endsWith(".heif") || it.endsWith(".gif") } + content.substringBefore("?").lowercase().let { it.endsWith(".jpg") || it.endsWith(".jpeg") || it.endsWith(".png") || it.endsWith(".webp") || it.endsWith(".heic") || it.endsWith(".heif") || it.endsWith(".gif") } - val isGif: Boolean get() = attachment?.mimeType == "image/gif" || content.lowercase().endsWith(".gif") + val isGif: Boolean get() = attachment?.mimeType == "image/gif" || content.substringBefore("?").lowercase().endsWith(".gif") val isVideo: Boolean get() = type == "video" || attachment?.mimeType?.startsWith("video/") == true || - content.lowercase().let { it.endsWith(".mp4") || it.endsWith(".mov") || it.endsWith(".mkv") || it.endsWith(".avi") || it.endsWith(".3gp") || it.endsWith(".webm") } + content.substringBefore("?").lowercase().let { it.endsWith(".mp4") || it.endsWith(".mov") || it.endsWith(".mkv") || it.endsWith(".avi") || it.endsWith(".3gp") || it.endsWith(".webm") } val isAudio: Boolean get() = type == "audio" || attachment?.mimeType?.startsWith("audio/") == true || - content.lowercase().let { it.endsWith(".mp3") || it.endsWith(".wav") || it.endsWith(".m4a") || it.endsWith(".aac") || it.endsWith(".ogg") || it.endsWith(".opus") || it.endsWith(".amr") } + content.substringBefore("?").lowercase().let { it.endsWith(".mp3") || it.endsWith(".wav") || it.endsWith(".m4a") || it.endsWith(".aac") || it.endsWith(".ogg") || it.endsWith(".opus") || it.endsWith(".amr") } val isFile: Boolean get() = attachment?.mimeType?.startsWith("application/") == true || attachment?.mimeType == "text/plain" || - content.lowercase().let { it.endsWith(".zip") || it.endsWith(".rar") || it.endsWith(".7z") || it.endsWith(".pdf") || it.endsWith(".doc") || it.endsWith(".docx") || it.endsWith(".xls") || it.endsWith(".xlsx") || it.endsWith(".ppt") || it.endsWith(".pptx") || it.endsWith(".txt") } + content.substringBefore("?").lowercase().let { it.endsWith(".zip") || it.endsWith(".rar") || it.endsWith(".7z") || it.endsWith(".pdf") || it.endsWith(".doc") || it.endsWith(".docx") || it.endsWith(".xls") || it.endsWith(".xlsx") || it.endsWith(".ppt") || it.endsWith(".pptx") || it.endsWith(".txt") } val mediaUrl: String get() { - val rawPath = attachment?.filename ?: content + // 🎯 核心修正:媒體檔案必須優先使用 content,因為 content 包含正確的 Hash 路徑與專屬簽名 + // attachment.filename 通常只是顯示用的原始檔名 (例如 IMG_123.jpg) + val rawPath = if (isImage || isVideo || isAudio) content else (attachment?.filename ?: content) val baseUrl = "https://tg.technologia-tw.com" - return when { + + // 🎯 Step 1: 基礎 URL 處理 + var finalUrl = when { rawPath.isBlank() -> "" rawPath.startsWith("http") -> rawPath + rawPath.startsWith("/uploads/") -> "$baseUrl$rawPath" + rawPath.startsWith("uploads/") -> "$baseUrl/$rawPath" else -> { val cleanPath = rawPath.removePrefix("/").removePrefix("uploads/") - if (cleanPath.startsWith("attachment/")) { - "$baseUrl/uploads/$cleanPath" - } else { - "$baseUrl/uploads/attachment/$cleanPath" + if (cleanPath.contains("/")) "$baseUrl/uploads/$cleanPath" + else "$baseUrl/uploads/attachment/$cleanPath" + } + } + + // 🎯 Step 2: 簽名繼承 (如果 content 本身沒簽名,才去借縮圖的) + if (!finalUrl.contains("?")) { + attachment?.thumbnailUrl?.let { thumb -> + if (thumb.contains("?")) { + val signature = thumb.substringAfter("?", "") + if (signature.isNotEmpty()) { + finalUrl += "?$signature" + } } } } + + return finalUrl } } 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 index c297869..dfc1b71 100644 --- 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 @@ -64,11 +64,16 @@ fun ImageLightbox( .clickable(enabled = scale == 1f) { onDismiss() }, contentAlignment = Alignment.Center ) { - // 1. 底層:大圖檢視元件(保持不變) AsyncImage( model = imageUrl, contentDescription = "放大檢視圖片", contentScale = ContentScale.Fit, + onLoading = { android.util.Log.d("LightboxDebug", "Loading original image: $imageUrl") }, + onSuccess = { android.util.Log.d("LightboxDebug", "Successfully loaded original image") }, + onError = { error -> + android.util.Log.e("LightboxDebug", "Failed to load original image: ${error.result.throwable.message}") + error.result.throwable.printStackTrace() + }, modifier = Modifier .fillMaxWidth() .fillMaxHeight(0.85f) 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 d936f3d..bb25c7f 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 @@ -535,6 +535,15 @@ fun MessageMessaging( val onRowClickStable = remember(viewModel) { { message: MessageUiModel -> + // Debug Logs + Log.d("ChatDebug", "--- Clicked Message Content ---") + Log.d("ChatDebug", "Message ID: ${message.id}") + Log.d("ChatDebug", "Type: ${message.type}") + Log.d("ChatDebug", "Raw Content: ${message.content}") + Log.d("ChatDebug", "Attachment Filename: ${message.attachment?.filename}") + Log.d("ChatDebug", "Thumbnail URL: ${message.thumbnailUrl}") + Log.d("ChatDebug", "Final Media URL (OG): ${message.mediaUrl}") + //is image val isImage = message.isImage //is video