mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-03-26 17:52:29 +01:00
use alternative gallery using 1163 events instead of 10011 lists.
(This might still need some tuning but works in general)
This commit is contained in:
parent
06a1862d17
commit
511a7030b8
@ -71,7 +71,6 @@ import com.vitorpamplona.quartz.events.FileHeaderEvent
|
||||
import com.vitorpamplona.quartz.events.FileServersEvent
|
||||
import com.vitorpamplona.quartz.events.FileStorageEvent
|
||||
import com.vitorpamplona.quartz.events.FileStorageHeaderEvent
|
||||
import com.vitorpamplona.quartz.events.GalleryListEvent
|
||||
import com.vitorpamplona.quartz.events.GeneralListEvent
|
||||
import com.vitorpamplona.quartz.events.GenericRepostEvent
|
||||
import com.vitorpamplona.quartz.events.GiftWrapEvent
|
||||
@ -92,6 +91,7 @@ import com.vitorpamplona.quartz.events.PollNoteEvent
|
||||
import com.vitorpamplona.quartz.events.Price
|
||||
import com.vitorpamplona.quartz.events.PrivateDmEvent
|
||||
import com.vitorpamplona.quartz.events.PrivateOutboxRelayListEvent
|
||||
import com.vitorpamplona.quartz.events.ProfileGalleryEntryEvent
|
||||
import com.vitorpamplona.quartz.events.ReactionEvent
|
||||
import com.vitorpamplona.quartz.events.RelayAuthEvent
|
||||
import com.vitorpamplona.quartz.events.ReportEvent
|
||||
@ -2204,48 +2204,27 @@ class Account(
|
||||
relay: String?,
|
||||
) {
|
||||
if (!isWriteable()) return
|
||||
|
||||
GalleryListEvent.addEvent(
|
||||
userProfile().latestGalleryList,
|
||||
idHex,
|
||||
url,
|
||||
relay,
|
||||
signer,
|
||||
) {
|
||||
Client.send(it)
|
||||
LocalCache.consume(it)
|
||||
ProfileGalleryEntryEvent.create(
|
||||
url = url,
|
||||
eventid = idHex,
|
||||
/*magnetUri = magnetUri,
|
||||
mimeType = headerInfo.mimeType,
|
||||
hash = headerInfo.hash,
|
||||
size = headerInfo.size.toString(),
|
||||
dimensions = headerInfo.dim,
|
||||
blurhash = headerInfo.blurHash,
|
||||
alt = alt,
|
||||
originalHash = originalHash,
|
||||
sensitiveContent = sensitiveContent, */
|
||||
signer = signer,
|
||||
) { event ->
|
||||
Client.send(event)
|
||||
LocalCache.consume(event, null)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeFromGallery(
|
||||
note: Note,
|
||||
url: String,
|
||||
) {
|
||||
if (!isWriteable()) return
|
||||
|
||||
val galleryentries = userProfile().latestGalleryList ?: return
|
||||
|
||||
if (note is AddressableNote) {
|
||||
GalleryListEvent.removeReplaceable(
|
||||
galleryentries,
|
||||
note.address,
|
||||
url,
|
||||
signer,
|
||||
) {
|
||||
Client.send(it)
|
||||
LocalCache.consume(it)
|
||||
}
|
||||
} else {
|
||||
GalleryListEvent.removeEvent(
|
||||
galleryentries,
|
||||
note.idHex,
|
||||
url,
|
||||
signer,
|
||||
) {
|
||||
Client.send(it)
|
||||
LocalCache.consume(it)
|
||||
}
|
||||
}
|
||||
fun removeFromGallery(note: Note) {
|
||||
delete(note)
|
||||
}
|
||||
|
||||
fun addBookmark(
|
||||
|
@ -75,7 +75,6 @@ import com.vitorpamplona.quartz.events.FileHeaderEvent
|
||||
import com.vitorpamplona.quartz.events.FileServersEvent
|
||||
import com.vitorpamplona.quartz.events.FileStorageEvent
|
||||
import com.vitorpamplona.quartz.events.FileStorageHeaderEvent
|
||||
import com.vitorpamplona.quartz.events.GalleryListEvent
|
||||
import com.vitorpamplona.quartz.events.GenericRepostEvent
|
||||
import com.vitorpamplona.quartz.events.GiftWrapEvent
|
||||
import com.vitorpamplona.quartz.events.GitIssueEvent
|
||||
@ -104,6 +103,7 @@ import com.vitorpamplona.quartz.events.PinListEvent
|
||||
import com.vitorpamplona.quartz.events.PollNoteEvent
|
||||
import com.vitorpamplona.quartz.events.PrivateDmEvent
|
||||
import com.vitorpamplona.quartz.events.PrivateOutboxRelayListEvent
|
||||
import com.vitorpamplona.quartz.events.ProfileGalleryEntryEvent
|
||||
import com.vitorpamplona.quartz.events.ReactionEvent
|
||||
import com.vitorpamplona.quartz.events.RecommendRelayEvent
|
||||
import com.vitorpamplona.quartz.events.RelaySetEvent
|
||||
@ -424,17 +424,6 @@ object LocalCache {
|
||||
}
|
||||
}
|
||||
|
||||
fun consume(event: GalleryListEvent) {
|
||||
val user = getOrCreateUser(event.pubKey)
|
||||
if (user.latestGalleryList == null || event.createdAt > user.latestGalleryList!!.createdAt) {
|
||||
user.updateGallery(event)
|
||||
// Log.d("MT", "New User Metadata ${oldUser.pubkeyDisplayHex} ${oldUser.toBestDisplayName()}")
|
||||
} else {
|
||||
// Log.d("MT","Relay sent a previous Metadata Event ${oldUser.toBestDisplayName()}
|
||||
// ${formattedDateTime(event.createdAt)} > ${formattedDateTime(oldUser.updatedAt)}")
|
||||
}
|
||||
}
|
||||
|
||||
fun formattedDateTime(timestamp: Long): String =
|
||||
Instant
|
||||
.ofEpochSecond(timestamp)
|
||||
@ -1680,6 +1669,26 @@ object LocalCache {
|
||||
refreshObservers(note)
|
||||
}
|
||||
|
||||
fun consume(
|
||||
event: ProfileGalleryEntryEvent,
|
||||
relay: Relay?,
|
||||
) {
|
||||
val note = getOrCreateNote(event.id)
|
||||
val author = getOrCreateUser(event.pubKey)
|
||||
|
||||
if (relay != null) {
|
||||
author.addRelayBeingUsed(relay, event.createdAt)
|
||||
note.addRelay(relay)
|
||||
}
|
||||
|
||||
// Already processed this event.
|
||||
if (note.event != null) return
|
||||
|
||||
note.loadEvent(event, author, emptyList())
|
||||
|
||||
refreshObservers(note)
|
||||
}
|
||||
|
||||
fun consume(
|
||||
event: FileStorageHeaderEvent,
|
||||
relay: Relay?,
|
||||
@ -2535,13 +2544,13 @@ object LocalCache {
|
||||
is DraftEvent -> consume(event, relay)
|
||||
is EmojiPackEvent -> consume(event, relay)
|
||||
is EmojiPackSelectionEvent -> consume(event, relay)
|
||||
is GalleryListEvent -> consume(event)
|
||||
is GenericRepostEvent -> {
|
||||
event.containedPost()?.let { verifyAndConsume(it, relay) }
|
||||
consume(event)
|
||||
}
|
||||
is FhirResourceEvent -> consume(event, relay)
|
||||
is FileHeaderEvent -> consume(event, relay)
|
||||
is ProfileGalleryEntryEvent -> consume(event, relay)
|
||||
is FileServersEvent -> consume(event, relay)
|
||||
is FileStorageEvent -> consume(event, relay)
|
||||
is FileStorageHeaderEvent -> consume(event, relay)
|
||||
|
@ -139,7 +139,7 @@ open class Note(
|
||||
var relays = listOf<RelayBriefInfoCache.RelayBriefInfo>()
|
||||
private set
|
||||
|
||||
var headerImage: String? = null
|
||||
var associatedNote: Note? = null
|
||||
|
||||
var lastReactionsDownloadTime: Map<String, EOSETime> = emptyMap()
|
||||
|
||||
|
@ -40,7 +40,6 @@ import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent
|
||||
import com.vitorpamplona.quartz.events.BookmarkListEvent
|
||||
import com.vitorpamplona.quartz.events.ChatroomKey
|
||||
import com.vitorpamplona.quartz.events.ContactListEvent
|
||||
import com.vitorpamplona.quartz.events.GalleryListEvent
|
||||
import com.vitorpamplona.quartz.events.LnZapEvent
|
||||
import com.vitorpamplona.quartz.events.MetadataEvent
|
||||
import com.vitorpamplona.quartz.events.ReportEvent
|
||||
@ -61,7 +60,6 @@ class User(
|
||||
var latestMetadataRelay: String? = null
|
||||
var latestContactList: ContactListEvent? = null
|
||||
var latestBookmarkList: BookmarkListEvent? = null
|
||||
var latestGalleryList: GalleryListEvent? = null
|
||||
|
||||
var reports = mapOf<User, Set<Note>>()
|
||||
private set
|
||||
@ -125,13 +123,6 @@ class User(
|
||||
liveSet?.innerBookmarks?.invalidateData()
|
||||
}
|
||||
|
||||
fun updateGallery(event: GalleryListEvent) {
|
||||
if (event.id == latestGalleryList?.id) return
|
||||
print("GALLERY " + event.id())
|
||||
latestGalleryList = event
|
||||
liveSet?.innerGallery?.invalidateData()
|
||||
}
|
||||
|
||||
fun clearEOSE() {
|
||||
latestEOSEs = emptyMap()
|
||||
}
|
||||
|
@ -31,7 +31,6 @@ import com.vitorpamplona.quartz.events.BadgeAwardEvent
|
||||
import com.vitorpamplona.quartz.events.BadgeProfilesEvent
|
||||
import com.vitorpamplona.quartz.events.BookmarkListEvent
|
||||
import com.vitorpamplona.quartz.events.ContactListEvent
|
||||
import com.vitorpamplona.quartz.events.GalleryListEvent
|
||||
import com.vitorpamplona.quartz.events.GenericRepostEvent
|
||||
import com.vitorpamplona.quartz.events.HighlightEvent
|
||||
import com.vitorpamplona.quartz.events.LnZapEvent
|
||||
@ -40,6 +39,7 @@ import com.vitorpamplona.quartz.events.MetadataEvent
|
||||
import com.vitorpamplona.quartz.events.PeopleListEvent
|
||||
import com.vitorpamplona.quartz.events.PinListEvent
|
||||
import com.vitorpamplona.quartz.events.PollNoteEvent
|
||||
import com.vitorpamplona.quartz.events.ProfileGalleryEntryEvent
|
||||
import com.vitorpamplona.quartz.events.RepostEvent
|
||||
import com.vitorpamplona.quartz.events.TextNoteEvent
|
||||
import com.vitorpamplona.quartz.events.WikiNoteEvent
|
||||
@ -84,7 +84,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") {
|
||||
WikiNoteEvent.KIND,
|
||||
),
|
||||
authors = listOf(it.pubkeyHex),
|
||||
limit = 200,
|
||||
limit = 500,
|
||||
),
|
||||
)
|
||||
}
|
||||
@ -147,13 +147,27 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") {
|
||||
filter =
|
||||
Filter(
|
||||
kinds =
|
||||
listOf(BookmarkListEvent.KIND, PeopleListEvent.KIND, AppRecommendationEvent.KIND, GalleryListEvent.KIND),
|
||||
listOf(BookmarkListEvent.KIND, PeopleListEvent.KIND, AppRecommendationEvent.KIND),
|
||||
authors = listOf(it.pubkeyHex),
|
||||
limit = 100,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun createProfileGalleryFilter() =
|
||||
user?.let {
|
||||
TypedFilter(
|
||||
types = COMMON_FEED_TYPES,
|
||||
filter =
|
||||
Filter(
|
||||
kinds =
|
||||
listOf(ProfileGalleryEntryEvent.KIND),
|
||||
authors = listOf(it.pubkeyHex),
|
||||
limit = 1000,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun createReceivedAwardsFilter() =
|
||||
user?.let {
|
||||
TypedFilter(
|
||||
@ -174,6 +188,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") {
|
||||
listOfNotNull(
|
||||
createUserInfoFilter(),
|
||||
createUserPostsFilter(),
|
||||
createProfileGalleryFilter(),
|
||||
createFollowFilter(),
|
||||
createFollowersFilter(),
|
||||
createUserReceivedZapsFilter(),
|
||||
|
@ -24,47 +24,65 @@ import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.ammolite.relays.FeedType
|
||||
import com.vitorpamplona.ammolite.relays.Relay
|
||||
import com.vitorpamplona.quartz.events.MuteListEvent
|
||||
import com.vitorpamplona.quartz.events.PeopleListEvent
|
||||
import com.vitorpamplona.quartz.events.ProfileGalleryEntryEvent
|
||||
|
||||
class UserProfileGalleryFeedFilter(
|
||||
val user: User,
|
||||
val account: Account,
|
||||
) : FeedFilter<Note>() {
|
||||
override fun feedKey(): String = account.userProfile().pubkeyHex + "-Gallery-" + user.pubkeyHex
|
||||
) : AdditiveFeedFilter<Note>() {
|
||||
override fun feedKey(): String = account.userProfile().pubkeyHex + "-" + account.defaultStoriesFollowList.value
|
||||
|
||||
override fun showHiddenKey(): Boolean =
|
||||
account.defaultStoriesFollowList.value == PeopleListEvent.blockListFor(account.userProfile().pubkeyHex) ||
|
||||
account.defaultStoriesFollowList.value == MuteListEvent.blockListFor(account.userProfile().pubkeyHex)
|
||||
|
||||
override fun feed(): List<Note> {
|
||||
val params = buildFilterParams(account)
|
||||
|
||||
val notes =
|
||||
user.latestGalleryList
|
||||
?.taggedGalleryEntries()
|
||||
?.map {
|
||||
Triple(
|
||||
// (
|
||||
// if (ATag.isATag(it.id)) {
|
||||
// ATag.parse(it.id, null)?.let { it1 -> LocalCache.getOrCreateAddressableNote(it1) }
|
||||
// } else {
|
||||
LocalCache.getOrCreateNote(it.id),
|
||||
// }
|
||||
// )!!
|
||||
it.url,
|
||||
it.relay,
|
||||
)
|
||||
}?.toSet()
|
||||
?: emptySet()
|
||||
LocalCache.notes.filterIntoSet { _, it ->
|
||||
acceptableEvent(it, params, user)
|
||||
}
|
||||
|
||||
var finalnotes = setOf<Note>()
|
||||
for (pair in notes) {
|
||||
pair.first.headerImage = pair.second
|
||||
if (pair.third != null) {
|
||||
val relay = Relay(pair.third!!, true, false, setOf(FeedType.GLOBAL))
|
||||
pair.first.createdAt()?.let { user.addRelayBeingUsed(relay, it) }
|
||||
pair.first.addRelay(relay)
|
||||
}
|
||||
finalnotes = finalnotes + pair.first
|
||||
for (item in notes) {
|
||||
item.associatedNote = (item.event as ProfileGalleryEntryEvent).event()?.let { LocalCache.getOrCreateNote(it) }
|
||||
finalnotes = finalnotes + item
|
||||
}
|
||||
println(finalnotes)
|
||||
|
||||
return (finalnotes)
|
||||
.filter { account.isAcceptable(it) }
|
||||
return sort(finalnotes)
|
||||
}
|
||||
|
||||
override fun applyFilter(collection: Set<Note>): Set<Note> = innerApplyFilter(collection)
|
||||
|
||||
private fun innerApplyFilter(collection: Collection<Note>): Set<Note> {
|
||||
val params = buildFilterParams(account)
|
||||
|
||||
return collection.filterTo(HashSet()) { acceptableEvent(it, params, user) }
|
||||
}
|
||||
|
||||
fun acceptableEvent(
|
||||
it: Note,
|
||||
params: FilterByListParams,
|
||||
user: User,
|
||||
): Boolean {
|
||||
val noteEvent = it.event
|
||||
return (
|
||||
(it.event?.pubKey() == user.pubkeyHex && noteEvent is ProfileGalleryEntryEvent) && noteEvent.hasUrl() && noteEvent.hasEvent() // && noteEvent.isOneOf(SUPPORTED_VIDEO_FEED_MIME_TYPES_SET))
|
||||
) &&
|
||||
params.match(noteEvent) &&
|
||||
account.isAcceptable(it)
|
||||
}
|
||||
|
||||
fun buildFilterParams(account: Account): FilterByListParams =
|
||||
FilterByListParams.create(
|
||||
userHex = account.userProfile().pubkeyHex,
|
||||
selectedListName = account.defaultStoriesFollowList.value,
|
||||
followLists = account.liveStoriesFollowLists.value,
|
||||
hiddenUsers = account.flowHiddenUsers.value,
|
||||
)
|
||||
|
||||
override fun sort(collection: Set<Note>): List<Note> = collection.sortedWith(DefaultFeedOrder)
|
||||
}
|
||||
|
@ -671,11 +671,7 @@ fun DeleteFromGalleryDialog(
|
||||
buttonIcon = Icons.Default.Delete,
|
||||
buttonText = stringRes(R.string.quick_action_delete_dialog_btn),
|
||||
onClickDoOnce = {
|
||||
note.headerImage.let {
|
||||
if (it != null) {
|
||||
accountViewModel.removefromMediaGallery(note, it)
|
||||
}
|
||||
}
|
||||
accountViewModel.removefromMediaGallery(note)
|
||||
onDismiss()
|
||||
},
|
||||
onDismiss = onDismiss,
|
||||
|
@ -677,11 +677,8 @@ class AccountViewModel(
|
||||
viewModelScope.launch(Dispatchers.IO) { account.addToGallery(hex, url, relay) }
|
||||
}
|
||||
|
||||
fun removefromMediaGallery(
|
||||
note: Note,
|
||||
url: String,
|
||||
) {
|
||||
viewModelScope.launch(Dispatchers.IO) { account.removeFromGallery(note, url) }
|
||||
fun removefromMediaGallery(note: Note) {
|
||||
viewModelScope.launch(Dispatchers.IO) { account.removeFromGallery(note) }
|
||||
}
|
||||
|
||||
fun addPrivateBookmark(note: Note) {
|
||||
|
@ -33,7 +33,6 @@ import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyGridState
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
@ -74,7 +73,7 @@ import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
||||
import com.vitorpamplona.amethyst.ui.theme.HalfPadding
|
||||
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
||||
import com.vitorpamplona.quartz.events.TextNoteEvent
|
||||
import com.vitorpamplona.quartz.events.ProfileGalleryEntryEvent
|
||||
|
||||
@Composable
|
||||
fun RenderGalleryFeed(
|
||||
@ -134,27 +133,45 @@ private fun GalleryFeedLoaded(
|
||||
itemsIndexed(state.feed.value, key = { _, item -> item.idHex }) { _, item ->
|
||||
val defaultModifier = remember { Modifier.fillMaxWidth().animateItemPlacement() }
|
||||
|
||||
Row(defaultModifier) {
|
||||
GalleryCardCompose(
|
||||
baseNote = item,
|
||||
routeForLastRead = routeForLastRead,
|
||||
modifier = Modifier,
|
||||
forceEventKind = forceEventKind,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
if (item.associatedNote != null) {
|
||||
if (item.associatedNote!!.event != null) {
|
||||
if ((item.event as ProfileGalleryEntryEvent).hasUrl() &&
|
||||
(item.event as ProfileGalleryEntryEvent).hasEvent()
|
||||
) {
|
||||
val image = (item.event as ProfileGalleryEntryEvent).url()
|
||||
|
||||
HorizontalDivider(
|
||||
thickness = DividerThickness,
|
||||
)
|
||||
Row(defaultModifier) {
|
||||
if (image != null) {
|
||||
GalleryCardCompose(
|
||||
galleryNote = item,
|
||||
image = image,
|
||||
baseNote = item.associatedNote!!,
|
||||
routeForLastRead = routeForLastRead,
|
||||
modifier = Modifier,
|
||||
forceEventKind = forceEventKind,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider(
|
||||
thickness = DividerThickness,
|
||||
)
|
||||
} else {
|
||||
accountViewModel.delete(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun GalleryCardCompose(
|
||||
galleryNote: Note,
|
||||
baseNote: Note,
|
||||
image: String,
|
||||
routeForLastRead: String? = null,
|
||||
modifier: Modifier = Modifier,
|
||||
parentBackgroundColor: MutableState<Color>? = null,
|
||||
@ -172,8 +189,11 @@ fun GalleryCardCompose(
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
) { canPreview ->
|
||||
|
||||
GalleryCard(
|
||||
galleryNote = galleryNote,
|
||||
baseNote = baseNote,
|
||||
image = image,
|
||||
modifier = modifier,
|
||||
parentBackgroundColor = parentBackgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
@ -185,16 +205,19 @@ fun GalleryCardCompose(
|
||||
|
||||
@Composable
|
||||
fun GalleryCard(
|
||||
galleryNote: Note,
|
||||
baseNote: Note,
|
||||
image: String,
|
||||
modifier: Modifier = Modifier,
|
||||
parentBackgroundColor: MutableState<Color>? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
// baseNote.event?.let { Text(text = it.pubKey()) }
|
||||
LongPressToQuickActionGallery(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup ->
|
||||
LongPressToQuickActionGallery(baseNote = galleryNote, accountViewModel = accountViewModel) { showPopup ->
|
||||
CheckNewAndRenderChannelCard(
|
||||
baseNote,
|
||||
image,
|
||||
modifier,
|
||||
parentBackgroundColor,
|
||||
accountViewModel,
|
||||
@ -207,6 +230,7 @@ fun GalleryCard(
|
||||
@Composable
|
||||
private fun CheckNewAndRenderChannelCard(
|
||||
baseNote: Note,
|
||||
image: String,
|
||||
modifier: Modifier = Modifier,
|
||||
parentBackgroundColor: MutableState<Color>? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
@ -228,26 +252,14 @@ private fun CheckNewAndRenderChannelCard(
|
||||
showPopup = showPopup,
|
||||
nav = nav,
|
||||
) {
|
||||
InnerGalleryCardWithReactions(
|
||||
baseNote = baseNote,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
InnerGalleryCardBox(baseNote, image, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun InnerGalleryCardWithReactions(
|
||||
baseNote: Note,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
InnerGalleryCardBox(baseNote, accountViewModel, nav)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun InnerGalleryCardBox(
|
||||
baseNote: Note,
|
||||
image: String,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
@ -256,7 +268,7 @@ fun InnerGalleryCardBox(
|
||||
note = baseNote,
|
||||
accountViewModel = accountViewModel,
|
||||
) {
|
||||
RenderGalleryThumb(baseNote, accountViewModel, nav)
|
||||
RenderGalleryThumb(baseNote, image, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -272,21 +284,19 @@ data class GalleryThumb(
|
||||
@Composable
|
||||
fun RenderGalleryThumb(
|
||||
baseNote: Note,
|
||||
image: String,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
val noteEvent = baseNote.event as? TextNoteEvent ?: return
|
||||
|
||||
val card by
|
||||
baseNote
|
||||
.live()
|
||||
.metadata
|
||||
.map {
|
||||
val noteEvent = baseNote.event as TextNoteEvent
|
||||
GalleryThumb(
|
||||
id = "",
|
||||
image = baseNote.headerImage,
|
||||
title = noteEvent.content(),
|
||||
image = image,
|
||||
title = "",
|
||||
// noteEvent?.title(),
|
||||
// price = noteEvent?.price(),
|
||||
)
|
||||
@ -294,11 +304,8 @@ fun RenderGalleryThumb(
|
||||
.observeAsState(
|
||||
GalleryThumb(
|
||||
id = "",
|
||||
image = baseNote.headerImage,
|
||||
title = noteEvent.content(),
|
||||
// image = noteEvent.image(),
|
||||
// title = noteEvent.title(),
|
||||
// price = noteEvent.price(),
|
||||
image = image,
|
||||
title = "",
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -119,11 +119,6 @@ open class Event(
|
||||
|
||||
override fun taggedEvents() = tags.filter { it.size > 1 && it[0] == "e" }.map { it[1] }
|
||||
|
||||
override fun taggedGalleryEntries() =
|
||||
tags.filter { it.size > 2 && it[0] == GalleryListEvent.GALLERYTAGNAME }.map {
|
||||
GalleryListEvent.GalleryUrl(it[1], it[2], it.getOrNull(3))
|
||||
}
|
||||
|
||||
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] }
|
||||
|
@ -85,6 +85,7 @@ class EventFactory {
|
||||
EmojiPackSelectionEvent.KIND ->
|
||||
EmojiPackSelectionEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
FileHeaderEvent.KIND -> FileHeaderEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
ProfileGalleryEntryEvent.KIND -> ProfileGalleryEntryEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
FileServersEvent.KIND -> FileServersEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
FileStorageEvent.KIND -> FileStorageEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
FileStorageHeaderEvent.KIND ->
|
||||
@ -97,7 +98,6 @@ class EventFactory {
|
||||
GitPatchEvent.KIND -> GitPatchEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
GitRepositoryEvent.KIND -> GitRepositoryEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
GoalEvent.KIND -> GoalEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
GalleryListEvent.KIND -> GalleryListEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
HighlightEvent.KIND -> HighlightEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
HTTPAuthorizationEvent.KIND ->
|
||||
HTTPAuthorizationEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
|
@ -145,8 +145,6 @@ interface EventInterface {
|
||||
|
||||
fun firstTaggedK(): Int?
|
||||
|
||||
fun taggedGalleryEntries(): List<GalleryListEvent.GalleryUrl>
|
||||
|
||||
fun taggedEmojis(): List<EmojiUrl>
|
||||
|
||||
fun matchTag1With(text: String): Boolean
|
||||
|
@ -0,0 +1,130 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.events
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.encoders.HexKey
|
||||
import com.vitorpamplona.quartz.signers.NostrSigner
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
@Immutable
|
||||
class ProfileGalleryEntryEvent(
|
||||
id: HexKey,
|
||||
pubKey: HexKey,
|
||||
createdAt: Long,
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
sig: HexKey,
|
||||
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
fun url() = tags.firstOrNull { it.size > 1 && it[0] == URL }?.get(1)
|
||||
|
||||
fun urls() = tags.filter { it.size > 1 && it[0] == URL }.map { it[1] }
|
||||
|
||||
fun encryptionKey() = tags.firstOrNull { it.size > 2 && it[0] == ENCRYPTION_KEY }?.let { AESGCM(it[1], it[2]) }
|
||||
|
||||
fun mimeType() = tags.firstOrNull { it.size > 1 && it[0] == MIME_TYPE }?.get(1)
|
||||
|
||||
fun hash() = tags.firstOrNull { it.size > 1 && it[0] == HASH }?.get(1)
|
||||
|
||||
fun size() = tags.firstOrNull { it.size > 1 && it[0] == FILE_SIZE }?.get(1)
|
||||
|
||||
fun alt() = tags.firstOrNull { it.size > 1 && it[0] == ALT }?.get(1)
|
||||
|
||||
fun dimensions() = tags.firstOrNull { it.size > 1 && it[0] == DIMENSION }?.get(1)
|
||||
|
||||
fun magnetURI() = tags.firstOrNull { it.size > 1 && it[0] == MAGNET_URI }?.get(1)
|
||||
|
||||
fun torrentInfoHash() = tags.firstOrNull { it.size > 1 && it[0] == TORRENT_INFOHASH }?.get(1)
|
||||
|
||||
fun blurhash() = tags.firstOrNull { it.size > 1 && it[0] == BLUR_HASH }?.get(1)
|
||||
|
||||
fun hasUrl() = tags.any { it.size > 1 && it[0] == URL }
|
||||
|
||||
fun event() = tags.firstOrNull { it.size > 1 && it[0] == "e" }?.get(1)
|
||||
|
||||
fun hasEvent() = tags.any { it.size > 1 && it[0] == "e" }
|
||||
|
||||
fun isOneOf(mimeTypes: Set<String>) = tags.any { it.size > 1 && it[0] == MIME_TYPE && mimeTypes.contains(it[1]) }
|
||||
|
||||
companion object {
|
||||
const val KIND = 1163
|
||||
const val ALT_DESCRIPTION = "Profile Gallery Entry"
|
||||
|
||||
const val URL = "url"
|
||||
const val ENCRYPTION_KEY = "aes-256-gcm"
|
||||
const val MIME_TYPE = "m"
|
||||
const val FILE_SIZE = "size"
|
||||
const val DIMENSION = "dim"
|
||||
const val HASH = "x"
|
||||
const val MAGNET_URI = "magnet"
|
||||
const val TORRENT_INFOHASH = "i"
|
||||
const val BLUR_HASH = "blurhash"
|
||||
const val ORIGINAL_HASH = "ox"
|
||||
const val ALT = "alt"
|
||||
|
||||
fun create(
|
||||
url: String,
|
||||
eventid: String? = null,
|
||||
magnetUri: String? = null,
|
||||
mimeType: String? = null,
|
||||
alt: String? = null,
|
||||
hash: String? = null,
|
||||
size: String? = null,
|
||||
dimensions: String? = null,
|
||||
blurhash: String? = null,
|
||||
originalHash: String? = null,
|
||||
magnetURI: String? = null,
|
||||
torrentInfoHash: String? = null,
|
||||
encryptionKey: AESGCM? = null,
|
||||
sensitiveContent: Boolean? = null,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
onReady: (ProfileGalleryEntryEvent) -> Unit,
|
||||
) {
|
||||
val tags =
|
||||
listOfNotNull(
|
||||
arrayOf(URL, url),
|
||||
eventid?.let { arrayOf("e", it) },
|
||||
magnetUri?.let { arrayOf(MAGNET_URI, it) },
|
||||
mimeType?.let { arrayOf(MIME_TYPE, it) },
|
||||
alt?.ifBlank { null }?.let { arrayOf(ALT, it) } ?: arrayOf("alt", ALT_DESCRIPTION),
|
||||
hash?.let { arrayOf(HASH, it) },
|
||||
size?.let { arrayOf(FILE_SIZE, it) },
|
||||
dimensions?.let { arrayOf(DIMENSION, it) },
|
||||
blurhash?.let { arrayOf(BLUR_HASH, it) },
|
||||
originalHash?.let { arrayOf(ORIGINAL_HASH, it) },
|
||||
magnetURI?.let { arrayOf(MAGNET_URI, it) },
|
||||
torrentInfoHash?.let { arrayOf(TORRENT_INFOHASH, it) },
|
||||
encryptionKey?.let { arrayOf(ENCRYPTION_KEY, it.key, it.nonce) },
|
||||
sensitiveContent?.let {
|
||||
if (it) {
|
||||
arrayOf("content-warning", "")
|
||||
} else {
|
||||
null
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
val content = alt ?: ""
|
||||
signer.sign(createdAt, KIND, tags.toTypedArray(), content, onReady)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user