Adds a Reads feed to the discovery tab

This commit is contained in:
Vitor Pamplona
2025-05-06 15:48:03 -04:00
parent 80d4971548
commit fcd70001bf
12 changed files with 202 additions and 30 deletions
@@ -63,12 +63,15 @@ import com.vitorpamplona.quartz.nip47WalletConnect.LnZapPaymentResponseEvent
import com.vitorpamplona.quartz.nip47WalletConnect.PayInvoiceSuccessResponse import com.vitorpamplona.quartz.nip47WalletConnect.PayInvoiceSuccessResponse
import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessageEvent import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessageEvent
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent
import com.vitorpamplona.quartz.nip54Wiki.WikiNoteEvent
import com.vitorpamplona.quartz.nip56Reports.ReportEvent import com.vitorpamplona.quartz.nip56Reports.ReportEvent
import com.vitorpamplona.quartz.nip56Reports.ReportType import com.vitorpamplona.quartz.nip56Reports.ReportType
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent
import com.vitorpamplona.quartz.nip59Giftwrap.WrappedEvent import com.vitorpamplona.quartz.nip59Giftwrap.WrappedEvent
import com.vitorpamplona.quartz.nip71Video.VideoEvent
import com.vitorpamplona.quartz.nip72ModCommunities.approval.CommunityPostApprovalEvent import com.vitorpamplona.quartz.nip72ModCommunities.approval.CommunityPostApprovalEvent
import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent
import com.vitorpamplona.quartz.utils.Hex import com.vitorpamplona.quartz.utils.Hex
import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.TimeUtils
import com.vitorpamplona.quartz.utils.containsAny import com.vitorpamplona.quartz.utils.containsAny
@@ -94,12 +97,20 @@ class AddressableNote(
override fun address() = address override fun address() = address
override fun createdAt(): Long? { override fun createdAt(): Long? {
if (event == null) return null val currentEvent = event
val publishedAt = (event as? LongTextNoteEvent)?.publishedAt() ?: Long.MAX_VALUE if (currentEvent == null) return null
val lastCreatedAt = event?.createdAt ?: Long.MAX_VALUE
return minOf(publishedAt, lastCreatedAt) val publishedAt =
when (currentEvent) {
is LongTextNoteEvent -> currentEvent.publishedAt() ?: Long.MAX_VALUE
is WikiNoteEvent -> currentEvent.publishedAt() ?: Long.MAX_VALUE
is VideoEvent -> currentEvent.publishedAt() ?: Long.MAX_VALUE
is ClassifiedsEvent -> currentEvent.publishedAt() ?: Long.MAX_VALUE
else -> Long.MAX_VALUE
}
return minOf(publishedAt, currentEvent.createdAt)
} }
fun dTag(): String = address.dTag fun dTag(): String = address.dTag
@@ -24,7 +24,7 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.Card import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.Card
val DefaultFeedOrder: Comparator<Note> = val DefaultFeedOrder: Comparator<Note> =
compareByDescending<Note> { it.event?.createdAt }.thenBy { it.idHex } compareByDescending<Note> { it.createdAt() }.thenBy { it.idHex }
val DefaultFeedOrderCard: Comparator<Card> = val DefaultFeedOrderCard: Comparator<Card> =
compareByDescending<Card> { it.createdAt() }.thenBy { it.id() } compareByDescending<Card> { it.createdAt() }.thenBy { it.id() }
@@ -46,6 +46,7 @@ object ScrollStateKeys {
const val DRAFTS = "DraftsFeed" const val DRAFTS = "DraftsFeed"
const val DISCOVER_FOLLOWS = "DiscoverFollowSetsFeed" const val DISCOVER_FOLLOWS = "DiscoverFollowSetsFeed"
const val DISCOVER_READS = "DiscoverReadsFeed"
const val DISCOVER_CONTENT = "DiscoverDiscoverContentFeed" const val DISCOVER_CONTENT = "DiscoverDiscoverContentFeed"
const val DISCOVER_MARKETPLACE = "DiscoverMarketplaceFeed" const val DISCOVER_MARKETPLACE = "DiscoverMarketplaceFeed"
const val DISCOVER_LIVE = "DiscoverLiveFeed" const val DISCOVER_LIVE = "DiscoverLiveFeed"
@@ -60,7 +60,7 @@ fun RenderLongFormContent(
} }
@Composable @Composable
private fun LongFormHeader( fun LongFormHeader(
noteEvent: LongTextNoteEvent, noteEvent: LongTextNoteEvent,
note: Note, note: Note,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
@@ -83,10 +83,7 @@ private fun LongFormHeader(
QuoteBorder, QuoteBorder,
), ),
) { ) {
val automaticallyShowUrlPreview = if (accountViewModel.settings.showImages.value) {
remember { accountViewModel.settings.showImages.value }
if (automaticallyShowUrlPreview) {
image?.let { image?.let {
AsyncImage( AsyncImage(
model = it, model = it,
@@ -28,6 +28,7 @@ import com.vitorpamplona.amethyst.ui.feeds.FeedContentState
import com.vitorpamplona.amethyst.ui.screen.FollowListState import com.vitorpamplona.amethyst.ui.screen.FollowListState
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.dal.ChatroomListKnownFeedFilter import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.dal.ChatroomListKnownFeedFilter
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.dal.ChatroomListNewFeedFilter import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.dal.ChatroomListNewFeedFilter
import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip23LongForm.DiscoverLongFormFeedFilter
import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip28Chats.DiscoverChatFeedFilter import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip28Chats.DiscoverChatFeedFilter
import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip51FollowSets.DiscoverFollowSetsFeedFilter import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip51FollowSets.DiscoverFollowSetsFeedFilter
import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip53LiveActivities.DiscoverLiveFeedFilter import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip53LiveActivities.DiscoverLiveFeedFilter
@@ -55,6 +56,7 @@ class AccountFeedContentStates(
val videoFeed = FeedContentState(VideoFeedFilter(accountViewModel.account), accountViewModel.viewModelScope) val videoFeed = FeedContentState(VideoFeedFilter(accountViewModel.account), accountViewModel.viewModelScope)
val discoverFollowSets = FeedContentState(DiscoverFollowSetsFeedFilter(accountViewModel.account), accountViewModel.viewModelScope) val discoverFollowSets = FeedContentState(DiscoverFollowSetsFeedFilter(accountViewModel.account), accountViewModel.viewModelScope)
val discoverReads = FeedContentState(DiscoverLongFormFeedFilter(accountViewModel.account), accountViewModel.viewModelScope)
val discoverMarketplace = FeedContentState(DiscoverMarketplaceFeedFilter(accountViewModel.account), accountViewModel.viewModelScope) val discoverMarketplace = FeedContentState(DiscoverMarketplaceFeedFilter(accountViewModel.account), accountViewModel.viewModelScope)
val discoverDVMs = FeedContentState(DiscoverNIP89FeedFilter(accountViewModel.account), accountViewModel.viewModelScope) val discoverDVMs = FeedContentState(DiscoverNIP89FeedFilter(accountViewModel.account), accountViewModel.viewModelScope)
val discoverLive = FeedContentState(DiscoverLiveFeedFilter(accountViewModel.account), accountViewModel.viewModelScope) val discoverLive = FeedContentState(DiscoverLiveFeedFilter(accountViewModel.account), accountViewModel.viewModelScope)
@@ -84,6 +86,8 @@ class AccountFeedContentStates(
videoFeed.updateFeedWith(newNotes) videoFeed.updateFeedWith(newNotes)
discoverMarketplace.updateFeedWith(newNotes) discoverMarketplace.updateFeedWith(newNotes)
discoverFollowSets.updateFeedWith(newNotes)
discoverReads.updateFeedWith(newNotes)
discoverDVMs.updateFeedWith(newNotes) discoverDVMs.updateFeedWith(newNotes)
discoverLive.updateFeedWith(newNotes) discoverLive.updateFeedWith(newNotes)
discoverCommunities.updateFeedWith(newNotes) discoverCommunities.updateFeedWith(newNotes)
@@ -105,6 +109,8 @@ class AccountFeedContentStates(
videoFeed.destroy() videoFeed.destroy()
discoverMarketplace.destroy() discoverMarketplace.destroy()
discoverFollowSets.destroy()
discoverReads.destroy()
discoverDVMs.destroy() discoverDVMs.destroy()
discoverLive.destroy() discoverLive.destroy()
discoverCommunities.destroy() discoverCommunities.destroy()
@@ -36,6 +36,7 @@ import com.vitorpamplona.amethyst.ui.note.LongPressToQuickAction
import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent
import com.vitorpamplona.amethyst.ui.note.calculateBackgroundColor import com.vitorpamplona.amethyst.ui.note.calculateBackgroundColor
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip23LongForm.RenderLongFormThumb
import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip28Chats.RenderChannelThumb import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip28Chats.RenderChannelThumb
import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip51FollowSets.RenderFollowSetThumb import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip51FollowSets.RenderFollowSetThumb
import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip53LiveActivities.RenderLiveActivityThumb import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip53LiveActivities.RenderLiveActivityThumb
@@ -44,6 +45,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip90DVMs.RenderCo
import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip99Classifieds.RenderClassifiedsThumb import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip99Classifieds.RenderClassifiedsThumb
import com.vitorpamplona.amethyst.ui.theme.HalfPadding import com.vitorpamplona.amethyst.ui.theme.HalfPadding
import com.vitorpamplona.amethyst.ui.theme.StdPadding import com.vitorpamplona.amethyst.ui.theme.StdPadding
import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent
import com.vitorpamplona.quartz.nip51Lists.FollowListEvent import com.vitorpamplona.quartz.nip51Lists.FollowListEvent
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent
@@ -154,6 +156,7 @@ fun InnerChannelCardWithReactions(
is ClassifiedsEvent -> InnerCardBox(baseNote, accountViewModel, nav) is ClassifiedsEvent -> InnerCardBox(baseNote, accountViewModel, nav)
is AppDefinitionEvent -> InnerCardRow(baseNote, accountViewModel, nav) is AppDefinitionEvent -> InnerCardRow(baseNote, accountViewModel, nav)
is FollowListEvent -> InnerCardRow(baseNote, accountViewModel, nav) is FollowListEvent -> InnerCardRow(baseNote, accountViewModel, nav)
is LongTextNoteEvent -> InnerCardRow(baseNote, accountViewModel, nav)
} }
} }
@@ -200,20 +203,11 @@ private fun RenderNoteRow(
nav: INav, nav: INav,
) { ) {
when (baseNote.event) { when (baseNote.event) {
is LiveActivitiesEvent -> { is LiveActivitiesEvent -> RenderLiveActivityThumb(baseNote, accountViewModel, nav)
RenderLiveActivityThumb(baseNote, accountViewModel, nav) is CommunityDefinitionEvent -> RenderCommunitiesThumb(baseNote, accountViewModel, nav)
} is ChannelCreateEvent -> RenderChannelThumb(baseNote, accountViewModel, nav)
is CommunityDefinitionEvent -> { is AppDefinitionEvent -> RenderContentDVMThumb(baseNote, accountViewModel, nav)
RenderCommunitiesThumb(baseNote, accountViewModel, nav) is FollowListEvent -> RenderFollowSetThumb(baseNote, accountViewModel, nav)
} is LongTextNoteEvent -> RenderLongFormThumb(baseNote, accountViewModel, nav)
is ChannelCreateEvent -> {
RenderChannelThumb(baseNote, accountViewModel, nav)
}
is AppDefinitionEvent -> {
RenderContentDVMThumb(baseNote, accountViewModel, nav)
}
is FollowListEvent -> {
RenderFollowSetThumb(baseNote, accountViewModel, nav)
}
} }
} }
@@ -81,6 +81,7 @@ import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.ui.theme.Size26Modifier
import com.vitorpamplona.amethyst.ui.theme.Size55Modifier import com.vitorpamplona.amethyst.ui.theme.Size55Modifier
import com.vitorpamplona.amethyst.ui.theme.TabRowHeight import com.vitorpamplona.amethyst.ui.theme.TabRowHeight
import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent
import com.vitorpamplona.quartz.nip51Lists.FollowListEvent import com.vitorpamplona.quartz.nip51Lists.FollowListEvent
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent
@@ -98,6 +99,7 @@ fun DiscoverScreen(
) { ) {
DiscoverScreen( DiscoverScreen(
discoveryFollowSetsFeedContentState = accountViewModel.feedStates.discoverFollowSets, discoveryFollowSetsFeedContentState = accountViewModel.feedStates.discoverFollowSets,
discoveryReadsFeedContentState = accountViewModel.feedStates.discoverReads,
discoveryContentNIP89FeedContentState = accountViewModel.feedStates.discoverDVMs, discoveryContentNIP89FeedContentState = accountViewModel.feedStates.discoverDVMs,
discoveryMarketplaceFeedContentState = accountViewModel.feedStates.discoverMarketplace, discoveryMarketplaceFeedContentState = accountViewModel.feedStates.discoverMarketplace,
discoveryLiveFeedContentState = accountViewModel.feedStates.discoverLive, discoveryLiveFeedContentState = accountViewModel.feedStates.discoverLive,
@@ -112,6 +114,7 @@ fun DiscoverScreen(
@Composable @Composable
fun DiscoverScreen( fun DiscoverScreen(
discoveryFollowSetsFeedContentState: FeedContentState, discoveryFollowSetsFeedContentState: FeedContentState,
discoveryReadsFeedContentState: FeedContentState,
discoveryContentNIP89FeedContentState: FeedContentState, discoveryContentNIP89FeedContentState: FeedContentState,
discoveryMarketplaceFeedContentState: FeedContentState, discoveryMarketplaceFeedContentState: FeedContentState,
discoveryLiveFeedContentState: FeedContentState, discoveryLiveFeedContentState: FeedContentState,
@@ -128,9 +131,16 @@ fun DiscoverScreen(
R.string.discover_follows, R.string.discover_follows,
discoveryFollowSetsFeedContentState, discoveryFollowSetsFeedContentState,
"DiscoverFollowSets", "DiscoverFollowSets",
ScrollStateKeys.DISCOVER_CONTENT, ScrollStateKeys.DISCOVER_FOLLOWS,
FollowListEvent.KIND, FollowListEvent.KIND,
), ),
TabItem(
R.string.discover_reads,
discoveryReadsFeedContentState,
"DiscoverReads",
ScrollStateKeys.DISCOVER_READS,
LongTextNoteEvent.KIND,
),
TabItem( TabItem(
R.string.discover_content, R.string.discover_content,
discoveryContentNIP89FeedContentState, discoveryContentNIP89FeedContentState,
@@ -175,6 +185,7 @@ fun DiscoverScreen(
WatchAccountForDiscoveryScreen( WatchAccountForDiscoveryScreen(
discoveryFollowSetsFeedContentState = discoveryFollowSetsFeedContentState, discoveryFollowSetsFeedContentState = discoveryFollowSetsFeedContentState,
discoveryReadsFeedContentState = discoveryReadsFeedContentState,
discoveryContentNIP89FeedContentState = discoveryContentNIP89FeedContentState, discoveryContentNIP89FeedContentState = discoveryContentNIP89FeedContentState,
discoveryMarketplaceFeedContentState = discoveryMarketplaceFeedContentState, discoveryMarketplaceFeedContentState = discoveryMarketplaceFeedContentState,
discoveryLiveFeedContentState = discoveryLiveFeedContentState, discoveryLiveFeedContentState = discoveryLiveFeedContentState,
@@ -184,6 +195,7 @@ fun DiscoverScreen(
) )
WatchLifecycleAndUpdateModel(discoveryFollowSetsFeedContentState) WatchLifecycleAndUpdateModel(discoveryFollowSetsFeedContentState)
WatchLifecycleAndUpdateModel(discoveryReadsFeedContentState)
WatchLifecycleAndUpdateModel(discoveryContentNIP89FeedContentState) WatchLifecycleAndUpdateModel(discoveryContentNIP89FeedContentState)
WatchLifecycleAndUpdateModel(discoveryMarketplaceFeedContentState) WatchLifecycleAndUpdateModel(discoveryMarketplaceFeedContentState)
WatchLifecycleAndUpdateModel(discoveryLiveFeedContentState) WatchLifecycleAndUpdateModel(discoveryLiveFeedContentState)
@@ -379,6 +391,7 @@ private fun RenderDiscoverFeed(
@Composable @Composable
fun WatchAccountForDiscoveryScreen( fun WatchAccountForDiscoveryScreen(
discoveryFollowSetsFeedContentState: FeedContentState, discoveryFollowSetsFeedContentState: FeedContentState,
discoveryReadsFeedContentState: FeedContentState,
discoveryContentNIP89FeedContentState: FeedContentState, discoveryContentNIP89FeedContentState: FeedContentState,
discoveryMarketplaceFeedContentState: FeedContentState, discoveryMarketplaceFeedContentState: FeedContentState,
discoveryLiveFeedContentState: FeedContentState, discoveryLiveFeedContentState: FeedContentState,
@@ -390,6 +403,7 @@ fun WatchAccountForDiscoveryScreen(
LaunchedEffect(accountViewModel, listState) { LaunchedEffect(accountViewModel, listState) {
discoveryFollowSetsFeedContentState.checkKeysInvalidateDataAndSendToTop() discoveryFollowSetsFeedContentState.checkKeysInvalidateDataAndSendToTop()
discoveryReadsFeedContentState.checkKeysInvalidateDataAndSendToTop()
discoveryContentNIP89FeedContentState.checkKeysInvalidateDataAndSendToTop() discoveryContentNIP89FeedContentState.checkKeysInvalidateDataAndSendToTop()
discoveryMarketplaceFeedContentState.checkKeysInvalidateDataAndSendToTop() discoveryMarketplaceFeedContentState.checkKeysInvalidateDataAndSendToTop()
discoveryLiveFeedContentState.checkKeysInvalidateDataAndSendToTop() discoveryLiveFeedContentState.checkKeysInvalidateDataAndSendToTop()
@@ -30,6 +30,7 @@ import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.datasources.Subscription import com.vitorpamplona.ammolite.relays.datasources.Subscription
import com.vitorpamplona.ammolite.relays.filters.SinceAuthorPerRelayFilter import com.vitorpamplona.ammolite.relays.filters.SinceAuthorPerRelayFilter
import com.vitorpamplona.ammolite.relays.filters.SincePerRelayFilter import com.vitorpamplona.ammolite.relays.filters.SincePerRelayFilter
import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent
import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelMetadataEvent import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelMetadataEvent
import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent
@@ -251,7 +252,26 @@ class DiscoveryFilterAssembler(
SinceAuthorPerRelayFilter( SinceAuthorPerRelayFilter(
authors = follows, authors = follows,
kinds = listOf(FollowListEvent.KIND), kinds = listOf(FollowListEvent.KIND),
limit = 500, limit = 300,
since = since(key),
),
),
)
}
fun createLongFormFilter(key: DiscoveryQueryState): List<TypedFilter> {
val follows =
key.account.liveDiscoveryListAuthorsPerRelay.value
?.ifEmpty { null }
return listOfNotNull(
TypedFilter(
types = setOf(FeedType.FOLLOWS),
filter =
SinceAuthorPerRelayFilter(
authors = follows,
kinds = listOf(LongTextNoteEvent.KIND),
limit = 300,
since = since(key), since = since(key),
), ),
), ),
@@ -471,6 +491,7 @@ class DiscoveryFilterAssembler(
.plus(createNIP89Filter(key)) .plus(createNIP89Filter(key))
.plus(createPublicChatFilter(key)) .plus(createPublicChatFilter(key))
.plus(createFollowSetFilter(key)) .plus(createFollowSetFilter(key))
.plus(createLongFormFilter(key))
.plus(createMarketplaceFilter(key)) .plus(createMarketplaceFilter(key))
.plus( .plus(
listOfNotNull( listOfNotNull(
@@ -0,0 +1,76 @@
/**
* 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.amethyst.ui.screen.loggedIn.discover.nip23LongForm
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
import com.vitorpamplona.quartz.nip51Lists.MuteListEvent
import com.vitorpamplona.quartz.nip51Lists.PeopleListEvent
open class DiscoverLongFormFeedFilter(
val account: Account,
) : AdditiveFeedFilter<Note>() {
override fun feedKey(): String = account.userProfile().pubkeyHex + "-" + followList()
open fun followList(): String = account.settings.defaultDiscoveryFollowList.value
override fun showHiddenKey(): Boolean =
followList() == PeopleListEvent.Companion.blockListFor(account.userProfile().pubkeyHex) ||
followList() == MuteListEvent.Companion.blockListFor(account.userProfile().pubkeyHex)
override fun feed(): List<Note> {
val params = buildFilterParams(account)
val notes =
LocalCache.addressables.filterIntoSet { _, it ->
val noteEvent = it.event
noteEvent is LongTextNoteEvent && params.match(noteEvent)
}
return sort(notes)
}
override fun applyFilter(collection: Set<Note>): Set<Note> = innerApplyFilter(collection)
fun buildFilterParams(account: Account): FilterByListParams =
FilterByListParams.Companion.create(
account.userProfile().pubkeyHex,
account.settings.defaultDiscoveryFollowList.value,
account.liveDiscoveryFollowLists.value,
account.flowHiddenUsers.value,
)
protected open fun innerApplyFilter(collection: Collection<Note>): Set<Note> {
val params = buildFilterParams(account)
return collection.filterTo(HashSet()) {
val noteEvent = it.event
noteEvent is LongTextNoteEvent && params.match(noteEvent)
}
}
override fun sort(collection: Set<Note>): List<Note> = collection.sortedWith(DefaultFeedOrder)
}
@@ -0,0 +1,47 @@
/**
* 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.amethyst.ui.screen.loggedIn.discover.nip23LongForm
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent
import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.note.types.LongFormHeader
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
@Composable
fun RenderLongFormThumb(
baseNote: Note,
accountViewModel: AccountViewModel,
nav: INav,
) {
val noteEvent by observeNoteEvent<LongTextNoteEvent>(baseNote, accountViewModel)
noteEvent?.let {
LongFormHeader(
it,
baseNote,
accountViewModel,
)
}
}
@@ -162,7 +162,10 @@ import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.ui.theme.Size55dp import com.vitorpamplona.amethyst.ui.theme.Size55dp
import com.vitorpamplona.amethyst.ui.theme.Size5dp import com.vitorpamplona.amethyst.ui.theme.Size5dp
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
import com.vitorpamplona.amethyst.ui.theme.grayText
import com.vitorpamplona.amethyst.ui.theme.imageModifier
import com.vitorpamplona.amethyst.ui.theme.lessImportantLink import com.vitorpamplona.amethyst.ui.theme.lessImportantLink
import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.amethyst.ui.theme.selectedNote import com.vitorpamplona.amethyst.ui.theme.selectedNote
@@ -933,7 +936,7 @@ private fun RenderLongFormHeaderForThread(noteEvent: LongTextNoteEvent) {
it, it,
), ),
contentScale = ContentScale.FillWidth, contentScale = ContentScale.FillWidth,
modifier = Modifier.fillMaxWidth(), modifier = MaterialTheme.colorScheme.imageModifier,
) )
} }
@@ -951,11 +954,12 @@ private fun RenderLongFormHeaderForThread(noteEvent: LongTextNoteEvent) {
.summary() .summary()
?.ifBlank { null } ?.ifBlank { null }
?.let { ?.let {
Spacer(modifier = DoubleVertSpacer) Spacer(modifier = StdVertSpacer)
Text( Text(
text = it, text = it,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
color = Color.Gray, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.grayText,
) )
} }
} }
+1
View File
@@ -649,6 +649,7 @@
<string name="relay_setup">Relays</string> <string name="relay_setup">Relays</string>
<string name="discover_follows">Follow Packs</string> <string name="discover_follows">Follow Packs</string>
<string name="discover_reads">Reads</string>
<string name="discover_content">Feed Algorithms</string> <string name="discover_content">Feed Algorithms</string>
<string name="discover_marketplace">Marketplace</string> <string name="discover_marketplace">Marketplace</string>
<string name="discover_live">Live Streams</string> <string name="discover_live">Live Streams</string>