From 86f976777f849f92881be6cd4dc612253bed4135 Mon Sep 17 00:00:00 2001 From: Janne Mareike Koschinski <janne@kuschku.de> Date: Fri, 1 Dec 2023 00:37:14 +0100 Subject: [PATCH] fix: initial sync --- .../de/chaosdorf/meteroid/sync/SyncManager.kt | 6 +++- .../sync/base/BaseIncrementalSyncHandler.kt | 32 ++++++++++++------- .../de/chaosdorf/meteroid/ui/AppViewModel.kt | 13 ++++++++ .../meteroid/ui/NavigationViewModel.kt | 16 ++++++++++ .../meteroid/ui/navigation/MeteroidTopBar.kt | 2 +- .../meteroid/ui/wrapped/WrappedSlide.kt | 8 ++--- 6 files changed, 60 insertions(+), 17 deletions(-) diff --git a/app/src/main/kotlin/de/chaosdorf/meteroid/sync/SyncManager.kt b/app/src/main/kotlin/de/chaosdorf/meteroid/sync/SyncManager.kt index e548fc1..1a3cbf3 100644 --- a/app/src/main/kotlin/de/chaosdorf/meteroid/sync/SyncManager.kt +++ b/app/src/main/kotlin/de/chaosdorf/meteroid/sync/SyncManager.kt @@ -57,6 +57,10 @@ class SyncManager @Inject constructor( userSyncHandler.sync(server) drinkSyncHandler.sync(server) if (user != null) { + Log.i( + "SyncManager", + "syncing transactions for user ${user.userId}, incremental ${incremental}" + ) if (incremental) { transactionSyncHandler.syncIncremental(Pair(server, user.userId)) } else { @@ -65,7 +69,7 @@ class SyncManager @Inject constructor( } } catch (e: Exception) { Log.e( - "Sync", + "SyncManager", "Could not finish transaction for ${user?.name} (${user?.userId}) on ${server.url}", e ) diff --git a/app/src/main/kotlin/de/chaosdorf/meteroid/sync/base/BaseIncrementalSyncHandler.kt b/app/src/main/kotlin/de/chaosdorf/meteroid/sync/base/BaseIncrementalSyncHandler.kt index 16ae412..0da6217 100644 --- a/app/src/main/kotlin/de/chaosdorf/meteroid/sync/base/BaseIncrementalSyncHandler.kt +++ b/app/src/main/kotlin/de/chaosdorf/meteroid/sync/base/BaseIncrementalSyncHandler.kt @@ -32,34 +32,44 @@ abstract class BaseIncrementalSyncHandler<Context, Entry, Key> : abstract suspend fun loadLatestEntry(context: Context): Entry? abstract suspend fun loadAdded(context: Context, latest: Entry): List<Entry> + override suspend fun sync(context: Context) { + super.sync(context) + } + override suspend fun syncIncremental(context: Context) { if (syncState.compareAndSet(State.Idle, State.Loading) || - syncState.compareAndSet(State.Error(), State.Loading)) { + syncState.compareAndSet(State.Error(), State.Loading) + ) { Log.w(this::class.simpleName, "Started incremental sync") - val success = try { - val result = withTransaction { + try { + withTransaction { val latestEntry = loadLatestEntry(context) if (latestEntry != null) { val addedEntries = loadAdded(context, latestEntry) for (loadedEntry in addedEntries) { store(loadedEntry) } - true } else { - false + // If we can't do an incremental sync, do a full sync + val loadedEntries = loadCurrent(context) + val storedEntries = loadStored(context) + val storedKeys = storedEntries.map(::entryToKey).toSet() + val loadedKeys = loadedEntries.map(::entryToKey).toSet() + val removedKeys = storedKeys - loadedKeys + for (removedKey in removedKeys) { + Log.e("SyncHandler", "deleting: $removedKey") + delete(removedKey) + } + for (loadedEntry in loadedEntries) { + store(loadedEntry) + } } } syncState.value = State.Idle Log.w(this::class.simpleName, "Finished incremental sync") - result } catch (e: Exception) { Log.e(this::class.simpleName, "Error while syncing data", e) syncState.value = State.Error("Error while syncing data: $e") - false - } - // If we can't do an incremental sync, do a full sync - if (!success) { - sync(context) } } else { Log.w(this::class.simpleName, "Already syncing, disregarding sync request") diff --git a/app/src/main/kotlin/de/chaosdorf/meteroid/ui/AppViewModel.kt b/app/src/main/kotlin/de/chaosdorf/meteroid/ui/AppViewModel.kt index c940440..cd55bf2 100644 --- a/app/src/main/kotlin/de/chaosdorf/meteroid/ui/AppViewModel.kt +++ b/app/src/main/kotlin/de/chaosdorf/meteroid/ui/AppViewModel.kt @@ -33,11 +33,14 @@ import de.chaosdorf.meteroid.storage.AccountPreferences import de.chaosdorf.meteroid.sync.SyncManager import de.chaosdorf.meteroid.ui.navigation.Routes import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel @@ -81,4 +84,14 @@ class AppViewModel @Inject constructor( }.mapLatest { server -> server?.let { syncManager.checkOffline(it) } ?: false }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false) + + init { + viewModelScope.launch { + serverRepository.getAllFlow().distinctUntilChanged().collectLatest { list -> + for (server in list) { + syncManager.sync(server, null, incremental = false) + } + } + } + } } diff --git a/app/src/main/kotlin/de/chaosdorf/meteroid/ui/NavigationViewModel.kt b/app/src/main/kotlin/de/chaosdorf/meteroid/ui/NavigationViewModel.kt index 6346fe5..29cd7a4 100644 --- a/app/src/main/kotlin/de/chaosdorf/meteroid/ui/NavigationViewModel.kt +++ b/app/src/main/kotlin/de/chaosdorf/meteroid/ui/NavigationViewModel.kt @@ -33,9 +33,12 @@ import de.chaosdorf.meteroid.model.ServerId import de.chaosdorf.meteroid.model.ServerRepository import de.chaosdorf.meteroid.model.UserRepository import de.chaosdorf.meteroid.sync.AccountProvider +import de.chaosdorf.meteroid.sync.SyncManager import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.stateIn @@ -44,6 +47,7 @@ import javax.inject.Inject @HiltViewModel class NavigationViewModel @Inject constructor( + syncManager: SyncManager, serverRepository: ServerRepository, userRepository: UserRepository, pinnedUserRepository: PinnedUserRepository, @@ -73,6 +77,18 @@ class NavigationViewModel @Inject constructor( else pinnedUserRepository.isPinnedFlow(it.first, it.second) }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null) + init { + viewModelScope.launch { + combine(server, user) { server, user -> + server?.let { Pair(server, user) } + }.distinctUntilChanged().collectLatest { account -> + account?.let { (server, user) -> + syncManager.sync(server, user, incremental = true) + } + } + } + } + fun togglePin(serverId: ServerId, userId: UserId) { viewModelScope.launch { accountProvider.togglePin(serverId, userId) diff --git a/app/src/main/kotlin/de/chaosdorf/meteroid/ui/navigation/MeteroidTopBar.kt b/app/src/main/kotlin/de/chaosdorf/meteroid/ui/navigation/MeteroidTopBar.kt index a018e1b..a653449 100644 --- a/app/src/main/kotlin/de/chaosdorf/meteroid/ui/navigation/MeteroidTopBar.kt +++ b/app/src/main/kotlin/de/chaosdorf/meteroid/ui/navigation/MeteroidTopBar.kt @@ -83,7 +83,7 @@ fun MeteroidTopBar( ?.replace("{server}", it.arguments?.getLong("server")?.toString() ?: "{server}") ?.replace("{user}", it.arguments?.getLong("user")?.toString() ?: "{user}") } - Log.e("Navigation", "BACKSTACK: [${backstackEntries.joinToString(" › ")}]") + Log.i("Navigation", "BACKSTACK: [${backstackEntries.joinToString(" › ")}]") } val avatarPainter = rememberAvatarPainter( diff --git a/app/src/main/kotlin/de/chaosdorf/meteroid/ui/wrapped/WrappedSlide.kt b/app/src/main/kotlin/de/chaosdorf/meteroid/ui/wrapped/WrappedSlide.kt index ec262ad..c326c1a 100644 --- a/app/src/main/kotlin/de/chaosdorf/meteroid/ui/wrapped/WrappedSlide.kt +++ b/app/src/main/kotlin/de/chaosdorf/meteroid/ui/wrapped/WrappedSlide.kt @@ -109,13 +109,13 @@ sealed class WrappedSlide { override fun create( transactions: List<Transaction>, drinks: Map<DrinkId, Drink> - ): WrappedSlide = transactions + ): WrappedSlide? = transactions .map { it.timestamp.toLocalDateTime(TimeZone.currentSystemDefault()) } .groupingBy { Pair(it.dayOfWeek, it.hour) } .eachCount() - .maxBy { it.value } - .key - .let { (dayOfWeek, hour) -> + .maxByOrNull { it.value } + ?.key + ?.let { (dayOfWeek, hour) -> MostActive(dayOfWeek, hour) } } -- GitLab