mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-04-09 04:18:11 +02:00
Removing the Duplicated Observer infrastructure on User: It wasn't updating observers correctly due to the batch update we use.
This commit is contained in:
parent
8e897762dd
commit
c3aa37534e
@ -20,6 +20,7 @@ import java.util.Locale
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
@ -391,13 +392,13 @@ class Account(
|
||||
}
|
||||
|
||||
init {
|
||||
userProfile().subscribe(object: User.Listener() {
|
||||
override fun onRelayChange() {
|
||||
userProfile().liveRelays.observeForever {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
Client.disconnect()
|
||||
Client.connect(activeRelays() ?: convertLocalRelays())
|
||||
RelayPool.requestAndWatch()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Observers line up here.
|
||||
|
@ -431,7 +431,7 @@ object LocalCache {
|
||||
return
|
||||
}
|
||||
|
||||
Log.d("ZP", "New ZapEvent ${event.content} (${notes.size},${users.size}) ${note.author?.toBestDisplayName()} ${formattedDateTime(event.createdAt)}")
|
||||
//Log.d("ZP", "New ZapEvent ${event.content} (${notes.size},${users.size}) ${note.author?.toBestDisplayName()} ${formattedDateTime(event.createdAt)}")
|
||||
|
||||
// Adds notifications to users.
|
||||
mentions.forEach {
|
||||
@ -461,7 +461,7 @@ object LocalCache {
|
||||
|
||||
note.loadEvent(event, author, mentions, repliesTo)
|
||||
|
||||
Log.d("ZP", "New Zap Request ${event.content} (${notes.size},${users.size}) ${note.author?.toBestDisplayName()} ${formattedDateTime(event.createdAt)}")
|
||||
//Log.d("ZP", "New Zap Request ${event.content} (${notes.size},${users.size}) ${note.author?.toBestDisplayName()} ${formattedDateTime(event.createdAt)}")
|
||||
|
||||
// Adds notifications to users.
|
||||
mentions.forEach {
|
||||
|
@ -2,6 +2,7 @@ package com.vitorpamplona.amethyst.model
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.vitorpamplona.amethyst.lnurl.LnInvoiceUtil
|
||||
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
|
||||
import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource
|
||||
import com.vitorpamplona.amethyst.service.model.LnZapEvent
|
||||
import com.vitorpamplona.amethyst.service.model.ReportEvent
|
||||
@ -89,29 +90,14 @@ class User(val pubkeyHex: String) {
|
||||
|
||||
liveFollows.invalidateData()
|
||||
user.liveFollows.invalidateData()
|
||||
|
||||
updateSubscribers {
|
||||
it.onFollowsChange()
|
||||
}
|
||||
|
||||
user.updateSubscribers {
|
||||
it.onFollowsChange()
|
||||
}
|
||||
}
|
||||
|
||||
fun unfollow(user: User) {
|
||||
follows = follows - user
|
||||
user.followers = user.followers - this
|
||||
|
||||
liveFollows.invalidateData()
|
||||
user.liveFollows.invalidateData()
|
||||
|
||||
updateSubscribers {
|
||||
it.onFollowsChange()
|
||||
}
|
||||
|
||||
user.updateSubscribers {
|
||||
it.onFollowsChange()
|
||||
}
|
||||
}
|
||||
|
||||
fun follow(users: Set<User>, followedAt: Long) {
|
||||
@ -119,42 +105,31 @@ class User(val pubkeyHex: String) {
|
||||
users.forEach {
|
||||
it.followers = it.followers + this
|
||||
it.liveFollows.invalidateData()
|
||||
it.updateSubscribers {
|
||||
it.onFollowsChange()
|
||||
}
|
||||
}
|
||||
|
||||
liveFollows.invalidateData()
|
||||
updateSubscribers {
|
||||
it.onFollowsChange()
|
||||
}
|
||||
}
|
||||
|
||||
fun unfollow(users: Set<User>) {
|
||||
follows = follows - users
|
||||
users.forEach {
|
||||
it.followers = it.followers - this
|
||||
it.liveFollows.invalidateData()
|
||||
it.updateSubscribers {
|
||||
it.onFollowsChange()
|
||||
}
|
||||
}
|
||||
liveFollows.invalidateData()
|
||||
updateSubscribers {
|
||||
it.onFollowsChange()
|
||||
}
|
||||
}
|
||||
|
||||
fun addTaggedPost(note: Note) {
|
||||
if (note !in taggedPosts) {
|
||||
taggedPosts = taggedPosts + note
|
||||
updateSubscribers { it.onNewTaggedPosts() }
|
||||
// No need for Listener yet
|
||||
}
|
||||
}
|
||||
|
||||
fun addNote(note: Note) {
|
||||
if (note !in notes) {
|
||||
notes = notes + note
|
||||
updateSubscribers { it.onNewNotes() }
|
||||
// No need for Listener yet
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,7 +191,6 @@ class User(val pubkeyHex: String) {
|
||||
if (msg !in channel) {
|
||||
messages = messages + Pair(user, channel + msg)
|
||||
liveMessages.invalidateData()
|
||||
updateSubscribers { it.onNewMessage() }
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,7 +211,6 @@ class User(val pubkeyHex: String) {
|
||||
here.counter++
|
||||
}
|
||||
|
||||
updateSubscribers { it.onNewRelayInfo() }
|
||||
liveRelayInfo.invalidateData()
|
||||
}
|
||||
|
||||
@ -251,17 +224,11 @@ class User(val pubkeyHex: String) {
|
||||
updatedFollowsAt = updateAt
|
||||
}
|
||||
|
||||
data class RelayMetadata(val read: Boolean, val write: Boolean, val activeTypes: Set<FeedType>)
|
||||
|
||||
fun updateRelays(relayUse: Map<String, ContactListEvent.ReadWrite>) {
|
||||
if (relays != relayUse) {
|
||||
relays = relayUse
|
||||
listeners.forEach {
|
||||
it.onRelayChange()
|
||||
}
|
||||
liveRelays.invalidateData()
|
||||
}
|
||||
|
||||
liveRelays.invalidateData()
|
||||
}
|
||||
|
||||
fun updateUserInfo(newUserInfo: UserMetadata, updateAt: Long) {
|
||||
@ -287,45 +254,6 @@ class User(val pubkeyHex: String) {
|
||||
} != null
|
||||
}
|
||||
|
||||
// Model Observers
|
||||
private var listeners = setOf<Listener>()
|
||||
|
||||
fun subscribe(listener: Listener) {
|
||||
listeners = listeners.plus(listener)
|
||||
}
|
||||
|
||||
fun unsubscribe(listener: Listener) {
|
||||
listeners = listeners.minus(listener)
|
||||
}
|
||||
|
||||
abstract class Listener {
|
||||
open fun onRelayChange() = Unit
|
||||
open fun onFollowsChange() = Unit
|
||||
open fun onNewTaggedPosts() = Unit
|
||||
open fun onNewNotes() = Unit
|
||||
open fun onNewMessage() = Unit
|
||||
open fun onNewRelayInfo() = Unit
|
||||
open fun onNewReports() = Unit
|
||||
}
|
||||
|
||||
// Refreshes observers in batches.
|
||||
var modelHandlerWaiting = AtomicBoolean()
|
||||
|
||||
@Synchronized
|
||||
fun updateSubscribers(on: (Listener) -> Unit) {
|
||||
if (modelHandlerWaiting.getAndSet(true)) return
|
||||
|
||||
modelHandlerWaiting.set(true)
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Default)
|
||||
scope.launch {
|
||||
delay(100)
|
||||
listeners.forEach {
|
||||
on(it)
|
||||
}
|
||||
modelHandlerWaiting.set(false)
|
||||
}
|
||||
}
|
||||
|
||||
// UI Observers line up here.
|
||||
val liveFollows: UserLiveData = UserLiveData(this)
|
||||
val liveReports: UserLiveData = UserLiveData(this)
|
||||
|
@ -2,11 +2,16 @@ package com.vitorpamplona.amethyst.service
|
||||
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.LocalCacheState
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.model.UserState
|
||||
import com.vitorpamplona.amethyst.service.model.RepostEvent
|
||||
import com.vitorpamplona.amethyst.service.relays.FeedType
|
||||
import com.vitorpamplona.amethyst.service.relays.TypedFilter
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import nostr.postr.JsonFilter
|
||||
import nostr.postr.events.TextNoteEvent
|
||||
import nostr.postr.toHex
|
||||
@ -14,22 +19,26 @@ import nostr.postr.toHex
|
||||
object NostrHomeDataSource: NostrDataSource<Note>("HomeFeed") {
|
||||
lateinit var account: Account
|
||||
|
||||
object cacheListener: User.Listener() {
|
||||
override fun onFollowsChange() {
|
||||
resetFilters()
|
||||
}
|
||||
private val cacheListener: (UserState) -> Unit = {
|
||||
resetFilters()
|
||||
}
|
||||
|
||||
override fun start() {
|
||||
if (this::account.isInitialized)
|
||||
account.userProfile().subscribe(cacheListener)
|
||||
if (this::account.isInitialized) {
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
account.userProfile().liveFollows.observeForever(cacheListener)
|
||||
}
|
||||
}
|
||||
super.start()
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
if (this::account.isInitialized)
|
||||
account.userProfile().unsubscribe(cacheListener)
|
||||
if (this::account.isInitialized) {
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
account.userProfile().liveFollows.removeObserver(cacheListener)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createFollowAccountsFilter(): TypedFilter {
|
||||
|
@ -78,34 +78,38 @@ abstract class FeedViewModel(val dataSource: NostrDataSource<Note>): ViewModel()
|
||||
}
|
||||
|
||||
fun refresh() {
|
||||
viewModelScope.launch(Dispatchers.Default) {
|
||||
val notes = newListFromDataSource()
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Default)
|
||||
scope.launch {
|
||||
refreshSuspended()
|
||||
}
|
||||
}
|
||||
|
||||
val oldNotesState = feedContent.value
|
||||
if (oldNotesState is FeedState.Loaded) {
|
||||
if (notes != oldNotesState.feed) {
|
||||
withContext(Dispatchers.Main) {
|
||||
updateFeed(notes)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
withContext(Dispatchers.Main) {
|
||||
updateFeed(notes)
|
||||
}
|
||||
fun refreshSuspended() {
|
||||
val notes = newListFromDataSource()
|
||||
|
||||
val oldNotesState = feedContent.value
|
||||
if (oldNotesState is FeedState.Loaded) {
|
||||
if (notes != oldNotesState.feed) {
|
||||
updateFeed(notes)
|
||||
}
|
||||
} else {
|
||||
updateFeed(notes)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateFeed(notes: List<Note>) {
|
||||
val currentState = feedContent.value
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
scope.launch {
|
||||
val currentState = feedContent.value
|
||||
|
||||
if (notes.isEmpty()) {
|
||||
_feedContent.update { FeedState.Empty }
|
||||
} else if (currentState is FeedState.Loaded) {
|
||||
// updates the current list
|
||||
currentState.feed.value = notes
|
||||
} else {
|
||||
_feedContent.update { FeedState.Loaded(mutableStateOf(notes)) }
|
||||
if (notes.isEmpty()) {
|
||||
_feedContent.update { FeedState.Empty }
|
||||
} else if (currentState is FeedState.Loaded) {
|
||||
// updates the current list
|
||||
currentState.feed.value = notes
|
||||
} else {
|
||||
_feedContent.update { FeedState.Loaded(mutableStateOf(notes)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,8 @@ import androidx.navigation.NavController
|
||||
import com.google.accompanist.swiperefresh.SwipeRefresh
|
||||
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.model.UserState
|
||||
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
|
||||
import com.vitorpamplona.amethyst.ui.actions.NewRelayListView
|
||||
import com.vitorpamplona.amethyst.ui.note.RelayCompose
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
@ -59,21 +61,20 @@ class RelayFeedViewModel: ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
inner class CacheListener: User.Listener() {
|
||||
override fun onNewRelayInfo() { invalidateData() }
|
||||
override fun onRelayChange() { invalidateData() }
|
||||
val listener: (UserState) -> Unit = {
|
||||
invalidateData()
|
||||
}
|
||||
|
||||
val listener = CacheListener()
|
||||
|
||||
fun subscribeTo(user: User) {
|
||||
currentUser = user
|
||||
user.subscribe(listener)
|
||||
user.liveRelays.observeForever(listener)
|
||||
user.liveRelayInfo.observeForever(listener)
|
||||
invalidateData()
|
||||
}
|
||||
|
||||
fun unsubscribeTo(user: User) {
|
||||
user.unsubscribe(listener)
|
||||
user.liveRelays.removeObserver(listener)
|
||||
user.liveRelayInfo.removeObserver(listener)
|
||||
currentUser = null
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user