Adds an isRefreshing status for all feeds.

This commit is contained in:
Vitor Pamplona
2024-09-06 17:19:10 -04:00
parent f12cf93e9f
commit c7fcc47b11
7 changed files with 114 additions and 59 deletions

View File

@@ -21,7 +21,11 @@
package com.vitorpamplona.amethyst.ui.feeds
import android.util.Log
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.service.checkNotInMainThread
@@ -54,6 +58,8 @@ class FeedContentState(
private var lastFeedKey: String? = null
override val isRefreshing: MutableState<Boolean> = mutableStateOf(false)
fun sendToTop() {
if (scrolltoTopPending) return
@@ -72,16 +78,21 @@ class FeedContentState(
fun refreshSuspended() {
checkNotInMainThread()
lastFeedKey = localFilter.feedKey()
val notes = localFilter.loadTop().distinctBy { it.idHex }.toImmutableList()
isRefreshing.value = true
try {
lastFeedKey = localFilter.feedKey()
val notes = localFilter.loadTop().distinctBy { it.idHex }.toImmutableList()
val oldNotesState = _feedContent.value
if (oldNotesState is FeedState.Loaded) {
if (!equalImmutableLists(notes, oldNotesState.feed.value.list)) {
val oldNotesState = _feedContent.value
if (oldNotesState is FeedState.Loaded) {
if (!equalImmutableLists(notes, oldNotesState.feed.value.list)) {
updateFeed(notes)
}
} else {
updateFeed(notes)
}
} else {
updateFeed(notes)
} finally {
isRefreshing.value = false
}
}

View File

@@ -20,6 +20,10 @@
*/
package com.vitorpamplona.amethyst.ui.feeds
import androidx.compose.runtime.MutableState
interface InvalidatableContent {
fun invalidateData(ignoreIfDoing: Boolean = false)
val isRefreshing: MutableState<Boolean>
}

View File

@@ -260,6 +260,8 @@ abstract class FeedViewModel(
InvalidatableContent {
val feedState = FeedContentState(localFilter, viewModelScope)
override val isRefreshing = feedState.isRefreshing
fun sendToTop() = feedState.sendToTop()
suspend fun sentToTop() = feedState.sentToTop()

View File

@@ -21,6 +21,7 @@
package com.vitorpamplona.amethyst.ui.screen
import android.util.Log
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
@@ -107,19 +108,27 @@ open class UserFeedViewModel(
viewModelScope.launch(Dispatchers.Default) { refreshSuspended() }
}
override val isRefreshing: MutableState<Boolean> = mutableStateOf(false)
private fun refreshSuspended() {
checkNotInMainThread()
val notes = dataSource.loadTop().toImmutableList()
try {
isRefreshing.value = true
val oldNotesState = _feedContent.value
if (oldNotesState is UserFeedState.Loaded) {
// Using size as a proxy for has changed.
if (!equalImmutableLists(notes, oldNotesState.feed.value)) {
val notes = dataSource.loadTop().toImmutableList()
val oldNotesState = _feedContent.value
if (oldNotesState is UserFeedState.Loaded) {
// Using size as a proxy for has changed.
if (!equalImmutableLists(notes, oldNotesState.feed.value)) {
updateFeed(notes)
}
} else {
updateFeed(notes)
}
} else {
updateFeed(notes)
} finally {
isRefreshing.value = false
}
}

View File

@@ -22,7 +22,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications
import android.util.Log
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
@@ -72,6 +74,8 @@ class CardFeedContentState(
private var lastFeedKey: String? = null
override val isRefreshing: MutableState<Boolean> = mutableStateOf(false)
fun sendToTop() {
if (scrolltoTopPending) return
@@ -94,41 +98,47 @@ class CardFeedContentState(
private fun refreshSuspended() {
checkNotInMainThread()
val notes = localFilter.feed()
lastFeedKey = localFilter.feedKey()
try {
isRefreshing.value = true
val thisAccount = (localFilter as? NotificationFeedFilter)?.account
val lastNotesCopy = if (thisAccount == lastAccount) lastNotes else null
val notes = localFilter.feed()
lastFeedKey = localFilter.feedKey()
val oldNotesState = _feedContent.value
if (lastNotesCopy != null && oldNotesState is CardFeedState.Loaded) {
val newCards = convertToCard(notes.minus(lastNotesCopy))
if (newCards.isNotEmpty()) {
val thisAccount = (localFilter as? NotificationFeedFilter)?.account
val lastNotesCopy = if (thisAccount == lastAccount) lastNotes else null
val oldNotesState = _feedContent.value
if (lastNotesCopy != null && oldNotesState is CardFeedState.Loaded) {
val newCards = convertToCard(notes.minus(lastNotesCopy))
if (newCards.isNotEmpty()) {
lastNotes = notes.toSet()
lastAccount = (localFilter as? NotificationFeedFilter)?.account
val updatedCards =
(oldNotesState.feed.value.list + newCards)
.distinctBy { it.id() }
.sortedWith(DefaultFeedOrderCard)
.take(localFilter.limit())
.toImmutableList()
if (!equalImmutableLists(oldNotesState.feed.value.list, updatedCards)) {
updateFeed(updatedCards)
}
}
} else {
lastNotes = notes.toSet()
lastAccount = (localFilter as? NotificationFeedFilter)?.account
val updatedCards =
(oldNotesState.feed.value.list + newCards)
.distinctBy { it.id() }
val cards =
convertToCard(notes)
.sortedWith(DefaultFeedOrderCard)
.take(localFilter.limit())
.toImmutableList()
if (!equalImmutableLists(oldNotesState.feed.value.list, updatedCards)) {
updateFeed(updatedCards)
}
updateFeed(cards)
}
} else {
lastNotes = notes.toSet()
lastAccount = (localFilter as? NotificationFeedFilter)?.account
val cards =
convertToCard(notes)
.sortedWith(DefaultFeedOrderCard)
.take(localFilter.limit())
.toImmutableList()
updateFeed(cards)
} finally {
isRefreshing.value = false
}
}

View File

@@ -21,7 +21,9 @@
package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile
import android.util.Log
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.model.RelayInfo
@@ -50,28 +52,36 @@ class RelayFeedViewModel :
var currentUser: User? = null
override val isRefreshing: MutableState<Boolean> = mutableStateOf(false)
fun refresh() {
viewModelScope.launch(Dispatchers.Default) { refreshSuspended() }
}
fun refreshSuspended() {
val beingUsed = currentUser?.relaysBeingUsed?.values ?: emptyList()
val beingUsedSet = currentUser?.relaysBeingUsed?.keys ?: emptySet()
try {
isRefreshing.value = true
val newRelaysFromRecord =
currentUser?.latestContactList?.relays()?.entries?.mapNotNullTo(HashSet()) {
val url = RelayUrlFormatter.normalize(it.key)
if (url !in beingUsedSet) {
RelayInfo(url, 0, 0)
} else {
null
val beingUsed = currentUser?.relaysBeingUsed?.values ?: emptyList()
val beingUsedSet = currentUser?.relaysBeingUsed?.keys ?: emptySet()
val newRelaysFromRecord =
currentUser?.latestContactList?.relays()?.entries?.mapNotNullTo(HashSet()) {
val url = RelayUrlFormatter.normalize(it.key)
if (url !in beingUsedSet) {
RelayInfo(url, 0, 0)
} else {
null
}
}
}
?: emptyList()
?: emptyList()
val newList = (beingUsed + newRelaysFromRecord).sortedWith(order)
val newList = (beingUsed + newRelaysFromRecord).sortedWith(order)
_feedContent.update { newList }
_feedContent.update { newList }
} finally {
isRefreshing.value = false
}
}
val listener: (UserState) -> Unit = { invalidateData() }

View File

@@ -21,6 +21,7 @@
package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings
import android.util.Log
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
@@ -63,6 +64,8 @@ open class StringFeedViewModel(
private val _feedContent = MutableStateFlow<StringFeedState>(StringFeedState.Loading)
val feedContent = _feedContent.asStateFlow()
override val isRefreshing: MutableState<Boolean> = mutableStateOf(false)
private fun refresh() {
viewModelScope.launch(Dispatchers.Default) { refreshSuspended() }
}
@@ -70,16 +73,22 @@ open class StringFeedViewModel(
private fun refreshSuspended() {
checkNotInMainThread()
val notes = dataSource.loadTop().toImmutableList()
try {
isRefreshing.value = true
val oldNotesState = _feedContent.value
if (oldNotesState is StringFeedState.Loaded) {
// Using size as a proxy for has changed.
if (!equalImmutableLists(notes, oldNotesState.feed.value)) {
val notes = dataSource.loadTop().toImmutableList()
val oldNotesState = _feedContent.value
if (oldNotesState is StringFeedState.Loaded) {
// Using size as a proxy for has changed.
if (!equalImmutableLists(notes, oldNotesState.feed.value)) {
updateFeed(notes)
}
} else {
updateFeed(notes)
}
} else {
updateFeed(notes)
} finally {
isRefreshing.value = false
}
}