From c5cdfc0d5309d091a1ba940eab7769ab86beff42 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Tue, 1 Nov 2022 21:28:14 +0100 Subject: [PATCH 1/3] Update bottom bar badges through a state flow --- .../android/HomeActivity.kt | 62 ++++++++++++------- .../repository/RepositoryImpl.kt | 33 +++++----- 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/HomeActivity.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/HomeActivity.kt index d0a9c5e..3d4985b 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/HomeActivity.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/HomeActivity.kt @@ -18,6 +18,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.SearchView import androidx.core.view.doOnNextLayout import androidx.drawerlayout.widget.DrawerLayout +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.* import androidx.work.Constraints import androidx.work.ExistingPeriodicWorkPolicy @@ -178,8 +179,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar adapter.handleItemAtIndex(position) - reloadBadgeContent() - val tagHashes = i.tags.map { it.longHash() } tagsBadge = tagsBadge.map { if (tagHashes.contains(it.key)) { @@ -207,6 +206,16 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(binding.recyclerView) } + private fun updateBottomBarBadgeCount(badge: TextBadgeItem, count: Int) { + if (count > 0) { + badge + .setText(count.toString()) + .maybeShow() + } else { + badge.removeBadge() + } + } + private fun handleBottomBar() { tabNewBadge = TextBadgeItem() @@ -219,6 +228,28 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar .setText("") .setHideOnSelect(false).hide(false) + if (appSettingsService.isDisplayUnreadCountEnabled()) { + lifecycleScope.launch { + repository.badgeUnread.collect { + updateBottomBarBadgeCount(tabNewBadge, it) + } + } + } + + if (appSettingsService.isDisplayAllCountEnabled()) { + lifecycleScope.launch { + repository.badgeAll.collect { + updateBottomBarBadgeCount(tabArchiveBadge, it) + } + } + + lifecycleScope.launch { + repository.badgeStarred.collect { + updateBottomBarBadgeCount(tabStarredBadge, it) + } + } + } + val tabNew = BottomNavigationItem( R.drawable.ic_tab_fiber_new_black_24dp, @@ -714,29 +745,12 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar private fun reloadBadges() { if (appSettingsService.isDisplayUnreadCountEnabled() || appSettingsService.isDisplayAllCountEnabled()) { - CoroutineScope(Dispatchers.Main).launch { + CoroutineScope(Dispatchers.IO).launch { repository.reloadBadges() - reloadBadgeContent() } } } - private fun reloadBadgeContent() { - if (appSettingsService.isDisplayUnreadCountEnabled()) { - tabNewBadge - .setText(repository.badgeUnread.toString()) - .maybeShow() - } - if (appSettingsService.isDisplayAllCountEnabled()) { - tabArchiveBadge - .setText(repository.badgeAll.toString()) - .maybeShow() - tabStarredBadge - .setText(repository.badgeStarred.toString()) - .maybeShow() - } - } - private fun reloadTagsBadges() { tagsBadge.forEach { binding.mainDrawer.updateBadge(it.key, StringHolder(it.value.toString())) @@ -858,10 +872,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar private fun maxItemNumber(): Int = when (elementsShown) { - ItemType.UNREAD -> repository.badgeUnread - ItemType.ALL -> repository.badgeAll - ItemType.STARRED -> repository.badgeStarred - else -> repository.badgeUnread // if !elementsShown then unread are fetched. + ItemType.UNREAD -> repository.badgeUnread.value + ItemType.ALL -> repository.badgeAll.value + ItemType.STARRED -> repository.badgeStarred.value + else -> repository.badgeUnread.value // if !elementsShown then unread are fetched. } private fun updateItems(adapterItems: ArrayList) { diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index 9b3b1ff..8996e8e 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -10,6 +10,7 @@ import io.github.aakira.napier.Napier import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch class Repository(private val api: SelfossApi, private val appSettingsService: AppSettingsService, val isConnectionAvailable: MutableStateFlow, private val db: ReaderForSelfossDB) { @@ -27,12 +28,12 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap var offlineOverride = false - var badgeUnread = 0 - set(value) {field = if (value < 0) { 0 } else { value } } - var badgeAll = 0 - set(value) {field = if (value < 0) { 0 } else { value } } - var badgeStarred = 0 - set(value) {field = if (value < 0) { 0 } else { value } } + private val _badgeUnread = MutableStateFlow(0) + val badgeUnread = _badgeUnread.asStateFlow() + private val _badgeAll = MutableStateFlow(0) + val badgeAll = _badgeAll.asStateFlow() + private val _badgeStarred = MutableStateFlow(0) + val badgeStarred = _badgeStarred.asStateFlow() private var fetchedSources = false private var fetchedTags = false @@ -125,17 +126,17 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap if (isNetworkAvailable()) { val response = api.stats() if (response.success && response.data != null) { - badgeUnread = response.data.unread - badgeAll = response.data.total - badgeStarred = response.data.starred + _badgeUnread.value = response.data.unread + _badgeAll.value = response.data.total + _badgeStarred.value = response.data.starred success = true } } else if (appSettingsService.isItemCachingEnabled()) { // TODO: do this differently, because it's not efficient val dbItems = getDBItems() - badgeUnread = dbItems.filter { item -> item.unread }.size - badgeStarred = dbItems.filter { item -> item.starred }.size - badgeAll = dbItems.size + _badgeUnread.value = dbItems.filter { item -> item.unread }.size + _badgeStarred.value = dbItems.filter { item -> item.starred }.size + _badgeAll.value = dbItems.size success = true } return success @@ -283,7 +284,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap private fun markAsReadLocally(item: SelfossModel.Item) { if (item.unread) { item.unread = false - badgeUnread -= 1 + _badgeUnread.value -= 1 } CoroutineScope(Dispatchers.Main).launch { @@ -294,7 +295,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap private fun unmarkAsReadLocally(item: SelfossModel.Item) { if (!item.unread) { item.unread = true - badgeUnread += 1 + _badgeUnread.value += 1 } CoroutineScope(Dispatchers.Main).launch { @@ -305,7 +306,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap private fun starrLocally(item: SelfossModel.Item) { if (!item.starred) { item.starred = true - badgeStarred += 1 + _badgeStarred.value += 1 } CoroutineScope(Dispatchers.Main).launch { @@ -316,7 +317,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap private fun unstarrLocally(item: SelfossModel.Item) { if (item.starred) { item.starred = false - badgeStarred -= 1 + _badgeStarred.value -= 1 } CoroutineScope(Dispatchers.Main).launch { From 02d734eee88cbda6dbd7ece20309928250b814a3 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Tue, 1 Nov 2022 21:29:04 +0100 Subject: [PATCH 2/3] Do not edit the repository items from outside the repository --- .../apps/readerforselfossv2/android/adapters/ItemCardAdapter.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/ItemCardAdapter.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/ItemCardAdapter.kt index cb2dcae..227977a 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/ItemCardAdapter.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/ItemCardAdapter.kt @@ -111,13 +111,11 @@ class ItemCardAdapter( CoroutineScope(Dispatchers.IO).launch { repository.unstarr(item) } - item.starred = false binding.favButton.isSelected = false } else { CoroutineScope(Dispatchers.IO).launch { repository.starr(item) } - item.starred = true binding.favButton.isSelected = true } } From 4b63afe62af37eebf21078e839015d7ed1738482 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Tue, 1 Nov 2022 21:51:46 +0100 Subject: [PATCH 3/3] Update badges tests --- androidApp/src/test/kotlin/RepositoryTest.kt | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/androidApp/src/test/kotlin/RepositoryTest.kt b/androidApp/src/test/kotlin/RepositoryTest.kt index 803c5a2..fd16d9b 100644 --- a/androidApp/src/test/kotlin/RepositoryTest.kt +++ b/androidApp/src/test/kotlin/RepositoryTest.kt @@ -299,9 +299,9 @@ class RepositoryTest { } assertSame(true, success) - assertSame(NUMBER_ARTICLES, repository.badgeAll) - assertSame(NUMBER_UNREAD, repository.badgeUnread) - assertSame(NUMBER_STARRED, repository.badgeStarred) + assertEquals(NUMBER_ARTICLES, repository.badgeAll.value) + assertEquals(NUMBER_UNREAD, repository.badgeUnread.value) + assertEquals(NUMBER_STARRED, repository.badgeStarred.value) coVerify(atLeast = 1) { api.stats() } verify(exactly = 0) { db.itemsQueries.items().executeAsList() } } @@ -318,9 +318,9 @@ class RepositoryTest { } assertSame(false, success) - assertSame(0, repository.badgeAll) - assertSame(0, repository.badgeUnread) - assertSame(0, repository.badgeStarred) + assertSame(0, repository.badgeAll.value) + assertSame(0, repository.badgeUnread.value) + assertSame(0, repository.badgeStarred.value) coVerify(atLeast = 1) { api.stats() } verify(exactly = 0) { db.itemsQueries.items().executeAsList() } } @@ -338,9 +338,9 @@ class RepositoryTest { } assertTrue(success) - assertSame(1, repository.badgeAll) - assertSame(1, repository.badgeUnread) - assertSame(1, repository.badgeStarred) + assertEquals(1, repository.badgeAll.value) + assertEquals(1, repository.badgeUnread.value) + assertEquals(1, repository.badgeStarred.value) coVerify(exactly = 0) { api.stats() } verify(atLeast = 1) { db.itemsQueries.items().executeAsList() } } @@ -358,9 +358,9 @@ class RepositoryTest { } assertFalse(success) - assertSame(0, repository.badgeAll) - assertSame(0, repository.badgeUnread) - assertSame(0, repository.badgeStarred) + assertSame(0, repository.badgeAll.value) + assertSame(0, repository.badgeUnread.value) + assertSame(0, repository.badgeStarred.value) coVerify(exactly = 0) { api.stats() } verify(exactly = 0) { db.itemsQueries.items().executeAsList() } }