add delta sync for dm-v25

This commit is contained in:
eric 2026-08-11 20:19:53 +08:00
parent 0740aaebc5
commit 7c2c89fc8b
3 changed files with 65 additions and 57 deletions

View file

@ -1,10 +1,8 @@
package com.example.login_v3.home.Message.UI.Detail.Message_Component
import android.R.attr.onClick
import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
@ -20,6 +18,16 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd
import androidx.compose.foundation.text.input.clearText
import androidx.compose.foundation.content.contentReceiver
import androidx.compose.foundation.content.MediaType
import androidx.compose.foundation.content.hasMediaType
import androidx.compose.foundation.content.consume
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AddCircle
import androidx.compose.material.icons.filled.Check
@ -33,7 +41,7 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect // 🎯 新增
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@ -43,41 +51,38 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.blur
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.example.login_v3.home.Message.UI.Detail.MessageUiModel
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun MessageInputBar(
isLoading: Boolean,
replyingMessage: MessageUiModel?,
editingMessage: MessageUiModel? = null, // 🎯 新增
editingMessage: MessageUiModel? = null,
onCancelReply: () -> Unit,
onCancelEdit: () -> Unit = {}, // 🎯 新增
onCancelEdit: () -> Unit = {},
onSendClick: (String) -> Unit,
onEditSaveClick: (String) -> Unit = {}, // 🎯 新增
onAttachmentClick: () -> Unit
onEditSaveClick: (String) -> Unit = {},
onAttachmentClick: () -> Unit,
onMediaReceived: (Uri) -> Unit = {}
) {
var textState by remember { mutableStateOf("") }
val textState = rememberTextFieldState()
// 🎯 當進入編輯模式時,自動填入原本的內容
LaunchedEffect(editingMessage) {
if (editingMessage != null) {
textState = editingMessage.content
} else {
// 如果從編輯模式退出且不是因為發送成功,可能需要清空?
// 但通常 clearEditingMessage 會觸發這裡
textState.setTextAndPlaceCursorAtEnd(editingMessage.content)
}
}
// 💡 外層包裹一層 Box,並加上 padding 與 navigationBarsPadding,確保懸浮且不被系統列擋住
Box(
modifier = Modifier
.fillMaxWidth()
.navigationBarsPadding() // 自動適應 Android 系統導覽列高度
.padding(horizontal = 16.dp, vertical = 8.dp) // 懸浮的外邊距
//color
.navigationBarsPadding()
.padding(horizontal = 16.dp, vertical = 8.dp)
.background(
color = MaterialTheme.colorScheme.primary,
RoundedCornerShape(16.dp)
@ -88,34 +93,27 @@ fun MessageInputBar(
RoundedCornerShape(16.dp)
)
) {
Column(modifier = Modifier.fillMaxWidth()) {
// 1. 回覆預覽列 (現代化樣式 + 圓角與間距)
AnimatedVisibility(visible = replyingMessage != null) {
if (replyingMessage != null) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 8.dp, end = 8.dp, top = 8.dp) // 🎯 與邊框保持間距
.padding(start = 8.dp, end = 8.dp, top = 8.dp)
.background(
color = Color.White.copy(alpha = 0.92f),
shape = RoundedCornerShape(12.dp) // 🎯 圓角
shape = RoundedCornerShape(12.dp)
)
.padding(horizontal = 12.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
// 左側綠色裝飾條
Box(
modifier = Modifier
.width(3.dp)
.height(16.dp)
.background(Color(0xFF4CAF50), RoundedCornerShape(2.dp))
)
Spacer(modifier = Modifier.width(10.dp))
Column(modifier = Modifier.weight(1f)) {
Text(
text = replyingMessage.content,
@ -137,39 +135,33 @@ fun MessageInputBar(
}
}
// 🎯 1.5 編輯預覽列 (現代化樣式 + 圓角與間距)
AnimatedVisibility(visible = editingMessage != null) {
if (editingMessage != null) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 8.dp, end = 8.dp, top = 8.dp) // 🎯 與邊框保持間距
.padding(start = 8.dp, end = 8.dp, top = 8.dp)
.background(
color = Color.White.copy(alpha = 0.92f),
shape = RoundedCornerShape(12.dp) // 🎯 圓角
shape = RoundedCornerShape(12.dp)
)
.padding(horizontal = 12.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
// 左側橘色裝飾條,提升現代感
Box(
modifier = Modifier
.width(3.dp)
.height(16.dp)
.background(Color(0xFFDA7029), RoundedCornerShape(2.dp))
)
Spacer(modifier = Modifier.width(10.dp))
Icon(
imageVector = Icons.Default.Edit,
contentDescription = null,
tint = Color(0xFFDA7029),
modifier = Modifier.size(16.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = "正在編輯訊息",
style = MaterialTheme.typography.labelMedium.copy(
@ -178,11 +170,10 @@ fun MessageInputBar(
),
modifier = Modifier.weight(1f)
)
IconButton(
onClick = {
onCancelEdit()
textState = ""
textState.clearText()
},
modifier = Modifier.size(24.dp)
) {
@ -197,14 +188,12 @@ fun MessageInputBar(
}
}
// 2. 實際的輸入工具列
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 8.dp, vertical = 6.dp),
verticalAlignment = Alignment.CenterVertically
) {
// 檔案上傳
IconButton(onClick = { onAttachmentClick() }) {
Icon(
imageVector = Icons.Default.AddCircle,
@ -213,16 +202,34 @@ fun MessageInputBar(
)
}
// 輸入文字框 (改為內嵌樣式,去掉自帶的邊框,讓整體更有一體感)
BasicTextField(
value = textState,
onValueChange = { textState = it },
state = textState,
modifier = Modifier
.weight(1f)
.padding(horizontal = 8.dp),
.padding(horizontal = 8.dp)
.contentReceiver { transferableContent ->
if (transferableContent.hasMediaType(MediaType.Image)) {
transferableContent.consume { item ->
val uri = item.uri
if (uri != null) {
onMediaReceived(uri)
true
} else {
false
}
}
} else {
transferableContent
}
},
textStyle = MaterialTheme.typography.bodyLarge.copy(color = Color.White),
decorationBox = { innerTextField ->
if (textState.isEmpty()) {
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
autoCorrectEnabled = true,
imeAction = ImeAction.Default
),
decorator = { innerTextField ->
if (textState.text.isEmpty()) {
Text(
text = if (editingMessage != null) "編輯訊息..." else "請輸入訊息...",
color = Color.White.copy(alpha = 0.6f)
@ -232,25 +239,24 @@ fun MessageInputBar(
}
)
// 送出按鈕
IconButton(
onClick = {
if (textState.isNotBlank() && !isLoading) {
val content = textState.text.toString()
if (content.isNotBlank() && !isLoading) {
if (editingMessage != null) {
onEditSaveClick(textState)
onEditSaveClick(content)
} else {
onSendClick(textState)
onSendClick(content)
}
textState = ""
textState.clearText()
}
},
enabled = textState.isNotBlank() && !isLoading
enabled = textState.text.isNotBlank() && !isLoading
) {
if (isLoading) {
CircularProgressIndicator(modifier = Modifier.size(24.dp), strokeWidth = 2.dp)
} else {
// 加上小背景讓送出按鈕更有重點
val iconColor = if (textState.isNotBlank()) Color(0xFFDA7029) else Color.LightGray
val iconColor = if (textState.text.isNotBlank()) Color(0xFFDA7029) else Color.LightGray
val icon = if (editingMessage != null) Icons.Default.Check else Icons.Default.Send
Icon(
imageVector = icon,
@ -262,4 +268,4 @@ fun MessageInputBar(
}
}
}
}
}

View file

@ -519,7 +519,8 @@ fun MessageMessaging(
// 2. 沒權限,叫起多重權限請求視窗(傳入 requiredPermissions 陣列)
mainPermissionLauncher.launch(requiredPermissions)
}
}
},
onMediaReceived = { uri -> viewModel.uploadAttachment(roomId, uri) }
)
}

View file

@ -153,9 +153,10 @@ fun SharedTransitionScope.setting_list_Screen(
Spacer(modifier = Modifier.width(8.dp))
Column {
Text(
text = " ${item.title}",
text = "${item.title}",
style = MaterialTheme.typography.titleMedium,
fontSize = 24.sp,
fontWeight = FontWeight.Bold,