# HG changeset patch # User Da Risk # Date 1745789571 14400 # Node ID 46e9b7ddc2ea787d56cc7f4f029ed2b460d77e0d # Parent ed956769792c57938c064bfce9abf0dc65269f06 ui:material3: update creation of LinkAnnotation.Url diff -r ed956769792c -r 46e9b7ddc2ea ui/material3/src/commonMain/kotlin/com/geekorum/aboutoss/ui/material3/AdaptiveOpenSourceDependenciesScreen.kt --- a/ui/material3/src/commonMain/kotlin/com/geekorum/aboutoss/ui/material3/AdaptiveOpenSourceDependenciesScreen.kt Sun Apr 27 17:28:37 2025 -0400 +++ b/ui/material3/src/commonMain/kotlin/com/geekorum/aboutoss/ui/material3/AdaptiveOpenSourceDependenciesScreen.kt Sun Apr 27 17:32:51 2025 -0400 @@ -23,7 +23,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.clickable -import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi @@ -76,9 +75,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.backhandler.BackHandler import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.text.ExperimentalTextApi -import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -321,7 +318,7 @@ onUrlClick: (String) -> Unit, onUrlsFound: (List) -> Unit, ) { - val linkifiedLicense = linkifyText(text = license) + val linkifiedLicense = linkifyText(text = license, onUrlClick = onUrlClick) LaunchedEffect(linkifiedLicense) { val uris = linkifiedLicense.getUrlAnnotations(0, linkifiedLicense.length).map { it.item.url } @@ -349,20 +346,6 @@ ) } ) { paddingValues -> - val layoutResult = remember { mutableStateOf(null) } - val pressIndicator = Modifier.pointerInput(layoutResult, linkifiedLicense) { - detectTapGestures { pos -> - layoutResult.value?.let { layoutResult -> - val posWithScroll = pos.copy(y = pos.y + scrollState.value) - val offset = layoutResult.getOffsetForPosition(posWithScroll) - linkifiedLicense.getUrlAnnotations(start = offset, end = offset) - .firstOrNull()?.let { annotation -> - onUrlClick(annotation.item.url) - } - } - } - } - Text( linkifiedLicense, modifier = Modifier @@ -370,11 +353,7 @@ .consumeWindowInsets(paddingValues) .padding(horizontal = 16.dp) .fillMaxSize() - .then(pressIndicator) - .verticalScroll(scrollState), - onTextLayout = { - layoutResult.value = it - } + .verticalScroll(scrollState) ) } } diff -r ed956769792c -r 46e9b7ddc2ea ui/material3/src/commonMain/kotlin/com/geekorum/aboutoss/ui/material3/OpenSourceDependenciesListScreen.kt --- a/ui/material3/src/commonMain/kotlin/com/geekorum/aboutoss/ui/material3/OpenSourceDependenciesListScreen.kt Sun Apr 27 17:28:37 2025 -0400 +++ b/ui/material3/src/commonMain/kotlin/com/geekorum/aboutoss/ui/material3/OpenSourceDependenciesListScreen.kt Sun Apr 27 17:32:51 2025 -0400 @@ -24,13 +24,11 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack -import androidx.compose.material3.Divider +import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon @@ -97,15 +95,16 @@ navigationIcon = { IconButton(onClick = onUpClick) { Icon( - Icons.Default.ArrowBack, + Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null ) } }, scrollBehavior = scrollBehavior ) - }) { - LazyColumn(Modifier.fillMaxSize(), contentPadding = it) { + } + ) { contentPadding -> + LazyColumn(Modifier.fillMaxSize(), contentPadding = contentPadding) { items(dependencies) { Column { ListItem( diff -r ed956769792c -r 46e9b7ddc2ea ui/material3/src/commonMain/kotlin/com/geekorum/aboutoss/ui/material3/OpenSourceLicenseScreen.kt --- a/ui/material3/src/commonMain/kotlin/com/geekorum/aboutoss/ui/material3/OpenSourceLicenseScreen.kt Sun Apr 27 17:28:37 2025 -0400 +++ b/ui/material3/src/commonMain/kotlin/com/geekorum/aboutoss/ui/material3/OpenSourceLicenseScreen.kt Sun Apr 27 17:32:51 2025 -0400 @@ -21,7 +21,6 @@ */ package com.geekorum.aboutoss.ui.material3 -import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize @@ -29,7 +28,7 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -43,20 +42,18 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.ExperimentalTextApi +import androidx.compose.ui.text.LinkAnnotation +import androidx.compose.ui.text.LinkInteractionListener import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.TextLayoutResult -import androidx.compose.ui.text.UrlAnnotation import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.text.withAnnotation +import androidx.compose.ui.text.withLink import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import com.geekorum.aboutoss.ui.common.BrowserLauncher @@ -109,10 +106,12 @@ onUrlClick: (String) -> Unit, onUrlsFound: (List) -> Unit, ) { - val linkifiedLicense = linkifyText(text = license) + val linkifiedLicense = linkifyText(text = license, onUrlClick = onUrlClick) LaunchedEffect(linkifiedLicense) { val uris = - linkifiedLicense.getUrlAnnotations(0, linkifiedLicense.length).map { it.item.url } + linkifiedLicense.getLinkAnnotations(0, linkifiedLicense.length).map { it.item } + .filterIsInstance() + .map { it.url } onUrlsFound(uris) } @@ -126,38 +125,20 @@ navigationIcon = { IconButton(onClick = onUpClick) { Icon( - Icons.Default.ArrowBack, + Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null ) } }, ) }) { paddingValues -> - val layoutResult = remember { mutableStateOf(null) } - val pressIndicator = Modifier.pointerInput(layoutResult, linkifiedLicense) { - detectTapGestures { pos -> - layoutResult.value?.let { layoutResult -> - val posWithScroll = pos.copy(y = pos.y + scrollState.value) - val offset = layoutResult.getOffsetForPosition(posWithScroll) - linkifiedLicense.getUrlAnnotations(start = offset, end = offset) - .firstOrNull()?.let { annotation -> - onUrlClick(annotation.item.url) - } - } - } - } - Text(linkifiedLicense, modifier = Modifier .padding(paddingValues) .consumeWindowInsets(paddingValues) .padding(horizontal = 16.dp) .fillMaxSize() - .then(pressIndicator) - .verticalScroll(scrollState), - onTextLayout = { - layoutResult.value = it - } + .verticalScroll(scrollState) ) } } @@ -169,7 +150,7 @@ @OptIn(ExperimentalTextApi::class) @Composable -internal fun linkifyText(text: String): AnnotatedString { +internal fun linkifyText(text: String, onUrlClick: (String) -> Unit): AnnotatedString { val style = SpanStyle( color = MaterialTheme.colorScheme.primary, textDecoration = TextDecoration.Underline @@ -182,7 +163,17 @@ append(text.substring(currentIdx, match.range.first)) } val url = text.substring(match.range) - withAnnotation(UrlAnnotation(url)) { + val linkInteractionListener = LinkInteractionListener { + val url = when(it) { + is LinkAnnotation.Url -> it.url + is LinkAnnotation.Clickable -> it.tag + else -> null + } + if (url != null) { + onUrlClick(url) + } + } + withLink(LinkAnnotation.Url(url, linkInteractionListener = linkInteractionListener)) { withStyle(style) { append(url) }