feat: run EventSync in background by scoping it to AccountViewModel
Move EventSyncViewModel from a screen-scoped ViewModel to a plain class held by AccountViewModel (activity-scoped). The sync job now runs on AccountViewModel's viewModelScope, so it continues when the user navigates away. The back button no longer cancels the sync. https://claude.ai/code/session_01U8qF9mK4UBvXsXP1zNMXfX
This commit is contained in:
+2
@@ -79,6 +79,7 @@ import com.vitorpamplona.amethyst.ui.note.showAmount
|
||||
import com.vitorpamplona.amethyst.ui.note.showAmountInteger
|
||||
import com.vitorpamplona.amethyst.ui.screen.UiSettingsState
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.CombinedZap
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.eventsync.EventSyncViewModel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.tor.TorSettingsFlow
|
||||
import com.vitorpamplona.amethyst.ui.tor.TorType
|
||||
@@ -175,6 +176,7 @@ class AccountViewModel(
|
||||
val toastManager = ToastManager()
|
||||
val broadcastTracker = BroadcastTracker()
|
||||
val feedStates = AccountFeedContentStates(account, viewModelScope)
|
||||
val eventSyncViewModel = EventSyncViewModel(account, viewModelScope)
|
||||
|
||||
val tempManualPaymentCache = LruCache<String, List<ZapPaymentHandler.Payable>>(5)
|
||||
|
||||
|
||||
+2
-7
@@ -48,7 +48,6 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton
|
||||
@@ -60,8 +59,7 @@ fun EventSyncScreen(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val syncViewModel: EventSyncViewModel =
|
||||
viewModel(factory = EventSyncViewModel.Factory(accountViewModel.account))
|
||||
val syncViewModel = accountViewModel.eventSyncViewModel
|
||||
|
||||
val syncState by syncViewModel.syncState.collectAsStateWithLifecycle()
|
||||
val isMobileOrMetered by accountViewModel.settings.isMobileOrMeteredConnection.collectAsStateWithLifecycle()
|
||||
@@ -70,10 +68,7 @@ fun EventSyncScreen(
|
||||
topBar = {
|
||||
TopBarWithBackButton(
|
||||
caption = stringRes(R.string.event_sync_title),
|
||||
popBack = {
|
||||
syncViewModel.cancel()
|
||||
nav.popBack()
|
||||
},
|
||||
popBack = nav::popBack,
|
||||
)
|
||||
},
|
||||
) { padding ->
|
||||
|
||||
+7
-12
@@ -21,15 +21,13 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.eventsync
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.IRequestListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.single.newSubId
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
@@ -47,10 +45,14 @@ import kotlinx.coroutines.withTimeoutOrNull
|
||||
*
|
||||
* The procedure iterates over every relay URL in LocalCache.relayHints.relayDB.
|
||||
* Events are deduplicated per destination to avoid redundant sends.
|
||||
*
|
||||
* Scoped to the AccountViewModel so the sync continues in the background while
|
||||
* the user navigates to other screens or away from the app.
|
||||
*/
|
||||
class EventSyncViewModel(
|
||||
val account: Account,
|
||||
) : ViewModel() {
|
||||
private val scope: CoroutineScope,
|
||||
) {
|
||||
sealed class SyncState {
|
||||
object Idle : SyncState()
|
||||
|
||||
@@ -81,7 +83,7 @@ class EventSyncViewModel(
|
||||
fun start() {
|
||||
if (_syncState.value is SyncState.Running) return
|
||||
syncJob =
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
runSync()
|
||||
}
|
||||
}
|
||||
@@ -276,11 +278,4 @@ class EventSyncViewModel(
|
||||
account.client.close(subId)
|
||||
done.close()
|
||||
}
|
||||
|
||||
class Factory(
|
||||
val account: Account,
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T = EventSyncViewModel(account) as T
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user