Fix crash: show an error message with a Retry button when there is no network when displaying the BootstrapBottomSheet.

This commit is contained in:
Benoit Marty 2023-06-15 14:15:06 +02:00
parent 0573915a0a
commit 2a5df54ae4
6 changed files with 141 additions and 25 deletions

View File

@ -20,6 +20,7 @@ import im.vector.app.core.platform.VectorViewModelAction
import java.io.OutputStream
sealed class BootstrapActions : VectorViewModelAction {
object Retry : BootstrapActions()
// Navigation

View File

@ -212,6 +212,11 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetBoot
views.bootstrapTitleText.text = getString(R.string.upgrade_security)
showFragment(BootstrapMigrateBackupFragment::class)
}
is BootstrapStep.Error -> {
views.bootstrapIcon.isVisible = true
views.bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title)
showFragment(BootstrapErrorFragment::class)
}
}
super.invalidate()
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2023 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.crypto.recover
import android.view.LayoutInflater
import android.view.ViewGroup
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.epoxy.onClick
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentBootstrapErrorBinding
@AndroidEntryPoint
class BootstrapErrorFragment :
VectorBaseFragment<FragmentBootstrapErrorBinding>() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapErrorBinding {
return FragmentBootstrapErrorBinding.inflate(inflater, container, false)
}
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
override fun invalidate() = withState(sharedViewModel) { state ->
when (state.step) {
is BootstrapStep.Error -> {
views.bootstrapDescriptionText.setTextOrHide(errorFormatter.toHumanReadable(state.step.error))
}
else -> {
// Should not happen, show a generic error
views.bootstrapDescriptionText.setTextOrHide(getString(R.string.unknown_error))
}
}
views.bootstrapRetryButton.onClick {
sharedViewModel.handle(BootstrapActions.Retry)
}
}
}

View File

@ -54,6 +54,7 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromR
import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec
import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth
import timber.log.Timber
import java.io.OutputStream
import kotlin.coroutines.Continuation
import kotlin.coroutines.resumeWithException
@ -118,6 +119,12 @@ class BootstrapSharedViewModel @AssistedInject constructor(
}
}
SetupMode.NORMAL -> {
checkMigration()
}
}
}
private fun checkMigration() {
// need to check if user have an existing keybackup
setState {
copy(step = BootstrapStep.CheckingMigration)
@ -125,6 +132,7 @@ class BootstrapSharedViewModel @AssistedInject constructor(
// We need to check if there is an existing backup
viewModelScope.launch(Dispatchers.IO) {
try {
val version = tryOrNull { session.cryptoService().keysBackupService().getCurrentVersion() }?.toKeysVersionResult()
if (version == null) {
// we just resume plain bootstrap
@ -148,6 +156,10 @@ class BootstrapSharedViewModel @AssistedInject constructor(
}
}
}
} catch (failure: Throwable) {
Timber.e(failure, "Error while checking key backup")
setState {
copy(step = BootstrapStep.Error(failure))
}
}
}
@ -268,6 +280,9 @@ class BootstrapSharedViewModel @AssistedInject constructor(
copy(step = BootstrapStep.AccountReAuth(stringProvider.getString(R.string.authentication_error)))
}
}
BootstrapActions.Retry -> {
checkMigration()
}
}
}
@ -568,6 +583,12 @@ class BootstrapSharedViewModel @AssistedInject constructor(
)
}
}
is BootstrapStep.Error -> {
// do we let you cancel from here?
if (state.canLeave) {
_viewEvents.post(BootstrapViewEvents.SkipBootstrap(state.passphrase != null))
}
}
}
}

View File

@ -105,6 +105,8 @@ sealed class BootstrapStep {
object Initializing : BootstrapStep()
data class SaveRecoveryKey(val isSaved: Boolean) : BootstrapStep()
object DoneSuccess : BootstrapStep()
data class Error(val error: Throwable) : BootstrapStep()
}
fun BootstrapStep.GetBackupSecretForMigration.useKey(): Boolean {

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="200dp"
android:padding="16dp">
<TextView
android:id="@+id/bootstrapDescriptionText"
style="@style/Widget.Vector.TextView.Body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/error_check_network"
android:textColor="?vctr_content_primary"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/bootstrapRetryButton"
style="@style/Widget.Vector.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/layout_vertical_margin"
android:text="@string/global_retry"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bootstrapDescriptionText"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>