mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-27 12:00:03 +03:00
providing dedicated reset action for resetting invalid deeplink homeserver
- also fixes the usecase screen becoming stuck with an invalid homeserver deeplink
This commit is contained in:
parent
8c44c9828c
commit
690fda180c
5 changed files with 101 additions and 33 deletions
|
@ -25,8 +25,9 @@ import org.matrix.android.sdk.api.auth.data.Credentials
|
|||
import org.matrix.android.sdk.api.network.ssl.Fingerprint
|
||||
|
||||
sealed interface OnboardingAction : VectorViewModelAction {
|
||||
data class OnGetStarted(val resetLoginConfig: Boolean, val onboardingFlow: OnboardingFlow) : OnboardingAction
|
||||
data class OnIAlreadyHaveAnAccount(val resetLoginConfig: Boolean, val onboardingFlow: OnboardingFlow) : OnboardingAction
|
||||
object ResetDeeplinkConfig : OnboardingAction
|
||||
data class OnGetStarted(val onboardingFlow: OnboardingFlow) : OnboardingAction
|
||||
data class OnIAlreadyHaveAnAccount(val onboardingFlow: OnboardingFlow) : OnboardingAction
|
||||
|
||||
data class UpdateServerType(val serverType: ServerType) : OnboardingAction
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ import im.vector.app.core.extensions.configureAndStart
|
|||
import im.vector.app.core.extensions.vectorStore
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.core.utils.ensureProtocol
|
||||
import im.vector.app.core.utils.ensureTrailingSlash
|
||||
import im.vector.app.features.VectorFeatures
|
||||
import im.vector.app.features.VectorOverrides
|
||||
|
@ -110,7 +111,8 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||
private var currentHomeServerConnectionConfig: HomeServerConnectionConfig? = null
|
||||
|
||||
private val matrixOrgUrl = stringProvider.getString(R.string.matrix_org_server_url).ensureTrailingSlash()
|
||||
private val defaultHomeserverUrl = matrixOrgUrl
|
||||
private val defaultHomeserverUrl: String
|
||||
get() = loginConfig?.homeServerUrl?.ensureProtocol() ?: matrixOrgUrl
|
||||
|
||||
private val registrationWizard: RegistrationWizard
|
||||
get() = authenticationService.getRegistrationWizard()
|
||||
|
@ -132,8 +134,8 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||
|
||||
override fun handle(action: OnboardingAction) {
|
||||
when (action) {
|
||||
is OnboardingAction.OnGetStarted -> handleSplashAction(action.resetLoginConfig, action.onboardingFlow)
|
||||
is OnboardingAction.OnIAlreadyHaveAnAccount -> handleSplashAction(action.resetLoginConfig, action.onboardingFlow)
|
||||
is OnboardingAction.OnGetStarted -> handleSplashAction(action.onboardingFlow)
|
||||
is OnboardingAction.OnIAlreadyHaveAnAccount -> handleSplashAction(action.onboardingFlow)
|
||||
is OnboardingAction.UpdateUseCase -> handleUpdateUseCase(action)
|
||||
OnboardingAction.ResetUseCase -> resetUseCase()
|
||||
is OnboardingAction.UpdateServerType -> handleUpdateServerType(action)
|
||||
|
@ -157,6 +159,7 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||
OnboardingAction.SaveSelectedProfilePicture -> updateProfilePicture()
|
||||
is OnboardingAction.PostViewEvent -> _viewEvents.post(action.viewEvent)
|
||||
OnboardingAction.StopEmailValidationCheck -> cancelWaitForEmailValidation()
|
||||
OnboardingAction.ResetDeeplinkConfig -> loginConfig = null
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,10 +176,7 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleSplashAction(resetConfig: Boolean, onboardingFlow: OnboardingFlow) {
|
||||
if (resetConfig) {
|
||||
loginConfig = null
|
||||
}
|
||||
private fun handleSplashAction(onboardingFlow: OnboardingFlow) {
|
||||
setState { copy(onboardingFlow = onboardingFlow) }
|
||||
|
||||
return when (val config = loginConfig.toHomeserverConfig()) {
|
||||
|
@ -422,7 +422,6 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||
|
||||
private fun handleInitWith(action: OnboardingAction.InitWith) {
|
||||
loginConfig = action.loginConfig
|
||||
|
||||
// If there is a pending email validation continue on this step
|
||||
try {
|
||||
if (registrationWizard.isRegistrationStarted) {
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
package im.vector.app.features.onboarding.ftueauth
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.NetworkCapabilities
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -41,8 +44,7 @@ import im.vector.app.features.settings.VectorPreferences
|
|||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
import java.net.UnknownHostException
|
||||
import org.matrix.android.sdk.api.failure.isHomeserverUnavailable
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val CAROUSEL_ROTATION_DELAY_MS = 5000L
|
||||
|
@ -128,11 +130,11 @@ class FtueAuthSplashCarouselFragment @Inject constructor(
|
|||
|
||||
private fun splashSubmit(isAlreadyHaveAccountEnabled: Boolean) {
|
||||
val getStartedFlow = if (isAlreadyHaveAccountEnabled) OnboardingFlow.SignUp else OnboardingFlow.SignInSignUp
|
||||
viewModel.handle(OnboardingAction.OnGetStarted(resetLoginConfig = false, onboardingFlow = getStartedFlow))
|
||||
viewModel.handle(OnboardingAction.OnGetStarted(onboardingFlow = getStartedFlow))
|
||||
}
|
||||
|
||||
private fun alreadyHaveAnAccount() {
|
||||
viewModel.handle(OnboardingAction.OnIAlreadyHaveAnAccount(resetLoginConfig = false, onboardingFlow = OnboardingFlow.SignIn))
|
||||
viewModel.handle(OnboardingAction.OnIAlreadyHaveAnAccount(onboardingFlow = OnboardingFlow.SignIn))
|
||||
}
|
||||
|
||||
override fun resetViewModel() {
|
||||
|
@ -140,21 +142,56 @@ class FtueAuthSplashCarouselFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onError(throwable: Throwable) {
|
||||
if (throwable is Failure.NetworkConnection &&
|
||||
throwable.ioException is UnknownHostException) {
|
||||
// Invalid homeserver from URL config
|
||||
val url = viewModel.getInitialHomeServerUrl().orEmpty()
|
||||
MaterialAlertDialogBuilder(requireActivity())
|
||||
.setTitle(R.string.dialog_title_error)
|
||||
.setMessage(getString(R.string.login_error_homeserver_from_url_not_found, url))
|
||||
.setPositiveButton(R.string.login_error_homeserver_from_url_not_found_enter_manual) { _, _ ->
|
||||
val flow = withState(viewModel) { it.onboardingFlow } ?: OnboardingFlow.SignInSignUp
|
||||
viewModel.handle(OnboardingAction.OnGetStarted(resetLoginConfig = true, flow))
|
||||
}
|
||||
.setNegativeButton(R.string.action_cancel, null)
|
||||
.show()
|
||||
} else {
|
||||
super.onError(throwable)
|
||||
when {
|
||||
requireContext().inferNoConnectivity() -> super.onError(throwable)
|
||||
throwable.isHomeserverUnavailable() -> {
|
||||
val url = viewModel.getInitialHomeServerUrl().orEmpty()
|
||||
homeserverUnavailableDialog(url) { onContinueFlowWithLoginConfigReset() }
|
||||
}
|
||||
else -> super.onError(throwable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onContinueFlowWithLoginConfigReset() {
|
||||
viewModel.handle(OnboardingAction.ResetDeeplinkConfig)
|
||||
when (val flow = withState(viewModel) { it.onboardingFlow } ?: OnboardingFlow.SignInSignUp) {
|
||||
OnboardingFlow.SignIn -> if (vectorFeatures.isOnboardingCombinedLoginEnabled()) {
|
||||
viewModel.handle(OnboardingAction.OnIAlreadyHaveAnAccount(flow))
|
||||
} else {
|
||||
viewModel.handle(OnboardingAction.OnGetStarted(flow))
|
||||
}
|
||||
else -> viewModel.handle(OnboardingAction.OnGetStarted(flow))
|
||||
}
|
||||
}
|
||||
|
||||
private fun homeserverUnavailableDialog(url: String, action: () -> Unit) {
|
||||
MaterialAlertDialogBuilder(requireActivity())
|
||||
.setTitle(R.string.dialog_title_error)
|
||||
.setMessage(getString(R.string.login_error_homeserver_from_url_not_found, url))
|
||||
.setPositiveButton(R.string.login_error_homeserver_from_url_not_found_enter_manual) { _, _ -> action() }
|
||||
.setNegativeButton(R.string.action_cancel, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.inferNoConnectivity(): Boolean {
|
||||
var networkAvailable = false
|
||||
|
||||
val connectivityManager: ConnectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
val network = connectivityManager.activeNetwork
|
||||
val networkCapabilities = connectivityManager.getNetworkCapabilities(network)
|
||||
|
||||
when {
|
||||
networkCapabilities?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == true -> {
|
||||
networkAvailable = true
|
||||
}
|
||||
networkCapabilities?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) == true -> {
|
||||
networkAvailable = true
|
||||
}
|
||||
networkCapabilities?.hasTransport(NetworkCapabilities.TRANSPORT_VPN) == true -> {
|
||||
networkAvailable = true
|
||||
}
|
||||
}
|
||||
|
||||
return !networkAvailable
|
||||
}
|
||||
|
|
|
@ -75,11 +75,11 @@ class FtueAuthSplashFragment @Inject constructor(
|
|||
|
||||
private fun splashSubmit(isAlreadyHaveAccountEnabled: Boolean) {
|
||||
val getStartedFlow = if (isAlreadyHaveAccountEnabled) OnboardingFlow.SignUp else OnboardingFlow.SignInSignUp
|
||||
viewModel.handle(OnboardingAction.OnGetStarted(resetLoginConfig = false, onboardingFlow = getStartedFlow))
|
||||
viewModel.handle(OnboardingAction.OnGetStarted(onboardingFlow = getStartedFlow))
|
||||
}
|
||||
|
||||
private fun alreadyHaveAnAccount() {
|
||||
viewModel.handle(OnboardingAction.OnIAlreadyHaveAnAccount(resetLoginConfig = false, onboardingFlow = OnboardingFlow.SignIn))
|
||||
viewModel.handle(OnboardingAction.OnIAlreadyHaveAnAccount(onboardingFlow = OnboardingFlow.SignIn))
|
||||
}
|
||||
|
||||
override fun resetViewModel() {
|
||||
|
@ -96,7 +96,8 @@ class FtueAuthSplashFragment @Inject constructor(
|
|||
.setMessage(getString(R.string.login_error_homeserver_from_url_not_found, url))
|
||||
.setPositiveButton(R.string.login_error_homeserver_from_url_not_found_enter_manual) { _, _ ->
|
||||
val flow = withState(viewModel) { it.onboardingFlow } ?: OnboardingFlow.SignInSignUp
|
||||
viewModel.handle(OnboardingAction.OnGetStarted(resetLoginConfig = true, flow))
|
||||
viewModel.handle(OnboardingAction.ResetDeeplinkConfig)
|
||||
viewModel.handle(OnboardingAction.OnGetStarted(flow))
|
||||
}
|
||||
.setNegativeButton(R.string.action_cancel, null)
|
||||
.show()
|
||||
|
|
|
@ -28,6 +28,8 @@ import androidx.annotation.ColorRes
|
|||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.airbnb.mvrx.withState
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.getResTintedDrawable
|
||||
import im.vector.app.core.extensions.getTintedDrawable
|
||||
|
@ -38,13 +40,14 @@ import im.vector.app.features.login.ServerType
|
|||
import im.vector.app.features.onboarding.FtueUseCase
|
||||
import im.vector.app.features.onboarding.OnboardingAction
|
||||
import im.vector.app.features.themes.ThemeProvider
|
||||
import org.matrix.android.sdk.api.failure.isHomeserverUnavailable
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val DARK_MODE_ICON_BACKGROUND_ALPHA = 0.30f
|
||||
private const val LIGHT_MODE_ICON_BACKGROUND_ALPHA = 0.15f
|
||||
|
||||
class FtueAuthUseCaseFragment @Inject constructor(
|
||||
private val themeProvider: ThemeProvider
|
||||
private val themeProvider: ThemeProvider,
|
||||
) : AbstractFtueAuthFragment<FragmentFtueAuthUseCaseBinding>() {
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueAuthUseCaseBinding {
|
||||
|
@ -111,4 +114,31 @@ class FtueAuthUseCaseFragment @Inject constructor(
|
|||
val whiteLayer = context.getTintedDrawable(R.drawable.bg_feature_icon, Color.WHITE)
|
||||
return LayerDrawable(arrayOf(whiteLayer, iconBackground, ContextCompat.getDrawable(context, icon)))
|
||||
}
|
||||
|
||||
override fun onError(throwable: Throwable) {
|
||||
when {
|
||||
requireContext().inferNoConnectivity() -> super.onError(throwable)
|
||||
throwable.isHomeserverUnavailable() -> {
|
||||
val url = viewModel.getInitialHomeServerUrl().orEmpty()
|
||||
homeserverUnavailableDialog(url) { onContinueFlowWithLoginConfigReset() }
|
||||
}
|
||||
else -> super.onError(throwable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onContinueFlowWithLoginConfigReset() {
|
||||
viewModel.handle(OnboardingAction.ResetDeeplinkConfig)
|
||||
withState(viewModel) { it.useCase }?.let {
|
||||
viewModel.handle(OnboardingAction.UpdateUseCase(it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun homeserverUnavailableDialog(url: String, action: () -> Unit) {
|
||||
MaterialAlertDialogBuilder(requireActivity())
|
||||
.setTitle(R.string.dialog_title_error)
|
||||
.setMessage(getString(R.string.login_error_homeserver_from_url_not_found, url))
|
||||
.setPositiveButton(R.string.login_error_homeserver_from_url_not_found_enter_manual) { _, _ -> action() }
|
||||
.setNegativeButton(R.string.action_cancel, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue