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

View File

@ -28,7 +28,6 @@ import com.vitorpamplona.quartz.events.MuteListEvent
import com.vitorpamplona.quartz.events.PeopleListEvent
open class DiscoverNIP89FeedFilter(
val ktag: Int,
val account: Account,
) : AdditiveFeedFilter<Note>() {
override fun feedKey(): String {

View File

@ -89,6 +89,7 @@ import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
import com.vitorpamplona.amethyst.ui.theme.StdPadding
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.quartz.events.AppDefinitionEvent
import com.vitorpamplona.quartz.events.ChannelCreateEvent
import com.vitorpamplona.quartz.events.ClassifiedsEvent
import com.vitorpamplona.quartz.events.CommunityDefinitionEvent
@ -213,6 +214,9 @@ fun InnerChannelCardWithReactions(
is ClassifiedsEvent -> {
InnerCardBox(baseNote, accountViewModel, nav)
}
is AppDefinitionEvent -> {
InnerCardRow(baseNote, accountViewModel, nav)
}
}
}
@ -268,6 +272,9 @@ private fun RenderNoteRow(
is ChannelCreateEvent -> {
RenderChannelThumb(baseNote, accountViewModel, nav)
}
is AppDefinitionEvent -> {
RenderContentDVMThumb(baseNote, accountViewModel, nav)
}
}
}
@ -516,6 +523,14 @@ data class CommunityCard(
val moderators: ImmutableList<Participant>,
)
@Immutable
data class DVMCard(
val name: String,
val description: String?,
val cover: String?,
val moderators: ImmutableList<Participant>,
)
@Composable
fun RenderCommunitiesThumb(
baseNote: Note,
@ -715,6 +730,94 @@ private fun LoadParticipants(
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
fun RenderChannelThumb(
baseNote: Note,

View File

@ -234,3 +234,25 @@ fun LoadChannel(
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) }
}

View File

@ -70,8 +70,8 @@ import com.vitorpamplona.amethyst.ui.theme.Size16Modifier
import com.vitorpamplona.amethyst.ui.theme.Size35dp
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.quartz.events.AppDefinitionEvent
import com.vitorpamplona.quartz.events.AppMetadata
import com.vitorpamplona.quartz.events.EmptyTagList
import com.vitorpamplona.quartz.events.UserMetadata
import com.vitorpamplona.quartz.events.toImmutableListOfLists
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@ -85,7 +85,7 @@ fun RenderAppDefinition(
) {
val noteEvent = note.event as? AppDefinitionEvent ?: return
var metadata by remember { mutableStateOf<UserMetadata?>(null) }
var metadata by remember { mutableStateOf<AppMetadata?>(null) }
LaunchedEffect(key1 = noteEvent) {
withContext(Dispatchers.Default) { metadata = noteEvent.appMetaData() }

View File

@ -112,7 +112,7 @@ class NostrDiscoverMarketplaceFeedViewModel(val account: Account) :
class NostrDiscoverNIP89FeedViewModel(val account: Account) :
FeedViewModel(
DiscoverNIP89FeedFilter(5003, account),
DiscoverNIP89FeedFilter(account),
) {
class Factory(val account: Account) : ViewModelProvider.Factory {
override fun <NostrDiscoverNIP89FeedViewModel : ViewModel> create(modelClass: Class<NostrDiscoverNIP89FeedViewModel>): NostrDiscoverNIP89FeedViewModel {

View File

@ -22,11 +22,94 @@ package com.vitorpamplona.quartz.events
import android.util.Log
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.signers.NostrSigner
import com.vitorpamplona.quartz.utils.TimeUtils
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
class AppDefinitionEvent(
id: HexKey,
@ -36,7 +119,7 @@ class AppDefinitionEvent(
content: String,
sig: HexKey,
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
@Transient private var cachedMetadata: UserMetadata? = null
@Transient private var cachedMetadata: AppMetadata? = null
fun appMetaData() =
if (cachedMetadata != null) {
@ -46,7 +129,7 @@ class AppDefinitionEvent(
val newMetadata =
mapper.readValue(
ByteArrayInputStream(content.toByteArray(Charsets.UTF_8)),
UserMetadata::class.java,
AppMetadata::class.java,
)
cachedMetadata = newMetadata