Merge pull request #7630 from vector-im/feature/mna/remote-notification-toggle-account-data

Save m.local_notification_settings.<device-id> event in account_data (PSG-873)
This commit is contained in:
Maxime NATUREL 2022-12-05 16:58:51 +01:00 committed by GitHub
commit a12c640984
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 1087 additions and 369 deletions

1
changelog.d/7596.feature Normal file
View File

@ -0,0 +1 @@
Save m.local_notification_settings.<device-id> event in account_data

View File

@ -21,5 +21,6 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class LocalNotificationSettingsContent( data class LocalNotificationSettingsContent(
@Json(name = "is_silenced") val isSilenced: Boolean = false @Json(name = "is_silenced")
val isSilenced: Boolean?
) )

View File

@ -23,14 +23,21 @@ import org.matrix.android.sdk.api.session.Session
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
/**
* Listen changes in Pusher or Account Data to update the local setting for notification toggle.
*/
@Singleton @Singleton
class EnableNotificationsSettingUpdater @Inject constructor( class NotificationsSettingUpdater @Inject constructor(
private val updateEnableNotificationsSettingOnChangeUseCase: UpdateEnableNotificationsSettingOnChangeUseCase, private val updateEnableNotificationsSettingOnChangeUseCase: UpdateEnableNotificationsSettingOnChangeUseCase,
) { ) {
private var job: Job? = null private var job: Job? = null
fun onSessionsStarted(session: Session) { fun onSessionStarted(session: Session) {
updateEnableNotificationsSettingOnChange(session)
}
private fun updateEnableNotificationsSettingOnChange(session: Session) {
job?.cancel() job?.cancel()
job = session.coroutineScope.launch { job = session.coroutineScope.launch {
updateEnableNotificationsSettingOnChangeUseCase.execute(session) updateEnableNotificationsSettingOnChangeUseCase.execute(session)

View File

@ -19,11 +19,12 @@ package im.vector.app.core.session
import android.content.Context import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import im.vector.app.core.extensions.startSyncing 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.core.session.clientinfo.UpdateMatrixClientInfoUseCase
import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.call.webrtc.WebRtcCallManager
import im.vector.app.features.session.coroutineScope import im.vector.app.features.session.coroutineScope
import im.vector.app.features.settings.VectorPreferences 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 im.vector.app.features.sync.SyncUtils
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
@ -35,7 +36,8 @@ class ConfigureAndStartSessionUseCase @Inject constructor(
private val webRtcCallManager: WebRtcCallManager, private val webRtcCallManager: WebRtcCallManager,
private val updateMatrixClientInfoUseCase: UpdateMatrixClientInfoUseCase, private val updateMatrixClientInfoUseCase: UpdateMatrixClientInfoUseCase,
private val vectorPreferences: VectorPreferences, private val vectorPreferences: VectorPreferences,
private val enableNotificationsSettingUpdater: EnableNotificationsSettingUpdater, private val notificationsSettingUpdater: NotificationsSettingUpdater,
private val updateNotificationSettingsAccountDataUseCase: UpdateNotificationSettingsAccountDataUseCase,
) { ) {
fun execute(session: Session, startSyncing: Boolean = true) { fun execute(session: Session, startSyncing: Boolean = true) {
@ -49,11 +51,22 @@ class ConfigureAndStartSessionUseCase @Inject constructor(
} }
session.pushersService().refreshPushers() session.pushersService().refreshPushers()
webRtcCallManager.checkForProtocolsSupportIfNeeded() webRtcCallManager.checkForProtocolsSupportIfNeeded()
updateMatrixClientInfoIfNeeded(session)
createNotificationSettingsAccountDataIfNeeded(session)
notificationsSettingUpdater.onSessionStarted(session)
}
private fun updateMatrixClientInfoIfNeeded(session: Session) {
session.coroutineScope.launch { session.coroutineScope.launch {
if (vectorPreferences.isClientInfoRecordingEnabled()) { if (vectorPreferences.isClientInfoRecordingEnabled()) {
updateMatrixClientInfoUseCase.execute(session) updateMatrixClientInfoUseCase.execute(session)
} }
} }
enableNotificationsSettingUpdater.onSessionsStarted(session) }
private fun createNotificationSettingsAccountDataIfNeeded(session: Session) {
session.coroutineScope.launch {
updateNotificationSettingsAccountDataUseCase.execute(session)
}
} }
} }

View File

@ -29,6 +29,7 @@ import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.pushers.EnsureFcmTokenIsRetrievedUseCase import im.vector.app.core.pushers.EnsureFcmTokenIsRetrievedUseCase
import im.vector.app.core.pushers.PushersManager import im.vector.app.core.pushers.PushersManager
import im.vector.app.core.pushers.RegisterUnifiedPushUseCase 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.AnalyticsConfig
import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.analytics.AnalyticsTracker
import im.vector.app.features.analytics.extensions.toAnalyticsType import im.vector.app.features.analytics.extensions.toAnalyticsType
@ -92,6 +93,7 @@ class HomeActivityViewModel @AssistedInject constructor(
private val stopOngoingVoiceBroadcastUseCase: StopOngoingVoiceBroadcastUseCase, private val stopOngoingVoiceBroadcastUseCase: StopOngoingVoiceBroadcastUseCase,
private val pushersManager: PushersManager, private val pushersManager: PushersManager,
private val registerUnifiedPushUseCase: RegisterUnifiedPushUseCase, private val registerUnifiedPushUseCase: RegisterUnifiedPushUseCase,
private val unregisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase,
private val ensureFcmTokenIsRetrievedUseCase: EnsureFcmTokenIsRetrievedUseCase, private val ensureFcmTokenIsRetrievedUseCase: EnsureFcmTokenIsRetrievedUseCase,
) : VectorViewModel<HomeActivityViewState, HomeActivityViewActions, HomeActivityViewEvents>(initialState) { ) : VectorViewModel<HomeActivityViewState, HomeActivityViewActions, HomeActivityViewEvents>(initialState) {
@ -130,6 +132,8 @@ class HomeActivityViewModel @AssistedInject constructor(
private fun registerUnifiedPushIfNeeded() { private fun registerUnifiedPushIfNeeded() {
if (vectorPreferences.areNotificationEnabledForDevice()) { if (vectorPreferences.areNotificationEnabledForDevice()) {
registerUnifiedPush(distributor = "") 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 -> private fun observeReleaseNotes() = withState { state ->
if (vectorPreferences.isNewAppLayoutEnabled()) { if (vectorPreferences.isNewAppLayoutEnabled()) {
// we don't want to show release notes for new users or after relogin // we don't want to show release notes for new users or after relogin

View File

@ -28,7 +28,6 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.features.auth.PendingAuthHandler import im.vector.app.features.auth.PendingAuthHandler
import im.vector.app.features.settings.VectorPreferences 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.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.SignoutSessionsReAuthNeeded
import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsUseCase import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsUseCase
import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase
@ -48,7 +47,6 @@ class DevicesViewModel @AssistedInject constructor(
private val refreshDevicesOnCryptoDevicesChangeUseCase: RefreshDevicesOnCryptoDevicesChangeUseCase, private val refreshDevicesOnCryptoDevicesChangeUseCase: RefreshDevicesOnCryptoDevicesChangeUseCase,
private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase, private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase,
private val signoutSessionsUseCase: SignoutSessionsUseCase, private val signoutSessionsUseCase: SignoutSessionsUseCase,
private val interceptSignoutFlowResponseUseCase: InterceptSignoutFlowResponseUseCase,
private val pendingAuthHandler: PendingAuthHandler, private val pendingAuthHandler: PendingAuthHandler,
refreshDevicesUseCase: RefreshDevicesUseCase, refreshDevicesUseCase: RefreshDevicesUseCase,
private val vectorPreferences: VectorPreferences, private val vectorPreferences: VectorPreferences,

View File

@ -24,7 +24,7 @@ import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.flow.unwrap import org.matrix.android.sdk.flow.unwrap
import javax.inject.Inject import javax.inject.Inject
class CanTogglePushNotificationsViaPusherUseCase @Inject constructor() { class CanToggleNotificationsViaPusherUseCase @Inject constructor() {
fun execute(session: Session): Flow<Boolean> { fun execute(session: Session): Flow<Boolean> {
return session return session

View File

@ -17,14 +17,13 @@
package im.vector.app.features.settings.devices.v2.notification package im.vector.app.features.settings.devices.v2.notification
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes
import javax.inject.Inject import javax.inject.Inject
class CheckIfCanTogglePushNotificationsViaAccountDataUseCase @Inject constructor() { class CheckIfCanToggleNotificationsViaAccountDataUseCase @Inject constructor(
private val getNotificationSettingsAccountDataUseCase: GetNotificationSettingsAccountDataUseCase,
) {
fun execute(session: Session, deviceId: String): Boolean { fun execute(session: Session, deviceId: String): Boolean {
return session return getNotificationSettingsAccountDataUseCase.execute(session, deviceId)?.isSilenced != null
.accountDataService()
.getUserAccountDataEvent(UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId) != null
} }
} }

View File

@ -19,7 +19,7 @@ package im.vector.app.features.settings.devices.v2.notification
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import javax.inject.Inject import javax.inject.Inject
class CheckIfCanTogglePushNotificationsViaPusherUseCase @Inject constructor() { class CheckIfCanToggleNotificationsViaPusherUseCase @Inject constructor() {
fun execute(session: Session): Boolean { fun execute(session: Session): Boolean {
return session return session

View File

@ -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)
}
}
}

View File

@ -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<LocalNotificationSettingsContent>()
}
}

View File

@ -30,13 +30,13 @@ import org.matrix.android.sdk.flow.unwrap
import javax.inject.Inject import javax.inject.Inject
class GetNotificationsStatusUseCase @Inject constructor( class GetNotificationsStatusUseCase @Inject constructor(
private val canTogglePushNotificationsViaPusherUseCase: CanTogglePushNotificationsViaPusherUseCase, private val canToggleNotificationsViaPusherUseCase: CanToggleNotificationsViaPusherUseCase,
private val checkIfCanTogglePushNotificationsViaAccountDataUseCase: CheckIfCanTogglePushNotificationsViaAccountDataUseCase, private val checkIfCanToggleNotificationsViaAccountDataUseCase: CheckIfCanToggleNotificationsViaAccountDataUseCase,
) { ) {
fun execute(session: Session, deviceId: String): Flow<NotificationsStatus> { fun execute(session: Session, deviceId: String): Flow<NotificationsStatus> {
return when { return when {
checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(session, deviceId) -> { checkIfCanToggleNotificationsViaAccountDataUseCase.execute(session, deviceId) -> {
session.flow() session.flow()
.liveUserAccountData(UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId) .liveUserAccountData(UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId)
.unwrap() .unwrap()
@ -44,14 +44,20 @@ class GetNotificationsStatusUseCase @Inject constructor(
.map { if (it == true) NotificationsStatus.ENABLED else NotificationsStatus.DISABLED } .map { if (it == true) NotificationsStatus.ENABLED else NotificationsStatus.DISABLED }
.distinctUntilChanged() .distinctUntilChanged()
} }
else -> canTogglePushNotificationsViaPusherUseCase.execute(session) else -> canToggleNotificationsViaPusherUseCase.execute(session)
.flatMapLatest { canToggle -> .flatMapLatest { canToggle ->
if (canToggle) { if (canToggle) {
session.flow() session.flow()
.livePushers() .livePushers()
.map { it.filter { pusher -> pusher.deviceId == deviceId } } .map { it.filter { pusher -> pusher.deviceId == deviceId } }
.map { it.takeIf { it.isNotEmpty() }?.any { pusher -> pusher.enabled } } .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() .distinctUntilChanged()
} else { } else {
flowOf(NotificationsStatus.NOT_SUPPORTED) flowOf(NotificationsStatus.NOT_SUPPORTED)

View File

@ -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(),
)
}
}

View File

@ -18,32 +18,28 @@ package im.vector.app.features.settings.devices.v2.notification
import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ActiveSessionHolder
import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent 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 import javax.inject.Inject
class TogglePushNotificationUseCase @Inject constructor( class ToggleNotificationsUseCase @Inject constructor(
private val activeSessionHolder: ActiveSessionHolder, private val activeSessionHolder: ActiveSessionHolder,
private val checkIfCanTogglePushNotificationsViaPusherUseCase: CheckIfCanTogglePushNotificationsViaPusherUseCase, private val checkIfCanToggleNotificationsViaPusherUseCase: CheckIfCanToggleNotificationsViaPusherUseCase,
private val checkIfCanTogglePushNotificationsViaAccountDataUseCase: CheckIfCanTogglePushNotificationsViaAccountDataUseCase, private val checkIfCanToggleNotificationsViaAccountDataUseCase: CheckIfCanToggleNotificationsViaAccountDataUseCase,
private val setNotificationSettingsAccountDataUseCase: SetNotificationSettingsAccountDataUseCase,
) { ) {
suspend fun execute(deviceId: String, enabled: Boolean) { suspend fun execute(deviceId: String, enabled: Boolean) {
val session = activeSessionHolder.getSafeActiveSession() ?: return val session = activeSessionHolder.getSafeActiveSession() ?: return
if (checkIfCanTogglePushNotificationsViaPusherUseCase.execute(session)) { if (checkIfCanToggleNotificationsViaPusherUseCase.execute(session)) {
val devicePusher = session.pushersService().getPushers().firstOrNull { it.deviceId == deviceId } val devicePusher = session.pushersService().getPushers().firstOrNull { it.deviceId == deviceId }
devicePusher?.let { pusher -> devicePusher?.let { pusher ->
session.pushersService().togglePusher(pusher, enabled) session.pushersService().togglePusher(pusher, enabled)
} }
} }
if (checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(session, deviceId)) { if (checkIfCanToggleNotificationsViaAccountDataUseCase.execute(session, deviceId)) {
val newNotificationSettingsContent = LocalNotificationSettingsContent(isSilenced = !enabled) val newNotificationSettingsContent = LocalNotificationSettingsContent(isSilenced = !enabled)
session.accountDataService().updateUserAccountData( setNotificationSettingsAccountDataUseCase.execute(session, deviceId, newNotificationSettingsContent)
UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId,
newNotificationSettingsContent.toContent(),
)
} }
} }
} }

View File

@ -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)
}
}

View File

@ -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.ToggleIpAddressVisibilityUseCase
import im.vector.app.features.settings.devices.v2.VectorSessionsListViewModel 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.GetNotificationsStatusUseCase
import im.vector.app.features.settings.devices.v2.notification.TogglePushNotificationUseCase import im.vector.app.features.settings.devices.v2.notification.ToggleNotificationsUseCase
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.SignoutSessionsReAuthNeeded
import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsUseCase import im.vector.app.features.settings.devices.v2.signout.SignoutSessionsUseCase
import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase
@ -51,10 +50,9 @@ class SessionOverviewViewModel @AssistedInject constructor(
private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase, private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase,
private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase, private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase,
private val signoutSessionsUseCase: SignoutSessionsUseCase, private val signoutSessionsUseCase: SignoutSessionsUseCase,
private val interceptSignoutFlowResponseUseCase: InterceptSignoutFlowResponseUseCase,
private val pendingAuthHandler: PendingAuthHandler, private val pendingAuthHandler: PendingAuthHandler,
private val activeSessionHolder: ActiveSessionHolder, private val activeSessionHolder: ActiveSessionHolder,
private val togglePushNotificationUseCase: TogglePushNotificationUseCase, private val toggleNotificationsUseCase: ToggleNotificationsUseCase,
private val getNotificationsStatusUseCase: GetNotificationsStatusUseCase, private val getNotificationsStatusUseCase: GetNotificationsStatusUseCase,
refreshDevicesUseCase: RefreshDevicesUseCase, refreshDevicesUseCase: RefreshDevicesUseCase,
private val vectorPreferences: VectorPreferences, private val vectorPreferences: VectorPreferences,
@ -228,7 +226,7 @@ class SessionOverviewViewModel @AssistedInject constructor(
private fun handleTogglePusherAction(action: SessionOverviewAction.TogglePushNotifications) { private fun handleTogglePusherAction(action: SessionOverviewAction.TogglePushNotifications) {
viewModelScope.launch { viewModelScope.launch {
togglePushNotificationUseCase.execute(action.deviceId, action.enabled) toggleNotificationsUseCase.execute(action.deviceId, action.enabled)
} }
} }
} }

View File

@ -16,28 +16,18 @@
package im.vector.app.features.settings.notifications 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.PushersManager
import im.vector.app.core.pushers.UnregisterUnifiedPushUseCase 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 import javax.inject.Inject
class DisableNotificationsForCurrentSessionUseCase @Inject constructor( class DisableNotificationsForCurrentSessionUseCase @Inject constructor(
private val activeSessionHolder: ActiveSessionHolder,
private val pushersManager: PushersManager, private val pushersManager: PushersManager,
private val checkIfCanTogglePushNotificationsViaPusherUseCase: CheckIfCanTogglePushNotificationsViaPusherUseCase, private val toggleNotificationsForCurrentSessionUseCase: ToggleNotificationsForCurrentSessionUseCase,
private val togglePushNotificationUseCase: TogglePushNotificationUseCase,
private val unregisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase, private val unregisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase,
) { ) {
suspend fun execute() { suspend fun execute() {
val session = activeSessionHolder.getSafeActiveSession() ?: return toggleNotificationsForCurrentSessionUseCase.execute(enabled = false)
val deviceId = session.sessionParams.deviceId ?: return unregisterUnifiedPushUseCase.execute(pushersManager)
if (checkIfCanTogglePushNotificationsViaPusherUseCase.execute(session)) {
togglePushNotificationUseCase.execute(deviceId, enabled = false)
} else {
unregisterUnifiedPushUseCase.execute(pushersManager)
}
} }
} }

View File

@ -16,24 +16,20 @@
package im.vector.app.features.settings.notifications 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.EnsureFcmTokenIsRetrievedUseCase
import im.vector.app.core.pushers.PushersManager import im.vector.app.core.pushers.PushersManager
import im.vector.app.core.pushers.RegisterUnifiedPushUseCase import im.vector.app.core.pushers.RegisterUnifiedPushUseCase
import im.vector.app.features.settings.devices.v2.notification.TogglePushNotificationUseCase
import javax.inject.Inject import javax.inject.Inject
class EnableNotificationsForCurrentSessionUseCase @Inject constructor( class EnableNotificationsForCurrentSessionUseCase @Inject constructor(
private val activeSessionHolder: ActiveSessionHolder,
private val pushersManager: PushersManager, private val pushersManager: PushersManager,
private val togglePushNotificationUseCase: TogglePushNotificationUseCase, private val toggleNotificationsForCurrentSessionUseCase: ToggleNotificationsForCurrentSessionUseCase,
private val registerUnifiedPushUseCase: RegisterUnifiedPushUseCase, private val registerUnifiedPushUseCase: RegisterUnifiedPushUseCase,
private val ensureFcmTokenIsRetrievedUseCase: EnsureFcmTokenIsRetrievedUseCase, private val ensureFcmTokenIsRetrievedUseCase: EnsureFcmTokenIsRetrievedUseCase,
) { ) {
sealed interface EnableNotificationsResult { sealed interface EnableNotificationsResult {
object Success : EnableNotificationsResult object Success : EnableNotificationsResult
object Failure : EnableNotificationsResult
object NeedToAskUserForDistributor : EnableNotificationsResult object NeedToAskUserForDistributor : EnableNotificationsResult
} }
@ -50,9 +46,7 @@ class EnableNotificationsForCurrentSessionUseCase @Inject constructor(
} }
} }
val session = activeSessionHolder.getSafeActiveSession() ?: return EnableNotificationsResult.Failure toggleNotificationsForCurrentSessionUseCase.execute(enabled = true)
val deviceId = session.sessionParams.deviceId ?: return EnableNotificationsResult.Failure
togglePushNotificationUseCase.execute(deviceId, enabled = true)
return EnableNotificationsResult.Success return EnableNotificationsResult.Success
} }

View File

@ -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)
}
}
}
}
}

View File

@ -119,7 +119,6 @@ class VectorSettingsNotificationPreferenceFragment :
VectorSettingsNotificationPreferenceViewEvent.NotificationsForDeviceEnabled -> onNotificationsForDeviceEnabled() VectorSettingsNotificationPreferenceViewEvent.NotificationsForDeviceEnabled -> onNotificationsForDeviceEnabled()
VectorSettingsNotificationPreferenceViewEvent.NotificationsForDeviceDisabled -> onNotificationsForDeviceDisabled() VectorSettingsNotificationPreferenceViewEvent.NotificationsForDeviceDisabled -> onNotificationsForDeviceDisabled()
is VectorSettingsNotificationPreferenceViewEvent.AskUserForPushDistributor -> askUserToSelectPushDistributor() is VectorSettingsNotificationPreferenceViewEvent.AskUserForPushDistributor -> askUserToSelectPushDistributor()
VectorSettingsNotificationPreferenceViewEvent.EnableNotificationForDeviceFailure -> displayErrorDialog(throwable = null)
VectorSettingsNotificationPreferenceViewEvent.NotificationMethodChanged -> onNotificationMethodChanged() VectorSettingsNotificationPreferenceViewEvent.NotificationMethodChanged -> onNotificationMethodChanged()
} }
} }

View File

@ -20,7 +20,6 @@ import im.vector.app.core.platform.VectorViewEvents
sealed interface VectorSettingsNotificationPreferenceViewEvent : VectorViewEvents { sealed interface VectorSettingsNotificationPreferenceViewEvent : VectorViewEvents {
object NotificationsForDeviceEnabled : VectorSettingsNotificationPreferenceViewEvent object NotificationsForDeviceEnabled : VectorSettingsNotificationPreferenceViewEvent
object EnableNotificationForDeviceFailure : VectorSettingsNotificationPreferenceViewEvent
object NotificationsForDeviceDisabled : VectorSettingsNotificationPreferenceViewEvent object NotificationsForDeviceDisabled : VectorSettingsNotificationPreferenceViewEvent
object AskUserForPushDistributor : VectorSettingsNotificationPreferenceViewEvent object AskUserForPushDistributor : VectorSettingsNotificationPreferenceViewEvent
object NotificationMethodChanged : VectorSettingsNotificationPreferenceViewEvent object NotificationMethodChanged : VectorSettingsNotificationPreferenceViewEvent

View File

@ -40,6 +40,7 @@ class VectorSettingsNotificationPreferenceViewModel @AssistedInject constructor(
private val unregisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase, private val unregisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase,
private val registerUnifiedPushUseCase: RegisterUnifiedPushUseCase, private val registerUnifiedPushUseCase: RegisterUnifiedPushUseCase,
private val ensureFcmTokenIsRetrievedUseCase: EnsureFcmTokenIsRetrievedUseCase, private val ensureFcmTokenIsRetrievedUseCase: EnsureFcmTokenIsRetrievedUseCase,
private val toggleNotificationsForCurrentSessionUseCase: ToggleNotificationsForCurrentSessionUseCase,
) : VectorViewModel<VectorDummyViewState, VectorSettingsNotificationPreferenceViewAction, VectorSettingsNotificationPreferenceViewEvent>(initialState) { ) : VectorViewModel<VectorDummyViewState, VectorSettingsNotificationPreferenceViewAction, VectorSettingsNotificationPreferenceViewEvent>(initialState) {
@AssistedFactory @AssistedFactory
@ -67,9 +68,6 @@ class VectorSettingsNotificationPreferenceViewModel @AssistedInject constructor(
private fun handleEnableNotificationsForDevice(distributor: String) { private fun handleEnableNotificationsForDevice(distributor: String) {
viewModelScope.launch { viewModelScope.launch {
when (enableNotificationsForCurrentSessionUseCase.execute(distributor)) { when (enableNotificationsForCurrentSessionUseCase.execute(distributor)) {
EnableNotificationsForCurrentSessionUseCase.EnableNotificationsResult.Failure -> {
_viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.EnableNotificationForDeviceFailure)
}
is EnableNotificationsForCurrentSessionUseCase.EnableNotificationsResult.NeedToAskUserForDistributor -> { is EnableNotificationsForCurrentSessionUseCase.EnableNotificationsResult.NeedToAskUserForDistributor -> {
_viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.AskUserForPushDistributor) _viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.AskUserForPushDistributor)
} }
@ -88,7 +86,9 @@ class VectorSettingsNotificationPreferenceViewModel @AssistedInject constructor(
_viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.AskUserForPushDistributor) _viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.AskUserForPushDistributor)
} }
RegisterUnifiedPushUseCase.RegisterUnifiedPushResult.Success -> { 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) _viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.NotificationMethodChanged)
} }
} }

View File

@ -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<UpdateEnableNotificationsSettingOnChangeUseCase>()
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) }
}
}

View File

@ -19,9 +19,10 @@ package im.vector.app.core.session
import im.vector.app.core.extensions.startSyncing import im.vector.app.core.extensions.startSyncing
import im.vector.app.core.session.clientinfo.UpdateMatrixClientInfoUseCase import im.vector.app.core.session.clientinfo.UpdateMatrixClientInfoUseCase
import im.vector.app.features.session.coroutineScope 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.features.sync.SyncUtils
import im.vector.app.test.fakes.FakeContext 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.FakeSession
import im.vector.app.test.fakes.FakeVectorPreferences import im.vector.app.test.fakes.FakeVectorPreferences
import im.vector.app.test.fakes.FakeWebRtcCallManager import im.vector.app.test.fakes.FakeWebRtcCallManager
@ -46,14 +47,16 @@ class ConfigureAndStartSessionUseCaseTest {
private val fakeWebRtcCallManager = FakeWebRtcCallManager() private val fakeWebRtcCallManager = FakeWebRtcCallManager()
private val fakeUpdateMatrixClientInfoUseCase = mockk<UpdateMatrixClientInfoUseCase>() private val fakeUpdateMatrixClientInfoUseCase = mockk<UpdateMatrixClientInfoUseCase>()
private val fakeVectorPreferences = FakeVectorPreferences() private val fakeVectorPreferences = FakeVectorPreferences()
private val fakeEnableNotificationsSettingUpdater = FakeEnableNotificationsSettingUpdater() private val fakeNotificationsSettingUpdater = FakeNotificationsSettingUpdater()
private val fakeUpdateNotificationSettingsAccountDataUseCase = mockk<UpdateNotificationSettingsAccountDataUseCase>()
private val configureAndStartSessionUseCase = ConfigureAndStartSessionUseCase( private val configureAndStartSessionUseCase = ConfigureAndStartSessionUseCase(
context = fakeContext.instance, context = fakeContext.instance,
webRtcCallManager = fakeWebRtcCallManager.instance, webRtcCallManager = fakeWebRtcCallManager.instance,
updateMatrixClientInfoUseCase = fakeUpdateMatrixClientInfoUseCase, updateMatrixClientInfoUseCase = fakeUpdateMatrixClientInfoUseCase,
vectorPreferences = fakeVectorPreferences.instance, vectorPreferences = fakeVectorPreferences.instance,
enableNotificationsSettingUpdater = fakeEnableNotificationsSettingUpdater.instance, notificationsSettingUpdater = fakeNotificationsSettingUpdater.instance,
updateNotificationSettingsAccountDataUseCase = fakeUpdateNotificationSettingsAccountDataUseCase,
) )
@Before @Before
@ -70,67 +73,80 @@ class ConfigureAndStartSessionUseCaseTest {
@Test @Test
fun `given start sync needed and client info recording enabled when execute then it should be configured properly`() = runTest { fun `given start sync needed and client info recording enabled when execute then it should be configured properly`() = runTest {
// Given // Given
val fakeSession = givenASession() val aSession = givenASession()
every { fakeSession.coroutineScope } returns this every { aSession.coroutineScope } returns this
fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds()
coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) } coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) }
coJustRun { fakeUpdateNotificationSettingsAccountDataUseCase.execute(any()) }
fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = true) fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = true)
fakeEnableNotificationsSettingUpdater.givenOnSessionsStarted(fakeSession) fakeNotificationsSettingUpdater.givenOnSessionsStarted(aSession)
// When // When
configureAndStartSessionUseCase.execute(fakeSession, startSyncing = true) configureAndStartSessionUseCase.execute(aSession, startSyncing = true)
advanceUntilIdle() advanceUntilIdle()
// Then // Then
verify { fakeSession.startSyncing(fakeContext.instance) } verify { aSession.startSyncing(fakeContext.instance) }
fakeSession.fakeFilterService.verifySetSyncFilter(SyncUtils.getSyncFilterBuilder()) aSession.fakeFilterService.verifySetSyncFilter(SyncUtils.getSyncFilterBuilder())
fakeSession.fakePushersService.verifyRefreshPushers() aSession.fakePushersService.verifyRefreshPushers()
fakeWebRtcCallManager.verifyCheckForProtocolsSupportIfNeeded() fakeWebRtcCallManager.verifyCheckForProtocolsSupportIfNeeded()
coVerify { fakeUpdateMatrixClientInfoUseCase.execute(fakeSession) } coVerify {
fakeUpdateMatrixClientInfoUseCase.execute(aSession)
fakeUpdateNotificationSettingsAccountDataUseCase.execute(aSession)
}
} }
@Test @Test
fun `given start sync needed and client info recording disabled when execute then it should be configured properly`() = runTest { fun `given start sync needed and client info recording disabled when execute then it should be configured properly`() = runTest {
// Given // Given
val fakeSession = givenASession() val aSession = givenASession()
every { fakeSession.coroutineScope } returns this every { aSession.coroutineScope } returns this
fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds()
coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) } coJustRun { fakeUpdateNotificationSettingsAccountDataUseCase.execute(any()) }
fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = false) fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = false)
fakeEnableNotificationsSettingUpdater.givenOnSessionsStarted(fakeSession) fakeNotificationsSettingUpdater.givenOnSessionsStarted(aSession)
// When // When
configureAndStartSessionUseCase.execute(fakeSession, startSyncing = true) configureAndStartSessionUseCase.execute(aSession, startSyncing = true)
advanceUntilIdle() advanceUntilIdle()
// Then // Then
verify { fakeSession.startSyncing(fakeContext.instance) } verify { aSession.startSyncing(fakeContext.instance) }
fakeSession.fakeFilterService.verifySetSyncFilter(SyncUtils.getSyncFilterBuilder()) aSession.fakeFilterService.verifySetSyncFilter(SyncUtils.getSyncFilterBuilder())
fakeSession.fakePushersService.verifyRefreshPushers() aSession.fakePushersService.verifyRefreshPushers()
fakeWebRtcCallManager.verifyCheckForProtocolsSupportIfNeeded() fakeWebRtcCallManager.verifyCheckForProtocolsSupportIfNeeded()
coVerify(inverse = true) { fakeUpdateMatrixClientInfoUseCase.execute(fakeSession) } coVerify(inverse = true) {
fakeUpdateMatrixClientInfoUseCase.execute(aSession)
}
coVerify {
fakeUpdateNotificationSettingsAccountDataUseCase.execute(aSession)
}
} }
@Test @Test
fun `given a session and no start sync needed when execute then it should be configured properly`() = runTest { fun `given a session and no start sync needed when execute then it should be configured properly`() = runTest {
// Given // Given
val fakeSession = givenASession() val aSession = givenASession()
every { fakeSession.coroutineScope } returns this every { aSession.coroutineScope } returns this
fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds()
coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) } coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) }
coJustRun { fakeUpdateNotificationSettingsAccountDataUseCase.execute(any()) }
fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = true) fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = true)
fakeEnableNotificationsSettingUpdater.givenOnSessionsStarted(fakeSession) fakeNotificationsSettingUpdater.givenOnSessionsStarted(aSession)
// When // When
configureAndStartSessionUseCase.execute(fakeSession, startSyncing = false) configureAndStartSessionUseCase.execute(aSession, startSyncing = false)
advanceUntilIdle() advanceUntilIdle()
// Then // Then
verify(inverse = true) { fakeSession.startSyncing(fakeContext.instance) } verify(inverse = true) { aSession.startSyncing(fakeContext.instance) }
fakeSession.fakeFilterService.verifySetSyncFilter(SyncUtils.getSyncFilterBuilder()) aSession.fakeFilterService.verifySetSyncFilter(SyncUtils.getSyncFilterBuilder())
fakeSession.fakePushersService.verifyRefreshPushers() aSession.fakePushersService.verifyRefreshPushers()
fakeWebRtcCallManager.verifyCheckForProtocolsSupportIfNeeded() fakeWebRtcCallManager.verifyCheckForProtocolsSupportIfNeeded()
coVerify { fakeUpdateMatrixClientInfoUseCase.execute(fakeSession) } coVerify {
fakeUpdateMatrixClientInfoUseCase.execute(aSession)
fakeUpdateNotificationSettingsAccountDataUseCase.execute(aSession)
}
} }
private fun givenASession(): FakeSession { private fun givenASession(): FakeSession {

View File

@ -22,7 +22,6 @@ import com.airbnb.mvrx.test.MavericksTestRule
import im.vector.app.core.session.clientinfo.MatrixClientInfoContent 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.details.extended.DeviceExtendedInfo
import im.vector.app.features.settings.devices.v2.list.DeviceType 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.CheckIfCurrentSessionCanBeVerifiedUseCase
import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo
import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase
@ -72,7 +71,6 @@ class DevicesViewModelTest {
private val refreshDevicesOnCryptoDevicesChangeUseCase = mockk<RefreshDevicesOnCryptoDevicesChangeUseCase>(relaxed = true) private val refreshDevicesOnCryptoDevicesChangeUseCase = mockk<RefreshDevicesOnCryptoDevicesChangeUseCase>(relaxed = true)
private val checkIfCurrentSessionCanBeVerifiedUseCase = mockk<CheckIfCurrentSessionCanBeVerifiedUseCase>() private val checkIfCurrentSessionCanBeVerifiedUseCase = mockk<CheckIfCurrentSessionCanBeVerifiedUseCase>()
private val fakeSignoutSessionsUseCase = FakeSignoutSessionsUseCase() private val fakeSignoutSessionsUseCase = FakeSignoutSessionsUseCase()
private val fakeInterceptSignoutFlowResponseUseCase = mockk<InterceptSignoutFlowResponseUseCase>()
private val fakePendingAuthHandler = FakePendingAuthHandler() private val fakePendingAuthHandler = FakePendingAuthHandler()
private val fakeRefreshDevicesUseCase = mockk<RefreshDevicesUseCase>(relaxUnitFun = true) private val fakeRefreshDevicesUseCase = mockk<RefreshDevicesUseCase>(relaxUnitFun = true)
private val fakeVectorPreferences = FakeVectorPreferences() private val fakeVectorPreferences = FakeVectorPreferences()
@ -87,7 +85,6 @@ class DevicesViewModelTest {
refreshDevicesOnCryptoDevicesChangeUseCase = refreshDevicesOnCryptoDevicesChangeUseCase, refreshDevicesOnCryptoDevicesChangeUseCase = refreshDevicesOnCryptoDevicesChangeUseCase,
checkIfCurrentSessionCanBeVerifiedUseCase = checkIfCurrentSessionCanBeVerifiedUseCase, checkIfCurrentSessionCanBeVerifiedUseCase = checkIfCurrentSessionCanBeVerifiedUseCase,
signoutSessionsUseCase = fakeSignoutSessionsUseCase.instance, signoutSessionsUseCase = fakeSignoutSessionsUseCase.instance,
interceptSignoutFlowResponseUseCase = fakeInterceptSignoutFlowResponseUseCase,
pendingAuthHandler = fakePendingAuthHandler.instance, pendingAuthHandler = fakePendingAuthHandler.instance,
refreshDevicesUseCase = fakeRefreshDevicesUseCase, refreshDevicesUseCase = fakeRefreshDevicesUseCase,
vectorPreferences = fakeVectorPreferences.instance, vectorPreferences = fakeVectorPreferences.instance,

View File

@ -30,13 +30,13 @@ import org.junit.Test
private val A_HOMESERVER_CAPABILITIES = aHomeServerCapabilities(canRemotelyTogglePushNotificationsOfDevices = true) private val A_HOMESERVER_CAPABILITIES = aHomeServerCapabilities(canRemotelyTogglePushNotificationsOfDevices = true)
class CanTogglePushNotificationsViaPusherUseCaseTest { class CanToggleNotificationsViaPusherUseCaseTest {
private val fakeSession = FakeSession() private val fakeSession = FakeSession()
private val fakeFlowLiveDataConversions = FakeFlowLiveDataConversions() private val fakeFlowLiveDataConversions = FakeFlowLiveDataConversions()
private val canTogglePushNotificationsViaPusherUseCase = private val canToggleNotificationsViaPusherUseCase =
CanTogglePushNotificationsViaPusherUseCase() CanToggleNotificationsViaPusherUseCase()
@Before @Before
fun setUp() { fun setUp() {
@ -57,7 +57,7 @@ class CanTogglePushNotificationsViaPusherUseCaseTest {
.givenAsFlow() .givenAsFlow()
// When // When
val result = canTogglePushNotificationsViaPusherUseCase.execute(fakeSession).firstOrNull() val result = canToggleNotificationsViaPusherUseCase.execute(fakeSession).firstOrNull()
// Then // Then
result shouldBeEqualTo A_HOMESERVER_CAPABILITIES.canRemotelyTogglePushNotificationsOfDevices result shouldBeEqualTo A_HOMESERVER_CAPABILITIES.canRemotelyTogglePushNotificationsOfDevices

View File

@ -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<GetNotificationSettingsAccountDataUseCase>()
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
}
}

View File

@ -23,12 +23,12 @@ import org.junit.Test
private val A_HOMESERVER_CAPABILITIES = aHomeServerCapabilities(canRemotelyTogglePushNotificationsOfDevices = true) private val A_HOMESERVER_CAPABILITIES = aHomeServerCapabilities(canRemotelyTogglePushNotificationsOfDevices = true)
class CheckIfCanTogglePushNotificationsViaPusherUseCaseTest { class CheckIfCanToggleNotificationsViaPusherUseCaseTest {
private val fakeSession = FakeSession() private val fakeSession = FakeSession()
private val checkIfCanTogglePushNotificationsViaPusherUseCase = private val checkIfCanToggleNotificationsViaPusherUseCase =
CheckIfCanTogglePushNotificationsViaPusherUseCase() CheckIfCanToggleNotificationsViaPusherUseCase()
@Test @Test
fun `given current session when execute then toggle capability is returned`() { fun `given current session when execute then toggle capability is returned`() {
@ -38,7 +38,7 @@ class CheckIfCanTogglePushNotificationsViaPusherUseCaseTest {
.givenCapabilities(A_HOMESERVER_CAPABILITIES) .givenCapabilities(A_HOMESERVER_CAPABILITIES)
// When // When
val result = checkIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) val result = checkIfCanToggleNotificationsViaPusherUseCase.execute(fakeSession)
// Then // Then
result shouldBeEqualTo A_HOMESERVER_CAPABILITIES.canRemotelyTogglePushNotificationsOfDevices result shouldBeEqualTo A_HOMESERVER_CAPABILITIES.canRemotelyTogglePushNotificationsOfDevices

View File

@ -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
}
}

View File

@ -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<SetNotificationSettingsAccountDataUseCase>()
private val fakeGetNotificationSettingsAccountDataUseCase = mockk<GetNotificationSettingsAccountDataUseCase>()
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()) }
}
}

View File

@ -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
}
}

View File

@ -46,15 +46,15 @@ class GetNotificationsStatusUseCaseTest {
val instantTaskExecutorRule = InstantTaskExecutorRule() val instantTaskExecutorRule = InstantTaskExecutorRule()
private val fakeSession = FakeSession() private val fakeSession = FakeSession()
private val fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase = private val fakeCheckIfCanToggleNotificationsViaAccountDataUseCase =
mockk<CheckIfCanTogglePushNotificationsViaAccountDataUseCase>() mockk<CheckIfCanToggleNotificationsViaAccountDataUseCase>()
private val fakeCanTogglePushNotificationsViaPusherUseCase = private val fakeCanToggleNotificationsViaPusherUseCase =
mockk<CanTogglePushNotificationsViaPusherUseCase>() mockk<CanToggleNotificationsViaPusherUseCase>()
private val getNotificationsStatusUseCase = private val getNotificationsStatusUseCase =
GetNotificationsStatusUseCase( GetNotificationsStatusUseCase(
checkIfCanTogglePushNotificationsViaAccountDataUseCase = fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase, checkIfCanToggleNotificationsViaAccountDataUseCase = fakeCheckIfCanToggleNotificationsViaAccountDataUseCase,
canTogglePushNotificationsViaPusherUseCase = fakeCanTogglePushNotificationsViaPusherUseCase, canToggleNotificationsViaPusherUseCase = fakeCanToggleNotificationsViaPusherUseCase,
) )
@Before @Before
@ -70,8 +70,8 @@ class GetNotificationsStatusUseCaseTest {
@Test @Test
fun `given current session and toggle is not supported when execute then resulting flow contains NOT_SUPPORTED value`() = runTest { fun `given current session and toggle is not supported when execute then resulting flow contains NOT_SUPPORTED value`() = runTest {
// Given // Given
every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns false every { fakeCheckIfCanToggleNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns false
every { fakeCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(false) every { fakeCanToggleNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(false)
// When // When
val result = getNotificationsStatusUseCase.execute(fakeSession, A_DEVICE_ID) val result = getNotificationsStatusUseCase.execute(fakeSession, A_DEVICE_ID)
@ -80,8 +80,8 @@ class GetNotificationsStatusUseCaseTest {
result.firstOrNull() shouldBeEqualTo NotificationsStatus.NOT_SUPPORTED result.firstOrNull() shouldBeEqualTo NotificationsStatus.NOT_SUPPORTED
verifyOrder { verifyOrder {
// we should first check account data // we should first check account data
fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) fakeCheckIfCanToggleNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID)
fakeCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) fakeCanToggleNotificationsViaPusherUseCase.execute(fakeSession)
} }
} }
@ -95,8 +95,8 @@ class GetNotificationsStatusUseCaseTest {
) )
) )
fakeSession.pushersService().givenPushersLive(pushers) fakeSession.pushersService().givenPushersLive(pushers)
every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns false every { fakeCheckIfCanToggleNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns false
every { fakeCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(true) every { fakeCanToggleNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(true)
// When // When
val result = getNotificationsStatusUseCase.execute(fakeSession, A_DEVICE_ID) val result = getNotificationsStatusUseCase.execute(fakeSession, A_DEVICE_ID)
@ -105,6 +105,20 @@ class GetNotificationsStatusUseCaseTest {
result.firstOrNull() shouldBeEqualTo NotificationsStatus.ENABLED 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 @Test
fun `given current session and toggle via account data is supported when execute then resulting flow contains status based on settings value`() = runTest { fun `given current session and toggle via account data is supported when execute then resulting flow contains status based on settings value`() = runTest {
// Given // Given
@ -116,8 +130,8 @@ class GetNotificationsStatusUseCaseTest {
isSilenced = false isSilenced = false
).toContent(), ).toContent(),
) )
every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns true every { fakeCheckIfCanToggleNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns true
every { fakeCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(false) every { fakeCanToggleNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(false)
// When // When
val result = getNotificationsStatusUseCase.execute(fakeSession, A_DEVICE_ID) val result = getNotificationsStatusUseCase.execute(fakeSession, A_DEVICE_ID)

View File

@ -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(),
)
}
}

View File

@ -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<CheckIfCanToggleNotificationsViaPusherUseCase>()
private val fakeCheckIfCanToggleNotificationsViaAccountDataUseCase =
mockk<CheckIfCanToggleNotificationsViaAccountDataUseCase>()
private val fakeSetNotificationSettingsAccountDataUseCase =
mockk<SetNotificationSettingsAccountDataUseCase>()
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)
}
}
}

View File

@ -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<CheckIfCanTogglePushNotificationsViaPusherUseCase>()
private val fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase =
mockk<CheckIfCanTogglePushNotificationsViaAccountDataUseCase>()
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(),
)
}
}

