mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 05:31:21 +03:00
Login screens: ensure homeserver version is supported
This commit is contained in:
parent
3f1540b54e
commit
9b207dd5dc
24 changed files with 228 additions and 58 deletions
|
@ -19,12 +19,12 @@ package im.vector.matrix.android.api.auth
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.auth.data.Credentials
|
import im.vector.matrix.android.api.auth.data.Credentials
|
||||||
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
|
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
|
||||||
|
import im.vector.matrix.android.api.auth.data.LoginFlowResult
|
||||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||||
import im.vector.matrix.android.api.auth.login.LoginWizard
|
import im.vector.matrix.android.api.auth.login.LoginWizard
|
||||||
import im.vector.matrix.android.api.auth.registration.RegistrationWizard
|
import im.vector.matrix.android.api.auth.registration.RegistrationWizard
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.api.util.Cancelable
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
import im.vector.matrix.android.internal.auth.data.LoginFlowResponse
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface defines methods to authenticate or to create an account to a matrix server.
|
* This interface defines methods to authenticate or to create an account to a matrix server.
|
||||||
|
@ -35,7 +35,7 @@ interface AuthenticationService {
|
||||||
* Request the supported login flows for this homeserver.
|
* Request the supported login flows for this homeserver.
|
||||||
* This is the first method to call to be able to get a wizard to login or the create an account
|
* This is the first method to call to be able to get a wizard to login or the create an account
|
||||||
*/
|
*/
|
||||||
fun getLoginFlow(homeServerConnectionConfig: HomeServerConnectionConfig, callback: MatrixCallback<LoginFlowResponse>): Cancelable
|
fun getLoginFlow(homeServerConnectionConfig: HomeServerConnectionConfig, callback: MatrixCallback<LoginFlowResult>): Cancelable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a LoginWizard, to login to the homeserver
|
* Return a LoginWizard, to login to the homeserver
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 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.matrix.android.api.auth.data
|
||||||
|
|
||||||
|
import im.vector.matrix.android.internal.auth.data.LoginFlowResponse
|
||||||
|
|
||||||
|
// Either a LoginFlowResponse, or an error if the homeserver is outdated
|
||||||
|
sealed class LoginFlowResult {
|
||||||
|
data class Success(val loginFlowResponse: LoginFlowResponse) : LoginFlowResult()
|
||||||
|
object OutdatedHomeserver : LoginFlowResult()
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 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.matrix.android.api.auth.data
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model for https://matrix.org/docs/spec/client_server/latest#get-matrix-client-versions
|
||||||
|
*
|
||||||
|
* Ex:
|
||||||
|
* <pre>
|
||||||
|
* {
|
||||||
|
* "unstable_features": {
|
||||||
|
* "m.lazy_load_members": true
|
||||||
|
* },
|
||||||
|
* "versions": [
|
||||||
|
* "r0.0.1",
|
||||||
|
* "r0.1.0",
|
||||||
|
* "r0.2.0",
|
||||||
|
* "r0.3.0"
|
||||||
|
* ]
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class Versions(
|
||||||
|
@Json(name = "versions")
|
||||||
|
val supportedVersions: List<String>? = null,
|
||||||
|
|
||||||
|
@Json(name = "unstable_features")
|
||||||
|
val unstableFeatures: Map<String, Boolean>? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
// MatrixClientServerAPIVersion
|
||||||
|
private const val r0_0_1 = "r0_0_1"
|
||||||
|
private const val r0_1_0 = "r0_1_0"
|
||||||
|
private const val r0_2_0 = "r0_2_0"
|
||||||
|
private const val r0_3_0 = "r0_3_0"
|
||||||
|
private const val r0_4_0 = "r0_4_0"
|
||||||
|
private const val r0_5_0 = "r0_5_0"
|
||||||
|
private const val r0_6_0 = "r0_6_0"
|
||||||
|
|
||||||
|
// MatrixVersionsFeature
|
||||||
|
private const val FEATURE_LAZY_LOAD_MEMBERS = "m.lazy_load_members"
|
||||||
|
private const val FEATURE_REQUIRE_IDENTITY_SERVER = "m.require_identity_server"
|
||||||
|
private const val FEATURE_ID_ACCESS_TOKEN = "m.id_access_token"
|
||||||
|
private const val FEATURE_SEPARATE_ADD_AND_BIND = "m.separate_add_and_bind"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the SDK supports this homeserver version
|
||||||
|
*/
|
||||||
|
fun Versions.isSupportedBySdk(): Boolean {
|
||||||
|
return supportLazyLoadMembers()
|
||||||
|
&& !doesServerRequireIdentityServerParam()
|
||||||
|
&& doesServerAcceptIdentityAccessToken()
|
||||||
|
&& doesServerSeparatesAddAndBind()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the server support the lazy loading of room members
|
||||||
|
*
|
||||||
|
* @return true if the server support the lazy loading of room members
|
||||||
|
*/
|
||||||
|
private fun Versions.supportLazyLoadMembers(): Boolean {
|
||||||
|
return supportedVersions?.contains(r0_5_0) == true
|
||||||
|
|| unstableFeatures?.get(FEATURE_LAZY_LOAD_MEMBERS) == true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate if the `id_server` parameter is required when registering with an 3pid,
|
||||||
|
* adding a 3pid or resetting password.
|
||||||
|
*/
|
||||||
|
private fun Versions.doesServerRequireIdentityServerParam(): Boolean {
|
||||||
|
if (supportedVersions?.contains(r0_6_0) == true) return false
|
||||||
|
return unstableFeatures?.get(FEATURE_REQUIRE_IDENTITY_SERVER) ?: true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate if the `id_access_token` parameter can be safely passed to the homeserver.
|
||||||
|
* Some homeservers may trigger errors if they are not prepared for the new parameter.
|
||||||
|
*/
|
||||||
|
private fun Versions.doesServerAcceptIdentityAccessToken(): Boolean {
|
||||||
|
return supportedVersions?.contains(r0_6_0) == true
|
||||||
|
|| unstableFeatures?.get(FEATURE_ID_ACCESS_TOKEN) ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Versions.doesServerSeparatesAddAndBind(): Boolean {
|
||||||
|
return supportedVersions?.contains(r0_6_0) == true
|
||||||
|
|| unstableFeatures?.get(FEATURE_SEPARATE_ADD_AND_BIND) ?: false
|
||||||
|
}
|
|
@ -17,10 +17,11 @@
|
||||||
package im.vector.matrix.android.internal.auth
|
package im.vector.matrix.android.internal.auth
|
||||||
|
|
||||||
import im.vector.matrix.android.api.auth.data.Credentials
|
import im.vector.matrix.android.api.auth.data.Credentials
|
||||||
|
import im.vector.matrix.android.api.auth.data.Versions
|
||||||
import im.vector.matrix.android.internal.auth.data.LoginFlowResponse
|
import im.vector.matrix.android.internal.auth.data.LoginFlowResponse
|
||||||
import im.vector.matrix.android.internal.auth.data.PasswordLoginParams
|
import im.vector.matrix.android.internal.auth.data.PasswordLoginParams
|
||||||
import im.vector.matrix.android.internal.auth.registration.*
|
|
||||||
import im.vector.matrix.android.internal.auth.login.ResetPasswordMailConfirmed
|
import im.vector.matrix.android.internal.auth.login.ResetPasswordMailConfirmed
|
||||||
|
import im.vector.matrix.android.internal.auth.registration.*
|
||||||
import im.vector.matrix.android.internal.network.NetworkConstants
|
import im.vector.matrix.android.internal.network.NetworkConstants
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.http.*
|
import retrofit2.http.*
|
||||||
|
@ -30,6 +31,12 @@ import retrofit2.http.*
|
||||||
*/
|
*/
|
||||||
internal interface AuthAPI {
|
internal interface AuthAPI {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the version information of the homeserver
|
||||||
|
*/
|
||||||
|
@GET(NetworkConstants.URI_API_PREFIX_PATH_ + "versions")
|
||||||
|
fun versions(): Call<Versions>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register to the homeserver
|
* Register to the homeserver
|
||||||
* Ref: https://matrix.org/docs/spec/client_server/latest#account-registration-and-management
|
* Ref: https://matrix.org/docs/spec/client_server/latest#account-registration-and-management
|
||||||
|
|
|
@ -19,9 +19,7 @@ package im.vector.matrix.android.internal.auth
|
||||||
import dagger.Lazy
|
import dagger.Lazy
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.auth.AuthenticationService
|
import im.vector.matrix.android.api.auth.AuthenticationService
|
||||||
import im.vector.matrix.android.api.auth.data.Credentials
|
import im.vector.matrix.android.api.auth.data.*
|
||||||
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
|
|
||||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
|
||||||
import im.vector.matrix.android.api.auth.login.LoginWizard
|
import im.vector.matrix.android.api.auth.login.LoginWizard
|
||||||
import im.vector.matrix.android.api.auth.registration.RegistrationWizard
|
import im.vector.matrix.android.api.auth.registration.RegistrationWizard
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
|
@ -68,7 +66,7 @@ internal class DefaultAuthenticationService @Inject constructor(@Unauthenticated
|
||||||
return sessionManager.getOrCreateSession(sessionParams)
|
return sessionManager.getOrCreateSession(sessionParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getLoginFlow(homeServerConnectionConfig: HomeServerConnectionConfig, callback: MatrixCallback<LoginFlowResponse>): Cancelable {
|
override fun getLoginFlow(homeServerConnectionConfig: HomeServerConnectionConfig, callback: MatrixCallback<LoginFlowResult>): Cancelable {
|
||||||
currentHomeServerConnectionConfig = null
|
currentHomeServerConnectionConfig = null
|
||||||
|
|
||||||
return GlobalScope.launch(coroutineDispatchers.main) {
|
return GlobalScope.launch(coroutineDispatchers.main) {
|
||||||
|
@ -77,8 +75,10 @@ internal class DefaultAuthenticationService @Inject constructor(@Unauthenticated
|
||||||
}
|
}
|
||||||
result.fold(
|
result.fold(
|
||||||
{
|
{
|
||||||
// The homeserver exists, keep the config
|
if (it is LoginFlowResult.Success) {
|
||||||
|
// The homeserver exists and up to date, keep the config
|
||||||
currentHomeServerConnectionConfig = homeServerConnectionConfig
|
currentHomeServerConnectionConfig = homeServerConnectionConfig
|
||||||
|
}
|
||||||
callback.onSuccess(it)
|
callback.onSuccess(it)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -92,9 +92,21 @@ internal class DefaultAuthenticationService @Inject constructor(@Unauthenticated
|
||||||
private suspend fun getLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig) = withContext(coroutineDispatchers.io) {
|
private suspend fun getLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig) = withContext(coroutineDispatchers.io) {
|
||||||
val authAPI = buildAuthAPI(homeServerConnectionConfig)
|
val authAPI = buildAuthAPI(homeServerConnectionConfig)
|
||||||
|
|
||||||
executeRequest<LoginFlowResponse> {
|
// First check the homeserver version
|
||||||
|
val versions = executeRequest<Versions> {
|
||||||
|
apiCall = authAPI.versions()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (versions.isSupportedBySdk()) {
|
||||||
|
// Get the login flow
|
||||||
|
val loginFlowResponse = executeRequest<LoginFlowResponse> {
|
||||||
apiCall = authAPI.getLoginFlows()
|
apiCall = authAPI.getLoginFlows()
|
||||||
}
|
}
|
||||||
|
LoginFlowResult.Success(loginFlowResponse)
|
||||||
|
} else {
|
||||||
|
// Not supported
|
||||||
|
LoginFlowResult.OutdatedHomeserver
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getOrCreateRegistrationWizard(): RegistrationWizard {
|
override fun getOrCreateRegistrationWizard(): RegistrationWizard {
|
||||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.network
|
||||||
internal object NetworkConstants {
|
internal object NetworkConstants {
|
||||||
|
|
||||||
private const val URI_API_PREFIX_PATH = "_matrix/client"
|
private const val URI_API_PREFIX_PATH = "_matrix/client"
|
||||||
|
const val URI_API_PREFIX_PATH_ = "$URI_API_PREFIX_PATH/"
|
||||||
const val URI_API_PREFIX_PATH_R0 = "$URI_API_PREFIX_PATH/r0/"
|
const val URI_API_PREFIX_PATH_R0 = "$URI_API_PREFIX_PATH/r0/"
|
||||||
const val URI_API_PREFIX_PATH_UNSTABLE = "$URI_API_PREFIX_PATH/unstable/"
|
const val URI_API_PREFIX_PATH_UNSTABLE = "$URI_API_PREFIX_PATH/unstable/"
|
||||||
|
|
||||||
|
|
|
@ -52,14 +52,14 @@ abstract class AbstractLoginFragment : VectorBaseFragment(), OnBackPressed {
|
||||||
|
|
||||||
private fun handleLoginViewEvents(loginViewEvents: LoginViewEvents) {
|
private fun handleLoginViewEvents(loginViewEvents: LoginViewEvents) {
|
||||||
when (loginViewEvents) {
|
when (loginViewEvents) {
|
||||||
is LoginViewEvents.RegistrationFlowResult ->
|
is LoginViewEvents.Error -> showError(loginViewEvents.throwable)
|
||||||
|
else ->
|
||||||
// This is handled by the Activity
|
// This is handled by the Activity
|
||||||
Unit
|
Unit
|
||||||
is LoginViewEvents.RegistrationError -> displayRegistrationError(loginViewEvents.throwable)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun displayRegistrationError(throwable: Throwable) {
|
private fun showError(throwable: Throwable) {
|
||||||
when (throwable) {
|
when (throwable) {
|
||||||
is Failure.ServerError -> {
|
is Failure.ServerError -> {
|
||||||
if (throwable.error.code == MatrixError.FORBIDDEN
|
if (throwable.error.code == MatrixError.FORBIDDEN
|
||||||
|
@ -70,14 +70,14 @@ abstract class AbstractLoginFragment : VectorBaseFragment(), OnBackPressed {
|
||||||
.setPositiveButton(R.string.ok, null)
|
.setPositiveButton(R.string.ok, null)
|
||||||
.show()
|
.show()
|
||||||
} else {
|
} else {
|
||||||
onRegistrationError(throwable)
|
onError(throwable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> onRegistrationError(throwable)
|
else -> onError(throwable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun onRegistrationError(throwable: Throwable)
|
abstract fun onError(throwable: Throwable)
|
||||||
|
|
||||||
override fun onBackPressed(toolbarButton: Boolean): Boolean {
|
override fun onBackPressed(toolbarButton: Boolean): Boolean {
|
||||||
return when {
|
return when {
|
||||||
|
|
|
@ -160,7 +160,13 @@ class LoginActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is LoginViewEvents.RegistrationError ->
|
is LoginViewEvents.OutdatedHomeserver ->
|
||||||
|
AlertDialog.Builder(this)
|
||||||
|
.setTitle(R.string.dialog_title_error)
|
||||||
|
.setMessage(R.string.login_error_outdated_homeserver)
|
||||||
|
.setPositiveButton(R.string.ok, null)
|
||||||
|
.show()
|
||||||
|
is LoginViewEvents.Error ->
|
||||||
// This is handled by the Fragments
|
// This is handled by the Fragments
|
||||||
Unit
|
Unit
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,8 +178,7 @@ class LoginCaptchaFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRegistrationError(throwable: Throwable) {
|
override fun onError(throwable: Throwable) {
|
||||||
// Cannot happen here, but just in case
|
|
||||||
AlertDialog.Builder(requireActivity())
|
AlertDialog.Builder(requireActivity())
|
||||||
.setTitle(R.string.dialog_title_error)
|
.setTitle(R.string.dialog_title_error)
|
||||||
.setMessage(errorFormatter.toHumanReadable(throwable))
|
.setMessage(errorFormatter.toHumanReadable(throwable))
|
||||||
|
|
|
@ -189,7 +189,7 @@ class LoginFragment @Inject constructor(
|
||||||
loginViewModel.handle(LoginAction.ResetLogin)
|
loginViewModel.handle(LoginAction.ResetLogin)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRegistrationError(throwable: Throwable) {
|
override fun onError(throwable: Throwable) {
|
||||||
loginFieldTil.error = errorFormatter.toHumanReadable(throwable)
|
loginFieldTil.error = errorFormatter.toHumanReadable(throwable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -213,7 +213,7 @@ class LoginGenericTextInputFormFragment @Inject constructor(private val errorFor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRegistrationError(throwable: Throwable) {
|
override fun onError(throwable: Throwable) {
|
||||||
when (params.mode) {
|
when (params.mode) {
|
||||||
TextInputFormFragmentMode.SetEmail -> {
|
TextInputFormFragmentMode.SetEmail -> {
|
||||||
if (throwable.is401()) {
|
if (throwable.is401()) {
|
||||||
|
|
|
@ -140,8 +140,7 @@ class LoginResetPasswordFragment @Inject constructor(
|
||||||
loginViewModel.handle(LoginAction.ResetResetPassword)
|
loginViewModel.handle(LoginAction.ResetResetPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRegistrationError(throwable: Throwable) {
|
override fun onError(throwable: Throwable) {
|
||||||
// TODO
|
|
||||||
AlertDialog.Builder(requireActivity())
|
AlertDialog.Builder(requireActivity())
|
||||||
.setTitle(R.string.dialog_title_error)
|
.setTitle(R.string.dialog_title_error)
|
||||||
.setMessage(errorFormatter.toHumanReadable(throwable))
|
.setMessage(errorFormatter.toHumanReadable(throwable))
|
||||||
|
|
|
@ -53,8 +53,12 @@ class LoginResetPasswordMailConfirmationFragment @Inject constructor(
|
||||||
loginViewModel.handle(LoginAction.ResetPasswordMailConfirmed)
|
loginViewModel.handle(LoginAction.ResetPasswordMailConfirmed)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRegistrationError(throwable: Throwable) {
|
override fun onError(throwable: Throwable) {
|
||||||
// No op
|
AlertDialog.Builder(requireActivity())
|
||||||
|
.setTitle(R.string.dialog_title_error)
|
||||||
|
.setMessage(errorFormatter.toHumanReadable(throwable))
|
||||||
|
.setPositiveButton(R.string.ok, null)
|
||||||
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun resetViewModel() {
|
override fun resetViewModel() {
|
||||||
|
|
|
@ -36,8 +36,7 @@ class LoginResetPasswordSuccessFragment @Inject constructor(
|
||||||
loginSharedActionViewModel.post(LoginNavigation.OnResetPasswordMailConfirmationSuccessDone)
|
loginSharedActionViewModel.post(LoginNavigation.OnResetPasswordMailConfirmationSuccessDone)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRegistrationError(throwable: Throwable) {
|
override fun onError(throwable: Throwable) {
|
||||||
// Cannot happen here, but just in case
|
|
||||||
AlertDialog.Builder(requireActivity())
|
AlertDialog.Builder(requireActivity())
|
||||||
.setTitle(R.string.dialog_title_error)
|
.setTitle(R.string.dialog_title_error)
|
||||||
.setMessage(errorFormatter.toHumanReadable(throwable))
|
.setMessage(errorFormatter.toHumanReadable(throwable))
|
||||||
|
|
|
@ -123,8 +123,7 @@ class LoginServerSelectionFragment @Inject constructor(
|
||||||
loginViewModel.handle(LoginAction.ResetHomeServerType)
|
loginViewModel.handle(LoginAction.ResetHomeServerType)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRegistrationError(throwable: Throwable) {
|
override fun onError(throwable: Throwable) {
|
||||||
// Cannot happen here, but just in case
|
|
||||||
AlertDialog.Builder(requireActivity())
|
AlertDialog.Builder(requireActivity())
|
||||||
.setTitle(R.string.dialog_title_error)
|
.setTitle(R.string.dialog_title_error)
|
||||||
.setMessage(errorFormatter.toHumanReadable(throwable))
|
.setMessage(errorFormatter.toHumanReadable(throwable))
|
||||||
|
|
|
@ -125,8 +125,7 @@ class LoginServerUrlFormFragment @Inject constructor(
|
||||||
loginServerUrlFormHomeServerUrlTil.error = null
|
loginServerUrlFormHomeServerUrlTil.error = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRegistrationError(throwable: Throwable) {
|
override fun onError(throwable: Throwable) {
|
||||||
// Cannot happen here, but just in case
|
|
||||||
AlertDialog.Builder(requireActivity())
|
AlertDialog.Builder(requireActivity())
|
||||||
.setTitle(R.string.dialog_title_error)
|
.setTitle(R.string.dialog_title_error)
|
||||||
.setMessage(errorFormatter.toHumanReadable(throwable))
|
.setMessage(errorFormatter.toHumanReadable(throwable))
|
||||||
|
|
|
@ -95,8 +95,7 @@ class LoginSignUpSignInSelectionFragment @Inject constructor(
|
||||||
loginSharedActionViewModel.post(LoginNavigation.OnSignModeSelected)
|
loginSharedActionViewModel.post(LoginNavigation.OnSignModeSelected)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRegistrationError(throwable: Throwable) {
|
override fun onError(throwable: Throwable) {
|
||||||
// Cannot happen here, but just in case
|
|
||||||
AlertDialog.Builder(requireActivity())
|
AlertDialog.Builder(requireActivity())
|
||||||
.setTitle(R.string.dialog_title_error)
|
.setTitle(R.string.dialog_title_error)
|
||||||
.setMessage(errorFormatter.toHumanReadable(throwable))
|
.setMessage(errorFormatter.toHumanReadable(throwable))
|
||||||
|
|
|
@ -36,8 +36,7 @@ class LoginSplashFragment @Inject constructor(
|
||||||
loginSharedActionViewModel.post(LoginNavigation.OpenServerSelection)
|
loginSharedActionViewModel.post(LoginNavigation.OpenServerSelection)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRegistrationError(throwable: Throwable) {
|
override fun onError(throwable: Throwable) {
|
||||||
// Cannot happen here, but just in case
|
|
||||||
AlertDialog.Builder(requireActivity())
|
AlertDialog.Builder(requireActivity())
|
||||||
.setTitle(R.string.dialog_title_error)
|
.setTitle(R.string.dialog_title_error)
|
||||||
.setMessage(errorFormatter.toHumanReadable(throwable))
|
.setMessage(errorFormatter.toHumanReadable(throwable))
|
||||||
|
|
|
@ -24,5 +24,6 @@ import im.vector.matrix.android.api.auth.registration.FlowResult
|
||||||
*/
|
*/
|
||||||
sealed class LoginViewEvents {
|
sealed class LoginViewEvents {
|
||||||
data class RegistrationFlowResult(val flowResult: FlowResult) : LoginViewEvents()
|
data class RegistrationFlowResult(val flowResult: FlowResult) : LoginViewEvents()
|
||||||
data class RegistrationError(val throwable: Throwable) : LoginViewEvents()
|
data class Error(val throwable: Throwable) : LoginViewEvents()
|
||||||
|
object OutdatedHomeserver : LoginViewEvents()
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import com.squareup.inject.assisted.AssistedInject
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.auth.AuthenticationService
|
import im.vector.matrix.android.api.auth.AuthenticationService
|
||||||
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
|
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
|
||||||
|
import im.vector.matrix.android.api.auth.data.LoginFlowResult
|
||||||
import im.vector.matrix.android.api.auth.login.LoginWizard
|
import im.vector.matrix.android.api.auth.login.LoginWizard
|
||||||
import im.vector.matrix.android.api.auth.registration.FlowResult
|
import im.vector.matrix.android.api.auth.registration.FlowResult
|
||||||
import im.vector.matrix.android.api.auth.registration.RegistrationResult
|
import im.vector.matrix.android.api.auth.registration.RegistrationResult
|
||||||
|
@ -31,7 +32,6 @@ import im.vector.matrix.android.api.auth.registration.Stage
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.api.util.Cancelable
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
import im.vector.matrix.android.api.util.MatrixCallbackDelegate
|
import im.vector.matrix.android.api.util.MatrixCallbackDelegate
|
||||||
import im.vector.matrix.android.internal.auth.data.LoginFlowResponse
|
|
||||||
import im.vector.matrix.android.internal.auth.data.LoginFlowTypes
|
import im.vector.matrix.android.internal.auth.data.LoginFlowTypes
|
||||||
import im.vector.riotx.core.di.ActiveSessionHolder
|
import im.vector.riotx.core.di.ActiveSessionHolder
|
||||||
import im.vector.riotx.core.extensions.configureAndStart
|
import im.vector.riotx.core.extensions.configureAndStart
|
||||||
|
@ -166,7 +166,7 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
|
||||||
|
|
||||||
override fun onFailure(failure: Throwable) {
|
override fun onFailure(failure: Throwable) {
|
||||||
if (failure !is CancellationException) {
|
if (failure !is CancellationException) {
|
||||||
_viewEvents.post(LoginViewEvents.RegistrationError(failure))
|
_viewEvents.post(LoginViewEvents.Error(failure))
|
||||||
}
|
}
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
|
@ -188,7 +188,7 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(failure: Throwable) {
|
override fun onFailure(failure: Throwable) {
|
||||||
_viewEvents.post(LoginViewEvents.RegistrationError(failure))
|
_viewEvents.post(LoginViewEvents.Error(failure))
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
asyncRegistration = Uninitialized
|
asyncRegistration = Uninitialized
|
||||||
|
@ -210,7 +210,7 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(failure: Throwable) {
|
override fun onFailure(failure: Throwable) {
|
||||||
_viewEvents.post(LoginViewEvents.RegistrationError(failure))
|
_viewEvents.post(LoginViewEvents.Error(failure))
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
asyncRegistration = Uninitialized
|
asyncRegistration = Uninitialized
|
||||||
|
@ -525,8 +525,9 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
currentTask = authenticationService.getLoginFlow(homeServerConnectionConfigFinal, object : MatrixCallback<LoginFlowResponse> {
|
currentTask = authenticationService.getLoginFlow(homeServerConnectionConfigFinal, object : MatrixCallback<LoginFlowResult> {
|
||||||
override fun onFailure(failure: Throwable) {
|
override fun onFailure(failure: Throwable) {
|
||||||
|
_viewEvents.post(LoginViewEvents.Error(failure))
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
asyncHomeServerLoginFlowRequest = Fail(failure)
|
asyncHomeServerLoginFlowRequest = Fail(failure)
|
||||||
|
@ -534,12 +535,14 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSuccess(data: LoginFlowResponse) {
|
override fun onSuccess(data: LoginFlowResult) {
|
||||||
|
when (data) {
|
||||||
|
is LoginFlowResult.Success -> {
|
||||||
val loginMode = when {
|
val loginMode = when {
|
||||||
// SSO login is taken first
|
// SSO login is taken first
|
||||||
data.flows.any { it.type == LoginFlowTypes.SSO } -> LoginMode.Sso
|
data.loginFlowResponse.flows.any { it.type == LoginFlowTypes.SSO } -> LoginMode.Sso
|
||||||
data.flows.any { it.type == LoginFlowTypes.PASSWORD } -> LoginMode.Password
|
data.loginFlowResponse.flows.any { it.type == LoginFlowTypes.PASSWORD } -> LoginMode.Password
|
||||||
else -> LoginMode.Unsupported(data.flows.mapNotNull { it.type }.toList())
|
else -> LoginMode.Unsupported(data.loginFlowResponse.flows.mapNotNull { it.type }.toList())
|
||||||
}
|
}
|
||||||
|
|
||||||
setState {
|
setState {
|
||||||
|
@ -548,6 +551,18 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is LoginFlowResult.OutdatedHomeserver -> {
|
||||||
|
// Notify the UI
|
||||||
|
_viewEvents.post(LoginViewEvents.OutdatedHomeserver)
|
||||||
|
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
asyncHomeServerLoginFlowRequest = Uninitialized
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ class LoginWaitForEmailFragment @Inject constructor(private val errorFormatter:
|
||||||
loginWaitForEmailNotice.text = getString(R.string.login_wait_for_email_notice, params.email)
|
loginWaitForEmailNotice.text = getString(R.string.login_wait_for_email_notice, params.email)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRegistrationError(throwable: Throwable) {
|
override fun onError(throwable: Throwable) {
|
||||||
if (throwable.is401()) {
|
if (throwable.is401()) {
|
||||||
// Try again, with a delay
|
// Try again, with a delay
|
||||||
loginViewModel.handle(LoginAction.CheckIfEmailHasBeenValidated(10_000))
|
loginViewModel.handle(LoginAction.CheckIfEmailHasBeenValidated(10_000))
|
||||||
|
|
|
@ -245,8 +245,7 @@ class LoginWebFragment @Inject constructor(
|
||||||
loginViewModel.handle(LoginAction.ResetLogin)
|
loginViewModel.handle(LoginAction.ResetLogin)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRegistrationError(throwable: Throwable) {
|
override fun onError(throwable: Throwable) {
|
||||||
// Cannot happen here, but just in case
|
|
||||||
AlertDialog.Builder(requireActivity())
|
AlertDialog.Builder(requireActivity())
|
||||||
.setTitle(R.string.dialog_title_error)
|
.setTitle(R.string.dialog_title_error)
|
||||||
.setMessage(errorFormatter.toHumanReadable(throwable))
|
.setMessage(errorFormatter.toHumanReadable(throwable))
|
||||||
|
|
|
@ -101,7 +101,7 @@ class LoginTermsFragment @Inject constructor(
|
||||||
loginViewModel.handle(LoginAction.AcceptTerms)
|
loginViewModel.handle(LoginAction.AcceptTerms)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRegistrationError(throwable: Throwable) {
|
override fun onError(throwable: Throwable) {
|
||||||
AlertDialog.Builder(requireActivity())
|
AlertDialog.Builder(requireActivity())
|
||||||
.setTitle(R.string.dialog_title_error)
|
.setTitle(R.string.dialog_title_error)
|
||||||
.setMessage(errorFormatter.toHumanReadable(throwable))
|
.setMessage(errorFormatter.toHumanReadable(throwable))
|
||||||
|
|
|
@ -129,6 +129,7 @@
|
||||||
<string name="login_wait_for_email_title">Please check your email</string>
|
<string name="login_wait_for_email_title">Please check your email</string>
|
||||||
<string name="login_wait_for_email_notice">We just sent an email to %1$s.\nPlease click on the link it contains to continue the account creation.</string>
|
<string name="login_wait_for_email_notice">We just sent an email to %1$s.\nPlease click on the link it contains to continue the account creation.</string>
|
||||||
<string name="login_validation_code_is_not_correct">The entered code is not correct. Please check.</string>
|
<string name="login_validation_code_is_not_correct">The entered code is not correct. Please check.</string>
|
||||||
|
<string name="login_error_outdated_homeserver">The homeserver version is outdated, RiotX supports only recent versions of homeserver.\n\nYou may contact the administrator of the homeserver to request for an upgrade of the homeserver.</string>
|
||||||
|
|
||||||
<plurals name="login_error_limit_exceeded_retry_after">
|
<plurals name="login_error_limit_exceeded_retry_after">
|
||||||
<item quantity="one">Too many requests have been sent. You can retry in %1$d second…</item>
|
<item quantity="one">Too many requests have been sent. You can retry in %1$d second…</item>
|
||||||
|
|
Loading…
Reference in a new issue