Adds an isRefreshing status for all feeds.
This commit is contained in:
@@ -21,7 +21,11 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.feeds
|
package com.vitorpamplona.amethyst.ui.feeds
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.Stable
|
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 androidx.lifecycle.viewModelScope
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||||
@@ -54,6 +58,8 @@ class FeedContentState(
|
|||||||
|
|
||||||
private var lastFeedKey: String? = null
|
private var lastFeedKey: String? = null
|
||||||
|
|
||||||
|
override val isRefreshing: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
|
||||||
fun sendToTop() {
|
fun sendToTop() {
|
||||||
if (scrolltoTopPending) return
|
if (scrolltoTopPending) return
|
||||||
|
|
||||||
@@ -72,16 +78,21 @@ class FeedContentState(
|
|||||||
fun refreshSuspended() {
|
fun refreshSuspended() {
|
||||||
checkNotInMainThread()
|
checkNotInMainThread()
|
||||||
|
|
||||||
lastFeedKey = localFilter.feedKey()
|
isRefreshing.value = true
|
||||||
val notes = localFilter.loadTop().distinctBy { it.idHex }.toImmutableList()
|
try {
|
||||||
|
lastFeedKey = localFilter.feedKey()
|
||||||
|
val notes = localFilter.loadTop().distinctBy { it.idHex }.toImmutableList()
|
||||||
|
|
||||||
val oldNotesState = _feedContent.value
|
val oldNotesState = _feedContent.value
|
||||||
if (oldNotesState is FeedState.Loaded) {
|
if (oldNotesState is FeedState.Loaded) {
|
||||||
if (!equalImmutableLists(notes, oldNotesState.feed.value.list)) {
|
if (!equalImmutableLists(notes, oldNotesState.feed.value.list)) {
|
||||||
|
updateFeed(notes)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
updateFeed(notes)
|
updateFeed(notes)
|
||||||
}
|
}
|
||||||
} else {
|
} finally {
|
||||||
updateFeed(notes)
|
isRefreshing.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.feeds
|
package com.vitorpamplona.amethyst.ui.feeds
|
||||||
|
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
|
||||||
interface InvalidatableContent {
|
interface InvalidatableContent {
|
||||||
fun invalidateData(ignoreIfDoing: Boolean = false)
|
fun invalidateData(ignoreIfDoing: Boolean = false)
|
||||||
|
|
||||||
|
val isRefreshing: MutableState<Boolean>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,6 +260,8 @@ abstract class FeedViewModel(
|
|||||||
InvalidatableContent {
|
InvalidatableContent {
|
||||||
val feedState = FeedContentState(localFilter, viewModelScope)
|
val feedState = FeedContentState(localFilter, viewModelScope)
|
||||||
|
|
||||||
|
override val isRefreshing = feedState.isRefreshing
|
||||||
|
|
||||||
fun sendToTop() = feedState.sendToTop()
|
fun sendToTop() = feedState.sendToTop()
|
||||||
|
|
||||||
suspend fun sentToTop() = feedState.sentToTop()
|
suspend fun sentToTop() = feedState.sentToTop()
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.screen
|
package com.vitorpamplona.amethyst.ui.screen
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
@@ -107,19 +108,27 @@ open class UserFeedViewModel(
|
|||||||
viewModelScope.launch(Dispatchers.Default) { refreshSuspended() }
|
viewModelScope.launch(Dispatchers.Default) { refreshSuspended() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val isRefreshing: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
|
||||||
private fun refreshSuspended() {
|
private fun refreshSuspended() {
|
||||||
checkNotInMainThread()
|
checkNotInMainThread()
|
||||||
|
|
||||||
val notes = dataSource.loadTop().toImmutableList()
|
try {
|
||||||
|
isRefreshing.value = true
|
||||||
|
|
||||||
val oldNotesState = _feedContent.value
|
val notes = dataSource.loadTop().toImmutableList()
|
||||||
if (oldNotesState is UserFeedState.Loaded) {
|
|
||||||
// Using size as a proxy for has changed.
|
val oldNotesState = _feedContent.value
|
||||||
if (!equalImmutableLists(notes, oldNotesState.feed.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)
|
updateFeed(notes)
|
||||||
}
|
}
|
||||||
} else {
|
} finally {
|
||||||
updateFeed(notes)
|
isRefreshing.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+35
-25
@@ -22,7 +22,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications
|
|||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import com.vitorpamplona.amethyst.model.Account
|
import com.vitorpamplona.amethyst.model.Account
|
||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
@@ -72,6 +74,8 @@ class CardFeedContentState(
|
|||||||
|
|
||||||
private var lastFeedKey: String? = null
|
private var lastFeedKey: String? = null
|
||||||
|
|
||||||
|
override val isRefreshing: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
|
||||||
fun sendToTop() {
|
fun sendToTop() {
|
||||||
if (scrolltoTopPending) return
|
if (scrolltoTopPending) return
|
||||||
|
|
||||||
@@ -94,41 +98,47 @@ class CardFeedContentState(
|
|||||||
private fun refreshSuspended() {
|
private fun refreshSuspended() {
|
||||||
checkNotInMainThread()
|
checkNotInMainThread()
|
||||||
|
|
||||||
val notes = localFilter.feed()
|
try {
|
||||||
lastFeedKey = localFilter.feedKey()
|
isRefreshing.value = true
|
||||||
|
|
||||||
val thisAccount = (localFilter as? NotificationFeedFilter)?.account
|
val notes = localFilter.feed()
|
||||||
val lastNotesCopy = if (thisAccount == lastAccount) lastNotes else null
|
lastFeedKey = localFilter.feedKey()
|
||||||
|
|
||||||
val oldNotesState = _feedContent.value
|
val thisAccount = (localFilter as? NotificationFeedFilter)?.account
|
||||||
if (lastNotesCopy != null && oldNotesState is CardFeedState.Loaded) {
|
val lastNotesCopy = if (thisAccount == lastAccount) lastNotes else null
|
||||||
val newCards = convertToCard(notes.minus(lastNotesCopy))
|
|
||||||
if (newCards.isNotEmpty()) {
|
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()
|
lastNotes = notes.toSet()
|
||||||
lastAccount = (localFilter as? NotificationFeedFilter)?.account
|
lastAccount = (localFilter as? NotificationFeedFilter)?.account
|
||||||
|
|
||||||
val updatedCards =
|
val cards =
|
||||||
(oldNotesState.feed.value.list + newCards)
|
convertToCard(notes)
|
||||||
.distinctBy { it.id() }
|
|
||||||
.sortedWith(DefaultFeedOrderCard)
|
.sortedWith(DefaultFeedOrderCard)
|
||||||
.take(localFilter.limit())
|
.take(localFilter.limit())
|
||||||
.toImmutableList()
|
.toImmutableList()
|
||||||
|
|
||||||
if (!equalImmutableLists(oldNotesState.feed.value.list, updatedCards)) {
|
updateFeed(cards)
|
||||||
updateFeed(updatedCards)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} finally {
|
||||||
lastNotes = notes.toSet()
|
isRefreshing.value = false
|
||||||
lastAccount = (localFilter as? NotificationFeedFilter)?.account
|
|
||||||
|
|
||||||
val cards =
|
|
||||||
convertToCard(notes)
|
|
||||||
.sortedWith(DefaultFeedOrderCard)
|
|
||||||
.take(localFilter.limit())
|
|
||||||
.toImmutableList()
|
|
||||||
|
|
||||||
updateFeed(cards)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+23
-13
@@ -21,7 +21,9 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.vitorpamplona.amethyst.model.RelayInfo
|
import com.vitorpamplona.amethyst.model.RelayInfo
|
||||||
@@ -50,28 +52,36 @@ class RelayFeedViewModel :
|
|||||||
|
|
||||||
var currentUser: User? = null
|
var currentUser: User? = null
|
||||||
|
|
||||||
|
override val isRefreshing: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
|
||||||
fun refresh() {
|
fun refresh() {
|
||||||
viewModelScope.launch(Dispatchers.Default) { refreshSuspended() }
|
viewModelScope.launch(Dispatchers.Default) { refreshSuspended() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refreshSuspended() {
|
fun refreshSuspended() {
|
||||||
val beingUsed = currentUser?.relaysBeingUsed?.values ?: emptyList()
|
try {
|
||||||
val beingUsedSet = currentUser?.relaysBeingUsed?.keys ?: emptySet()
|
isRefreshing.value = true
|
||||||
|
|
||||||
val newRelaysFromRecord =
|
val beingUsed = currentUser?.relaysBeingUsed?.values ?: emptyList()
|
||||||
currentUser?.latestContactList?.relays()?.entries?.mapNotNullTo(HashSet()) {
|
val beingUsedSet = currentUser?.relaysBeingUsed?.keys ?: emptySet()
|
||||||
val url = RelayUrlFormatter.normalize(it.key)
|
|
||||||
if (url !in beingUsedSet) {
|
val newRelaysFromRecord =
|
||||||
RelayInfo(url, 0, 0)
|
currentUser?.latestContactList?.relays()?.entries?.mapNotNullTo(HashSet()) {
|
||||||
} else {
|
val url = RelayUrlFormatter.normalize(it.key)
|
||||||
null
|
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() }
|
val listener: (UserState) -> Unit = { invalidateData() }
|
||||||
|
|||||||
+16
-7
@@ -21,6 +21,7 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
@@ -63,6 +64,8 @@ open class StringFeedViewModel(
|
|||||||
private val _feedContent = MutableStateFlow<StringFeedState>(StringFeedState.Loading)
|
private val _feedContent = MutableStateFlow<StringFeedState>(StringFeedState.Loading)
|
||||||
val feedContent = _feedContent.asStateFlow()
|
val feedContent = _feedContent.asStateFlow()
|
||||||
|
|
||||||
|
override val isRefreshing: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
|
||||||
private fun refresh() {
|
private fun refresh() {
|
||||||
viewModelScope.launch(Dispatchers.Default) { refreshSuspended() }
|
viewModelScope.launch(Dispatchers.Default) { refreshSuspended() }
|
||||||
}
|
}
|
||||||
@@ -70,16 +73,22 @@ open class StringFeedViewModel(
|
|||||||
private fun refreshSuspended() {
|
private fun refreshSuspended() {
|
||||||
checkNotInMainThread()
|
checkNotInMainThread()
|
||||||
|
|
||||||
val notes = dataSource.loadTop().toImmutableList()
|
try {
|
||||||
|
isRefreshing.value = true
|
||||||
|
|
||||||
val oldNotesState = _feedContent.value
|
val notes = dataSource.loadTop().toImmutableList()
|
||||||
if (oldNotesState is StringFeedState.Loaded) {
|
|
||||||
// Using size as a proxy for has changed.
|
val oldNotesState = _feedContent.value
|
||||||
if (!equalImmutableLists(notes, oldNotesState.feed.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)
|
updateFeed(notes)
|
||||||
}
|
}
|
||||||
} else {
|
} finally {
|
||||||
updateFeed(notes)
|
isRefreshing.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user