View File

@ -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<GetNotificationSettingsAccountDataUseCase>()
private val fakeSetNotificationSettingsAccountDataUseCase = mockk<SetNotificationSettingsAccountDataUseCase>()
private val fakeDeleteNotificationSettingsAccountDataUseCase = mockk<DeleteNotificationSettingsAccountDataUseCase>()
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()) }
}
}

View File

@ -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.RefreshDevicesUseCase
import im.vector.app.features.settings.devices.v2.ToggleIpAddressVisibilityUseCase 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.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.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase
import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeActiveSessionHolder
import im.vector.app.test.fakes.FakeGetNotificationsStatusUseCase import im.vector.app.test.fakes.FakeGetNotificationsStatusUseCase
import im.vector.app.test.fakes.FakePendingAuthHandler import im.vector.app.test.fakes.FakePendingAuthHandler
import im.vector.app.test.fakes.FakeSignoutSessionsUseCase 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.FakeVectorPreferences
import im.vector.app.test.fakes.FakeVerificationService import im.vector.app.test.fakes.FakeVerificationService
import im.vector.app.test.test import im.vector.app.test.test
@ -73,10 +72,9 @@ class SessionOverviewViewModelTest {
private val fakeActiveSessionHolder = FakeActiveSessionHolder() private val fakeActiveSessionHolder = FakeActiveSessionHolder()
private val checkIfCurrentSessionCanBeVerifiedUseCase = mockk<CheckIfCurrentSessionCanBeVerifiedUseCase>() private val checkIfCurrentSessionCanBeVerifiedUseCase = mockk<CheckIfCurrentSessionCanBeVerifiedUseCase>()
private val fakeSignoutSessionsUseCase = FakeSignoutSessionsUseCase() private val fakeSignoutSessionsUseCase = FakeSignoutSessionsUseCase()
private val interceptSignoutFlowResponseUseCase = mockk<InterceptSignoutFlowResponseUseCase>()
private val fakePendingAuthHandler = FakePendingAuthHandler() private val fakePendingAuthHandler = FakePendingAuthHandler()
private val refreshDevicesUseCase = mockk<RefreshDevicesUseCase>(relaxed = true) private val refreshDevicesUseCase = mockk<RefreshDevicesUseCase>(relaxed = true)
private val togglePushNotificationUseCase = FakeTogglePushNotificationUseCase() private val toggleNotificationUseCase = FakeToggleNotificationUseCase()
private val fakeGetNotificationsStatusUseCase = FakeGetNotificationsStatusUseCase() private val fakeGetNotificationsStatusUseCase = FakeGetNotificationsStatusUseCase()
private val notificationsStatus = NotificationsStatus.ENABLED private val notificationsStatus = NotificationsStatus.ENABLED
private val fakeVectorPreferences = FakeVectorPreferences() private val fakeVectorPreferences = FakeVectorPreferences()
@ -87,11 +85,10 @@ class SessionOverviewViewModelTest {
getDeviceFullInfoUseCase = getDeviceFullInfoUseCase, getDeviceFullInfoUseCase = getDeviceFullInfoUseCase,
checkIfCurrentSessionCanBeVerifiedUseCase = checkIfCurrentSessionCanBeVerifiedUseCase, checkIfCurrentSessionCanBeVerifiedUseCase = checkIfCurrentSessionCanBeVerifiedUseCase,
signoutSessionsUseCase = fakeSignoutSessionsUseCase.instance, signoutSessionsUseCase = fakeSignoutSessionsUseCase.instance,
interceptSignoutFlowResponseUseCase = interceptSignoutFlowResponseUseCase,
pendingAuthHandler = fakePendingAuthHandler.instance, pendingAuthHandler = fakePendingAuthHandler.instance,
activeSessionHolder = fakeActiveSessionHolder.instance, activeSessionHolder = fakeActiveSessionHolder.instance,
refreshDevicesUseCase = refreshDevicesUseCase, refreshDevicesUseCase = refreshDevicesUseCase,
togglePushNotificationUseCase = togglePushNotificationUseCase.instance, toggleNotificationsUseCase = toggleNotificationUseCase.instance,
getNotificationsStatusUseCase = fakeGetNotificationsStatusUseCase.instance, getNotificationsStatusUseCase = fakeGetNotificationsStatusUseCase.instance,
vectorPreferences = fakeVectorPreferences.instance, vectorPreferences = fakeVectorPreferences.instance,
toggleIpAddressVisibilityUseCase = toggleIpAddressVisibilityUseCase, toggleIpAddressVisibilityUseCase = toggleIpAddressVisibilityUseCase,
@ -436,7 +433,7 @@ class SessionOverviewViewModelTest {
viewModel.handle(SessionOverviewAction.TogglePushNotifications(A_SESSION_ID_1, true)) 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() viewModel.test().assertLatestState { state -> state.notificationsStatus == NotificationsStatus.ENABLED }.finish()
} }
} }

