From 7c1f8d6a4c40c9f58f31ea318dea46fd1ff970a7 Mon Sep 17 00:00:00 2001 From: Jesse Horne Date: Mon, 27 Nov 2023 20:02:17 -0500 Subject: [PATCH] initial work on selecting text in desktop --- .../common/views/helpers/Modifiers.android.kt | 44 +++++++++++++ .../common/views/chat/item/ChatItemView.kt | 2 +- .../common/views/chat/item/FramedItemView.kt | 64 +++++++++++++++---- .../simplex/common/views/helpers/Modifiers.kt | 16 +---- .../common/views/helpers/Modifiers.desktop.kt | 14 ++++ 5 files changed, 111 insertions(+), 29 deletions(-) create mode 100644 apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/helpers/Modifiers.android.kt create mode 100644 apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/Modifiers.desktop.kt diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/helpers/Modifiers.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/helpers/Modifiers.android.kt new file mode 100644 index 0000000000..bc7767a9ef --- /dev/null +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/helpers/Modifiers.android.kt @@ -0,0 +1,44 @@ +package chat.simplex.common.views.helpers + +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.layout.offset +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.layout +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.LayoutDirection +import kotlin.math.roundToInt + +fun Modifier.badgeLayout() = + layout { measurable, constraints -> + val placeable = measurable.measure(constraints) + + // based on the expectation of only one line of text + val minPadding = placeable.height / 4 + + val width = maxOf(placeable.width + minPadding, placeable.height) + layout(width, placeable.height) { + placeable.place((width - placeable.width) / 2, 0) + } + } + +@Composable +actual fun SwipeToDismissModifier( + state: DismissState, + directions: Set, + swipeDistance: Float, +): Modifier { + val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl + val anchors = mutableMapOf(0f to DismissValue.Default) + if (DismissDirection.StartToEnd in directions) anchors += swipeDistance to DismissValue.DismissedToEnd + if (DismissDirection.EndToStart in directions) anchors += -swipeDistance to DismissValue.DismissedToStart + return Modifier.swipeable( + state = state, + anchors = anchors, + thresholds = { _, _ -> FractionalThreshold(0.5f) }, + orientation = Orientation.Horizontal, + reverseDirection = isRtl, + ).offset { IntOffset(state.offset.value.roundToInt(), 0) } +} diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt index abb67da50a..1c361df9a3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt @@ -124,7 +124,7 @@ fun ChatItemView( Column( Modifier .clip(RoundedCornerShape(18.dp)) - .combinedClickable(onLongClick = { showMenu.value = true }, onClick = onClick) + .combinedClickable(onLongClick = { if (!appPlatform.isDesktop) showMenu.value = true }, onClick = onClick) .onRightClick { showMenu.value = true }, ) { @Composable diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/FramedItemView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/FramedItemView.kt index c391200c2d..8dab87a453 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/FramedItemView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/FramedItemView.kt @@ -3,6 +3,7 @@ package chat.simplex.common.views.chat.item import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment @@ -11,6 +12,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.input.pointer.PointerButton import androidx.compose.ui.layout.* import androidx.compose.ui.platform.UriHandler import dev.icerock.moko.resources.compose.painterResource @@ -51,15 +53,34 @@ fun FramedItemView( @Composable fun ciQuotedMsgTextView(qi: CIQuote, lines: Int) { - MarkdownText( - qi.text, - qi.formattedText, - maxLines = lines, - overflow = TextOverflow.Ellipsis, - style = TextStyle(fontSize = 15.sp, color = MaterialTheme.colors.onSurface), - linkMode = linkMode, - uriHandler = if (appPlatform.isDesktop) uriHandler else null - ) + if (appPlatform.isDesktop) { + SelectionContainer( + modifier = Modifier.onClick( + matcher = PointerMatcher.mouse(PointerButton.Secondary), + onClick = { showMenu.value = true } + ) + ) { + MarkdownText( + qi.text, + qi.formattedText, + maxLines = lines, + overflow = TextOverflow.Ellipsis, + style = TextStyle(fontSize = 15.sp, color = MaterialTheme.colors.onSurface), + linkMode = linkMode, + uriHandler = if (appPlatform.isDesktop) uriHandler else null + ) + } + } else { + MarkdownText( + qi.text, + qi.formattedText, + maxLines = lines, + overflow = TextOverflow.Ellipsis, + style = TextStyle(fontSize = 15.sp, color = MaterialTheme.colors.onSurface), + linkMode = linkMode, + uriHandler = if (appPlatform.isDesktop) uriHandler else null + ) + } } @Composable @@ -287,11 +308,26 @@ fun CIMarkdownText( ) { Box(Modifier.padding(vertical = 6.dp, horizontal = 12.dp)) { val text = if (ci.meta.isLive) ci.content.msgContent?.text ?: ci.text else ci.text - MarkdownText( - text, if (text.isEmpty()) emptyList() else ci.formattedText, - meta = ci.meta, chatTTL = chatTTL, linkMode = linkMode, - uriHandler = uriHandler, senderBold = true, onLinkLongClick = onLinkLongClick - ) + if (appPlatform.isDesktop) { + SelectionContainer( + modifier = Modifier.onClick( + matcher = PointerMatcher.mouse(PointerButton.Secondary), + onClick = {} + ) + ) { + MarkdownText( + text, if (text.isEmpty()) emptyList() else ci.formattedText, + meta = ci.meta, chatTTL = chatTTL, linkMode = linkMode, + uriHandler = uriHandler, senderBold = true, onLinkLongClick = onLinkLongClick + ) + } + } else { + MarkdownText( + text, if (text.isEmpty()) emptyList() else ci.formattedText, + meta = ci.meta, chatTTL = chatTTL, linkMode = linkMode, + uriHandler = uriHandler, senderBold = true, onLinkLongClick = onLinkLongClick + ) + } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Modifiers.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Modifiers.kt index 6990a69ebd..d907c1394f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Modifiers.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Modifiers.kt @@ -25,20 +25,8 @@ fun Modifier.badgeLayout() = } @Composable -fun SwipeToDismissModifier( +expect fun SwipeToDismissModifier( state: DismissState, directions: Set = setOf(DismissDirection.EndToStart, DismissDirection.StartToEnd), swipeDistance: Float, -): Modifier { - val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl - val anchors = mutableMapOf(0f to DismissValue.Default) - if (DismissDirection.StartToEnd in directions) anchors += swipeDistance to DismissValue.DismissedToEnd - if (DismissDirection.EndToStart in directions) anchors += -swipeDistance to DismissValue.DismissedToStart - return Modifier.swipeable( - state = state, - anchors = anchors, - thresholds = { _, _ -> FractionalThreshold(0.5f) }, - orientation = Orientation.Horizontal, - reverseDirection = isRtl, - ).offset { IntOffset(state.offset.value.roundToInt(), 0) } -} +): Modifier diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/Modifiers.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/Modifiers.desktop.kt new file mode 100644 index 0000000000..40e28b5be0 --- /dev/null +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/Modifiers.desktop.kt @@ -0,0 +1,14 @@ +package chat.simplex.common.views.helpers + +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +actual fun SwipeToDismissModifier( + state: DismissState, + directions: Set, + swipeDistance: Float, +): Modifier { + return Modifier +}