fix: avoid TimSort contract violation in feed filters

DiscoverLongFormFeedFilter.sort (and ~44 other feed filters/view models)
sorted notes with the live DefaultFeedOrder comparator, which reads
Note.createdAt() on every comparison. When another thread swaps a Note's
event mid-sort (e.g. a newer replaceable/addressable event arriving from
a relay), createdAt() changes between comparisons and TimSort throws
"Comparison method violates its general contract!"
(IllegalArgumentException).

Migrate every amethyst Set<Note>/Iterable<Note> sort from
sortedWith(DefaultFeedOrder) to the existing sortedByDefaultFeedOrder()
helper, which snapshots createdAt() once per note so the comparator stays
consistent. The pinned-chatroom comparator in ChatroomListKnownFeedFilter
is given the same snapshot treatment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Sh5XNLssw9GJNxjkxZcRS
This commit is contained in:
Claude
2026-06-19 21:09:27 +00:00
parent a99e67d8be
commit d606b05d24
45 changed files with 105 additions and 98 deletions
@@ -26,8 +26,8 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
class ArticlesFeedFilter(
@@ -74,5 +74,5 @@ class ArticlesFeedFilter(
}
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -26,8 +26,8 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip58Badges.definition.BadgeDefinitionEvent
class BadgesFeedFilter(
@@ -89,5 +89,5 @@ class BadgesFeedFilter(
account.hiddenUsers.flow.value,
)
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -25,8 +25,8 @@ import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip52Calendar.calendar.CalendarEvent
class CalendarCollectionsFeedFilter(
@@ -70,5 +70,5 @@ class CalendarCollectionsFeedFilter(
}
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.ChangesFlowFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
class ChannelFeedFilter(
val channel: Channel,
@@ -44,5 +44,5 @@ class ChannelFeedFilter(
.filter { channel.notes.containsKey(it.idHex) && account.isAcceptable(it) }
.toSet()
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -25,7 +25,7 @@ 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.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent
import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId
import com.vitorpamplona.quartz.nip01Core.core.HexKey
@@ -64,7 +64,7 @@ class ChatroomListKnownFeedFilter(
.getOrCreatePublicChatChannel(channelId)
.notes
.filter { _, it -> account.isAcceptable(it) && it.event != null }
.sortedWith(DefaultFeedOrder)
.sortedByDefaultFeedOrder()
.firstOrNull()
}
@@ -76,7 +76,7 @@ class ChatroomListKnownFeedFilter(
.getOrCreateEphemeralChannel(it)
.notes
.filter { _, it -> account.isAcceptable(it) && it.event != null }
.sortedWith(DefaultFeedOrder)
.sortedByDefaultFeedOrder()
.firstOrNull()
}
@@ -264,12 +264,19 @@ class ChatroomListKnownFeedFilter(
override fun sort(items: Set<Note>): List<Note> {
val pinned = account.settings.syncedSettings.chats.pinnedChatrooms.value
if (pinned.isEmpty()) return items.sortedWith(DefaultFeedOrder)
if (pinned.isEmpty()) return items.sortedByDefaultFeedOrder()
val me = account.userProfile().pubkeyHex
return items.sortedWith(
compareByDescending<Note> { isPinned(it, me, pinned) }.then(DefaultFeedOrder),
)
// Snapshots isPinned + createdAt once per note so the comparator stays consistent
// even if another thread swaps a Note's event mid-sort. Avoids TimSort's
// "Comparison method violates its general contract!" IllegalArgumentException.
return items
.map { Triple(it, isPinned(it, me, pinned), it.createdAt() ?: 0L) }
.sortedWith(
compareByDescending<Triple<Note, Boolean, Long>> { it.second }
.thenByDescending { it.third }
.thenBy { it.first.idHex },
).map { it.first }
}
private fun isPinned(
@@ -24,7 +24,7 @@ import com.vitorpamplona.amethyst.commons.util.replace
import com.vitorpamplona.amethyst.model.Account
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.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey
import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable
@@ -56,7 +56,7 @@ class ChatroomListNewFeedFilter(
}
}
return (privateMessages + marmotGroups).sortedWith(DefaultFeedOrder)
return (privateMessages + marmotGroups).sortedByDefaultFeedOrder()
}
override fun updateListWith(
@@ -142,5 +142,5 @@ class ChatroomListNewFeedFilter(
return newRelevantPrivateMessages
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.share
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedFilter
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
/**
* Recent private-DM conversations only (no public channels, ephemeral chats, or
@@ -49,6 +49,6 @@ class ShareDMRoomsFeedFilter(
} else {
null
}
}.sortedWith(DefaultFeedOrder)
}.sortedByDefaultFeedOrder()
}
}
@@ -24,8 +24,8 @@ 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.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip64Chess.game.ChessGameEvent
/**
@@ -77,5 +77,5 @@ class ChessFeedFilter(
hiddenUsers = account.hiddenUsers.flow.value,
)
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.model.AddressableNote
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.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
import com.vitorpamplona.quartz.nip22Comments.CommentEvent
import com.vitorpamplona.quartz.nip72ModCommunities.approval.CommunityPostApprovalEvent
@@ -120,5 +120,5 @@ class CommunityFeedFilter(
validator: CommunityRulesValidator?,
): Boolean = validator == null || !violatesCommunityRules(validator, candidate)
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.model.AddressableNote
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.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent
import com.vitorpamplona.quartz.nip18Reposts.RepostEvent
@@ -142,5 +142,5 @@ class CommunityModerationFeedFilter(
validator: CommunityRulesValidator?,
): Boolean = validator == null || !violatesCommunityRules(validator, candidate)
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -26,8 +26,8 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
open class DiscoverLongFormFeedFilter(
@@ -74,5 +74,5 @@ open class DiscoverLongFormFeedFilter(
}
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -26,8 +26,8 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip51Lists.followList.FollowListEvent
open class DiscoverFollowSetsFeedFilter(
@@ -74,5 +74,5 @@ open class DiscoverFollowSetsFeedFilter(
}
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip37Drafts.DraftWrapEvent
class DraftEventsFeedFilter(
@@ -52,5 +52,5 @@ class DraftEventsFeedFilter(
return noteEvent is DraftWrapEvent && noteEvent.pubKey == account.userProfile().pubkeyHex
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -26,8 +26,8 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent
class BrowseEmojiSetsFeedFilter(
@@ -74,5 +74,5 @@ class BrowseEmojiSetsFeedFilter(
}
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -29,8 +29,8 @@ import com.vitorpamplona.amethyst.model.topNavFeeds.allUserFollows.AllUserFollow
import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.muted.MutedAuthorsByOutboxTopNavFilter
import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.muted.MutedAuthorsByProxyTopNavFilter
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -116,5 +116,5 @@ class FollowPackFeedConversationsFeedFilter(
filterParams: FilterByListParams,
): Boolean = acceptableEvent(note.event, note.relays, filterParams) && !note.isNewThread()
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -29,8 +29,8 @@ import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.model.topNavFeeds.allUserFollows.AllUserFollowsByOutboxTopNavFilter
import com.vitorpamplona.amethyst.model.topNavFeeds.allUserFollows.AllUserFollowsByProxyTopNavFilter
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.agora.FundraiserEvent
import com.vitorpamplona.quartz.experimental.audio.header.AudioHeaderEvent
import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent
@@ -167,5 +167,5 @@ class FollowPackFeedNewThreadFeedFilter(
} else {
it.idHex
}
}.sortedWith(DefaultFeedOrder)
}.sortedByDefaultFeedOrder()
}
@@ -24,7 +24,7 @@ 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.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.audio.header.AudioHeaderEvent
import com.vitorpamplona.quartz.experimental.music.playlist.MusicPlaylistEvent
import com.vitorpamplona.quartz.experimental.music.track.MusicTrackEvent
@@ -99,5 +99,5 @@ class GeoHashFeedFilter(
geohash: String,
): Boolean = event is CommentEvent && event.isTaggedScope(geohash, GeohashId::match)
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.model.AddressableNote
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.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent
class RepositoryIssuesFeedFilter(
@@ -51,5 +51,5 @@ class RepositoryIssuesFeedFilter(
return event.repositoryHex() == repositoryAddressId
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.model.AddressableNote
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.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip34Git.patch.GitPatchEvent
import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestEvent
@@ -56,5 +56,5 @@ class RepositoryPatchesFeedFilter(
}
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -25,7 +25,7 @@ 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.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.audio.header.AudioHeaderEvent
import com.vitorpamplona.quartz.experimental.music.playlist.MusicPlaylistEvent
import com.vitorpamplona.quartz.experimental.music.track.MusicTrackEvent
@@ -122,5 +122,5 @@ class HashtagFeedFilter(
hashTag: String,
): Boolean = event is CommentEvent && event.isTaggedScope(hashTag, HashtagId::match)
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -26,8 +26,8 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.muted.MutedAuthorsByOutboxTopNavFilter
import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.muted.MutedAuthorsByProxyTopNavFilter
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -96,5 +96,5 @@ class HomeConversationsFeedFilter(
filterParams: FilterByListParams,
): Boolean = acceptableEvent(note.event, note.relays, filterParams) && !note.isNewThread()
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.muted.MutedAuthorsByOutboxTopNavFilter
import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.muted.MutedAuthorsByProxyTopNavFilter
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent
import com.vitorpamplona.quartz.nip18Reposts.RepostEvent
@@ -57,5 +57,5 @@ class HomeEverythingFeedFilter(
} else {
it.idHex
}
}.sortedWith(DefaultFeedOrder)
}.sortedByDefaultFeedOrder()
}
@@ -28,8 +28,8 @@ import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.muted.MutedAuthorsByOutboxTopNavFilter
import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.muted.MutedAuthorsByProxyTopNavFilter
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.agora.FundraiserEvent
import com.vitorpamplona.quartz.experimental.attestations.attestation.AttestationEvent
import com.vitorpamplona.quartz.experimental.attestations.proficiency.AttestorProficiencyEvent
@@ -163,5 +163,5 @@ class HomeNewThreadFeedFilter(
} else {
it.idHex
}
}.sortedWith(DefaultFeedOrder)
}.sortedByDefaultFeedOrder()
}
@@ -28,8 +28,8 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.dal.SupportedContent
import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.datasource.SUPPORTED_VIDEO_FEED_MIME_TYPES_SET
import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent
@@ -113,5 +113,5 @@ class LongsFeedFilter(
(params.isHiddenList || account.isAcceptable(note))
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -26,8 +26,8 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.music.playlist.MusicPlaylistEvent
/**
@@ -102,5 +102,5 @@ class MusicPlaylistsFeedFilter(
(params.isHiddenList || account.isAcceptable(note))
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -26,8 +26,8 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.music.track.MusicTrackEvent
/**
@@ -105,5 +105,5 @@ class MusicTracksFeedFilter(
(params.isHiddenList || account.isAcceptable(note))
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -29,8 +29,8 @@ import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.model.topNavFeeds.IFeedTopNavFilter
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.attestations.request.AttestationRequestEvent
import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent
import com.vitorpamplona.quartz.experimental.forks.IForkableEvent
@@ -364,5 +364,5 @@ class NotificationFeedFilter(
(isRawGlobal || tagsAnEventByUser(it, loggedInUserHex))
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -25,8 +25,8 @@ import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip68Picture.PictureEvent
class PictureFeedFilter(
@@ -73,5 +73,5 @@ class PictureFeedFilter(
}
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -24,14 +24,14 @@ 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.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nipF4Podcasts.episode.PodcastEpisodeEvent
/**
* Every episode of a single podcast. Per NIP-F4 each podcast is its own keypair, so all
* episodes (kind 54) of a show are authored by [podcastPubkey]. Episodes are regular events,
* so they live in `LocalCache.notes`. Most-recent-first via [DefaultFeedOrder].
* so they live in `LocalCache.notes`. Most-recent-first via [sortedByDefaultFeedOrder].
*/
class OnePodcastEpisodesFeedFilter(
val podcastPubkey: HexKey,
@@ -58,5 +58,5 @@ class OnePodcastEpisodesFeedFilter(
account.isAcceptable(note)
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -26,8 +26,8 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nipF4Podcasts.episode.PodcastEpisodeEvent
/**
@@ -84,5 +84,5 @@ class PodcastEpisodesFeedFilter(
(params.isHiddenList || account.isAcceptable(note))
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -26,8 +26,8 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nipF4Podcasts.metadata.PodcastMetadataEvent
/**
@@ -83,5 +83,5 @@ class PodcastsFeedFilter(
(params.isHiddenList || account.isAcceptable(note))
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -25,8 +25,8 @@ import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent
import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent
import com.vitorpamplona.quartz.utils.TimeUtils
@@ -93,5 +93,5 @@ class ClosedPollsFeedFilter(
}
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -25,8 +25,8 @@ import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent
import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent
import com.vitorpamplona.quartz.utils.TimeUtils
@@ -93,5 +93,5 @@ class OpenPollsFeedFilter(
}
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -25,8 +25,8 @@ import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent
import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent
@@ -74,5 +74,5 @@ class PollsFeedFilter(
}
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -27,7 +27,7 @@ import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
import com.vitorpamplona.quartz.nip22Comments.CommentEvent
@@ -78,7 +78,7 @@ class UserProfileConversationsFeedFilter(
!it.isNewThread() &&
account.isAcceptable(it)
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
override fun limit() = 200
}
@@ -27,8 +27,8 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.model.filter
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.profileGallery.ProfileGalleryEntryEvent
import com.vitorpamplona.quartz.nip53LiveActivities.clip.LiveActivitiesClipEvent
import com.vitorpamplona.quartz.nip68Picture.PictureEvent
@@ -103,5 +103,5 @@ class UserProfileGalleryFeedFilter(
hiddenUsers = account.hiddenUsers.flow.value,
)
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -24,7 +24,7 @@ import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip89AppHandlers.recommendation.AppRecommendationEvent
import com.vitorpamplona.quartz.utils.flattenToSet
@@ -55,5 +55,5 @@ class UserProfileAppRecommendationsFeedFilter(
return null
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -27,7 +27,7 @@ import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.agora.FundraiserEvent
import com.vitorpamplona.quartz.experimental.audio.header.AudioHeaderEvent
import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent
@@ -98,7 +98,7 @@ class UserProfileMutualFeedFilter(
) &&
it.event?.isTaggedUser(user.pubkeyHex) == true
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
override fun limit() = 200
}
@@ -27,7 +27,7 @@ import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.agora.FundraiserEvent
import com.vitorpamplona.quartz.experimental.attestations.attestation.AttestationEvent
import com.vitorpamplona.quartz.experimental.attestations.proficiency.AttestorProficiencyEvent
@@ -110,7 +110,7 @@ class UserProfileNewThreadFeedFilter(
it.isNewThread() &&
account.isAcceptable(it)
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
override fun limit() = 200
}
@@ -24,7 +24,7 @@ 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.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
class RelayFeedFilter(
@@ -52,5 +52,5 @@ class RelayFeedFilter(
!it.isHiddenFor(account.hiddenUsers.flow.value) &&
account.isAcceptable(it)
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -38,7 +38,7 @@ import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.service.relayClient.searchCommand.SearchQueryState
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.userUriPrefixes
@@ -276,11 +276,11 @@ class SearchBarViewModel(
}
SearchSortOrder.RELEVANCE, SearchSortOrder.NEWEST -> {
filtered.sortedWith(DefaultFeedOrder)
filtered.sortedByDefaultFeedOrder()
}
else -> {
filtered.sortedWith(DefaultFeedOrder)
filtered.sortedByDefaultFeedOrder()
}
}
}.flowOn(Dispatchers.IO)
@@ -26,8 +26,8 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.application.SoftwareApplicationEvent
class SoftwareAppsFeedFilter(
@@ -74,5 +74,5 @@ class SoftwareAppsFeedFilter(
}
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -28,8 +28,8 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.datasource.SUPPORTED_VIDEO_FEED_MIME_TYPES_SET
import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent
import com.vitorpamplona.quartz.nip68Picture.PictureEvent
@@ -139,5 +139,5 @@ class VideoFeedFilter(
hiddenUsers = account.hiddenUsers.flow.value,
)
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.filterIntoSet
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.nipB0WebBookmarks.WebBookmarkEvent
class WebBookmarkFeedFilter(
@@ -52,5 +52,5 @@ class WebBookmarkFeedFilter(
return noteEvent is WebBookmarkEvent && noteEvent.pubKey == account.userProfile().pubkeyHex
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}
@@ -25,8 +25,8 @@ import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
import com.vitorpamplona.quartz.experimental.fitness.workout.WorkoutRecordEvent
class WorkoutFeedFilter(
@@ -73,5 +73,5 @@ class WorkoutFeedFilter(
}
}
override fun sort(items: Set<Note>): List<Note> = items.sortedWith(DefaultFeedOrder)
override fun sort(items: Set<Note>): List<Note> = items.sortedByDefaultFeedOrder()
}