From 2f2dfb00a46da24b70ce6decbb7a7bb6c56eb330 Mon Sep 17 00:00:00 2001 From: James Rose Date: Tue, 9 May 2023 11:21:04 -0700 Subject: [PATCH] Mark all news resources read on first sync Otherwise, there will be unread articles until the user clicks through every article that has ever been published. --- .../repository/OfflineFirstNewsRepository.kt | 13 +++++++-- .../OfflineFirstNewsRepositoryTest.kt | 27 +++++++++++++++++++ .../datastore/NiaPreferencesDataSource.kt | 14 +++++++--- 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/core/data/src/main/java/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepository.kt b/core/data/src/main/java/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepository.kt index bd6ed11b4..b18bb9044 100644 --- a/core/data/src/main/java/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepository.kt +++ b/core/data/src/main/java/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepository.kt @@ -63,10 +63,12 @@ class OfflineFirstNewsRepository @Inject constructor( ) .map { it.map(PopulatedNewsResource::asExternalModel) } - override suspend fun syncWith(synchronizer: Synchronizer) = - synchronizer.changeListSync( + override suspend fun syncWith(synchronizer: Synchronizer): Boolean { + var isFirstSync = false + return synchronizer.changeListSync( versionReader = ChangeListVersions::newsResourceVersion, changeListFetcher = { currentVersion -> + isFirstSync = currentVersion <= 0 network.getNewsResourceChangeList(after = currentVersion) }, versionUpdater = { latestVersion -> @@ -94,6 +96,12 @@ class OfflineFirstNewsRepository @Inject constructor( else -> emptySet() } + if (isFirstSync) { + // When we first retrieve news, mark everything viewed, so that we aren't + // overwhelmed with all historical news. + niaPreferencesDataSource.setNewsResourcesViewed(changedIds, true) + } + // Obtain the news resources which have changed from the network and upsert them locally changedIds.chunked(SYNC_BATCH_SIZE).forEach { chunkedIds -> val networkNewsResources = network.getNewsResources(ids = chunkedIds) @@ -137,4 +145,5 @@ class OfflineFirstNewsRepository @Inject constructor( } }, ) + } } diff --git a/core/data/src/test/java/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepositoryTest.kt b/core/data/src/test/java/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepositoryTest.kt index a38d9c621..47c3996c4 100644 --- a/core/data/src/test/java/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepositoryTest.kt +++ b/core/data/src/test/java/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepositoryTest.kt @@ -288,6 +288,33 @@ class OfflineFirstNewsRepositoryTest { ) } + @Test + fun offlineFirstNewsRepository_sync_marks_as_read_on_first_run() = + testScope.runTest { + subject.syncWith(synchronizer) + + assertEquals( + network.getNewsResources().map { it.id }.toSet(), + niaPreferencesDataSource.userData.first().viewedNewsResources, + ) + } + + @Test + fun offlineFirstNewsRepository_sync_does_not_mark_as_read_on_subsequent_run() = + testScope.runTest { + // Pretend that we already have up to change list 7 + synchronizer.updateChangeListVersions { + copy(newsResourceVersion = 7) + } + + subject.syncWith(synchronizer) + + assertEquals( + emptySet(), + niaPreferencesDataSource.userData.first().viewedNewsResources, + ) + } + @Test fun offlineFirstNewsRepository_sends_notifications_for_newly_synced_news_that_is_followed() = testScope.runTest { diff --git a/core/datastore/src/main/java/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSource.kt b/core/datastore/src/main/java/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSource.kt index 33c04b70d..6d585ebd4 100644 --- a/core/datastore/src/main/java/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSource.kt +++ b/core/datastore/src/main/java/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSource.kt @@ -139,12 +139,18 @@ class NiaPreferencesDataSource @Inject constructor( } suspend fun setNewsResourceViewed(newsResourceId: String, viewed: Boolean) { + setNewsResourcesViewed(listOf(newsResourceId), viewed) + } + + suspend fun setNewsResourcesViewed(newsResourceIds: List, viewed: Boolean) { userPreferences.updateData { it.copy { - if (viewed) { - viewedNewsResourceIds.put(newsResourceId, true) - } else { - viewedNewsResourceIds.remove(newsResourceId) + newsResourceIds.forEach { + if (viewed) { + viewedNewsResourceIds.put(it, true) + } else { + viewedNewsResourceIds.remove(it) + } } } }