mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-03-26 17:52:29 +01:00
app meta data, show content dvms
This commit is contained in:
parent
357981f266
commit
334b948900
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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) }
|
||||
}
|
||||
|
@ -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() }
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user