app meta data, show content dvms

This commit is contained in:
Believethehype
2024-05-13 17:27:34 +02:00
parent 357981f266
commit 334b948900
6 changed files with 213 additions and 6 deletions
@@ -28,7 +28,6 @@ import com.vitorpamplona.quartz.events.MuteListEvent
import com.vitorpamplona.quartz.events.PeopleListEvent import com.vitorpamplona.quartz.events.PeopleListEvent
open class DiscoverNIP89FeedFilter( open class DiscoverNIP89FeedFilter(
val ktag: Int,
val account: Account, val account: Account,
) : AdditiveFeedFilter<Note>() { ) : AdditiveFeedFilter<Note>() {
override fun feedKey(): String { override fun feedKey(): String {
@@ -89,6 +89,7 @@ import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
import com.vitorpamplona.amethyst.ui.theme.StdPadding import com.vitorpamplona.amethyst.ui.theme.StdPadding
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.quartz.events.AppDefinitionEvent
import com.vitorpamplona.quartz.events.ChannelCreateEvent import com.vitorpamplona.quartz.events.ChannelCreateEvent
import com.vitorpamplona.quartz.events.ClassifiedsEvent import com.vitorpamplona.quartz.events.ClassifiedsEvent
import com.vitorpamplona.quartz.events.CommunityDefinitionEvent import com.vitorpamplona.quartz.events.CommunityDefinitionEvent
@@ -213,6 +214,9 @@ fun InnerChannelCardWithReactions(
is ClassifiedsEvent -> { is ClassifiedsEvent -> {
InnerCardBox(baseNote, accountViewModel, nav) InnerCardBox(baseNote, accountViewModel, nav)
} }
is AppDefinitionEvent -> {
InnerCardRow(baseNote, accountViewModel, nav)
}
} }
} }
@@ -268,6 +272,9 @@ private fun RenderNoteRow(
is ChannelCreateEvent -> { is ChannelCreateEvent -> {
RenderChannelThumb(baseNote, accountViewModel, nav) RenderChannelThumb(baseNote, accountViewModel, nav)
} }
is AppDefinitionEvent -> {
RenderContentDVMThumb(baseNote, accountViewModel, nav)
}
} }
} }
@@ -516,6 +523,14 @@ data class CommunityCard(
val moderators: ImmutableList<Participant>, val moderators: ImmutableList<Participant>,
) )
@Immutable
data class DVMCard(
val name: String,
val description: String?,
val cover: String?,
val moderators: ImmutableList<Participant>,
)
@Composable @Composable
fun RenderCommunitiesThumb( fun RenderCommunitiesThumb(
baseNote: Note, baseNote: Note,
@@ -715,6 +730,94 @@ private fun LoadParticipants(
inner(participantUsers) inner(participantUsers)
} }
@Composable
fun RenderContentDVMThumb(
baseNote: Note,
accountViewModel: AccountViewModel,
nav: (String) -> Unit,
) {
val noteEvent = baseNote.event as? AppDefinitionEvent ?: return
val card by
baseNote
.live()
.metadata
.map {
val noteEvent = it.note.event as? AppDefinitionEvent
DVMCard(
name = noteEvent?.appMetaData()?.name ?: "",
description = noteEvent?.appMetaData()?.about ?: "",
cover = noteEvent?.appMetaData()?.image?.ifBlank { null },
moderators = persistentListOf(),
)
}
.distinctUntilChanged()
.observeAsState(
DVMCard(
name = noteEvent.appMetaData()?.name ?: "",
description = noteEvent.appMetaData()?.about ?: "",
cover = noteEvent.appMetaData()?.image?.ifBlank { null },
moderators = persistentListOf(),
),
)
LeftPictureLayout(
onImage = {
card.cover?.let {
Box(contentAlignment = BottomStart) {
AsyncImage(
model = it,
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize().clip(QuoteBorder),
)
}
} ?: run { DisplayAuthorBanner(baseNote) }
},
onTitleRow = {
Text(
text = card.name,
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f),
)
Spacer(modifier = StdHorzSpacer)
LikeReaction(
baseNote = baseNote,
grayTint = MaterialTheme.colorScheme.onSurface,
accountViewModel = accountViewModel,
nav,
)
Spacer(modifier = StdHorzSpacer)
ZapReaction(
baseNote = baseNote,
grayTint = MaterialTheme.colorScheme.onSurface,
accountViewModel = accountViewModel,
nav = nav,
)
},
onDescription = {
card.description?.let {
Spacer(modifier = StdVertSpacer)
Row {
Text(
text = it,
color = MaterialTheme.colorScheme.placeholderText,
maxLines = 3,
overflow = TextOverflow.Ellipsis,
fontSize = 14.sp,
)
}
}
},
onBottomRow = {
},
)
}
@Composable @Composable
fun RenderChannelThumb( fun RenderChannelThumb(
baseNote: Note, baseNote: Note,
@@ -234,3 +234,25 @@ fun LoadChannel(
channel?.let { content(it) } channel?.let { content(it) }
} }
@Composable
fun LoadDVMNip89(
baseChannelHex: String,
accountViewModel: AccountViewModel,
content: @Composable (Channel) -> Unit,
) {
var channel by
remember(baseChannelHex) {
mutableStateOf<Channel?>(accountViewModel.getChannelIfExists(baseChannelHex))
}
if (channel == null) {
LaunchedEffect(key1 = baseChannelHex) {
accountViewModel.checkGetOrCreateChannel(baseChannelHex) { newChannel ->
launch(Dispatchers.Main) { channel = newChannel }
}
}
}
channel?.let { content(it) }
}
@@ -70,8 +70,8 @@ import com.vitorpamplona.amethyst.ui.theme.Size16Modifier
import com.vitorpamplona.amethyst.ui.theme.Size35dp import com.vitorpamplona.amethyst.ui.theme.Size35dp
import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.quartz.events.AppDefinitionEvent import com.vitorpamplona.quartz.events.AppDefinitionEvent
import com.vitorpamplona.quartz.events.AppMetadata
import com.vitorpamplona.quartz.events.EmptyTagList import com.vitorpamplona.quartz.events.EmptyTagList
import com.vitorpamplona.quartz.events.UserMetadata
import com.vitorpamplona.quartz.events.toImmutableListOfLists import com.vitorpamplona.quartz.events.toImmutableListOfLists
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@@ -85,7 +85,7 @@ fun RenderAppDefinition(
) { ) {
val noteEvent = note.event as? AppDefinitionEvent ?: return val noteEvent = note.event as? AppDefinitionEvent ?: return
var metadata by remember { mutableStateOf<UserMetadata?>(null) } var metadata by remember { mutableStateOf<AppMetadata?>(null) }
LaunchedEffect(key1 = noteEvent) { LaunchedEffect(key1 = noteEvent) {
withContext(Dispatchers.Default) { metadata = noteEvent.appMetaData() } withContext(Dispatchers.Default) { metadata = noteEvent.appMetaData() }
@@ -112,7 +112,7 @@ class NostrDiscoverMarketplaceFeedViewModel(val account: Account) :
class NostrDiscoverNIP89FeedViewModel(val account: Account) : class NostrDiscoverNIP89FeedViewModel(val account: Account) :
FeedViewModel( FeedViewModel(
DiscoverNIP89FeedFilter(5003, account), DiscoverNIP89FeedFilter(account),
) { ) {
class Factory(val account: Account) : ViewModelProvider.Factory { class Factory(val account: Account) : ViewModelProvider.Factory {
override fun <NostrDiscoverNIP89FeedViewModel : ViewModel> create(modelClass: Class<NostrDiscoverNIP89FeedViewModel>): NostrDiscoverNIP89FeedViewModel { override fun <NostrDiscoverNIP89FeedViewModel : ViewModel> create(modelClass: Class<NostrDiscoverNIP89FeedViewModel>): NostrDiscoverNIP89FeedViewModel {
@@ -22,11 +22,94 @@ package com.vitorpamplona.quartz.events
import android.util.Log import android.util.Log
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import com.fasterxml.jackson.annotation.JsonProperty
import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.encoders.HexKey
import com.vitorpamplona.quartz.signers.NostrSigner import com.vitorpamplona.quartz.signers.NostrSigner
import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.TimeUtils
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
@Stable
class AppMetadata {
var name: String? = null
var username: String? = null
@JsonProperty("display_name")
var displayName: String? = null
var picture: String? = null
var banner: String? = null
var image: String? = null
var website: String? = null
var about: String? = null
var subscription: Boolean? = false
var cashuAccepted: Boolean? = false
var encryptionSupported: Boolean? = false
var personalized: Boolean? = false
var amount: String? = null
var nip05: String? = null
var domain: String? = null
var lud06: String? = null
var lud16: String? = null
var twitter: String? = null
@Transient
var tags: ImmutableListOfLists<String>? = null
fun anyName(): String? {
return displayName ?: name ?: username
}
fun anyNameStartsWith(prefix: String): Boolean {
return listOfNotNull(name, username, displayName, nip05, lud06, lud16).any {
it.contains(prefix, true)
}
}
fun lnAddress(): String? {
return lud16 ?: lud06
}
fun bestName(): String? {
return displayName ?: name ?: username
}
fun nip05(): String? {
return nip05
}
fun profilePicture(): String? {
return picture
}
fun cleanBlankNames() {
if (picture?.isNotEmpty() == true) picture = picture?.trim()
if (nip05?.isNotEmpty() == true) nip05 = nip05?.trim()
if (displayName?.isNotEmpty() == true) displayName = displayName?.trim()
if (name?.isNotEmpty() == true) name = name?.trim()
if (username?.isNotEmpty() == true) username = username?.trim()
if (lud06?.isNotEmpty() == true) lud06 = lud06?.trim()
if (lud16?.isNotEmpty() == true) lud16 = lud16?.trim()
if (website?.isNotEmpty() == true) website = website?.trim()
if (domain?.isNotEmpty() == true) domain = domain?.trim()
if (picture?.isBlank() == true) picture = null
if (nip05?.isBlank() == true) nip05 = null
if (displayName?.isBlank() == true) displayName = null
if (name?.isBlank() == true) name = null
if (username?.isBlank() == true) username = null
if (lud06?.isBlank() == true) lud06 = null
if (lud16?.isBlank() == true) lud16 = null
if (website?.isBlank() == true) website = null
if (domain?.isBlank() == true) domain = null
}
}
@Immutable @Immutable
class AppDefinitionEvent( class AppDefinitionEvent(
id: HexKey, id: HexKey,
@@ -36,7 +119,7 @@ class AppDefinitionEvent(
content: String, content: String,
sig: HexKey, sig: HexKey,
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { ) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
@Transient private var cachedMetadata: UserMetadata? = null @Transient private var cachedMetadata: AppMetadata? = null
fun appMetaData() = fun appMetaData() =
if (cachedMetadata != null) { if (cachedMetadata != null) {
@@ -46,7 +129,7 @@ class AppDefinitionEvent(
val newMetadata = val newMetadata =
mapper.readValue( mapper.readValue(
ByteArrayInputStream(content.toByteArray(Charsets.UTF_8)), ByteArrayInputStream(content.toByteArray(Charsets.UTF_8)),
UserMetadata::class.java, AppMetadata::class.java,
) )
cachedMetadata = newMetadata cachedMetadata = newMetadata