refactor modals

This commit is contained in:
Evgeny @ SimpleX Chat
2026-07-15 12:56:21 +00:00
parent 3f02af11d2
commit ea3f0e7c0d
3 changed files with 41 additions and 33 deletions
@@ -4872,7 +4872,11 @@ sealed class Format {
@Serializable @SerialName("simplexName") class SimplexName(val nameInfo: SimplexNameInfo): Format()
@Serializable @SerialName("command") class Command(val commandStr: String): Format()
@Serializable @SerialName("mention") class Mention(val memberName: String): Format()
@Serializable @SerialName("modal") class Modal(val modalName: String): Format()
@Serializable @SerialName("modal") class Modal(val modalName: String, val text: String): Format() {
companion object {
const val Description = "description"
}
}
@Serializable @SerialName("email") class Email: Format()
@Serializable @SerialName("phone") class Phone: Format()
@Serializable @SerialName("unknown") class Unknown: Format()
@@ -809,28 +809,10 @@ fun ProfileDescriptionText(shortDescr: String?, description: String?, style: Tex
val teaser = short ?: (if (truncated) firstLine.take(100).trimEnd() + "" else "$firstLine")
val readMore = stringResource(MR.strings.whats_new_read_more)
val formatted = (parseToMarkdown(teaser) ?: FormattedText.plain(teaser)) +
FormattedText(" ") + FormattedText(readMore, Format.Modal("description"))
FormattedText(" ") + FormattedText(readMore, Format.Modal(Format.Modal.Description, descr))
MarkdownText(
"$teaser $readMore", formatted, toggleSecrets = true, style = style, maxLines = 4,
overflow = TextOverflow.Ellipsis, uriHandler = uriHandler, modifier = modifier, linkMode = linkMode,
onModalClick = { showFullProfileDescription(descr) }
)
}
}
}
private fun showFullProfileDescription(description: String) {
ModalManager.end.showModalCloseable { _ ->
ColumnWithScrollBar {
AppBarTitle(stringResource(MR.strings.profile_description__field))
MarkdownText(
description,
parseToMarkdown(description),
toggleSecrets = true,
style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onBackground, lineHeight = 22.sp),
uriHandler = LocalUriHandler.current,
linkMode = chatModel.simplexLinkMode.value,
modifier = Modifier.padding(horizontal = DEFAULT_PADDING).padding(bottom = DEFAULT_PADDING),
overflow = TextOverflow.Ellipsis, uriHandler = uriHandler, modifier = modifier, linkMode = linkMode
)
}
}
@@ -3,6 +3,7 @@ package chat.simplex.common.views.chat.item
import SectionItemView
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.BasicText
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.material.MaterialTheme
@@ -23,6 +24,7 @@ import androidx.compose.ui.unit.sp
import chat.simplex.common.model.*
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.CurrentColors
import chat.simplex.common.ui.theme.DEFAULT_PADDING
import chat.simplex.common.views.chat.SelectionHighlightColor
import chat.simplex.common.views.helpers.*
import chat.simplex.res.*
@@ -39,6 +41,29 @@ fun appendSender(b: AnnotatedString.Builder, sender: String?, senderBold: Boolea
}
}
private fun openMarkdownModal(modal: Format.Modal) {
when (modal.modalName) {
Format.Modal.Description -> showFullProfileDescription(modal.text)
}
}
private fun showFullProfileDescription(description: String) {
ModalManager.end.showModalCloseable { _ ->
ColumnWithScrollBar {
AppBarTitle(generalGetString(MR.strings.profile_description__field))
MarkdownText(
description,
parseToMarkdown(description),
toggleSecrets = true,
style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onBackground, lineHeight = 22.sp),
uriHandler = LocalUriHandler.current,
linkMode = chatModel.simplexLinkMode.value,
modifier = Modifier.padding(horizontal = DEFAULT_PADDING).padding(bottom = DEFAULT_PADDING),
)
}
}
}
private val noTyping: AnnotatedString = AnnotatedString(" ")
private val typingIndicators: List<AnnotatedString> = listOf(
@@ -113,7 +138,6 @@ fun MarkdownText (
linkMode: SimplexLinkMode,
inlineContent: Pair<AnnotatedString.Builder.() -> Unit, Map<String, InlineTextContent>>? = null,
onLinkLongClick: (link: String) -> Unit = {},
onModalClick: ((modalName: String) -> Unit)? = null,
showViaProxy: Boolean = false,
showTimestamp: Boolean = true,
prefix: AnnotatedString? = null,
@@ -305,14 +329,10 @@ fun MarkdownText (
}
}
is Format.Modal -> {
if (onModalClick == null) {
append(ft.text)
} else {
hasModals = true
val ftStyle = Format.linkStyle
withAnnotation(tag = "MODAL", annotation = ft.format.modalName) {
withStyle(ftStyle) { append(ft.text) }
}
hasModals = true
val ftStyle = Format.linkStyle
withAnnotation(tag = "MODAL", annotation = i.toString()) {
withStyle(ftStyle) { append(ft.text) }
}
}
is Format.Unknown -> append(ft.text)
@@ -328,7 +348,7 @@ fun MarkdownText (
else */if (meta != null) withStyle(reserveTimestampStyle) { append(reserve) }
}
val clampedRange = selectionRange?.let { it.first .. minOf(it.last, selectableEnd) }
if ((hasLinks && uriHandler != null) || hasSecrets || (hasCommands && sendCommandMsg != null) || (hasModals && onModalClick != null)) {
if ((hasLinks && uriHandler != null) || hasSecrets || (hasCommands && sendCommandMsg != null) || hasModals) {
val icon = remember { mutableStateOf(PointerIcon.Text) }
ClickableText(annotatedText, style = style, selectionRange = clampedRange, modifier = modifier.pointerHoverIcon(icon.value), maxLines = maxLines, overflow = overflow,
onLongClick = { offset ->
@@ -366,8 +386,10 @@ fun MarkdownText (
if (hasCommands && sendCommandMsg != null) {
withAnnotation("COMMAND") { a -> sendCommandMsg("/${a.item}") }
}
if (hasModals && onModalClick != null) {
withAnnotation("MODAL") { a -> onModalClick(a.item) }
if (hasModals) {
withAnnotation("MODAL") { a ->
(a.item.toIntOrNull()?.let { formattedText.getOrNull(it)?.format } as? Format.Modal)?.let { openMarkdownModal(it) }
}
}
},
onHover = { offset ->