kopia lustrzana https://github.com/vitorpamplona/amethyst
Fixes the rendering of highlights when no user is present and includes options to render by `e` tags
rodzic
95694ac355
commit
5e417dd890
|
@ -138,7 +138,7 @@ private fun LoadAndDisplayEvent(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun DisplayEvent(
|
||||
fun DisplayEvent(
|
||||
hex: HexKey,
|
||||
kind: Int?,
|
||||
additionalChars: String?,
|
||||
|
@ -293,7 +293,7 @@ public fun DisplayUser(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun RenderUserAsClickableText(
|
||||
public fun RenderUserAsClickableText(
|
||||
baseUser: User,
|
||||
additionalChars: String?,
|
||||
nav: (String) -> Unit,
|
||||
|
|
|
@ -40,19 +40,27 @@ import androidx.compose.runtime.setValue
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import com.vitorpamplona.amethyst.model.AddressableNote
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.ui.components.ClickableUrl
|
||||
import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.ui.components.DisplayEvent
|
||||
import com.vitorpamplona.amethyst.ui.components.LoadNote
|
||||
import com.vitorpamplona.amethyst.ui.components.RenderUserAsClickableText
|
||||
import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
|
||||
import com.vitorpamplona.amethyst.ui.components.measureSpaceWidth
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.quartz.encoders.ATag
|
||||
import com.vitorpamplona.quartz.encoders.HexKey
|
||||
import com.vitorpamplona.quartz.events.BaseTextNoteEvent
|
||||
import com.vitorpamplona.quartz.events.EmptyTagList
|
||||
import com.vitorpamplona.quartz.events.HighlightEvent
|
||||
import com.vitorpamplona.quartz.events.LongTextNoteEvent
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.net.URL
|
||||
|
||||
@Composable
|
||||
|
@ -72,6 +80,7 @@ fun RenderHighlight(
|
|||
authorHex = noteEvent.author(),
|
||||
url = noteEvent.inUrl(),
|
||||
postAddress = noteEvent.inPost(),
|
||||
postVersion = noteEvent.inPostVersion(),
|
||||
makeItShort = makeItShort,
|
||||
canPreview = canPreview,
|
||||
quotesLeft = quotesLeft,
|
||||
|
@ -81,12 +90,14 @@ fun RenderHighlight(
|
|||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun DisplayHighlight(
|
||||
highlight: String,
|
||||
authorHex: String?,
|
||||
url: String?,
|
||||
postAddress: ATag?,
|
||||
postVersion: HexKey?,
|
||||
makeItShort: Boolean,
|
||||
canPreview: Boolean,
|
||||
quotesLeft: Int,
|
||||
|
@ -112,54 +123,151 @@ fun DisplayHighlight(
|
|||
nav = nav,
|
||||
)
|
||||
|
||||
DisplayQuoteAuthor(authorHex ?: "", url, postAddress, accountViewModel, nav)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
private fun DisplayQuoteAuthor(
|
||||
authorHex: String,
|
||||
url: String?,
|
||||
postAddress: ATag?,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
var userBase by remember { mutableStateOf<User?>(accountViewModel.getUserIfExists(authorHex)) }
|
||||
|
||||
if (userBase == null) {
|
||||
LaunchedEffect(Unit) {
|
||||
accountViewModel.checkGetOrCreateUser(authorHex) { newUserBase ->
|
||||
userBase = newUserBase
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val spaceWidth = measureSpaceWidth(textStyle = LocalTextStyle.current)
|
||||
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.spacedBy(spaceWidth),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
userBase?.let { userBase ->
|
||||
val userMetadata by userBase.live().userMetadataInfo.observeAsState()
|
||||
|
||||
CreateClickableTextWithEmoji(
|
||||
clickablePart = userMetadata?.bestName() ?: userBase.pubkeyDisplayHex(),
|
||||
maxLines = 1,
|
||||
route = "User/${userBase.pubkeyHex}",
|
||||
nav = nav,
|
||||
tags = userMetadata?.tags,
|
||||
)
|
||||
}
|
||||
|
||||
url?.let { url -> LoadAndDisplayUrl(url) }
|
||||
|
||||
postAddress?.let { address -> LoadAndDisplayPost(address, accountViewModel, nav) }
|
||||
DisplayQuoteAuthor(
|
||||
authorHex = authorHex,
|
||||
url = url,
|
||||
postAddress = postAddress,
|
||||
postVersion = postVersion,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LoadAndDisplayUrl(url: String) {
|
||||
private fun DisplayQuoteAuthor(
|
||||
authorHex: String?,
|
||||
url: String?,
|
||||
postAddress: ATag?,
|
||||
postVersion: HexKey?,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
var userBase by remember { mutableStateOf<User?>(authorHex?.let { accountViewModel.getUserIfExists(it) }) }
|
||||
|
||||
if (userBase == null && authorHex != null) {
|
||||
LaunchedEffect(authorHex) {
|
||||
accountViewModel.checkGetOrCreateUser(authorHex) { newUserBase ->
|
||||
userBase = newUserBase
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var addressable by remember {
|
||||
mutableStateOf<AddressableNote?>(postAddress?.let { accountViewModel.getAddressableNoteIfExists(it.toTag()) })
|
||||
}
|
||||
|
||||
if (addressable == null && postAddress != null) {
|
||||
LaunchedEffect(key1 = postAddress) {
|
||||
val newNote =
|
||||
withContext(Dispatchers.IO) {
|
||||
accountViewModel.getOrCreateAddressableNote(postAddress)
|
||||
}
|
||||
if (addressable != newNote) {
|
||||
addressable = newNote
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var version by remember {
|
||||
mutableStateOf<Note?>(postVersion?.let { accountViewModel.getNoteIfExists(it) })
|
||||
}
|
||||
|
||||
if (version == null && postVersion != null) {
|
||||
LaunchedEffect(key1 = postVersion) {
|
||||
val newNote =
|
||||
withContext(Dispatchers.IO) {
|
||||
accountViewModel.getOrCreateNote(postVersion)
|
||||
}
|
||||
if (version != newNote) {
|
||||
version = newNote
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addressable != null) {
|
||||
addressable?.let {
|
||||
DisplayEntryForNote(it, userBase, accountViewModel, nav)
|
||||
}
|
||||
} else if (version != null) {
|
||||
version?.let {
|
||||
DisplayEntryForNote(it, userBase, accountViewModel, nav)
|
||||
}
|
||||
} else if (url != null) {
|
||||
DisplayEntryForAUrl(url, userBase, accountViewModel, nav)
|
||||
} else if (userBase != null) {
|
||||
userBase?.let {
|
||||
DisplayEntryForUser(it, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DisplayEntryForUser(
|
||||
userBase: User,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
val userMetadata by userBase.live().userMetadataInfo.observeAsState()
|
||||
|
||||
CreateClickableTextWithEmoji(
|
||||
clickablePart = userMetadata?.bestName() ?: userBase.pubkeyDisplayHex(),
|
||||
maxLines = 1,
|
||||
route = "User/${userBase.pubkeyHex}",
|
||||
nav = nav,
|
||||
tags = userMetadata?.tags,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DisplayEntryForNote(
|
||||
note: Note,
|
||||
userBase: User?,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
val noteState by note.live().metadata.observeAsState()
|
||||
|
||||
val author = userBase ?: noteState?.note?.author
|
||||
|
||||
if (author != null) {
|
||||
RenderUserAsClickableText(author, null, nav)
|
||||
}
|
||||
|
||||
val noteEvent = noteState?.note?.event as? BaseTextNoteEvent ?: return
|
||||
|
||||
val description = noteEvent.firstTagFor("title", "subject", "alt")
|
||||
|
||||
Text("-", maxLines = 1)
|
||||
|
||||
if (description != null) {
|
||||
ClickableText(
|
||||
text = AnnotatedString(description),
|
||||
onClick = { routeFor(note, accountViewModel.userProfile())?.let { nav(it) } },
|
||||
style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary),
|
||||
)
|
||||
} else {
|
||||
DisplayEvent(noteEvent.id, noteEvent.kind, "", accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DisplayEntryForAUrl(
|
||||
url: String,
|
||||
userBase: User?,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
if (userBase != null) {
|
||||
DisplayEntryForUser(userBase, accountViewModel, nav)
|
||||
}
|
||||
|
||||
val validatedUrl =
|
||||
remember {
|
||||
try {
|
||||
|
@ -171,7 +279,9 @@ fun LoadAndDisplayUrl(url: String) {
|
|||
}
|
||||
|
||||
validatedUrl?.host?.let { host ->
|
||||
Text("-", maxLines = 1)
|
||||
if (userBase != null) {
|
||||
Text("-", maxLines = 1)
|
||||
}
|
||||
ClickableUrl(urlText = host, url = url)
|
||||
}
|
||||
}
|
||||
|
@ -198,3 +308,21 @@ private fun LoadAndDisplayPost(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LoadAndDisplayPostVersion(
|
||||
postEvent: HexKey,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
LoadNote(baseNoteHex = postEvent, accountViewModel) { baseNote ->
|
||||
baseNote?.let { note ->
|
||||
val noteState by note.live().metadata.observeAsState()
|
||||
val noteEvent = noteState?.note?.event as? BaseTextNoteEvent ?: return@LoadNote
|
||||
|
||||
Text("-", maxLines = 1)
|
||||
|
||||
DisplayEvent(noteEvent.id, noteEvent.kind, "", accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,6 +121,8 @@ open class Event(
|
|||
|
||||
override fun taggedUrls() = tags.filter { it.size > 1 && it[0] == "r" }.map { it[1] }
|
||||
|
||||
override fun firstTagFor(vararg key: String) = tags.firstOrNull { it.size > 1 && it[0] in key }?.let { it[1] }
|
||||
|
||||
override fun firstTaggedUser() = tags.firstOrNull { it.size > 1 && it[0] == "p" }?.let { it[1] }
|
||||
|
||||
override fun firstTaggedEvent() = tags.firstOrNull { it.size > 1 && it[0] == "e" }?.let { it[1] }
|
||||
|
|
|
@ -133,6 +133,8 @@ interface EventInterface {
|
|||
|
||||
fun taggedUrls(): List<String>
|
||||
|
||||
fun firstTagFor(vararg key: String): String?
|
||||
|
||||
fun firstTaggedAddress(): ATag?
|
||||
|
||||
fun firstTaggedUser(): HexKey?
|
||||
|
|
|
@ -42,6 +42,8 @@ class HighlightEvent(
|
|||
|
||||
fun inPost() = firstTaggedAddress()
|
||||
|
||||
fun inPostVersion() = firstTaggedEvent()
|
||||
|
||||
companion object {
|
||||
const val KIND = 9802
|
||||
const val ALT = "Highlight/quote event"
|
||||
|
|
Ładowanie…
Reference in New Issue