From 8faf23d4bade011b4cb426d5c24ce4c4641f89e2 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 10 Jan 2023 11:04:52 -0800 Subject: [PATCH] load library list using room db --- .../java/app/omnivore/omnivore/DataService.kt | 25 ++++- .../omnivore/networking/SavedItemQuery.kt | 1 + .../omnivore/ui/library/LibraryViewModel.kt | 97 ++++++++++--------- 3 files changed, 75 insertions(+), 48 deletions(-) diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/DataService.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/DataService.kt index e155ecc82..80790f8c1 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/DataService.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/DataService.kt @@ -18,15 +18,32 @@ class DataService @Inject constructor( ).build() } -suspend fun DataService.sync(since: String, cursor: String?, limit: Int = 15): Boolean { - val syncResult = networker.savedItemUpdates(cursor = cursor, limit = limit, since = since) ?: return false +suspend fun DataService.sync(since: String, cursor: String?, limit: Int = 15): SavedItemSyncMarker { + val syncResult = networker.savedItemUpdates(cursor = cursor, limit = limit, since = since) ?: return SavedItemSyncMarker.errorResult Log.d("sync", "count: ${syncResult.totalCount}; sync result: $syncResult") - // TODO: Store items in Room DB - return true + db.savedItemDao().insertAll(syncResult.items) + + return SavedItemSyncMarker( + hasError = false, + hasMoreItems = syncResult.hasMoreItems, + cursor = syncResult.cursor, + count = syncResult.items.size + ) } suspend fun DataService.syncOfflineItemsWithServerIfNeeded() { // TODO: implement this } + +data class SavedItemSyncMarker( + val hasError: Boolean, + val hasMoreItems: Boolean, + val count: Int, + val cursor: String? +) { + companion object { + val errorResult = SavedItemSyncMarker(hasError = true, hasMoreItems = true, cursor = null, count = 0) + } +} diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/networking/SavedItemQuery.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/networking/SavedItemQuery.kt index 882c3d304..0133d3dbd 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/networking/SavedItemQuery.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/networking/SavedItemQuery.kt @@ -53,6 +53,7 @@ suspend fun Networker.savedItem(slug: String): SavedItemQueryResponse { updatedAt = null, //updatedAtString?.let { str -> LocalDate.parse(str) }, TODO: fix date parsing createdByMe = it.highlightFields.createdByMe, markedForDeletion = false, + serverSyncStatus = 0 ) } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/library/LibraryViewModel.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/library/LibraryViewModel.kt index 5fbb65b5e..1b43c0d67 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/library/LibraryViewModel.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/library/LibraryViewModel.kt @@ -56,63 +56,72 @@ class LibraryViewModel @Inject constructor( } } - suspend fun syncItems() { + private suspend fun syncItems() { val syncStart = LocalDateTime.now() val lastSyncDate = getLastSyncTime() ?: LocalDateTime.MIN withContext(Dispatchers.IO) { - dataService.syncOfflineItemsWithServerIfNeeded() - dataService.sync(since = lastSyncDate.toString(), cursor = null) + performItemSync(cursor = null, since = lastSyncDate.toString(), count = 0) } } - fun load(clearPreviousSearch: Boolean = false) { + private suspend fun performItemSync(cursor: String?, since: String, count: Int) { + dataService.syncOfflineItemsWithServerIfNeeded() + val result = dataService.sync(since = since, cursor = cursor) + val totalCount = count + result.count + + Log.d("sync", "grabbed ${result.count} items in this batch") + + if (totalCount < 180 && !result.hasError && result.hasMoreItems && result.cursor != null) { + performItemSync(cursor = result.cursor, since = since, count = totalCount) + } else { + Log.d("sync", "grabbed $count total items") + + val items = dataService.db.savedItemDao().getLibraryData() + + itemsLiveData.postValue(items) + + CoroutineScope(Dispatchers.Main).launch { + isRefreshing = false + } + } + } + + private suspend fun performSearch(clearPreviousSearch: Boolean) { if (clearPreviousSearch) { cursor = null } + val thisSearchIdx = searchIdx + searchIdx += 1 + + // Execute the search + val searchResult = networker.typeaheadSearch(searchTextLiveData.value ?: "") + + // Search results aren't guaranteed to return in order so this + // will discard old results that are returned while a user is typing. + // For example if a user types 'Canucks', often the search results + // for 'C' are returned after 'Canucks' because it takes the backend + // much longer to compute. + if (thisSearchIdx in 1..receivedIdx) { + return + } + + val previousItems = if (clearPreviousSearch) listOf() else searchedItems + searchedItems = previousItems.plus(searchResult.cardsData) + itemsLiveData.postValue(searchedItems) + + CoroutineScope(Dispatchers.Main).launch { + isRefreshing = false + } + } + + fun load(clearPreviousSearch: Boolean = false) { viewModelScope.launch { - syncItems() - val thisSearchIdx = searchIdx - searchIdx += 1 - - // Execute the search - val searchResult = - if (searchTextLiveData.value != "") { - networker.typeaheadSearch(searchTextLiveData.value ?: "") - } else { - networker.search(cursor = cursor, query = searchQuery()) - } - - // Search results aren't guaranteed to return in order so this - // will discard old results that are returned while a user is typing. - // For example if a user types 'Canucks', often the search results - // for 'C' are returned after 'Canucks' because it takes the backend - // much longer to compute. - if (thisSearchIdx in 1..receivedIdx) { - return@launch - } - - receivedIdx = thisSearchIdx - cursor = searchResult.cursor - - if (searchTextLiveData.value != "" || clearPreviousSearch) { - val previousItems = if (clearPreviousSearch) listOf() else searchedItems - searchedItems = previousItems.plus(searchResult.cardsData) - itemsLiveData.postValue(searchedItems) + if (searchTextLiveData.value != "") { + performSearch(clearPreviousSearch) } else { - items = items.plus(searchResult.cardsData) - itemsLiveData.postValue(items) - } - -// withContext(Dispatchers.IO) { -// dataService.db.savedItemDao().insertAll(items) -// val items = dataService.db.savedItemDao().getLibraryData() -// Log.d("appDatabase", "libraryData: $items") -// } - - CoroutineScope(Dispatchers.Main).launch { - isRefreshing = false + syncItems() } } }