dm-131
This commit is contained in:
parent
b41e149095
commit
944d91e3d9
3 changed files with 170 additions and 3 deletions
|
|
@ -4,7 +4,8 @@ import com.example.login_v3.R
|
|||
import com.example.login_v3.home.Message.ViewModel.Detail.MessageStatus
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
||||
|
||||
|
||||
//Get DM list
|
||||
|
|
@ -125,4 +126,38 @@ data class SendMessageRequest(
|
|||
@JsonClass(generateAdapter = true)
|
||||
data class MessageReactionUsersResponse(
|
||||
@Json(name = "users") val users: List<String>
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
//voice call
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CallLogInfo(
|
||||
@Json(name = "type") val type: String, // 例如: call, call_log, call_missed, call_rejected 等
|
||||
@Json(name = "initiator_id") val initiator_id: String,
|
||||
@Json(name = "has_video") val has_video: Boolean
|
||||
) {
|
||||
companion object {
|
||||
private val moshi = Moshi.Builder()
|
||||
.addLast(KotlinJsonAdapterFactory())
|
||||
.build()
|
||||
|
||||
private val adapter = moshi.adapter(CallLogInfo::class.java)
|
||||
|
||||
fun parse(message: Message): CallLogInfo? {
|
||||
// 🌟 修正:只要是 call 開頭的 type 都允許解析,避免 call_missed 被擋掉
|
||||
if (message.type == null || !message.type.startsWith("call")) return null
|
||||
|
||||
val content = message.content?.trim() ?: return null
|
||||
if (!content.startsWith("{") || !content.endsWith("}")) return null
|
||||
|
||||
return try {
|
||||
adapter.fromJson(content)
|
||||
} catch (e: Exception) {
|
||||
android.util.Log.e("CallLogInfo", "解析通話 JSON 失敗: ${e.message}")
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package com.example.login_v3.home.Message.UI.Detail.Message_Component
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Call
|
||||
import androidx.compose.material.icons.filled.CallMissed
|
||||
import androidx.compose.material.icons.filled.VideoCall
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
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.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.login_v3.data.api.api_class.CallLogInfo
|
||||
|
||||
@Composable
|
||||
fun CallLogBubble(
|
||||
callLog: CallLogInfo,
|
||||
isMe: Boolean,
|
||||
currentUserId: String,
|
||||
partnerDisplayName: String,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
// 判斷這通電話是不是「我」撥打的
|
||||
val isIInitiated = callLog.initiator_id == currentUserId
|
||||
|
||||
// 根據通話狀態決定圖示、顏色與顯示主標題
|
||||
val (icon, iconColor, titleText) = when (callLog.type) {
|
||||
"call_missed" -> {
|
||||
Triple(
|
||||
Icons.Default.CallMissed,
|
||||
Color(0xFFEC1C24), // 未接來電用紅色
|
||||
if (isIInitiated) "對方未接聽" else "未接來電"
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
val callTypeStr = if (callLog.has_video) "視訊通話" else "語音通話"
|
||||
Triple(
|
||||
if (callLog.has_video) Icons.Default.VideoCall else Icons.Default.Call,
|
||||
if (isMe) Color(0xFF4CAF50) else Color(0xFF1976D2),
|
||||
if (isIInitiated) "撥出$callTypeStr" else "已接聽$callTypeStr"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 🌟 新增:來電顯示副標題邏輯
|
||||
val callTypeLabel = if (callLog.has_video) "視訊" else "語音"
|
||||
val subText = when {
|
||||
// 我撥出去的 -> 顯示「撥給 某某」
|
||||
isIInitiated -> "$callTypeLabel • 撥給 $partnerDisplayName"
|
||||
// 對方撥進來的 -> 顯示「來自 某某」
|
||||
else -> "$callTypeLabel • 來自 $partnerDisplayName"
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = modifier.padding(vertical = 2.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
// 左側:圓形背景與狀態圖示
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(38.dp)
|
||||
.background(iconColor.copy(alpha = 0.12f), shape = CircleShape),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = titleText,
|
||||
tint = iconColor,
|
||||
modifier = Modifier.size(22.dp)
|
||||
)
|
||||
}
|
||||
|
||||
// 右側:通話狀態與來電顯示文字
|
||||
Column {
|
||||
Text(
|
||||
text = titleText,
|
||||
style = MaterialTheme.typography.bodyMedium.copy(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.SemiBold
|
||||
)
|
||||
)
|
||||
Text(
|
||||
// 🌟 改用動態組合的來電顯示文字
|
||||
text = subText,
|
||||
style = MaterialTheme.typography.bodySmall.copy(
|
||||
fontSize = 12.sp,
|
||||
color = Color.Gray
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -75,6 +75,8 @@ import androidx.compose.foundation.layout.windowInsetsTopHeight
|
|||
import androidx.compose.foundation.layout.statusBars // 如果要使用 statusBars 也需要這個
|
||||
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.UserStatusDot
|
||||
|
||||
|
||||
|
|
@ -515,6 +517,8 @@ fun MessageRow(
|
|||
val isImage = isAttachmentImage || isLegacyImage
|
||||
val rawContent = message.content ?: ""
|
||||
|
||||
val callLog = remember(message.id, message.content) { CallLogInfo.parse(message) }
|
||||
|
||||
val finalImageModel = remember(message) {
|
||||
val rawPath = if (isAttachmentImage && !message.attachment?.filename.isNullOrBlank()) {
|
||||
message.attachment!!.filename
|
||||
|
|
@ -536,8 +540,11 @@ fun MessageRow(
|
|||
}
|
||||
}
|
||||
|
||||
val finalBubbleColor = remember(message.status, isHighlight) {
|
||||
val finalBubbleColor = remember(message.status, isHighlight, callLog) {
|
||||
val baseColor = when {
|
||||
callLog != null -> {
|
||||
if (callLog.type == "call_missed") Color(0xFFFCE8E6) else Color(0xFFF1F3F4)
|
||||
}
|
||||
isMe && isHighlight -> Color(0xFFB4E197)
|
||||
isMe -> Color(0xFFDCF8C6)
|
||||
!isMe && isHighlight -> Color(0xFFCFD8DC)
|
||||
|
|
@ -617,6 +624,26 @@ fun MessageRow(
|
|||
}
|
||||
)
|
||||
}
|
||||
} else if (callLog != null) {
|
||||
// 🌟 通話紀錄渲染
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.widthIn(max = 280.dp)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.combinedClickable(
|
||||
onLongClick = { onReplyClick(message) },
|
||||
onClick = { onRowClick(message) }
|
||||
)
|
||||
.background(color = finalBubbleColor)
|
||||
.padding(horizontal = 14.dp, vertical = 10.dp)
|
||||
) {
|
||||
CallLogBubble(
|
||||
callLog = callLog,
|
||||
isMe = isMe,
|
||||
currentUserId = currentUserId,
|
||||
partnerDisplayName = partnerDisplayName
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// 🌟 文字訊息:維持原本的 Box 氣泡樣式
|
||||
Box(
|
||||
|
|
|
|||
Loading…
Reference in a new issue