Add pusher status in the state.
It improve the tests and we may want to render errors in the View at some point.
This commit is contained in:
parent
3d5951cbf0
commit
21ce1c40b3
5 changed files with 74 additions and 18 deletions
|
|
@ -18,14 +18,17 @@ package io.element.android.appnav.loggedin
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import im.vector.app.features.analytics.plan.CryptoSessionStateChange
|
||||
import im.vector.app.features.analytics.plan.UserProperties
|
||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
|
|
@ -55,13 +58,16 @@ class LoggedInPresenter @Inject constructor(
|
|||
val isVerified by remember {
|
||||
sessionVerificationService.sessionVerifiedStatus.map { it == SessionVerifiedStatus.Verified }
|
||||
}.collectAsState(initial = false)
|
||||
|
||||
val pusherRegistrationState = remember<MutableState<AsyncData<Unit>>> { mutableStateOf(AsyncData.Uninitialized) }
|
||||
if (isVerified) {
|
||||
LaunchedEffect(Unit) {
|
||||
ensurePusherIsRegistered()
|
||||
ensurePusherIsRegistered(pusherRegistrationState)
|
||||
}
|
||||
} else {
|
||||
LaunchedEffect(Unit) {
|
||||
pusherRegistrationState.value = AsyncData.Failure(PusherRegistrationFailure.AccountNotVerified())
|
||||
}
|
||||
}
|
||||
|
||||
val syncIndicator by matrixClient.roomListService.syncIndicator.collectAsState()
|
||||
val networkStatus by networkMonitor.connectivity.collectAsState()
|
||||
val showSyncSpinner by remember {
|
||||
|
|
@ -77,25 +83,32 @@ class LoggedInPresenter @Inject constructor(
|
|||
|
||||
return LoggedInState(
|
||||
showSyncSpinner = showSyncSpinner,
|
||||
pusherRegistrationState = pusherRegistrationState.value,
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun ensurePusherIsRegistered() {
|
||||
private suspend fun ensurePusherIsRegistered(pusherRegistrationState: MutableState<AsyncData<Unit>>) {
|
||||
Timber.tag(pusherTag.value).d("Ensure pusher is registered")
|
||||
val currentPushProvider = pushService.getCurrentPushProvider()
|
||||
val result = if (currentPushProvider == null) {
|
||||
Timber.tag(pusherTag.value).d("Register with the first available push provider")
|
||||
val pushProvider = pushService.getAvailablePushProviders().firstOrNull()
|
||||
?: return Unit.also { Timber.tag(pusherTag.value).w("No push provider available") }
|
||||
?: return Unit
|
||||
.also { Timber.tag(pusherTag.value).w("No push providers available") }
|
||||
.also { pusherRegistrationState.value = AsyncData.Failure(PusherRegistrationFailure.NoProvidersAvailable()) }
|
||||
val distributor = pushProvider.getDistributors().firstOrNull()
|
||||
?: return Unit.also { Timber.tag(pusherTag.value).w("No distributor available") }
|
||||
?: return Unit
|
||||
.also { Timber.tag(pusherTag.value).w("No distributors available") }
|
||||
.also { pusherRegistrationState.value = AsyncData.Failure(PusherRegistrationFailure.NoDistributorsAvailable()) }
|
||||
pushService.registerWith(matrixClient, pushProvider, distributor)
|
||||
} else {
|
||||
val currentPushDistributor = currentPushProvider.getCurrentDistributor(matrixClient)
|
||||
if (currentPushDistributor == null) {
|
||||
Timber.tag(pusherTag.value).d("Register with the first available distributor")
|
||||
val distributor = currentPushProvider.getDistributors().firstOrNull()
|
||||
?: return Unit.also { Timber.tag(pusherTag.value).w("No distributor available") }
|
||||
?: return Unit
|
||||
.also { Timber.tag(pusherTag.value).w("No distributors available") }
|
||||
.also { pusherRegistrationState.value = AsyncData.Failure(PusherRegistrationFailure.NoDistributorsAvailable()) }
|
||||
pushService.registerWith(matrixClient, currentPushProvider, distributor)
|
||||
} else {
|
||||
Timber.tag(pusherTag.value).d("Re-register with the current distributor")
|
||||
|
|
@ -105,9 +118,11 @@ class LoggedInPresenter @Inject constructor(
|
|||
result.fold(
|
||||
onSuccess = {
|
||||
Timber.tag(pusherTag.value).d("Pusher registered")
|
||||
pusherRegistrationState.value = AsyncData.Success(Unit)
|
||||
},
|
||||
onFailure = {
|
||||
Timber.tag(pusherTag.value).e(it, "Failed to register pusher")
|
||||
pusherRegistrationState.value = AsyncData.Failure(PusherRegistrationFailure.RegistrationFailure(it))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
package io.element.android.appnav.loggedin
|
||||
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
|
||||
data class LoggedInState(
|
||||
val showSyncSpinner: Boolean,
|
||||
val pusherRegistrationState: AsyncData<Unit>,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package io.element.android.appnav.loggedin
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
|
||||
open class LoggedInStateProvider : PreviewParameterProvider<LoggedInState> {
|
||||
override val values: Sequence<LoggedInState>
|
||||
|
|
@ -31,4 +32,5 @@ fun aLoggedInState(
|
|||
showSyncSpinner: Boolean = true,
|
||||
) = LoggedInState(
|
||||
showSyncSpinner = showSyncSpinner,
|
||||
pusherRegistrationState = AsyncData.Uninitialized,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2024 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 io.element.android.appnav.loggedin
|
||||
|
||||
sealed class PusherRegistrationFailure : Exception() {
|
||||
class AccountNotVerified : PusherRegistrationFailure()
|
||||
class NoProvidersAvailable : PusherRegistrationFailure()
|
||||
class NoDistributorsAvailable : PusherRegistrationFailure()
|
||||
class RegistrationFailure(val failure: Throwable) : PusherRegistrationFailure()
|
||||
}
|
||||
|
|
@ -47,13 +47,10 @@ import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
|||
import io.element.android.tests.testutils.lambda.any
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.lambda.value
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class LoggedInPresenterTest {
|
||||
@get:Rule
|
||||
val warmUpRule = WarmUpRule()
|
||||
|
|
@ -66,6 +63,8 @@ class LoggedInPresenterTest {
|
|||
}.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.showSyncSpinner).isFalse()
|
||||
assertThat(initialState.pusherRegistrationState.isUninitialized()).isTrue()
|
||||
skipItems(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +105,7 @@ class LoggedInPresenterTest {
|
|||
encryptionService.emitRecoveryState(RecoveryState.INCOMPLETE)
|
||||
verificationService.emitVerifiedStatus(SessionVerifiedStatus.Verified)
|
||||
|
||||
skipItems(4)
|
||||
skipItems(6)
|
||||
|
||||
assertThat(analyticsService.capturedEvents.size).isEqualTo(1)
|
||||
assertThat(analyticsService.capturedEvents[0]).isInstanceOf(CryptoSessionStateChange::class.java)
|
||||
|
|
@ -133,6 +132,9 @@ class LoggedInPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
skipItems(1)
|
||||
val finalState = awaitItem()
|
||||
assertThat(finalState.pusherRegistrationState.errorOrNull())
|
||||
.isInstanceOf(PusherRegistrationFailure.AccountNotVerified::class.java)
|
||||
lambda.assertions()
|
||||
.isNeverCalled()
|
||||
}
|
||||
|
|
@ -156,7 +158,8 @@ class LoggedInPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
skipItems(2)
|
||||
advanceUntilIdle()
|
||||
val finalState = awaitItem()
|
||||
assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
|
||||
lambda.assertions()
|
||||
.isCalledOnce()
|
||||
.with(
|
||||
|
|
@ -188,7 +191,8 @@ class LoggedInPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
skipItems(2)
|
||||
advanceUntilIdle()
|
||||
val finalState = awaitItem()
|
||||
assertThat(finalState.pusherRegistrationState.isFailure()).isTrue()
|
||||
lambda.assertions()
|
||||
.isCalledOnce()
|
||||
.with(
|
||||
|
|
@ -233,7 +237,8 @@ class LoggedInPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
skipItems(2)
|
||||
advanceUntilIdle()
|
||||
val finalState = awaitItem()
|
||||
assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
|
||||
lambda.assertions()
|
||||
.isCalledOnce()
|
||||
.with(
|
||||
|
|
@ -277,7 +282,8 @@ class LoggedInPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
skipItems(2)
|
||||
advanceUntilIdle()
|
||||
val finalState = awaitItem()
|
||||
assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
|
||||
lambda.assertions()
|
||||
.isCalledOnce()
|
||||
.with(
|
||||
|
|
@ -317,7 +323,9 @@ class LoggedInPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
skipItems(2)
|
||||
advanceUntilIdle()
|
||||
val finalState = awaitItem()
|
||||
assertThat(finalState.pusherRegistrationState.errorOrNull())
|
||||
.isInstanceOf(PusherRegistrationFailure.NoDistributorsAvailable::class.java)
|
||||
lambda.assertions()
|
||||
.isNeverCalled()
|
||||
}
|
||||
|
|
@ -343,7 +351,9 @@ class LoggedInPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
skipItems(2)
|
||||
advanceUntilIdle()
|
||||
val finalState = awaitItem()
|
||||
assertThat(finalState.pusherRegistrationState.errorOrNull())
|
||||
.isInstanceOf(PusherRegistrationFailure.NoProvidersAvailable::class.java)
|
||||
lambda.assertions()
|
||||
.isNeverCalled()
|
||||
}
|
||||
|
|
@ -374,7 +384,9 @@ class LoggedInPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
skipItems(2)
|
||||
advanceUntilIdle()
|
||||
val finalState = awaitItem()
|
||||
assertThat(finalState.pusherRegistrationState.errorOrNull())
|
||||
.isInstanceOf(PusherRegistrationFailure.NoDistributorsAvailable::class.java)
|
||||
lambda.assertions()
|
||||
.isNeverCalled()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue