mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2024-09-29 16:30:49 +00:00
New thread ordering scheme:
1. Thread author, ascending order by date. 2. My replies, descending by date. 3. My follow's replies, descending by date. 4. Everybody else, descending by date.
This commit is contained in:
parent
8ea8cf2985
commit
f06b5fdacf
@ -136,26 +136,60 @@ open class Note(val idHex: String) {
|
||||
.format(DateTimeFormatter.ofPattern("uuuu-MM-dd-HH:mm:ss"))
|
||||
}
|
||||
|
||||
data class LevelSignature(val signature: String, val createdAt: Long?, val author: User?)
|
||||
|
||||
/**
|
||||
* This method caches signatures during each execution to avoid recalculation in longer threads
|
||||
*/
|
||||
fun replyLevelSignature(
|
||||
eventsToConsider: Set<Note>,
|
||||
cachedSignatures: MutableMap<Note, String>
|
||||
): String {
|
||||
cachedSignatures: MutableMap<Note, LevelSignature>,
|
||||
account: User,
|
||||
accountFollowingSet: Set<String>,
|
||||
now: Long
|
||||
): LevelSignature {
|
||||
val replyTo = replyTo
|
||||
if (event is RepostEvent || event is GenericRepostEvent || replyTo == null || replyTo.isEmpty()) {
|
||||
return "/" + formattedDateTime(createdAt() ?: 0) + ";"
|
||||
return LevelSignature(
|
||||
signature = "/" + formattedDateTime(createdAt() ?: 0) + ";",
|
||||
createdAt = createdAt(),
|
||||
author = author
|
||||
)
|
||||
}
|
||||
|
||||
val mySignature = (
|
||||
val parent = (
|
||||
replyTo
|
||||
.filter { it in eventsToConsider } // This forces the signature to be based on a branch, avoiding two roots
|
||||
.map {
|
||||
cachedSignatures[it] ?: it.replyLevelSignature(eventsToConsider, cachedSignatures).apply { cachedSignatures.put(it, this) }
|
||||
cachedSignatures[it] ?: it.replyLevelSignature(
|
||||
eventsToConsider,
|
||||
cachedSignatures,
|
||||
account,
|
||||
accountFollowingSet,
|
||||
now
|
||||
).apply { cachedSignatures.put(it, this) }
|
||||
}
|
||||
.maxByOrNull { it.length }?.removeSuffix(";") ?: ""
|
||||
) + "/" + formattedDateTime(createdAt() ?: 0) + ";"
|
||||
.maxByOrNull { it.signature.length }
|
||||
)
|
||||
|
||||
val parentSignature = parent?.signature?.removeSuffix(";") ?: ""
|
||||
|
||||
val threadOrder = if (parent?.author == author && createdAt() != null) {
|
||||
// author of the thread first, in **ascending** order
|
||||
"9" + formattedDateTime((parent?.createdAt ?: 0) + (now - (createdAt() ?: 0)))
|
||||
} else if (author?.pubkeyHex == account.pubkeyHex) {
|
||||
"8" + formattedDateTime(createdAt() ?: 0) // my replies
|
||||
} else if (author?.pubkeyHex in accountFollowingSet) {
|
||||
"7" + formattedDateTime(createdAt() ?: 0) // my follows replies.
|
||||
} else {
|
||||
"0" + formattedDateTime(createdAt() ?: 0) // everyone else.
|
||||
}
|
||||
|
||||
val mySignature = LevelSignature(
|
||||
signature = parentSignature + "/" + threadOrder + ";",
|
||||
createdAt = createdAt(),
|
||||
author = author
|
||||
)
|
||||
|
||||
cachedSignatures[this] = mySignature
|
||||
return mySignature
|
||||
|
@ -1,22 +1,29 @@
|
||||
package com.vitorpamplona.amethyst.ui.dal
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.KIND3_FOLLOWS
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.ThreadAssembler
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
@Immutable
|
||||
class ThreadFeedFilter(val noteId: String) : FeedFilter<Note>() {
|
||||
class ThreadFeedFilter(val account: Account, val noteId: String) : FeedFilter<Note>() {
|
||||
|
||||
override fun feedKey(): String {
|
||||
return noteId
|
||||
}
|
||||
|
||||
override fun feed(): List<Note> {
|
||||
val cachedSignatures: MutableMap<Note, String> = mutableMapOf()
|
||||
val eventsToWatch = ThreadAssembler().findThreadFor(noteId) ?: emptySet()
|
||||
val cachedSignatures: MutableMap<Note, Note.LevelSignature> = mutableMapOf()
|
||||
val followingSet = account.selectedUsersFollowList(KIND3_FOLLOWS) ?: emptySet()
|
||||
val eventsToWatch = ThreadAssembler().findThreadFor(noteId)
|
||||
val now = TimeUtils.now()
|
||||
|
||||
// Currently orders by date of each event, descending, at each level of the reply stack
|
||||
val order = compareByDescending<Note> { it.replyLevelSignature(eventsToWatch, cachedSignatures) }
|
||||
val order = compareByDescending<Note> {
|
||||
it.replyLevelSignature(eventsToWatch, cachedSignatures, account.userProfile(), followingSet, now).signature
|
||||
}
|
||||
|
||||
return eventsToWatch.sortedWith(order)
|
||||
}
|
||||
|
@ -95,10 +95,10 @@ class NostrDiscoverChatFeedViewModel(val account: Account) : FeedViewModel(Disco
|
||||
}
|
||||
}
|
||||
|
||||
class NostrThreadFeedViewModel(val noteId: String) : FeedViewModel(ThreadFeedFilter(noteId)) {
|
||||
class Factory(val noteId: String) : ViewModelProvider.Factory {
|
||||
class NostrThreadFeedViewModel(account: Account, noteId: String) : FeedViewModel(ThreadFeedFilter(account, noteId)) {
|
||||
class Factory(val account: Account, val noteId: String) : ViewModelProvider.Factory {
|
||||
override fun <NostrThreadFeedViewModel : ViewModel> create(modelClass: Class<NostrThreadFeedViewModel>): NostrThreadFeedViewModel {
|
||||
return NostrThreadFeedViewModel(noteId) as NostrThreadFeedViewModel
|
||||
return NostrThreadFeedViewModel(account, noteId) as NostrThreadFeedViewModel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ fun ThreadScreen(noteId: String?, accountViewModel: AccountViewModel, nav: (Stri
|
||||
|
||||
val feedViewModel: NostrThreadFeedViewModel = viewModel(
|
||||
key = noteId + "NostrThreadFeedViewModel",
|
||||
factory = NostrThreadFeedViewModel.Factory(noteId)
|
||||
factory = NostrThreadFeedViewModel.Factory(accountViewModel.account, noteId)
|
||||
)
|
||||
|
||||
NostrThreadDataSource.loadThread(noteId)
|
||||
|
Loading…
Reference in New Issue
Block a user