diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/components/TextSelectionHelper.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/components/TextSelectionHelper.kt index 0c88ce0..5ab7aa9 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/components/TextSelectionHelper.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/components/TextSelectionHelper.kt @@ -19,6 +19,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf @@ -34,6 +35,8 @@ import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.DrawScope import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.positionInWindow import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.font.FontWeight @@ -77,6 +80,10 @@ class TextSelectionHelper { var endHandleX by mutableFloatStateOf(0f) var endHandleY by mutableFloatStateOf(0f) + // Overlay position in window — set by TextSelectionOverlay + var overlayWindowX = 0f + var overlayWindowY = 0f + val isInSelectionMode: Boolean get() = isActive && selectionStart >= 0 && selectionEnd > selectionStart fun startSelection( @@ -199,13 +206,14 @@ class TextSelectionHelper { magnifier = null } - fun getCharOffsetFromCoords(x: Int, y: Int): Int { + fun getCharOffsetFromCoords(overlayLocalX: Int, overlayLocalY: Int): Int { val info = layoutInfo ?: return -1 - val localX = x - info.windowX - val localY = y - info.windowY + // overlay-local → text-local: subtract text position relative to overlay + val textLocalX = overlayLocalX - (info.windowX - overlayWindowX) + val textLocalY = overlayLocalY - (info.windowY - overlayWindowY) val layout = info.layout - val line = layout.getLineForVertical(localY.coerceIn(0, layout.height)) - val hx = localX.toFloat().coerceIn(layout.getLineLeft(line), layout.getLineRight(line)) + val line = layout.getLineForVertical(textLocalY.toInt().coerceIn(0, layout.height)) + val hx = textLocalX.toFloat().coerceIn(layout.getLineLeft(line), layout.getLineRight(line)) return layout.getOffsetForHorizontal(line, hx) } @@ -324,7 +332,15 @@ fun TextSelectionOverlay( val handleInsetPx = with(density) { HandleInset.toPx() } val highlightCornerPx = with(density) { HighlightCorner.toPx() } - Box(modifier = modifier.fillMaxSize()) { + Box( + modifier = modifier + .fillMaxSize() + .onGloballyPositioned { coords -> + val pos = coords.positionInWindow() + helper.overlayWindowX = pos.x + helper.overlayWindowY = pos.y + } + ) { FloatingToolbarPopup(helper = helper) Canvas( modifier = Modifier @@ -387,6 +403,10 @@ fun TextSelectionOverlay( val layout = info.layout val text = info.text + // Convert window coords to overlay-local coords + val offsetX = info.windowX - helper.overlayWindowX + val offsetY = info.windowY - helper.overlayWindowY + val startOffset = helper.selectionStart.coerceIn(0, text.length) val endOffset = helper.selectionEnd.coerceIn(0, text.length) if (startOffset >= endOffset) return@Canvas @@ -395,17 +415,17 @@ fun TextSelectionOverlay( val endLine = layout.getLineForOffset(endOffset) for (line in startLine..endLine) { - val lineTop = layout.getLineTop(line).toFloat() + info.windowY - val lineBottom = layout.getLineBottom(line).toFloat() + info.windowY + val lineTop = layout.getLineTop(line).toFloat() + offsetY + val lineBottom = layout.getLineBottom(line).toFloat() + offsetY val left = if (line == startLine) { - layout.getPrimaryHorizontal(startOffset) + info.windowX + layout.getPrimaryHorizontal(startOffset) + offsetX } else { - layout.getLineLeft(line) + info.windowX + layout.getLineLeft(line) + offsetX } val right = if (line == endLine) { - layout.getPrimaryHorizontal(endOffset) + info.windowX + layout.getPrimaryHorizontal(endOffset) + offsetX } else { - layout.getLineRight(line) + info.windowX + layout.getLineRight(line) + offsetX } drawRoundRect( color = HighlightColor, @@ -415,10 +435,10 @@ fun TextSelectionOverlay( ) } - val startHx = layout.getPrimaryHorizontal(startOffset) + info.windowX - val startHy = layout.getLineBottom(startLine).toFloat() + info.windowY - val endHx = layout.getPrimaryHorizontal(endOffset) + info.windowX - val endHy = layout.getLineBottom(endLine).toFloat() + info.windowY + val startHx = layout.getPrimaryHorizontal(startOffset) + offsetX + val startHy = layout.getLineBottom(startLine).toFloat() + offsetY + val endHx = layout.getPrimaryHorizontal(endOffset) + offsetX + val endHy = layout.getLineBottom(endLine).toFloat() + offsetY helper.startHandleX = startHx helper.startHandleY = startHy