feat: add context menu for chat message #43

Merged
reya merged 4 commits from feat/context-menu into master 2026-07-13 10:56:23 +00:00
2 changed files with 32 additions and 21 deletions
Showing only changes of commit 2e290cce0c - Show all commits

View File

@@ -107,7 +107,11 @@ fun rememberMessageUiModel(
} }
@Composable @Composable
fun ChatMessage(model: MessageUiModel, onLongClick: (Rect) -> Unit = {}) { fun ChatMessage(
model: MessageUiModel,
modifier: Modifier = Modifier,
onLongClick: (Rect) -> Unit = {}
) {
var isMessageClicked by remember { mutableStateOf(false) } var isMessageClicked by remember { mutableStateOf(false) }
var layoutCoordinates by remember { mutableStateOf<LayoutCoordinates?>(null) } var layoutCoordinates by remember { mutableStateOf<LayoutCoordinates?>(null) }
@@ -124,10 +128,10 @@ fun ChatMessage(model: MessageUiModel, onLongClick: (Rect) -> Unit = {}) {
if (!model.isMine) MaterialTheme.colorScheme.onSurface else MaterialTheme.colorScheme.onPrimaryContainer if (!model.isMine) MaterialTheme.colorScheme.onSurface else MaterialTheme.colorScheme.onPrimaryContainer
Box( Box(
modifier = Modifier modifier = modifier
.onGloballyPositioned { layoutCoordinates = it }
.fillMaxWidth() .fillMaxWidth()
.padding(vertical = 4.dp) .padding(vertical = 4.dp),
.onGloballyPositioned { layoutCoordinates = it },
contentAlignment = if (model.isMine) Alignment.CenterEnd else Alignment.CenterStart contentAlignment = if (model.isMine) Alignment.CenterEnd else Alignment.CenterStart
) { ) {
Column( Column(

View File

@@ -64,6 +64,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.blur import androidx.compose.ui.draw.blur
import androidx.compose.ui.geometry.Rect import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalWindowInfo import androidx.compose.ui.platform.LocalWindowInfo
@@ -277,8 +278,14 @@ fun ChatScreen(
currentUserPublicKey = currentUser?.publicKey, currentUserPublicKey = currentUser?.publicKey,
contentColor = if (isMine) mineColor else otherColor contentColor = if (isMine) mineColor else otherColor
) )
val isHighlighted =
selectedMessage?.first?.id == uiModel.id
ChatMessage( ChatMessage(
model = uiModel, model = uiModel,
modifier = Modifier.graphicsLayer {
alpha = if (isHighlighted) 0f else 1f
},
onLongClick = { rect -> onLongClick = { rect ->
selectedMessage = uiModel to rect selectedMessage = uiModel to rect
} }
@@ -419,27 +426,27 @@ fun ChatScreen(
val contentBottomDp = with(density) { (bounds.bottom + totalExtraHeightPx).toDp() } val contentBottomDp = with(density) { (bounds.bottom + totalExtraHeightPx).toDp() }
Spacer(modifier = Modifier.height(contentBottomDp + 200.dp)) Spacer(modifier = Modifier.height(contentBottomDp + 200.dp))
Column( ChatMessage(
model = model,
modifier = Modifier modifier = Modifier
.offset { .offset { IntOffset(0, bounds.top.toInt()) }
IntOffset( .padding(horizontal = 16.dp)
0, )
if (showAbove) (bounds.top - totalExtraHeightPx).toInt()
.coerceAtLeast(0) else bounds.top.toInt() val menuOffset = if (showAbove) {
) bounds.top - totalExtraHeightPx
} } else {
bounds.bottom + with(density) { 12.dp.toPx() } // 12dp spacing below
}
Box(
modifier = Modifier
.offset { IntOffset(0, menuOffset.toInt().coerceAtLeast(0)) }
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
horizontalAlignment = if (model.isMine) Alignment.End else Alignment.Start, contentAlignment = if (model.isMine) Alignment.CenterEnd else Alignment.CenterStart
verticalArrangement = Arrangement.spacedBy(12.dp)
) { ) {
if (showAbove) { ContextMenu { selectedMessage = null }
ContextMenu { selectedMessage = null }
ChatMessage(model = model)
} else {
ChatMessage(model = model)
ContextMenu { selectedMessage = null }
}
} }
} }
} }