Fix markdown links

CLose #427
This commit is contained in:
MM20 2023-06-17 21:44:52 +02:00
parent 20f96845e1
commit 0287b5e583
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
2 changed files with 51 additions and 4 deletions

View File

@ -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()
}
}
}
) )
} }

View File

@ -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() &&