View File

@ -17,56 +17,29 @@
package im.vector.app.features.settings.notifications package im.vector.app.features.settings.notifications
import im.vector.app.core.pushers.UnregisterUnifiedPushUseCase 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 im.vector.app.test.fakes.FakePushersManager
import io.mockk.coJustRun import io.mockk.coJustRun
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
private const val A_SESSION_ID = "session-id"
class DisableNotificationsForCurrentSessionUseCaseTest { class DisableNotificationsForCurrentSessionUseCaseTest {
private val fakeActiveSessionHolder = FakeActiveSessionHolder()
private val fakePushersManager = FakePushersManager() private val fakePushersManager = FakePushersManager()
private val fakeCheckIfCanTogglePushNotificationsViaPusherUseCase = mockk<CheckIfCanTogglePushNotificationsViaPusherUseCase>() private val fakeToggleNotificationsForCurrentSessionUseCase = mockk<ToggleNotificationsForCurrentSessionUseCase>()
private val fakeTogglePushNotificationUseCase = mockk<TogglePushNotificationUseCase>()
private val fakeUnregisterUnifiedPushUseCase = mockk<UnregisterUnifiedPushUseCase>() private val fakeUnregisterUnifiedPushUseCase = mockk<UnregisterUnifiedPushUseCase>()
private val disableNotificationsForCurrentSessionUseCase = DisableNotificationsForCurrentSessionUseCase( private val disableNotificationsForCurrentSessionUseCase = DisableNotificationsForCurrentSessionUseCase(
activeSessionHolder = fakeActiveSessionHolder.instance,
pushersManager = fakePushersManager.instance, pushersManager = fakePushersManager.instance,
checkIfCanTogglePushNotificationsViaPusherUseCase = fakeCheckIfCanTogglePushNotificationsViaPusherUseCase, toggleNotificationsForCurrentSessionUseCase = fakeToggleNotificationsForCurrentSessionUseCase,
togglePushNotificationUseCase = fakeTogglePushNotificationUseCase,
unregisterUnifiedPushUseCase = fakeUnregisterUnifiedPushUseCase, unregisterUnifiedPushUseCase = fakeUnregisterUnifiedPushUseCase,
) )
@Test @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 // Given
val fakeSession = fakeActiveSessionHolder.fakeSession coJustRun { fakeToggleNotificationsForCurrentSessionUseCase.execute(any()) }
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 { fakeUnregisterUnifiedPushUseCase.execute(any()) } coJustRun { fakeUnregisterUnifiedPushUseCase.execute(any()) }
// When // When
@ -74,6 +47,7 @@ class DisableNotificationsForCurrentSessionUseCaseTest {
// Then // Then
coVerify { coVerify {
fakeToggleNotificationsForCurrentSessionUseCase.execute(false)
fakeUnregisterUnifiedPushUseCase.execute(fakePushersManager.instance) fakeUnregisterUnifiedPushUseCase.execute(fakePushersManager.instance)
} }
} }

View File

@ -18,10 +18,9 @@ package im.vector.app.features.settings.notifications
import im.vector.app.core.pushers.EnsureFcmTokenIsRetrievedUseCase import im.vector.app.core.pushers.EnsureFcmTokenIsRetrievedUseCase
import im.vector.app.core.pushers.RegisterUnifiedPushUseCase 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 im.vector.app.test.fakes.FakePushersManager
import io.mockk.coJustRun import io.mockk.coJustRun
import io.mockk.coVerify
import io.mockk.every import io.mockk.every
import io.mockk.justRun import io.mockk.justRun
import io.mockk.mockk import io.mockk.mockk
@ -30,20 +29,16 @@ import kotlinx.coroutines.test.runTest
import org.amshove.kluent.shouldBe import org.amshove.kluent.shouldBe
import org.junit.Test import org.junit.Test
private const val A_SESSION_ID = "session-id"
class EnableNotificationsForCurrentSessionUseCaseTest { class EnableNotificationsForCurrentSessionUseCaseTest {
private val fakeActiveSessionHolder = FakeActiveSessionHolder()
private val fakePushersManager = FakePushersManager() private val fakePushersManager = FakePushersManager()
private val fakeTogglePushNotificationUseCase = mockk<TogglePushNotificationUseCase>() private val fakeToggleNotificationsForCurrentSessionUseCase = mockk<ToggleNotificationsForCurrentSessionUseCase>()
private val fakeRegisterUnifiedPushUseCase = mockk<RegisterUnifiedPushUseCase>() private val fakeRegisterUnifiedPushUseCase = mockk<RegisterUnifiedPushUseCase>()
private val fakeEnsureFcmTokenIsRetrievedUseCase = mockk<EnsureFcmTokenIsRetrievedUseCase>() private val fakeEnsureFcmTokenIsRetrievedUseCase = mockk<EnsureFcmTokenIsRetrievedUseCase>()
private val enableNotificationsForCurrentSessionUseCase = EnableNotificationsForCurrentSessionUseCase( private val enableNotificationsForCurrentSessionUseCase = EnableNotificationsForCurrentSessionUseCase(
activeSessionHolder = fakeActiveSessionHolder.instance,
pushersManager = fakePushersManager.instance, pushersManager = fakePushersManager.instance,
togglePushNotificationUseCase = fakeTogglePushNotificationUseCase, toggleNotificationsForCurrentSessionUseCase = fakeToggleNotificationsForCurrentSessionUseCase,
registerUnifiedPushUseCase = fakeRegisterUnifiedPushUseCase, registerUnifiedPushUseCase = fakeRegisterUnifiedPushUseCase,
ensureFcmTokenIsRetrievedUseCase = fakeEnsureFcmTokenIsRetrievedUseCase, 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 { fun `given no existing pusher and a registered distributor when execute then a new pusher is registered and result is success`() = runTest {
// Given // Given
val aDistributor = "distributor" val aDistributor = "distributor"
val fakeSession = fakeActiveSessionHolder.fakeSession
fakeSession.givenSessionId(A_SESSION_ID)
fakePushersManager.givenGetPusherForCurrentSessionReturns(null) fakePushersManager.givenGetPusherForCurrentSessionReturns(null)
every { fakeRegisterUnifiedPushUseCase.execute(any()) } returns RegisterUnifiedPushUseCase.RegisterUnifiedPushResult.Success every { fakeRegisterUnifiedPushUseCase.execute(any()) } returns RegisterUnifiedPushUseCase.RegisterUnifiedPushResult.Success
justRun { fakeEnsureFcmTokenIsRetrievedUseCase.execute(any(), any()) } justRun { fakeEnsureFcmTokenIsRetrievedUseCase.execute(any(), any()) }
coJustRun { fakeTogglePushNotificationUseCase.execute(A_SESSION_ID, any()) } coJustRun { fakeToggleNotificationsForCurrentSessionUseCase.execute(any()) }
// When // When
val result = enableNotificationsForCurrentSessionUseCase.execute(aDistributor) val result = enableNotificationsForCurrentSessionUseCase.execute(aDistributor)
@ -68,6 +61,9 @@ class EnableNotificationsForCurrentSessionUseCaseTest {
fakeRegisterUnifiedPushUseCase.execute(aDistributor) fakeRegisterUnifiedPushUseCase.execute(aDistributor)
fakeEnsureFcmTokenIsRetrievedUseCase.execute(fakePushersManager.instance, registerPusher = true) fakeEnsureFcmTokenIsRetrievedUseCase.execute(fakePushersManager.instance, registerPusher = true)
} }
coVerify {
fakeToggleNotificationsForCurrentSessionUseCase.execute(enabled = true)
}
} }
@Test @Test
@ -86,20 +82,4 @@ class EnableNotificationsForCurrentSessionUseCaseTest {
fakeRegisterUnifiedPushUseCase.execute(aDistributor) 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
}
} }

View File

@ -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<CheckIfCanToggleNotificationsViaPusherUseCase>()
private val fakeSetNotificationSettingsAccountDataUseCase = mockk<SetNotificationSettingsAccountDataUseCase>()
private val fakeDeleteNotificationSettingsAccountDataUseCase = mockk<DeleteNotificationSettingsAccountDataUseCase>()
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())
}
}
}

