improvement: Ofload Markdown parsing (Vault, Send screens) from UI thread

This commit is contained in:
Artem Chepurnoy 2024-03-07 18:55:40 +02:00
parent aefb752467
commit e6649feafa
No known key found for this signature in database
GPG Key ID: FAC37D0CF674043E
5 changed files with 94 additions and 22 deletions

View File

@ -78,12 +78,15 @@ fun VaultViewNoteItem(
.fillMaxWidth(),
) {
SelectionContainer {
if (item.markdown) {
when (item.content) {
is VaultViewItem.Note.Content.Markdown -> {
MarkdownText(
markdown = item.text,
markdown = item.content.node,
)
} else {
Text(item.text)
}
is VaultViewItem.Note.Content.Text -> {
Text(item.content.text)
}
}
}
}

View File

@ -16,6 +16,8 @@ import com.artemchep.keyguard.common.usecase.CopyText
import com.artemchep.keyguard.feature.attachments.model.AttachmentItem
import com.artemchep.keyguard.ui.ContextItem
import com.artemchep.keyguard.ui.FlatItemAction
import com.halilibo.richtext.commonmark.CommonmarkAstNodeParser
import com.halilibo.richtext.markdown.node.AstNode
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
@ -144,13 +146,39 @@ sealed interface VaultViewItem {
data class Note(
override val id: String,
val text: String,
val markdown: Boolean,
val content: Content,
val elevation: Dp = 0.dp,
val conceal: Boolean = false,
val verify: ((() -> Unit) -> Unit)? = null,
) : VaultViewItem {
companion object
companion object;
sealed interface Content {
companion object {
fun of(
parser: CommonmarkAstNodeParser,
markdown: Boolean,
text: String,
): Content =
if (markdown) {
kotlin.runCatching {
val data = text.trimIndent()
val node = parser.parse(data)
Markdown(node)
}.getOrNull()
} else {
null
} ?: Text(text)
}
data class Markdown(
val node: AstNode,
) : Content
data class Text(
val text: String,
) : Content
}
}
data class Spacer(

View File

@ -192,6 +192,7 @@ import com.artemchep.keyguard.ui.text.annotate
import com.artemchep.keyguard.ui.theme.Dimens
import com.artemchep.keyguard.ui.theme.combineAlpha
import com.artemchep.keyguard.ui.totp.formatCode2
import com.halilibo.richtext.commonmark.CommonmarkAstNodeParser
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
@ -387,6 +388,7 @@ fun vaultViewScreenState(
val selectionHandle = selectionHandle("selection")
val markdown = getMarkdown().first()
val markdownParser = CommonmarkAstNodeParser()
val accountFlow = getAccounts()
.map { accounts ->
@ -715,6 +717,7 @@ fun vaultViewScreenState(
primaryAction = primaryAction,
items = oh(
mode = mode,
markdownParser = markdownParser,
sharingScope = screenScope, // FIXME: must not be a screen scope!!
selectionHandle = selectionHandle,
canEdit = canEdit,
@ -767,6 +770,7 @@ fun vaultViewScreenState(
private fun RememberStateFlowScope.oh(
mode: AppMode,
markdownParser: CommonmarkAstNodeParser,
sharingScope: CoroutineScope,
selectionHandle: SelectionHandle,
canEdit: Boolean,
@ -1423,10 +1427,14 @@ private fun RememberStateFlowScope.oh(
}
if (cipher.type == DSecret.Type.SecureNote && cipher.notes.isNotEmpty()) {
val content = VaultViewItem.Note.Content.of(
parser = markdownParser,
markdown = markdown,
text = cipher.notes,
)
val note = VaultViewItem.Note(
id = "note.text",
text = if (markdown) cipher.notes.trimIndent() else cipher.notes,
markdown = markdown,
content = content,
verify = verify,
conceal = verify != null,
)
@ -1633,10 +1641,14 @@ private fun RememberStateFlowScope.oh(
text = translate(Res.strings.notes),
)
emit(section)
val content = VaultViewItem.Note.Content.of(
parser = markdownParser,
markdown = markdown,
text = cipher.notes,
)
val note = VaultViewItem.Note(
id = "note.text",
text = if (markdown) cipher.notes.trimIndent() else cipher.notes,
markdown = markdown,
content = content,
verify = verify,
conceal = verify != null,
)

View File

@ -87,6 +87,7 @@ import com.artemchep.keyguard.ui.icons.KeyguardView
import com.artemchep.keyguard.ui.selection.SelectionHandle
import com.artemchep.keyguard.ui.selection.selectionHandle
import com.artemchep.keyguard.ui.text.annotate
import com.halilibo.richtext.commonmark.CommonmarkAstNodeParser
import io.ktor.http.Url
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
@ -226,6 +227,7 @@ fun sendViewScreenState(
)
val markdown = getMarkdown().first()
val markdownParser = CommonmarkAstNodeParser()
val accountFlow = getAccounts()
.map { accounts ->
@ -297,6 +299,7 @@ fun sendViewScreenState(
null
},
items = oh(
markdownParser = markdownParser,
canEdit = canAddSecret,
contentColor = contentColor,
disabledContentColor = disabledContentColor,
@ -323,6 +326,7 @@ fun sendViewScreenState(
}
private fun RememberStateFlowScope.oh(
markdownParser: CommonmarkAstNodeParser,
canEdit: Boolean,
contentColor: Color,
disabledContentColor: Color,
@ -438,10 +442,14 @@ private fun RememberStateFlowScope.oh(
text = translate(Res.strings.notes),
)
emit(section)
val content = VaultViewItem.Note.Content.of(
parser = markdownParser,
markdown = markdown,
text = send.notes,
)
val note = VaultViewItem.Note(
id = "note.text",
text = if (markdown) send.notes.trimIndent() else send.notes,
markdown = markdown,
content = content,
)
emit(note)
}

View File

@ -4,6 +4,8 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.halilibo.richtext.commonmark.Markdown
import com.halilibo.richtext.markdown.BasicMarkdown
import com.halilibo.richtext.markdown.node.AstNode
import com.halilibo.richtext.ui.RichTextStyle
import com.halilibo.richtext.ui.material3.RichText
import com.halilibo.richtext.ui.resolveDefaults
@ -14,13 +16,7 @@ fun MarkdownText(
modifier: Modifier = Modifier,
markdown: String,
) {
val richTextStyle = RichTextStyle().resolveDefaults().copy(
stringStyle = RichTextStringStyle().copy(
linkStyle = MaterialTheme.typography.bodyLarge.toSpanStyle().copy(
color = MaterialTheme.colorScheme.primary,
),
),
)
val richTextStyle = getRichTextStyle()
RichText(
modifier = modifier,
style = richTextStyle,
@ -28,3 +24,28 @@ fun MarkdownText(
Markdown(markdown)
}
}
@Composable
fun MarkdownText(
modifier: Modifier = Modifier,
markdown: AstNode,
) {
val richTextStyle = getRichTextStyle()
RichText(
modifier = modifier,
style = richTextStyle,
) {
BasicMarkdown(markdown)
}
}
@Composable
private fun getRichTextStyle(): RichTextStyle {
return RichTextStyle().resolveDefaults().copy(
stringStyle = RichTextStringStyle().copy(
linkStyle = MaterialTheme.typography.bodyLarge.toSpanStyle().copy(
color = MaterialTheme.colorScheme.primary,
),
),
)
}