From e354a9b440e9d42d1e88e0b75ed372bcde96a535 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Fri, 18 Nov 2022 04:54:10 +0300 Subject: [PATCH 01/11] Convert NotificationsSettingsActivity to Kotlin --- .../NotificationsSettingsActivity.java | 156 ------------------ .../NotificationsSettingsActivity.kt | 142 ++++++++++++++++ 2 files changed, 142 insertions(+), 156 deletions(-) delete mode 100644 WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/NotificationsSettingsActivity.java create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/NotificationsSettingsActivity.kt diff --git a/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/NotificationsSettingsActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/NotificationsSettingsActivity.java deleted file mode 100644 index b81f3d02d5f7..000000000000 --- a/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/NotificationsSettingsActivity.java +++ /dev/null @@ -1,156 +0,0 @@ -package org.wordpress.android.ui.prefs.notifications; - -import android.app.FragmentManager; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.MenuItem; -import android.view.View; -import android.widget.CompoundButton; -import android.widget.LinearLayout; -import android.widget.TextView; - -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.widget.Toolbar; -import androidx.preference.PreferenceManager; - - -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; -import org.wordpress.android.R; -import org.wordpress.android.analytics.AnalyticsTracker; -import org.wordpress.android.ui.LocaleAwareActivity; -import org.wordpress.android.ui.notifications.NotificationEvents; -import org.wordpress.android.ui.prefs.notifications.PrefMainSwitchToolbarView.MainSwitchToolbarListener; - -import dagger.hilt.android.AndroidEntryPoint; - -@AndroidEntryPoint -public class NotificationsSettingsActivity extends LocaleAwareActivity - implements MainSwitchToolbarListener { - private TextView mMessageTextView; - private View mMessageContainer; - - protected SharedPreferences mSharedPreferences; - protected View mFragmentContainer; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.notifications_settings_activity); - mFragmentContainer = findViewById(R.id.fragment_container); - - // Get shared preferences for main switch. - mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(NotificationsSettingsActivity.this); - - // Set up primary toolbar - setUpToolbar(); - - // Set up main switch - setUpMainSwitch(); - - FragmentManager fragmentManager = getFragmentManager(); - if (savedInstanceState == null) { - fragmentManager.beginTransaction() - .add(R.id.fragment_container, new NotificationsSettingsFragment()) - .commit(); - } - - mMessageContainer = findViewById(R.id.notifications_settings_message_container); - mMessageTextView = findViewById(R.id.notifications_settings_message); - } - - @Override - protected void onStop() { - EventBus.getDefault().unregister(this); - super.onStop(); - } - - @Override - protected void onStart() { - super.onStart(); - EventBus.getDefault().register(this); - } - - @Override - public boolean onOptionsItemSelected(final MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - onBackPressed(); - return true; - } - return super.onOptionsItemSelected(item); - } - - @SuppressWarnings("unused") - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(NotificationEvents.NotificationsSettingsStatusChanged event) { - if (TextUtils.isEmpty(event.getMessage())) { - mMessageContainer.setVisibility(View.GONE); - } else { - mMessageContainer.setVisibility(View.VISIBLE); - mMessageTextView.setText(event.getMessage()); - } - } - - /** - * Set up primary toolbar for navigation and search - */ - private void setUpToolbar() { - Toolbar toolbar = findViewById(R.id.toolbar_with_search); - - if (toolbar != null) { - setSupportActionBar(toolbar); - } - - ActionBar actionBar = getSupportActionBar(); - - if (actionBar != null) { - actionBar.setTitle(R.string.notification_settings); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowTitleEnabled(true); - } - } - - /** - * Sets up main switch to disable/enable all notification settings - */ - private void setUpMainSwitch() { - PrefMainSwitchToolbarView mainSwitchToolBarView = findViewById(R.id.main_switch); - mainSwitchToolBarView.setMainSwitchToolbarListener(this); - - // Set main switch state from shared preferences. - boolean isMainChecked = mSharedPreferences.getBoolean(getString(R.string.wp_pref_notifications_main), true); - mainSwitchToolBarView.loadInitialState(isMainChecked); - hideDisabledView(isMainChecked); - } - - @Override - public void onMainSwitchCheckedChanged( - CompoundButton buttonView, - boolean isChecked - ) { - mSharedPreferences.edit().putBoolean(getString(R.string.wp_pref_notifications_main), isChecked) - .apply(); - - hideDisabledView(isChecked); - - if (isChecked) { - AnalyticsTracker.track(AnalyticsTracker.Stat.NOTIFICATION_SETTINGS_APP_NOTIFICATIONS_ENABLED); - } else { - AnalyticsTracker.track(AnalyticsTracker.Stat.NOTIFICATION_SETTINGS_APP_NOTIFICATIONS_DISABLED); - } - } - - /** - * Hide view when Notification Settings are disabled by toggling the main switch off. - * - * @param isMainChecked TRUE to hide disabled view, FALSE to show disabled view - */ - protected void hideDisabledView(boolean isMainChecked) { - LinearLayout notificationsDisabledView = findViewById(R.id.notification_settings_disabled_view); - notificationsDisabledView.setVisibility(isMainChecked ? View.INVISIBLE : View.VISIBLE); - mFragmentContainer.setVisibility(isMainChecked ? View.VISIBLE : View.GONE); - } -} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/NotificationsSettingsActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/NotificationsSettingsActivity.kt new file mode 100644 index 000000000000..ceeaa283e0b0 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/NotificationsSettingsActivity.kt @@ -0,0 +1,142 @@ +package org.wordpress.android.ui.prefs.notifications + +import android.content.SharedPreferences +import android.os.Bundle +import android.text.TextUtils +import android.view.MenuItem +import android.view.View +import android.widget.CompoundButton +import android.widget.LinearLayout +import android.widget.TextView +import androidx.appcompat.widget.Toolbar +import androidx.preference.PreferenceManager +import dagger.hilt.android.AndroidEntryPoint +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode.MAIN +import org.wordpress.android.R.id +import org.wordpress.android.R.layout +import org.wordpress.android.R.string +import org.wordpress.android.analytics.AnalyticsTracker +import org.wordpress.android.analytics.AnalyticsTracker.Stat.NOTIFICATION_SETTINGS_APP_NOTIFICATIONS_DISABLED +import org.wordpress.android.analytics.AnalyticsTracker.Stat.NOTIFICATION_SETTINGS_APP_NOTIFICATIONS_ENABLED +import org.wordpress.android.ui.LocaleAwareActivity +import org.wordpress.android.ui.notifications.NotificationEvents.NotificationsSettingsStatusChanged +import org.wordpress.android.ui.prefs.notifications.PrefMainSwitchToolbarView.MainSwitchToolbarListener + +@AndroidEntryPoint +class NotificationsSettingsActivity : LocaleAwareActivity(), MainSwitchToolbarListener { + private lateinit var messageTextView: TextView + private lateinit var messageContainer: View + + private lateinit var sharedPreferences: SharedPreferences + private lateinit var fragmentContainer: View + + public override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(layout.notifications_settings_activity) + fragmentContainer = findViewById(id.fragment_container) + + // Get shared preferences for main switch. + sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this@NotificationsSettingsActivity) + + // Set up primary toolbar + setUpToolbar() + + // Set up main switch + setUpMainSwitch() + + if (savedInstanceState == null) { + @Suppress("DEPRECATION") + fragmentManager.beginTransaction() + .add(id.fragment_container, NotificationsSettingsFragment()) + .commit() + } + + messageContainer = findViewById(id.notifications_settings_message_container) + messageTextView = findViewById(id.notifications_settings_message) + } + + override fun onStop() { + EventBus.getDefault().unregister(this) + super.onStop() + } + + override fun onStart() { + super.onStart() + EventBus.getDefault().register(this) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + android.R.id.home -> { + onBackPressed() + return true + } + } + return super.onOptionsItemSelected(item) + } + + @Subscribe(threadMode = MAIN) + fun onEventMainThread(event: NotificationsSettingsStatusChanged) { + if (TextUtils.isEmpty(event.message)) { + messageContainer.visibility = View.GONE + } else { + messageContainer.visibility = View.VISIBLE + messageTextView.text = event.message + } + } + + /** + * Set up primary toolbar for navigation and search + */ + private fun setUpToolbar() { + val toolbar = findViewById(id.toolbar_with_search) + + toolbar?.let { setSupportActionBar(it) } + + supportActionBar?.apply { + setTitle(string.notification_settings) + setDisplayHomeAsUpEnabled(true) + setDisplayShowTitleEnabled(true) + } + } + + /** + * Sets up main switch to disable/enable all notification settings + */ + private fun setUpMainSwitch() { + val mainSwitchToolBarView = findViewById(id.main_switch) + mainSwitchToolBarView.setMainSwitchToolbarListener(this) + + // Set main switch state from shared preferences. + val isMainChecked = sharedPreferences.getBoolean(getString(string.wp_pref_notifications_main), true) + mainSwitchToolBarView.loadInitialState(isMainChecked) + hideDisabledView(isMainChecked) + } + + override fun onMainSwitchCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) { + sharedPreferences.edit() + .putBoolean(getString(string.wp_pref_notifications_main), isChecked) + .apply() + + hideDisabledView(isChecked) + + if (isChecked) { + AnalyticsTracker.track(NOTIFICATION_SETTINGS_APP_NOTIFICATIONS_ENABLED) + } else { + AnalyticsTracker.track(NOTIFICATION_SETTINGS_APP_NOTIFICATIONS_DISABLED) + } + } + + /** + * Hide view when Notification Settings are disabled by toggling the main switch off. + * + * @param isMainChecked TRUE to hide disabled view, FALSE to show disabled view + */ + private fun hideDisabledView(isMainChecked: Boolean) { + val notificationsDisabledView = findViewById(id.notification_settings_disabled_view) + notificationsDisabledView.visibility = if (isMainChecked) View.INVISIBLE else View.VISIBLE + fragmentContainer.visibility = if (isMainChecked) View.VISIBLE else View.GONE + } +} From b085873550d48900e68897e2a26ce6533152a470 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Sun, 20 Nov 2022 02:00:34 +0300 Subject: [PATCH 02/11] Update FluxC version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 83faa2bec3b7..a4a33b41b329 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ ext { coroutinesVersion = '1.5.2' androidxWorkVersion = "2.7.0" - fluxCVersion = '2.0.0' + fluxCVersion = '2571-60e0a8bdd1c5faca73f4e2908d8827d4138e06cc' appCompatVersion = '1.0.2' androidxCoreVersion = '1.3.2' From a055a19767c8838814fce34881881192308ccf2d Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Sun, 20 Nov 2022 02:01:19 +0300 Subject: [PATCH 03/11] Add UpdateNotificationSettingsUseCase --- .../android/modules/ApplicationModule.java | 7 ++ .../UpdateNotificationSettingsUseCase.kt | 70 +++++++++++++++++++ .../android/ui/stats/refresh/StatsModule.kt | 10 --- 3 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/usecase/UpdateNotificationSettingsUseCase.kt diff --git a/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java b/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java index 1d921b9ee177..c80723422816 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java @@ -2,8 +2,10 @@ import android.app.Application; import android.content.Context; +import android.content.SharedPreferences; import androidx.lifecycle.LiveData; +import androidx.preference.PreferenceManager; import com.tenor.android.core.network.ApiClient; import com.tenor.android.core.network.ApiService; @@ -109,6 +111,11 @@ public abstract class ApplicationModule { @ContributesAndroidInjector abstract BasicDialog contributeBasicDialog(); + @Provides + public static SharedPreferences provideSharedPrefs(@ApplicationContext Context context) { + return PreferenceManager.getDefaultSharedPreferences(context); + } + @Provides public static WizardManager provideWizardManager( SiteCreationStepsProvider stepsProvider) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/usecase/UpdateNotificationSettingsUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/usecase/UpdateNotificationSettingsUseCase.kt new file mode 100644 index 000000000000..bedb1e965973 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/usecase/UpdateNotificationSettingsUseCase.kt @@ -0,0 +1,70 @@ +package org.wordpress.android.ui.prefs.notifications.usecase + +import android.content.SharedPreferences +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.withContext +import org.wordpress.android.R +import org.wordpress.android.fluxc.store.BloggingRemindersStore +import org.wordpress.android.modules.IO_THREAD +import org.wordpress.android.viewmodel.ResourceProvider +import org.wordpress.android.workers.notification.createsite.CreateSiteNotificationScheduler +import org.wordpress.android.workers.reminder.ReminderConfig.WeeklyReminder +import org.wordpress.android.workers.reminder.ReminderScheduler +import org.wordpress.android.workers.weeklyroundup.WeeklyRoundupScheduler +import java.time.DayOfWeek +import javax.inject.Inject +import javax.inject.Named + +@Suppress("LongParameterList") +class UpdateNotificationSettingsUseCase @Inject constructor( + private val sharedPrefs: SharedPreferences, + private val resourceProvider: ResourceProvider, + private val weeklyRoundupScheduler: WeeklyRoundupScheduler, + private val reminderScheduler: ReminderScheduler, + private val createSiteNotificationScheduler: CreateSiteNotificationScheduler, + private val bloggingRemindersStore: BloggingRemindersStore, + @Named(IO_THREAD) private val ioDispatcher: CoroutineDispatcher +) { + suspend fun updateNotificationSettings(enabled: Boolean) { + updatePref(enabled) + + if (enabled) { + // The switch is turned on. Schedule local notifications. + weeklyRoundupScheduler.schedule() + scheduleSavedBloggingReminders() + createSiteNotificationScheduler.scheduleCreateSiteNotificationIfNeeded() + } else { + // The switch is turned off. Cancel scheduled local notifications. + weeklyRoundupScheduler.cancel() + reminderScheduler.cancelAll() + createSiteNotificationScheduler.cancelCreateSiteNotification() + } + } + + private fun updatePref(enabled: Boolean) { + val editor = sharedPrefs.edit() + editor.putBoolean(resourceProvider.getString(R.string.wp_pref_notifications_main), enabled) + editor.apply() + } + + /** + * Fetches saved blogging reminders from the db and schedules reminders for them. + */ + private suspend fun scheduleSavedBloggingReminders() = withContext(ioDispatcher) { + bloggingRemindersStore.getAll().collect { bloggingRemindersModelList -> + bloggingRemindersModelList.forEach { bloggingRemindersModel -> + val daysCount = bloggingRemindersModel.enabledDays.size + if (daysCount > 0) { + val enabledDaysOfWeek = bloggingRemindersModel.enabledDays.map { DayOfWeek.valueOf(it.name) } + reminderScheduler.schedule( + bloggingRemindersModel.siteId, + bloggingRemindersModel.hour, + bloggingRemindersModel.minute, + WeeklyReminder(enabledDaysOfWeek.toSet()) + ) + } + } + } + } +} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsModule.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsModule.kt index 2bb3832424d3..055d880c60f7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsModule.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsModule.kt @@ -1,12 +1,8 @@ package org.wordpress.android.ui.stats.refresh -import android.content.Context -import android.content.SharedPreferences -import androidx.preference.PreferenceManager import dagger.Module import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import kotlinx.coroutines.CoroutineDispatcher import org.wordpress.android.BuildConfig @@ -589,10 +585,4 @@ class StatsModule { { listOf(InsightType.TOTAL_FOLLOWERS, InsightType.FOLLOWER_TYPES, InsightType.FOLLOWERS) }, uiModelMapper::mapInsights ) - - @Provides - @Singleton - fun provideSharedPrefs(@ApplicationContext context: Context): SharedPreferences { - return PreferenceManager.getDefaultSharedPreferences(context) - } } From 86725a71d535c8734dbf903c7c5693ba79568ea7 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Sun, 20 Nov 2022 02:01:54 +0300 Subject: [PATCH 04/11] Use UpdateNotificationSettingsUseCase in NotificationsSettingsActivity --- .../notifications/NotificationsSettingsActivity.kt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/NotificationsSettingsActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/NotificationsSettingsActivity.kt index ceeaa283e0b0..feeb78368070 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/NotificationsSettingsActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/NotificationsSettingsActivity.kt @@ -11,6 +11,8 @@ import android.widget.TextView import androidx.appcompat.widget.Toolbar import androidx.preference.PreferenceManager import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode.MAIN @@ -20,12 +22,19 @@ import org.wordpress.android.R.string import org.wordpress.android.analytics.AnalyticsTracker import org.wordpress.android.analytics.AnalyticsTracker.Stat.NOTIFICATION_SETTINGS_APP_NOTIFICATIONS_DISABLED import org.wordpress.android.analytics.AnalyticsTracker.Stat.NOTIFICATION_SETTINGS_APP_NOTIFICATIONS_ENABLED +import org.wordpress.android.modules.APPLICATION_SCOPE import org.wordpress.android.ui.LocaleAwareActivity import org.wordpress.android.ui.notifications.NotificationEvents.NotificationsSettingsStatusChanged import org.wordpress.android.ui.prefs.notifications.PrefMainSwitchToolbarView.MainSwitchToolbarListener +import org.wordpress.android.ui.prefs.notifications.usecase.UpdateNotificationSettingsUseCase +import javax.inject.Inject +import javax.inject.Named @AndroidEntryPoint class NotificationsSettingsActivity : LocaleAwareActivity(), MainSwitchToolbarListener { + @Inject lateinit var updateNotificationSettingsUseCase: UpdateNotificationSettingsUseCase + @Inject @Named(APPLICATION_SCOPE) lateinit var applicationScope: CoroutineScope + private lateinit var messageTextView: TextView private lateinit var messageContainer: View @@ -116,9 +125,7 @@ class NotificationsSettingsActivity : LocaleAwareActivity(), MainSwitchToolbarLi } override fun onMainSwitchCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) { - sharedPreferences.edit() - .putBoolean(getString(string.wp_pref_notifications_main), isChecked) - .apply() + applicationScope.launch { updateNotificationSettingsUseCase.updateNotificationSettings(isChecked) } hideDisabledView(isChecked) From f72f456d9afb6f6b1d8b440858fa4e19dee55ed6 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Sun, 20 Nov 2022 02:05:23 +0300 Subject: [PATCH 05/11] Use UpdateNotificationSettingsUseCase in JetpackAppInstallReceiver --- .../jetpackbadge/JetpackAppInstallReceiver.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/WordPress/src/wordpress/java/org/wordpress/android/ui/mysite/jetpackbadge/JetpackAppInstallReceiver.kt b/WordPress/src/wordpress/java/org/wordpress/android/ui/mysite/jetpackbadge/JetpackAppInstallReceiver.kt index 86597032df53..a49c668ad764 100644 --- a/WordPress/src/wordpress/java/org/wordpress/android/ui/mysite/jetpackbadge/JetpackAppInstallReceiver.kt +++ b/WordPress/src/wordpress/java/org/wordpress/android/ui/mysite/jetpackbadge/JetpackAppInstallReceiver.kt @@ -3,15 +3,20 @@ package org.wordpress.android.ui.mysite.jetpackbadge import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import androidx.preference.PreferenceManager import dagger.hilt.android.AndroidEntryPoint -import org.wordpress.android.R +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import org.wordpress.android.modules.APPLICATION_SCOPE import org.wordpress.android.push.GCMMessageHandler +import org.wordpress.android.ui.prefs.notifications.usecase.UpdateNotificationSettingsUseCase import javax.inject.Inject +import javax.inject.Named @AndroidEntryPoint class JetpackAppInstallReceiver : BroadcastReceiver() { + @Inject lateinit var updateNotificationSettingsUseCase: UpdateNotificationSettingsUseCase @Inject lateinit var gcmMessageHandler: GCMMessageHandler + @Inject @Named(APPLICATION_SCOPE) lateinit var applicationScope: CoroutineScope override fun onReceive(context: Context, intent: Intent) { disableNotifications(context) @@ -19,11 +24,7 @@ class JetpackAppInstallReceiver : BroadcastReceiver() { private fun disableNotifications(context: Context) { // Turn toggle off on Notifications Settings screen - val mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) - mSharedPreferences - .edit() - .putBoolean(context.getString(R.string.wp_pref_notifications_main), false) - .apply() + applicationScope.launch { updateNotificationSettingsUseCase.updateNotificationSettings(false) } gcmMessageHandler.removeAllNotifications(context) } From 09a7618c986567e45fb11d72e9c034bd76aa6a0e Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Sun, 20 Nov 2022 18:13:00 +0300 Subject: [PATCH 06/11] Fetch blogging reminders once in UpdateNotificationSettingsUseCase --- .../UpdateNotificationSettingsUseCase.kt | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/usecase/UpdateNotificationSettingsUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/usecase/UpdateNotificationSettingsUseCase.kt index bedb1e965973..bbc09e533bcd 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/usecase/UpdateNotificationSettingsUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/usecase/UpdateNotificationSettingsUseCase.kt @@ -2,7 +2,7 @@ package org.wordpress.android.ui.prefs.notifications.usecase import android.content.SharedPreferences import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.first import kotlinx.coroutines.withContext import org.wordpress.android.R import org.wordpress.android.fluxc.store.BloggingRemindersStore @@ -52,18 +52,17 @@ class UpdateNotificationSettingsUseCase @Inject constructor( * Fetches saved blogging reminders from the db and schedules reminders for them. */ private suspend fun scheduleSavedBloggingReminders() = withContext(ioDispatcher) { - bloggingRemindersStore.getAll().collect { bloggingRemindersModelList -> - bloggingRemindersModelList.forEach { bloggingRemindersModel -> - val daysCount = bloggingRemindersModel.enabledDays.size - if (daysCount > 0) { - val enabledDaysOfWeek = bloggingRemindersModel.enabledDays.map { DayOfWeek.valueOf(it.name) } - reminderScheduler.schedule( - bloggingRemindersModel.siteId, - bloggingRemindersModel.hour, - bloggingRemindersModel.minute, - WeeklyReminder(enabledDaysOfWeek.toSet()) - ) - } + val bloggingRemindersModelList = bloggingRemindersStore.getAll().first() + bloggingRemindersModelList.forEach { bloggingRemindersModel -> + val daysCount = bloggingRemindersModel.enabledDays.size + if (daysCount > 0) { + val enabledDaysOfWeek = bloggingRemindersModel.enabledDays.map { DayOfWeek.valueOf(it.name) } + reminderScheduler.schedule( + bloggingRemindersModel.siteId, + bloggingRemindersModel.hour, + bloggingRemindersModel.minute, + WeeklyReminder(enabledDaysOfWeek.toSet()) + ) } } } From f600aa1db92823f070bc9331adb59ed2630da1fe Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Mon, 21 Nov 2022 01:00:06 +0300 Subject: [PATCH 07/11] Update release notes for PR 17496 --- RELEASE-NOTES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 6ee33bc3f3c8..1a69e8fc431d 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -2,7 +2,7 @@ 21.3 ----- - +* [*] Disable local notifications with Notification Settings switch. [https://github.com/wordpress-mobile/WordPress-Android/pull/17496] 21.2 ----- From 62ce8c749e3c2196e3a2b179f0e8d0da7a5944df Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Mon, 21 Nov 2022 22:28:23 +0300 Subject: [PATCH 08/11] Update FluxC version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 38a076e31756..1f8df7188d57 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ ext { coroutinesVersion = '1.5.2' androidxWorkVersion = "2.7.0" - fluxCVersion = 'trunk-5a4f8132de39ae666f841edc4522f87b1b02a265' + fluxCVersion = 'trunk-7e1f7406753a72cbed61feab1204ca52ba7f0f77' appCompatVersion = '1.0.2' androidxCoreVersion = '1.3.2' From 4be1196c32a36699cac45157b234db0de6efad8b Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Mon, 21 Nov 2022 23:31:25 +0300 Subject: [PATCH 09/11] Prevent scheduling local notifications if switch is off --- .../android/ui/main/WPMainActivity.java | 2 +- .../UpdateNotificationSettingsUseCase.kt | 2 +- .../CreateSiteNotificationHandler.kt | 11 ++++- .../weeklyroundup/WeeklyRoundupNotifier.kt | 2 +- .../weeklyroundup/WeeklyRoundupScheduler.kt | 43 ++++++++++++------- 5 files changed, 40 insertions(+), 20 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/main/WPMainActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/main/WPMainActivity.java index eaea47553556..84e49cea4e67 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/main/WPMainActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/main/WPMainActivity.java @@ -527,7 +527,7 @@ private boolean isGooglePlayServicesAvailable(Activity activity) { private void scheduleLocalNotifications() { mCreateSiteNotificationScheduler.scheduleCreateSiteNotificationIfNeeded(); - mWeeklyRoundupScheduler.schedule(); + mWeeklyRoundupScheduler.scheduleIfNeeded(); } @Override diff --git a/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/usecase/UpdateNotificationSettingsUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/usecase/UpdateNotificationSettingsUseCase.kt index bbc09e533bcd..290e9b59397a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/usecase/UpdateNotificationSettingsUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/usecase/UpdateNotificationSettingsUseCase.kt @@ -31,7 +31,7 @@ class UpdateNotificationSettingsUseCase @Inject constructor( if (enabled) { // The switch is turned on. Schedule local notifications. - weeklyRoundupScheduler.schedule() + weeklyRoundupScheduler.scheduleIfNeeded() scheduleSavedBloggingReminders() createSiteNotificationScheduler.scheduleCreateSiteNotificationIfNeeded() } else { diff --git a/WordPress/src/main/java/org/wordpress/android/workers/notification/createsite/CreateSiteNotificationHandler.kt b/WordPress/src/main/java/org/wordpress/android/workers/notification/createsite/CreateSiteNotificationHandler.kt index ade95c89ff60..627249d6a4d3 100644 --- a/WordPress/src/main/java/org/wordpress/android/workers/notification/createsite/CreateSiteNotificationHandler.kt +++ b/WordPress/src/main/java/org/wordpress/android/workers/notification/createsite/CreateSiteNotificationHandler.kt @@ -2,22 +2,31 @@ package org.wordpress.android.workers.notification.createsite import android.app.PendingIntent import android.content.Context +import android.content.SharedPreferences +import org.wordpress.android.R import org.wordpress.android.fluxc.store.AccountStore import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.push.NotificationType.CREATE_SITE import org.wordpress.android.ui.ActivityLauncher import org.wordpress.android.ui.notifications.SystemNotificationsTracker import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource +import org.wordpress.android.viewmodel.ResourceProvider import org.wordpress.android.workers.notification.local.LocalNotificationHandler import javax.inject.Inject class CreateSiteNotificationHandler @Inject constructor( + private val sharedPrefs: SharedPreferences, + private val resourceProvider: ResourceProvider, private val accountStore: AccountStore, private val siteStore: SiteStore, private val notificationsTracker: SystemNotificationsTracker ) : LocalNotificationHandler { override fun shouldShowNotification(): Boolean { - return accountStore.hasAccessToken() && !siteStore.hasSite() + val isNotificationSettingsEnabled = sharedPrefs.getBoolean( + resourceProvider.getString(R.string.wp_pref_notifications_main), + true + ) + return isNotificationSettingsEnabled && accountStore.hasAccessToken() && !siteStore.hasSite() } override fun buildFirstActionPendingIntent(context: Context, notificationId: Int): PendingIntent { diff --git a/WordPress/src/main/java/org/wordpress/android/workers/weeklyroundup/WeeklyRoundupNotifier.kt b/WordPress/src/main/java/org/wordpress/android/workers/weeklyroundup/WeeklyRoundupNotifier.kt index 64e99a132924..e3d6733fe21f 100644 --- a/WordPress/src/main/java/org/wordpress/android/workers/weeklyroundup/WeeklyRoundupNotifier.kt +++ b/WordPress/src/main/java/org/wordpress/android/workers/weeklyroundup/WeeklyRoundupNotifier.kt @@ -56,7 +56,7 @@ class WeeklyRoundupNotifier @Inject constructor( notificationsTracker.trackShownNotification(WEEKLY_ROUNDUP) } - weeklyRoundupScheduler.schedule() + weeklyRoundupScheduler.scheduleIfNeeded() } private fun buildNotification(data: WeeklyRoundupData): WeeklyRoundupNotification { diff --git a/WordPress/src/main/java/org/wordpress/android/workers/weeklyroundup/WeeklyRoundupScheduler.kt b/WordPress/src/main/java/org/wordpress/android/workers/weeklyroundup/WeeklyRoundupScheduler.kt index 425b182a0d96..f169a843b303 100644 --- a/WordPress/src/main/java/org/wordpress/android/workers/weeklyroundup/WeeklyRoundupScheduler.kt +++ b/WordPress/src/main/java/org/wordpress/android/workers/weeklyroundup/WeeklyRoundupScheduler.kt @@ -1,11 +1,13 @@ package org.wordpress.android.workers.weeklyroundup import android.content.Context +import android.content.SharedPreferences import androidx.work.Constraints import androidx.work.ExistingWorkPolicy.KEEP import androidx.work.NetworkType.CONNECTED import androidx.work.OneTimeWorkRequestBuilder import androidx.work.WorkManager +import org.wordpress.android.R import java.time.DayOfWeek.MONDAY import java.time.Duration import java.time.LocalDate @@ -15,24 +17,33 @@ import java.time.temporal.TemporalAdjusters.next import java.util.concurrent.TimeUnit.MILLISECONDS import javax.inject.Inject -class WeeklyRoundupScheduler @Inject constructor(private val context: Context) { +class WeeklyRoundupScheduler @Inject constructor( + private val context: Context, + private val sharedPrefs: SharedPreferences +) { private val workManager by lazy { WorkManager.getInstance(context) } - fun schedule() { - val next = LocalDate.now().with(next(MONDAY)).atTime(DEFAULT_START_TIME) - val delay = Duration.between(LocalDateTime.now(), next) - - val constraints = Constraints.Builder() - .setRequiredNetworkType(CONNECTED) - .build() - - val workRequest = OneTimeWorkRequestBuilder() - .addTag(TAG) - .setInitialDelay(delay.toMillis(), MILLISECONDS) - .setConstraints(constraints) - .build() - - workManager.enqueueUniqueWork(TAG, KEEP, workRequest) + fun scheduleIfNeeded() { + val isNotificationSettingsEnabled = sharedPrefs.getBoolean( + context.getString(R.string.wp_pref_notifications_main), + true + ) + if (isNotificationSettingsEnabled) { + val next = LocalDate.now().with(next(MONDAY)).atTime(DEFAULT_START_TIME) + val delay = Duration.between(LocalDateTime.now(), next) + + val constraints = Constraints.Builder() + .setRequiredNetworkType(CONNECTED) + .build() + + val workRequest = OneTimeWorkRequestBuilder() + .addTag(TAG) + .setInitialDelay(delay.toMillis(), MILLISECONDS) + .setConstraints(constraints) + .build() + + workManager.enqueueUniqueWork(TAG, KEEP, workRequest) + } } fun cancel() = workManager.cancelUniqueWork(TAG) From fad1f9f2a5e5e4143bcd6e37313bd212c24fbccf Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Tue, 22 Nov 2022 18:58:38 +0300 Subject: [PATCH 10/11] Update CreateSiteNotificationHandlerTest --- .../CreateSiteNotificationHandlerTest.kt | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/WordPress/src/test/java/org/wordpress/android/workers/notification/createsite/CreateSiteNotificationHandlerTest.kt b/WordPress/src/test/java/org/wordpress/android/workers/notification/createsite/CreateSiteNotificationHandlerTest.kt index edc692083555..79b790ad38f5 100644 --- a/WordPress/src/test/java/org/wordpress/android/workers/notification/createsite/CreateSiteNotificationHandlerTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/workers/notification/createsite/CreateSiteNotificationHandlerTest.kt @@ -1,5 +1,6 @@ package org.wordpress.android.workers.notification.createsite +import android.content.SharedPreferences import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test @@ -8,30 +9,56 @@ import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever +import org.wordpress.android.R import org.wordpress.android.fluxc.store.AccountStore import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.push.NotificationType.CREATE_SITE import org.wordpress.android.ui.notifications.SystemNotificationsTracker +import org.wordpress.android.viewmodel.ResourceProvider @RunWith(MockitoJUnitRunner::class) class CreateSiteNotificationHandlerTest { private lateinit var createSiteNotificationHandler: CreateSiteNotificationHandler + private val sharedPrefs: SharedPreferences = mock() + private val resourceProvider: ResourceProvider = mock() private val accountStore: AccountStore = mock() private val siteStore: SiteStore = mock() private val notificationsTracker: SystemNotificationsTracker = mock() @Before fun setUp() { + val notificationsMainKey = "wp_pref_notifications_master" + whenever(resourceProvider.getString(R.string.wp_pref_notifications_main)).thenReturn(notificationsMainKey) createSiteNotificationHandler = CreateSiteNotificationHandler( + sharedPrefs, + resourceProvider, accountStore, siteStore, notificationsTracker ) } + @Test + fun `should not show notification when the notification settings is disabled`() { + whenever( + sharedPrefs.getBoolean( + resourceProvider.getString(R.string.wp_pref_notifications_main), + true + ) + ).thenReturn(false) + + assertThat(createSiteNotificationHandler.shouldShowNotification()).isFalse + } + @Test fun `should not show notification when the user is logged out`() { + whenever( + sharedPrefs.getBoolean( + resourceProvider.getString(R.string.wp_pref_notifications_main), + true + ) + ).thenReturn(true) whenever(accountStore.hasAccessToken()).thenReturn(false) assertThat(createSiteNotificationHandler.shouldShowNotification()).isFalse @@ -39,14 +66,41 @@ class CreateSiteNotificationHandlerTest { @Test fun `should not show notification when the user has sites`() { + val notificationsMainKey = "wp_pref_notifications_master" + whenever(resourceProvider.getString(R.string.wp_pref_notifications_main)).thenReturn(notificationsMainKey) + whenever( + sharedPrefs.getBoolean( + resourceProvider.getString(R.string.wp_pref_notifications_main), + true + ) + ).thenReturn(true) whenever(accountStore.hasAccessToken()).thenReturn(true) whenever(siteStore.hasSite()).thenReturn(true) assertThat(createSiteNotificationHandler.shouldShowNotification()).isFalse } + @Test + fun `should show notification when the notification settings is enabled`() { + whenever( + sharedPrefs.getBoolean( + resourceProvider.getString(R.string.wp_pref_notifications_main), + true + ) + ).thenReturn(true) + whenever(accountStore.hasAccessToken()).thenReturn(true) + + assertThat(createSiteNotificationHandler.shouldShowNotification()).isTrue + } + @Test fun `should show notification when the user is logged in and has no sites`() { + whenever( + sharedPrefs.getBoolean( + resourceProvider.getString(R.string.wp_pref_notifications_main), + true + ) + ).thenReturn(true) whenever(accountStore.hasAccessToken()).thenReturn(true) whenever(siteStore.hasSite()).thenReturn(false) From 7df6d32733173af5f17a60c4880b0e9c5dae6158 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Tue, 22 Nov 2022 19:15:06 +0300 Subject: [PATCH 11/11] Refactor NotificationsSettingsActivity --- .../notifications/NotificationsSettingsActivity.kt | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/NotificationsSettingsActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/NotificationsSettingsActivity.kt index feeb78368070..a19502121531 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/NotificationsSettingsActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/prefs/notifications/NotificationsSettingsActivity.kt @@ -1,6 +1,5 @@ package org.wordpress.android.ui.prefs.notifications -import android.content.SharedPreferences import android.os.Bundle import android.text.TextUtils import android.view.MenuItem @@ -38,7 +37,6 @@ class NotificationsSettingsActivity : LocaleAwareActivity(), MainSwitchToolbarLi private lateinit var messageTextView: TextView private lateinit var messageContainer: View - private lateinit var sharedPreferences: SharedPreferences private lateinit var fragmentContainer: View public override fun onCreate(savedInstanceState: Bundle?) { @@ -46,13 +44,8 @@ class NotificationsSettingsActivity : LocaleAwareActivity(), MainSwitchToolbarLi setContentView(layout.notifications_settings_activity) fragmentContainer = findViewById(id.fragment_container) - // Get shared preferences for main switch. - sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this@NotificationsSettingsActivity) + setUpPrimaryToolbar() - // Set up primary toolbar - setUpToolbar() - - // Set up main switch setUpMainSwitch() if (savedInstanceState == null) { @@ -99,7 +92,7 @@ class NotificationsSettingsActivity : LocaleAwareActivity(), MainSwitchToolbarLi /** * Set up primary toolbar for navigation and search */ - private fun setUpToolbar() { + private fun setUpPrimaryToolbar() { val toolbar = findViewById(id.toolbar_with_search) toolbar?.let { setSupportActionBar(it) } @@ -119,6 +112,7 @@ class NotificationsSettingsActivity : LocaleAwareActivity(), MainSwitchToolbarLi mainSwitchToolBarView.setMainSwitchToolbarListener(this) // Set main switch state from shared preferences. + val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this@NotificationsSettingsActivity) val isMainChecked = sharedPreferences.getBoolean(getString(string.wp_pref_notifications_main), true) mainSwitchToolBarView.loadInitialState(isMainChecked) hideDisabledView(isMainChecked)