mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2025-06-28 20:29:53 +00:00
Added Double tap to edit
This commit is contained in:
parent
c81d114d9a
commit
aac670e323
1 changed files with 42 additions and 58 deletions
|
@ -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,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue