diff --git a/libraries/htmlrenderer/api/src/main/kotlin/io/element/android/libraries/htmlrenderer/api/ui/HtmlMessageContent.kt b/libraries/htmlrenderer/api/src/main/kotlin/io/element/android/libraries/htmlrenderer/api/ui/HtmlMessageContent.kt index a8daab7a90..e113856cf7 100644 --- a/libraries/htmlrenderer/api/src/main/kotlin/io/element/android/libraries/htmlrenderer/api/ui/HtmlMessageContent.kt +++ b/libraries/htmlrenderer/api/src/main/kotlin/io/element/android/libraries/htmlrenderer/api/ui/HtmlMessageContent.kt @@ -13,7 +13,8 @@ import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable -import androidx.compose.foundation.gestures.detectTapGestures +import androidx.compose.foundation.gestures.awaitEachGesture +import androidx.compose.foundation.gestures.awaitFirstDown import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -51,6 +52,8 @@ import androidx.compose.ui.graphics.drawOutline import androidx.compose.ui.graphics.drawscope.Fill import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.drawscope.translate +import androidx.compose.ui.input.pointer.PointerEventTimeoutCancellationException +import androidx.compose.ui.input.pointer.changedToUp import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.ClipEntry import androidx.compose.ui.platform.LocalClipboard @@ -327,10 +330,10 @@ private fun CodeBlockView( ) // Previews and screenshots can't render the fading edge gradients properly, everything is obscured by them, so we skip them in the preview mode. - if (LocalInspectionMode.current.not()) { + if (LocalInspectionMode.current.not() && (scrollState.canScrollForward || scrollState.canScrollBackward)) { val progress by remember { derivedStateOf { - scrollState.value.toFloat() / scrollState.maxValue.coerceAtLeast(1) + scrollState.value.toFloat() / scrollState.maxValue } } @@ -536,21 +539,50 @@ private fun Modifier.drawInlineCodeBackgrounds( } } +/** + * Detects taps and long presses on link-annotated ranges ([LINK_ANNOTATION_TAG]) without consuming the touch events if none are detected, and invokes the + * appropriate callbacks in [context]. + */ private fun Modifier.linkTapHandler( text: AnnotatedString, layoutResult: State, context: RenderContext, ): Modifier = pointerInput(text) { - detectTapGestures( - onTap = { offset -> - val (url, urlText) = layoutResult.value?.urlAt(offset, text) ?: return@detectTapGestures - context.onLinkClick(url, urlText) - }, - onLongPress = { offset -> - val (url, urlText) = layoutResult.value?.urlAt(offset, text) ?: return@detectTapGestures + awaitEachGesture { + val down = awaitFirstDown(requireUnconsumed = true) + val (url, urlText) = layoutResult.value?.urlAt(down.position, text) ?: return@awaitEachGesture + down.consume() + + val longPressTimeout = viewConfiguration.longPressTimeoutMillis + + // Try detecting a long press by waiting for the long press timeout and checking if we received an up event before that. + // If we did, it's a tap, otherwise it's a long press. + // This warning is a false positive. + @Suppress("KotlinConstantConditions") + val isLongPress = try { + withTimeout(longPressTimeout) { + var receivedUp = false + while (!receivedUp) { + val event = awaitPointerEvent() + val up = event.changes.firstOrNull { it.id == down.id && it.changedToUp() } + if (up != null) { + receivedUp = true + up.consume() + } + } + + !receivedUp + } + } catch (_: PointerEventTimeoutCancellationException) { + true + } + + if (isLongPress) { context.onLinkLongClick(url, urlText) - }, - ) + } else { + context.onLinkClick(url, urlText) + } + } } private fun TextLayoutResult.urlAt(offset: Offset, text: AnnotatedString): Pair? { @@ -563,7 +595,7 @@ private val BlockSpacing: Dp = 8.dp private val ListItemSpacing: Dp = 4.dp private val ListMarkerWidth: Dp = 24.dp private val PillPaddingHorizontal: Dp = 6.dp -private val PillPaddingVertical: Dp = 2.dp +private val PillPaddingVertical: Dp = 0.dp /** Rounded, bordered box drawn behind inline code. */ private val InlineCodeCornerRadius: Dp = 6.dp diff --git a/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Day_12_en.png b/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Day_12_en.png index 36fea9517e..49814bedc6 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Day_12_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Day_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9cf8a07aeadd7d54bcdf3304d0bf1efe0a00c1964c02b0a24cd6d7718cc51d4b -size 31085 +oid sha256:b8b3b3a5773ae0b1f977a8b1292236bcff53edc62a5e23ff1be4bf0d754f63be +size 30970 diff --git a/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Day_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Day_8_en.png index 8937dd7d87..24681fe14e 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:55da0734cf5c1c97e17eee5c88273fc63c94dfa7b3eab12a3e1ea2da0783e039 -size 8812 +oid sha256:7b83727a7fc35b5e45a33646e9bf96ef97360ab0f306a69e9d5bf31c2a24259e +size 8771 diff --git a/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Day_9_en.png b/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Day_9_en.png index b1f89a1f45..391077324c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2e457089542659d700e4493bf1d345f79d7c829cbbded2d4337882a7e45f6808 -size 8783 +oid sha256:75c27380a0cf861710146a84fd5ab935b2d7561bd032333e748c627147886cd9 +size 8727 diff --git a/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Night_12_en.png b/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Night_12_en.png index 7cc90da21f..64077b57d0 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Night_12_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Night_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eb4918eba234005d307ff24540bc837d4e3f06db06eee6e841e5c2af6cae1063 -size 30378 +oid sha256:caba9c9e478971907b7a2b50efc4ea48280cb140995b7805c5bd35c30215d86e +size 30285 diff --git a/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Night_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Night_8_en.png index 5d48d880e6..518fa26b23 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2bc513febce6bcc1a452cedbfe640ff029cdd8bafcae852d6bdaa2fac4b85094 -size 8593 +oid sha256:84c81c2abeb213aa164c9eab7fd23d4a7e02d2140d0d6ceb054c20b596d039ca +size 8453 diff --git a/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Night_9_en.png b/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Night_9_en.png index 30fad755ca..24ca8f674a 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.htmlrenderer.api.ui_HtmlMessageContent_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3db9c79b4e0ce71b93da5aba58fd9bdcc977a0a979eb89f8027b3ca378f25d5e -size 8360 +oid sha256:e236ca70f7b453462f63dbc21027408ab5bb37c7240378e0286b60ead3dc3730 +size 8385