parent
20f96845e1
commit
0287b5e583
@ -1,7 +1,13 @@
|
|||||||
package de.mm20.launcher2.ui.component.markdown
|
package de.mm20.launcher2.ui.component.markdown
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.gestures.awaitEachGesture
|
||||||
|
import androidx.compose.foundation.gestures.awaitFirstDown
|
||||||
|
import androidx.compose.foundation.gestures.detectTapGestures
|
||||||
|
import androidx.compose.foundation.gestures.waitForUpOrCancellation
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.IntrinsicSize
|
import androidx.compose.foundation.layout.IntrinsicSize
|
||||||
@ -21,10 +27,14 @@ import androidx.compose.material3.ProvideTextStyle
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.SpanStyle
|
import androidx.compose.ui.text.SpanStyle
|
||||||
|
import androidx.compose.ui.text.TextLayoutResult
|
||||||
import androidx.compose.ui.text.buildAnnotatedString
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
@ -134,11 +144,38 @@ fun ParagraphNode(node: ASTNode, text: String) {
|
|||||||
val substring = text.substring(start, end)
|
val substring = text.substring(start, end)
|
||||||
val colorScheme = MaterialTheme.colorScheme
|
val colorScheme = MaterialTheme.colorScheme
|
||||||
val typography = MaterialTheme.typography
|
val typography = MaterialTheme.typography
|
||||||
|
|
||||||
|
val layoutResult = remember { mutableStateOf<TextLayoutResult?>(null) }
|
||||||
|
|
||||||
|
val text = buildAnnotatedString {
|
||||||
|
append(substring)
|
||||||
|
applyStyles(node, colorScheme, typography, SpanStyle(fontSize = 0.sp), text, node.startOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = buildAnnotatedString {
|
text = text,
|
||||||
append(substring)
|
onTextLayout = {
|
||||||
applyStyles(node, colorScheme, typography, SpanStyle(fontSize = 0.sp), node.startOffset)
|
layoutResult.value = it
|
||||||
},
|
},
|
||||||
|
modifier = Modifier.pointerInput(Unit) {
|
||||||
|
awaitEachGesture {
|
||||||
|
val down = awaitFirstDown(true)
|
||||||
|
val offset = down.position
|
||||||
|
val position = layoutResult.value?.getOffsetForPosition(offset) ?: return@awaitEachGesture
|
||||||
|
val downUrlAnnotation = text.getUrlAnnotations(position, position).firstOrNull()
|
||||||
|
val downUrl = downUrlAnnotation?.item?.url ?: return@awaitEachGesture
|
||||||
|
val up = waitForUpOrCancellation()?.takeIf { !it.isConsumed } ?: return@awaitEachGesture
|
||||||
|
val upPosition = layoutResult.value?.getOffsetForPosition(offset) ?: return@awaitEachGesture
|
||||||
|
val upAnnotation = text.getUrlAnnotations(upPosition, upPosition).firstOrNull()
|
||||||
|
val url = upAnnotation?.item?.url ?: return@awaitEachGesture
|
||||||
|
if (url == downUrl) {
|
||||||
|
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
|
||||||
|
up.consume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import androidx.compose.material3.MaterialTheme
|
|||||||
import androidx.compose.material3.Typography
|
import androidx.compose.material3.Typography
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
import androidx.compose.ui.text.SpanStyle
|
import androidx.compose.ui.text.SpanStyle
|
||||||
|
import androidx.compose.ui.text.UrlAnnotation
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.text.font.FontStyle
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
@ -19,6 +20,7 @@ fun AnnotatedString.Builder.applyStyles(
|
|||||||
colorScheme: ColorScheme,
|
colorScheme: ColorScheme,
|
||||||
typography: Typography,
|
typography: Typography,
|
||||||
delimiterStyle: SpanStyle,
|
delimiterStyle: SpanStyle,
|
||||||
|
fullText: String? = null,
|
||||||
rootOffset: Int = 0,
|
rootOffset: Int = 0,
|
||||||
) {
|
) {
|
||||||
require(node.startOffset >= rootOffset) {
|
require(node.startOffset >= rootOffset) {
|
||||||
@ -143,11 +145,19 @@ fun AnnotatedString.Builder.applyStyles(
|
|||||||
destination.startOffset - rootOffset,
|
destination.startOffset - rootOffset,
|
||||||
destination.endOffset - rootOffset,
|
destination.endOffset - rootOffset,
|
||||||
)
|
)
|
||||||
|
if (fullText != null) {
|
||||||
|
val url = fullText.substring(destination.startOffset, destination.endOffset)
|
||||||
|
addUrlAnnotation(
|
||||||
|
UrlAnnotation(url),
|
||||||
|
text.startOffset - rootOffset,
|
||||||
|
text.endOffset - rootOffset,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (child in node.children) {
|
for (child in node.children) {
|
||||||
applyStyles(child, colorScheme, typography, delimiterStyle, rootOffset)
|
applyStyles(child, colorScheme, typography, delimiterStyle, fullText, rootOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.children.isEmpty() &&
|
if (node.children.isEmpty() &&
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user