diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt index ee3a3670d..f4fc37874 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt @@ -13,6 +13,9 @@ import nostr.postr.events.Event * RelayPool manages the connection to multiple Relays and lets consumers deal with simple events. */ object RelayPool: Relay.Listener { + + val scope = CoroutineScope(Job() + Dispatchers.IO) + private var relays = listOf() private var listeners = setOf() @@ -116,7 +119,6 @@ object RelayPool: Relay.Listener { val live: RelayPoolLiveData = RelayPoolLiveData(this) private fun refreshObservers() { - val scope = CoroutineScope(Job() + Dispatchers.Main) scope.launch { live.refresh() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt index 2eeb14032..947c46cce 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt @@ -22,6 +22,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class CardFeedViewModel(val dataSource: NostrDataSource): ViewModel() { private val _feedContent = MutableStateFlow(CardFeedState.Loading) @@ -29,11 +30,8 @@ class CardFeedViewModel(val dataSource: NostrDataSource): ViewModel() { private var lastNotes: List? = null - fun refresh() { - val scope = CoroutineScope(Job() + Dispatchers.Default) - scope.launch { - refreshSuspended() - } + suspend fun refresh() = withContext(Dispatchers.IO) { + refreshSuspended() } private fun refreshSuspended() { @@ -83,19 +81,16 @@ class CardFeedViewModel(val dataSource: NostrDataSource): ViewModel() { return (reactionCards + boostCards + textNoteCards).sortedBy { it.createdAt() }.reversed() } - fun updateFeed(notes: List) { - val scope = CoroutineScope(Job() + Dispatchers.Main) - scope.launch { - val currentState = feedContent.value + private fun updateFeed(notes: List) { + val currentState = feedContent.value - if (notes.isEmpty()) { - _feedContent.update { CardFeedState.Empty } - } else if (currentState is CardFeedState.Loaded) { - // updates the current list - currentState.feed.value = notes - } else { - _feedContent.update { CardFeedState.Loaded(mutableStateOf(notes)) } - } + if (notes.isEmpty()) { + _feedContent.update { CardFeedState.Empty } + } else if (currentState is CardFeedState.Loaded) { + // updates the current list + currentState.feed.value = notes + } else { + _feedContent.update { CardFeedState.Loaded(mutableStateOf(notes)) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt index 54d642ab0..f064441fa 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt @@ -28,6 +28,7 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import nostr.postr.events.TextNoteEvent +import java.util.concurrent.atomic.AtomicBoolean class NostrChannelFeedViewModel: FeedViewModel(NostrChannelDataSource) class NostrChatRoomFeedViewModel: FeedViewModel(NostrChatRoomDataSource) @@ -86,25 +87,21 @@ abstract class FeedViewModel(val dataSource: NostrDataSource): ViewModel() } fun refresh() { - viewModelScope.launch(Dispatchers.Default) { + viewModelScope.launch(Dispatchers.IO) { val notes = newListFromDataSource() val oldNotesState = feedContent.value if (oldNotesState is FeedState.Loaded) { if (notes != oldNotesState.feed) { - withContext(Dispatchers.Main) { - updateFeed(notes) - } - } - } else { - withContext(Dispatchers.Main) { updateFeed(notes) } + } else { + updateFeed(notes) } } } - fun updateFeed(notes: List) { + private fun updateFeed(notes: List) { val currentState = feedContent.value if (notes.isEmpty()) { @@ -117,19 +114,18 @@ abstract class FeedViewModel(val dataSource: NostrDataSource): ViewModel() } } - var handlerWaiting = false - fun invalidateData() { - synchronized(handlerWaiting) { - if (handlerWaiting) return + private var handlerWaiting = AtomicBoolean() + @Synchronized + private fun invalidateData() { + if (handlerWaiting.get()) return - handlerWaiting = true + handlerWaiting.set(true) val scope = CoroutineScope(Job() + Dispatchers.Default) scope.launch { delay(100) refresh() - handlerWaiting = false + handlerWaiting.set(false) } - } } private val cacheListener: (LocalCacheState) -> Unit = { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt index ad85ee181..cbe938f54 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt @@ -22,6 +22,8 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.util.concurrent.atomic.AtomicBoolean class NostrUserProfileFollowsUserFeedViewModel(): UserFeedViewModel( NostrUserProfileFollowsDataSource @@ -39,13 +41,11 @@ open class UserFeedViewModel(val dataSource: NostrDataSource): ViewModel() private val _feedContent = MutableStateFlow(UserFeedState.Loading) val feedContent = _feedContent.asStateFlow() - fun refresh() { - val scope = CoroutineScope(Job() + Dispatchers.Default) - scope.launch { - refreshSuspended() - } + suspend fun refresh() = withContext(Dispatchers.IO) { + refreshSuspended() } + private fun refreshSuspended() { val notes = dataSource.loadTop() @@ -59,34 +59,30 @@ open class UserFeedViewModel(val dataSource: NostrDataSource): ViewModel() } } - fun updateFeed(notes: List) { - val scope = CoroutineScope(Job() + Dispatchers.Main) - scope.launch { - val currentState = feedContent.value - - if (notes.isEmpty()) { - _feedContent.update { UserFeedState.Empty } - } else if (currentState is UserFeedState.Loaded) { - // updates the current list - currentState.feed.value = notes - } else { - _feedContent.update { UserFeedState.Loaded(mutableStateOf(notes)) } - } + private fun updateFeed(notes: List) { + val currentState = feedContent.value + if (notes.isEmpty()) { + _feedContent.update { UserFeedState.Empty } + } else if (currentState is UserFeedState.Loaded) { + // updates the current list + currentState.feed.value = notes + } else { + _feedContent.update { UserFeedState.Loaded(mutableStateOf(notes)) } } } - var handlerWaiting = false - fun invalidateData() { - synchronized(handlerWaiting) { - if (handlerWaiting) return + var handlerWaiting = AtomicBoolean() - handlerWaiting = true - val scope = CoroutineScope(Job() + Dispatchers.Default) - scope.launch { - delay(100) - refresh() - handlerWaiting = false - } + @Synchronized + private fun invalidateData() { + if (handlerWaiting.get()) return + + handlerWaiting.set(true) + val scope = CoroutineScope(Job() + Dispatchers.Default) + scope.launch { + delay(100) + refresh() + handlerWaiting.set(false) } }