mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-09-16 23:24:58 +00:00
ui: show secrets on tap (#3628)
* ios: show secrets on tap * android: show secrets on tap/click * android: clickable links in group descriptions * android: hide secrets one by one * ios: clickable links in welcome message preview * refactor * refactor2
This commit is contained in:
+1
@@ -53,6 +53,7 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d
|
||||
text, if (text.isEmpty()) emptyList() else formattedText,
|
||||
sender = sender,
|
||||
senderBold = true,
|
||||
toggleSecrets = true,
|
||||
linkMode = SimplexLinkMode.DESCRIPTION, uriHandler = uriHandler,
|
||||
onLinkLongClick = { showMenu.value = true }
|
||||
)
|
||||
|
||||
+1
@@ -34,6 +34,7 @@ fun ContextItemView(
|
||||
fun msgContentView(lines: Int) {
|
||||
MarkdownText(
|
||||
contextItem.text, contextItem.formattedText,
|
||||
toggleSecrets = false,
|
||||
maxLines = lines,
|
||||
linkMode = SimplexLinkMode.DESCRIPTION,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
|
||||
+4
-1
@@ -15,6 +15,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
@@ -119,13 +120,15 @@ private fun GroupWelcomeLayout(
|
||||
|
||||
@Composable
|
||||
private fun TextPreview(text: String, linkMode: SimplexLinkMode, markdown: Boolean = true) {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
Column {
|
||||
SelectionContainer(Modifier.fillMaxWidth()) {
|
||||
MarkdownText(
|
||||
text,
|
||||
formattedText = if (markdown) remember(text) { parseToMarkdown(text) } else null,
|
||||
toggleSecrets = false,
|
||||
modifier = Modifier.fillMaxHeight().padding(horizontal = DEFAULT_PADDING),
|
||||
linkMode = linkMode,
|
||||
linkMode = linkMode, uriHandler = uriHandler,
|
||||
style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onBackground, lineHeight = 22.sp)
|
||||
)
|
||||
}
|
||||
|
||||
+2
-1
@@ -54,6 +54,7 @@ fun FramedItemView(
|
||||
MarkdownText(
|
||||
qi.text,
|
||||
qi.formattedText,
|
||||
toggleSecrets = true,
|
||||
maxLines = lines,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = TextStyle(fontSize = 15.sp, color = MaterialTheme.colors.onSurface),
|
||||
@@ -288,7 +289,7 @@ fun CIMarkdownText(
|
||||
Box(Modifier.padding(vertical = 6.dp, horizontal = 12.dp)) {
|
||||
val text = if (ci.meta.isLive) ci.content.msgContent?.text ?: ci.text else ci.text
|
||||
MarkdownText(
|
||||
text, if (text.isEmpty()) emptyList() else ci.formattedText,
|
||||
text, if (text.isEmpty()) emptyList() else ci.formattedText, toggleSecrets = true,
|
||||
meta = ci.meta, chatTTL = chatTTL, linkMode = linkMode,
|
||||
uriHandler = uriHandler, senderBold = true, onLinkLongClick = onLinkLongClick
|
||||
)
|
||||
|
||||
+22
-5
@@ -60,6 +60,7 @@ fun MarkdownText (
|
||||
sender: String? = null,
|
||||
meta: CIMeta? = null,
|
||||
chatTTL: Int? = null,
|
||||
toggleSecrets: Boolean,
|
||||
style: TextStyle = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onSurface, lineHeight = 22.sp),
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
overflow: TextOverflow = TextOverflow.Clip,
|
||||
@@ -89,6 +90,7 @@ fun MarkdownText (
|
||||
) {
|
||||
var timer: Job? by remember { mutableStateOf(null) }
|
||||
var typingIdx by rememberSaveable { mutableStateOf(0) }
|
||||
val showSecrets = remember { mutableStateMapOf<String, Boolean>() }
|
||||
fun stopTyping() {
|
||||
timer?.cancel()
|
||||
timer = null
|
||||
@@ -127,15 +129,22 @@ fun MarkdownText (
|
||||
}
|
||||
Text(annotatedText, style = style, modifier = modifier, maxLines = maxLines, overflow = overflow, inlineContent = inlineContent ?: mapOf())
|
||||
} else {
|
||||
var hasLinks = false
|
||||
var hasAnnotations = false
|
||||
val annotatedText = buildAnnotatedString {
|
||||
appendSender(this, sender, senderBold)
|
||||
for (ft in formattedText) {
|
||||
for ((i, ft) in formattedText.withIndex()) {
|
||||
if (ft.format == null) append(ft.text)
|
||||
else {
|
||||
else if (toggleSecrets && ft.format is Format.Secret) {
|
||||
val ftStyle = ft.format.style
|
||||
hasAnnotations = true
|
||||
val key = i.toString()
|
||||
withAnnotation(tag = "SECRET", annotation = key) {
|
||||
if (showSecrets[key] == true) append(ft.text) else withStyle(ftStyle) { append(ft.text) }
|
||||
}
|
||||
} else {
|
||||
val link = ft.link(linkMode)
|
||||
if (link != null) {
|
||||
hasLinks = true
|
||||
hasAnnotations = true
|
||||
val ftStyle = ft.format.style
|
||||
withAnnotation(tag = if (ft.format is Format.SimplexLink) "SIMPLEX_URL" else "URL", annotation = link) {
|
||||
withStyle(ftStyle) { append(ft.viewText(linkMode)) }
|
||||
@@ -153,7 +162,7 @@ fun MarkdownText (
|
||||
withStyle(reserveTimestampStyle) { append("\n" + metaText) }
|
||||
else */if (meta != null) withStyle(reserveTimestampStyle) { append(reserve) }
|
||||
}
|
||||
if (hasLinks && uriHandler != null) {
|
||||
if (hasAnnotations && uriHandler != null) {
|
||||
val icon = remember { mutableStateOf(PointerIcon.Default) }
|
||||
ClickableText(annotatedText, style = style, modifier = modifier.pointerHoverIcon(icon.value), maxLines = maxLines, overflow = overflow,
|
||||
onLongClick = { offset ->
|
||||
@@ -177,12 +186,20 @@ fun MarkdownText (
|
||||
.firstOrNull()?.let { annotation ->
|
||||
uriHandler.openVerifiedSimplexUri(annotation.item)
|
||||
}
|
||||
annotatedText.getStringAnnotations(tag = "SECRET", start = offset, end = offset)
|
||||
.firstOrNull()?.let { annotation ->
|
||||
val key = annotation.item
|
||||
showSecrets[key] = !(showSecrets[key] ?: false)
|
||||
}
|
||||
},
|
||||
onHover = { offset ->
|
||||
icon.value = annotatedText.getStringAnnotations(tag = "URL", start = offset, end = offset)
|
||||
.firstOrNull()?.let {
|
||||
PointerIcon.Hand
|
||||
} ?: annotatedText.getStringAnnotations(tag = "SIMPLEX_URL", start = offset, end = offset)
|
||||
.firstOrNull()?.let {
|
||||
PointerIcon.Hand
|
||||
} ?: annotatedText.getStringAnnotations(tag = "SECRET", start = offset, end = offset)
|
||||
.firstOrNull()?.let {
|
||||
PointerIcon.Hand
|
||||
} ?: PointerIcon.Default
|
||||
|
||||
+1
@@ -173,6 +173,7 @@ fun ChatPreviewView(
|
||||
cInfo is ChatInfo.Group && !ci.chatDir.sent -> ci.memberDisplayName
|
||||
else -> null
|
||||
},
|
||||
toggleSecrets = false,
|
||||
linkMode = linkMode,
|
||||
senderBold = true,
|
||||
maxLines = 2,
|
||||
|
||||
-11
@@ -78,17 +78,6 @@ fun ReadableText(text: String, textAlign: TextAlign = TextAlign.Start, padding:
|
||||
Text(text, modifier = Modifier.padding(padding), textAlign = textAlign, lineHeight = 22.sp)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ReadableMarkdownText(text: String, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp)) {
|
||||
MarkdownText(
|
||||
text,
|
||||
formattedText = remember(text) { parseToMarkdown(text) },
|
||||
modifier = Modifier.padding(padding),
|
||||
style = TextStyle(textAlign = textAlign, lineHeight = 22.sp, fontSize = 16.sp),
|
||||
linkMode = ChatController.appPrefs.simplexLinkMode.get(),
|
||||
)
|
||||
}
|
||||
|
||||
@Preview/*(
|
||||
uiMode = Configuration.UI_MODE_NIGHT_YES,
|
||||
showBackground = true,
|
||||
|
||||
Reference in New Issue
Block a user