Added Double tap to edit

This commit is contained in:
RiyasDev72 2025-05-26 19:36:36 +05:30
parent c81d114d9a
commit aac670e323

View file

@ -1,10 +1,5 @@
package chat.simplex.common.views.chat.item package chat.simplex.common.views.chat.item
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.util.Log
import android.widget.Toast
import androidx.compose.foundation.text.BasicText import androidx.compose.foundation.text.BasicText
import androidx.compose.foundation.text.InlineTextContent import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
@ -47,6 +42,7 @@ private val typingIndicators: List<AnnotatedString> = listOf(
typing() + typing() + typing(FontWeight.Bold) typing() + typing() + typing(FontWeight.Bold)
) )
private fun typingIndicator(recent: Boolean, typingIdx: Int): AnnotatedString = buildAnnotatedString { private fun typingIndicator(recent: Boolean, typingIdx: Int): AnnotatedString = buildAnnotatedString {
pushStyle(SpanStyle(color = CurrentColors.value.colors.secondary, fontFamily = FontFamily.Monospace, letterSpacing = (-1).sp)) pushStyle(SpanStyle(color = CurrentColors.value.colors.secondary, fontFamily = FontFamily.Monospace, letterSpacing = (-1).sp))
append(if (recent) typingIndicators[typingIdx] else noTyping) append(if (recent) typingIndicators[typingIdx] else noTyping)
@ -188,20 +184,14 @@ fun MarkdownText (
if (meta?.isLive == true) { if (meta?.isLive == true) {
append(typingIndicator(meta.recent, typingIdx)) append(typingIndicator(meta.recent, typingIdx))
} }
if (meta != null) withStyle(reserveTimestampStyle) { append(reserve) } // With RTL language set globally links looks bad sometimes, better to add a new line to bo sure everything looks good
/*if (metaText != null && hasLinks && LocalLayoutDirection.current == LayoutDirection.Rtl)
withStyle(reserveTimestampStyle) { append("\n" + metaText) }
else */if (meta != null) withStyle(reserveTimestampStyle) { append(reserve) }
} }
if (hasAnnotations && uriHandler != null) { if (hasAnnotations && uriHandler != null) {
val icon = remember { mutableStateOf(PointerIcon.Default) } val icon = remember { mutableStateOf(PointerIcon.Default) }
val clipboardManager = LocalClipboardManager.current ClickableText(annotatedText, style = style, modifier = modifier.pointerHoverIcon(icon.value), maxLines = maxLines, overflow = overflow,
val context = LocalContext.current
ClickableText(
annotatedText,
style = style,
modifier = modifier.pointerHoverIcon(icon.value),
maxLines = maxLines,
overflow = overflow,
onLongClick = { offset -> onLongClick = { offset ->
annotatedText.getStringAnnotations(tag = "URL", start = offset, end = offset) annotatedText.getStringAnnotations(tag = "URL", start = offset, end = offset)
.firstOrNull()?.let { annotation -> onLinkLongClick(annotation.item) } .firstOrNull()?.let { annotation -> onLinkLongClick(annotation.item) }
@ -214,7 +204,9 @@ fun MarkdownText (
try { try {
uriHandler.openUri(annotation.item) uriHandler.openUri(annotation.item)
} catch (e: Exception) { } catch (e: Exception) {
Log.e("MarkdownText", "Open url: ${e.stackTraceToString()}") // It can happen, for example, when you click on a text 0.00001 but don't have any app that can catch
// `tel:` scheme in url installed on a device (no phone app or contacts, maybe)
Log.e(TAG, "Open url: ${e.stackTraceToString()}")
} }
} }
annotatedText.getStringAnnotations(tag = "SIMPLEX_URL", start = offset, end = offset) annotatedText.getStringAnnotations(tag = "SIMPLEX_URL", start = offset, end = offset)
@ -227,29 +219,21 @@ fun MarkdownText (
showSecrets[key] = !(showSecrets[key] ?: false) showSecrets[key] = !(showSecrets[key] ?: false)
} }
}, },
onDoubleTap = { offset ->
annotatedText.getStringAnnotations(tag = "SECRET", start = offset, end = offset)
.firstOrNull()?.let { annotation ->
val key = annotation.item
// Copy the secret text to clipboard
val secretText = annotatedText.text
clipboardManager.setText(AnnotatedString(secretText))
Toast.makeText(context, "Secret text copied to clipboard", Toast.LENGTH_SHORT).show()
Log.d("MarkdownText", "Secret text copied on double tap (key=$key)")
}
},
onHover = { offset -> onHover = { offset ->
icon.value = annotatedText.getStringAnnotations(tag = "URL", start = offset, end = offset) icon.value = annotatedText.getStringAnnotations(tag = "URL", start = offset, end = offset)
.firstOrNull()?.let { PointerIcon.Hand } .firstOrNull()?.let {
?: annotatedText.getStringAnnotations(tag = "SIMPLEX_URL", start = offset, end = offset) PointerIcon.Hand
.firstOrNull()?.let { PointerIcon.Hand } } ?: annotatedText.getStringAnnotations(tag = "SIMPLEX_URL", start = offset, end = offset)
?: annotatedText.getStringAnnotations(tag = "SECRET", start = offset, end = offset) .firstOrNull()?.let {
.firstOrNull()?.let { PointerIcon.Hand } PointerIcon.Hand
?: PointerIcon.Default } ?: annotatedText.getStringAnnotations(tag = "SECRET", start = offset, end = offset)
.firstOrNull()?.let {
PointerIcon.Hand
} ?: PointerIcon.Default
}, },
shouldConsumeEvent = { offset -> shouldConsumeEvent = { offset ->
annotatedText.getStringAnnotations(tag = "URL", start = offset, end = offset).any() || annotatedText.getStringAnnotations(tag = "URL", start = offset, end = offset).any()
annotatedText.getStringAnnotations(tag = "SIMPLEX_URL", start = offset, end = offset).any() annotatedText.getStringAnnotations(tag = "SIMPLEX_URL", start = offset, end = offset).any()
} }
) )
} else { } else {
@ -270,39 +254,39 @@ fun ClickableText(
onTextLayout: (TextLayoutResult) -> Unit = {}, onTextLayout: (TextLayoutResult) -> Unit = {},
onClick: (Int) -> Unit, onClick: (Int) -> Unit,
onLongClick: (Int) -> Unit = {}, onLongClick: (Int) -> Unit = {},
onDoubleTap: (Int) -> Unit = {},
onHover: (Int) -> Unit = {}, onHover: (Int) -> Unit = {},
shouldConsumeEvent: (Int) -> Boolean shouldConsumeEvent: (Int) -> Boolean
) { ) {
val layoutResult = remember { mutableStateOf<TextLayoutResult?>(null) } val layoutResult = remember { mutableStateOf<TextLayoutResult?>(null) }
val pressIndicator = Modifier.pointerInput(onClick, onLongClick, onDoubleTap) { val pressIndicator = Modifier.pointerInput(onClick, onLongClick) {
detectTapGestures( detectGesture(onLongPress = { pos ->
onDoubleTap = { pos -> layoutResult.value?.let { layoutResult ->
layoutResult.value?.let { layoutResult -> onLongClick(layoutResult.getOffsetForPosition(pos))
onDoubleTap(layoutResult.getOffsetForPosition(pos)) }
} }, onPress = { pos ->
}, layoutResult.value?.let { layoutResult ->
onLongPress = { pos -> val res = tryAwaitRelease()
layoutResult.value?.let { layoutResult -> if (res) {
onLongClick(layoutResult.getOffsetForPosition(pos))
}
},
onTap = { pos ->
layoutResult.value?.let { layoutResult ->
onClick(layoutResult.getOffsetForPosition(pos)) onClick(layoutResult.getOffsetForPosition(pos))
} }
} }
}, shouldConsumeEvent = { pos ->
var consume = false
layoutResult.value?.let { layoutResult ->
consume = shouldConsumeEvent(layoutResult.getOffsetForPosition(pos))
}
consume
}
) )
} }.pointerInput(onHover) {
.pointerInput(onHover) { if (appPlatform.isDesktop) {
if (appPlatform.isDesktop) { detectCursorMove { pos ->
detectCursorMove { pos -> layoutResult.value?.let { layoutResult ->
layoutResult.value?.let { layoutResult -> onHover(layoutResult.getOffsetForPosition(pos))
onHover(layoutResult.getOffsetForPosition(pos))
}
} }
} }
} }
}
BasicText( BasicText(
text = text, text = text,