add delta sync for dm-v17
This commit is contained in:
parent
fc605183d5
commit
d84ba852c6
1 changed files with 221 additions and 115 deletions
|
|
@ -85,11 +85,14 @@ import androidx.compose.foundation.layout.statusBars // 如果要使用 statusBa
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material.icons.filled.ArrowDownward
|
import androidx.compose.material.icons.filled.ArrowDownward
|
||||||
|
import androidx.compose.material.icons.filled.Block
|
||||||
import androidx.compose.material.icons.filled.Call
|
import androidx.compose.material.icons.filled.Call
|
||||||
import androidx.compose.material.icons.filled.Check
|
import androidx.compose.material.icons.filled.Check
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material.icons.filled.MoreVert
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
import androidx.compose.material.icons.filled.PlayArrow
|
import androidx.compose.material.icons.filled.PlayArrow
|
||||||
|
import androidx.compose.material.icons.filled.Search
|
||||||
|
import androidx.compose.material.icons.filled.Wallpaper
|
||||||
import androidx.compose.runtime.snapshotFlow
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.example.login_v3.home.Message.UI.Detail.Message_Component.AudioMessageBubble
|
import com.example.login_v3.home.Message.UI.Detail.Message_Component.AudioMessageBubble
|
||||||
|
|
@ -112,6 +115,12 @@ sealed interface BottomBarState {
|
||||||
object AttachmentMenu : BottomBarState // 🎯 新增:附件選單
|
object AttachmentMenu : BottomBarState // 🎯 新增:附件選單
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🎯 新增:Top Bar 狀態機
|
||||||
|
sealed interface TopBarState {
|
||||||
|
object Regular : TopBarState // 預設:姓名、頭像、通話、更多
|
||||||
|
object MoreOptions : TopBarState // 點擊「更多」後:顯示功能工具列
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun MessageMessaging(
|
fun MessageMessaging(
|
||||||
|
|
@ -143,6 +152,9 @@ fun MessageMessaging(
|
||||||
//inspect video
|
//inspect video
|
||||||
var lightboxVideoUrl by remember { mutableStateOf<String?>(null) }
|
var lightboxVideoUrl by remember { mutableStateOf<String?>(null) }
|
||||||
|
|
||||||
|
// 🎯 新增:Top Bar 的本地狀態
|
||||||
|
var topBarState by remember { mutableStateOf<TopBarState>(TopBarState.Regular) }
|
||||||
|
|
||||||
// 🌟 核心:使用 derivedStateOf 統一控管狀態權限(長按優先權通常大於單擊)
|
// 🌟 核心:使用 derivedStateOf 統一控管狀態權限(長按優先權通常大於單擊)
|
||||||
// 🎯 新增:用來控管非訊息觸發的底部狀態(例如:AttachmentMenu)
|
// 🎯 新增:用來控管非訊息觸發的底部狀態(例如:AttachmentMenu)
|
||||||
var localBottomBarState by remember { mutableStateOf<BottomBarState?>(null) }
|
var localBottomBarState by remember { mutableStateOf<BottomBarState?>(null) }
|
||||||
|
|
@ -256,11 +268,17 @@ fun MessageMessaging(
|
||||||
|
|
||||||
val topBarShape = RoundedCornerShape(16.dp)
|
val topBarShape = RoundedCornerShape(16.dp)
|
||||||
|
|
||||||
|
// 👈 使用 AnimatedContent 讓 TopBar 切換更平滑
|
||||||
|
AnimatedContent(
|
||||||
|
targetState = topBarState,
|
||||||
|
label = "TopBarSwitchAnimation"
|
||||||
|
) { currentState ->
|
||||||
|
when (currentState) {
|
||||||
|
TopBarState.Regular -> {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 4.dp)
|
.padding(horizontal = 4.dp),
|
||||||
,
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.Start
|
horizontalArrangement = Arrangement.Start
|
||||||
) {
|
) {
|
||||||
|
|
@ -287,10 +305,10 @@ fun MessageMessaging(
|
||||||
.height(58.dp) // 58dp 就會是純內容的高度,內容就會完美垂直置中了!
|
.height(58.dp) // 58dp 就會是純內容的高度,內容就會完美垂直置中了!
|
||||||
.padding(horizontal = 12.dp)
|
.padding(horizontal = 12.dp)
|
||||||
) {
|
) {
|
||||||
val currentState = uiState
|
val uiStateVal = uiState
|
||||||
if (currentState is MessagesUiState.Success) {
|
if (uiStateVal is MessagesUiState.Success) {
|
||||||
UserAvatar(
|
UserAvatar(
|
||||||
avatarUrl = currentState.partnerAvatarUrl,
|
avatarUrl = uiStateVal.partnerAvatarUrl,
|
||||||
modifier = Modifier.size(42.dp)
|
modifier = Modifier.size(42.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -309,10 +327,10 @@ fun MessageMessaging(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if (currentState is MessagesUiState.Success) {
|
if (uiStateVal is MessagesUiState.Success) {
|
||||||
// 拿掉原本只判斷 ONLINE 的 if,讓所有狀態(除了 UNKNOWN)都能顯示
|
// 拿掉原本只判斷 ONLINE 的 if,讓所有狀態(除了 UNKNOWN)都能顯示
|
||||||
UserStatusDot(
|
UserStatusDot(
|
||||||
status = currentState.partnerStatus,
|
status = uiStateVal.partnerStatus,
|
||||||
size = 14.dp // 建議統一成 14.dp,包含白色外圈的視覺效果最好
|
size = 14.dp // 建議統一成 14.dp,包含白色外圈的視覺效果最好
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -365,22 +383,110 @@ fun MessageMessaging(
|
||||||
) {
|
) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
// 這裡觸發語音通話的邏輯,例如:viewModel.startVoiceCall(roomId)
|
topBarState = TopBarState.MoreOptions
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(48.dp) // 給予標準的點擊區域大小
|
.size(48.dp) // 給予標準的點擊區域大小
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.MoreVert, // 👈 這裡使用 Material Design 的預設電話圖標,也可以換成 Icons.Rounded.Phone
|
imageVector = Icons.Default.MoreVert,
|
||||||
contentDescription = "語音通話",
|
contentDescription = "更多選項",
|
||||||
tint = Color.White, // 👈 顏色可以根據你的漸層背景調整,如果是亮色背景可改用 MaterialTheme.colorScheme.onBackground
|
tint = Color.White,
|
||||||
modifier = Modifier.size(28.dp) // Icon 實際的大小
|
modifier = Modifier.size(28.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(6.dp))
|
Spacer(modifier = Modifier.width(6.dp))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TopBarState.MoreOptions -> {
|
||||||
|
// 🎯 當切換到「更多選項」時顯示的 TopBar
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 4.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.Start
|
||||||
|
) {
|
||||||
|
Spacer(modifier = Modifier.width(6.dp))
|
||||||
|
|
||||||
|
// 關閉按鈕,點擊回到 Regular 狀態
|
||||||
|
Box(
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(58.dp)
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
shape = topBarShape
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
IconButton(onClick = { topBarState = TopBarState.Regular }) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Close,
|
||||||
|
contentDescription = "關閉更多選項",
|
||||||
|
tint = Color.White,
|
||||||
|
modifier = Modifier.size(28.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
|
// 更多選項的內容(這裡可以放置搜尋、靜音、成員清單等功能)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.height(58.dp)
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
shape = topBarShape
|
||||||
|
),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
// 搜尋訊息
|
||||||
|
IconButton(onClick = { /* TODO */ }) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Search,
|
||||||
|
contentDescription = "搜尋訊息",
|
||||||
|
tint = Color.White,
|
||||||
|
modifier = Modifier.size(26.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更換壁紙
|
||||||
|
IconButton(onClick = { /* TODO */ }) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Wallpaper,
|
||||||
|
contentDescription = "更換壁紙",
|
||||||
|
tint = Color.White,
|
||||||
|
modifier = Modifier.size(26.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 封鎖用戶
|
||||||
|
IconButton(onClick = { /* TODO */ }) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Block,
|
||||||
|
contentDescription = "封鎖用戶",
|
||||||
|
tint = Color.White,
|
||||||
|
modifier = Modifier.size(26.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(6.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(6.dp))
|
Spacer(modifier = Modifier.height(6.dp))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue