Improve note rendering

This commit is contained in:
Kgothatso Ngako
2026-05-03 19:03:50 +02:00
parent 3fef7bdabc
commit e7db6598d0
9 changed files with 483 additions and 201 deletions

View File

@@ -7,21 +7,24 @@ import ac.cord.auxiliary.compose.database.model.QuotedRelation
import ac.cord.auxiliary.compose.extensions.toFormattedTimeAndDateString
import ac.cord.auxiliary.compose.ui.composable.widgets.content.RichContent
import ac.cord.auxiliary.compose.ui.composable.widgets.profile.ProfileAvatar
import ac.cord.auxiliary.compose.ui.composable.widgets.profile.ProfileColor
import ac.cord.auxiliary.compose.ui.theme.AuxTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.room3.Embedded
import androidx.room3.Relation
import com.vitorpamplona.quartz.nip01Core.core.HexKey
data class LocalQuotedNostrEvent(
@Embedded val quotedRelation: QuotedRelation,
@@ -46,37 +49,43 @@ data class LocalQuotedNostrEvent(
val mentionedProfiles: List<LocalMention> = emptyList(),
) {
@Composable
fun RenderNotePreview() {
fun RenderNotePreview(
onNavigateToEvent: (HexKey) -> Unit
) {
Column {
Row(
modifier = Modifier.fillMaxWidth().padding(12.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp),
modifier = Modifier.fillMaxWidth().padding(10.dp)
// .clickable(
// onClick = {
// onNavigateToEvent.invoke(profile.nostrEventId)
// }
// )
,
horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.Start),
verticalAlignment = Alignment.CenterVertically
) {
val profile = profile
ProfileAvatar(
profile = profile,
publicKey = nostrEvent.pubKey
publicKey = nostrEvent.pubKey,
profile = profile
)
Column(
modifier = Modifier.weight(1f)
) {
){
Text(
text = profile?.displayName ?: profile?.userName ?: nostrEvent.pubKey,
style = MaterialTheme.typography.labelLarge
text = profile?.humanReadableNameOrPubkey() ?: nostrEvent.pubKey,
style = MaterialTheme.typography.bodyMedium
)
profile?.nip05?.let {
profile?.staticIdentifier()?.let { staticIdentifier ->
Text(
text = profile.nip05 ?: "",
style = MaterialTheme.typography.labelMedium
text = staticIdentifier,
style = MaterialTheme.typography.bodySmall,
color = ProfileColor.fromProfile(profile)
)
}
}
}
Column(
modifier = Modifier.fillMaxWidth().padding(
horizontal = 10.dp
@@ -86,6 +95,7 @@ data class LocalQuotedNostrEvent(
nostrEvent = nostrEvent,
localQuotedNostrEvent = null,
mentionedProfiles = mentionedProfiles,
onNavigateToEvent = onNavigateToEvent
)
}
@@ -100,4 +110,37 @@ data class LocalQuotedNostrEvent(
}
}
}
}
@Preview
@Composable
private fun LocalQuotedNostrEventPreview() {
AuxTheme {
Surface(
modifier = Modifier.padding(20.dp)
) {
LocalQuotedNostrEvent(
nostrEvent = NostrEvent(
id = "1c7213118d4e17c6bad5c6b11125f005619bc3e43374affb9cd6483f665fd5e6",
content = "God is not in the habit of coming down from heaven to solve peoples problems on earth.",
pubKey = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a522",
kind = 0,
sig = "hexsig",
tags = emptyArray()
),
quotedRelation = QuotedRelation(
quotingNostrEventId = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a520",
quotedProfilePublicKey = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a522",
quotedNostrEventId = "1c7213118d4e17c6bad5c6b11125f005619bc3e43374affb9cd6483f665fd5e6"
),
profile = Profile(
publicKey = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a522",
nostrEventId = "referenced",
displayName = "Steve Biko"
),
).RenderNotePreview(
onNavigateToEvent = {}
)
}
}
}

View File

@@ -78,7 +78,7 @@ fun NostrEventDetailScreen(
feedListUIState.localNostrEvent,
onNavigateBack = onNavigateBack,
onNavigateToWriteAReply = onNavigateToWriteAReply,
onNavigateToQuoteNostrEvent = onNavigateToQuoteNostrEvent
onNavigateToNostrEvent = onNavigateToQuoteNostrEvent
)
}
RepostEvent.KIND -> {

View File

@@ -47,11 +47,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.SpanStyle
@@ -60,7 +56,6 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import co.touchlab.kermit.Logger
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
import kotlin.time.Clock
@@ -368,6 +363,7 @@ fun WriteNewNoteScreen(
)
},
style = MaterialTheme.typography.bodySmall,
onNavigateToEvent = {}
// TODO: Add TextAlign.Center
)

View File

@@ -1,6 +1,5 @@
package ac.cord.auxiliary.compose.ui.composable.widgets.content
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalNostrEvent
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalQuotedNostrEvent
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.Row
@@ -28,7 +27,7 @@ internal fun QuotedAddressableNote(
dTag: String,
author: String,
relayHints: List<String>,
onNoteClick: ((String) -> Unit)?,
onNoteClick: (String) -> Unit,
onProfileClick: ((String) -> Unit)?,
noteActions: NoteActions?,
style: TextStyle
@@ -39,7 +38,7 @@ internal fun QuotedAddressableNote(
if (localQuotedNostrEvent != null) {
QuotedNote(
localQuotedNostrEvent = localQuotedNostrEvent,
onNoteClick = onNoteClick,
onNavigateToEvent = onNoteClick,
noteActions = noteActions
)
} else {

View File

@@ -1,8 +1,10 @@
package ac.cord.auxiliary.compose.ui.composable.widgets.content
import ac.cord.auxiliary.compose.database.model.NostrEvent
import ac.cord.auxiliary.compose.database.model.Profile
import ac.cord.auxiliary.compose.database.model.QuotedRelation
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalQuotedNostrEvent
import ac.cord.auxiliary.compose.ui.theme.AuxTheme
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Row
@@ -19,12 +21,14 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.vitorpamplona.quartz.nip01Core.core.HexKey
@Composable
fun QuotedNote(
localQuotedNostrEvent: LocalQuotedNostrEvent? = null,
onNoteClick: ((String) -> Unit)? = null,
onNavigateToEvent:(HexKey) -> Unit,
noteActions: NoteActions? = null
) {
// Observe versions so we recompose when data arrives from relays
@@ -36,7 +40,7 @@ fun QuotedNote(
// }
// }
val effectiveNoteClick = noteActions?.onNoteClick ?: onNoteClick
val effectiveNoteClick = noteActions?.onNoteClick ?: onNavigateToEvent
// Fetch poll votes when quoted event is a poll
// LaunchedEffect(event?.id, event?.kind) {
@@ -59,7 +63,9 @@ fun QuotedNote(
.fillMaxWidth()
.padding(vertical = 6.dp)
) {
localQuotedNostrEvent.RenderNotePreview()
localQuotedNostrEvent.RenderNotePreview(
onNavigateToEvent = onNavigateToEvent
)
// quotedNostrEvent.RenderNotePreview()
}
} else if (localQuotedNostrEvent != null) {
@@ -70,13 +76,13 @@ fun QuotedNote(
color = MaterialTheme.colorScheme.surface,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 6.dp)
.then(
if (effectiveNoteClick != null) Modifier.clickable { effectiveNoteClick(localQuotedNostrEvent.nostrEvent.id) }
else Modifier
Modifier.clickable { effectiveNoteClick(localQuotedNostrEvent.nostrEvent.id) }
)
) {
localQuotedNostrEvent.RenderNotePreview()
localQuotedNostrEvent.RenderNotePreview(
onNavigateToEvent = onNavigateToEvent
)
}
} else {
// Loading state
@@ -108,4 +114,41 @@ fun QuotedNote(
}
}
}
}
@Preview
@Composable
private fun QuotedNotePreview() {
AuxTheme {
Surface(
modifier = Modifier.padding(20.dp)
) {
QuotedNote(
localQuotedNostrEvent = LocalQuotedNostrEvent(
nostrEvent = NostrEvent(
id = "1c7213118d4e17c6bad5c6b11125f005619bc3e43374affb9cd6483f665fd5e6",
content = "God is not in the habit of coming down from heaven to solve peoples problems on earth.",
pubKey = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a522",
kind = 0,
sig = "hexsig",
tags = emptyArray()
),
quotedRelation = QuotedRelation(
quotingNostrEventId = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a520",
quotedProfilePublicKey = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a522",
quotedNostrEventId = "1c7213118d4e17c6bad5c6b11125f005619bc3e43374affb9cd6483f665fd5e6"
),
profile = Profile(
publicKey = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a522",
nostrEventId = "referenced",
displayName = "Steve Biko"
),
),
onNavigateToEvent = { },
noteActions = null
)
}
}
}

View File

@@ -5,14 +5,14 @@ import ac.cord.auxiliary.compose.database.model.NostrEvent
import ac.cord.auxiliary.compose.database.model.Profile
import ac.cord.auxiliary.compose.database.model.QuotedRelation
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalMention
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalNostrEvent
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalQuotedNostrEvent
import ac.cord.auxiliary.compose.ui.composable.widgets.content.Constants.INLINE_CONTENT_TAG
import ac.cord.auxiliary.compose.ui.composable.widgets.feed.ListView
import ac.cord.auxiliary.compose.ui.composable.widgets.profile.ProfileColor
import ac.cord.auxiliary.compose.ui.theme.AuxTheme
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.foundation.text.selection.SelectionContainer
@@ -41,6 +41,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import co.touchlab.kermit.Logger
import coil3.compose.AsyncImage
import com.vitorpamplona.quartz.nip01Core.core.HexKey
@Composable
fun RichContent(
@@ -54,7 +55,7 @@ fun RichContent(
imetaMap: Map<String, MediaMeta> = emptyMap(),
plainLinks: Boolean = false,
onProfileClick: ((String) -> Unit)? = null,
onNoteClick: ((String) -> Unit)? = null,
onNavigateToEvent: (HexKey) -> Unit,
onHashtagClick: ((String) -> Unit)? = null,
onLiveStreamClick: ((String, String, String?) -> Unit)? = null,
noteActions: NoteActions? = null,
@@ -294,7 +295,7 @@ fun RichContent(
if (localQuotedNostrEvent != null) {
QuotedNote(
localQuotedNostrEvent = localQuotedNostrEvent,
onNoteClick = onNoteClick,
onNavigateToEvent = onNavigateToEvent,
noteActions = noteActions
)
} else {
@@ -316,7 +317,7 @@ fun RichContent(
dTag = segment.dTag,
author = segment.author,
relayHints = segment.relays,
onNoteClick = onNoteClick,
onNoteClick = onNavigateToEvent,
onProfileClick = onProfileClick,
noteActions = noteActions,
style = style
@@ -423,7 +424,7 @@ private fun RichContentPreview() {
modifier = Modifier.padding(10.dp),
nostrEvent = NostrEvent(
id = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a520",
content = "Something something something nostr:npub1uh366qnj68a7atvwgwdy4569xd6v5jtferftapqztwjwlzh9553q47pqsx\nnostr:note1uh366qnj68a7atvwgwdy4569xd6v5jtferftapqztwjwlzh955s53z8ee",
content = "Something something something nostr:npub1uh366qnj68a7atvwgwdy4569xd6v5jtferftapqztwjwlzh9553q47pqsx\nhttps://www.brainyquote.com/authors/steven-biko-quotes\nnostr:nevent1qqspcusnzxx5u97xht2udvg3yhcq2cvmc0jrxa90lwwdvjplve0atespzpmhxue69uhkummnw3ezuamfdejsyg8h5g639qhuv803hzwexfwhyud6t6suxfu364anddqvrmn9j4cahvxksr8q",
pubKey = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a522",
kind = 0,
sig = "hexsig",
@@ -431,8 +432,8 @@ private fun RichContentPreview() {
),
localQuotedNostrEvent = LocalQuotedNostrEvent(
nostrEvent = NostrEvent(
id = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a521",
content = "Quote me on this!",
id = "1c7213118d4e17c6bad5c6b11125f005619bc3e43374affb9cd6483f665fd5e6",
content = "God is not in the habit of coming down from heaven to solve peoples problems on earth.",
pubKey = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a522",
kind = 0,
sig = "hexsig",
@@ -441,12 +442,12 @@ private fun RichContentPreview() {
quotedRelation = QuotedRelation(
quotingNostrEventId = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a520",
quotedProfilePublicKey = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a522",
quotedNostrEventId = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a521"
quotedNostrEventId = "1c7213118d4e17c6bad5c6b11125f005619bc3e43374affb9cd6483f665fd5e6"
),
profile = Profile(
publicKey = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a522",
nostrEventId = "referenced",
displayName = "Frank Talk"
displayName = "Steve Biko"
),
),
mentionedProfiles = listOf(
@@ -462,6 +463,7 @@ private fun RichContentPreview() {
),
)
),
onNavigateToEvent = {}
)
}

View File

@@ -4,13 +4,10 @@ import ac.cord.auxiliary.compose.database.model.NostrEvent
import ac.cord.auxiliary.compose.database.model.Profile
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalNostrEvent
import ac.cord.auxiliary.compose.extensions.toFormattedTimeAndDateString
import ac.cord.auxiliary.compose.ui.composable.widgets.content.ContentParser
import ac.cord.auxiliary.compose.ui.composable.widgets.content.ContentSegment
import ac.cord.auxiliary.compose.ui.composable.widgets.content.RichContent
import ac.cord.auxiliary.compose.ui.composable.widgets.profile.ProfileAvatar
import ac.cord.auxiliary.compose.ui.composable.widgets.profile.ProfileColor
import ac.cord.auxiliary.compose.ui.theme.AuxTheme
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -21,14 +18,8 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.CornerBasedShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.input.InputTransformation
import androidx.compose.foundation.text.input.OutputTransformation
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AddReaction
import androidx.compose.material.icons.filled.ArrowBackIosNew
@@ -37,36 +28,25 @@ import androidx.compose.material.icons.filled.CurrencyBitcoin
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.filled.Repeat
import androidx.compose.material.icons.filled.Reply
import androidx.compose.material.icons.filled.Send
import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.FlexibleBottomAppBar
import androidx.compose.material3.FloatingToolbarDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.HorizontalFloatingToolbar
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Shapes
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.graphics.shapes.CornerRounding
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@@ -75,7 +55,7 @@ fun TextNoteEventDetail(
localNostrEvent: LocalNostrEvent,
onNavigateBack: () -> Unit,
onNavigateToWriteAReply: (String) -> Unit,
onNavigateToQuoteNostrEvent: (String) -> Unit,
onNavigateToNostrEvent: (HexKey) -> Unit,
) {
Scaffold(
modifier = Modifier.fillMaxSize(),
@@ -259,7 +239,8 @@ fun TextNoteEventDetail(
),
nostrEvent = localNostrEvent.nostrEvent,
localQuotedNostrEvent = localNostrEvent.localQuotedNostrEvent,
mentionedProfiles = localNostrEvent.mentionedProfiles
mentionedProfiles = localNostrEvent.mentionedProfiles,
onNavigateToEvent = onNavigateToNostrEvent
)
Row(
@@ -302,7 +283,7 @@ fun TextNoteEventDetail(
IconButton(
onClick = {
onNavigateToQuoteNostrEvent.invoke(
onNavigateToNostrEvent.invoke(
localNostrEvent.nostrEvent.id
)
}
@@ -373,7 +354,7 @@ It has survived not only five centuries, but also the leap into electronic types
),
onNavigateBack = {},
onNavigateToWriteAReply = {},
onNavigateToQuoteNostrEvent = {}
onNavigateToNostrEvent = {}
)
}
}

View File

@@ -1,8 +1,12 @@
package ac.cord.auxiliary.compose.ui.composable.widgets.feed
import ac.cord.auxiliary.compose.database.model.InReplyToRelation
import ac.cord.auxiliary.compose.database.model.NostrEvent
import ac.cord.auxiliary.compose.database.model.Profile
import ac.cord.auxiliary.compose.database.model.RepostedRelation
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalInReplyToNostrEvent
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalNostrEvent
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalRepostedNostrEvent
import ac.cord.auxiliary.compose.extensions.toFormattedTimeAndDateString
import ac.cord.auxiliary.compose.ui.composable.widgets.content.RichContent
import ac.cord.auxiliary.compose.ui.composable.widgets.profile.ProfileAvatar
@@ -36,6 +40,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
import com.vitorpamplona.quartz.nip18Reposts.RepostEvent
import kotlin.time.Instant
@@ -135,7 +140,7 @@ fun LocalNostrEvent.ListView(
@Preview
@Composable
private fun EventListViewPreview() {
private fun EventListViewRepostedPreview() {
AuxTheme {
Surface(
modifier = Modifier.padding(20.dp)
@@ -143,17 +148,92 @@ private fun EventListViewPreview() {
LocalNostrEvent(
nostrEvent = NostrEvent(
id = "hex",
content = "Something something seomthing",
content = "Reposting",
pubKey = "hexpubkeypubkeypubkeypubkey",
kind = 0,
kind = RepostEvent.KIND,
sig = "hexsig",
tags = emptyArray()
),
localRepostedNostrEvent = LocalRepostedNostrEvent(
repostedRelation = RepostedRelation(
repostingNostrEventId = "hex",
repostedNostrEventId = "repostedhex",
repostedProfilePublicKey = "reposterHex"
),
nostrEvent = NostrEvent(
id = "hex",
content = "Something something something",
pubKey = "hexpubkeypubkeypubkeypubkey",
kind = 0,
sig = "hexsig",
tags = emptyArray()
),
profile = Profile(
publicKey = "hesd",
nostrEventId = "referenced",
displayName = "Frank Talk",
nip05 = "frank@talk.at"
),
mentionedProfiles = emptyList()
),
profile = Profile(
publicKey = "",
nostrEventId = "referenced",
displayName = "Frank Talk",
nip05 = "frank@talk.at"
displayName = "Steve Biko",
nip05 = "steve@bck.co.za"
),
).ListView(
onNavigateToEvent = {}
)
}
}
}
@Preview
@Composable
private fun EventListViewInReplyPreview() {
AuxTheme {
Surface(
modifier = Modifier.padding(20.dp)
) {
LocalNostrEvent(
nostrEvent = NostrEvent(
id = "hex",
content = "Reposting",
pubKey = "hexpubkeypubkeypubkeypubkey",
kind = TextNoteEvent.KIND,
sig = "hexsig",
tags = emptyArray()
),
localInReplyToNostrEvent = LocalInReplyToNostrEvent(
inReplyToRelation = InReplyToRelation(
inReplyToNostrEventId = "nostrEvent",
inReplyToRootNostrEventId = "rootId",
inReplyToProfilePublicKey = "inReplyToProfileKey",
inReplyToRootProfilePublicKey = "rootPubKey",
replyingNostrEventId = "hex"
),
nostrEvent = NostrEvent(
id = "hex",
content = "Something something something",
pubKey = "hexpubkeypubkeypubkeypubkey",
kind = 0,
sig = "hexsig",
tags = emptyArray()
),
profile = Profile(
publicKey = "hesd",
nostrEventId = "referenced",
displayName = "Frank Talk",
nip05 = "frank@talk.at"
),
mentionedProfiles = emptyList()
),
profile = Profile(
publicKey = "",
nostrEventId = "referenced",
displayName = "Steve Biko",
nip05 = "steve@bck.co.za"
),
).ListView(
onNavigateToEvent = {}

View File

@@ -1,10 +1,12 @@
package ac.cord.auxiliary.compose.ui.composable.widgets.feed
import ac.cord.auxiliary.compose.database.model.InReplyToRelation
import ac.cord.auxiliary.compose.database.model.Mention
import ac.cord.auxiliary.compose.database.model.NostrEvent
import ac.cord.auxiliary.compose.database.model.Profile
import ac.cord.auxiliary.compose.database.model.QuotedRelation
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalInReplyToNostrEvent
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalMention
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalNostrEvent
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalQuotedNostrEvent
import ac.cord.auxiliary.compose.extensions.toFormattedTimeAndDateString
import ac.cord.auxiliary.compose.ui.composable.widgets.content.RichContent
@@ -27,6 +29,7 @@ import androidx.compose.material3.SuggestionChip
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
@@ -44,156 +47,150 @@ internal fun TextNoteFeedItem(
mentionedProfiles: List<LocalMention>,
onNavigateToEvent: (HexKey) -> Unit
) {
if (localInReplyToNostrEvent != null) {
Row(
modifier = Modifier.fillMaxWidth().padding(
horizontal = 20.dp
),
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically
) {
Text(
"In reply to ",
style = MaterialTheme.typography.labelSmall
)
val expended = mutableStateOf(false)
Text(
modifier = Modifier.clickable(
onClick = {
onNavigateToEvent.invoke(localInReplyToNostrEvent.inReplyToRelation.inReplyToNostrEventId)
}
Column {
if (localInReplyToNostrEvent != null) {
Row(
modifier = Modifier.fillMaxWidth().padding(
horizontal = 20.dp
),
style = MaterialTheme.typography.labelLargeEmphasized,
text = localInReplyToNostrEvent.profile?.humanReadableNameOrPubkey() ?: "loading information..."
)
}
}
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically
) {
Text(
"In reply to ",
style = MaterialTheme.typography.labelSmall
)
ElevatedCard(
modifier = Modifier.padding(
horizontal = 10.dp
),
onClick = {
onNavigateToEvent.invoke(nostrEvent.id)
}
) {
Column(
modifier = Modifier.padding(10.dp).fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(10.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
if (profile != null) {
Row(
modifier = Modifier.fillMaxWidth().clickable(
Text(
modifier = Modifier.clickable(
onClick = {
onNavigateToEvent.invoke(profile.nostrEventId)
onNavigateToEvent.invoke(localInReplyToNostrEvent.inReplyToRelation.inReplyToNostrEventId)
}
),
horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.Start),
verticalAlignment = Alignment.CenterVertically
) {
ProfileAvatar(
publicKey = nostrEvent.pubKey,
profile = profile
)
style = MaterialTheme.typography.labelLargeEmphasized,
color = ProfileColor.fromPublicKey(localInReplyToNostrEvent.nostrEvent.pubKey),
text = localInReplyToNostrEvent.profile?.humanReadableNameOrPubkey() ?: "loading information..."
)
}
}
Column(
modifier = Modifier.weight(1f)
){
Text(
text = profile.humanReadableNameOrPubkey(),
style = MaterialTheme.typography.bodyMedium
ElevatedCard(
modifier = Modifier.padding(
horizontal = 10.dp
),
onClick = {
onNavigateToEvent.invoke(nostrEvent.id)
}
) {
Column(
modifier = Modifier.padding(10.dp).fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(10.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
if (profile != null) {
Row(
modifier = Modifier.fillMaxWidth().clickable(
onClick = {
onNavigateToEvent.invoke(profile.nostrEventId)
}
),
horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.Start),
verticalAlignment = Alignment.CenterVertically
) {
ProfileAvatar(
publicKey = nostrEvent.pubKey,
profile = profile
)
profile.staticIdentifier()?.let { staticIdentifier ->
Column(
modifier = Modifier.weight(1f)
){
Text(
text = staticIdentifier,
style = MaterialTheme.typography.bodySmall,
color = ProfileColor.fromProfile(profile)
text = profile.humanReadableNameOrPubkey(),
style = MaterialTheme.typography.bodyMedium
)
profile.staticIdentifier()?.let { staticIdentifier ->
Text(
text = staticIdentifier,
style = MaterialTheme.typography.bodySmall,
color = ProfileColor.fromProfile(profile)
)
}
}
}
} else {
Text(
text = "Loading author information"
)
}
RichContent(
modifier = Modifier.fillMaxWidth(),
nostrEvent = nostrEvent,
localQuotedNostrEvent = localQuotedNostrEvent,
mentionedProfiles = mentionedProfiles,
onNavigateToEvent = onNavigateToEvent
)
if (expended.value) {
LazyRow(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(
10.dp,
alignment = Alignment.Start
)
) {
item {
AssistChip(
label = {
Text(
text = nostrEvent.kind.toString() // TODO: Kind by name...
)
},
onClick = {
}
)
}
items(
items = nostrEvent.tags,
) { tag ->
SuggestionChip(
label = {
Text(
text = tag.joinToString(":"),
maxLines = 1
)
},
onClick = {
}
)
}
}
}
} else {
Text(
text = "Loading author information"
modifier = Modifier.fillMaxWidth(),
style = MaterialTheme.typography.labelLarge,
textAlign = TextAlign.End,
text = nostrEvent.createdAt.toFormattedTimeAndDateString()
)
}
RichContent(
modifier = Modifier.fillMaxWidth(),
nostrEvent = nostrEvent,
localQuotedNostrEvent = localQuotedNostrEvent,
mentionedProfiles = mentionedProfiles
)
LazyRow(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(
10.dp,
alignment = Alignment.Start
)
) {
item {
AssistChip(
label = {
Text(
text = nostrEvent.kind.toString() // TODO: Kind by name...
)
},
onClick = {
}
)
}
// item {
// SuggestionChip(
// label = {
// Text(
// text = if (localNostrEvent.mentionedProfiles.isNotEmpty()) {
// localNostrEvent.mentionedProfiles.joinToString(",") { it?.profile?.humanReadableNameOrPubkey() ?: "Find user information" }
// } else {
// ":-("
// }
// )
// },
// onClick = {
//
// }
// )
// }
items(
items = nostrEvent.tags,
) { tag ->
SuggestionChip(
label = {
Text(
text = tag.joinToString(":"),
maxLines = 1
)
},
onClick = {
}
)
}
}
Text(
modifier = Modifier.fillMaxWidth(),
style = MaterialTheme.typography.labelLarge,
textAlign = TextAlign.End,
text = nostrEvent.createdAt.toFormattedTimeAndDateString()
)
}
}
}
@Preview
@Composable
private fun EventListViewPreview() {
private fun TextNoteFeedItemPreview() {
AuxTheme {
Surface(
modifier = Modifier.padding(20.dp)
@@ -201,7 +198,7 @@ private fun EventListViewPreview() {
TextNoteFeedItem(
nostrEvent = NostrEvent(
id = "hex",
content = "Something something something",
content = "You are either alive and proud or you are dead, and when you are dead, you can't care anyway. https://www.brainyquote.com/authors/steven-biko-quotes",
pubKey = "hexpubkeypubkeypubkeypubkey",
kind = 0,
sig = "hexsig",
@@ -220,4 +217,145 @@ private fun EventListViewPreview() {
)
}
}
}
@Preview
@Composable
private fun TextNoteFeedItemInReplyToPreview() {
AuxTheme {
Surface(
modifier = Modifier.padding(20.dp)
) {
TextNoteFeedItem(
nostrEvent = NostrEvent(
id = "hex",
content = "It is better to die for an idea that will live, than to live for an idea that will die",
pubKey = "hexpubkeypubkeypubkeypubkey",
kind = 0,
sig = "hexsig",
tags = emptyArray()
),
profile = Profile(
publicKey = "",
nostrEventId = "referenced",
displayName = "Frank Talk",
nip05 = "frank@talk.at"
),
localQuotedNostrEvent = null,
localInReplyToNostrEvent = LocalInReplyToNostrEvent(
inReplyToRelation = InReplyToRelation(
inReplyToNostrEventId = "nostrEvent",
inReplyToRootNostrEventId = "rootId",
inReplyToProfilePublicKey = "inReplyToProfileKey",
inReplyToRootProfilePublicKey = "rootPubKey",
replyingNostrEventId = "hex"
),
nostrEvent = NostrEvent(
id = "hex",
content = "Something something something",
pubKey = "hexie",
kind = 0,
sig = "hexsig",
tags = emptyArray()
),
profile = Profile(
publicKey = "hesd",
nostrEventId = "referenced",
displayName = "Steve Biko",
nip05 = "steve@bcm.co.za"
),
mentionedProfiles = emptyList()
),
mentionedProfiles = emptyList(),
onNavigateToEvent = {}
)
}
}
}
@Preview
@Composable
private fun TextNoteFeedItemQuoteNostrEventPreview() {
AuxTheme {
Surface(
modifier = Modifier.padding(20.dp)
) {
TextNoteFeedItem(
nostrEvent = NostrEvent(
id = "hex",
content = "The revolutionary sees his task as liberation not only of the oppressed but also of the oppressor. Happiness can never truly exist in a state of tension.\n" +
"Read more at nostr:npub1uh366qnj68a7atvwgwdy4569xd6v5jtferftapqztwjwlzh9553q47pqsx\nnostr:nevent1qqspcusnzxx5u97xht2udvg3yhcq2cvmc0jrxa90lwwdvjplve0atespzpmhxue69uhkummnw3ezuamfdejsyg8h5g639qhuv803hzwexfwhyud6t6suxfu364anddqvrmn9j4cahvxksr8q",
pubKey = "hexpubkeypubkeypubkeypubkey",
kind = 0,
sig = "hexsig",
tags = emptyArray()
),
profile = Profile(
publicKey = "",
nostrEventId = "referenced",
displayName = "Frank Talk",
nip05 = "frank@talk.at"
),
localQuotedNostrEvent = LocalQuotedNostrEvent(
nostrEvent = NostrEvent(
id = "1c7213118d4e17c6bad5c6b11125f005619bc3e43374affb9cd6483f665fd5e6",
content = "God is not in the habit of coming down from heaven to solve peoples problems on earth.",
pubKey = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a522",
kind = 0,
sig = "hexsig",
tags = emptyArray()
),
quotedRelation = QuotedRelation(
quotingNostrEventId = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a520",
quotedProfilePublicKey = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a522",
quotedNostrEventId = "1c7213118d4e17c6bad5c6b11125f005619bc3e43374affb9cd6483f665fd5e6"
),
profile = Profile(
publicKey = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a522",
nostrEventId = "referenced",
displayName = "Steve Biko"
),
),
localInReplyToNostrEvent = LocalInReplyToNostrEvent(
inReplyToRelation = InReplyToRelation(
inReplyToNostrEventId = "nostrEvent",
inReplyToRootNostrEventId = "rootId",
inReplyToProfilePublicKey = "inReplyToProfileKey",
inReplyToRootProfilePublicKey = "rootPubKey",
replyingNostrEventId = "hex"
),
nostrEvent = NostrEvent(
id = "hex",
content = "Something something something",
pubKey = "hexie",
kind = 0,
sig = "hexsig",
tags = emptyArray()
),
profile = Profile(
publicKey = "hesd",
nostrEventId = "referenced",
displayName = "Steve Biko",
nip05 = "steve@bcm.co.za"
),
mentionedProfiles = emptyList()
),
mentionedProfiles = listOf(
LocalMention(
mention = Mention(
mentioningNostrEventId = "000067b3f15cac88ba066b28c370083a4fc80dacc054e554ab1dc0def974c89c",
mentionedPublicKey = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a522"
),
profile = Profile(
publicKey = "e5e3ad0272d1fbeead8e439a4ad3453374ca4969c8d2be84025ba4ef8ae5a522",
nostrEventId = "referenced",
displayName = "Steve Biko",
nip05 = "steve@bcm.co.za"
),
)
),
onNavigateToEvent = {}
)
}
}
}