From adeaf2c71f8d17f9fa364cce8642be0924f2b3fd Mon Sep 17 00:00:00 2001 From: "Evgeny @ SimpleX Chat" <259188159+evgeny-simplex@users.noreply.github.com> Date: Wed, 1 Apr 2026 18:58:56 +0000 Subject: [PATCH] better copy button position --- .../chat/simplex/common/views/chat/ChatView.kt | 16 ++++++++++++++-- .../simplex/common/views/chat/TextSelection.kt | 4 ++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt index f36c824b99..758c0f73f9 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt @@ -1137,9 +1137,21 @@ fun ChatLayout( // Desktop selection copy button — last child of outer Box, on top of everything if (appPlatform.isDesktop) { val manager = LocalSelectionManager.current - if (manager != null && manager.selectionState == SelectionState.Selected && manager.onCopySelection != null) { + val range = manager?.range + if (manager != null && manager.selectionState == SelectionState.Selected && manager.onCopySelection != null && range != null) { + val draggingDown = range.startIndex > range.endIndex + val gap = with(LocalDensity.current) { 4.dp.toPx() } + var buttonSize by remember { mutableStateOf(IntSize.Zero) } + val x = if (draggingDown) manager.focusWindowX + else (manager.focusWindowX - buttonSize.width).coerceAtLeast(0f) + val y = if (draggingDown) manager.focusWindowY + gap + else (manager.focusWindowY - buttonSize.height - gap).coerceAtLeast(0f) + val clampedX = x.coerceIn(0f, (manager.viewportWidth - buttonSize.width).coerceAtLeast(0f)) + val clampedY = y.coerceIn(0f, (manager.viewportHeight - buttonSize.height).coerceAtLeast(0f)) SelectionCopyButton( - modifier = Modifier.align(Alignment.BottomCenter).padding(bottom = composeViewHeight.value + 8.dp), + modifier = Modifier + .offset { IntOffset(clampedX.toInt(), clampedY.toInt()) } + .onSizeChanged { buttonSize = it }, onCopy = { manager.onCopySelection?.invoke() } ) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/TextSelection.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/TextSelection.kt index 4d35386bd2..4e36d30890 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/TextSelection.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/TextSelection.kt @@ -64,6 +64,8 @@ class SelectionManager { private set var focusWindowY by mutableStateOf(0f) var focusWindowX by mutableStateOf(0f) + var viewportWidth by mutableStateOf(0f) + var viewportHeight by mutableStateOf(0f) var onCopySelection: (() -> Unit)? = null fun startSelection(startIndex: Int, anchorY: Float, anchorX: Float) { @@ -191,6 +193,8 @@ fun BoxScope.SelectionHandler( val bounds = it.boundsInWindow() viewportTop = bounds.top viewportBottom = bounds.bottom + manager.viewportWidth = bounds.right - bounds.left + manager.viewportHeight = bounds.bottom - bounds.top } .pointerInput(manager) { awaitEachGesture {