diff --git a/changelog.d/7596.feature b/changelog.d/7596.feature new file mode 100644 index 0000000000..022d86342b --- /dev/null +++ b/changelog.d/7596.feature @@ -0,0 +1 @@ +Save m.local_notification_settings. event in account_data diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/account/LocalNotificationSettingsContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/account/LocalNotificationSettingsContent.kt index 2a95ccce7a..75d04f340a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/account/LocalNotificationSettingsContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/account/LocalNotificationSettingsContent.kt @@ -21,5 +21,6 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class LocalNotificationSettingsContent( - @Json(name = "is_silenced") val isSilenced: Boolean = false + @Json(name = "is_silenced") + val isSilenced: Boolean? ) diff --git a/vector/src/main/java/im/vector/app/core/notification/EnableNotificationsSettingUpdater.kt b/vector/src/main/java/im/vector/app/core/notification/NotificationsSettingUpdater.kt similarity index 77% rename from vector/src/main/java/im/vector/app/core/notification/EnableNotificationsSettingUpdater.kt rename to vector/src/main/java/im/vector/app/core/notification/NotificationsSettingUpdater.kt index 81b524cde9..a4d18baa64 100644 --- a/vector/src/main/java/im/vector/app/core/notification/EnableNotificationsSettingUpdater.kt +++ b/vector/src/main/java/im/vector/app/core/notification/NotificationsSettingUpdater.kt @@ -23,14 +23,21 @@ import org.matrix.android.sdk.api.session.Session import javax.inject.Inject import javax.inject.Singleton +/** + * Listen changes in Pusher or Account Data to update the local setting for notification toggle. + */ @Singleton -class EnableNotificationsSettingUpdater @Inject constructor( +class NotificationsSettingUpdater @Inject constructor( private val updateEnableNotificationsSettingOnChangeUseCase: UpdateEnableNotificationsSettingOnChangeUseCase, ) { private var job: Job? = null - fun onSessionsStarted(session: Session) { + fun onSessionStarted(session: Session) { + updateEnableNotificationsSettingOnChange(session) + } + + private fun updateEnableNotificationsSettingOnChange(session: Session) { job?.cancel() job = session.coroutineScope.launch { updateEnableNotificationsSettingOnChangeUseCase.execute(session) diff --git a/vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt b/vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt index 96c3f8a6ce..fbf89b76a4 100644 --- a/vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt +++ b/vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt @@ -19,11 +19,12 @@ package im.vector.app.core.session import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import im.vector.app.core.extensions.startSyncing -import im.vector.app.core.notification.EnableNotificationsSettingUpdater +import im.vector.app.core.notification.NotificationsSettingUpdater import im.vector.app.core.session.clientinfo.UpdateMatrixClientInfoUseCase import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.session.coroutineScope import im.vector.app.features.settings.VectorPreferences +import im.vector.app.features.settings.devices.v2.notification.UpdateNotificationSettingsAccountDataUseCase import im.vector.app.features.sync.SyncUtils import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session @@ -35,7 +36,8 @@ class ConfigureAndStartSessionUseCase @Inject constructor( private val webRtcCallManager: WebRtcCallManager, private val updateMatrixClientInfoUseCase: UpdateMatrixClientInfoUseCase, private val vectorPreferences: VectorPreferences, - private val enableNotificationsSettingUpdater: EnableNotificationsSettingUpdater, + private val notificationsSettingUpdater: NotificationsSettingUpdater, + private val updateNotificationSettingsAccountDataUseCase: UpdateNotificationSettingsAccountDataUseCase, ) { fun execute(session: Session, startSyncing: Boolean = true) { @@ -49,11 +51,22 @@ class ConfigureAndStartSessionUseCase @Inject constructor( } session.pushersService().refreshPushers() webRtcCallManager.checkForProtocolsSupportIfNeeded() + updateMatrixClientInfoIfNeeded(session) + createNotificationSettingsAccountDataIfNeeded(session) + notificationsSettingUpdater.onSessionStarted(session) + } + + private fun updateMatrixClientInfoIfNeeded(session: Session) { session.coroutineScope.launch { if (vectorPreferences.isClientInfoRecordingEnabled()) { updateMatrixClientInfoUseCase.execute(session) } } - enableNotificationsSettingUpdater.onSessionsStarted(session) + } + + private fun createNotificationSettingsAccountDataIfNeeded(session: Session) { + session.coroutineScope.launch { + updateNotificationSettingsAccountDataUseCase.execute(session) + } } } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt index 26034fc09c..a54ce2cff3 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt @@ -29,6 +29,7 @@ import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.pushers.EnsureFcmTokenIsRetrievedUseCase import im.vector.app.core.pushers.PushersManager import im.vector.app.core.pushers.RegisterUnifiedPushUseCase +import im.vector.app.core.pushers.UnregisterUnifiedPushUseCase import im.vector.app.features.analytics.AnalyticsConfig import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.analytics.extensions.toAnalyticsType @@ -92,6 +93,7 @@ class HomeActivityViewModel @AssistedInject constructor( private val stopOngoingVoiceBroadcastUseCase: StopOngoingVoiceBroadcastUseCase, private val pushersManager: PushersManager, private val registerUnifiedPushUseCase: RegisterUnifiedPushUseCase, + private val unregisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase, private val ensureFcmTokenIsRetrievedUseCase: EnsureFcmTokenIsRetrievedUseCase, ) : VectorViewModel(initialState) { @@ -130,6 +132,8 @@ class HomeActivityViewModel @AssistedInject constructor( private fun registerUnifiedPushIfNeeded() { if (vectorPreferences.areNotificationEnabledForDevice()) { registerUnifiedPush(distributor = "") + } else { + unregisterUnifiedPush() } } @@ -146,6 +150,12 @@ class HomeActivityViewModel @AssistedInject constructor( } } + private fun unregisterUnifiedPush() { + viewModelScope.launch { + unregisterUnifiedPushUseCase.execute(pushersManager) + } + } + private fun observeReleaseNotes() = withState { state -> if (vectorPreferences.isNewAppLayoutEnabled()) { // we don't want to show release notes for new users or after relogin diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt index f42d5af398..b7a6c5df30 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt @@ -28,7 +28,6 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.features.auth.PendingAuthHandler import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType -import im.vector.app.features.settings.devices.v2.signout.InterceptSignoutFlowResponseUseCase import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsReAuthNeeded import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsUseCase import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase @@ -48,7 +47,6 @@ class DevicesViewModel @AssistedInject constructor( private val refreshDevicesOnCryptoDevicesChangeUseCase: RefreshDevicesOnCryptoDevicesChangeUseCase, private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase, private val signoutSessionsUseCase: SignoutSessionsUseCase, - private val interceptSignoutFlowResponseUseCase: InterceptSignoutFlowResponseUseCase, private val pendingAuthHandler: PendingAuthHandler, refreshDevicesUseCase: RefreshDevicesUseCase, private val vectorPreferences: VectorPreferences, diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CanTogglePushNotificationsViaPusherUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CanToggleNotificationsViaPusherUseCase.kt similarity index 94% rename from vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CanTogglePushNotificationsViaPusherUseCase.kt rename to vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CanToggleNotificationsViaPusherUseCase.kt index 0125d92ba6..96521ec78c 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CanTogglePushNotificationsViaPusherUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CanToggleNotificationsViaPusherUseCase.kt @@ -24,7 +24,7 @@ import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.flow.unwrap import javax.inject.Inject -class CanTogglePushNotificationsViaPusherUseCase @Inject constructor() { +class CanToggleNotificationsViaPusherUseCase @Inject constructor() { fun execute(session: Session): Flow { return session diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaAccountDataUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanToggleNotificationsViaAccountDataUseCase.kt similarity index 70% rename from vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaAccountDataUseCase.kt rename to vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanToggleNotificationsViaAccountDataUseCase.kt index 194a2aebbf..58289495a4 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaAccountDataUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanToggleNotificationsViaAccountDataUseCase.kt @@ -17,14 +17,13 @@ package im.vector.app.features.settings.devices.v2.notification import org.matrix.android.sdk.api.session.Session -import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes import javax.inject.Inject -class CheckIfCanTogglePushNotificationsViaAccountDataUseCase @Inject constructor() { +class CheckIfCanToggleNotificationsViaAccountDataUseCase @Inject constructor( + private val getNotificationSettingsAccountDataUseCase: GetNotificationSettingsAccountDataUseCase, +) { fun execute(session: Session, deviceId: String): Boolean { - return session - .accountDataService() - .getUserAccountDataEvent(UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId) != null + return getNotificationSettingsAccountDataUseCase.execute(session, deviceId)?.isSilenced != null } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaPusherUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanToggleNotificationsViaPusherUseCase.kt similarity index 92% rename from vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaPusherUseCase.kt rename to vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanToggleNotificationsViaPusherUseCase.kt index ca314bf145..1dc186be7c 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaPusherUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanToggleNotificationsViaPusherUseCase.kt @@ -19,7 +19,7 @@ package im.vector.app.features.settings.devices.v2.notification import org.matrix.android.sdk.api.session.Session import javax.inject.Inject -class CheckIfCanTogglePushNotificationsViaPusherUseCase @Inject constructor() { +class CheckIfCanToggleNotificationsViaPusherUseCase @Inject constructor() { fun execute(session: Session): Boolean { return session diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/DeleteNotificationSettingsAccountDataUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/DeleteNotificationSettingsAccountDataUseCase.kt new file mode 100644 index 0000000000..3c086fe111 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/DeleteNotificationSettingsAccountDataUseCase.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.notification + +import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent +import org.matrix.android.sdk.api.session.Session +import javax.inject.Inject + +/** + * Delete the content of any associated notification settings to the current session. + */ +class DeleteNotificationSettingsAccountDataUseCase @Inject constructor( + private val getNotificationSettingsAccountDataUseCase: GetNotificationSettingsAccountDataUseCase, + private val setNotificationSettingsAccountDataUseCase: SetNotificationSettingsAccountDataUseCase, +) { + + suspend fun execute(session: Session) { + val deviceId = session.sessionParams.deviceId ?: return + if (getNotificationSettingsAccountDataUseCase.execute(session, deviceId)?.isSilenced != null) { + val emptyNotificationSettingsContent = LocalNotificationSettingsContent( + isSilenced = null + ) + setNotificationSettingsAccountDataUseCase.execute(session, deviceId, emptyNotificationSettingsContent) + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationSettingsAccountDataUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationSettingsAccountDataUseCase.kt new file mode 100644 index 0000000000..5517fa0978 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationSettingsAccountDataUseCase.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.notification + +import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes +import org.matrix.android.sdk.api.session.events.model.toModel +import javax.inject.Inject + +class GetNotificationSettingsAccountDataUseCase @Inject constructor() { + + fun execute(session: Session, deviceId: String): LocalNotificationSettingsContent? { + return session + .accountDataService() + .getUserAccountDataEvent(UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId) + ?.content + .toModel() + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationsStatusUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationsStatusUseCase.kt index 03e4e31f2e..ae7e859573 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationsStatusUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationsStatusUseCase.kt @@ -30,13 +30,13 @@ import org.matrix.android.sdk.flow.unwrap import javax.inject.Inject class GetNotificationsStatusUseCase @Inject constructor( - private val canTogglePushNotificationsViaPusherUseCase: CanTogglePushNotificationsViaPusherUseCase, - private val checkIfCanTogglePushNotificationsViaAccountDataUseCase: CheckIfCanTogglePushNotificationsViaAccountDataUseCase, + private val canToggleNotificationsViaPusherUseCase: CanToggleNotificationsViaPusherUseCase, + private val checkIfCanToggleNotificationsViaAccountDataUseCase: CheckIfCanToggleNotificationsViaAccountDataUseCase, ) { fun execute(session: Session, deviceId: String): Flow { return when { - checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(session, deviceId) -> { + checkIfCanToggleNotificationsViaAccountDataUseCase.execute(session, deviceId) -> { session.flow() .liveUserAccountData(UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId) .unwrap() @@ -44,14 +44,20 @@ class GetNotificationsStatusUseCase @Inject constructor( .map { if (it == true) NotificationsStatus.ENABLED else NotificationsStatus.DISABLED } .distinctUntilChanged() } - else -> canTogglePushNotificationsViaPusherUseCase.execute(session) + else -> canToggleNotificationsViaPusherUseCase.execute(session) .flatMapLatest { canToggle -> if (canToggle) { session.flow() .livePushers() .map { it.filter { pusher -> pusher.deviceId == deviceId } } .map { it.takeIf { it.isNotEmpty() }?.any { pusher -> pusher.enabled } } - .map { if (it == true) NotificationsStatus.ENABLED else NotificationsStatus.DISABLED } + .map { + when (it) { + true -> NotificationsStatus.ENABLED + false -> NotificationsStatus.DISABLED + else -> NotificationsStatus.NOT_SUPPORTED + } + } .distinctUntilChanged() } else { flowOf(NotificationsStatus.NOT_SUPPORTED) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/SetNotificationSettingsAccountDataUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/SetNotificationSettingsAccountDataUseCase.kt new file mode 100644 index 0000000000..7306794f16 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/SetNotificationSettingsAccountDataUseCase.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.notification + +import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes +import org.matrix.android.sdk.api.session.events.model.toContent +import javax.inject.Inject + +class SetNotificationSettingsAccountDataUseCase @Inject constructor() { + + suspend fun execute(session: Session, deviceId: String, localNotificationSettingsContent: LocalNotificationSettingsContent) { + session.accountDataService().updateUserAccountData( + UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId, + localNotificationSettingsContent.toContent(), + ) + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/TogglePushNotificationUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/ToggleNotificationsUseCase.kt similarity index 61% rename from vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/TogglePushNotificationUseCase.kt rename to vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/ToggleNotificationsUseCase.kt index 7969bbbe9b..77195ea950 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/TogglePushNotificationUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/ToggleNotificationsUseCase.kt @@ -18,32 +18,28 @@ package im.vector.app.features.settings.devices.v2.notification import im.vector.app.core.di.ActiveSessionHolder import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent -import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes -import org.matrix.android.sdk.api.session.events.model.toContent import javax.inject.Inject -class TogglePushNotificationUseCase @Inject constructor( +class ToggleNotificationsUseCase @Inject constructor( private val activeSessionHolder: ActiveSessionHolder, - private val checkIfCanTogglePushNotificationsViaPusherUseCase: CheckIfCanTogglePushNotificationsViaPusherUseCase, - private val checkIfCanTogglePushNotificationsViaAccountDataUseCase: CheckIfCanTogglePushNotificationsViaAccountDataUseCase, + private val checkIfCanToggleNotificationsViaPusherUseCase: CheckIfCanToggleNotificationsViaPusherUseCase, + private val checkIfCanToggleNotificationsViaAccountDataUseCase: CheckIfCanToggleNotificationsViaAccountDataUseCase, + private val setNotificationSettingsAccountDataUseCase: SetNotificationSettingsAccountDataUseCase, ) { suspend fun execute(deviceId: String, enabled: Boolean) { val session = activeSessionHolder.getSafeActiveSession() ?: return - if (checkIfCanTogglePushNotificationsViaPusherUseCase.execute(session)) { + if (checkIfCanToggleNotificationsViaPusherUseCase.execute(session)) { val devicePusher = session.pushersService().getPushers().firstOrNull { it.deviceId == deviceId } devicePusher?.let { pusher -> session.pushersService().togglePusher(pusher, enabled) } } - if (checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(session, deviceId)) { + if (checkIfCanToggleNotificationsViaAccountDataUseCase.execute(session, deviceId)) { val newNotificationSettingsContent = LocalNotificationSettingsContent(isSilenced = !enabled) - session.accountDataService().updateUserAccountData( - UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId, - newNotificationSettingsContent.toContent(), - ) + setNotificationSettingsAccountDataUseCase.execute(session, deviceId, newNotificationSettingsContent) } } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/UpdateNotificationSettingsAccountDataUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/UpdateNotificationSettingsAccountDataUseCase.kt new file mode 100644 index 0000000000..9296bcd912 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/UpdateNotificationSettingsAccountDataUseCase.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.notification + +import im.vector.app.core.pushers.UnifiedPushHelper +import im.vector.app.features.settings.VectorPreferences +import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent +import org.matrix.android.sdk.api.session.Session +import javax.inject.Inject + +/** + * Update the notification settings account data for the current session depending on whether + * the background sync is enabled or not. + */ +class UpdateNotificationSettingsAccountDataUseCase @Inject constructor( + private val vectorPreferences: VectorPreferences, + private val unifiedPushHelper: UnifiedPushHelper, + private val getNotificationSettingsAccountDataUseCase: GetNotificationSettingsAccountDataUseCase, + private val setNotificationSettingsAccountDataUseCase: SetNotificationSettingsAccountDataUseCase, + private val deleteNotificationSettingsAccountDataUseCase: DeleteNotificationSettingsAccountDataUseCase, +) { + + suspend fun execute(session: Session) { + if (unifiedPushHelper.isBackgroundSync()) { + setCurrentNotificationStatus(session) + } else { + deleteCurrentNotificationStatus(session) + } + } + + private suspend fun setCurrentNotificationStatus(session: Session) { + val deviceId = session.sessionParams.deviceId ?: return + val areNotificationsSilenced = !vectorPreferences.areNotificationEnabledForDevice() + val isSilencedAccountData = getNotificationSettingsAccountDataUseCase.execute(session, deviceId)?.isSilenced + if (areNotificationsSilenced != isSilencedAccountData) { + val notificationSettingsContent = LocalNotificationSettingsContent( + isSilenced = areNotificationsSilenced + ) + setNotificationSettingsAccountDataUseCase.execute(session, deviceId, notificationSettingsContent) + } + } + + private suspend fun deleteCurrentNotificationStatus(session: Session) { + deleteNotificationSettingsAccountDataUseCase.execute(session) + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index 472e0a4269..55866cb8c4 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -31,8 +31,7 @@ import im.vector.app.features.settings.devices.v2.RefreshDevicesUseCase import im.vector.app.features.settings.devices.v2.ToggleIpAddressVisibilityUseCase import im.vector.app.features.settings.devices.v2.VectorSessionsListViewModel import im.vector.app.features.settings.devices.v2.notification.GetNotificationsStatusUseCase -import im.vector.app.features.settings.devices.v2.notification.TogglePushNotificationUseCase -import im.vector.app.features.settings.devices.v2.signout.InterceptSignoutFlowResponseUseCase +import im.vector.app.features.settings.devices.v2.notification.ToggleNotificationsUseCase import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsReAuthNeeded import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsUseCase import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase @@ -51,10 +50,9 @@ class SessionOverviewViewModel @AssistedInject constructor( private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase, private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase, private val signoutSessionsUseCase: SignoutSessionsUseCase, - private val interceptSignoutFlowResponseUseCase: InterceptSignoutFlowResponseUseCase, private val pendingAuthHandler: PendingAuthHandler, private val activeSessionHolder: ActiveSessionHolder, - private val togglePushNotificationUseCase: TogglePushNotificationUseCase, + private val toggleNotificationsUseCase: ToggleNotificationsUseCase, private val getNotificationsStatusUseCase: GetNotificationsStatusUseCase, refreshDevicesUseCase: RefreshDevicesUseCase, private val vectorPreferences: VectorPreferences, @@ -228,7 +226,7 @@ class SessionOverviewViewModel @AssistedInject constructor( private fun handleTogglePusherAction(action: SessionOverviewAction.TogglePushNotifications) { viewModelScope.launch { - togglePushNotificationUseCase.execute(action.deviceId, action.enabled) + toggleNotificationsUseCase.execute(action.deviceId, action.enabled) } } } diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCase.kt index 84d92c4291..0c50a296f3 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCase.kt @@ -16,28 +16,18 @@ package im.vector.app.features.settings.notifications -import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.pushers.PushersManager import im.vector.app.core.pushers.UnregisterUnifiedPushUseCase -import im.vector.app.features.settings.devices.v2.notification.CheckIfCanTogglePushNotificationsViaPusherUseCase -import im.vector.app.features.settings.devices.v2.notification.TogglePushNotificationUseCase import javax.inject.Inject class DisableNotificationsForCurrentSessionUseCase @Inject constructor( - private val activeSessionHolder: ActiveSessionHolder, private val pushersManager: PushersManager, - private val checkIfCanTogglePushNotificationsViaPusherUseCase: CheckIfCanTogglePushNotificationsViaPusherUseCase, - private val togglePushNotificationUseCase: TogglePushNotificationUseCase, + private val toggleNotificationsForCurrentSessionUseCase: ToggleNotificationsForCurrentSessionUseCase, private val unregisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase, ) { suspend fun execute() { - val session = activeSessionHolder.getSafeActiveSession() ?: return - val deviceId = session.sessionParams.deviceId ?: return - if (checkIfCanTogglePushNotificationsViaPusherUseCase.execute(session)) { - togglePushNotificationUseCase.execute(deviceId, enabled = false) - } else { - unregisterUnifiedPushUseCase.execute(pushersManager) - } + toggleNotificationsForCurrentSessionUseCase.execute(enabled = false) + unregisterUnifiedPushUseCase.execute(pushersManager) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCase.kt index 99fb249384..daf3890e33 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCase.kt @@ -16,24 +16,20 @@ package im.vector.app.features.settings.notifications -import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.pushers.EnsureFcmTokenIsRetrievedUseCase import im.vector.app.core.pushers.PushersManager import im.vector.app.core.pushers.RegisterUnifiedPushUseCase -import im.vector.app.features.settings.devices.v2.notification.TogglePushNotificationUseCase import javax.inject.Inject class EnableNotificationsForCurrentSessionUseCase @Inject constructor( - private val activeSessionHolder: ActiveSessionHolder, private val pushersManager: PushersManager, - private val togglePushNotificationUseCase: TogglePushNotificationUseCase, + private val toggleNotificationsForCurrentSessionUseCase: ToggleNotificationsForCurrentSessionUseCase, private val registerUnifiedPushUseCase: RegisterUnifiedPushUseCase, private val ensureFcmTokenIsRetrievedUseCase: EnsureFcmTokenIsRetrievedUseCase, ) { sealed interface EnableNotificationsResult { object Success : EnableNotificationsResult - object Failure : EnableNotificationsResult object NeedToAskUserForDistributor : EnableNotificationsResult } @@ -50,9 +46,7 @@ class EnableNotificationsForCurrentSessionUseCase @Inject constructor( } } - val session = activeSessionHolder.getSafeActiveSession() ?: return EnableNotificationsResult.Failure - val deviceId = session.sessionParams.deviceId ?: return EnableNotificationsResult.Failure - togglePushNotificationUseCase.execute(deviceId, enabled = true) + toggleNotificationsForCurrentSessionUseCase.execute(enabled = true) return EnableNotificationsResult.Success } diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/ToggleNotificationsForCurrentSessionUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/ToggleNotificationsForCurrentSessionUseCase.kt new file mode 100644 index 0000000000..3dc73f0a31 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/ToggleNotificationsForCurrentSessionUseCase.kt @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.notifications + +import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.core.pushers.UnifiedPushHelper +import im.vector.app.features.settings.devices.v2.notification.CheckIfCanToggleNotificationsViaPusherUseCase +import im.vector.app.features.settings.devices.v2.notification.DeleteNotificationSettingsAccountDataUseCase +import im.vector.app.features.settings.devices.v2.notification.SetNotificationSettingsAccountDataUseCase +import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent +import timber.log.Timber +import javax.inject.Inject + +class ToggleNotificationsForCurrentSessionUseCase @Inject constructor( + private val activeSessionHolder: ActiveSessionHolder, + private val unifiedPushHelper: UnifiedPushHelper, + private val checkIfCanToggleNotificationsViaPusherUseCase: CheckIfCanToggleNotificationsViaPusherUseCase, + private val setNotificationSettingsAccountDataUseCase: SetNotificationSettingsAccountDataUseCase, + private val deleteNotificationSettingsAccountDataUseCase: DeleteNotificationSettingsAccountDataUseCase, +) { + + suspend fun execute(enabled: Boolean) { + val session = activeSessionHolder.getSafeActiveSession() ?: return + val deviceId = session.sessionParams.deviceId ?: return + + if (unifiedPushHelper.isBackgroundSync()) { + Timber.d("background sync is enabled, setting account data event") + val newNotificationSettingsContent = LocalNotificationSettingsContent(isSilenced = !enabled) + setNotificationSettingsAccountDataUseCase.execute(session, deviceId, newNotificationSettingsContent) + } else { + Timber.d("push notif is enabled, deleting any account data and updating pusher") + deleteNotificationSettingsAccountDataUseCase.execute(session) + + if (checkIfCanToggleNotificationsViaPusherUseCase.execute(session)) { + val devicePusher = session.pushersService().getPushers().firstOrNull { it.deviceId == deviceId } + devicePusher?.let { pusher -> + session.pushersService().togglePusher(pusher, enabled) + } + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt index 238ed4218c..490a47ef61 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt @@ -119,7 +119,6 @@ class VectorSettingsNotificationPreferenceFragment : VectorSettingsNotificationPreferenceViewEvent.NotificationsForDeviceEnabled -> onNotificationsForDeviceEnabled() VectorSettingsNotificationPreferenceViewEvent.NotificationsForDeviceDisabled -> onNotificationsForDeviceDisabled() is VectorSettingsNotificationPreferenceViewEvent.AskUserForPushDistributor -> askUserToSelectPushDistributor() - VectorSettingsNotificationPreferenceViewEvent.EnableNotificationForDeviceFailure -> displayErrorDialog(throwable = null) VectorSettingsNotificationPreferenceViewEvent.NotificationMethodChanged -> onNotificationMethodChanged() } } diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewEvent.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewEvent.kt index e4cf8e1973..b0ee107769 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewEvent.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewEvent.kt @@ -20,7 +20,6 @@ import im.vector.app.core.platform.VectorViewEvents sealed interface VectorSettingsNotificationPreferenceViewEvent : VectorViewEvents { object NotificationsForDeviceEnabled : VectorSettingsNotificationPreferenceViewEvent - object EnableNotificationForDeviceFailure : VectorSettingsNotificationPreferenceViewEvent object NotificationsForDeviceDisabled : VectorSettingsNotificationPreferenceViewEvent object AskUserForPushDistributor : VectorSettingsNotificationPreferenceViewEvent object NotificationMethodChanged : VectorSettingsNotificationPreferenceViewEvent diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewModel.kt index d6a9c621f2..48e82b35e8 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewModel.kt @@ -40,6 +40,7 @@ class VectorSettingsNotificationPreferenceViewModel @AssistedInject constructor( private val unregisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase, private val registerUnifiedPushUseCase: RegisterUnifiedPushUseCase, private val ensureFcmTokenIsRetrievedUseCase: EnsureFcmTokenIsRetrievedUseCase, + private val toggleNotificationsForCurrentSessionUseCase: ToggleNotificationsForCurrentSessionUseCase, ) : VectorViewModel(initialState) { @AssistedFactory @@ -67,9 +68,6 @@ class VectorSettingsNotificationPreferenceViewModel @AssistedInject constructor( private fun handleEnableNotificationsForDevice(distributor: String) { viewModelScope.launch { when (enableNotificationsForCurrentSessionUseCase.execute(distributor)) { - EnableNotificationsForCurrentSessionUseCase.EnableNotificationsResult.Failure -> { - _viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.EnableNotificationForDeviceFailure) - } is EnableNotificationsForCurrentSessionUseCase.EnableNotificationsResult.NeedToAskUserForDistributor -> { _viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.AskUserForPushDistributor) } @@ -88,7 +86,9 @@ class VectorSettingsNotificationPreferenceViewModel @AssistedInject constructor( _viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.AskUserForPushDistributor) } RegisterUnifiedPushUseCase.RegisterUnifiedPushResult.Success -> { - ensureFcmTokenIsRetrievedUseCase.execute(pushersManager, registerPusher = vectorPreferences.areNotificationEnabledForDevice()) + val areNotificationsEnabled = vectorPreferences.areNotificationEnabledForDevice() + ensureFcmTokenIsRetrievedUseCase.execute(pushersManager, registerPusher = areNotificationsEnabled) + toggleNotificationsForCurrentSessionUseCase.execute(enabled = areNotificationsEnabled) _viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.NotificationMethodChanged) } } diff --git a/vector/src/test/java/im/vector/app/core/notification/NotificationsSettingUpdaterTest.kt b/vector/src/test/java/im/vector/app/core/notification/NotificationsSettingUpdaterTest.kt new file mode 100644 index 0000000000..0920ee4716 --- /dev/null +++ b/vector/src/test/java/im/vector/app/core/notification/NotificationsSettingUpdaterTest.kt @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.core.notification + +import im.vector.app.features.session.coroutineScope +import im.vector.app.test.fakes.FakeSession +import io.mockk.coJustRun +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkAll +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.runTest +import org.junit.After +import org.junit.Before +import org.junit.Test + +class NotificationsSettingUpdaterTest { + + private val fakeUpdateEnableNotificationsSettingOnChangeUseCase = mockk() + + private val notificationsSettingUpdater = NotificationsSettingUpdater( + updateEnableNotificationsSettingOnChangeUseCase = fakeUpdateEnableNotificationsSettingOnChangeUseCase, + ) + + @Before + fun setup() { + mockkStatic("im.vector.app.features.session.SessionCoroutineScopesKt") + } + + @After + fun tearDown() { + unmockkAll() + } + + @Test + fun `given a session when calling onSessionStarted then update enable notification on change`() = runTest { + // Given + val aSession = FakeSession() + every { aSession.coroutineScope } returns this + coJustRun { fakeUpdateEnableNotificationsSettingOnChangeUseCase.execute(any()) } + + // When + notificationsSettingUpdater.onSessionStarted(aSession) + advanceUntilIdle() + + // Then + coVerify { fakeUpdateEnableNotificationsSettingOnChangeUseCase.execute(aSession) } + } +} diff --git a/vector/src/test/java/im/vector/app/core/session/ConfigureAndStartSessionUseCaseTest.kt b/vector/src/test/java/im/vector/app/core/session/ConfigureAndStartSessionUseCaseTest.kt index 01596e796d..3fb128c759 100644 --- a/vector/src/test/java/im/vector/app/core/session/ConfigureAndStartSessionUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/core/session/ConfigureAndStartSessionUseCaseTest.kt @@ -19,9 +19,10 @@ package im.vector.app.core.session import im.vector.app.core.extensions.startSyncing import im.vector.app.core.session.clientinfo.UpdateMatrixClientInfoUseCase import im.vector.app.features.session.coroutineScope +import im.vector.app.features.settings.devices.v2.notification.UpdateNotificationSettingsAccountDataUseCase import im.vector.app.features.sync.SyncUtils import im.vector.app.test.fakes.FakeContext -import im.vector.app.test.fakes.FakeEnableNotificationsSettingUpdater +import im.vector.app.test.fakes.FakeNotificationsSettingUpdater import im.vector.app.test.fakes.FakeSession import im.vector.app.test.fakes.FakeVectorPreferences import im.vector.app.test.fakes.FakeWebRtcCallManager @@ -46,14 +47,16 @@ class ConfigureAndStartSessionUseCaseTest { private val fakeWebRtcCallManager = FakeWebRtcCallManager() private val fakeUpdateMatrixClientInfoUseCase = mockk() private val fakeVectorPreferences = FakeVectorPreferences() - private val fakeEnableNotificationsSettingUpdater = FakeEnableNotificationsSettingUpdater() + private val fakeNotificationsSettingUpdater = FakeNotificationsSettingUpdater() + private val fakeUpdateNotificationSettingsAccountDataUseCase = mockk() private val configureAndStartSessionUseCase = ConfigureAndStartSessionUseCase( context = fakeContext.instance, webRtcCallManager = fakeWebRtcCallManager.instance, updateMatrixClientInfoUseCase = fakeUpdateMatrixClientInfoUseCase, vectorPreferences = fakeVectorPreferences.instance, - enableNotificationsSettingUpdater = fakeEnableNotificationsSettingUpdater.instance, + notificationsSettingUpdater = fakeNotificationsSettingUpdater.instance, + updateNotificationSettingsAccountDataUseCase = fakeUpdateNotificationSettingsAccountDataUseCase, ) @Before @@ -70,67 +73,80 @@ class ConfigureAndStartSessionUseCaseTest { @Test fun `given start sync needed and client info recording enabled when execute then it should be configured properly`() = runTest { // Given - val fakeSession = givenASession() - every { fakeSession.coroutineScope } returns this + val aSession = givenASession() + every { aSession.coroutineScope } returns this fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) } + coJustRun { fakeUpdateNotificationSettingsAccountDataUseCase.execute(any()) } fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = true) - fakeEnableNotificationsSettingUpdater.givenOnSessionsStarted(fakeSession) + fakeNotificationsSettingUpdater.givenOnSessionsStarted(aSession) // When - configureAndStartSessionUseCase.execute(fakeSession, startSyncing = true) + configureAndStartSessionUseCase.execute(aSession, startSyncing = true) advanceUntilIdle() // Then - verify { fakeSession.startSyncing(fakeContext.instance) } - fakeSession.fakeFilterService.verifySetSyncFilter(SyncUtils.getSyncFilterBuilder()) - fakeSession.fakePushersService.verifyRefreshPushers() + verify { aSession.startSyncing(fakeContext.instance) } + aSession.fakeFilterService.verifySetSyncFilter(SyncUtils.getSyncFilterBuilder()) + aSession.fakePushersService.verifyRefreshPushers() fakeWebRtcCallManager.verifyCheckForProtocolsSupportIfNeeded() - coVerify { fakeUpdateMatrixClientInfoUseCase.execute(fakeSession) } + coVerify { + fakeUpdateMatrixClientInfoUseCase.execute(aSession) + fakeUpdateNotificationSettingsAccountDataUseCase.execute(aSession) + } } @Test fun `given start sync needed and client info recording disabled when execute then it should be configured properly`() = runTest { // Given - val fakeSession = givenASession() - every { fakeSession.coroutineScope } returns this + val aSession = givenASession() + every { aSession.coroutineScope } returns this fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() - coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) } + coJustRun { fakeUpdateNotificationSettingsAccountDataUseCase.execute(any()) } fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = false) - fakeEnableNotificationsSettingUpdater.givenOnSessionsStarted(fakeSession) + fakeNotificationsSettingUpdater.givenOnSessionsStarted(aSession) // When - configureAndStartSessionUseCase.execute(fakeSession, startSyncing = true) + configureAndStartSessionUseCase.execute(aSession, startSyncing = true) advanceUntilIdle() // Then - verify { fakeSession.startSyncing(fakeContext.instance) } - fakeSession.fakeFilterService.verifySetSyncFilter(SyncUtils.getSyncFilterBuilder()) - fakeSession.fakePushersService.verifyRefreshPushers() + verify { aSession.startSyncing(fakeContext.instance) } + aSession.fakeFilterService.verifySetSyncFilter(SyncUtils.getSyncFilterBuilder()) + aSession.fakePushersService.verifyRefreshPushers() fakeWebRtcCallManager.verifyCheckForProtocolsSupportIfNeeded() - coVerify(inverse = true) { fakeUpdateMatrixClientInfoUseCase.execute(fakeSession) } + coVerify(inverse = true) { + fakeUpdateMatrixClientInfoUseCase.execute(aSession) + } + coVerify { + fakeUpdateNotificationSettingsAccountDataUseCase.execute(aSession) + } } @Test fun `given a session and no start sync needed when execute then it should be configured properly`() = runTest { // Given - val fakeSession = givenASession() - every { fakeSession.coroutineScope } returns this + val aSession = givenASession() + every { aSession.coroutineScope } returns this fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) } + coJustRun { fakeUpdateNotificationSettingsAccountDataUseCase.execute(any()) } fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = true) - fakeEnableNotificationsSettingUpdater.givenOnSessionsStarted(fakeSession) + fakeNotificationsSettingUpdater.givenOnSessionsStarted(aSession) // When - configureAndStartSessionUseCase.execute(fakeSession, startSyncing = false) + configureAndStartSessionUseCase.execute(aSession, startSyncing = false) advanceUntilIdle() // Then - verify(inverse = true) { fakeSession.startSyncing(fakeContext.instance) } - fakeSession.fakeFilterService.verifySetSyncFilter(SyncUtils.getSyncFilterBuilder()) - fakeSession.fakePushersService.verifyRefreshPushers() + verify(inverse = true) { aSession.startSyncing(fakeContext.instance) } + aSession.fakeFilterService.verifySetSyncFilter(SyncUtils.getSyncFilterBuilder()) + aSession.fakePushersService.verifyRefreshPushers() fakeWebRtcCallManager.verifyCheckForProtocolsSupportIfNeeded() - coVerify { fakeUpdateMatrixClientInfoUseCase.execute(fakeSession) } + coVerify { + fakeUpdateMatrixClientInfoUseCase.execute(aSession) + fakeUpdateNotificationSettingsAccountDataUseCase.execute(aSession) + } } private fun givenASession(): FakeSession { diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt index 03177aac47..4bfd5c4496 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt @@ -22,7 +22,6 @@ import com.airbnb.mvrx.test.MavericksTestRule import im.vector.app.core.session.clientinfo.MatrixClientInfoContent import im.vector.app.features.settings.devices.v2.details.extended.DeviceExtendedInfo import im.vector.app.features.settings.devices.v2.list.DeviceType -import im.vector.app.features.settings.devices.v2.signout.InterceptSignoutFlowResponseUseCase import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase @@ -72,7 +71,6 @@ class DevicesViewModelTest { private val refreshDevicesOnCryptoDevicesChangeUseCase = mockk(relaxed = true) private val checkIfCurrentSessionCanBeVerifiedUseCase = mockk() private val fakeSignoutSessionsUseCase = FakeSignoutSessionsUseCase() - private val fakeInterceptSignoutFlowResponseUseCase = mockk() private val fakePendingAuthHandler = FakePendingAuthHandler() private val fakeRefreshDevicesUseCase = mockk(relaxUnitFun = true) private val fakeVectorPreferences = FakeVectorPreferences() @@ -87,7 +85,6 @@ class DevicesViewModelTest { refreshDevicesOnCryptoDevicesChangeUseCase = refreshDevicesOnCryptoDevicesChangeUseCase, checkIfCurrentSessionCanBeVerifiedUseCase = checkIfCurrentSessionCanBeVerifiedUseCase, signoutSessionsUseCase = fakeSignoutSessionsUseCase.instance, - interceptSignoutFlowResponseUseCase = fakeInterceptSignoutFlowResponseUseCase, pendingAuthHandler = fakePendingAuthHandler.instance, refreshDevicesUseCase = fakeRefreshDevicesUseCase, vectorPreferences = fakeVectorPreferences.instance, diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CanTogglePushNotificationsViaPusherUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CanToggleNotificationsViaPusherUseCaseTest.kt similarity index 87% rename from vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CanTogglePushNotificationsViaPusherUseCaseTest.kt rename to vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CanToggleNotificationsViaPusherUseCaseTest.kt index 997fa827f5..3284adb32d 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CanTogglePushNotificationsViaPusherUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CanToggleNotificationsViaPusherUseCaseTest.kt @@ -30,13 +30,13 @@ import org.junit.Test private val A_HOMESERVER_CAPABILITIES = aHomeServerCapabilities(canRemotelyTogglePushNotificationsOfDevices = true) -class CanTogglePushNotificationsViaPusherUseCaseTest { +class CanToggleNotificationsViaPusherUseCaseTest { private val fakeSession = FakeSession() private val fakeFlowLiveDataConversions = FakeFlowLiveDataConversions() - private val canTogglePushNotificationsViaPusherUseCase = - CanTogglePushNotificationsViaPusherUseCase() + private val canToggleNotificationsViaPusherUseCase = + CanToggleNotificationsViaPusherUseCase() @Before fun setUp() { @@ -57,7 +57,7 @@ class CanTogglePushNotificationsViaPusherUseCaseTest { .givenAsFlow() // When - val result = canTogglePushNotificationsViaPusherUseCase.execute(fakeSession).firstOrNull() + val result = canToggleNotificationsViaPusherUseCase.execute(fakeSession).firstOrNull() // Then result shouldBeEqualTo A_HOMESERVER_CAPABILITIES.canRemotelyTogglePushNotificationsOfDevices diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanToggleNotificationsViaAccountDataUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanToggleNotificationsViaAccountDataUseCaseTest.kt new file mode 100644 index 0000000000..f97e326a02 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanToggleNotificationsViaAccountDataUseCaseTest.kt @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.notification + +import im.vector.app.test.fakes.FakeSession +import io.mockk.every +import io.mockk.mockk +import org.amshove.kluent.shouldBeEqualTo +import org.junit.Test +import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent + +private const val A_DEVICE_ID = "device-id" + +class CheckIfCanToggleNotificationsViaAccountDataUseCaseTest { + + private val fakeGetNotificationSettingsAccountDataUseCase = mockk() + private val fakeSession = FakeSession() + + private val checkIfCanToggleNotificationsViaAccountDataUseCase = + CheckIfCanToggleNotificationsViaAccountDataUseCase( + getNotificationSettingsAccountDataUseCase = fakeGetNotificationSettingsAccountDataUseCase, + ) + + @Test + fun `given current session and an account data with a content for the device id when execute then result is true`() { + // Given + val content = LocalNotificationSettingsContent(isSilenced = true) + every { fakeGetNotificationSettingsAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns content + + // When + val result = checkIfCanToggleNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) + + // Then + result shouldBeEqualTo true + } + + @Test + fun `given current session and an account data with empty content for the device id when execute then result is false`() { + // Given + val content = LocalNotificationSettingsContent(isSilenced = null) + every { fakeGetNotificationSettingsAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns content + + // When + val result = checkIfCanToggleNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) + + // Then + result shouldBeEqualTo false + } + + @Test + fun `given current session and NO account data for the device id when execute then result is false`() { + // Given + val content = null + every { fakeGetNotificationSettingsAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns content + + // When + val result = checkIfCanToggleNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) + + // Then + result shouldBeEqualTo false + } +} diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaPusherUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanToggleNotificationsViaPusherUseCaseTest.kt similarity index 82% rename from vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaPusherUseCaseTest.kt rename to vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanToggleNotificationsViaPusherUseCaseTest.kt index 508a05acd6..64beb7b8e2 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaPusherUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanToggleNotificationsViaPusherUseCaseTest.kt @@ -23,12 +23,12 @@ import org.junit.Test private val A_HOMESERVER_CAPABILITIES = aHomeServerCapabilities(canRemotelyTogglePushNotificationsOfDevices = true) -class CheckIfCanTogglePushNotificationsViaPusherUseCaseTest { +class CheckIfCanToggleNotificationsViaPusherUseCaseTest { private val fakeSession = FakeSession() - private val checkIfCanTogglePushNotificationsViaPusherUseCase = - CheckIfCanTogglePushNotificationsViaPusherUseCase() + private val checkIfCanToggleNotificationsViaPusherUseCase = + CheckIfCanToggleNotificationsViaPusherUseCase() @Test fun `given current session when execute then toggle capability is returned`() { @@ -38,7 +38,7 @@ class CheckIfCanTogglePushNotificationsViaPusherUseCaseTest { .givenCapabilities(A_HOMESERVER_CAPABILITIES) // When - val result = checkIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) + val result = checkIfCanToggleNotificationsViaPusherUseCase.execute(fakeSession) // Then result shouldBeEqualTo A_HOMESERVER_CAPABILITIES.canRemotelyTogglePushNotificationsOfDevices diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest.kt deleted file mode 100644 index 37433364e8..0000000000 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package im.vector.app.features.settings.devices.v2.notification - -import im.vector.app.test.fakes.FakeSession -import io.mockk.mockk -import org.amshove.kluent.shouldBeEqualTo -import org.junit.Test -import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes - -private const val A_DEVICE_ID = "device-id" - -class CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest { - - private val fakeSession = FakeSession() - - private val checkIfCanTogglePushNotificationsViaAccountDataUseCase = - CheckIfCanTogglePushNotificationsViaAccountDataUseCase() - - @Test - fun `given current session and an account data for the device id when execute then result is true`() { - // Given - fakeSession - .accountDataService() - .givenGetUserAccountDataEventReturns( - type = UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + A_DEVICE_ID, - content = mockk(), - ) - - // When - val result = checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) - - // Then - result shouldBeEqualTo true - } - - @Test - fun `given current session and NO account data for the device id when execute then result is false`() { - // Given - fakeSession - .accountDataService() - .givenGetUserAccountDataEventReturns( - type = UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + A_DEVICE_ID, - content = null, - ) - - // When - val result = checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) - - // Then - result shouldBeEqualTo false - } -} diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/DeleteNotificationSettingsAccountDataUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/DeleteNotificationSettingsAccountDataUseCaseTest.kt new file mode 100644 index 0000000000..600ba2ba48 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/DeleteNotificationSettingsAccountDataUseCaseTest.kt @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.notification + +import im.vector.app.test.fakes.FakeSession +import io.mockk.coJustRun +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent + +class DeleteNotificationSettingsAccountDataUseCaseTest { + + private val fakeSetNotificationSettingsAccountDataUseCase = mockk() + private val fakeGetNotificationSettingsAccountDataUseCase = mockk() + + private val deleteNotificationSettingsAccountDataUseCase = DeleteNotificationSettingsAccountDataUseCase( + setNotificationSettingsAccountDataUseCase = fakeSetNotificationSettingsAccountDataUseCase, + getNotificationSettingsAccountDataUseCase = fakeGetNotificationSettingsAccountDataUseCase, + ) + + @Test + fun `given a device id and existing account data content when execute then empty content is set for the account data`() = runTest { + // Given + val aDeviceId = "device-id" + val aSession = FakeSession() + aSession.givenSessionId(aDeviceId) + every { fakeGetNotificationSettingsAccountDataUseCase.execute(any(), any()) } returns LocalNotificationSettingsContent( + isSilenced = true, + ) + coJustRun { fakeSetNotificationSettingsAccountDataUseCase.execute(any(), any(), any()) } + val expectedContent = LocalNotificationSettingsContent( + isSilenced = null + ) + + // When + deleteNotificationSettingsAccountDataUseCase.execute(aSession) + + // Then + verify { fakeGetNotificationSettingsAccountDataUseCase.execute(aSession, aDeviceId) } + coVerify { fakeSetNotificationSettingsAccountDataUseCase.execute(aSession, aDeviceId, expectedContent) } + } + + @Test + fun `given a device id and empty existing account data content when execute then nothing is done`() = runTest { + // Given + val aDeviceId = "device-id" + val aSession = FakeSession() + aSession.givenSessionId(aDeviceId) + every { fakeGetNotificationSettingsAccountDataUseCase.execute(any(), any()) } returns LocalNotificationSettingsContent( + isSilenced = null, + ) + + // When + deleteNotificationSettingsAccountDataUseCase.execute(aSession) + + // Then + verify { fakeGetNotificationSettingsAccountDataUseCase.execute(aSession, aDeviceId) } + coVerify(inverse = true) { fakeSetNotificationSettingsAccountDataUseCase.execute(aSession, aDeviceId, any()) } + } +} diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationSettingsAccountDataUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationSettingsAccountDataUseCaseTest.kt new file mode 100644 index 0000000000..2adb0d8599 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationSettingsAccountDataUseCaseTest.kt @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.notification + +import im.vector.app.test.fakes.FakeSession +import org.amshove.kluent.shouldBeEqualTo +import org.junit.Test +import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent +import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes +import org.matrix.android.sdk.api.session.events.model.toContent + +class GetNotificationSettingsAccountDataUseCaseTest { + + private val getNotificationSettingsAccountDataUseCase = GetNotificationSettingsAccountDataUseCase() + + @Test + fun `given a device id when execute then retrieve the account data event corresponding to this id if any`() { + // Given + val aDeviceId = "device-id" + val aSession = FakeSession() + val expectedContent = LocalNotificationSettingsContent(isSilenced = true) + aSession + .accountDataService() + .givenGetUserAccountDataEventReturns( + type = UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + aDeviceId, + content = expectedContent.toContent(), + ) + + // When + val result = getNotificationSettingsAccountDataUseCase.execute(aSession, aDeviceId) + + // Then + result shouldBeEqualTo expectedContent + } + + @Test + fun `given a device id and empty content when execute then retrieve the account data event corresponding to this id if any`() { + // Given + val aDeviceId = "device-id" + val aSession = FakeSession() + val expectedContent = LocalNotificationSettingsContent(isSilenced = null) + aSession + .accountDataService() + .givenGetUserAccountDataEventReturns( + type = UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + aDeviceId, + content = expectedContent.toContent(), + ) + + // When + val result = getNotificationSettingsAccountDataUseCase.execute(aSession, aDeviceId) + + // Then + result shouldBeEqualTo expectedContent + } +} diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationsStatusUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationsStatusUseCaseTest.kt index b38367b098..3c454f7965 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationsStatusUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationsStatusUseCaseTest.kt @@ -46,15 +46,15 @@ class GetNotificationsStatusUseCaseTest { val instantTaskExecutorRule = InstantTaskExecutorRule() private val fakeSession = FakeSession() - private val fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase = - mockk() - private val fakeCanTogglePushNotificationsViaPusherUseCase = - mockk() + private val fakeCheckIfCanToggleNotificationsViaAccountDataUseCase = + mockk() + private val fakeCanToggleNotificationsViaPusherUseCase = + mockk() private val getNotificationsStatusUseCase = GetNotificationsStatusUseCase( - checkIfCanTogglePushNotificationsViaAccountDataUseCase = fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase, - canTogglePushNotificationsViaPusherUseCase = fakeCanTogglePushNotificationsViaPusherUseCase, + checkIfCanToggleNotificationsViaAccountDataUseCase = fakeCheckIfCanToggleNotificationsViaAccountDataUseCase, + canToggleNotificationsViaPusherUseCase = fakeCanToggleNotificationsViaPusherUseCase, ) @Before @@ -70,8 +70,8 @@ class GetNotificationsStatusUseCaseTest { @Test fun `given current session and toggle is not supported when execute then resulting flow contains NOT_SUPPORTED value`() = runTest { // Given - every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns false - every { fakeCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(false) + every { fakeCheckIfCanToggleNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns false + every { fakeCanToggleNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(false) // When val result = getNotificationsStatusUseCase.execute(fakeSession, A_DEVICE_ID) @@ -80,8 +80,8 @@ class GetNotificationsStatusUseCaseTest { result.firstOrNull() shouldBeEqualTo NotificationsStatus.NOT_SUPPORTED verifyOrder { // we should first check account data - fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) - fakeCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) + fakeCheckIfCanToggleNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) + fakeCanToggleNotificationsViaPusherUseCase.execute(fakeSession) } } @@ -95,8 +95,8 @@ class GetNotificationsStatusUseCaseTest { ) ) fakeSession.pushersService().givenPushersLive(pushers) - every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns false - every { fakeCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(true) + every { fakeCheckIfCanToggleNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns false + every { fakeCanToggleNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(true) // When val result = getNotificationsStatusUseCase.execute(fakeSession, A_DEVICE_ID) @@ -105,6 +105,20 @@ class GetNotificationsStatusUseCaseTest { result.firstOrNull() shouldBeEqualTo NotificationsStatus.ENABLED } + @Test + fun `given toggle via pusher is supported and no registered pusher when execute then resulting flow contains NOT_SUPPORTED value`() = runTest { + // Given + fakeSession.pushersService().givenPushersLive(emptyList()) + every { fakeCheckIfCanToggleNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns false + every { fakeCanToggleNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(true) + + // When + val result = getNotificationsStatusUseCase.execute(fakeSession, A_DEVICE_ID) + + // Then + result.firstOrNull() shouldBeEqualTo NotificationsStatus.NOT_SUPPORTED + } + @Test fun `given current session and toggle via account data is supported when execute then resulting flow contains status based on settings value`() = runTest { // Given @@ -116,8 +130,8 @@ class GetNotificationsStatusUseCaseTest { isSilenced = false ).toContent(), ) - every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns true - every { fakeCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(false) + every { fakeCheckIfCanToggleNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns true + every { fakeCanToggleNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(false) // When val result = getNotificationsStatusUseCase.execute(fakeSession, A_DEVICE_ID) diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/SetNotificationSettingsAccountDataUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/SetNotificationSettingsAccountDataUseCaseTest.kt new file mode 100644 index 0000000000..89fcd5e512 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/SetNotificationSettingsAccountDataUseCaseTest.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.notification + +import im.vector.app.test.fakes.FakeSession +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent +import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes +import org.matrix.android.sdk.api.session.events.model.toContent + +class SetNotificationSettingsAccountDataUseCaseTest { + + private val setNotificationSettingsAccountDataUseCase = SetNotificationSettingsAccountDataUseCase() + + @Test + fun `given a content when execute then update local notification settings with this content`() = runTest { + // Given + val sessionId = "a_session_id" + val localNotificationSettingsContent = LocalNotificationSettingsContent(isSilenced = true) + val fakeSession = FakeSession() + fakeSession.accountDataService().givenUpdateUserAccountDataEventSucceeds() + + // When + setNotificationSettingsAccountDataUseCase.execute(fakeSession, sessionId, localNotificationSettingsContent) + + // Then + fakeSession.accountDataService().verifyUpdateUserAccountDataEventSucceeds( + UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + sessionId, + localNotificationSettingsContent.toContent(), + ) + } +} diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/ToggleNotificationsUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/ToggleNotificationsUseCaseTest.kt new file mode 100644 index 0000000000..90afbe9045 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/ToggleNotificationsUseCaseTest.kt @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.notification + +import im.vector.app.test.fakes.FakeActiveSessionHolder +import im.vector.app.test.fixtures.PusherFixture +import io.mockk.coJustRun +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent + +class ToggleNotificationsUseCaseTest { + + private val activeSessionHolder = FakeActiveSessionHolder() + private val fakeCheckIfCanToggleNotificationsViaPusherUseCase = + mockk() + private val fakeCheckIfCanToggleNotificationsViaAccountDataUseCase = + mockk() + private val fakeSetNotificationSettingsAccountDataUseCase = + mockk() + + private val toggleNotificationsUseCase = + ToggleNotificationsUseCase( + activeSessionHolder = activeSessionHolder.instance, + checkIfCanToggleNotificationsViaPusherUseCase = fakeCheckIfCanToggleNotificationsViaPusherUseCase, + checkIfCanToggleNotificationsViaAccountDataUseCase = fakeCheckIfCanToggleNotificationsViaAccountDataUseCase, + setNotificationSettingsAccountDataUseCase = fakeSetNotificationSettingsAccountDataUseCase, + ) + + @Test + fun `when execute, then toggle enabled for device pushers`() = runTest { + // Given + val sessionId = "a_session_id" + val pushers = listOf( + PusherFixture.aPusher(deviceId = sessionId, enabled = false), + PusherFixture.aPusher(deviceId = "another id", enabled = false) + ) + val fakeSession = activeSessionHolder.fakeSession + fakeSession.pushersService().givenPushersLive(pushers) + fakeSession.pushersService().givenGetPushers(pushers) + every { fakeCheckIfCanToggleNotificationsViaPusherUseCase.execute(fakeSession) } returns true + every { fakeCheckIfCanToggleNotificationsViaAccountDataUseCase.execute(fakeSession, sessionId) } returns false + + // When + toggleNotificationsUseCase.execute(sessionId, true) + + // Then + activeSessionHolder.fakeSession.pushersService().verifyTogglePusherCalled(pushers.first(), true) + } + + @Test + fun `when execute, then toggle local notification settings`() = runTest { + // Given + val sessionId = "a_session_id" + val fakeSession = activeSessionHolder.fakeSession + every { fakeCheckIfCanToggleNotificationsViaPusherUseCase.execute(fakeSession) } returns false + every { fakeCheckIfCanToggleNotificationsViaAccountDataUseCase.execute(fakeSession, sessionId) } returns true + coJustRun { fakeSetNotificationSettingsAccountDataUseCase.execute(any(), any(), any()) } + val expectedLocalNotificationSettingsContent = LocalNotificationSettingsContent( + isSilenced = false + ) + + // When + toggleNotificationsUseCase.execute(sessionId, true) + + // Then + coVerify { + fakeSetNotificationSettingsAccountDataUseCase.execute(fakeSession, sessionId, expectedLocalNotificationSettingsContent) + } + } +} diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/TogglePushNotificationUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/TogglePushNotificationUseCaseTest.kt deleted file mode 100644 index 35c5979e53..0000000000 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/TogglePushNotificationUseCaseTest.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package im.vector.app.features.settings.devices.v2.notification - -import im.vector.app.test.fakes.FakeActiveSessionHolder -import im.vector.app.test.fixtures.PusherFixture -import io.mockk.every -import io.mockk.mockk -import kotlinx.coroutines.test.runTest -import org.junit.Test -import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent -import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes -import org.matrix.android.sdk.api.session.events.model.toContent - -class TogglePushNotificationUseCaseTest { - - private val activeSessionHolder = FakeActiveSessionHolder() - private val fakeCheckIfCanTogglePushNotificationsViaPusherUseCase = - mockk() - private val fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase = - mockk() - - private val togglePushNotificationUseCase = - TogglePushNotificationUseCase( - activeSessionHolder = activeSessionHolder.instance, - checkIfCanTogglePushNotificationsViaPusherUseCase = fakeCheckIfCanTogglePushNotificationsViaPusherUseCase, - checkIfCanTogglePushNotificationsViaAccountDataUseCase = fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase, - ) - - @Test - fun `when execute, then toggle enabled for device pushers`() = runTest { - // Given - val sessionId = "a_session_id" - val pushers = listOf( - PusherFixture.aPusher(deviceId = sessionId, enabled = false), - PusherFixture.aPusher(deviceId = "another id", enabled = false) - ) - val fakeSession = activeSessionHolder.fakeSession - fakeSession.pushersService().givenPushersLive(pushers) - fakeSession.pushersService().givenGetPushers(pushers) - every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns true - every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, sessionId) } returns false - - // When - togglePushNotificationUseCase.execute(sessionId, true) - - // Then - activeSessionHolder.fakeSession.pushersService().verifyTogglePusherCalled(pushers.first(), true) - } - - @Test - fun `when execute, then toggle local notification settings`() = runTest { - // Given - val sessionId = "a_session_id" - val pushers = listOf( - PusherFixture.aPusher(deviceId = sessionId, enabled = false), - PusherFixture.aPusher(deviceId = "another id", enabled = false) - ) - val fakeSession = activeSessionHolder.fakeSession - fakeSession.pushersService().givenPushersLive(pushers) - fakeSession.accountDataService().givenGetUserAccountDataEventReturns( - UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + sessionId, - LocalNotificationSettingsContent(isSilenced = true).toContent() - ) - every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns false - every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, sessionId) } returns true - - // When - togglePushNotificationUseCase.execute(sessionId, true) - - // Then - activeSessionHolder.fakeSession.accountDataService().verifyUpdateUserAccountDataEventSucceeds( - UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + sessionId, - LocalNotificationSettingsContent(isSilenced = false).toContent(), - ) - } -} diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/UpdateNotificationSettingsAccountDataUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/UpdateNotificationSettingsAccountDataUseCaseTest.kt new file mode 100644 index 0000000000..0075be02d2 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/UpdateNotificationSettingsAccountDataUseCaseTest.kt @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.notification + +import im.vector.app.test.fakes.FakeSession +import im.vector.app.test.fakes.FakeUnifiedPushHelper +import im.vector.app.test.fakes.FakeVectorPreferences +import io.mockk.coJustRun +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent + +class UpdateNotificationSettingsAccountDataUseCaseTest { + + private val fakeVectorPreferences = FakeVectorPreferences() + private val fakeUnifiedPushHelper = FakeUnifiedPushHelper() + private val fakeGetNotificationSettingsAccountDataUseCase = mockk() + private val fakeSetNotificationSettingsAccountDataUseCase = mockk() + private val fakeDeleteNotificationSettingsAccountDataUseCase = mockk() + + private val updateNotificationSettingsAccountDataUseCase = UpdateNotificationSettingsAccountDataUseCase( + vectorPreferences = fakeVectorPreferences.instance, + unifiedPushHelper = fakeUnifiedPushHelper.instance, + getNotificationSettingsAccountDataUseCase = fakeGetNotificationSettingsAccountDataUseCase, + setNotificationSettingsAccountDataUseCase = fakeSetNotificationSettingsAccountDataUseCase, + deleteNotificationSettingsAccountDataUseCase = fakeDeleteNotificationSettingsAccountDataUseCase, + ) + + @Test + fun `given back sync enabled, a device id and a different local setting compared to remote when execute then content is updated`() = runTest { + // Given + val aDeviceId = "device-id" + val aSession = FakeSession() + aSession.givenSessionId(aDeviceId) + coJustRun { fakeSetNotificationSettingsAccountDataUseCase.execute(any(), any(), any()) } + val areNotificationsEnabled = true + fakeVectorPreferences.givenAreNotificationsEnabledForDevice(areNotificationsEnabled) + fakeUnifiedPushHelper.givenIsBackgroundSyncReturns(true) + every { fakeGetNotificationSettingsAccountDataUseCase.execute(any(), any()) } returns + LocalNotificationSettingsContent( + isSilenced = null + ) + val expectedContent = LocalNotificationSettingsContent( + isSilenced = !areNotificationsEnabled + ) + + // When + updateNotificationSettingsAccountDataUseCase.execute(aSession) + + // Then + verify { + fakeUnifiedPushHelper.instance.isBackgroundSync() + fakeVectorPreferences.instance.areNotificationEnabledForDevice() + fakeGetNotificationSettingsAccountDataUseCase.execute(aSession, aDeviceId) + } + coVerify(inverse = true) { fakeDeleteNotificationSettingsAccountDataUseCase.execute(aSession) } + coVerify { fakeSetNotificationSettingsAccountDataUseCase.execute(aSession, aDeviceId, expectedContent) } + } + + @Test + fun `given back sync enabled, a device id and a same local setting compared to remote when execute then content is not updated`() = runTest { + // Given + val aDeviceId = "device-id" + val aSession = FakeSession() + aSession.givenSessionId(aDeviceId) + coJustRun { fakeSetNotificationSettingsAccountDataUseCase.execute(any(), any(), any()) } + val areNotificationsEnabled = true + fakeVectorPreferences.givenAreNotificationsEnabledForDevice(areNotificationsEnabled) + fakeUnifiedPushHelper.givenIsBackgroundSyncReturns(true) + every { fakeGetNotificationSettingsAccountDataUseCase.execute(any(), any()) } returns + LocalNotificationSettingsContent( + isSilenced = false + ) + val expectedContent = LocalNotificationSettingsContent( + isSilenced = !areNotificationsEnabled + ) + + // When + updateNotificationSettingsAccountDataUseCase.execute(aSession) + + // Then + verify { + fakeUnifiedPushHelper.instance.isBackgroundSync() + fakeVectorPreferences.instance.areNotificationEnabledForDevice() + fakeGetNotificationSettingsAccountDataUseCase.execute(aSession, aDeviceId) + } + coVerify(inverse = true) { fakeDeleteNotificationSettingsAccountDataUseCase.execute(aSession) } + coVerify(inverse = true) { fakeSetNotificationSettingsAccountDataUseCase.execute(aSession, aDeviceId, expectedContent) } + } + + @Test + fun `given back sync disabled and a device id when execute then content is deleted`() = runTest { + // Given + val aDeviceId = "device-id" + val aSession = FakeSession() + aSession.givenSessionId(aDeviceId) + coJustRun { fakeDeleteNotificationSettingsAccountDataUseCase.execute(any()) } + fakeUnifiedPushHelper.givenIsBackgroundSyncReturns(false) + + // When + updateNotificationSettingsAccountDataUseCase.execute(aSession) + + // Then + verify { + fakeUnifiedPushHelper.instance.isBackgroundSync() + } + coVerify { fakeDeleteNotificationSettingsAccountDataUseCase.execute(aSession) } + coVerify(inverse = true) { fakeSetNotificationSettingsAccountDataUseCase.execute(aSession, aDeviceId, any()) } + } +} diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt index 287bdd159c..b0f7a774f2 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt @@ -24,13 +24,12 @@ import im.vector.app.features.settings.devices.v2.DeviceFullInfo import im.vector.app.features.settings.devices.v2.RefreshDevicesUseCase import im.vector.app.features.settings.devices.v2.ToggleIpAddressVisibilityUseCase import im.vector.app.features.settings.devices.v2.notification.NotificationsStatus -import im.vector.app.features.settings.devices.v2.signout.InterceptSignoutFlowResponseUseCase import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeGetNotificationsStatusUseCase import im.vector.app.test.fakes.FakePendingAuthHandler import im.vector.app.test.fakes.FakeSignoutSessionsUseCase -import im.vector.app.test.fakes.FakeTogglePushNotificationUseCase +import im.vector.app.test.fakes.FakeToggleNotificationUseCase import im.vector.app.test.fakes.FakeVectorPreferences import im.vector.app.test.fakes.FakeVerificationService import im.vector.app.test.test @@ -73,10 +72,9 @@ class SessionOverviewViewModelTest { private val fakeActiveSessionHolder = FakeActiveSessionHolder() private val checkIfCurrentSessionCanBeVerifiedUseCase = mockk() private val fakeSignoutSessionsUseCase = FakeSignoutSessionsUseCase() - private val interceptSignoutFlowResponseUseCase = mockk() private val fakePendingAuthHandler = FakePendingAuthHandler() private val refreshDevicesUseCase = mockk(relaxed = true) - private val togglePushNotificationUseCase = FakeTogglePushNotificationUseCase() + private val toggleNotificationUseCase = FakeToggleNotificationUseCase() private val fakeGetNotificationsStatusUseCase = FakeGetNotificationsStatusUseCase() private val notificationsStatus = NotificationsStatus.ENABLED private val fakeVectorPreferences = FakeVectorPreferences() @@ -87,11 +85,10 @@ class SessionOverviewViewModelTest { getDeviceFullInfoUseCase = getDeviceFullInfoUseCase, checkIfCurrentSessionCanBeVerifiedUseCase = checkIfCurrentSessionCanBeVerifiedUseCase, signoutSessionsUseCase = fakeSignoutSessionsUseCase.instance, - interceptSignoutFlowResponseUseCase = interceptSignoutFlowResponseUseCase, pendingAuthHandler = fakePendingAuthHandler.instance, activeSessionHolder = fakeActiveSessionHolder.instance, refreshDevicesUseCase = refreshDevicesUseCase, - togglePushNotificationUseCase = togglePushNotificationUseCase.instance, + toggleNotificationsUseCase = toggleNotificationUseCase.instance, getNotificationsStatusUseCase = fakeGetNotificationsStatusUseCase.instance, vectorPreferences = fakeVectorPreferences.instance, toggleIpAddressVisibilityUseCase = toggleIpAddressVisibilityUseCase, @@ -436,7 +433,7 @@ class SessionOverviewViewModelTest { viewModel.handle(SessionOverviewAction.TogglePushNotifications(A_SESSION_ID_1, true)) - togglePushNotificationUseCase.verifyExecute(A_SESSION_ID_1, true) + toggleNotificationUseCase.verifyExecute(A_SESSION_ID_1, true) viewModel.test().assertLatestState { state -> state.notificationsStatus == NotificationsStatus.ENABLED }.finish() } } diff --git a/vector/src/test/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCaseTest.kt index 386e68ee3a..669b20fc1a 100644 --- a/vector/src/test/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCaseTest.kt @@ -17,56 +17,29 @@ package im.vector.app.features.settings.notifications import im.vector.app.core.pushers.UnregisterUnifiedPushUseCase -import im.vector.app.features.settings.devices.v2.notification.CheckIfCanTogglePushNotificationsViaPusherUseCase -import im.vector.app.features.settings.devices.v2.notification.TogglePushNotificationUseCase -import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakePushersManager import io.mockk.coJustRun import io.mockk.coVerify -import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.test.runTest import org.junit.Test -private const val A_SESSION_ID = "session-id" - class DisableNotificationsForCurrentSessionUseCaseTest { - private val fakeActiveSessionHolder = FakeActiveSessionHolder() private val fakePushersManager = FakePushersManager() - private val fakeCheckIfCanTogglePushNotificationsViaPusherUseCase = mockk() - private val fakeTogglePushNotificationUseCase = mockk() + private val fakeToggleNotificationsForCurrentSessionUseCase = mockk() private val fakeUnregisterUnifiedPushUseCase = mockk() private val disableNotificationsForCurrentSessionUseCase = DisableNotificationsForCurrentSessionUseCase( - activeSessionHolder = fakeActiveSessionHolder.instance, pushersManager = fakePushersManager.instance, - checkIfCanTogglePushNotificationsViaPusherUseCase = fakeCheckIfCanTogglePushNotificationsViaPusherUseCase, - togglePushNotificationUseCase = fakeTogglePushNotificationUseCase, + toggleNotificationsForCurrentSessionUseCase = fakeToggleNotificationsForCurrentSessionUseCase, unregisterUnifiedPushUseCase = fakeUnregisterUnifiedPushUseCase, ) @Test - fun `given toggle via pusher is possible when execute then disable notification via toggle of existing pusher`() = runTest { + fun `when execute then disable notifications and unregister the pusher`() = runTest { // Given - val fakeSession = fakeActiveSessionHolder.fakeSession - fakeSession.givenSessionId(A_SESSION_ID) - every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns true - coJustRun { fakeTogglePushNotificationUseCase.execute(A_SESSION_ID, any()) } - - // When - disableNotificationsForCurrentSessionUseCase.execute() - - // Then - coVerify { fakeTogglePushNotificationUseCase.execute(A_SESSION_ID, false) } - } - - @Test - fun `given toggle via pusher is NOT possible when execute then disable notification by unregistering the pusher`() = runTest { - // Given - val fakeSession = fakeActiveSessionHolder.fakeSession - fakeSession.givenSessionId(A_SESSION_ID) - every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns false + coJustRun { fakeToggleNotificationsForCurrentSessionUseCase.execute(any()) } coJustRun { fakeUnregisterUnifiedPushUseCase.execute(any()) } // When @@ -74,6 +47,7 @@ class DisableNotificationsForCurrentSessionUseCaseTest { // Then coVerify { + fakeToggleNotificationsForCurrentSessionUseCase.execute(false) fakeUnregisterUnifiedPushUseCase.execute(fakePushersManager.instance) } } diff --git a/vector/src/test/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCaseTest.kt index c923f0c7d6..d58ba7645c 100644 --- a/vector/src/test/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCaseTest.kt @@ -18,10 +18,9 @@ package im.vector.app.features.settings.notifications import im.vector.app.core.pushers.EnsureFcmTokenIsRetrievedUseCase import im.vector.app.core.pushers.RegisterUnifiedPushUseCase -import im.vector.app.features.settings.devices.v2.notification.TogglePushNotificationUseCase -import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakePushersManager import io.mockk.coJustRun +import io.mockk.coVerify import io.mockk.every import io.mockk.justRun import io.mockk.mockk @@ -30,20 +29,16 @@ import kotlinx.coroutines.test.runTest import org.amshove.kluent.shouldBe import org.junit.Test -private const val A_SESSION_ID = "session-id" - class EnableNotificationsForCurrentSessionUseCaseTest { - private val fakeActiveSessionHolder = FakeActiveSessionHolder() private val fakePushersManager = FakePushersManager() - private val fakeTogglePushNotificationUseCase = mockk() + private val fakeToggleNotificationsForCurrentSessionUseCase = mockk() private val fakeRegisterUnifiedPushUseCase = mockk() private val fakeEnsureFcmTokenIsRetrievedUseCase = mockk() private val enableNotificationsForCurrentSessionUseCase = EnableNotificationsForCurrentSessionUseCase( - activeSessionHolder = fakeActiveSessionHolder.instance, pushersManager = fakePushersManager.instance, - togglePushNotificationUseCase = fakeTogglePushNotificationUseCase, + toggleNotificationsForCurrentSessionUseCase = fakeToggleNotificationsForCurrentSessionUseCase, registerUnifiedPushUseCase = fakeRegisterUnifiedPushUseCase, ensureFcmTokenIsRetrievedUseCase = fakeEnsureFcmTokenIsRetrievedUseCase, ) @@ -52,12 +47,10 @@ class EnableNotificationsForCurrentSessionUseCaseTest { fun `given no existing pusher and a registered distributor when execute then a new pusher is registered and result is success`() = runTest { // Given val aDistributor = "distributor" - val fakeSession = fakeActiveSessionHolder.fakeSession - fakeSession.givenSessionId(A_SESSION_ID) fakePushersManager.givenGetPusherForCurrentSessionReturns(null) every { fakeRegisterUnifiedPushUseCase.execute(any()) } returns RegisterUnifiedPushUseCase.RegisterUnifiedPushResult.Success justRun { fakeEnsureFcmTokenIsRetrievedUseCase.execute(any(), any()) } - coJustRun { fakeTogglePushNotificationUseCase.execute(A_SESSION_ID, any()) } + coJustRun { fakeToggleNotificationsForCurrentSessionUseCase.execute(any()) } // When val result = enableNotificationsForCurrentSessionUseCase.execute(aDistributor) @@ -68,6 +61,9 @@ class EnableNotificationsForCurrentSessionUseCaseTest { fakeRegisterUnifiedPushUseCase.execute(aDistributor) fakeEnsureFcmTokenIsRetrievedUseCase.execute(fakePushersManager.instance, registerPusher = true) } + coVerify { + fakeToggleNotificationsForCurrentSessionUseCase.execute(enabled = true) + } } @Test @@ -86,20 +82,4 @@ class EnableNotificationsForCurrentSessionUseCaseTest { fakeRegisterUnifiedPushUseCase.execute(aDistributor) } } - - @Test - fun `given no deviceId for current session when execute then result is failure`() = runTest { - // Given - val aDistributor = "distributor" - val fakeSession = fakeActiveSessionHolder.fakeSession - fakeSession.givenSessionId(null) - fakePushersManager.givenGetPusherForCurrentSessionReturns(mockk()) - every { fakeRegisterUnifiedPushUseCase.execute(any()) } returns RegisterUnifiedPushUseCase.RegisterUnifiedPushResult.NeedToAskUserForDistributor - - // When - val result = enableNotificationsForCurrentSessionUseCase.execute(aDistributor) - - // Then - result shouldBe EnableNotificationsForCurrentSessionUseCase.EnableNotificationsResult.Failure - } } diff --git a/vector/src/test/java/im/vector/app/features/settings/notifications/ToggleNotificationsForCurrentSessionUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/notifications/ToggleNotificationsForCurrentSessionUseCaseTest.kt new file mode 100644 index 0000000000..f49aafab8a --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/notifications/ToggleNotificationsForCurrentSessionUseCaseTest.kt @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.notifications + +import im.vector.app.features.settings.devices.v2.notification.CheckIfCanToggleNotificationsViaPusherUseCase +import im.vector.app.features.settings.devices.v2.notification.DeleteNotificationSettingsAccountDataUseCase +import im.vector.app.features.settings.devices.v2.notification.SetNotificationSettingsAccountDataUseCase +import im.vector.app.test.fakes.FakeActiveSessionHolder +import im.vector.app.test.fakes.FakeUnifiedPushHelper +import im.vector.app.test.fixtures.PusherFixture +import io.mockk.coJustRun +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent + +class ToggleNotificationsForCurrentSessionUseCaseTest { + + private val fakeActiveSessionHolder = FakeActiveSessionHolder() + private val fakeUnifiedPushHelper = FakeUnifiedPushHelper() + private val fakeCheckIfCanToggleNotificationsViaPusherUseCase = mockk() + private val fakeSetNotificationSettingsAccountDataUseCase = mockk() + private val fakeDeleteNotificationSettingsAccountDataUseCase = mockk() + + private val toggleNotificationsForCurrentSessionUseCase = ToggleNotificationsForCurrentSessionUseCase( + activeSessionHolder = fakeActiveSessionHolder.instance, + unifiedPushHelper = fakeUnifiedPushHelper.instance, + checkIfCanToggleNotificationsViaPusherUseCase = fakeCheckIfCanToggleNotificationsViaPusherUseCase, + setNotificationSettingsAccountDataUseCase = fakeSetNotificationSettingsAccountDataUseCase, + deleteNotificationSettingsAccountDataUseCase = fakeDeleteNotificationSettingsAccountDataUseCase, + ) + + @Test + fun `given background sync is enabled when execute then set the related account data with correct value`() = runTest { + // Given + val enabled = true + val aDeviceId = "deviceId" + fakeUnifiedPushHelper.givenIsBackgroundSyncReturns(true) + fakeActiveSessionHolder.fakeSession.givenSessionId(aDeviceId) + coJustRun { fakeSetNotificationSettingsAccountDataUseCase.execute(any(), any(), any()) } + val expectedNotificationContent = LocalNotificationSettingsContent(isSilenced = !enabled) + + // When + toggleNotificationsForCurrentSessionUseCase.execute(enabled) + + // Then + coVerify { + fakeSetNotificationSettingsAccountDataUseCase.execute( + fakeActiveSessionHolder.fakeSession, + aDeviceId, + expectedNotificationContent + ) + } + } + + @Test + fun `given background sync is not enabled and toggle pusher is possible when execute then delete any related account data and toggle pusher`() = runTest { + // Given + val enabled = true + val aDeviceId = "deviceId" + fakeUnifiedPushHelper.givenIsBackgroundSyncReturns(false) + fakeActiveSessionHolder.fakeSession.givenSessionId(aDeviceId) + coJustRun { fakeDeleteNotificationSettingsAccountDataUseCase.execute(any()) } + every { fakeCheckIfCanToggleNotificationsViaPusherUseCase.execute(any()) } returns true + val aPusher = PusherFixture.aPusher(deviceId = aDeviceId) + fakeActiveSessionHolder.fakeSession.fakePushersService.givenGetPushers(listOf(aPusher)) + + // When + toggleNotificationsForCurrentSessionUseCase.execute(enabled) + + // Then + coVerify { + fakeDeleteNotificationSettingsAccountDataUseCase.execute(fakeActiveSessionHolder.fakeSession) + fakeCheckIfCanToggleNotificationsViaPusherUseCase.execute(fakeActiveSessionHolder.fakeSession) + } + fakeActiveSessionHolder.fakeSession.fakePushersService.verifyTogglePusherCalled(aPusher, enabled) + } + + @Test + fun `given background sync is not enabled and toggle pusher is not possible when execute then only delete any related account data`() = runTest { + // Given + val enabled = true + val aDeviceId = "deviceId" + fakeUnifiedPushHelper.givenIsBackgroundSyncReturns(false) + fakeActiveSessionHolder.fakeSession.givenSessionId(aDeviceId) + coJustRun { fakeDeleteNotificationSettingsAccountDataUseCase.execute(any()) } + every { fakeCheckIfCanToggleNotificationsViaPusherUseCase.execute(any()) } returns false + + // When + toggleNotificationsForCurrentSessionUseCase.execute(enabled) + + // Then + coVerify { + fakeDeleteNotificationSettingsAccountDataUseCase.execute(fakeActiveSessionHolder.fakeSession) + fakeCheckIfCanToggleNotificationsViaPusherUseCase.execute(fakeActiveSessionHolder.fakeSession) + } + coVerify(inverse = true) { + fakeActiveSessionHolder.fakeSession.fakePushersService.togglePusher(any(), any()) + } + } +} diff --git a/vector/src/test/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewModelTest.kt index f9d7527316..270447c461 100644 --- a/vector/src/test/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewModelTest.kt @@ -46,6 +46,7 @@ class VectorSettingsNotificationPreferenceViewModelTest { private val fakeUnregisterUnifiedPushUseCase = mockk() private val fakeRegisterUnifiedPushUseCase = mockk() private val fakeEnsureFcmTokenIsRetrievedUseCase = mockk() + private val fakeToggleNotificationsForCurrentSessionUseCase = mockk() private fun createViewModel() = VectorSettingsNotificationPreferenceViewModel( initialState = VectorDummyViewState(), @@ -56,6 +57,7 @@ class VectorSettingsNotificationPreferenceViewModelTest { unregisterUnifiedPushUseCase = fakeUnregisterUnifiedPushUseCase, registerUnifiedPushUseCase = fakeRegisterUnifiedPushUseCase, ensureFcmTokenIsRetrievedUseCase = fakeEnsureFcmTokenIsRetrievedUseCase, + toggleNotificationsForCurrentSessionUseCase = fakeToggleNotificationsForCurrentSessionUseCase, ) @Test @@ -125,29 +127,6 @@ class VectorSettingsNotificationPreferenceViewModelTest { } } - @Test - fun `given EnableNotificationsForDevice action and enable failure when handling action then enable use case is called`() { - // Given - val viewModel = createViewModel() - val aDistributor = "aDistributor" - val action = VectorSettingsNotificationPreferenceViewAction.EnableNotificationsForDevice(aDistributor) - coEvery { fakeEnableNotificationsForCurrentSessionUseCase.execute(any()) } returns - EnableNotificationsForCurrentSessionUseCase.EnableNotificationsResult.Failure - val expectedEvent = VectorSettingsNotificationPreferenceViewEvent.EnableNotificationForDeviceFailure - - // When - val viewModelTest = viewModel.test() - viewModel.handle(action) - - // Then - viewModelTest - .assertEvent { event -> event == expectedEvent } - .finish() - coVerify { - fakeEnableNotificationsForCurrentSessionUseCase.execute(aDistributor) - } - } - @Test fun `given RegisterPushDistributor action and register success when handling action then register use case is called`() { // Given @@ -158,6 +137,7 @@ class VectorSettingsNotificationPreferenceViewModelTest { coJustRun { fakeUnregisterUnifiedPushUseCase.execute(any()) } val areNotificationsEnabled = true fakeVectorPreferences.givenAreNotificationsEnabledForDevice(areNotificationsEnabled) + coJustRun { fakeToggleNotificationsForCurrentSessionUseCase.execute(any()) } justRun { fakeEnsureFcmTokenIsRetrievedUseCase.execute(any(), any()) } val expectedEvent = VectorSettingsNotificationPreferenceViewEvent.NotificationMethodChanged @@ -173,6 +153,7 @@ class VectorSettingsNotificationPreferenceViewModelTest { fakeUnregisterUnifiedPushUseCase.execute(fakePushersManager.instance) fakeRegisterUnifiedPushUseCase.execute(aDistributor) fakeEnsureFcmTokenIsRetrievedUseCase.execute(fakePushersManager.instance, registerPusher = areNotificationsEnabled) + fakeToggleNotificationsForCurrentSessionUseCase.execute(enabled = areNotificationsEnabled) } } diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeEnableNotificationsSettingUpdater.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeNotificationsSettingUpdater.kt similarity index 77% rename from vector/src/test/java/im/vector/app/test/fakes/FakeEnableNotificationsSettingUpdater.kt rename to vector/src/test/java/im/vector/app/test/fakes/FakeNotificationsSettingUpdater.kt index a78dd1a34b..2e397763f8 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeEnableNotificationsSettingUpdater.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeNotificationsSettingUpdater.kt @@ -16,16 +16,16 @@ package im.vector.app.test.fakes -import im.vector.app.core.notification.EnableNotificationsSettingUpdater +import im.vector.app.core.notification.NotificationsSettingUpdater import io.mockk.justRun import io.mockk.mockk import org.matrix.android.sdk.api.session.Session -class FakeEnableNotificationsSettingUpdater { +class FakeNotificationsSettingUpdater { - val instance = mockk() + val instance = mockk() fun givenOnSessionsStarted(session: Session) { - justRun { instance.onSessionsStarted(session) } + justRun { instance.onSessionStarted(session) } } } diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeTogglePushNotificationUseCase.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeToggleNotificationUseCase.kt similarity index 88% rename from vector/src/test/java/im/vector/app/test/fakes/FakeTogglePushNotificationUseCase.kt rename to vector/src/test/java/im/vector/app/test/fakes/FakeToggleNotificationUseCase.kt index bfbbb87705..3d2179bc2d 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeTogglePushNotificationUseCase.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeToggleNotificationUseCase.kt @@ -16,14 +16,14 @@ package im.vector.app.test.fakes -import im.vector.app.features.settings.devices.v2.notification.TogglePushNotificationUseCase +import im.vector.app.features.settings.devices.v2.notification.ToggleNotificationsUseCase import io.mockk.coJustRun import io.mockk.coVerify import io.mockk.mockk -class FakeTogglePushNotificationUseCase { +class FakeToggleNotificationUseCase { - val instance = mockk { + val instance = mockk { coJustRun { execute(any(), any()) } } diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeUnifiedPushHelper.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeUnifiedPushHelper.kt index 99b5b75874..1a09783fad 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeUnifiedPushHelper.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeUnifiedPushHelper.kt @@ -31,4 +31,8 @@ class FakeUnifiedPushHelper { fun givenGetEndpointOrTokenReturns(endpoint: String?) { every { instance.getEndpointOrToken() } returns endpoint } + + fun givenIsBackgroundSyncReturns(enabled: Boolean) { + every { instance.isBackgroundSync() } returns enabled + } } diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeVectorPreferences.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeVectorPreferences.kt index 06efca1bf7..3d7de662bd 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeVectorPreferences.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeVectorPreferences.kt @@ -16,6 +16,7 @@ package im.vector.app.test.fakes +import android.content.SharedPreferences.OnSharedPreferenceChangeListener import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.VectorPreferences import io.mockk.every @@ -73,4 +74,14 @@ class FakeVectorPreferences { fun givenAreNotificationsEnabledForDevice(notificationsEnabled: Boolean) { every { instance.areNotificationEnabledForDevice() } returns notificationsEnabled } + + fun givenIsBackgroundSyncEnabled(isEnabled: Boolean) { + every { instance.isBackgroundSyncEnabled() } returns isEnabled + } + + fun givenChangeOnPreference(key: String) { + every { instance.subscribeToChanges(any()) } answers { + firstArg().onSharedPreferenceChanged(mockk(), key) + } + } }