This commit is contained in:
Eric85710 2026-06-24 16:03:17 +08:00
parent 2844977df8
commit 18065034b7
2 changed files with 34 additions and 10 deletions

View file

@ -1,5 +1,6 @@
package com.example.login_v3.home.Message.UI.Detail.Message_Component package com.example.login_v3.home.Message.UI.Detail.Message_Component
import android.R.attr.onClick
import android.net.Uri import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
@ -45,17 +46,10 @@ fun MessageInputBar(
replyingMessage: Message?, replyingMessage: Message?,
onCancelReply: () -> Unit, onCancelReply: () -> Unit,
onSendClick: (String) -> Unit, onSendClick: (String) -> Unit,
onImageSelected: (Uri) -> Unit onAttachmentClick: () -> Unit
) { ) {
var textState by remember { mutableStateOf("") } var textState by remember { mutableStateOf("") }
val imagePickerLauncher =
rememberLauncherForActivityResult(
contract = ActivityResultContracts.GetContent()
) { uri: Uri? ->
uri?.let { onImageSelected(it) }
}
// 💡 外層包裹一層 Box,並加上 padding 與 navigationBarsPadding,確保懸浮且不被系統列擋住 // 💡 外層包裹一層 Box,並加上 padding 與 navigationBarsPadding,確保懸浮且不被系統列擋住
Box( Box(
modifier = Modifier modifier = Modifier
@ -125,7 +119,7 @@ fun MessageInputBar(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
// 檔案上傳 // 檔案上傳
IconButton(onClick = { imagePickerLauncher.launch("image/*") }) { IconButton(onClick = { onAttachmentClick() }) {
Icon( Icon(
imageVector = Icons.Default.AddCircle, imageVector = Icons.Default.AddCircle,
contentDescription = "attachment bar", contentDescription = "attachment bar",

View file

@ -1,6 +1,9 @@
package com.example.login_v3.home.Message.UI.Detail package com.example.login_v3.home.Message.UI.Detail
import android.net.Uri
import android.widget.Toast import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibilityScope import androidx.compose.animation.AnimatedVisibilityScope
import androidx.compose.animation.SharedTransitionScope import androidx.compose.animation.SharedTransitionScope
@ -86,6 +89,7 @@ import com.example.login_v3.data.api.api_class.CallLogInfo
import com.example.login_v3.home.Message.UI.Detail.Message_Component.AudioMessageBubble import com.example.login_v3.home.Message.UI.Detail.Message_Component.AudioMessageBubble
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.ImageLightbox
import com.example.login_v3.home.Message.UI.Detail.Message_Component.MessageAttachmentBar
import com.example.login_v3.home.Message.UI.Detail.Message_Component.UserStatusDot import com.example.login_v3.home.Message.UI.Detail.Message_Component.UserStatusDot
import com.example.login_v3.home.Message.UI.Detail.Message_Component.VideoLightbox import com.example.login_v3.home.Message.UI.Detail.Message_Component.VideoLightbox
@ -129,16 +133,25 @@ fun MessageMessaging(
var lightboxVideoUrl by remember { mutableStateOf<String?>(null) } var lightboxVideoUrl by remember { mutableStateOf<String?>(null) }
// 🌟 核心:使用 derivedStateOf 統一控管狀態權限(長按優先權通常大於單擊) // 🌟 核心:使用 derivedStateOf 統一控管狀態權限(長按優先權通常大於單擊)
// 🎯 新增:用來控管非訊息觸發的底部狀態(例如:AttachmentMenu)
var localBottomBarState by remember { mutableStateOf<BottomBarState?>(null) }
val bottomBarState by remember { val bottomBarState by remember {
derivedStateOf { derivedStateOf {
when { when {
actionMessage != null -> BottomBarState.ActionMenu(actionMessage!!) actionMessage != null -> BottomBarState.ActionMenu(actionMessage!!)
emojiTargetMessage != null -> BottomBarState.EmojiMenu(emojiTargetMessage!!) emojiTargetMessage != null -> BottomBarState.EmojiMenu(emojiTargetMessage!!)
localBottomBarState != null -> localBottomBarState!! // 🎯 如果有本地狀態,則採用它
else -> BottomBarState.Input else -> BottomBarState.Input
} }
} }
} }
val imagePickerLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.GetContent()
) { uri: Uri? ->
uri?.let { viewModel.uploadAttachment(roomId, it) }
}
//進入時重整 //進入時重整
LaunchedEffect(roomId) { LaunchedEffect(roomId) {
viewModel.loadMessages(roomId) viewModel.loadMessages(roomId)
@ -359,7 +372,10 @@ fun MessageMessaging(
replyingMessage = replyingMessage, replyingMessage = replyingMessage,
onCancelReply = { viewModel.setReplyingMessage(null) }, onCancelReply = { viewModel.setReplyingMessage(null) },
onSendClick = { content -> viewModel.sendMessage(roomId, content) }, onSendClick = { content -> viewModel.sendMessage(roomId, content) },
onImageSelected = { uri -> viewModel.uploadAttachment(roomId, uri) }, // 🎯 改為直接修改本地狀態,切換至附件選單
onAttachmentClick = {
localBottomBarState = BottomBarState.AttachmentMenu
}
) )
} }
@ -408,6 +424,20 @@ fun MessageMessaging(
} }
) )
} }
is BottomBarState.AttachmentMenu -> {
MessageAttachmentBar(
onImageClick = {
imagePickerLauncher.launch("image/*")
// 🎯 選完圖片後,將本地狀態重置,自動回歸 Input 輸入框
localBottomBarState = null
},
onCancel = {
// 🎯 點擊關閉,同樣回歸 Input 輸入框
localBottomBarState = null
}
)
}
} }
} }
} }