View File

@ -46,6 +46,7 @@ class VectorSettingsNotificationPreferenceViewModelTest {
private val fakeUnregisterUnifiedPushUseCase = mockk<UnregisterUnifiedPushUseCase>() private val fakeUnregisterUnifiedPushUseCase = mockk<UnregisterUnifiedPushUseCase>()
private val fakeRegisterUnifiedPushUseCase = mockk<RegisterUnifiedPushUseCase>() private val fakeRegisterUnifiedPushUseCase = mockk<RegisterUnifiedPushUseCase>()
private val fakeEnsureFcmTokenIsRetrievedUseCase = mockk<EnsureFcmTokenIsRetrievedUseCase>() private val fakeEnsureFcmTokenIsRetrievedUseCase = mockk<EnsureFcmTokenIsRetrievedUseCase>()
private val fakeToggleNotificationsForCurrentSessionUseCase = mockk<ToggleNotificationsForCurrentSessionUseCase>()
private fun createViewModel() = VectorSettingsNotificationPreferenceViewModel( private fun createViewModel() = VectorSettingsNotificationPreferenceViewModel(
initialState = VectorDummyViewState(), initialState = VectorDummyViewState(),
@ -56,6 +57,7 @@ class VectorSettingsNotificationPreferenceViewModelTest {
unregisterUnifiedPushUseCase = fakeUnregisterUnifiedPushUseCase, unregisterUnifiedPushUseCase = fakeUnregisterUnifiedPushUseCase,
registerUnifiedPushUseCase = fakeRegisterUnifiedPushUseCase, registerUnifiedPushUseCase = fakeRegisterUnifiedPushUseCase,
ensureFcmTokenIsRetrievedUseCase = fakeEnsureFcmTokenIsRetrievedUseCase, ensureFcmTokenIsRetrievedUseCase = fakeEnsureFcmTokenIsRetrievedUseCase,
toggleNotificationsForCurrentSessionUseCase = fakeToggleNotificationsForCurrentSessionUseCase,
) )
@Test @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 @Test
fun `given RegisterPushDistributor action and register success when handling action then register use case is called`() { fun `given RegisterPushDistributor action and register success when handling action then register use case is called`() {
// Given // Given
@ -158,6 +137,7 @@ class VectorSettingsNotificationPreferenceViewModelTest {
coJustRun { fakeUnregisterUnifiedPushUseCase.execute(any()) } coJustRun { fakeUnregisterUnifiedPushUseCase.execute(any()) }
val areNotificationsEnabled = true val areNotificationsEnabled = true
fakeVectorPreferences.givenAreNotificationsEnabledForDevice(areNotificationsEnabled) fakeVectorPreferences.givenAreNotificationsEnabledForDevice(areNotificationsEnabled)
coJustRun { fakeToggleNotificationsForCurrentSessionUseCase.execute(any()) }
justRun { fakeEnsureFcmTokenIsRetrievedUseCase.execute(any(), any()) } justRun { fakeEnsureFcmTokenIsRetrievedUseCase.execute(any(), any()) }
val expectedEvent = VectorSettingsNotificationPreferenceViewEvent.NotificationMethodChanged val expectedEvent = VectorSettingsNotificationPreferenceViewEvent.NotificationMethodChanged
@ -173,6 +153,7 @@ class VectorSettingsNotificationPreferenceViewModelTest {
fakeUnregisterUnifiedPushUseCase.execute(fakePushersManager.instance) fakeUnregisterUnifiedPushUseCase.execute(fakePushersManager.instance)
fakeRegisterUnifiedPushUseCase.execute(aDistributor) fakeRegisterUnifiedPushUseCase.execute(aDistributor)
fakeEnsureFcmTokenIsRetrievedUseCase.execute(fakePushersManager.instance, registerPusher = areNotificationsEnabled) fakeEnsureFcmTokenIsRetrievedUseCase.execute(fakePushersManager.instance, registerPusher = areNotificationsEnabled)
fakeToggleNotificationsForCurrentSessionUseCase.execute(enabled = areNotificationsEnabled)
} }
} }

View File

@ -16,16 +16,16 @@
package im.vector.app.test.fakes 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.justRun
import io.mockk.mockk import io.mockk.mockk
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
class FakeEnableNotificationsSettingUpdater { class FakeNotificationsSettingUpdater {
val instance = mockk<EnableNotificationsSettingUpdater>() val instance = mockk<NotificationsSettingUpdater>()
fun givenOnSessionsStarted(session: Session) { fun givenOnSessionsStarted(session: Session) {
justRun { instance.onSessionsStarted(session) } justRun { instance.onSessionStarted(session) }
} }
} }

View File

@ -16,14 +16,14 @@
package im.vector.app.test.fakes 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.coJustRun
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.mockk import io.mockk.mockk
class FakeTogglePushNotificationUseCase { class FakeToggleNotificationUseCase {
val instance = mockk<TogglePushNotificationUseCase> { val instance = mockk<ToggleNotificationsUseCase> {
coJustRun { execute(any(), any()) } coJustRun { execute(any(), any()) }
} }

View File

@ -31,4 +31,8 @@ class FakeUnifiedPushHelper {
fun givenGetEndpointOrTokenReturns(endpoint: String?) { fun givenGetEndpointOrTokenReturns(endpoint: String?) {
every { instance.getEndpointOrToken() } returns endpoint every { instance.getEndpointOrToken() } returns endpoint
} }
fun givenIsBackgroundSyncReturns(enabled: Boolean) {
every { instance.isBackgroundSync() } returns enabled
}
} }

View File

@ -16,6 +16,7 @@
package im.vector.app.test.fakes package im.vector.app.test.fakes
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.BackgroundSyncMode
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import io.mockk.every import io.mockk.every
@ -73,4 +74,14 @@ class FakeVectorPreferences {
fun givenAreNotificationsEnabledForDevice(notificationsEnabled: Boolean) { fun givenAreNotificationsEnabledForDevice(notificationsEnabled: Boolean) {
every { instance.areNotificationEnabledForDevice() } returns notificationsEnabled every { instance.areNotificationEnabledForDevice() } returns notificationsEnabled
} }
fun givenIsBackgroundSyncEnabled(isEnabled: Boolean) {
every { instance.isBackgroundSyncEnabled() } returns isEnabled
}
fun givenChangeOnPreference(key: String) {
every { instance.subscribeToChanges(any()) } answers {
firstArg<OnSharedPreferenceChangeListener>().onSharedPreferenceChanged(mockk(), key)
}
}
} }