From a5c40322e2758616f524156d5c061b483527ec63 Mon Sep 17 00:00:00 2001 From: Mucientes Date: Mon, 14 Feb 2022 20:16:45 +0100 Subject: [PATCH 1/8] Expose Flow from NotificationStore.kt to observe changes on "unseen" state from notifications --- .../android/fluxc/store/NotificationStore.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt index 45992137a2..187170e107 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt @@ -3,6 +3,8 @@ package org.wordpress.android.fluxc.store import android.annotation.SuppressLint import android.content.Context import com.yarolegovich.wellsql.SelectQuery.ORDER_DESCENDING +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import org.wordpress.android.fluxc.Dispatcher @@ -40,6 +42,10 @@ class NotificationStore @Inject constructor( private val preferences by lazy { PreferenceUtils.getFluxCPreferences(context) } + private val unreadNotificationUpdates: MutableSharedFlow = MutableSharedFlow(replay = 0) + + fun observeNotificationChanges(): Flow = unreadNotificationUpdates + class RegisterDevicePayload( val gcmToken: String, val appKey: NotificationAppKey, @@ -454,6 +460,7 @@ class NotificationStore @Inject constructor( causeOfChange = NotificationAction.MARK_NOTIFICATIONS_SEEN } emitChange(onNotificationChanged) + onUnreadNotificationUpdate(onNotificationChanged) } @Suppress("MemberVisibilityCanBePrivate") @@ -483,7 +490,9 @@ class NotificationStore @Inject constructor( result.notifications?.forEach { changedNotificationLocalIds.add(it.noteId) } + causeOfChange = NotificationAction.MARK_NOTIFICATIONS_SEEN } + onUnreadNotificationUpdate(onNotificationChanged) onNotificationChanged } } @@ -496,5 +505,12 @@ class NotificationStore @Inject constructor( causeOfChange = NotificationAction.UPDATE_NOTIFICATION } emitChange(onNotificationChanged) + onUnreadNotificationUpdate(onNotificationChanged) + } + + private fun onUnreadNotificationUpdate(onNotificationChanged: OnNotificationChanged) { + coroutineEngine.launch(T.API, this, "Unread notification state updated") { + unreadNotificationUpdates.emit(onNotificationChanged) + } } } From e2a6611e2a9a1fb2eb66ac574aab9a0572def87e Mon Sep 17 00:00:00 2001 From: Mucientes Date: Tue, 15 Feb 2022 16:53:26 +0100 Subject: [PATCH 2/8] Fix the events to listen to, to ensure unseen badge count is properly updated --- .../wordpress/android/fluxc/store/NotificationStore.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt index 187170e107..693adc6b81 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt @@ -2,6 +2,7 @@ package org.wordpress.android.fluxc.store import android.annotation.SuppressLint import android.content.Context +import android.util.Log import com.yarolegovich.wellsql.SelectQuery.ORDER_DESCENDING import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -438,6 +439,7 @@ class NotificationStore @Inject constructor( causeOfChange = NotificationAction.FETCH_NOTIFICATION } emitChange(onNotificationChanged) + onUnreadNotificationUpdate(onNotificationChanged) } private fun markNotificationSeen(payload: MarkNotificationsSeenPayload) { @@ -460,7 +462,6 @@ class NotificationStore @Inject constructor( causeOfChange = NotificationAction.MARK_NOTIFICATIONS_SEEN } emitChange(onNotificationChanged) - onUnreadNotificationUpdate(onNotificationChanged) } @Suppress("MemberVisibilityCanBePrivate") @@ -505,10 +506,13 @@ class NotificationStore @Inject constructor( causeOfChange = NotificationAction.UPDATE_NOTIFICATION } emitChange(onNotificationChanged) - onUnreadNotificationUpdate(onNotificationChanged) } private fun onUnreadNotificationUpdate(onNotificationChanged: OnNotificationChanged) { + Log.i( + "TEST_UNSEEN", + "NotificationStore onUnreadNotificationUpdate: ${onNotificationChanged.causeOfChange.toString()}" + ) coroutineEngine.launch(T.API, this, "Unread notification state updated") { unreadNotificationUpdates.emit(onNotificationChanged) } From d7bd86773ba11f5faf62741b0ad7a37fcc886d93 Mon Sep 17 00:00:00 2001 From: Mucientes Date: Tue, 15 Feb 2022 17:10:24 +0100 Subject: [PATCH 3/8] Remove tests logs --- .../org/wordpress/android/fluxc/store/NotificationStore.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt index 693adc6b81..cc6663fbb3 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt @@ -2,7 +2,6 @@ package org.wordpress.android.fluxc.store import android.annotation.SuppressLint import android.content.Context -import android.util.Log import com.yarolegovich.wellsql.SelectQuery.ORDER_DESCENDING import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -509,10 +508,6 @@ class NotificationStore @Inject constructor( } private fun onUnreadNotificationUpdate(onNotificationChanged: OnNotificationChanged) { - Log.i( - "TEST_UNSEEN", - "NotificationStore onUnreadNotificationUpdate: ${onNotificationChanged.causeOfChange.toString()}" - ) coroutineEngine.launch(T.API, this, "Unread notification state updated") { unreadNotificationUpdates.emit(onNotificationChanged) } From 982c1bf584fc709a4ff24befbc7095f1c2889db8 Mon Sep 17 00:00:00 2001 From: Mucientes Date: Wed, 16 Feb 2022 10:55:01 +0100 Subject: [PATCH 4/8] Simplify unreadNotificationUpdates to only trigger Unit events when a notification update occurs --- .../android/fluxc/store/NotificationStore.kt | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt index cc6663fbb3..cdf2aa4afb 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt @@ -42,9 +42,9 @@ class NotificationStore @Inject constructor( private val preferences by lazy { PreferenceUtils.getFluxCPreferences(context) } - private val unreadNotificationUpdates: MutableSharedFlow = MutableSharedFlow(replay = 0) + private val unreadNotificationUpdates: MutableSharedFlow = MutableSharedFlow(replay = 0) - fun observeNotificationChanges(): Flow = unreadNotificationUpdates + fun observeNotificationChanges(): Flow = unreadNotificationUpdates class RegisterDevicePayload( val gcmToken: String, @@ -438,7 +438,7 @@ class NotificationStore @Inject constructor( causeOfChange = NotificationAction.FETCH_NOTIFICATION } emitChange(onNotificationChanged) - onUnreadNotificationUpdate(onNotificationChanged) + onUnreadNotificationUpdate() } private fun markNotificationSeen(payload: MarkNotificationsSeenPayload) { @@ -490,9 +490,8 @@ class NotificationStore @Inject constructor( result.notifications?.forEach { changedNotificationLocalIds.add(it.noteId) } - causeOfChange = NotificationAction.MARK_NOTIFICATIONS_SEEN } - onUnreadNotificationUpdate(onNotificationChanged) + onUnreadNotificationUpdate() onNotificationChanged } } @@ -507,9 +506,9 @@ class NotificationStore @Inject constructor( emitChange(onNotificationChanged) } - private fun onUnreadNotificationUpdate(onNotificationChanged: OnNotificationChanged) { + private fun onUnreadNotificationUpdate() { coroutineEngine.launch(T.API, this, "Unread notification state updated") { - unreadNotificationUpdates.emit(onNotificationChanged) + unreadNotificationUpdates.emit(Unit) } } } From d9b1e318a6242283849b583d394202b25640f659 Mon Sep 17 00:00:00 2001 From: hicham Date: Wed, 16 Feb 2022 15:52:48 +0100 Subject: [PATCH 5/8] Offer a way to observe all notification DB changes --- .../fluxc/persistence/NotificationSqlUtils.kt | 38 +++++++++++++++++-- .../android/fluxc/store/NotificationStore.kt | 20 ++++------ 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/NotificationSqlUtils.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/NotificationSqlUtils.kt index 4a4ba0e9bc..97fecd189a 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/NotificationSqlUtils.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/NotificationSqlUtils.kt @@ -9,6 +9,12 @@ import com.yarolegovich.wellsql.core.Identifiable import com.yarolegovich.wellsql.core.annotation.Column import com.yarolegovich.wellsql.core.annotation.PrimaryKey import com.yarolegovich.wellsql.core.annotation.Table +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.mapLatest +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.withContext import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.model.notification.NoteIdSet import org.wordpress.android.fluxc.model.notification.NotificationModel @@ -21,6 +27,8 @@ import javax.inject.Singleton @Singleton class NotificationSqlUtils @Inject constructor(private val formattableContentMapper: FormattableContentMapper) { + private val dataUpdatesTrigger = MutableSharedFlow(extraBufferCapacity = 1) + fun insertOrUpdateNotification(notification: NotificationModel): Int { val notificationResult = WellSql.select(NotificationModelBuilder::class.java) .where().beginGroup() @@ -36,6 +44,7 @@ class NotificationSqlUtils @Inject constructor(private val formattableContentMap return if (notificationResult.isEmpty()) { // insert WellSql.insert(notification.toBuilder()).asSingleTransaction(true).execute() + dataUpdatesTrigger.tryEmit(Unit) 1 } else { // update @@ -43,7 +52,7 @@ class NotificationSqlUtils @Inject constructor(private val formattableContentMap WellSql.update(NotificationModelBuilder::class.java).whereId(oldId).put( notification.toBuilder(), UpdateAllExceptId(NotificationModelBuilder::class.java) - ).execute() + ).execute().also(::triggerUpdateIfNeeded) } } @@ -120,6 +129,21 @@ class NotificationSqlUtils @Inject constructor(private val formattableContentMap .map { it.build(formattableContentMapper) } } + fun observeNotificationsForSite( + site: SiteModel, + @SelectQuery.Order order: Int = ORDER_DESCENDING, + filterByType: List? = null, + filterBySubtype: List? = null + ): Flow> { + return dataUpdatesTrigger + .onStart { emit(Unit) } + .mapLatest { + withContext(Dispatchers.IO) { + getNotificationsForSite(site, order, filterByType, filterBySubtype) + } + } + } + fun hasUnreadNotificationsForSite( site: SiteModel, filterByType: List? = null, @@ -175,13 +199,21 @@ class NotificationSqlUtils @Inject constructor(private val formattableContentMap .firstOrNull()?.build(formattableContentMapper) } - fun deleteAllNotifications() = WellSql.delete(NotificationModelBuilder::class.java).execute() + fun deleteAllNotifications() = WellSql.delete(NotificationModelBuilder::class.java) + .execute() + .also(::triggerUpdateIfNeeded) fun deleteNotificationByRemoteId(remoteNoteId: Long): Int { return WellSql.delete(NotificationModelBuilder::class.java) .where().beginGroup() .equals(NotificationModelTable.REMOTE_NOTE_ID, remoteNoteId) - .endGroup().endWhere().execute() + .endGroup().endWhere() + .execute() + .also(::triggerUpdateIfNeeded) + } + + private fun triggerUpdateIfNeeded(affectedRows: Int) { + if (affectedRows != 0) dataUpdatesTrigger.tryEmit(Unit) } private fun NotificationModel.toBuilder(): NotificationModelBuilder { diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt index cdf2aa4afb..82d36d31b0 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/NotificationStore.kt @@ -4,7 +4,6 @@ import android.annotation.SuppressLint import android.content.Context import com.yarolegovich.wellsql.SelectQuery.ORDER_DESCENDING import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableSharedFlow import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import org.wordpress.android.fluxc.Dispatcher @@ -42,10 +41,6 @@ class NotificationStore @Inject constructor( private val preferences by lazy { PreferenceUtils.getFluxCPreferences(context) } - private val unreadNotificationUpdates: MutableSharedFlow = MutableSharedFlow(replay = 0) - - fun observeNotificationChanges(): Flow = unreadNotificationUpdates - class RegisterDevicePayload( val gcmToken: String, val appKey: NotificationAppKey, @@ -236,6 +231,13 @@ class NotificationStore @Inject constructor( ): List = notificationSqlUtils.getNotificationsForSite(site, ORDER_DESCENDING, filterByType, filterBySubtype) + fun observeNotificationsForSite( + site: SiteModel, + filterByType: List? = null, + filterBySubtype: List? = null + ): Flow> = + notificationSqlUtils.observeNotificationsForSite(site, ORDER_DESCENDING, filterByType, filterBySubtype) + /** * Returns true if the given site has unread notifications * @@ -438,7 +440,6 @@ class NotificationStore @Inject constructor( causeOfChange = NotificationAction.FETCH_NOTIFICATION } emitChange(onNotificationChanged) - onUnreadNotificationUpdate() } private fun markNotificationSeen(payload: MarkNotificationsSeenPayload) { @@ -491,7 +492,6 @@ class NotificationStore @Inject constructor( changedNotificationLocalIds.add(it.noteId) } } - onUnreadNotificationUpdate() onNotificationChanged } } @@ -505,10 +505,4 @@ class NotificationStore @Inject constructor( } emitChange(onNotificationChanged) } - - private fun onUnreadNotificationUpdate() { - coroutineEngine.launch(T.API, this, "Unread notification state updated") { - unreadNotificationUpdates.emit(Unit) - } - } } From 0c1c94a58024768f2da171f25e9e293894b9c40c Mon Sep 17 00:00:00 2001 From: hicham Date: Wed, 16 Feb 2022 16:19:23 +0100 Subject: [PATCH 6/8] Fix formatting --- .../wordpress/android/fluxc/persistence/NotificationSqlUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/NotificationSqlUtils.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/NotificationSqlUtils.kt index 97fecd189a..f6882c4ecf 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/NotificationSqlUtils.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/NotificationSqlUtils.kt @@ -141,7 +141,7 @@ class NotificationSqlUtils @Inject constructor(private val formattableContentMap withContext(Dispatchers.IO) { getNotificationsForSite(site, order, filterByType, filterBySubtype) } - } + } } fun hasUnreadNotificationsForSite( From 1f07ea8b44e56ce33317ba31228b12c546a3f9b3 Mon Sep 17 00:00:00 2001 From: hicham Date: Wed, 16 Feb 2022 17:39:32 +0100 Subject: [PATCH 7/8] Replace withContext with flowOn --- .../android/fluxc/persistence/NotificationSqlUtils.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/NotificationSqlUtils.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/NotificationSqlUtils.kt index f6882c4ecf..483900555c 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/NotificationSqlUtils.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/NotificationSqlUtils.kt @@ -10,11 +10,12 @@ import com.yarolegovich.wellsql.core.annotation.Column import com.yarolegovich.wellsql.core.annotation.PrimaryKey import com.yarolegovich.wellsql.core.annotation.Table import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.onStart -import kotlinx.coroutines.withContext import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.model.notification.NoteIdSet import org.wordpress.android.fluxc.model.notification.NotificationModel @@ -136,12 +137,11 @@ class NotificationSqlUtils @Inject constructor(private val formattableContentMap filterBySubtype: List? = null ): Flow> { return dataUpdatesTrigger - .onStart { emit(Unit) } - .mapLatest { - withContext(Dispatchers.IO) { + .onStart { emit(Unit) } + .mapLatest { getNotificationsForSite(site, order, filterByType, filterBySubtype) } - } + .flowOn(Dispatchers.IO) } fun hasUnreadNotificationsForSite( From 6ffe63705a4571c22b59cb0a298bc8ac902961a7 Mon Sep 17 00:00:00 2001 From: hicham Date: Wed, 16 Feb 2022 18:02:12 +0100 Subject: [PATCH 8/8] Remove unused import --- .../wordpress/android/fluxc/persistence/NotificationSqlUtils.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/NotificationSqlUtils.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/NotificationSqlUtils.kt index 483900555c..b972db8b67 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/NotificationSqlUtils.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/persistence/NotificationSqlUtils.kt @@ -10,7 +10,6 @@ import com.yarolegovich.wellsql.core.annotation.Column import com.yarolegovich.wellsql.core.annotation.PrimaryKey import com.yarolegovich.wellsql.core.annotation.Table import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.flowOn