Converts old ClickableTexts into new Compose Texts with clickable spans

This commit is contained in:
Vitor Pamplona
2025-04-02 20:37:14 -04:00
parent 4ac046fe39
commit 7c4911f2dc
27 changed files with 358 additions and 444 deletions
@@ -23,13 +23,8 @@ package com.vitorpamplona.amethyst.ui.components
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.AnnotatedString
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
@Composable @Composable
@@ -37,10 +32,9 @@ fun ClickableEmail(email: String) {
val stripped = email.replaceFirst("mailto:", "") val stripped = email.replaceFirst("mailto:", "")
val context = LocalContext.current val context = LocalContext.current
ClickableText( ClickableTextPrimary(
text = remember { AnnotatedString(stripped) }, text = stripped,
onClick = { runCatching { context.sendMail(stripped) } }, onClick = { runCatching { context.sendMail(stripped) } },
style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary),
) )
} }
@@ -1,45 +0,0 @@
/**
* Copyright (c) 2024 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.ui.components
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.text.AnnotatedString
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.navigation.routeFor
import com.vitorpamplona.amethyst.ui.note.toShortenHex
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
fun ClickableNoteTag(
baseNote: Note,
accountViewModel: AccountViewModel,
nav: INav,
) {
ClickableText(
text = AnnotatedString("@${baseNote.idNote().toShortenHex()}"),
onClick = { routeFor(baseNote, accountViewModel.userProfile())?.let { nav.nav(it) } },
style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary),
)
}
@@ -23,22 +23,16 @@ package com.vitorpamplona.amethyst.ui.components
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.AnnotatedString
@Composable @Composable
fun ClickablePhone(phone: String) { fun ClickablePhone(phone: String) {
val context = LocalContext.current val context = LocalContext.current
ClickableText( ClickableTextPrimary(
text = remember { AnnotatedString(phone) }, text = phone,
onClick = { runCatching { context.dial(phone) } }, onClick = { context.dial(phone) },
style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary),
) )
} }
@@ -20,10 +20,8 @@
*/ */
package com.vitorpamplona.amethyst.ui.components package com.vitorpamplona.amethyst.ui.components
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.InlineTextContent import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.foundation.text.appendInlineContent import androidx.compose.foundation.text.appendInlineContent
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
@@ -41,18 +39,18 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.takeOrElse import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.Placeholder import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.PlaceholderVerticalAlign import androidx.compose.ui.text.PlaceholderVerticalAlign
import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.text.TextLinkStyles
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withLink
import androidx.compose.ui.text.withStyle import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@@ -367,7 +365,7 @@ fun CreateClickableText(
overrideColor: Color? = null, overrideColor: Color? = null,
fontWeight: FontWeight? = null, fontWeight: FontWeight? = null,
fontSize: TextUnit = TextUnit.Unspecified, fontSize: TextUnit = TextUnit.Unspecified,
onClick: (Int) -> Unit, onClick: () -> Unit,
) { ) {
val primaryColor = MaterialTheme.colorScheme.primary val primaryColor = MaterialTheme.colorScheme.primary
val onBackgroundColor = MaterialTheme.colorScheme.onBackground val onBackgroundColor = MaterialTheme.colorScheme.onBackground
@@ -381,61 +379,34 @@ fun CreateClickableText(
fontWeight = fontWeight, fontWeight = fontWeight,
) )
val nonClickablePartStyle =
SpanStyle(
fontSize = fontSize,
color = overrideColor ?: onBackgroundColor,
fontWeight = fontWeight,
)
buildAnnotatedString { buildAnnotatedString {
withStyle(clickablePartStyle) { append(clickablePart) } withLink(
if (!suffix.isNullOrBlank()) { LinkAnnotation.Clickable(
withStyle(nonClickablePartStyle) { append(suffix) } tag = "clickable",
styles = TextLinkStyles(clickablePartStyle),
) {
onClick()
},
) {
append(clickablePart)
} }
} if (!suffix.isNullOrBlank()) {
} val nonClickablePartStyle =
SpanStyle(
fontSize = fontSize,
color = overrideColor ?: onBackgroundColor,
fontWeight = fontWeight,
)
ClickableText( withStyle(nonClickablePartStyle) { append(suffix) }
text = text,
maxLines = maxLines,
overflow = TextOverflow.Ellipsis,
onClick = onClick,
)
}
@Composable
fun ClickableText(
text: AnnotatedString,
modifier: Modifier = Modifier,
style: TextStyle = LocalTextStyle.current,
softWrap: Boolean = true,
overflow: TextOverflow = TextOverflow.Clip,
maxLines: Int = Int.MAX_VALUE,
onTextLayout: (TextLayoutResult) -> Unit = {},
onClick: (Int) -> Unit,
) {
val layoutResult = remember { mutableStateOf<TextLayoutResult?>(null) }
val pressIndicator =
Modifier.pointerInput(onClick) {
detectTapGestures { pos ->
layoutResult.value?.let { layoutResult ->
onClick(layoutResult.getOffsetForPosition(pos))
} }
} }
} }
Text( Text(
text = text, text = text,
modifier = modifier.then(pressIndicator),
style = style,
softWrap = softWrap,
overflow = overflow,
maxLines = maxLines, maxLines = maxLines,
onTextLayout = { overflow = TextOverflow.Ellipsis,
layoutResult.value = it
onTextLayout(it)
},
) )
} }
@@ -611,21 +582,29 @@ fun CreateClickableTextWithEmoji(
maxLines: Int = Int.MAX_VALUE, maxLines: Int = Int.MAX_VALUE,
tags: ImmutableListOfLists<String>?, tags: ImmutableListOfLists<String>?,
style: TextStyle, style: TextStyle,
onClick: (Int) -> Unit, onClick: () -> Unit,
) { ) {
CustomEmojiChecker( CustomEmojiChecker(
text = clickablePart, text = clickablePart,
tags = tags, tags = tags,
onRegularText = { onRegularText = {
ClickableText( Text(
text = AnnotatedString(clickablePart), text =
buildAnnotatedString {
withLink(
LinkAnnotation.Clickable("me") {
onClick()
},
) {
append(clickablePart)
}
},
style = style, style = style,
maxLines = maxLines, maxLines = maxLines,
onClick = onClick,
) )
}, },
onEmojiText = { onEmojiText = {
ClickableInLineIconRenderer(it, maxLines, style.toSpanStyle()) { onClick(it) } ClickableInLineIconRenderer(it, maxLines, style.toSpanStyle(), onClick = onClick)
}, },
) )
} }
@@ -683,15 +662,11 @@ fun ClickableInLineIconRenderer(
style: SpanStyle, style: SpanStyle,
suffix: String? = null, suffix: String? = null,
nonClickableStype: SpanStyle? = null, nonClickableStype: SpanStyle? = null,
onClick: (Int) -> Unit, onClick: () -> Unit,
) { ) {
val placeholderSize = val placeholderSize =
remember(style) { remember(style) {
if (style.fontSize == TextUnit.Unspecified) { if (style.fontSize == TextUnit.Unspecified) 22.sp else style.fontSize.times(1.1f)
22.sp
} else {
style.fontSize.times(1.1f)
}
} }
val inlineContent = val inlineContent =
@@ -725,8 +700,10 @@ fun ClickableInLineIconRenderer(
val annotatedText = val annotatedText =
buildAnnotatedString { buildAnnotatedString {
wordsInOrder.forEachIndexed { idx, value -> wordsInOrder.forEachIndexed { idx, value ->
withStyle( withLink(
style, LinkAnnotation.Clickable("link", TextLinkStyles(style)) {
onClick()
},
) { ) {
if (value is CustomEmoji.TextType) { if (value is CustomEmoji.TextType) {
append(value.text) append(value.text)
@@ -743,20 +720,10 @@ fun ClickableInLineIconRenderer(
} }
} }
val layoutResult = remember { mutableStateOf<TextLayoutResult?>(null) }
val pressIndicator =
Modifier.pointerInput(onClick) {
detectTapGestures { pos ->
layoutResult.value?.let { layoutResult -> onClick(layoutResult.getOffsetForPosition(pos)) }
}
}
Text( Text(
text = annotatedText, text = annotatedText,
modifier = pressIndicator,
inlineContent = inlineContent, inlineContent = inlineContent,
maxLines = maxLines, maxLines = maxLines,
onTextLayout = { layoutResult.value = it },
) )
} }
@@ -771,11 +738,7 @@ fun InLineIconRenderer(
) { ) {
val placeholderSize = val placeholderSize =
remember(fontSize) { remember(fontSize) {
if (fontSize == TextUnit.Unspecified) { if (fontSize == TextUnit.Unspecified) 22.sp else fontSize.times(1.1f)
22.sp
} else {
fontSize.times(1.1f)
}
} }
val inlineContent = val inlineContent =
@@ -0,0 +1,151 @@
/**
* Copyright (c) 2024 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.ui.components
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.AnnotatedString.Builder
import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextLinkStyles
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withLink
@Composable
fun ClickableTextPrimary(
text: String,
modifier: Modifier = Modifier,
style: TextStyle = LocalTextStyle.current,
softWrap: Boolean = true,
overflow: TextOverflow = TextOverflow.Ellipsis,
maxLines: Int = Int.MAX_VALUE,
onClick: () -> Unit,
) {
ClickableTextColor(
text,
modifier,
style,
softWrap,
overflow,
maxLines,
MaterialTheme.colorScheme.primary,
onClick,
)
}
@Composable
fun ClickableTextColor(
text: String,
modifier: Modifier = Modifier,
style: TextStyle = LocalTextStyle.current,
softWrap: Boolean = true,
overflow: TextOverflow = TextOverflow.Ellipsis,
maxLines: Int = Int.MAX_VALUE,
linkColor: Color = MaterialTheme.colorScheme.primary,
onClick: () -> Unit,
) {
Text(
text =
remember(text) {
buildAnnotatedString {
appendLink(text, linkColor, onClick)
}
},
modifier = modifier,
style = style,
softWrap = softWrap,
overflow = overflow,
maxLines = maxLines,
)
}
@Composable
fun ClickableTextNormal(
text: String,
modifier: Modifier = Modifier,
style: TextStyle = LocalTextStyle.current,
softWrap: Boolean = true,
overflow: TextOverflow = TextOverflow.Ellipsis,
maxLines: Int = Int.MAX_VALUE,
onClick: () -> Unit,
) {
Text(
text =
remember(text) {
buildAnnotatedString {
appendLink(text, onClick)
}
},
modifier = modifier,
style = style,
softWrap = softWrap,
overflow = overflow,
maxLines = maxLines,
)
}
inline fun Builder.appendLink(
text: String,
color: Color,
crossinline onClick: () -> Unit,
) = withLink(
LinkAnnotation.Clickable(
"clickable",
TextLinkStyles(SpanStyle(color)),
) {
onClick()
},
) {
append(text)
}
inline fun Builder.appendLink(
text: String,
crossinline onClick: () -> Unit,
) = withLink(
LinkAnnotation.Clickable("clickable") {
onClick()
},
) {
append(text)
}
inline fun buildLinkString(
text: String,
crossinline onClick: () -> Unit,
): AnnotatedString =
buildAnnotatedString {
withLink(
LinkAnnotation.Clickable("link") {
onClick()
},
) {
append(text)
}
}
@@ -20,13 +20,10 @@
*/ */
package com.vitorpamplona.amethyst.ui.components package com.vitorpamplona.amethyst.ui.components
import androidx.compose.foundation.text.ClickableText import android.R.attr.maxLines
import androidx.compose.material3.LocalTextStyle import android.R.attr.onClick
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
@Composable @Composable
@@ -36,10 +33,8 @@ fun ClickableUrl(
) { ) {
val uri = LocalUriHandler.current val uri = LocalUriHandler.current
val text = remember(urlText) { AnnotatedString(urlText) } ClickableTextPrimary(
text = urlText,
ClickableText(
text = text,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
onClick = { onClick = {
@@ -48,6 +43,5 @@ fun ClickableUrl(
uri.openUri(doubleCheckedUrl) uri.openUri(doubleCheckedUrl)
} }
}, },
style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary),
) )
} }
@@ -1,52 +0,0 @@
/**
* Copyright (c) 2024 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.ui.components
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.text.AnnotatedString
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.navigation.routeFor
@Composable
fun ClickableUserTag(
user: User,
nav: INav,
) {
val route = remember(user) { routeFor(user) }
val innerUserState by user.live().metadata.observeAsState()
val userName =
remember(innerUserState) { AnnotatedString("@${innerUserState?.user?.toBestDisplayName()}") }
ClickableText(
text = userName,
onClick = { nav.nav(route) },
style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary),
)
}
@@ -20,9 +20,7 @@
*/ */
package com.vitorpamplona.amethyst.ui.components package com.vitorpamplona.amethyst.ui.components
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -31,7 +29,6 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextDirection import androidx.compose.ui.text.style.TextDirection
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
@@ -70,8 +67,6 @@ fun MayBeWithdrawal(
fun ClickableWithdrawal(withdrawalString: String) { fun ClickableWithdrawal(withdrawalString: String) {
val context = LocalContext.current val context = LocalContext.current
val withdraw = remember(withdrawalString) { AnnotatedString("$withdrawalString ") }
var showErrorMessageDialog by remember { mutableStateOf<String?>(null) } var showErrorMessageDialog by remember { mutableStateOf<String?>(null) }
if (showErrorMessageDialog != null) { if (showErrorMessageDialog != null) {
@@ -82,9 +77,8 @@ fun ClickableWithdrawal(withdrawalString: String) {
) )
} }
ClickableText( ClickableTextPrimary(
text = withdraw, text = "$withdrawalString ",
onClick = { payViaIntent(withdrawalString, context, { }) { showErrorMessageDialog = it } }, onClick = { payViaIntent(withdrawalString, context, { }) { showErrorMessageDialog = it } },
style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary),
) )
} }
@@ -762,7 +762,10 @@ private fun DisplayNoteFromTag(
nav = nav, nav = nav,
) )
} else { } else {
ClickableNoteTag(baseNote, accountViewModel, nav) ClickableTextPrimary(
text = "@${baseNote.idNote().toShortenHex()}",
onClick = { routeFor(baseNote, accountViewModel.userProfile())?.let { nav.nav(it) } },
)
} }
addedChars?.ifBlank { null }?.let { Text(text = it) } addedChars?.ifBlank { null }?.let { Text(text = it) }
@@ -20,6 +20,7 @@
*/ */
package com.vitorpamplona.amethyst.ui.navigation package com.vitorpamplona.amethyst.ui.navigation
import android.R.attr.maxLines
import android.R.attr.onClick import android.R.attr.onClick
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.border import androidx.compose.foundation.border
@@ -73,13 +74,15 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextLinkStyles
import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withStyle import androidx.compose.ui.text.withLink
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -90,7 +93,6 @@ import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.FeatureSetType
import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.actions.mediaServers.MediaServersListView import com.vitorpamplona.amethyst.ui.actions.mediaServers.MediaServersListView
import com.vitorpamplona.amethyst.ui.components.ClickableText
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.ui.note.LoadStatuses import com.vitorpamplona.amethyst.ui.note.LoadStatuses
@@ -740,23 +742,33 @@ fun BottomContent(
.padding(horizontal = 15.dp), .padding(horizontal = 15.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
ClickableText( val string =
text = remember {
buildAnnotatedString { buildAnnotatedString {
withStyle( withLink(
SpanStyle( LinkAnnotation.Clickable(
fontSize = 12.sp, "clickable",
fontWeight = FontWeight.Bold, TextLinkStyles(
), SpanStyle(
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
),
),
) {
nav.nav(Route.Note(BuildConfig.RELEASE_NOTES_ID))
nav.closeDrawer()
},
) { ) {
append("v" + BuildConfig.VERSION_NAME + "-" + BuildConfig.FLAVOR.uppercase()) append("v12" + BuildConfig.VERSION_NAME + "-" + BuildConfig.FLAVOR.uppercase())
} }
}, }
onClick = { }
nav.nav(Route.Note(BuildConfig.RELEASE_NOTES_ID))
nav.closeDrawer() Text(
}, text = string,
modifier = Modifier.padding(start = 16.dp), modifier = Modifier.padding(start = 16.dp),
overflow = TextOverflow.Ellipsis,
maxLines = 1,
) )
Box(modifier = Modifier.weight(1F)) Box(modifier = Modifier.weight(1F))
IconButton( IconButton(
@@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.OpenInNew import androidx.compose.material.icons.filled.OpenInNew
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
@@ -390,8 +389,8 @@ fun DisplayNIP05(
NIP05VerifiedSymbol(nip05Verified, NIP05IconSize, accountViewModel) NIP05VerifiedSymbol(nip05Verified, NIP05IconSize, accountViewModel)
ClickableText( ClickableTextPrimary(
text = remember(nip05) { AnnotatedString(domain) }, text = domain,
onClick = { runCatching { uri.openUri("https://$domain") } }, onClick = { runCatching { uri.openUri("https://$domain") } },
style = style =
LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.nip05, fontSize = Font14SP), LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.nip05, fontSize = Font14SP),
@@ -441,7 +440,7 @@ fun DisplayNip05ProfileStatus(
if (user != "_") { if (user != "_") {
Text( Text(
text = remember { AnnotatedString(user + "@") }, text = "$user@",
color = MaterialTheme.colorScheme.primary, color = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(top = 1.dp, bottom = 1.dp, start = 5.dp), modifier = Modifier.padding(top = 1.dp, bottom = 1.dp, start = 5.dp),
maxLines = 1, maxLines = 1,
@@ -450,10 +449,9 @@ fun DisplayNip05ProfileStatus(
domainPadStart = 0.dp domainPadStart = 0.dp
} }
ClickableText( ClickableTextPrimary(
text = AnnotatedString(domain), text = domain,
onClick = { nip05.let { runCatching { uri.openUri("https://${it.split("@")[1]}") } } }, onClick = { nip05.let { runCatching { uri.openUri("https://${it.split("@")[1]}") } } },
style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary),
modifier = Modifier.padding(top = 1.dp, bottom = 1.dp, start = domainPadStart), modifier = Modifier.padding(top = 1.dp, bottom = 1.dp, start = domainPadStart),
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
@@ -24,13 +24,10 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.text.AnnotatedString import com.vitorpamplona.amethyst.ui.components.ClickableTextPrimary
import com.vitorpamplona.amethyst.ui.navigation.INav import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.note.UserPicture import com.vitorpamplona.amethyst.ui.note.UserPicture
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -76,11 +73,7 @@ fun DisplayZapSplits(
list.forEach { list.forEach {
when (it) { when (it) {
is ZapSplitSetupLnAddress -> is ZapSplitSetupLnAddress ->
ClickableText( ClickableTextPrimary(it.lnAddress) { }
text = AnnotatedString(it.lnAddress),
onClick = {},
style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary),
)
is ZapSplitSetup -> is ZapSplitSetup ->
UserPicture( UserPicture(
userHex = it.pubKeyHex, userHex = it.pubKeyHex,
@@ -20,16 +20,17 @@
*/ */
package com.vitorpamplona.amethyst.ui.note.elements package com.vitorpamplona.amethyst.ui.note.elements
import android.R.attr.maxLines
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.text.AnnotatedString
import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.components.buildLinkString
import com.vitorpamplona.amethyst.ui.navigation.INav import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.navigation.Route import com.vitorpamplona.amethyst.ui.navigation.Route
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -57,12 +58,13 @@ private fun DisplayCommunity(
val communityTag = val communityTag =
remember(note) { note.event?.getTagOfAddressableKind(CommunityDefinitionEvent.KIND) } ?: return remember(note) { note.event?.getTagOfAddressableKind(CommunityDefinitionEvent.KIND) } ?: return
val displayTag = remember(note) { AnnotatedString(getCommunityShortName(communityTag)) } val displayTag =
val route = remember(note) { Route.Community(communityTag.toTag()) } remember(note) {
buildLinkString(getCommunityShortName(communityTag)) { nav.nav(Route.Community(communityTag.toTag())) }
}
ClickableText( Text(
text = displayTag, text = displayTag,
onClick = { nav.nav(route) },
style = style =
LocalTextStyle.current.copy( LocalTextStyle.current.copy(
color = color =
@@ -20,12 +20,13 @@
*/ */
package com.vitorpamplona.amethyst.ui.note.elements package com.vitorpamplona.amethyst.ui.note.elements
import android.R.attr.maxLines
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -33,9 +34,10 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.style.TextOverflow
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.components.buildLinkString
import com.vitorpamplona.amethyst.ui.navigation.INav import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.navigation.Route import com.vitorpamplona.amethyst.ui.navigation.Route
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -70,19 +72,15 @@ private fun DisplayTagList(
firstTag: String, firstTag: String,
nav: INav, nav: INav,
) { ) {
val displayTag = remember(firstTag) { AnnotatedString(" #$firstTag") } Text(
val route = remember(firstTag) { Route.Hashtag(firstTag) } text =
remember(firstTag) {
ClickableText( buildLinkString(" #$firstTag") {
text = displayTag, nav.nav(Route.Hashtag(firstTag))
onClick = { nav.nav(route) }, }
style = },
LocalTextStyle.current.copy( style = LocalTextStyle.current.copy(MaterialTheme.colorScheme.primary.copy(alpha = 0.52f)),
color = overflow = TextOverflow.Ellipsis,
MaterialTheme.colorScheme.primary.copy(
alpha = 0.52f,
),
),
maxLines = 1, maxLines = 1,
) )
} }
@@ -20,12 +20,14 @@
*/ */
package com.vitorpamplona.amethyst.ui.note.elements package com.vitorpamplona.amethyst.ui.note.elements
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.withLink
import com.vitorpamplona.amethyst.ui.navigation.INav import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.navigation.Route import com.vitorpamplona.amethyst.ui.navigation.Route
import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName
@@ -37,9 +39,15 @@ fun DisplayLocation(
nav: INav, nav: INav,
) { ) {
LoadCityName(geohashStr) { cityName -> LoadCityName(geohashStr) { cityName ->
ClickableText( Text(
text = AnnotatedString(cityName), text =
onClick = { nav.nav(Route.Geohash(geohashStr)) }, buildAnnotatedString {
withLink(
LinkAnnotation.Clickable("cityname") { nav.nav(Route.Geohash(geohashStr)) },
) {
append(cityName)
}
},
style = style =
LocalTextStyle.current.copy( LocalTextStyle.current.copy(
color = color =
@@ -20,7 +20,6 @@
*/ */
package com.vitorpamplona.amethyst.ui.note.elements package com.vitorpamplona.amethyst.ui.note.elements
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -29,10 +28,10 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.components.buildLinkString
import com.vitorpamplona.amethyst.ui.note.LoadOts import com.vitorpamplona.amethyst.ui.note.LoadOts
import com.vitorpamplona.amethyst.ui.note.timeAgoNoDot import com.vitorpamplona.amethyst.ui.note.timeAgoNoDot
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -61,26 +60,15 @@ fun DisplayOts(
) )
} }
ClickableText( Text(
text = text =
buildAnnotatedString { buildLinkString(stringRes(R.string.existed_since, timeStr)) {
append( accountViewModel.toastManager.toast(
stringRes( R.string.ots_info_title,
id = R.string.existed_since, R.string.ots_info_description,
timeStr, SimpleDateFormat.getDateTimeInstance().format(Date(unixtimestamp * 1000)),
),
) )
}, },
onClick = {
val fullDateTime =
SimpleDateFormat.getDateTimeInstance().format(Date(unixtimestamp * 1000))
accountViewModel.toastManager.toast(
R.string.ots_info_title,
R.string.ots_info_description,
fullDateTime,
)
},
style = style =
LocalTextStyle.current.copy( LocalTextStyle.current.copy(
color = MaterialTheme.colorScheme.lessImportantLink, color = MaterialTheme.colorScheme.lessImportantLink,
@@ -30,9 +30,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
@@ -48,7 +46,6 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.TextFieldValue
@@ -61,6 +58,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.components.ClickableTextColor
import com.vitorpamplona.amethyst.ui.navigation.INav import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.navigation.Route import com.vitorpamplona.amethyst.ui.navigation.Route
import com.vitorpamplona.amethyst.ui.note.ZapIcon import com.vitorpamplona.amethyst.ui.note.ZapIcon
@@ -95,17 +93,12 @@ fun DisplayReward(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable { popupExpanded = true }, modifier = Modifier.clickable { popupExpanded = true },
) { ) {
ClickableText( ClickableTextColor(
text = AnnotatedString("#bounty"), "#bounty",
onClick = { nav.nav(Route.Hashtag("bounty")) }, linkColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.52f),
style = ) {
LocalTextStyle.current.copy( nav.nav(Route.Hashtag("bounty"))
color = }
MaterialTheme.colorScheme.primary.copy(
alpha = 0.52f,
),
),
)
RenderPledgeAmount(baseNote, baseReward, accountViewModel) RenderPledgeAmount(baseNote, baseReward, accountViewModel)
} }
@@ -22,16 +22,13 @@ package com.vitorpamplona.amethyst.ui.note.elements
import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.produceState import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.ui.text.AnnotatedString
import com.vitorpamplona.amethyst.commons.richtext.HashTagSegment import com.vitorpamplona.amethyst.commons.richtext.HashTagSegment
import com.vitorpamplona.amethyst.service.CachedRichTextParser import com.vitorpamplona.amethyst.service.CachedRichTextParser
import com.vitorpamplona.amethyst.ui.components.ClickableTextColor
import com.vitorpamplona.amethyst.ui.navigation.INav import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.navigation.Route import com.vitorpamplona.amethyst.ui.navigation.Route
import com.vitorpamplona.amethyst.ui.theme.HalfTopPadding import com.vitorpamplona.amethyst.ui.theme.HalfTopPadding
@@ -95,19 +92,14 @@ fun DisplayUncitedHashtags(
} }
if (unusedHashtags.isNotEmpty()) { if (unusedHashtags.isNotEmpty()) {
val style =
LocalTextStyle.current.copy(
color = MaterialTheme.colorScheme.lessImportantLink,
)
FlowRow( FlowRow(
modifier = HalfTopPadding, modifier = HalfTopPadding,
) { ) {
unusedHashtags.forEach { hashtag -> unusedHashtags.forEach { hashtag ->
ClickableText( ClickableTextColor(
text = remember { AnnotatedString("#$hashtag ") }, text = "#$hashtag ",
onClick = { nav.nav(Route.Hashtag(hashtag)) }, onClick = { nav.nav(Route.Hashtag(hashtag)) },
style = style, linkColor = MaterialTheme.colorScheme.lessImportantLink,
) )
} }
} }
@@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.note.elements
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -37,6 +36,7 @@ import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji
import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.LoadNote
import com.vitorpamplona.amethyst.ui.components.appendLink
import com.vitorpamplona.amethyst.ui.navigation.INav import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.navigation.routeFor import com.vitorpamplona.amethyst.ui.navigation.routeFor
import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote
@@ -87,13 +87,13 @@ fun ForkInformationRowLightColor(
if (route != null) { if (route != null) {
Row(modifier) { Row(modifier) {
ClickableText( Text(
text = text =
buildAnnotatedString { buildAnnotatedString {
append(stringRes(id = R.string.forked_from)) appendLink(stringRes(id = R.string.forked_from) + " ") {
append(" ") nav.nav(route)
}
}, },
onClick = { nav.nav(route) },
style = style =
LocalTextStyle.current.copy( LocalTextStyle.current.copy(
color = MaterialTheme.colorScheme.nip05, color = MaterialTheme.colorScheme.nip05,
@@ -20,6 +20,7 @@
*/ */
package com.vitorpamplona.amethyst.ui.note.elements package com.vitorpamplona.amethyst.ui.note.elements
import android.R.attr.onClick
import android.content.Context import android.content.Context
import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@@ -49,11 +50,11 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.withStyle import androidx.compose.ui.text.withLink
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@@ -65,8 +66,8 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.service.ZapPaymentHandler import com.vitorpamplona.amethyst.service.ZapPaymentHandler
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
import com.vitorpamplona.amethyst.ui.components.ClickableText
import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.LoadNote
import com.vitorpamplona.amethyst.ui.components.appendLink
import com.vitorpamplona.amethyst.ui.navigation.EmptyNav import com.vitorpamplona.amethyst.ui.navigation.EmptyNav
import com.vitorpamplona.amethyst.ui.navigation.INav import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.navigation.Route import com.vitorpamplona.amethyst.ui.navigation.Route
@@ -222,16 +223,12 @@ fun ZapTheDevsCard(
Spacer(modifier = StdVertSpacer) Spacer(modifier = StdVertSpacer)
ClickableText( Text(
text = buildAnnotatedString {
buildAnnotatedString { append(stringRes(id = R.string.zap_the_devs_description, BuildConfig.VERSION_NAME))
append(stringRes(id = R.string.zap_the_devs_description, BuildConfig.VERSION_NAME)) append(" ")
append(" ") appendLink("#value4value", MaterialTheme.colorScheme.primary) { nav.nav(Route.Hashtag("value4value")) }
withStyle(SpanStyle(color = MaterialTheme.colorScheme.primary)) { },
append("#value4value")
}
},
onClick = { nav.nav(Route.Hashtag("value4value")) },
) )
Spacer(modifier = StdVertSpacer) Spacer(modifier = StdVertSpacer)
@@ -244,15 +241,16 @@ fun ZapTheDevsCard(
} }
if (route != null) { if (route != null) {
ClickableText( Text(
text = text =
buildAnnotatedString { buildAnnotatedString {
withStyle(SpanStyle(color = MaterialTheme.colorScheme.primary)) { withLink(
LinkAnnotation.Clickable("clickable") { nav.nav(route) },
) {
append(stringRes(id = R.string.version_name, BuildConfig.VERSION_NAME.substringBefore("-"))) append(stringRes(id = R.string.version_name, BuildConfig.VERSION_NAME.substringBefore("-")))
} }
append(" " + stringRes(id = R.string.brought_to_you_by)) append(" " + stringRes(id = R.string.brought_to_you_by))
}, },
onClick = { nav.nav(route) },
) )
} else { } else {
Text(stringRes(id = R.string.this_version_brought_to_you_by)) Text(stringRes(id = R.string.this_version_brought_to_you_by))
@@ -36,8 +36,6 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -60,6 +58,7 @@ import coil3.compose.AsyncImage
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.commons.richtext.RichTextParser
import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.components.ClickableTextPrimary
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
import com.vitorpamplona.amethyst.ui.components.ZoomableImageDialog import com.vitorpamplona.amethyst.ui.components.ZoomableImageDialog
@@ -210,10 +209,9 @@ fun RenderAppDefinition(
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
LinkIcon(Size16Modifier, MaterialTheme.colorScheme.placeholderText) LinkIcon(Size16Modifier, MaterialTheme.colorScheme.placeholderText)
ClickableText( ClickableTextPrimary(
text = AnnotatedString(website.removePrefix("https://")), text = website.removePrefix("https://"),
onClick = { website.let { runCatching { uri.openUri(it) } } }, onClick = { website.let { runCatching { uri.openUri(it) } } },
style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary),
modifier = Modifier.padding(top = 1.dp, bottom = 1.dp, start = 5.dp), modifier = Modifier.padding(top = 1.dp, bottom = 1.dp, start = 5.dp),
) )
} }
@@ -26,9 +26,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -40,10 +38,10 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.AnnotatedString
import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.AddressableNote
import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.components.ClickableTextPrimary
import com.vitorpamplona.amethyst.ui.components.ClickableUrl import com.vitorpamplona.amethyst.ui.components.ClickableUrl
import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji
import com.vitorpamplona.amethyst.ui.components.DisplayEvent import com.vitorpamplona.amethyst.ui.components.DisplayEvent
@@ -253,10 +251,9 @@ fun DisplayEntryForNote(
Text("-", maxLines = 1) Text("-", maxLines = 1)
if (description != null) { if (description != null) {
ClickableText( ClickableTextPrimary(
text = AnnotatedString(description), text = description,
onClick = { routeFor(note, accountViewModel.userProfile())?.let { nav.nav(it) } }, onClick = { routeFor(note, accountViewModel.userProfile())?.let { nav.nav(it) } },
style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary),
) )
} else { } else {
DisplayEvent(noteEvent.id, noteEvent.kind, note.toNostrUri(), null, accountViewModel, nav) DisplayEvent(noteEvent.id, noteEvent.kind, note.toNostrUri(), null, accountViewModel, nav)
@@ -22,8 +22,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -33,11 +31,10 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.actions.InformationDialog import com.vitorpamplona.amethyst.ui.actions.InformationDialog
import com.vitorpamplona.amethyst.ui.components.ClickableText import com.vitorpamplona.amethyst.ui.components.ClickableTextPrimary
import com.vitorpamplona.amethyst.ui.navigation.INav import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.navigation.routeToMessage import com.vitorpamplona.amethyst.ui.navigation.routeToMessage
import com.vitorpamplona.amethyst.ui.note.ErrorMessageDialog import com.vitorpamplona.amethyst.ui.note.ErrorMessageDialog
@@ -91,10 +88,9 @@ fun DisplayLNAddress(
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
LightningAddressIcon(modifier = Size16Modifier, tint = BitcoinOrange) LightningAddressIcon(modifier = Size16Modifier, tint = BitcoinOrange)
ClickableText( ClickableTextPrimary(
text = AnnotatedString(lud16), text = lud16,
onClick = { zapExpanded = !zapExpanded }, onClick = { zapExpanded = !zapExpanded },
style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary),
modifier = modifier =
Modifier Modifier
.padding(top = 1.dp, bottom = 1.dp, start = 5.dp) .padding(top = 1.dp, bottom = 1.dp, start = 5.dp)
@@ -29,7 +29,6 @@ import androidx.compose.material.icons.filled.ContentCopy
import androidx.compose.material.icons.filled.Link import androidx.compose.material.icons.filled.Link
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -50,7 +49,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.components.ClickableText import com.vitorpamplona.amethyst.ui.components.ClickableTextPrimary
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
import com.vitorpamplona.amethyst.ui.components.DisplayNip05ProfileStatus import com.vitorpamplona.amethyst.ui.components.DisplayNip05ProfileStatus
import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
@@ -171,8 +170,8 @@ fun DrawAdditionalInfo(
modifier = Modifier.size(16.dp), modifier = Modifier.size(16.dp),
) )
ClickableText( ClickableTextPrimary(
text = AnnotatedString(website.removePrefix("https://")), text = website.removePrefix("https://"),
onClick = { onClick = {
website.let { website.let {
runCatching { runCatching {
@@ -184,7 +183,6 @@ fun DrawAdditionalInfo(
} }
} }
}, },
style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary),
modifier = Modifier.padding(top = 1.dp, bottom = 1.dp, start = 5.dp), modifier = Modifier.padding(top = 1.dp, bottom = 1.dp, start = 5.dp),
) )
} }
@@ -205,10 +203,9 @@ fun DrawAdditionalInfo(
modifier = Modifier.size(16.dp), modifier = Modifier.size(16.dp),
) )
ClickableText( ClickableTextPrimary(
text = AnnotatedString(identity.identity), text = identity.identity,
onClick = { runCatching { uri.openUri(identity.toProofUrl()) } }, onClick = { runCatching { uri.openUri(identity.toProofUrl()) } },
style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary),
modifier = modifier =
Modifier Modifier
.padding(top = 1.dp, bottom = 1.dp, start = 5.dp) .padding(top = 1.dp, bottom = 1.dp, start = 5.dp)
@@ -23,14 +23,13 @@ package com.vitorpamplona.amethyst.ui.screen.loggedOff
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.material3.Checkbox import androidx.compose.material3.Checkbox
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.components.ClickableText import com.vitorpamplona.amethyst.ui.components.appendLink
import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.stringRes
@Composable @Composable
@@ -44,32 +43,18 @@ fun AcceptTerms(
onCheckedChange = onCheckedChange, onCheckedChange = onCheckedChange,
) )
val regularText = SpanStyle(color = MaterialTheme.colorScheme.onBackground)
val clickableTextStyle = SpanStyle(color = MaterialTheme.colorScheme.primary)
val annotatedTermsString =
buildAnnotatedString {
withStyle(regularText) { append(stringRes(R.string.i_accept_the)) }
withStyle(clickableTextStyle) {
pushStringAnnotation("openTerms", "")
append(stringRes(R.string.terms_of_use))
pop()
}
}
val uri = LocalUriHandler.current val uri = LocalUriHandler.current
val primary = MaterialTheme.colorScheme.primary
ClickableText( Text(
annotatedTermsString, buildAnnotatedString {
) { spanOffset -> append(stringRes(R.string.i_accept_the))
annotatedTermsString.getStringAnnotations(spanOffset, spanOffset).firstOrNull()?.also { span -> appendLink(stringRes(R.string.terms_of_use), primary) {
if (span.tag == "openTerms") {
runCatching { runCatching {
uri.openUri("https://github.com/vitorpamplona/amethyst/blob/main/PRIVACY.md") uri.openUri("https://github.com/vitorpamplona/amethyst/blob/main/PRIVACY.md")
} }
} }
} },
} )
} }
} }
@@ -22,18 +22,17 @@ package com.vitorpamplona.amethyst.ui.screen.loggedOff
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.components.ClickableText import com.vitorpamplona.amethyst.ui.components.appendLink
import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.tor.ConnectTorDialog import com.vitorpamplona.amethyst.ui.tor.ConnectTorDialog
import com.vitorpamplona.amethyst.ui.tor.TorSettings import com.vitorpamplona.amethyst.ui.tor.TorSettings
@@ -48,20 +47,16 @@ fun TorSettingsSetup(
var connectOrbotDialogOpen by remember { mutableStateOf(false) } var connectOrbotDialogOpen by remember { mutableStateOf(false) }
var activeTor by remember { mutableStateOf(false) } var activeTor by remember { mutableStateOf(false) }
val text = val primary = MaterialTheme.colorScheme.primary
buildAnnotatedString {
append(stringRes(R.string.connect_via_tor1) + " ")
withStyle(SpanStyle(color = MaterialTheme.colorScheme.primary)) {
append(stringRes(R.string.connect_via_tor2))
}
}
ClickableText( Text(
text = text, text =
buildAnnotatedString {
append(stringRes(R.string.connect_via_tor1) + " ")
appendLink(stringRes(R.string.connect_via_tor2), primary) { connectOrbotDialogOpen = true }
},
modifier = Modifier.padding(vertical = 10.dp), modifier = Modifier.padding(vertical = 10.dp),
) { )
connectOrbotDialogOpen = true
}
if (connectOrbotDialogOpen) { if (connectOrbotDialogOpen) {
ConnectTorDialog( ConnectTorDialog(
@@ -27,7 +27,6 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Check
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
@@ -49,10 +48,8 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.os.ConfigurationCompat import androidx.core.os.ConfigurationCompat
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
@@ -178,54 +175,25 @@ private fun TranslationMessage(
Row( Row(
modifier = Modifier.fillMaxWidth().padding(top = 5.dp), modifier = Modifier.fillMaxWidth().padding(top = 5.dp),
) { ) {
val clickableTextStyle = SpanStyle(color = MaterialTheme.colorScheme.lessImportantLink) val textColor = MaterialTheme.colorScheme.lessImportantLink
val annotatedTranslationString = Text(
buildAnnotatedString { text =
withStyle(clickableTextStyle) { buildAnnotatedString {
pushStringAnnotation("langSettings", true.toString()) appendLink(stringRes(R.string.translations_auto), textColor) { langSettingsPopupExpanded = !langSettingsPopupExpanded }
append(stringRes(R.string.translations_auto)) append("-${stringRes(R.string.translations_translated_from)} ")
pop() appendLink(Locale(source).displayName, textColor) { onChangeWhatToShow(true) }
} append(" ${stringRes(R.string.translations_to)} ")
appendLink(Locale(target).displayName, textColor) { onChangeWhatToShow(false) }
append("-${stringRes(R.string.translations_translated_from)} ") },
withStyle(clickableTextStyle) {
pushStringAnnotation("showOriginal", true.toString())
append(Locale(source).displayName)
pop()
}
append(" ${stringRes(R.string.translations_to)} ")
withStyle(clickableTextStyle) {
pushStringAnnotation("showOriginal", false.toString())
append(Locale(target).displayName)
pop()
}
}
ClickableText(
text = annotatedTranslationString,
style = style =
LocalTextStyle.current.copy( LocalTextStyle.current.copy(
color = color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.32f),
MaterialTheme.colorScheme.onSurface.copy(
alpha = 0.32f,
),
fontSize = Font14SP, fontSize = Font14SP,
), ),
overflow = TextOverflow.Visible, overflow = TextOverflow.Visible,
maxLines = 3, maxLines = 3,
) { spanOffset -> )
annotatedTranslationString.getStringAnnotations(spanOffset, spanOffset).firstOrNull()?.also { span ->
if (span.tag == "showOriginal") {
onChangeWhatToShow(span.item.toBoolean())
} else {
langSettingsPopupExpanded = !langSettingsPopupExpanded
}
}
}
DropdownMenu( DropdownMenu(
expanded = langSettingsPopupExpanded, expanded = langSettingsPopupExpanded,