diff --git a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationItemView.kt b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationItemView.kt index 6eccffeb5b046b59c5560900955eb4cfe180710f..6dbbd900320400dfe3a9a97f0a026e54201c5c90 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationItemView.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationItemView.kt @@ -1,7 +1,11 @@ package org.briarproject.briar.desktop.conversation import androidx.compose.foundation.BorderStroke -import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.ContextMenuArea +import androidx.compose.foundation.ContextMenuItem +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth @@ -33,6 +37,7 @@ import org.briarproject.briar.desktop.theme.msgStroke import org.briarproject.briar.desktop.theme.privateMessageDate import org.briarproject.briar.desktop.theme.textPrimary import org.briarproject.briar.desktop.utils.InternationalizationUtils +import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n import org.briarproject.briar.desktop.utils.PreviewUtils.preview import org.briarproject.briar.desktop.utils.TimeUtils.getFormattedTimestamp import java.time.Instant @@ -143,28 +148,39 @@ fun main() = preview { /** * Base Composable for all kind of messages in private chats. */ +@OptIn(ExperimentalFoundationApi::class) @Composable fun ConversationItemView( item: ConversationItem, + onDelete: (MessageId) -> Unit = {}, content: @Composable () -> Unit ) { - val alignment = if (item.isIncoming) Alignment.Start else Alignment.End + val arrangement = if (item.isIncoming) Arrangement.Start else Arrangement.End + val alignment = if (item.isIncoming) Alignment.CenterStart else Alignment.CenterEnd val color = if (item.isIncoming) MaterialTheme.colors.msgIn else MaterialTheme.colors.msgOut val shape = if (item.isIncoming) RoundedCornerShape(topStart = 4.dp, topEnd = 16.dp, bottomStart = 16.dp, bottomEnd = 16.dp) else RoundedCornerShape(topStart = 16.dp, topEnd = 4.dp, bottomStart = 16.dp, bottomEnd = 16.dp) - Column(Modifier.fillMaxWidth()) { - Column(Modifier.fillMaxWidth(fraction = 0.8f).align(alignment)) { - Card( - backgroundColor = color, - elevation = 2.dp, - shape = shape, - border = BorderStroke(Dp.Hairline, MaterialTheme.colors.msgStroke), - modifier = Modifier.align(alignment).padding(8.dp), + Row(Modifier.fillMaxWidth(), arrangement) { + Box(Modifier.fillMaxWidth(0.8f), contentAlignment = alignment) { + ContextMenuArea( + items = { + listOf( + ContextMenuItem(i18n("delete")) { onDelete(item.id) } + ) + } ) { - content() + Card( + backgroundColor = color, + elevation = 2.dp, + shape = shape, + border = BorderStroke(Dp.Hairline, MaterialTheme.colors.msgStroke), + modifier = Modifier.padding(8.dp), + ) { + content() + } } } } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationMessageItemView.kt b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationMessageItemView.kt index b9ef25101f019b5b99ccf9c9345c3f54b1101e1d..3619b174251fa5b64689355d0c0f85303463b015 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationMessageItemView.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationMessageItemView.kt @@ -43,9 +43,12 @@ fun main() = preview( * Composable for normal private text messages. */ @Composable -fun ConversationMessageItemView(m: ConversationMessageItem) { +fun ConversationMessageItemView( + m: ConversationMessageItem, + onDelete: (MessageId) -> Unit = {}, +) { val textColor = if (m.isIncoming) MaterialTheme.colors.textPrimary else Color.White - ConversationItemView(m) { + ConversationItemView(m, onDelete) { Column( Modifier.padding(12.dp, 8.dp) ) { diff --git a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationNoticeItemView.kt b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationNoticeItemView.kt index 48dff66eb9e3bca62a0a16f4d743594c354ca34f..8a79f0b1f96accd13c7ca7b0efcb85c90e675d56 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationNoticeItemView.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationNoticeItemView.kt @@ -54,12 +54,15 @@ fun main() = preview( * Composable for private messages containing a notice. */ @Composable -fun ConversationNoticeItemView(m: ConversationNoticeItem) { +fun ConversationNoticeItemView( + m: ConversationNoticeItem, + onDelete: (MessageId) -> Unit = {}, +) { val textColor = if (m.isIncoming) MaterialTheme.colors.textPrimary else Color.White val noticeBackground = if (m.isIncoming) MaterialTheme.colors.noticeIn else MaterialTheme.colors.noticeOut val noticeColor = if (m.isIncoming) MaterialTheme.colors.textSecondary else MaterialTheme.colors.privateMessageDate val text = m.text - ConversationItemView(m) { + ConversationItemView(m, onDelete) { Column(Modifier.width(IntrinsicSize.Max)) { if (text != null) { Text( diff --git a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationRequestItemView.kt b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationRequestItemView.kt index bca4e4827d779bb9b7e1dab9f335d6cf7dd46ed7..865919e7a91b209c176339df9d9f97279f4f50ee 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationRequestItemView.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationRequestItemView.kt @@ -73,12 +73,13 @@ fun ConversationRequestItemView( m: ConversationRequestItem, onResponse: (Boolean) -> Unit = {}, onOpenRequestedShareable: () -> Unit = {}, + onDelete: (MessageId) -> Unit = {}, ) { val statusAlignment = if (m.isIncoming) Alignment.End else Alignment.Start val textColor = if (m.isIncoming) MaterialTheme.colors.textPrimary else Color.White val noticeBackground = if (m.isIncoming) MaterialTheme.colors.noticeIn else MaterialTheme.colors.noticeOut val noticeColor = if (m.isIncoming) MaterialTheme.colors.textSecondary else MaterialTheme.colors.privateMessageDate - ConversationItemView(m) { + ConversationItemView(m, onDelete) { Column(Modifier.width(IntrinsicSize.Max)) { Text( m.text!!, diff --git a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationScreen.kt b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationScreen.kt index de2d26119794712fd402afd096cf4651af952835..89b4a307476aadb896897cace783f53945087827 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationScreen.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationScreen.kt @@ -89,12 +89,13 @@ fun ConversationScreen( ) { items(viewModel.messages) { m -> when (m) { - is ConversationMessageItem -> ConversationMessageItemView(m) - is ConversationNoticeItem -> ConversationNoticeItemView(m) + is ConversationMessageItem -> ConversationMessageItemView(m, viewModel::deleteMessage) + is ConversationNoticeItem -> ConversationNoticeItemView(m, viewModel::deleteMessage) is ConversationRequestItem -> ConversationRequestItemView( m, onResponse = { accept -> viewModel.respondToRequest(m, accept) }, + onDelete = viewModel::deleteMessage, ) } } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationViewModel.kt b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationViewModel.kt index 7bad51e4e63a783bff1a785dd8d060758bbe1aa0..85da3d34147320b7a3d1cd65e8b3c736212362ac 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationViewModel.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/conversation/ConversationViewModel.kt @@ -310,6 +310,15 @@ constructor( } } + fun deleteMessage(id: MessageId) = runOnDbThread { + val result = conversationManager.deleteMessages(_contactId.value!!, listOf(id)) + if (result.allDeleted()) { + _messages.removeIf { it.id == id } + } else { + _deletionResult.value = result + } + } + fun deleteAllMessages() = runOnDbThread { _loadingMessages.value = true try {