Render an error dialog in case registering a pusher fails.
This commit is contained in:
parent
f7b8e0c931
commit
e6f6e82ce2
12 changed files with 131 additions and 9 deletions
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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 interface LoggedInEvents {
|
||||
data object CloseErrorDialog : LoggedInEvents
|
||||
}
|
||||
|
|
@ -38,6 +38,7 @@ import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
|||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
|
||||
import io.element.android.libraries.push.api.PushService
|
||||
import io.element.android.libraries.pushproviders.api.RegistrationFailure
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import kotlinx.coroutines.flow.map
|
||||
import timber.log.Timber
|
||||
|
|
@ -81,9 +82,16 @@ class LoggedInPresenter @Inject constructor(
|
|||
reportCryptoStatusToAnalytics(verificationState, recoveryState)
|
||||
}
|
||||
|
||||
fun handleEvent(event: LoggedInEvents) {
|
||||
when (event) {
|
||||
LoggedInEvents.CloseErrorDialog -> pusherRegistrationState.value = AsyncData.Uninitialized
|
||||
}
|
||||
}
|
||||
|
||||
return LoggedInState(
|
||||
showSyncSpinner = showSyncSpinner,
|
||||
pusherRegistrationState = pusherRegistrationState.value,
|
||||
eventSink = ::handleEvent
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -122,7 +130,13 @@ class LoggedInPresenter @Inject constructor(
|
|||
},
|
||||
onFailure = {
|
||||
Timber.tag(pusherTag.value).e(it, "Failed to register pusher")
|
||||
pusherRegistrationState.value = AsyncData.Failure(PusherRegistrationFailure.RegistrationFailure(it))
|
||||
if (it is RegistrationFailure) {
|
||||
pusherRegistrationState.value = AsyncData.Failure(
|
||||
PusherRegistrationFailure.RegistrationFailure(it.clientException, it.isRegisteringAgain)
|
||||
)
|
||||
} else {
|
||||
pusherRegistrationState.value = AsyncData.Failure(it)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,4 +21,5 @@ import io.element.android.libraries.architecture.AsyncData
|
|||
data class LoggedInState(
|
||||
val showSyncSpinner: Boolean,
|
||||
val pusherRegistrationState: AsyncData<Unit>,
|
||||
val eventSink: (LoggedInEvents) -> Unit,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -22,15 +22,17 @@ import io.element.android.libraries.architecture.AsyncData
|
|||
open class LoggedInStateProvider : PreviewParameterProvider<LoggedInState> {
|
||||
override val values: Sequence<LoggedInState>
|
||||
get() = sequenceOf(
|
||||
aLoggedInState(false),
|
||||
aLoggedInState(true),
|
||||
// Add other state here
|
||||
aLoggedInState(),
|
||||
aLoggedInState(showSyncSpinner = true),
|
||||
aLoggedInState(pusherRegistrationState = AsyncData.Failure(PusherRegistrationFailure.NoProvidersAvailable())),
|
||||
)
|
||||
}
|
||||
|
||||
fun aLoggedInState(
|
||||
showSyncSpinner: Boolean = true,
|
||||
showSyncSpinner: Boolean = false,
|
||||
pusherRegistrationState: AsyncData<Unit> = AsyncData.Uninitialized,
|
||||
) = LoggedInState(
|
||||
showSyncSpinner = showSyncSpinner,
|
||||
pusherRegistrationState = AsyncData.Uninitialized,
|
||||
pusherRegistrationState = pusherRegistrationState,
|
||||
eventSink = {},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -22,9 +22,14 @@ import androidx.compose.foundation.layout.systemBarsPadding
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.matrix.api.exception.isNetworkError
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@Composable
|
||||
fun LoggedInView(
|
||||
|
|
@ -41,6 +46,38 @@ fun LoggedInView(
|
|||
isVisible = state.showSyncSpinner,
|
||||
)
|
||||
}
|
||||
when (state.pusherRegistrationState) {
|
||||
is AsyncData.Uninitialized,
|
||||
is AsyncData.Loading,
|
||||
is AsyncData.Success -> Unit
|
||||
is AsyncData.Failure -> {
|
||||
state.pusherRegistrationState.errorOrNull()
|
||||
?.getReason()
|
||||
?.let { reason ->
|
||||
ErrorDialog(
|
||||
content = stringResource(id = CommonStrings.common_error_registering_pusher_android, reason),
|
||||
onDismiss = { state.eventSink(LoggedInEvents.CloseErrorDialog) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Throwable.getReason(): String? {
|
||||
return when (this) {
|
||||
is PusherRegistrationFailure.RegistrationFailure -> {
|
||||
if (isRegisteringAgain && clientException.isNetworkError()) {
|
||||
// When registering again, ignore network error
|
||||
null
|
||||
} else {
|
||||
clientException.message ?: "Unknown error"
|
||||
}
|
||||
}
|
||||
is PusherRegistrationFailure.AccountNotVerified -> null
|
||||
is PusherRegistrationFailure.NoDistributorsAvailable -> "No distributors available"
|
||||
is PusherRegistrationFailure.NoProvidersAvailable -> "No providers available"
|
||||
else -> "Other error"
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
|
|
|
|||
|
|
@ -16,9 +16,19 @@
|
|||
|
||||
package io.element.android.appnav.loggedin
|
||||
|
||||
import io.element.android.libraries.matrix.api.exception.ClientException
|
||||
|
||||
sealed class PusherRegistrationFailure : Exception() {
|
||||
class AccountNotVerified : PusherRegistrationFailure()
|
||||
class NoProvidersAvailable : PusherRegistrationFailure()
|
||||
class NoDistributorsAvailable : PusherRegistrationFailure()
|
||||
class RegistrationFailure(val failure: Throwable) : PusherRegistrationFailure()
|
||||
|
||||
/**
|
||||
* @param clientException the failure that occurred.
|
||||
* @param isRegisteringAgain true if the server should already have a the same pusher registered.
|
||||
*/
|
||||
class RegistrationFailure(
|
||||
val clientException: ClientException,
|
||||
val isRegisteringAgain: Boolean,
|
||||
) : PusherRegistrationFailure()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -389,6 +389,10 @@ class LoggedInPresenterTest {
|
|||
.isInstanceOf(PusherRegistrationFailure.NoDistributorsAvailable::class.java)
|
||||
lambda.assertions()
|
||||
.isNeverCalled()
|
||||
// Reset the error
|
||||
finalState.eventSink(LoggedInEvents.CloseErrorDialog)
|
||||
val lastState = awaitItem()
|
||||
assertThat(lastState.pusherRegistrationState.isUninitialized()).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue