kopia lustrzana https://github.com/vitorpamplona/amethyst
107 wiersze
3.5 KiB
Kotlin
107 wiersze
3.5 KiB
Kotlin
package com.vitorpamplona.amethyst.ui.screen
|
|
|
|
import androidx.lifecycle.ViewModel
|
|
import androidx.lifecycle.viewModelScope
|
|
import com.vitorpamplona.amethyst.model.LocalCache
|
|
import com.vitorpamplona.amethyst.model.LocalCacheState
|
|
import com.vitorpamplona.amethyst.model.Note
|
|
import com.vitorpamplona.amethyst.service.NostrDataSource
|
|
import com.vitorpamplona.amethyst.service.model.ReactionEvent
|
|
import com.vitorpamplona.amethyst.service.model.RepostEvent
|
|
import kotlinx.coroutines.cancel
|
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
import kotlinx.coroutines.flow.asStateFlow
|
|
import kotlinx.coroutines.flow.update
|
|
import kotlinx.coroutines.launch
|
|
|
|
class CardFeedViewModel(val dataSource: NostrDataSource): ViewModel() {
|
|
private val _feedContent = MutableStateFlow<CardFeedState>(CardFeedState.Loading)
|
|
val feedContent = _feedContent.asStateFlow()
|
|
|
|
private var lastNotes: List<Note>? = null
|
|
|
|
fun refresh() {
|
|
// For some reason, view Model Scope doesn't call
|
|
viewModelScope.launch {
|
|
refreshSuspend()
|
|
}
|
|
}
|
|
|
|
fun refreshSuspend() {
|
|
val notes = dataSource.loadTop()
|
|
|
|
val lastNotesCopy = lastNotes
|
|
|
|
val oldNotesState = feedContent.value
|
|
if (lastNotesCopy != null && oldNotesState is CardFeedState.Loaded) {
|
|
val newCards = convertToCard(notes.minus(lastNotesCopy))
|
|
if (newCards.isNotEmpty()) {
|
|
lastNotes = notes
|
|
updateFeed((oldNotesState.feed + newCards).sortedBy { it.createdAt() }.reversed())
|
|
}
|
|
} else {
|
|
val cards = convertToCard(notes)
|
|
lastNotes = notes
|
|
updateFeed(cards)
|
|
}
|
|
}
|
|
|
|
private fun convertToCard(notes: List<Note>): List<Card> {
|
|
val reactionsPerEvent = mutableMapOf<Note, MutableList<Note>>()
|
|
notes
|
|
.filter { it.event is ReactionEvent }
|
|
.forEach {
|
|
val reactedPost = it.replyTo?.last()
|
|
if (reactedPost != null)
|
|
reactionsPerEvent.getOrPut(reactedPost, { mutableListOf() }).add(it)
|
|
}
|
|
|
|
val reactionCards = reactionsPerEvent.map { LikeSetCard(it.key, it.value) }
|
|
|
|
val boostsPerEvent = mutableMapOf<Note, MutableList<Note>>()
|
|
notes
|
|
.filter { it.event is RepostEvent }
|
|
.forEach {
|
|
val boostedPost = it.replyTo?.last()
|
|
if (boostedPost != null)
|
|
boostsPerEvent.getOrPut(boostedPost, { mutableListOf() }).add(it)
|
|
}
|
|
|
|
val boostCards = boostsPerEvent.map { BoostSetCard(it.key, it.value) }
|
|
|
|
val textNoteCards = notes.filter { it.event !is ReactionEvent && it.event !is RepostEvent }.map { NoteCard(it) }
|
|
|
|
return (reactionCards + boostCards + textNoteCards).sortedBy { it.createdAt() }.reversed()
|
|
}
|
|
|
|
fun updateFeed(notes: List<Card>) {
|
|
if (notes.isEmpty()) {
|
|
_feedContent.update { CardFeedState.Empty }
|
|
} else {
|
|
_feedContent.update { CardFeedState.Loaded(notes) }
|
|
}
|
|
}
|
|
|
|
fun refreshCurrentList() {
|
|
val state = feedContent.value
|
|
if (state is CardFeedState.Loaded) {
|
|
_feedContent.update { CardFeedState.Loaded(state.feed) }
|
|
}
|
|
}
|
|
|
|
private val cacheListener: (LocalCacheState) -> Unit = {
|
|
refresh()
|
|
}
|
|
|
|
init {
|
|
LocalCache.live.observeForever(cacheListener)
|
|
}
|
|
|
|
override fun onCleared() {
|
|
LocalCache.live.removeObserver(cacheListener)
|
|
|
|
dataSource.stop()
|
|
viewModelScope.cancel()
|
|
super.onCleared()
|
|
}
|
|
} |