Merge pull request #7523 from vector-im/feature/mna/push-toggle-current-session

Push notifications toggle: align implementation for current session (PSG-971)
This commit is contained in:
Maxime NATUREL 2022-11-10 13:44:49 +01:00 committed by GitHub
commit 744b03a806
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 922 additions and 183 deletions

1
changelog.d/7512.feature Normal file
View file

@ -0,0 +1 @@
Push notifications toggle: align implementation for current session

View file

@ -1679,7 +1679,8 @@
<string name="create_new_room">Create New Room</string> <string name="create_new_room">Create New Room</string>
<string name="create_new_space">Create New Space</string> <string name="create_new_space">Create New Space</string>
<string name="error_no_network">No network. Please check your Internet connection.</string> <string name="error_no_network">No network. Please check your Internet connection.</string>
<string name="error_check_network">Something went wrong. Please check your network connection and try again.</string> <!-- TODO delete -->
<string name="error_check_network" tools:ignore="UnusedResources">Something went wrong. Please check your network connection and try again.</string>
<string name="change_room_directory_network">"Change network"</string> <string name="change_room_directory_network">"Change network"</string>
<string name="please_wait">"Please wait…"</string> <string name="please_wait">"Please wait…"</string>
<string name="updating_your_data">Updating your data…</string> <string name="updating_your_data">Updating your data…</string>

View file

@ -16,6 +16,9 @@
package org.matrix.android.sdk.api.session.homeserver package org.matrix.android.sdk.api.session.homeserver
import androidx.lifecycle.LiveData
import org.matrix.android.sdk.api.util.Optional
/** /**
* This interface defines a method to retrieve the homeserver capabilities. * This interface defines a method to retrieve the homeserver capabilities.
*/ */
@ -30,4 +33,9 @@ interface HomeServerCapabilitiesService {
* Get the HomeServer capabilities. * Get the HomeServer capabilities.
*/ */
fun getHomeServerCapabilities(): HomeServerCapabilities fun getHomeServerCapabilities(): HomeServerCapabilities
/**
* Get a LiveData on the HomeServer capabilities.
*/
fun getHomeServerCapabilitiesLive(): LiveData<Optional<HomeServerCapabilities>>
} }

View file

@ -16,8 +16,10 @@
package org.matrix.android.sdk.internal.session.homeserver package org.matrix.android.sdk.internal.session.homeserver
import androidx.lifecycle.LiveData
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
import org.matrix.android.sdk.api.util.Optional
import javax.inject.Inject import javax.inject.Inject
internal class DefaultHomeServerCapabilitiesService @Inject constructor( internal class DefaultHomeServerCapabilitiesService @Inject constructor(
@ -33,4 +35,8 @@ internal class DefaultHomeServerCapabilitiesService @Inject constructor(
return homeServerCapabilitiesDataSource.getHomeServerCapabilities() return homeServerCapabilitiesDataSource.getHomeServerCapabilities()
?: HomeServerCapabilities() ?: HomeServerCapabilities()
} }
override fun getHomeServerCapabilitiesLive(): LiveData<Optional<HomeServerCapabilities>> {
return homeServerCapabilitiesDataSource.getHomeServerCapabilitiesLive()
}
} }

View file

@ -16,9 +16,14 @@
package org.matrix.android.sdk.internal.session.homeserver package org.matrix.android.sdk.internal.session.homeserver
import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import io.realm.Realm import io.realm.Realm
import io.realm.kotlin.where
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.api.util.toOptional
import org.matrix.android.sdk.internal.database.mapper.HomeServerCapabilitiesMapper import org.matrix.android.sdk.internal.database.mapper.HomeServerCapabilitiesMapper
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
import org.matrix.android.sdk.internal.database.query.get import org.matrix.android.sdk.internal.database.query.get
@ -26,7 +31,7 @@ import org.matrix.android.sdk.internal.di.SessionDatabase
import javax.inject.Inject import javax.inject.Inject
internal class HomeServerCapabilitiesDataSource @Inject constructor( internal class HomeServerCapabilitiesDataSource @Inject constructor(
@SessionDatabase private val monarchy: Monarchy @SessionDatabase private val monarchy: Monarchy,
) { ) {
fun getHomeServerCapabilities(): HomeServerCapabilities? { fun getHomeServerCapabilities(): HomeServerCapabilities? {
return Realm.getInstance(monarchy.realmConfiguration).use { realm -> return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
@ -35,4 +40,14 @@ internal class HomeServerCapabilitiesDataSource @Inject constructor(
} }
} }
} }
fun getHomeServerCapabilitiesLive(): LiveData<Optional<HomeServerCapabilities>> {
val liveData = monarchy.findAllMappedWithChanges(
{ realm: Realm -> realm.where<HomeServerCapabilitiesEntity>() },
{ HomeServerCapabilitiesMapper.map(it) }
)
return Transformations.map(liveData) {
it.firstOrNull().toOptional()
}
}
} }

View file

@ -0,0 +1,39 @@
/*
* 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 kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.Session
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class EnableNotificationsSettingUpdater @Inject constructor(
private val updateEnableNotificationsSettingOnChangeUseCase: UpdateEnableNotificationsSettingOnChangeUseCase,
) {
private var job: Job? = null
fun onSessionsStarted(session: Session) {
job?.cancel()
job = session.coroutineScope.launch {
updateEnableNotificationsSettingOnChangeUseCase.execute(session)
}
}
}

View file

@ -0,0 +1,50 @@
/*
* 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.settings.VectorPreferences
import im.vector.app.features.settings.devices.v2.notification.GetNotificationsStatusUseCase
import im.vector.app.features.settings.devices.v2.notification.NotificationsStatus
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.session.Session
import javax.inject.Inject
/**
* Listen for changes in either Pusher or Account data to update the local enable notifications
* setting for the current device.
*/
class UpdateEnableNotificationsSettingOnChangeUseCase @Inject constructor(
private val vectorPreferences: VectorPreferences,
private val getNotificationsStatusUseCase: GetNotificationsStatusUseCase,
) {
suspend fun execute(session: Session) {
val deviceId = session.sessionParams.deviceId ?: return
getNotificationsStatusUseCase.execute(session, deviceId)
.onEach(::updatePreference)
.collect()
}
private fun updatePreference(notificationStatus: NotificationsStatus) {
when (notificationStatus) {
NotificationsStatus.ENABLED -> vectorPreferences.setNotificationEnabledForDevice(true)
NotificationsStatus.DISABLED -> vectorPreferences.setNotificationEnabledForDevice(false)
else -> Unit
}
}
}

View file

