-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathBaseHtmlText.kt
More file actions
81 lines (77 loc) · 3.24 KB
/
BaseHtmlText.kt
File metadata and controls
81 lines (77 loc) · 3.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package de.charlex.compose.htmltext.core
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.hideFromAccessibility
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.unit.dp
@Composable
fun BaseHtmlText(
modifier: Modifier = Modifier,
annotatedString: AnnotatedString,
linkBoxModifier: (text: String, link: String) -> Modifier = { _, _ -> Modifier },
onTextLayout: (TextLayoutResult) -> Unit = {},
onUriClick: ((String) -> Unit)? = null,
text: @Composable (modifier: Modifier, onTextLayout: (TextLayoutResult) -> Unit) -> Unit
) {
val urlAnns = remember(annotatedString) {
annotatedString.getStringAnnotations("url", 0, annotatedString.length)
}
val layoutResultState = remember { mutableStateOf<TextLayoutResult?>(null) }
val density = LocalDensity.current
val uriHandler = LocalUriHandler.current
Box(
modifier = Modifier.semantics(mergeDescendants = isIOS().not()) {
contentDescription = annotatedString.text
}
) {
text(
modifier
.semantics {
if(isIOS().not()) {
hideFromAccessibility()
}
}
) {
layoutResultState.value = it
onTextLayout(it)
}
val layoutResult = layoutResultState.value
if (layoutResult != null) {
urlAnns.forEachIndexed { index, ann ->
val rects = remember(layoutResult, ann) {
computeLinkRects(layoutResult, ann.start, ann.end)
}
rects.forEach { r ->
Box(
modifier = linkBoxModifier(annotatedString.text.substring(ann.start, ann.end), ann.item)
.offset(
x = with(density) { r.left.toDp().takeIf { it > 0.dp } ?: 1.dp }, // If we move the first clickable box to x = 1.dp, the screenreader will read the while string first
y = with(density) { r.top.toDp() }
)
.size(
width = with(density) { r.width.toDp() },
height = with(density) { r.height.toDp() }
)
.semantics {
contentDescription = "Link: ${annotatedString.text.substring(ann.start, ann.end)}"
}
.clickable {
onUriClick?.let { it(ann.item) } ?: uriHandler.openUri(ann.item)
}
)
}
}
}
}
}