Fixes misalignment of Clickable Texts
This commit is contained in:
@@ -24,7 +24,6 @@ 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.BasicText
|
import androidx.compose.foundation.text.BasicText
|
||||||
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
|
||||||
@@ -298,27 +297,24 @@ fun CreateClickableText(
|
|||||||
suffix: String?,
|
suffix: String?,
|
||||||
maxLines: Int = Int.MAX_VALUE,
|
maxLines: Int = Int.MAX_VALUE,
|
||||||
overrideColor: Color? = null,
|
overrideColor: Color? = null,
|
||||||
fontWeight: FontWeight = FontWeight.Normal,
|
fontWeight: FontWeight? = null,
|
||||||
route: String,
|
route: String,
|
||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
val currentStyle = LocalTextStyle.current
|
|
||||||
val primaryColor = MaterialTheme.colorScheme.primary
|
val primaryColor = MaterialTheme.colorScheme.primary
|
||||||
val onBackgroundColor = MaterialTheme.colorScheme.onBackground
|
val onBackgroundColor = MaterialTheme.colorScheme.onBackground
|
||||||
|
|
||||||
val clickablePartStyle =
|
val clickablePartStyle =
|
||||||
remember(primaryColor, overrideColor) {
|
SpanStyle(
|
||||||
currentStyle
|
color = overrideColor ?: primaryColor,
|
||||||
.copy(color = overrideColor ?: primaryColor, fontWeight = fontWeight)
|
fontWeight = fontWeight,
|
||||||
.toSpanStyle()
|
)
|
||||||
}
|
|
||||||
|
|
||||||
val nonClickablePartStyle =
|
val nonClickablePartStyle =
|
||||||
remember(onBackgroundColor, overrideColor) {
|
SpanStyle(
|
||||||
currentStyle
|
color = overrideColor ?: onBackgroundColor,
|
||||||
.copy(color = overrideColor ?: onBackgroundColor, fontWeight = fontWeight)
|
fontWeight = fontWeight,
|
||||||
.toSpanStyle()
|
)
|
||||||
}
|
|
||||||
|
|
||||||
val text =
|
val text =
|
||||||
remember(clickablePartStyle, nonClickablePartStyle, clickablePart, suffix) {
|
remember(clickablePartStyle, nonClickablePartStyle, clickablePart, suffix) {
|
||||||
@@ -333,11 +329,45 @@ fun CreateClickableText(
|
|||||||
ClickableText(
|
ClickableText(
|
||||||
text = text,
|
text = text,
|
||||||
maxLines = maxLines,
|
maxLines = maxLines,
|
||||||
style = currentStyle,
|
|
||||||
onClick = { nav(route) },
|
onClick = { nav(route) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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,
|
||||||
|
modifier = modifier.then(pressIndicator),
|
||||||
|
style = style,
|
||||||
|
softWrap = softWrap,
|
||||||
|
overflow = overflow,
|
||||||
|
maxLines = maxLines,
|
||||||
|
onTextLayout = {
|
||||||
|
layoutResult.value = it
|
||||||
|
onTextLayout(it)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CreateTextWithEmoji(
|
fun CreateTextWithEmoji(
|
||||||
text: String,
|
text: String,
|
||||||
|
|||||||
@@ -28,11 +28,10 @@ import androidx.compose.foundation.layout.Column
|
|||||||
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.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.text.BasicText
|
import androidx.compose.foundation.layout.padding
|
||||||
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.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.LocalContentColor
|
|
||||||
import androidx.compose.material3.LocalTextStyle
|
import androidx.compose.material3.LocalTextStyle
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.ProvideTextStyle
|
import androidx.compose.material3.ProvideTextStyle
|
||||||
@@ -49,7 +48,6 @@ 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.graphics.takeOrElse
|
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.platform.LocalFontFamilyResolver
|
import androidx.compose.ui.platform.LocalFontFamilyResolver
|
||||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
@@ -62,8 +60,10 @@ import androidx.compose.ui.text.TextMeasurer
|
|||||||
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.withStyle
|
import androidx.compose.ui.text.withStyle
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.em
|
import androidx.compose.ui.unit.em
|
||||||
import com.halilibo.richtext.markdown.Markdown
|
import com.halilibo.richtext.markdown.Markdown
|
||||||
import com.halilibo.richtext.markdown.MarkdownParseOptions
|
import com.halilibo.richtext.markdown.MarkdownParseOptions
|
||||||
@@ -174,7 +174,73 @@ fun RichTextViewer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
@Preview()
|
||||||
|
@Composable
|
||||||
|
fun RenderRegularPreview() {
|
||||||
|
val backgroundColor = MaterialTheme.colorScheme.background
|
||||||
|
val backgroundColorState =
|
||||||
|
remember {
|
||||||
|
mutableStateOf(backgroundColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
val nav: (String) -> Unit = {}
|
||||||
|
|
||||||
|
Column(modifier = Modifier.padding(10.dp)) {
|
||||||
|
RenderRegular(
|
||||||
|
"nostr:npub1e0z776cpe0gllgktjk54fuzv8pdfxmq6smsmh8xd7t8s7n474n9smk0txy but i'm Monthly funding" +
|
||||||
|
" 7 other humans vitor@vitorpamplona.com at the moment so spread #test a bit thin, but won't always be the case.",
|
||||||
|
EmptyTagList,
|
||||||
|
) { word, state ->
|
||||||
|
when (word) {
|
||||||
|
// is ImageSegment -> ZoomableContentView(word.segmentText, state, accountViewModel)
|
||||||
|
// is LinkSegment -> LoadUrlPreview(word.segmentText, word.segmentText, accountViewModel)
|
||||||
|
is EmojiSegment -> RenderCustomEmoji(word.segmentText, state)
|
||||||
|
is InvoiceSegment -> MayBeInvoicePreview(word.segmentText)
|
||||||
|
is WithdrawSegment -> MayBeWithdrawal(word.segmentText)
|
||||||
|
// is CashuSegment -> CashuPreview(word.segmentText, accountViewModel)
|
||||||
|
is EmailSegment -> ClickableEmail(word.segmentText)
|
||||||
|
is PhoneSegment -> ClickablePhone(word.segmentText)
|
||||||
|
is BechSegment -> {
|
||||||
|
CreateClickableText(
|
||||||
|
word.segmentText.substring(0, 10),
|
||||||
|
"",
|
||||||
|
1,
|
||||||
|
route = "",
|
||||||
|
nav = nav,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
is HashTagSegment -> HashTag(word, nav)
|
||||||
|
// is HashIndexUserSegment -> TagLink(word, accountViewModel, nav)
|
||||||
|
// is HashIndexEventSegment -> TagLink(word, true, backgroundColorState, accountViewModel, nav)
|
||||||
|
is SchemelessUrlSegment -> NoProtocolUrlRenderer(word)
|
||||||
|
is RegularTextSegment -> Text(word.segmentText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderRegular(
|
||||||
|
"#Amethyst v0.84.1: ncryptsec support (NIP-49)",
|
||||||
|
EmptyTagList,
|
||||||
|
) { word, state ->
|
||||||
|
when (word) {
|
||||||
|
// is ImageSegment -> ZoomableContentView(word.segmentText, state, accountViewModel)
|
||||||
|
// is LinkSegment -> LoadUrlPreview(word.segmentText, word.segmentText, accountViewModel)
|
||||||
|
is EmojiSegment -> RenderCustomEmoji(word.segmentText, state)
|
||||||
|
is InvoiceSegment -> MayBeInvoicePreview(word.segmentText)
|
||||||
|
is WithdrawSegment -> MayBeWithdrawal(word.segmentText)
|
||||||
|
// is CashuSegment -> CashuPreview(word.segmentText, accountViewModel)
|
||||||
|
is EmailSegment -> ClickableEmail(word.segmentText)
|
||||||
|
is PhoneSegment -> ClickablePhone(word.segmentText)
|
||||||
|
// is BechSegment -> BechLink(word.segmentText, true, backgroundColor, accountViewModel, nav)
|
||||||
|
is HashTagSegment -> HashTag(word, nav)
|
||||||
|
// is HashIndexUserSegment -> TagLink(word, accountViewModel, nav)
|
||||||
|
// is HashIndexEventSegment -> TagLink(word, true, backgroundColorState, accountViewModel, nav)
|
||||||
|
is SchemelessUrlSegment -> NoProtocolUrlRenderer(word)
|
||||||
|
is RegularTextSegment -> Text(word.segmentText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun RenderRegular(
|
private fun RenderRegular(
|
||||||
content: String,
|
content: String,
|
||||||
@@ -184,76 +250,66 @@ private fun RenderRegular(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
val state by remember(content, tags) { mutableStateOf(CachedRichTextParser.parseText(content, tags)) }
|
RenderRegular(content, tags) { word, state ->
|
||||||
|
|
||||||
val currentTextStyle = LocalTextStyle.current
|
|
||||||
val currentTextColor = LocalContentColor.current
|
|
||||||
|
|
||||||
val textStyle =
|
|
||||||
remember(currentTextStyle, currentTextColor) {
|
|
||||||
currentTextStyle.copy(
|
|
||||||
lineHeight = 1.4.em,
|
|
||||||
color = currentTextStyle.color.takeOrElse { currentTextColor },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val spaceWidth = measureSpaceWidth(textStyle)
|
|
||||||
|
|
||||||
Column {
|
|
||||||
if (canPreview) {
|
if (canPreview) {
|
||||||
// FlowRow doesn't work well with paragraphs. So we need to split them
|
|
||||||
state.paragraphs.forEach { paragraph ->
|
|
||||||
val direction =
|
|
||||||
if (paragraph.isRTL) {
|
|
||||||
LayoutDirection.Rtl
|
|
||||||
} else {
|
|
||||||
LayoutDirection.Ltr
|
|
||||||
}
|
|
||||||
|
|
||||||
CompositionLocalProvider(LocalLayoutDirection provides direction) {
|
|
||||||
FlowRow(
|
|
||||||
modifier = Modifier.align(if (paragraph.isRTL) Alignment.End else Alignment.Start),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(spaceWidth),
|
|
||||||
) {
|
|
||||||
paragraph.words.forEach { word ->
|
|
||||||
RenderWordWithPreview(
|
RenderWordWithPreview(
|
||||||
word,
|
word,
|
||||||
state,
|
state,
|
||||||
backgroundColor,
|
backgroundColor,
|
||||||
textStyle,
|
|
||||||
accountViewModel,
|
accountViewModel,
|
||||||
nav,
|
nav,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// FlowRow doesn't work well with paragraphs. So we need to split them
|
|
||||||
state.paragraphs.forEach { paragraph ->
|
|
||||||
val direction =
|
|
||||||
if (paragraph.isRTL) {
|
|
||||||
LayoutDirection.Rtl
|
|
||||||
} else {
|
|
||||||
LayoutDirection.Ltr
|
|
||||||
}
|
|
||||||
|
|
||||||
CompositionLocalProvider(LocalLayoutDirection provides direction) {
|
|
||||||
FlowRow(
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(spaceWidth),
|
|
||||||
modifier = Modifier.align(if (paragraph.isRTL) Alignment.End else Alignment.Start),
|
|
||||||
) {
|
|
||||||
paragraph.words.forEach { word ->
|
|
||||||
RenderWordWithoutPreview(
|
RenderWordWithoutPreview(
|
||||||
word,
|
word,
|
||||||
state,
|
state,
|
||||||
backgroundColor,
|
backgroundColor,
|
||||||
textStyle,
|
|
||||||
accountViewModel,
|
accountViewModel,
|
||||||
nav,
|
nav,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
|
@Composable
|
||||||
|
private fun RenderRegular(
|
||||||
|
content: String,
|
||||||
|
tags: ImmutableListOfLists<String>,
|
||||||
|
wordRenderer: @Composable (Segment, RichTextViewerState) -> Unit,
|
||||||
|
) {
|
||||||
|
val state by remember(content, tags) { mutableStateOf(CachedRichTextParser.parseText(content, tags)) }
|
||||||
|
|
||||||
|
val spaceWidth = measureSpaceWidth(LocalTextStyle.current)
|
||||||
|
|
||||||
|
val currentTextStyle = LocalTextStyle.current
|
||||||
|
|
||||||
|
val textStyle =
|
||||||
|
remember(currentTextStyle) {
|
||||||
|
currentTextStyle.copy(
|
||||||
|
lineHeight = 1.4.em,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
// FlowRow doesn't work well with paragraphs. So we need to split them
|
||||||
|
state.paragraphs.forEach { paragraph ->
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalLayoutDirection provides
|
||||||
|
if (paragraph.isRTL) {
|
||||||
|
LayoutDirection.Rtl
|
||||||
|
} else {
|
||||||
|
LayoutDirection.Ltr
|
||||||
|
},
|
||||||
|
LocalTextStyle provides textStyle,
|
||||||
|
) {
|
||||||
|
FlowRow(
|
||||||
|
modifier = Modifier.align(if (paragraph.isRTL) Alignment.End else Alignment.Start),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(spaceWidth),
|
||||||
|
) {
|
||||||
|
paragraph.words.forEach { word ->
|
||||||
|
wordRenderer(word, state)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,7 +337,6 @@ private fun RenderWordWithoutPreview(
|
|||||||
word: Segment,
|
word: Segment,
|
||||||
state: RichTextViewerState,
|
state: RichTextViewerState,
|
||||||
backgroundColor: MutableState<Color>,
|
backgroundColor: MutableState<Color>,
|
||||||
style: TextStyle,
|
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
@@ -291,10 +346,10 @@ private fun RenderWordWithoutPreview(
|
|||||||
is LinkSegment -> ClickableUrl(word.segmentText, word.segmentText)
|
is LinkSegment -> ClickableUrl(word.segmentText, word.segmentText)
|
||||||
is EmojiSegment -> RenderCustomEmoji(word.segmentText, state)
|
is EmojiSegment -> RenderCustomEmoji(word.segmentText, state)
|
||||||
// Don't offer to pay invoices
|
// Don't offer to pay invoices
|
||||||
is InvoiceSegment -> NormalWord(word.segmentText, style)
|
is InvoiceSegment -> Text(word.segmentText)
|
||||||
// Don't offer to withdraw
|
// Don't offer to withdraw
|
||||||
is WithdrawSegment -> NormalWord(word.segmentText, style)
|
is WithdrawSegment -> Text(word.segmentText)
|
||||||
is CashuSegment -> NormalWord(word.segmentText, style)
|
is CashuSegment -> Text(word.segmentText)
|
||||||
is EmailSegment -> ClickableEmail(word.segmentText)
|
is EmailSegment -> ClickableEmail(word.segmentText)
|
||||||
is PhoneSegment -> ClickablePhone(word.segmentText)
|
is PhoneSegment -> ClickablePhone(word.segmentText)
|
||||||
is BechSegment -> BechLink(word.segmentText, false, backgroundColor, accountViewModel, nav)
|
is BechSegment -> BechLink(word.segmentText, false, backgroundColor, accountViewModel, nav)
|
||||||
@@ -302,7 +357,7 @@ private fun RenderWordWithoutPreview(
|
|||||||
is HashIndexUserSegment -> TagLink(word, accountViewModel, nav)
|
is HashIndexUserSegment -> TagLink(word, accountViewModel, nav)
|
||||||
is HashIndexEventSegment -> TagLink(word, false, backgroundColor, accountViewModel, nav)
|
is HashIndexEventSegment -> TagLink(word, false, backgroundColor, accountViewModel, nav)
|
||||||
is SchemelessUrlSegment -> NoProtocolUrlRenderer(word)
|
is SchemelessUrlSegment -> NoProtocolUrlRenderer(word)
|
||||||
is RegularTextSegment -> NormalWord(word.segmentText, style)
|
is RegularTextSegment -> Text(word.segmentText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,7 +366,6 @@ private fun RenderWordWithPreview(
|
|||||||
word: Segment,
|
word: Segment,
|
||||||
state: RichTextViewerState,
|
state: RichTextViewerState,
|
||||||
backgroundColor: MutableState<Color>,
|
backgroundColor: MutableState<Color>,
|
||||||
style: TextStyle,
|
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
@@ -329,7 +383,7 @@ private fun RenderWordWithPreview(
|
|||||||
is HashIndexUserSegment -> TagLink(word, accountViewModel, nav)
|
is HashIndexUserSegment -> TagLink(word, accountViewModel, nav)
|
||||||
is HashIndexEventSegment -> TagLink(word, true, backgroundColor, accountViewModel, nav)
|
is HashIndexEventSegment -> TagLink(word, true, backgroundColor, accountViewModel, nav)
|
||||||
is SchemelessUrlSegment -> NoProtocolUrlRenderer(word)
|
is SchemelessUrlSegment -> NoProtocolUrlRenderer(word)
|
||||||
is RegularTextSegment -> NormalWord(word.segmentText, style)
|
is RegularTextSegment -> Text(word.segmentText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,23 +401,7 @@ private fun ZoomableContentView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun NormalWord(
|
private fun NoProtocolUrlRenderer(segment: SchemelessUrlSegment) {
|
||||||
word: String,
|
|
||||||
style: TextStyle,
|
|
||||||
) {
|
|
||||||
BasicText(
|
|
||||||
text = word,
|
|
||||||
style = style,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun NoProtocolUrlRenderer(word: SchemelessUrlSegment) {
|
|
||||||
RenderUrl(word)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun RenderUrl(segment: SchemelessUrlSegment) {
|
|
||||||
ClickableUrl(segment.url, "https://${segment.url}")
|
ClickableUrl(segment.url, "https://${segment.url}")
|
||||||
segment.extras?.let { it1 -> Text(it1) }
|
segment.extras?.let { it1 -> Text(it1) }
|
||||||
}
|
}
|
||||||
@@ -649,7 +687,7 @@ fun HashTag(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
segment.extras?.ifBlank { "" }?.let { withStyle(regularText) { append(it) } }
|
segment.extras?.let { withStyle(regularText) { append(it) } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user