Device Manager Notification and Pusher Fixes (#7370)

* Fixes existing pushers being overwritten on app startup

* Refreshes pushers in SessionOverview screen

* Fixes push toggle not working for non pusher sessions

* Various code improvements

* Further code improvements for safety

* Fixes CI errors
This commit is contained in:
Eric Decanini 2022-10-14 15:02:11 -04:00 committed by GitHub
parent ba49ee4e13
commit 75c97bc7c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 211 additions and 55 deletions

View File

@ -218,7 +218,7 @@ class HomeActivity :
fcmHelper.ensureFcmTokenIsRetrieved( fcmHelper.ensureFcmTokenIsRetrieved(
this, this,
pushersManager, pushersManager,
vectorPreferences.areNotificationEnabledForDevice() homeActivityViewModel.shouldAddHttpPusher()
) )
} }
} }

View File

@ -143,6 +143,14 @@ class HomeActivityViewModel @AssistedInject constructor(
} }
} }
fun shouldAddHttpPusher() = if (vectorPreferences.areNotificationEnabledForDevice()) {
val currentSession = activeSessionHolder.getActiveSession()
val currentPushers = currentSession.pushersService().getPushers()
currentPushers.none { it.deviceId == currentSession.sessionParams.deviceId }
} else {
false
}
fun observeLocalNotificationsSilenced() { fun observeLocalNotificationsSilenced() {
val currentSession = activeSessionHolder.getActiveSession() val currentSession = activeSessionHolder.getActiveSession()
val deviceId = currentSession.cryptoService().getMyDevice().deviceId val deviceId = currentSession.cryptoService().getMyDevice().deviceId

View File

@ -47,7 +47,6 @@ import im.vector.app.features.workers.signout.SignOutUiWorker
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.session.pushers.Pusher
import javax.inject.Inject import javax.inject.Inject
/** /**
@ -178,7 +177,7 @@ class SessionOverviewFragment :
updateEntryDetails(state.deviceId) updateEntryDetails(state.deviceId)
updateSessionInfo(state) updateSessionInfo(state)
updateLoading(state.isLoading) updateLoading(state.isLoading)
updatePushNotificationToggle(state.deviceId, state.pushers.invoke().orEmpty()) updatePushNotificationToggle(state.deviceId, state.notificationsEnabled)
} }
private fun updateToolbar(viewState: SessionOverviewViewState) { private fun updateToolbar(viewState: SessionOverviewViewState) {
@ -219,14 +218,10 @@ class SessionOverviewFragment :
} }
} }
private fun updatePushNotificationToggle(deviceId: String, pushers: List<Pusher>) { private fun updatePushNotificationToggle(deviceId: String, enabled: Boolean) {
views.sessionOverviewPushNotifications.apply { views.sessionOverviewPushNotifications.apply {
if (pushers.isEmpty()) {
isVisible = false
} else {
val allPushersAreEnabled = pushers.all { it.enabled }
setOnCheckedChangeListener(null) setOnCheckedChangeListener(null)
setChecked(allPushersAreEnabled) setChecked(enabled)
post { post {
setOnCheckedChangeListener { _, isChecked -> setOnCheckedChangeListener { _, isChecked ->
viewModel.handle(SessionOverviewAction.TogglePushNotifications(deviceId, isChecked)) viewModel.handle(SessionOverviewAction.TogglePushNotifications(deviceId, isChecked))
@ -234,7 +229,6 @@ class SessionOverviewFragment :
} }
} }
} }
}
private fun updateLoading(isLoading: Boolean) { private fun updateLoading(isLoading: Boolean) {
if (isLoading) { if (isLoading) {

View File

@ -36,24 +36,27 @@ import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSes
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent
import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UIABaseAuth
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth
import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.flow.unwrap
import timber.log.Timber import timber.log.Timber
import javax.net.ssl.HttpsURLConnection import javax.net.ssl.HttpsURLConnection
import kotlin.coroutines.Continuation import kotlin.coroutines.Continuation
class SessionOverviewViewModel @AssistedInject constructor( class SessionOverviewViewModel @AssistedInject constructor(
@Assisted val initialState: SessionOverviewViewState, @Assisted val initialState: SessionOverviewViewState,
private val session: Session,
private val stringProvider: StringProvider, private val stringProvider: StringProvider,
private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase, private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase,
private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase, private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase,
@ -61,6 +64,7 @@ class SessionOverviewViewModel @AssistedInject constructor(
private val interceptSignoutFlowResponseUseCase: InterceptSignoutFlowResponseUseCase, private val interceptSignoutFlowResponseUseCase: InterceptSignoutFlowResponseUseCase,
private val pendingAuthHandler: PendingAuthHandler, private val pendingAuthHandler: PendingAuthHandler,
private val activeSessionHolder: ActiveSessionHolder, private val activeSessionHolder: ActiveSessionHolder,
private val togglePushNotificationUseCase: TogglePushNotificationUseCase,
refreshDevicesUseCase: RefreshDevicesUseCase, refreshDevicesUseCase: RefreshDevicesUseCase,
) : VectorSessionsListViewModel<SessionOverviewViewState, SessionOverviewAction, SessionOverviewViewEvent>( ) : VectorSessionsListViewModel<SessionOverviewViewState, SessionOverviewAction, SessionOverviewViewEvent>(
initialState, activeSessionHolder, refreshDevicesUseCase initialState, activeSessionHolder, refreshDevicesUseCase
@ -74,11 +78,16 @@ class SessionOverviewViewModel @AssistedInject constructor(
} }
init { init {
refreshPushers()
observeSessionInfo(initialState.deviceId) observeSessionInfo(initialState.deviceId)
observeCurrentSessionInfo() observeCurrentSessionInfo()
observePushers(initialState.deviceId) observePushers(initialState.deviceId)
} }
private fun refreshPushers() {
activeSessionHolder.getSafeActiveSession()?.pushersService()?.refreshPushers()
}
private fun observeSessionInfo(deviceId: String) { private fun observeSessionInfo(deviceId: String) {
getDeviceFullInfoUseCase.execute(deviceId) getDeviceFullInfoUseCase.execute(deviceId)
.onEach { setState { copy(deviceInfo = Success(it)) } } .onEach { setState { copy(deviceInfo = Success(it)) } }
@ -99,10 +108,20 @@ class SessionOverviewViewModel @AssistedInject constructor(
} }
private fun observePushers(deviceId: String) { private fun observePushers(deviceId: String) {
session.flow() val session = activeSessionHolder.getSafeActiveSession() ?: return
val pusherFlow = session.flow()
.livePushers() .livePushers()
.map { it.filter { pusher -> pusher.deviceId == deviceId } } .map { it.filter { pusher -> pusher.deviceId == deviceId } }
.execute { copy(pushers = it) } .map { it.takeIf { it.isNotEmpty() }?.any { pusher -> pusher.enabled } }
val accountDataFlow = session.flow()
.liveUserAccountData(TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId)
.unwrap()
.map { it.content.toModel<LocalNotificationSettingsContent>()?.isSilenced?.not() }
merge(pusherFlow, accountDataFlow)
.onEach { it?.let { setState { copy(notificationsEnabled = it) } } }
.launchIn(viewModelScope)
} }
override fun handle(action: SessionOverviewAction) { override fun handle(action: SessionOverviewAction) {
@ -213,10 +232,8 @@ class SessionOverviewViewModel @AssistedInject constructor(
private fun handleTogglePusherAction(action: SessionOverviewAction.TogglePushNotifications) { private fun handleTogglePusherAction(action: SessionOverviewAction.TogglePushNotifications) {
viewModelScope.launch { viewModelScope.launch {
val devicePushers = awaitState().pushers.invoke()?.filter { it.deviceId == action.deviceId } togglePushNotificationUseCase.execute(action.deviceId, action.enabled)
devicePushers?.forEach { pusher -> setState { copy(notificationsEnabled = action.enabled) }
session.pushersService().togglePusher(pusher, action.enabled)
}
} }
} }
} }

View File

@ -20,14 +20,13 @@ import com.airbnb.mvrx.Async
import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.Uninitialized
import im.vector.app.features.settings.devices.v2.DeviceFullInfo import im.vector.app.features.settings.devices.v2.DeviceFullInfo
import org.matrix.android.sdk.api.session.pushers.Pusher
data class SessionOverviewViewState( data class SessionOverviewViewState(
val deviceId: String, val deviceId: String,
val isCurrentSessionTrusted: Boolean = false, val isCurrentSessionTrusted: Boolean = false,
val deviceInfo: Async<DeviceFullInfo> = Uninitialized, val deviceInfo: Async<DeviceFullInfo> = Uninitialized,
val isLoading: Boolean = false, val isLoading: Boolean = false,
val pushers: Async<List<Pusher>> = Uninitialized, val notificationsEnabled: Boolean = false,
) : MavericksState { ) : MavericksState {
constructor(args: SessionOverviewArgs) : this( constructor(args: SessionOverviewArgs) : this(
deviceId = args.deviceId deviceId = args.deviceId

View File

@ -0,0 +1,45 @@
/*
* 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.overview
import im.vector.app.core.di.ActiveSessionHolder
import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes
import org.matrix.android.sdk.api.session.events.model.toContent
import javax.inject.Inject
class TogglePushNotificationUseCase @Inject constructor(
private val activeSessionHolder: ActiveSessionHolder,
) {
suspend fun execute(deviceId: String, enabled: Boolean) {
val session = activeSessionHolder.getSafeActiveSession() ?: return
val devicePusher = session.pushersService().getPushers().firstOrNull { it.deviceId == deviceId }
devicePusher?.let { pusher ->
session.pushersService().togglePusher(pusher, enabled)
}
val accountData = session.accountDataService().getUserAccountDataEvent(UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId)
if (accountData != null) {
val newNotificationSettingsContent = LocalNotificationSettingsContent(isSilenced = !enabled)
session.accountDataService().updateUserAccountData(
UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId,
newNotificationSettingsContent.toContent(),
)
}
}
}

View File

@ -114,6 +114,6 @@ class PushersManagerTest {
pushersManager.togglePusherForCurrentSession(true) pushersManager.togglePusherForCurrentSession(true)
pushersService.verifyOnlyGetPushersAndTogglePusherCalled(pusher, true) pushersService.verifyTogglePusherCalled(pusher, true)
} }
} }

View File

@ -18,7 +18,6 @@ package im.vector.app.features.settings.devices.v2.overview
import android.os.SystemClock import android.os.SystemClock
import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.Success import com.airbnb.mvrx.Success
import com.airbnb.mvrx.test.MavericksTestRule import com.airbnb.mvrx.test.MavericksTestRule
import im.vector.app.R import im.vector.app.R
@ -30,8 +29,8 @@ import im.vector.app.features.settings.devices.v2.signout.SignoutSessionUseCase
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.FakePendingAuthHandler import im.vector.app.test.fakes.FakePendingAuthHandler
import im.vector.app.test.fakes.FakeSession
import im.vector.app.test.fakes.FakeStringProvider import im.vector.app.test.fakes.FakeStringProvider
import im.vector.app.test.fakes.FakeTogglePushNotificationUseCase
import im.vector.app.test.fakes.FakeVerificationService import im.vector.app.test.fakes.FakeVerificationService
import im.vector.app.test.fixtures.PusherFixture.aPusher import im.vector.app.test.fixtures.PusherFixture.aPusher
import im.vector.app.test.test import im.vector.app.test.test
@ -79,7 +78,6 @@ class SessionOverviewViewModelTest {
private val args = SessionOverviewArgs( private val args = SessionOverviewArgs(
deviceId = A_SESSION_ID_1 deviceId = A_SESSION_ID_1
) )
private val fakeSession = FakeSession()
private val getDeviceFullInfoUseCase = mockk<GetDeviceFullInfoUseCase>(relaxed = true) private val getDeviceFullInfoUseCase = mockk<GetDeviceFullInfoUseCase>(relaxed = true)
private val fakeActiveSessionHolder = FakeActiveSessionHolder() private val fakeActiveSessionHolder = FakeActiveSessionHolder()
private val fakeStringProvider = FakeStringProvider() private val fakeStringProvider = FakeStringProvider()
@ -88,10 +86,10 @@ class SessionOverviewViewModelTest {
private val interceptSignoutFlowResponseUseCase = mockk<InterceptSignoutFlowResponseUseCase>() private val interceptSignoutFlowResponseUseCase = mockk<InterceptSignoutFlowResponseUseCase>()
private val fakePendingAuthHandler = FakePendingAuthHandler() private val fakePendingAuthHandler = FakePendingAuthHandler()
private val refreshDevicesUseCase = mockk<RefreshDevicesUseCase>() private val refreshDevicesUseCase = mockk<RefreshDevicesUseCase>()
private val togglePushNotificationUseCase = FakeTogglePushNotificationUseCase()
private fun createViewModel() = SessionOverviewViewModel( private fun createViewModel() = SessionOverviewViewModel(
initialState = SessionOverviewViewState(args), initialState = SessionOverviewViewState(args),
session = fakeSession,
stringProvider = fakeStringProvider.instance, stringProvider = fakeStringProvider.instance,
getDeviceFullInfoUseCase = getDeviceFullInfoUseCase, getDeviceFullInfoUseCase = getDeviceFullInfoUseCase,
checkIfCurrentSessionCanBeVerifiedUseCase = checkIfCurrentSessionCanBeVerifiedUseCase, checkIfCurrentSessionCanBeVerifiedUseCase = checkIfCurrentSessionCanBeVerifiedUseCase,
@ -100,6 +98,7 @@ class SessionOverviewViewModelTest {
pendingAuthHandler = fakePendingAuthHandler.instance, pendingAuthHandler = fakePendingAuthHandler.instance,
activeSessionHolder = fakeActiveSessionHolder.instance, activeSessionHolder = fakeActiveSessionHolder.instance,
refreshDevicesUseCase = refreshDevicesUseCase, refreshDevicesUseCase = refreshDevicesUseCase,
togglePushNotificationUseCase = togglePushNotificationUseCase.instance,
) )
@Before @Before
@ -116,6 +115,13 @@ class SessionOverviewViewModelTest {
unmockkAll() unmockkAll()
} }
@Test
fun `given the viewModel has been initialized then pushers are refreshed`() {
createViewModel()
fakeActiveSessionHolder.fakeSession.pushersService().verifyRefreshPushers()
}
@Test @Test
fun `given the viewModel has been initialized then viewState is updated with session info`() { fun `given the viewModel has been initialized then viewState is updated with session info`() {
val deviceFullInfo = mockk<DeviceFullInfo>() val deviceFullInfo = mockk<DeviceFullInfo>()
@ -125,7 +131,7 @@ class SessionOverviewViewModelTest {
deviceId = A_SESSION_ID_1, deviceId = A_SESSION_ID_1,
deviceInfo = Success(deviceFullInfo), deviceInfo = Success(deviceFullInfo),
isCurrentSessionTrusted = true, isCurrentSessionTrusted = true,
pushers = Loading(), notificationsEnabled = true,
) )
val viewModel = createViewModel() val viewModel = createViewModel()
@ -221,7 +227,7 @@ class SessionOverviewViewModelTest {
isCurrentSessionTrusted = true, isCurrentSessionTrusted = true,
deviceInfo = Success(deviceFullInfo), deviceInfo = Success(deviceFullInfo),
isLoading = false, isLoading = false,
pushers = Loading(), notificationsEnabled = true,
) )
// When // When
@ -258,7 +264,7 @@ class SessionOverviewViewModelTest {
isCurrentSessionTrusted = true, isCurrentSessionTrusted = true,
deviceInfo = Success(deviceFullInfo), deviceInfo = Success(deviceFullInfo),
isLoading = false, isLoading = false,
pushers = Loading(), notificationsEnabled = true,
) )
fakeStringProvider.given(R.string.authentication_error, AUTH_ERROR_MESSAGE) fakeStringProvider.given(R.string.authentication_error, AUTH_ERROR_MESSAGE)
@ -293,7 +299,7 @@ class SessionOverviewViewModelTest {
isCurrentSessionTrusted = true, isCurrentSessionTrusted = true,
deviceInfo = Success(deviceFullInfo), deviceInfo = Success(deviceFullInfo),
isLoading = false, isLoading = false,
pushers = Loading(), notificationsEnabled = true,
) )
fakeStringProvider.given(R.string.matrix_error, AN_ERROR_MESSAGE) fakeStringProvider.given(R.string.matrix_error, AN_ERROR_MESSAGE)
@ -461,26 +467,22 @@ 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 pushers = listOf(aPusher(deviceId = A_SESSION_ID_1)) val pushers = listOf(aPusher(deviceId = A_SESSION_ID_1))
fakeSession.pushersService().givenPushersLive(pushers) fakeActiveSessionHolder.fakeSession.pushersService().givenPushersLive(pushers)
val viewModel = createViewModel() val viewModel = createViewModel()
viewModel.test() viewModel.test()
.assertLatestState { state -> state.pushers.invoke() == pushers } .assertLatestState { state -> state.notificationsEnabled }
.finish() .finish()
} }
@Test @Test
fun `when handle TogglePushNotifications, then toggle enabled for device pushers`() { fun `when handle TogglePushNotifications, then execute use case and update state`() {
val pushers = listOf(
aPusher(deviceId = A_SESSION_ID_1, enabled = false),
aPusher(deviceId = "another id", enabled = false)
)
fakeSession.pushersService().givenPushersLive(pushers)
val viewModel = createViewModel() val viewModel = createViewModel()
viewModel.handle(SessionOverviewAction.TogglePushNotifications(A_SESSION_ID_1, true)) viewModel.handle(SessionOverviewAction.TogglePushNotifications(A_SESSION_ID_1, true))
fakeSession.pushersService().verifyOnlyTogglePusherCalled(pushers.first(), true) togglePushNotificationUseCase.verifyExecute(A_SESSION_ID_1, true)
viewModel.test().assertLatestState { state -> state.notificationsEnabled }.finish()
} }
} }

View File

@ -0,0 +1,67 @@
/*
* 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.overview
import im.vector.app.test.fakes.FakeActiveSessionHolder
import im.vector.app.test.fixtures.PusherFixture
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 togglePushNotificationUseCase = TogglePushNotificationUseCase(activeSessionHolder.instance)
@Test
fun `when execute, then toggle enabled for device pushers`() = runTest {
val sessionId = "a_session_id"
val pushers = listOf(
PusherFixture.aPusher(deviceId = sessionId, enabled = false),
PusherFixture.aPusher(deviceId = "another id", enabled = false)
)
activeSessionHolder.fakeSession.pushersService().givenPushersLive(pushers)
activeSessionHolder.fakeSession.pushersService().givenGetPushers(pushers)
togglePushNotificationUseCase.execute(sessionId, true)
activeSessionHolder.fakeSession.pushersService().verifyTogglePusherCalled(pushers.first(), true)
}
@Test
fun `when execute, then toggle local notification settings`() = runTest {
val sessionId = "a_session_id"
val pushers = listOf(
PusherFixture.aPusher(deviceId = sessionId, enabled = false),
PusherFixture.aPusher(deviceId = "another id", enabled = false)
)
activeSessionHolder.fakeSession.pushersService().givenPushersLive(pushers)
activeSessionHolder.fakeSession.accountDataService().givenGetUserAccountDataEventReturns(
UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + sessionId,
LocalNotificationSettingsContent(isSilenced = true).toContent()
)
togglePushNotificationUseCase.execute(sessionId, true)
activeSessionHolder.fakeSession.accountDataService().verifyUpdateUserAccountDataEventSucceeds(
UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + sessionId,
LocalNotificationSettingsContent(isSilenced = false).toContent(),
)
}
}

View File

@ -17,7 +17,6 @@
package im.vector.app.test.fakes package im.vector.app.test.fakes
import androidx.lifecycle.liveData import androidx.lifecycle.liveData
import io.mockk.Ordering
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every import io.mockk.every
import io.mockk.justRun import io.mockk.justRun
@ -38,16 +37,8 @@ class FakePushersService : PushersService by mockk(relaxed = true) {
every { getPushersLive() } returns liveData { emit(pushers) } every { getPushersLive() } returns liveData { emit(pushers) }
} }
fun verifyOnlyGetPushersAndTogglePusherCalled(pusher: Pusher, enable: Boolean) { fun verifyTogglePusherCalled(pusher: Pusher, enable: Boolean) {
coVerify(ordering = Ordering.ALL) { coVerify {
getPushers()
togglePusher(pusher, enable)
}
}
fun verifyOnlyTogglePusherCalled(pusher: Pusher, enable: Boolean) {
coVerify(ordering = Ordering.ALL) {
getPushersLive() // verifies only getPushersLive and the following togglePusher was called
togglePusher(pusher, enable) togglePusher(pusher, enable)
} }
} }

View File

@ -26,7 +26,7 @@ import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent
import org.matrix.android.sdk.api.session.events.model.Content import org.matrix.android.sdk.api.session.events.model.Content
class FakeSessionAccountDataService : SessionAccountDataService by mockk() { class FakeSessionAccountDataService : SessionAccountDataService by mockk(relaxed = true) {
fun givenGetUserAccountDataEventReturns(type: String, content: Content) { fun givenGetUserAccountDataEventReturns(type: String, content: Content) {
every { getUserAccountDataEvent(type) } returns UserAccountDataEvent(type, content) every { getUserAccountDataEvent(type) } returns UserAccountDataEvent(type, content)

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.test.fakes
import im.vector.app.features.settings.devices.v2.overview.TogglePushNotificationUseCase
import io.mockk.coJustRun
import io.mockk.coVerify
import io.mockk.mockk
class FakeTogglePushNotificationUseCase {
val instance = mockk<TogglePushNotificationUseCase> {
coJustRun { execute(any(), any()) }
}
fun verifyExecute(deviceId: String, enabled: Boolean) {
coVerify { instance.execute(deviceId, enabled) }
}
}