@ -97,12 +97,6 @@ class PushersManager @Inject constructor(
return session.pushersService().getPushers().firstOrNull { it.deviceId == deviceId } return session.pushersService().getPushers().firstOrNull { it.deviceId == deviceId }
} }
suspend fun togglePusherForCurrentSession(enable: Boolean) {
val session = activeSessionHolder.getSafeActiveSession() ?: return
val pusher = getPusherForCurrentSession() ?: return
session.pushersService().togglePusher(pusher, enable)
}
suspend fun unregisterEmailPusher(email: String) { suspend fun unregisterEmailPusher(email: String) {
val currentSession = activeSessionHolder.getSafeActiveSession() ?: return val currentSession = activeSessionHolder.getSafeActiveSession() ?: return
currentSession.pushersService().removeEmailPusher(email) currentSession.pushersService().removeEmailPusher(email)

View file

@ -19,6 +19,7 @@ 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.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.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
@ -32,6 +33,7 @@ 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,
) { ) {
suspend fun execute(session: Session, startSyncing: Boolean = true) { suspend fun execute(session: Session, startSyncing: Boolean = true) {
@ -46,5 +48,6 @@ class ConfigureAndStartSessionUseCase @Inject constructor(
if (vectorPreferences.isClientInfoRecordingEnabled()) { if (vectorPreferences.isClientInfoRecordingEnabled()) {
updateMatrixClientInfoUseCase.execute(session) updateMatrixClientInfoUseCase.execute(session)
} }
enableNotificationsSettingUpdater.onSessionsStarted(session)
} }
} }

View file

@ -0,0 +1,38 @@
/*
* 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 androidx.lifecycle.asFlow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.flow.unwrap
import javax.inject.Inject
class CanTogglePushNotificationsViaPusherUseCase @Inject constructor() {
fun execute(session: Session): Flow<Boolean> {
return session
.homeServerCapabilitiesService()
.getHomeServerCapabilitiesLive()
.asFlow()
.unwrap()
.map { it.canRemotelyTogglePushNotificationsOfDevices }
.distinctUntilChanged()
}
}

View file

@ -16,18 +16,15 @@
package im.vector.app.features.settings.devices.v2.notification package im.vector.app.features.settings.devices.v2.notification
import im.vector.app.core.di.ActiveSessionHolder import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes
import javax.inject.Inject import javax.inject.Inject
class CheckIfCanTogglePushNotificationsViaAccountDataUseCase @Inject constructor( class CheckIfCanTogglePushNotificationsViaAccountDataUseCase @Inject constructor() {
private val activeSessionHolder: ActiveSessionHolder,
) {
fun execute(deviceId: String): Boolean { fun execute(session: Session, deviceId: String): Boolean {
return activeSessionHolder return session
.getSafeActiveSession() .accountDataService()
?.accountDataService() .getUserAccountDataEvent(UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId) != null
?.getUserAccountDataEvent(UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId) != null
} }
} }

View file

@ -16,20 +16,15 @@
package im.vector.app.features.settings.devices.v2.notification package im.vector.app.features.settings.devices.v2.notification
import im.vector.app.core.di.ActiveSessionHolder import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.extensions.orFalse
import javax.inject.Inject import javax.inject.Inject
class CheckIfCanTogglePushNotificationsViaPusherUseCase @Inject constructor( class CheckIfCanTogglePushNotificationsViaPusherUseCase @Inject constructor() {
private val activeSessionHolder: ActiveSessionHolder,
) {
fun execute(): Boolean { fun execute(session: Session): Boolean {
return activeSessionHolder return session
.getSafeActiveSession() .homeServerCapabilitiesService()
?.homeServerCapabilitiesService() .getHomeServerCapabilities()
?.getHomeServerCapabilities() .canRemotelyTogglePushNotificationsOfDevices
?.canRemotelyTogglePushNotificationsOfDevices
.orFalse()
} }
} }

View file

@ -16,12 +16,13 @@
package im.vector.app.features.settings.devices.v2.notification package im.vector.app.features.settings.devices.v2.notification
import im.vector.app.core.di.ActiveSessionHolder
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent 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.accountdata.UserAccountDataTypes
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.flow.flow
@ -29,16 +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 activeSessionHolder: ActiveSessionHolder, private val canTogglePushNotificationsViaPusherUseCase: CanTogglePushNotificationsViaPusherUseCase,
private val checkIfCanTogglePushNotificationsViaPusherUseCase: CheckIfCanTogglePushNotificationsViaPusherUseCase,
private val checkIfCanTogglePushNotificationsViaAccountDataUseCase: CheckIfCanTogglePushNotificationsViaAccountDataUseCase, private val checkIfCanTogglePushNotificationsViaAccountDataUseCase: CheckIfCanTogglePushNotificationsViaAccountDataUseCase,
) { ) {
fun execute(deviceId: String): Flow<NotificationsStatus> { fun execute(session: Session, deviceId: String): Flow<NotificationsStatus> {
val session = activeSessionHolder.getSafeActiveSession()
return when { return when {
session == null -> flowOf(NotificationsStatus.NOT_SUPPORTED) checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(session, deviceId) -> {
checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(deviceId) -> {
session.flow() session.flow()
.liveUserAccountData(UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId) .liveUserAccountData(UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId)
.unwrap() .unwrap()
@ -46,15 +44,19 @@ class GetNotificationsStatusUseCase @Inject constructor(
.map { if (it == true) NotificationsStatus.ENABLED else NotificationsStatus.DISABLED } .map { if (it == true) NotificationsStatus.ENABLED else NotificationsStatus.DISABLED }
.distinctUntilChanged() .distinctUntilChanged()
} }
checkIfCanTogglePushNotificationsViaPusherUseCase.execute() -> { else -> canTogglePushNotificationsViaPusherUseCase.execute(session)
session.flow() .flatMapLatest { canToggle ->
.livePushers() if (canToggle) {
.map { it.filter { pusher -> pusher.deviceId == deviceId } } session.flow()
.map { it.takeIf { it.isNotEmpty() }?.any { pusher -> pusher.enabled } } .livePushers()
.map { if (it == true) NotificationsStatus.ENABLED else NotificationsStatus.DISABLED } .map { it.filter { pusher -> pusher.deviceId == deviceId } }
.distinctUntilChanged() .map { it.takeIf { it.isNotEmpty() }?.any { pusher -> pusher.enabled } }
} .map { if (it == true) NotificationsStatus.ENABLED else NotificationsStatus.DISABLED }
else -> flowOf(NotificationsStatus.NOT_SUPPORTED) .distinctUntilChanged()
} else {
flowOf(NotificationsStatus.NOT_SUPPORTED)
}
}
} }
} }
} }

View file

@ -31,14 +31,14 @@ class TogglePushNotificationUseCase @Inject constructor(
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()) { if (checkIfCanTogglePushNotificationsViaPusherUseCase.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(deviceId)) { if (checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(session, deviceId)) {
val newNotificationSettingsContent = LocalNotificationSettingsContent(isSilenced = !enabled) val newNotificationSettingsContent = LocalNotificationSettingsContent(isSilenced = !enabled)
session.accountDataService().updateUserAccountData( session.accountDataService().updateUserAccountData(
UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId, UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId,

View file

@ -96,9 +96,11 @@ class SessionOverviewViewModel @AssistedInject constructor(
} }
private fun observeNotificationsStatus(deviceId: String) { private fun observeNotificationsStatus(deviceId: String) {
getNotificationsStatusUseCase.execute(deviceId) activeSessionHolder.getSafeActiveSession()?.let { session ->
.onEach { setState { copy(notificationsStatus = it) } } getNotificationsStatusUseCase.execute(session, deviceId)
.launchIn(viewModelScope) .onEach { setState { copy(notificationsStatus = it) } }
.launchIn(viewModelScope)
}
} }
override fun handle(action: SessionOverviewAction) { override fun handle(action: SessionOverviewAction) {

View file

@ -0,0 +1,43 @@
/*
* 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.PushersManager
import im.vector.app.core.pushers.UnifiedPushHelper
import im.vector.app.features.settings.devices.v2.notification.CheckIfCanTogglePushNotificationsViaPusherUseCase
import im.vector.app.features.settings.devices.v2.notification.TogglePushNotificationUseCase
import javax.inject.Inject
class DisableNotificationsForCurrentSessionUseCase @Inject constructor(
private val activeSessionHolder: ActiveSessionHolder,
private val unifiedPushHelper: UnifiedPushHelper,
private val pushersManager: PushersManager,
private val checkIfCanTogglePushNotificationsViaPusherUseCase: CheckIfCanTogglePushNotificationsViaPusherUseCase,
private val togglePushNotificationUseCase: TogglePushNotificationUseCase,
) {
suspend fun execute() {
val session = activeSessionHolder.getSafeActiveSession() ?: return
val deviceId = session.sessionParams.deviceId ?: return
if (checkIfCanTogglePushNotificationsViaPusherUseCase.execute(session)) {
togglePushNotificationUseCase.execute(deviceId, enabled = false)
} else {
unifiedPushHelper.unregister(pushersManager)
}
}
}

View file

@ -0,0 +1,71 @@
/*
* 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 androidx.fragment.app.FragmentActivity
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.pushers.FcmHelper
import im.vector.app.core.pushers.PushersManager
import im.vector.app.core.pushers.UnifiedPushHelper
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 kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
class EnableNotificationsForCurrentSessionUseCase @Inject constructor(
private val activeSessionHolder: ActiveSessionHolder,
private val unifiedPushHelper: UnifiedPushHelper,
private val pushersManager: PushersManager,
private val fcmHelper: FcmHelper,
private val checkIfCanTogglePushNotificationsViaPusherUseCase: CheckIfCanTogglePushNotificationsViaPusherUseCase,
private val togglePushNotificationUseCase: TogglePushNotificationUseCase,
) {
suspend fun execute(fragmentActivity: FragmentActivity) {
val pusherForCurrentSession = pushersManager.getPusherForCurrentSession()
if (pusherForCurrentSession == null) {
registerPusher(fragmentActivity)
}
val session = activeSessionHolder.getSafeActiveSession() ?: return
if (checkIfCanTogglePushNotificationsViaPusherUseCase.execute(session)) {
val deviceId = session.sessionParams.deviceId ?: return
togglePushNotificationUseCase.execute(deviceId, enabled = true)
}
}
private suspend fun registerPusher(fragmentActivity: FragmentActivity) {
suspendCoroutine { continuation ->
try {
unifiedPushHelper.register(fragmentActivity) {
if (unifiedPushHelper.isEmbeddedDistributor()) {
fcmHelper.ensureFcmTokenIsRetrieved(
fragmentActivity,
pushersManager,
registerPusher = true
)
}
continuation.resume(Unit)
}
} catch (error: Exception) {
continuation.resumeWithException(error)
}
}
}
}

View file

@ -57,7 +57,6 @@ import im.vector.app.features.settings.VectorSettingsBaseFragment
import im.vector.app.features.settings.VectorSettingsFragmentInteractionListener import im.vector.app.features.settings.VectorSettingsFragmentInteractionListener
import im.vector.lib.core.utils.compat.getParcelableExtraCompat import im.vector.lib.core.utils.compat.getParcelableExtraCompat
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
@ -81,6 +80,8 @@ class VectorSettingsNotificationPreferenceFragment :
@Inject lateinit var guardServiceStarter: GuardServiceStarter @Inject lateinit var guardServiceStarter: GuardServiceStarter
@Inject lateinit var vectorFeatures: VectorFeatures @Inject lateinit var vectorFeatures: VectorFeatures
@Inject lateinit var notificationPermissionManager: NotificationPermissionManager @Inject lateinit var notificationPermissionManager: NotificationPermissionManager
@Inject lateinit var disableNotificationsForCurrentSessionUseCase: DisableNotificationsForCurrentSessionUseCase
@Inject lateinit var enableNotificationsForCurrentSessionUseCase: EnableNotificationsForCurrentSessionUseCase
override var titleRes: Int = R.string.settings_notifications override var titleRes: Int = R.string.settings_notifications
override val preferenceXmlRes = R.xml.vector_settings_notifications override val preferenceXmlRes = R.xml.vector_settings_notifications
@ -119,48 +120,25 @@ class VectorSettingsNotificationPreferenceFragment :
(pref as SwitchPreference).isChecked = areNotifEnabledAtAccountLevel (pref as SwitchPreference).isChecked = areNotifEnabledAtAccountLevel
} }
findPreference<SwitchPreference>(VectorPreferences.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY)?.let { findPreference<SwitchPreference>(VectorPreferences.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY)
pushersManager.getPusherForCurrentSession()?.let { pusher -> ?.setTransactionalSwitchChangeListener(lifecycleScope) { isChecked ->
it.isChecked = pusher.enabled if (isChecked) {
} enableNotificationsForCurrentSessionUseCase.execute(requireActivity())
it.setTransactionalSwitchChangeListener(lifecycleScope) { isChecked ->
if (isChecked) {
unifiedPushHelper.register(requireActivity()) {
// Update the summary
if (unifiedPushHelper.isEmbeddedDistributor()) {
fcmHelper.ensureFcmTokenIsRetrieved(
requireActivity(),
pushersManager,
vectorPreferences.areNotificationEnabledForDevice()
)
}
findPreference<VectorPreference>(VectorPreferences.SETTINGS_NOTIFICATION_METHOD_KEY) findPreference<VectorPreference>(VectorPreferences.SETTINGS_NOTIFICATION_METHOD_KEY)
?.summary = unifiedPushHelper.getCurrentDistributorName() ?.summary = unifiedPushHelper.getCurrentDistributorName()
lifecycleScope.launch {
val result = runCatching {
pushersManager.togglePusherForCurrentSession(true)
}
result.exceptionOrNull()?.let { _ -> notificationPermissionManager.eventuallyRequestPermission(
Toast.makeText(context, R.string.error_check_network, Toast.LENGTH_SHORT).show() requireActivity(),
it.isChecked = false postPermissionLauncher,
} showRationale = false,
} ignorePreference = true
)
} else {
disableNotificationsForCurrentSessionUseCase.execute()
notificationPermissionManager.eventuallyRevokePermission(requireActivity())
} }
notificationPermissionManager.eventuallyRequestPermission(
requireActivity(),
postPermissionLauncher,
showRationale = false,
ignorePreference = true
)
} else {
unifiedPushHelper.unregister(pushersManager)
session.pushersService().refreshPushers()
notificationPermissionManager.eventuallyRevokePermission(requireActivity())
} }
}
}
findPreference<VectorPreference>(VectorPreferences.SETTINGS_FDROID_BACKGROUND_SYNC_MODE)?.let { findPreference<VectorPreference>(VectorPreferences.SETTINGS_FDROID_BACKGROUND_SYNC_MODE)?.let {
it.onPreferenceClickListener = Preference.OnPreferenceClickListener { it.onPreferenceClickListener = Preference.OnPreferenceClickListener {

View file

@ -0,0 +1,90 @@
/*
* 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.settings.devices.v2.notification.NotificationsStatus
import im.vector.app.test.fakes.FakeGetNotificationsStatusUseCase
import im.vector.app.test.fakes.FakeSession
import im.vector.app.test.fakes.FakeVectorPreferences
import kotlinx.coroutines.test.runTest
import org.junit.Test
private const val A_SESSION_ID = "session-id"
class UpdateEnableNotificationsSettingOnChangeUseCaseTest {
private val fakeSession = FakeSession().also { it.givenSessionId(A_SESSION_ID) }
private val fakeVectorPreferences = FakeVectorPreferences()
private val fakeGetNotificationsStatusUseCase = FakeGetNotificationsStatusUseCase()
private val updateEnableNotificationsSettingOnChangeUseCase = UpdateEnableNotificationsSettingOnChangeUseCase(
vectorPreferences = fakeVectorPreferences.instance,
getNotificationsStatusUseCase = fakeGetNotificationsStatusUseCase.instance,
)
@Test
fun `given notifications are enabled when execute then setting is updated to true`() = runTest {
// Given
fakeGetNotificationsStatusUseCase.givenExecuteReturns(
fakeSession,
A_SESSION_ID,
NotificationsStatus.ENABLED,
)
fakeVectorPreferences.givenSetNotificationEnabledForDevice()
// When
updateEnableNotificationsSettingOnChangeUseCase.execute(fakeSession)
// Then
fakeVectorPreferences.verifySetNotificationEnabledForDevice(true)
}
@Test
fun `given notifications are disabled when execute then setting is updated to false`() = runTest {
// Given
fakeGetNotificationsStatusUseCase.givenExecuteReturns(
fakeSession,
A_SESSION_ID,
NotificationsStatus.DISABLED,
)
fakeVectorPreferences.givenSetNotificationEnabledForDevice()
// When
updateEnableNotificationsSettingOnChangeUseCase.execute(fakeSession)
// Then
fakeVectorPreferences.verifySetNotificationEnabledForDevice(false)
}
@Test
fun `given notifications toggle is not supported when execute then nothing is done`() = runTest {
// Given
fakeGetNotificationsStatusUseCase.givenExecuteReturns(
fakeSession,
A_SESSION_ID,
NotificationsStatus.NOT_SUPPORTED,
)
fakeVectorPreferences.givenSetNotificationEnabledForDevice()
// When
updateEnableNotificationsSettingOnChangeUseCase.execute(fakeSession)
// Then
fakeVectorPreferences.verifySetNotificationEnabledForDevice(true, inverse = true)
fakeVectorPreferences.verifySetNotificationEnabledForDevice(false, inverse = true)
}
}

View file

@ -29,7 +29,6 @@ import im.vector.app.test.fixtures.CryptoDeviceInfoFixture.aCryptoDeviceInfo
import im.vector.app.test.fixtures.PusherFixture import im.vector.app.test.fixtures.PusherFixture
import im.vector.app.test.fixtures.SessionParamsFixture import im.vector.app.test.fixtures.SessionParamsFixture
import io.mockk.mockk import io.mockk.mockk
import kotlinx.coroutines.test.runTest
import org.amshove.kluent.shouldBeEqualTo import org.amshove.kluent.shouldBeEqualTo
import org.junit.Test import org.junit.Test
import org.matrix.android.sdk.api.session.crypto.model.UnsignedDeviceInfo import org.matrix.android.sdk.api.session.crypto.model.UnsignedDeviceInfo
@ -101,19 +100,4 @@ class PushersManagerTest {
pusher shouldBeEqualTo expectedPusher pusher shouldBeEqualTo expectedPusher
} }
@Test
fun `when togglePusherForCurrentSession, then do service toggle pusher`() = runTest {
val deviceId = "device_id"
val sessionParams = SessionParamsFixture.aSessionParams(
credentials = CredentialsFixture.aCredentials(deviceId = deviceId)
)
session.givenSessionParams(sessionParams)
val pusher = PusherFixture.aPusher(deviceId = deviceId)
pushersService.givenGetPushers(listOf(pusher))
pushersManager.togglePusherForCurrentSession(true)
pushersService.verifyTogglePusherCalled(pusher, true)
}
} }

View file

@ -19,6 +19,7 @@ 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.test.fakes.FakeContext import im.vector.app.test.fakes.FakeContext
import im.vector.app.test.fakes.FakeEnableNotificationsSettingUpdater
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
@ -43,12 +44,14 @@ 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 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,
) )
@Before @Before
@ -68,6 +71,7 @@ class ConfigureAndStartSessionUseCaseTest {
fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds()
coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) } coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) }
fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = true) fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = true)
fakeEnableNotificationsSettingUpdater.givenOnSessionsStarted(fakeSession)
// When // When
configureAndStartSessionUseCase.execute(fakeSession, startSyncing = true) configureAndStartSessionUseCase.execute(fakeSession, startSyncing = true)
@ -87,6 +91,7 @@ class ConfigureAndStartSessionUseCaseTest {
fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds()
coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) } coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) }
fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = false) fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = false)
fakeEnableNotificationsSettingUpdater.givenOnSessionsStarted(fakeSession)
// When // When
configureAndStartSessionUseCase.execute(fakeSession, startSyncing = true) configureAndStartSessionUseCase.execute(fakeSession, startSyncing = true)
@ -106,6 +111,7 @@ class ConfigureAndStartSessionUseCaseTest {
fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds()
coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) } coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) }
fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = true) fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = true)
fakeEnableNotificationsSettingUpdater.givenOnSessionsStarted(fakeSession)
// When // When
configureAndStartSessionUseCase.execute(fakeSession, startSyncing = false) configureAndStartSessionUseCase.execute(fakeSession, startSyncing = false)

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.features.settings.devices.v2.notification
import im.vector.app.test.fakes.FakeFlowLiveDataConversions
import im.vector.app.test.fakes.FakeSession
import im.vector.app.test.fakes.givenAsFlow
import im.vector.app.test.fixtures.aHomeServerCapabilities
import io.mockk.unmockkAll
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.test.runTest
import org.amshove.kluent.shouldBeEqualTo
import org.junit.After
import org.junit.Before
import org.junit.Test
private val A_HOMESERVER_CAPABILITIES = aHomeServerCapabilities(canRemotelyTogglePushNotificationsOfDevices = true)
class CanTogglePushNotificationsViaPusherUseCaseTest {
private val fakeSession = FakeSession()
private val fakeFlowLiveDataConversions = FakeFlowLiveDataConversions()
private val canTogglePushNotificationsViaPusherUseCase =
CanTogglePushNotificationsViaPusherUseCase()
@Before
fun setUp() {
fakeFlowLiveDataConversions.setup()
}
@After
fun tearDown() {
unmockkAll()
}
@Test
fun `given current session when execute then flow of the toggle capability is returned`() = runTest {
// Given
fakeSession
.fakeHomeServerCapabilitiesService
.givenCapabilitiesLiveReturns(A_HOMESERVER_CAPABILITIES)
.givenAsFlow()
// When
val result = canTogglePushNotificationsViaPusherUseCase.execute(fakeSession).firstOrNull()
// Then
result shouldBeEqualTo A_HOMESERVER_CAPABILITIES.canRemotelyTogglePushNotificationsOfDevices
}
}

View file

@ -16,7 +16,7 @@
package im.vector.app.features.settings.devices.v2.notification package im.vector.app.features.settings.devices.v2.notification
import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeSession
import io.mockk.mockk import io.mockk.mockk
import org.amshove.kluent.shouldBeEqualTo import org.amshove.kluent.shouldBeEqualTo
import org.junit.Test import org.junit.Test
@ -26,18 +26,15 @@ private const val A_DEVICE_ID = "device-id"
class CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest { class CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest {
private val fakeActiveSessionHolder = FakeActiveSessionHolder() private val fakeSession = FakeSession()
private val checkIfCanTogglePushNotificationsViaAccountDataUseCase = private val checkIfCanTogglePushNotificationsViaAccountDataUseCase =
CheckIfCanTogglePushNotificationsViaAccountDataUseCase( CheckIfCanTogglePushNotificationsViaAccountDataUseCase()
activeSessionHolder = fakeActiveSessionHolder.instance,
)
@Test @Test
fun `given current session and an account data for the device id when execute then result is true`() { fun `given current session and an account data for the device id when execute then result is true`() {
// Given // Given
fakeActiveSessionHolder fakeSession
.fakeSession
.accountDataService() .accountDataService()
.givenGetUserAccountDataEventReturns( .givenGetUserAccountDataEventReturns(
type = UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + A_DEVICE_ID, type = UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + A_DEVICE_ID,
@ -45,7 +42,7 @@ class CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest {
) )
// When // When
val result = checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(A_DEVICE_ID) val result = checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID)
// Then // Then
result shouldBeEqualTo true result shouldBeEqualTo true
@ -54,8 +51,7 @@ class CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest {
@Test @Test
fun `given current session and NO account data for the device id when execute then result is false`() { fun `given current session and NO account data for the device id when execute then result is false`() {
// Given // Given
fakeActiveSessionHolder fakeSession
.fakeSession
.accountDataService() .accountDataService()
.givenGetUserAccountDataEventReturns( .givenGetUserAccountDataEventReturns(
type = UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + A_DEVICE_ID, type = UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + A_DEVICE_ID,
@ -63,7 +59,7 @@ class CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest {
) )
// When // When
val result = checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(A_DEVICE_ID) val result = checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID)
// Then // Then
result shouldBeEqualTo false result shouldBeEqualTo false

View file

@ -16,7 +16,7 @@
package im.vector.app.features.settings.devices.v2.notification package im.vector.app.features.settings.devices.v2.notification
import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeSession
import im.vector.app.test.fixtures.aHomeServerCapabilities import im.vector.app.test.fixtures.aHomeServerCapabilities
import org.amshove.kluent.shouldBeEqualTo import org.amshove.kluent.shouldBeEqualTo
import org.junit.Test import org.junit.Test
@ -25,37 +25,22 @@ private val A_HOMESERVER_CAPABILITIES = aHomeServerCapabilities(canRemotelyToggl
class CheckIfCanTogglePushNotificationsViaPusherUseCaseTest { class CheckIfCanTogglePushNotificationsViaPusherUseCaseTest {
private val fakeActiveSessionHolder = FakeActiveSessionHolder() private val fakeSession = FakeSession()
private val checkIfCanTogglePushNotificationsViaPusherUseCase = private val checkIfCanTogglePushNotificationsViaPusherUseCase =
CheckIfCanTogglePushNotificationsViaPusherUseCase( CheckIfCanTogglePushNotificationsViaPusherUseCase()
activeSessionHolder = fakeActiveSessionHolder.instance,
)
@Test @Test
fun `given current session when execute then toggle capability is returned`() { fun `given current session when execute then toggle capability is returned`() {
// Given // Given
fakeActiveSessionHolder fakeSession
.fakeSession
.fakeHomeServerCapabilitiesService .fakeHomeServerCapabilitiesService
.givenCapabilities(A_HOMESERVER_CAPABILITIES) .givenCapabilities(A_HOMESERVER_CAPABILITIES)
// When // When
val result = checkIfCanTogglePushNotificationsViaPusherUseCase.execute() val result = checkIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession)
// Then // Then
result shouldBeEqualTo A_HOMESERVER_CAPABILITIES.canRemotelyTogglePushNotificationsOfDevices result shouldBeEqualTo A_HOMESERVER_CAPABILITIES.canRemotelyTogglePushNotificationsOfDevices
} }
@Test
fun `given no current session when execute then false is returned`() {
// Given
fakeActiveSessionHolder.givenGetSafeActiveSessionReturns(null)
// When
val result = checkIfCanTogglePushNotificationsViaPusherUseCase.execute()
// Then
result shouldBeEqualTo false
}
} }

View file

@ -17,7 +17,7 @@
package im.vector.app.features.settings.devices.v2.notification package im.vector.app.features.settings.devices.v2.notification
import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeSession
import im.vector.app.test.fixtures.PusherFixture import im.vector.app.test.fixtures.PusherFixture
import im.vector.app.test.testDispatcher import im.vector.app.test.testDispatcher
import io.mockk.every import io.mockk.every
@ -25,6 +25,7 @@ import io.mockk.mockk
import io.mockk.verifyOrder import io.mockk.verifyOrder
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.setMain import kotlinx.coroutines.test.setMain
@ -44,17 +45,16 @@ class GetNotificationsStatusUseCaseTest {
@get:Rule @get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule() val instantTaskExecutorRule = InstantTaskExecutorRule()
private val fakeActiveSessionHolder = FakeActiveSessionHolder() private val fakeSession = FakeSession()
private val fakeCheckIfCanTogglePushNotificationsViaPusherUseCase =
mockk<CheckIfCanTogglePushNotificationsViaPusherUseCase>()
private val fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase = private val fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase =
mockk<CheckIfCanTogglePushNotificationsViaAccountDataUseCase>() mockk<CheckIfCanTogglePushNotificationsViaAccountDataUseCase>()
private val fakeCanTogglePushNotificationsViaPusherUseCase =
mockk<CanTogglePushNotificationsViaPusherUseCase>()
private val getNotificationsStatusUseCase = private val getNotificationsStatusUseCase =
GetNotificationsStatusUseCase( GetNotificationsStatusUseCase(
activeSessionHolder = fakeActiveSessionHolder.instance,
checkIfCanTogglePushNotificationsViaPusherUseCase = fakeCheckIfCanTogglePushNotificationsViaPusherUseCase,
checkIfCanTogglePushNotificationsViaAccountDataUseCase = fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase, checkIfCanTogglePushNotificationsViaAccountDataUseCase = fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase,
canTogglePushNotificationsViaPusherUseCase = fakeCanTogglePushNotificationsViaPusherUseCase,
) )
@Before @Before
@ -67,33 +67,21 @@ class GetNotificationsStatusUseCaseTest {
Dispatchers.resetMain() Dispatchers.resetMain()
} }
@Test
fun `given NO current session when execute then resulting flow contains NOT_SUPPORTED value`() = runTest {
// Given
fakeActiveSessionHolder.givenGetSafeActiveSessionReturns(null)
// When
val result = getNotificationsStatusUseCase.execute(A_DEVICE_ID)
// Then
result.firstOrNull() shouldBeEqualTo NotificationsStatus.NOT_SUPPORTED
}
@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 { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute() } returns false every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns false
every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(A_DEVICE_ID) } returns false every { fakeCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(false)
// When // When
val result = getNotificationsStatusUseCase.execute(A_DEVICE_ID) val result = getNotificationsStatusUseCase.execute(fakeSession, A_DEVICE_ID)
// Then // Then
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(A_DEVICE_ID) fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID)
fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute() fakeCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession)
} }
} }
@ -106,12 +94,12 @@ class GetNotificationsStatusUseCaseTest {
enabled = true, enabled = true,
) )
) )
fakeActiveSessionHolder.fakeSession.pushersService().givenPushersLive(pushers) fakeSession.pushersService().givenPushersLive(pushers)
every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute() } returns true every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns false
every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(A_DEVICE_ID) } returns false every { fakeCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(true)
// When // When
val result = getNotificationsStatusUseCase.execute(A_DEVICE_ID) val result = getNotificationsStatusUseCase.execute(fakeSession, A_DEVICE_ID)
// Then // Then
result.firstOrNull() shouldBeEqualTo NotificationsStatus.ENABLED result.firstOrNull() shouldBeEqualTo NotificationsStatus.ENABLED
@ -120,8 +108,7 @@ class GetNotificationsStatusUseCaseTest {
@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
fakeActiveSessionHolder fakeSession
.fakeSession
.accountDataService() .accountDataService()
.givenGetUserAccountDataEventReturns( .givenGetUserAccountDataEventReturns(
type = UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + A_DEVICE_ID, type = UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + A_DEVICE_ID,
@ -129,11 +116,11 @@ class GetNotificationsStatusUseCaseTest {
isSilenced = false isSilenced = false
).toContent(), ).toContent(),
) )
every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute() } returns false every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns true
every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(A_DEVICE_ID) } returns true every { fakeCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(false)
// When // When
val result = getNotificationsStatusUseCase.execute(A_DEVICE_ID) val result = getNotificationsStatusUseCase.execute(fakeSession, A_DEVICE_ID)
// Then // Then
result.firstOrNull() shouldBeEqualTo NotificationsStatus.ENABLED result.firstOrNull() shouldBeEqualTo NotificationsStatus.ENABLED

View file

@ -49,10 +49,11 @@ class TogglePushNotificationUseCaseTest {
PusherFixture.aPusher(deviceId = sessionId, enabled = false), PusherFixture.aPusher(deviceId = sessionId, enabled = false),
PusherFixture.aPusher(deviceId = "another id", enabled = false) PusherFixture.aPusher(deviceId = "another id", enabled = false)
) )
activeSessionHolder.fakeSession.pushersService().givenPushersLive(pushers) val fakeSession = activeSessionHolder.fakeSession
activeSessionHolder.fakeSession.pushersService().givenGetPushers(pushers) fakeSession.pushersService().givenPushersLive(pushers)
every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute() } returns true fakeSession.pushersService().givenGetPushers(pushers)
every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(sessionId) } returns false every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns true
every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, sessionId) } returns false
// When // When
togglePushNotificationUseCase.execute(sessionId, true) togglePushNotificationUseCase.execute(sessionId, true)
@ -69,13 +70,14 @@ class TogglePushNotificationUseCaseTest {
PusherFixture.aPusher(deviceId = sessionId, enabled = false), PusherFixture.aPusher(deviceId = sessionId, enabled = false),
PusherFixture.aPusher(deviceId = "another id", enabled = false) PusherFixture.aPusher(deviceId = "another id", enabled = false)
) )
activeSessionHolder.fakeSession.pushersService().givenPushersLive(pushers) val fakeSession = activeSessionHolder.fakeSession
activeSessionHolder.fakeSession.accountDataService().givenGetUserAccountDataEventReturns( fakeSession.pushersService().givenPushersLive(pushers)
fakeSession.accountDataService().givenGetUserAccountDataEventReturns(
UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + sessionId, UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + sessionId,
LocalNotificationSettingsContent(isSilenced = true).toContent() LocalNotificationSettingsContent(isSilenced = true).toContent()
) )
every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute() } returns false every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns false
every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(sessionId) } returns true every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, sessionId) } returns true
// When // When
togglePushNotificationUseCase.execute(sessionId, true) togglePushNotificationUseCase.execute(sessionId, true)

View file

@ -22,11 +22,11 @@ import com.airbnb.mvrx.Success
import com.airbnb.mvrx.test.MavericksTestRule import com.airbnb.mvrx.test.MavericksTestRule
import im.vector.app.features.settings.devices.v2.DeviceFullInfo 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.notification.GetNotificationsStatusUseCase
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.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.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.FakeTogglePushNotificationUseCase
@ -75,7 +75,7 @@ class SessionOverviewViewModelTest {
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 togglePushNotificationUseCase = FakeTogglePushNotificationUseCase()
private val fakeGetNotificationsStatusUseCase = mockk<GetNotificationsStatusUseCase>() private val fakeGetNotificationsStatusUseCase = FakeGetNotificationsStatusUseCase()
private val notificationsStatus = NotificationsStatus.ENABLED private val notificationsStatus = NotificationsStatus.ENABLED
private fun createViewModel() = SessionOverviewViewModel( private fun createViewModel() = SessionOverviewViewModel(
@ -88,7 +88,7 @@ class SessionOverviewViewModelTest {
activeSessionHolder = fakeActiveSessionHolder.instance, activeSessionHolder = fakeActiveSessionHolder.instance,
refreshDevicesUseCase = refreshDevicesUseCase, refreshDevicesUseCase = refreshDevicesUseCase,
togglePushNotificationUseCase = togglePushNotificationUseCase.instance, togglePushNotificationUseCase = togglePushNotificationUseCase.instance,
getNotificationsStatusUseCase = fakeGetNotificationsStatusUseCase, getNotificationsStatusUseCase = fakeGetNotificationsStatusUseCase.instance,
) )
@Before @Before
@ -98,7 +98,11 @@ class SessionOverviewViewModelTest {
every { SystemClock.elapsedRealtime() } returns 1234 every { SystemClock.elapsedRealtime() } returns 1234
givenVerificationService() givenVerificationService()
every { fakeGetNotificationsStatusUseCase.execute(A_SESSION_ID_1) } returns flowOf(notificationsStatus) fakeGetNotificationsStatusUseCase.givenExecuteReturns(
fakeActiveSessionHolder.fakeSession,
A_SESSION_ID_1,
notificationsStatus
)
} }
private fun givenVerificationService(): FakeVerificationService { private fun givenVerificationService(): FakeVerificationService {
@ -412,13 +416,10 @@ class SessionOverviewViewModelTest {
@Test @Test
fun `when viewModel init, then observe pushers and emit to state`() { fun `when viewModel init, then observe pushers and emit to state`() {
val notificationStatus = NotificationsStatus.ENABLED
every { fakeGetNotificationsStatusUseCase.execute(A_SESSION_ID_1) } returns flowOf(notificationStatus)
val viewModel = createViewModel() val viewModel = createViewModel()
viewModel.test() viewModel.test()
.assertLatestState { state -> state.notificationsStatus == notificationStatus } .assertLatestState { state -> state.notificationsStatus == notificationsStatus }
.finish() .finish()
} }

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.notifications
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.FakeUnifiedPushHelper
import io.mockk.coJustRun
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.test.runTest
import org.junit.Test
private const val A_SESSION_ID = "session-id"
class DisableNotificationsForCurrentSessionUseCaseTest {
private val fakeActiveSessionHolder = FakeActiveSessionHolder()
private val fakeUnifiedPushHelper = FakeUnifiedPushHelper()
private val fakePushersManager = FakePushersManager()
private val fakeCheckIfCanTogglePushNotificationsViaPusherUseCase = mockk<CheckIfCanTogglePushNotificationsViaPusherUseCase>()
private val fakeTogglePushNotificationUseCase = mockk<TogglePushNotificationUseCase>()
private val disableNotificationsForCurrentSessionUseCase = DisableNotificationsForCurrentSessionUseCase(
activeSessionHolder = fakeActiveSessionHolder.instance,
unifiedPushHelper = fakeUnifiedPushHelper.instance,
pushersManager = fakePushersManager.instance,
checkIfCanTogglePushNotificationsViaPusherUseCase = fakeCheckIfCanTogglePushNotificationsViaPusherUseCase,
togglePushNotificationUseCase = fakeTogglePushNotificationUseCase,
)
@Test
fun `given toggle via pusher is possible when execute then disable notification via toggle of existing pusher`() = runTest {
// Given
val fakeSession = fakeActiveSessionHolder.fakeSession
fakeSession.givenSessionId(A_SESSION_ID)
every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns true
coJustRun { fakeTogglePushNotificationUseCase.execute(A_SESSION_ID, any()) }
// When
disableNotificationsForCurrentSessionUseCase.execute()
// Then
coVerify { fakeTogglePushNotificationUseCase.execute(A_SESSION_ID, false) }
}
@Test
fun `given toggle via pusher is NOT possible when execute then disable notification by unregistering the pusher`() = runTest {
// Given
val fakeSession = fakeActiveSessionHolder.fakeSession
fakeSession.givenSessionId(A_SESSION_ID)
every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns false
fakeUnifiedPushHelper.givenUnregister(fakePushersManager.instance)
// When
disableNotificationsForCurrentSessionUseCase.execute()
// Then
fakeUnifiedPushHelper.verifyUnregister(fakePushersManager.instance)
}
}

View file

@ -0,0 +1,87 @@
/*
* 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 androidx.fragment.app.FragmentActivity
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.FakeFcmHelper
import im.vector.app.test.fakes.FakePushersManager
import im.vector.app.test.fakes.FakeUnifiedPushHelper
import io.mockk.coJustRun
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.test.runTest
import org.junit.Test
private const val A_SESSION_ID = "session-id"
class EnableNotificationsForCurrentSessionUseCaseTest {
private val fakeActiveSessionHolder = FakeActiveSessionHolder()
private val fakeUnifiedPushHelper = FakeUnifiedPushHelper()
private val fakePushersManager = FakePushersManager()
private val fakeFcmHelper = FakeFcmHelper()
private val fakeCheckIfCanTogglePushNotificationsViaPusherUseCase = mockk<CheckIfCanTogglePushNotificationsViaPusherUseCase>()
private val fakeTogglePushNotificationUseCase = mockk<TogglePushNotificationUseCase>()
private val enableNotificationsForCurrentSessionUseCase = EnableNotificationsForCurrentSessionUseCase(
activeSessionHolder = fakeActiveSessionHolder.instance,
unifiedPushHelper = fakeUnifiedPushHelper.instance,
pushersManager = fakePushersManager.instance,
fcmHelper = fakeFcmHelper.instance,
checkIfCanTogglePushNotificationsViaPusherUseCase = fakeCheckIfCanTogglePushNotificationsViaPusherUseCase,
togglePushNotificationUseCase = fakeTogglePushNotificationUseCase,
)
@Test
fun `given no existing pusher for current session when execute then a new pusher is registered`() = runTest {
// Given
val fragmentActivity = mockk<FragmentActivity>()
fakePushersManager.givenGetPusherForCurrentSessionReturns(null)
fakeUnifiedPushHelper.givenRegister(fragmentActivity)
fakeUnifiedPushHelper.givenIsEmbeddedDistributorReturns(true)
fakeFcmHelper.givenEnsureFcmTokenIsRetrieved(fragmentActivity, fakePushersManager.instance)
every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeActiveSessionHolder.fakeSession) } returns false
// When
enableNotificationsForCurrentSessionUseCase.execute(fragmentActivity)
// Then
fakeUnifiedPushHelper.verifyRegister(fragmentActivity)
fakeFcmHelper.verifyEnsureFcmTokenIsRetrieved(fragmentActivity, fakePushersManager.instance, registerPusher = true)
}
@Test
fun `given toggle via Pusher is possible when execute then current pusher is toggled to true`() = runTest {
// Given
val fragmentActivity = mockk<FragmentActivity>()
fakePushersManager.givenGetPusherForCurrentSessionReturns(mockk())
val fakeSession = fakeActiveSessionHolder.fakeSession
fakeSession.givenSessionId(A_SESSION_ID)
every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeActiveSessionHolder.fakeSession) } returns true
coJustRun { fakeTogglePushNotificationUseCase.execute(A_SESSION_ID, any()) }
// When
enableNotificationsForCurrentSessionUseCase.execute(fragmentActivity)
// Then
coVerify { fakeTogglePushNotificationUseCase.execute(A_SESSION_ID, true) }
}
}

View file

@ -0,0 +1,31 @@
/*
* 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.test.fakes
import im.vector.app.core.notification.EnableNotificationsSettingUpdater
import io.mockk.justRun
import io.mockk.mockk
import org.matrix.android.sdk.api.session.Session
class FakeEnableNotificationsSettingUpdater {
val instance = mockk<EnableNotificationsSettingUpdater>()
fun givenOnSessionsStarted(session: Session) {
justRun { instance.onSessionsStarted(session) }
}
}

View file

@ -0,0 +1,44 @@
/*
* 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.test.fakes
import androidx.fragment.app.FragmentActivity
import im.vector.app.core.pushers.FcmHelper
import im.vector.app.core.pushers.PushersManager
import io.mockk.justRun
import io.mockk.mockk
import io.mockk.verify
class FakeFcmHelper {
val instance = mockk<FcmHelper>()
fun givenEnsureFcmTokenIsRetrieved(
fragmentActivity: FragmentActivity,
pushersManager: PushersManager,
) {
justRun { instance.ensureFcmTokenIsRetrieved(fragmentActivity, pushersManager, any()) }
}
fun verifyEnsureFcmTokenIsRetrieved(
fragmentActivity: FragmentActivity,
pushersManager: PushersManager,
registerPusher: Boolean,
) {
verify { instance.ensureFcmTokenIsRetrieved(fragmentActivity, pushersManager, registerPusher) }
}
}

View file

@ -0,0 +1,37 @@
/*
* 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.test.fakes
import im.vector.app.features.settings.devices.v2.notification.GetNotificationsStatusUseCase
import im.vector.app.features.settings.devices.v2.notification.NotificationsStatus
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.flow.flowOf
import org.matrix.android.sdk.api.session.Session
class FakeGetNotificationsStatusUseCase {
val instance = mockk<GetNotificationsStatusUseCase>()
fun givenExecuteReturns(
session: Session,
sessionId: String,
notificationsStatus: NotificationsStatus
) {
every { instance.execute(session, sessionId) } returns flowOf(notificationsStatus)
}
}

View file

@ -16,14 +16,24 @@
package im.vector.app.test.fakes package im.vector.app.test.fakes
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.api.util.toOptional
class FakeHomeServerCapabilitiesService : HomeServerCapabilitiesService by mockk() { class FakeHomeServerCapabilitiesService : HomeServerCapabilitiesService by mockk() {
fun givenCapabilities(homeServerCapabilities: HomeServerCapabilities) { fun givenCapabilities(homeServerCapabilities: HomeServerCapabilities) {
every { getHomeServerCapabilities() } returns homeServerCapabilities every { getHomeServerCapabilities() } returns homeServerCapabilities
} }
fun givenCapabilitiesLiveReturns(homeServerCapabilities: HomeServerCapabilities): LiveData<Optional<HomeServerCapabilities>> {
return MutableLiveData(homeServerCapabilities.toOptional()).also {
every { getHomeServerCapabilitiesLive() } returns it
}
}
} }

View file

@ -0,0 +1,31 @@
/*
* 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.test.fakes
import im.vector.app.core.pushers.PushersManager
import io.mockk.every
import io.mockk.mockk
import org.matrix.android.sdk.api.session.pushers.Pusher
class FakePushersManager {
val instance = mockk<PushersManager>()
fun givenGetPusherForCurrentSessionReturns(pusher: Pusher?) {
every { instance.getPusherForCurrentSession() } returns pusher
}
}

View file

@ -0,0 +1,53 @@
/*
* 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.test.fakes
import androidx.fragment.app.FragmentActivity
import im.vector.app.core.pushers.PushersManager
import im.vector.app.core.pushers.UnifiedPushHelper
import io.mockk.coJustRun
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
class FakeUnifiedPushHelper {
val instance = mockk<UnifiedPushHelper>()
fun givenRegister(fragmentActivity: FragmentActivity) {
every { instance.register(fragmentActivity, any()) } answers {
secondArg<Runnable>().run()
}
}
fun verifyRegister(fragmentActivity: FragmentActivity) {
verify { instance.register(fragmentActivity, any()) }
}
fun givenUnregister(pushersManager: PushersManager) {
coJustRun { instance.unregister(pushersManager) }
}
fun verifyUnregister(pushersManager: PushersManager) {
coVerify { instance.unregister(pushersManager) }
}
fun givenIsEmbeddedDistributorReturns(isEmbedded: Boolean) {
every { instance.isEmbeddedDistributor() } returns isEmbedded
}
}

View file

@ -18,6 +18,7 @@ package im.vector.app.test.fakes
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import io.mockk.every import io.mockk.every
import io.mockk.justRun
import io.mockk.mockk import io.mockk.mockk
import io.mockk.verify import io.mockk.verify
@ -42,5 +43,13 @@ class FakeVectorPreferences {
} }
fun givenTextFormatting(isEnabled: Boolean) = fun givenTextFormatting(isEnabled: Boolean) =
every { instance.isTextFormattingEnabled() } returns isEnabled every { instance.isTextFormattingEnabled() } returns isEnabled
fun givenSetNotificationEnabledForDevice() {
justRun { instance.setNotificationEnabledForDevice(any()) }
}
fun verifySetNotificationEnabledForDevice(enabled: Boolean, inverse: Boolean = false) {
verify(inverse = inverse) { instance.setNotificationEnabledForDevice(enabled) }
}
} }