Skip to content

Commit

Permalink
replace deprecated ClickableText
Browse files Browse the repository at this point in the history
* Introduced LinkAnnotation.Clickable to drive the behaviour of links
* Replaced SimpleClickableText with the good ol' Text
* Successfully wired onUrlClick and onTextClick lambdas
and the enabled flag.

Closes #418
  • Loading branch information
hamen committed Jul 2, 2024
1 parent dec6bc3 commit f13a767
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import androidx.compose.foundation.text.appendInlineContent
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.AnnotatedString.Builder
import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.LinkAnnotation.Url
import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import org.commonmark.renderer.text.TextContentRenderer
Expand All @@ -29,16 +28,17 @@ public open class DefaultInlineMarkdownRenderer(
inlineMarkdown: Iterable<InlineMarkdown>,
styling: InlinesStyling,
enabled: Boolean,
onUrlClicked: ((String) -> Unit)?,
): AnnotatedString =
buildAnnotatedString {
appendInlineMarkdownFrom(inlineMarkdown, styling, enabled)
appendInlineMarkdownFrom(inlineMarkdown, styling, enabled, onUrlClicked)
}

@OptIn(ExperimentalTextApi::class)
private fun Builder.appendInlineMarkdownFrom(
inlineMarkdown: Iterable<InlineMarkdown>,
styling: InlinesStyling,
enabled: Boolean,
onUrlClicked: ((String) -> Unit)? = null,
) {
for (child in inlineMarkdown) {
when (child) {
Expand All @@ -63,7 +63,17 @@ public open class DefaultInlineMarkdownRenderer(

is InlineMarkdown.Link -> {
withStyles(styling.link.withEnabled(enabled), child) {
pushLink(Url(it.nativeNode.destination))
val destination = it.nativeNode.destination
val link =
LinkAnnotation.Clickable(
tag = destination,
linkInteractionListener = { _ ->
if (enabled) {
onUrlClicked?.invoke(destination)
}
},
)
pushLink(link)
appendInlineMarkdownFrom(it.children, styling, enabled)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import androidx.compose.animation.core.tween
import androidx.compose.foundation.HorizontalScrollbar
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
Expand All @@ -20,7 +22,6 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.rememberScrollbarAdapter
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.selection.DisableSelection
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
Expand All @@ -42,7 +43,6 @@ import androidx.compose.ui.input.pointer.pointerHoverIcon
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection.Ltr
Expand Down Expand Up @@ -125,16 +125,29 @@ public open class DefaultMarkdownBlockRenderer(
onUrlClick: (String) -> Unit,
onTextClick: () -> Unit,
) {
val renderedContent = rememberRenderedContent(block, styling.inlinesStyling, enabled)
SimpleClickableText(
val renderedContent =
rememberRenderedContent(
block,
styling.inlinesStyling,
enabled,
onUrlClick,
)
val textColor =
styling.inlinesStyling.textStyle.color
.takeOrElse { LocalContentColor.current }
.takeOrElse { styling.inlinesStyling.textStyle.color }
val mergedStyle = styling.inlinesStyling.textStyle.merge(TextStyle(color = textColor))
val interactionSource = remember { MutableInteractionSource() }

Text(
modifier =
Modifier.clickable(
interactionSource = interactionSource,
indication = null,
onClick = onTextClick,
),
text = renderedContent,
textStyle = styling.inlinesStyling.textStyle,
color =
styling.inlinesStyling.textStyle.color
.takeOrElse { LocalContentColor.current },
enabled = enabled,
onUnhandledClick = onTextClick,
onUrlClick = onUrlClick,
style = mergedStyle,
)
}

Expand Down Expand Up @@ -165,17 +178,20 @@ public open class DefaultMarkdownBlockRenderer(
onUrlClick: (String) -> Unit,
onTextClick: () -> Unit,
) {
val renderedContent = rememberRenderedContent(block, styling.inlinesStyling, enabled)
val renderedContent =
rememberRenderedContent(
block,
styling.inlinesStyling,
enabled,
onUrlClick,
)
Heading(
renderedContent,
styling.inlinesStyling.textStyle,
styling.padding,
styling.underlineWidth,
styling.underlineColor,
styling.underlineGap,
enabled,
onUrlClick,
onTextClick,
)
}

Expand All @@ -187,18 +203,15 @@ public open class DefaultMarkdownBlockRenderer(
underlineWidth: Dp,
underlineColor: Color,
underlineGap: Dp,
enabled: Boolean,
onUrlClick: (String) -> Unit,
onTextClick: () -> Unit,
) {
Column(modifier = Modifier.padding(paddingValues)) {
SimpleClickableText(
val textColor =
textStyle.color
.takeOrElse { LocalContentColor.current.takeOrElse { textStyle.color } }
val mergedStyle = textStyle.merge(TextStyle(color = textColor))
Text(
text = renderedContent,
textStyle = textStyle,
color = textStyle.color.takeOrElse { LocalContentColor.current },
enabled = enabled,
onUnhandledClick = onTextClick,
onUrlClick = onUrlClick,
style = mergedStyle,
)

if (underlineWidth > 0.dp && underlineColor.isSpecified) {
Expand Down Expand Up @@ -457,60 +470,9 @@ public open class DefaultMarkdownBlockRenderer(
block: BlockWithInlineMarkdown,
styling: InlinesStyling,
enabled: Boolean,
onUrlClick: ((String) -> Unit)? = null,
) = remember(block.inlineContent, styling, enabled) {
inlineRenderer.renderAsAnnotatedString(block.inlineContent, styling, enabled)
}

@OptIn(ExperimentalTextApi::class)
@Composable
private fun SimpleClickableText(
text: AnnotatedString,
textStyle: TextStyle,
enabled: Boolean,
modifier: Modifier = Modifier,
color: Color = Color.Unspecified,
onUrlClick: (String) -> Unit,
onUnhandledClick: () -> Unit,
) {
var hoverPointerIcon by remember { mutableStateOf(PointerIcon.Default) }
val actualPointerIcon =
remember(hoverPointerIcon, enabled) {
if (enabled) hoverPointerIcon else PointerIcon.Default
}

val textColor = color.takeOrElse { LocalContentColor.current.takeOrElse { textStyle.color } }

val mergedStyle = textStyle.merge(TextStyle(color = textColor))

ClickableText(
text = text,
style = mergedStyle,
modifier = modifier.pointerHoverIcon(actualPointerIcon, true),
onHover = { offset -> hoverPointerIcon = determinePointerIcon(offset, text) },
onClick = { offset ->
if (!enabled) return@ClickableText

val span = text.getUrlAnnotations(offset, offset).firstOrNull()
if (span != null) {
onUrlClick(span.item.url)
} else {
onUnhandledClick()
}
},
)
}

private fun determinePointerIcon(
offset: Int?,
text: AnnotatedString,
): PointerIcon {
if (offset == null) return PointerIcon.Hand

val hasLinkAnnotations = text.getLinkAnnotations(offset, offset).isNotEmpty()
return when {
hasLinkAnnotations -> PointerIcon.Hand
else -> PointerIcon.Default
}
inlineRenderer.renderAsAnnotatedString(block.inlineContent, styling, enabled, onUrlClick)
}

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public interface InlineMarkdownRenderer {
inlineMarkdown: Iterable<InlineMarkdown>,
styling: InlinesStyling,
enabled: Boolean,
onUrlClicked: ((String) -> Unit)? = null,
): AnnotatedString

public companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ internal fun MarkdownPreview(
state = lazyListState,
selectable = true,
onUrlClick = { url -> Desktop.getDesktop().browse(URI.create(url)) },
onTextClick = { },
)

VerticalScrollbar(
Expand Down

0 comments on commit f13a767

Please sign in to comment.