mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-03-21 13:48:46 +03:00
Merge pull request #1630 from vector-im/feature/wellknown
Re-activate Wellknown support with updated UI (#1614)
This commit is contained in:
commit
98d56cb556
19 changed files with 172 additions and 124 deletions
CHANGES.md
matrix-sdk-android/src/main/java/im/vector/matrix/android/internal
vector/src/main
java/im/vector/riotx
core/utils
features
res
|
@ -2,7 +2,7 @@ Changes in Riot.imX 0.91.4 (2020-XX-XX)
|
||||||
===================================================
|
===================================================
|
||||||
|
|
||||||
Features ✨:
|
Features ✨:
|
||||||
-
|
- Re-activate Wellknown support with updated UI (#1614)
|
||||||
|
|
||||||
Improvements 🙌:
|
Improvements 🙌:
|
||||||
- Upload device keys only once to the homeserver and fix crash when no network (#1629)
|
- Upload device keys only once to the homeserver and fix crash when no network (#1629)
|
||||||
|
@ -21,7 +21,7 @@ SDK API changes ⚠️:
|
||||||
-
|
-
|
||||||
|
|
||||||
Build 🧱:
|
Build 🧱:
|
||||||
- Fix lint false-positive about WorkManger (#1012)
|
- Fix lint false-positive about WorkManager (#1012)
|
||||||
- Upgrade build-tools from 3.5.3 to 3.6.6
|
- Upgrade build-tools from 3.5.3 to 3.6.6
|
||||||
- Upgrade gradle from 5.4.1 to 5.6.4
|
- Upgrade gradle from 5.4.1 to 5.6.4
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.auth.login
|
||||||
import dagger.Lazy
|
import dagger.Lazy
|
||||||
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.failure.Failure
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.internal.auth.AuthAPI
|
import im.vector.matrix.android.internal.auth.AuthAPI
|
||||||
import im.vector.matrix.android.internal.auth.SessionCreator
|
import im.vector.matrix.android.internal.auth.SessionCreator
|
||||||
|
@ -27,6 +28,7 @@ import im.vector.matrix.android.internal.di.Unauthenticated
|
||||||
import im.vector.matrix.android.internal.network.RetrofitFactory
|
import im.vector.matrix.android.internal.network.RetrofitFactory
|
||||||
import im.vector.matrix.android.internal.network.executeRequest
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
import im.vector.matrix.android.internal.network.httpclient.addSocketFactory
|
import im.vector.matrix.android.internal.network.httpclient.addSocketFactory
|
||||||
|
import im.vector.matrix.android.internal.network.ssl.UnrecognizedCertificateException
|
||||||
import im.vector.matrix.android.internal.task.Task
|
import im.vector.matrix.android.internal.task.Task
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -49,13 +51,28 @@ internal class DefaultDirectLoginTask @Inject constructor(
|
||||||
|
|
||||||
override suspend fun execute(params: DirectLoginTask.Params): Session {
|
override suspend fun execute(params: DirectLoginTask.Params): Session {
|
||||||
val client = buildClient(params.homeServerConnectionConfig)
|
val client = buildClient(params.homeServerConnectionConfig)
|
||||||
val authAPI = retrofitFactory.create(client, params.homeServerConnectionConfig.homeServerUri.toString())
|
val homeServerUrl = params.homeServerConnectionConfig.homeServerUri.toString()
|
||||||
|
|
||||||
|
val authAPI = retrofitFactory.create(client, homeServerUrl)
|
||||||
.create(AuthAPI::class.java)
|
.create(AuthAPI::class.java)
|
||||||
|
|
||||||
val loginParams = PasswordLoginParams.userIdentifier(params.userId, params.password, params.deviceName)
|
val loginParams = PasswordLoginParams.userIdentifier(params.userId, params.password, params.deviceName)
|
||||||
|
|
||||||
val credentials = executeRequest<Credentials>(null) {
|
val credentials = try {
|
||||||
apiCall = authAPI.login(loginParams)
|
executeRequest<Credentials>(null) {
|
||||||
|
apiCall = authAPI.login(loginParams)
|
||||||
|
}
|
||||||
|
} catch (throwable: Throwable) {
|
||||||
|
when (throwable) {
|
||||||
|
is UnrecognizedCertificateException -> {
|
||||||
|
throw Failure.UnrecognizedCertificateFailure(
|
||||||
|
homeServerUrl,
|
||||||
|
throwable.fingerprint
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else ->
|
||||||
|
throw throwable
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sessionCreator.createSession(credentials, params.homeServerConnectionConfig)
|
return sessionCreator.createSession(credentials, params.homeServerConnectionConfig)
|
||||||
|
|
|
@ -27,6 +27,7 @@ import im.vector.matrix.android.internal.di.Unauthenticated
|
||||||
import im.vector.matrix.android.internal.network.RetrofitFactory
|
import im.vector.matrix.android.internal.network.RetrofitFactory
|
||||||
import im.vector.matrix.android.internal.network.executeRequest
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
import im.vector.matrix.android.internal.network.httpclient.addSocketFactory
|
import im.vector.matrix.android.internal.network.httpclient.addSocketFactory
|
||||||
|
import im.vector.matrix.android.internal.network.ssl.UnrecognizedCertificateException
|
||||||
import im.vector.matrix.android.internal.session.homeserver.CapabilitiesAPI
|
import im.vector.matrix.android.internal.session.homeserver.CapabilitiesAPI
|
||||||
import im.vector.matrix.android.internal.session.identity.IdentityAuthAPI
|
import im.vector.matrix.android.internal.session.identity.IdentityAuthAPI
|
||||||
import im.vector.matrix.android.internal.task.Task
|
import im.vector.matrix.android.internal.task.Task
|
||||||
|
@ -106,6 +107,12 @@ internal class DefaultGetWellknownTask @Inject constructor(
|
||||||
}
|
}
|
||||||
} catch (throwable: Throwable) {
|
} catch (throwable: Throwable) {
|
||||||
when (throwable) {
|
when (throwable) {
|
||||||
|
is UnrecognizedCertificateException -> {
|
||||||
|
throw Failure.UnrecognizedCertificateFailure(
|
||||||
|
"https://$domain",
|
||||||
|
throwable.fingerprint
|
||||||
|
)
|
||||||
|
}
|
||||||
is Failure.NetworkConnection -> {
|
is Failure.NetworkConnection -> {
|
||||||
WellknownResult.Ignore
|
WellknownResult.Ignore
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,3 +37,11 @@ internal fun String.ensureProtocol(): String {
|
||||||
else -> this
|
else -> this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun String.ensureTrailingSlash(): String {
|
||||||
|
return when {
|
||||||
|
isEmpty() -> this
|
||||||
|
!endsWith("/") -> "$this/"
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -73,6 +73,9 @@ abstract class AbstractLoginFragment : VectorBaseFragment(), OnBackPressed {
|
||||||
|
|
||||||
override fun showFailure(throwable: Throwable) {
|
override fun showFailure(throwable: Throwable) {
|
||||||
when (throwable) {
|
when (throwable) {
|
||||||
|
is Failure.Cancelled ->
|
||||||
|
/* Ignore this error, user has cancelled the action */
|
||||||
|
Unit
|
||||||
is Failure.ServerError ->
|
is Failure.ServerError ->
|
||||||
if (throwable.error.code == MatrixError.M_FORBIDDEN
|
if (throwable.error.code == MatrixError.M_FORBIDDEN
|
||||||
&& throwable.httpCode == HttpsURLConnection.HTTP_FORBIDDEN /* 403 */) {
|
&& throwable.httpCode == HttpsURLConnection.HTTP_FORBIDDEN /* 403 */) {
|
||||||
|
|
|
@ -151,8 +151,8 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||||
// TODO Disabled because it provokes a flickering
|
// TODO Disabled because it provokes a flickering
|
||||||
// ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim)
|
// ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim)
|
||||||
})
|
})
|
||||||
is LoginViewEvents.OnServerSelectionDone -> onServerSelectionDone()
|
is LoginViewEvents.OnServerSelectionDone -> onServerSelectionDone(loginViewEvents)
|
||||||
is LoginViewEvents.OnSignModeSelected -> onSignModeSelected()
|
is LoginViewEvents.OnSignModeSelected -> onSignModeSelected(loginViewEvents)
|
||||||
is LoginViewEvents.OnLoginFlowRetrieved ->
|
is LoginViewEvents.OnLoginFlowRetrieved ->
|
||||||
addFragmentToBackstack(R.id.loginFragmentContainer,
|
addFragmentToBackstack(R.id.loginFragmentContainer,
|
||||||
if (loginViewEvents.isSso) {
|
if (loginViewEvents.isSso) {
|
||||||
|
@ -228,18 +228,20 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onServerSelectionDone() = withState(loginViewModel) { state ->
|
private fun onServerSelectionDone(loginViewEvents: LoginViewEvents.OnServerSelectionDone) {
|
||||||
when (state.serverType) {
|
when (loginViewEvents.serverType) {
|
||||||
ServerType.MatrixOrg -> Unit // In this case, we wait for the login flow
|
ServerType.MatrixOrg -> Unit // In this case, we wait for the login flow
|
||||||
ServerType.Modular,
|
ServerType.Modular,
|
||||||
ServerType.Other -> addFragmentToBackstack(R.id.loginFragmentContainer,
|
ServerType.Other -> addFragmentToBackstack(R.id.loginFragmentContainer,
|
||||||
LoginServerUrlFormFragment::class.java,
|
LoginServerUrlFormFragment::class.java,
|
||||||
option = commonOption)
|
option = commonOption)
|
||||||
|
ServerType.Unknown -> Unit /* Should not happen */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onSignModeSelected() = withState(loginViewModel) { state ->
|
private fun onSignModeSelected(loginViewEvents: LoginViewEvents.OnSignModeSelected) = withState(loginViewModel) { state ->
|
||||||
when (state.signMode) {
|
// state.signMode could not be ready yet. So use value from the ViewEvent
|
||||||
|
when (loginViewEvents.signMode) {
|
||||||
SignMode.Unknown -> error("Sign mode has to be set before calling this method")
|
SignMode.Unknown -> error("Sign mode has to be set before calling this method")
|
||||||
SignMode.SignUp -> {
|
SignMode.SignUp -> {
|
||||||
// This is managed by the LoginViewEvents
|
// This is managed by the LoginViewEvents
|
||||||
|
|
|
@ -54,6 +54,7 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() {
|
||||||
|
|
||||||
private var passwordShown = false
|
private var passwordShown = false
|
||||||
private var isSignupMode = false
|
private var isSignupMode = false
|
||||||
|
|
||||||
// Temporary patch for https://github.com/vector-im/riotX-android/issues/1410,
|
// Temporary patch for https://github.com/vector-im/riotX-android/issues/1410,
|
||||||
// waiting for https://github.com/matrix-org/synapse/issues/7576
|
// waiting for https://github.com/matrix-org/synapse/issues/7576
|
||||||
private var isNumericOnlyUserIdForbidden = false
|
private var isNumericOnlyUserIdForbidden = false
|
||||||
|
@ -138,6 +139,7 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() {
|
||||||
loginServerIcon.isVisible = false
|
loginServerIcon.isVisible = false
|
||||||
loginTitle.text = getString(R.string.login_signin_matrix_id_title)
|
loginTitle.text = getString(R.string.login_signin_matrix_id_title)
|
||||||
loginNotice.text = getString(R.string.login_signin_matrix_id_notice)
|
loginNotice.text = getString(R.string.login_signin_matrix_id_notice)
|
||||||
|
loginPasswordNotice.isVisible = true
|
||||||
} else {
|
} else {
|
||||||
val resId = when (state.signMode) {
|
val resId = when (state.signMode) {
|
||||||
SignMode.Unknown -> error("developer error")
|
SignMode.Unknown -> error("developer error")
|
||||||
|
@ -164,7 +166,9 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() {
|
||||||
loginTitle.text = getString(resId, state.homeServerUrl.toReducedUrl())
|
loginTitle.text = getString(resId, state.homeServerUrl.toReducedUrl())
|
||||||
loginNotice.text = getString(R.string.login_server_other_text)
|
loginNotice.text = getString(R.string.login_server_other_text)
|
||||||
}
|
}
|
||||||
|
ServerType.Unknown -> Unit /* Should not happen */
|
||||||
}
|
}
|
||||||
|
loginPasswordNotice.isVisible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ package im.vector.riotx.features.login
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import butterknife.OnClick
|
import butterknife.OnClick
|
||||||
import com.airbnb.mvrx.withState
|
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.utils.openUrlInChromeCustomTab
|
import im.vector.riotx.core.utils.openUrlInChromeCustomTab
|
||||||
import kotlinx.android.synthetic.main.fragment_login_server_selection.*
|
import kotlinx.android.synthetic.main.fragment_login_server_selection.*
|
||||||
|
@ -40,11 +39,7 @@ class LoginServerSelectionFragment @Inject constructor() : AbstractLoginFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateSelectedChoice(state: LoginViewState) {
|
private fun updateSelectedChoice(state: LoginViewState) {
|
||||||
state.serverType.let {
|
loginServerChoiceMatrixOrg.isChecked = state.serverType == ServerType.MatrixOrg
|
||||||
loginServerChoiceMatrixOrg.isChecked = it == ServerType.MatrixOrg
|
|
||||||
loginServerChoiceModular.isChecked = it == ServerType.Modular
|
|
||||||
loginServerChoiceOther.isChecked = it == ServerType.Other
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initTextViews() {
|
private fun initTextViews() {
|
||||||
|
@ -61,42 +56,17 @@ class LoginServerSelectionFragment @Inject constructor() : AbstractLoginFragment
|
||||||
|
|
||||||
@OnClick(R.id.loginServerChoiceMatrixOrg)
|
@OnClick(R.id.loginServerChoiceMatrixOrg)
|
||||||
fun selectMatrixOrg() {
|
fun selectMatrixOrg() {
|
||||||
if (loginServerChoiceMatrixOrg.isChecked) {
|
loginViewModel.handle(LoginAction.UpdateServerType(ServerType.MatrixOrg))
|
||||||
// Consider this is a submit
|
|
||||||
submit()
|
|
||||||
} else {
|
|
||||||
loginViewModel.handle(LoginAction.UpdateServerType(ServerType.MatrixOrg))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.loginServerChoiceModular)
|
@OnClick(R.id.loginServerChoiceModular)
|
||||||
fun selectModular() {
|
fun selectModular() {
|
||||||
if (loginServerChoiceModular.isChecked) {
|
loginViewModel.handle(LoginAction.UpdateServerType(ServerType.Modular))
|
||||||
// Consider this is a submit
|
|
||||||
submit()
|
|
||||||
} else {
|
|
||||||
loginViewModel.handle(LoginAction.UpdateServerType(ServerType.Modular))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.loginServerChoiceOther)
|
@OnClick(R.id.loginServerChoiceOther)
|
||||||
fun selectOther() {
|
fun selectOther() {
|
||||||
if (loginServerChoiceOther.isChecked) {
|
loginViewModel.handle(LoginAction.UpdateServerType(ServerType.Other))
|
||||||
// Consider this is a submit
|
|
||||||
submit()
|
|
||||||
} else {
|
|
||||||
loginViewModel.handle(LoginAction.UpdateServerType(ServerType.Other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.loginServerSubmit)
|
|
||||||
fun submit() = withState(loginViewModel) { state ->
|
|
||||||
if (state.serverType == ServerType.MatrixOrg) {
|
|
||||||
// Request login flow here
|
|
||||||
loginViewModel.handle(LoginAction.UpdateHomeServer(getString(R.string.matrix_org_server_url)))
|
|
||||||
} else {
|
|
||||||
loginViewModel.handle(LoginAction.PostViewEvent(LoginViewEvents.OnServerSelectionDone))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.loginServerIKnowMyIdSubmit)
|
@OnClick(R.id.loginServerIKnowMyIdSubmit)
|
||||||
|
|
|
@ -70,7 +70,7 @@ class LoginServerUrlFormFragment @Inject constructor() : AbstractLoginFragment()
|
||||||
loginServerUrlFormHomeServerUrlTil.hint = getText(R.string.login_server_url_form_modular_hint)
|
loginServerUrlFormHomeServerUrlTil.hint = getText(R.string.login_server_url_form_modular_hint)
|
||||||
loginServerUrlFormNotice.text = getString(R.string.login_server_url_form_modular_notice)
|
loginServerUrlFormNotice.text = getString(R.string.login_server_url_form_modular_notice)
|
||||||
}
|
}
|
||||||
ServerType.Other -> {
|
else -> {
|
||||||
loginServerUrlFormIcon.isVisible = false
|
loginServerUrlFormIcon.isVisible = false
|
||||||
loginServerUrlFormTitle.text = getString(R.string.login_server_other_title)
|
loginServerUrlFormTitle.text = getString(R.string.login_server_other_title)
|
||||||
loginServerUrlFormText.text = getString(R.string.login_connect_to_a_custom_server)
|
loginServerUrlFormText.text = getString(R.string.login_connect_to_a_custom_server)
|
||||||
|
@ -78,7 +78,6 @@ class LoginServerUrlFormFragment @Inject constructor() : AbstractLoginFragment()
|
||||||
loginServerUrlFormHomeServerUrlTil.hint = getText(R.string.login_server_url_form_other_hint)
|
loginServerUrlFormHomeServerUrlTil.hint = getText(R.string.login_server_url_form_other_hint)
|
||||||
loginServerUrlFormNotice.text = getString(R.string.login_server_url_form_other_notice)
|
loginServerUrlFormNotice.text = getString(R.string.login_server_url_form_other_notice)
|
||||||
}
|
}
|
||||||
else -> error("This fragment should not be displayed in matrix.org mode")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ open class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractLo
|
||||||
loginSignupSigninTitle.text = getString(R.string.login_server_other_title)
|
loginSignupSigninTitle.text = getString(R.string.login_server_other_title)
|
||||||
loginSignupSigninText.text = getString(R.string.login_connect_to, state.homeServerUrl.toReducedUrl())
|
loginSignupSigninText.text = getString(R.string.login_connect_to, state.homeServerUrl.toReducedUrl())
|
||||||
}
|
}
|
||||||
|
ServerType.Unknown -> Unit /* Should not happen */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,9 @@ sealed class LoginViewEvents : VectorViewEvents {
|
||||||
// Navigation event
|
// Navigation event
|
||||||
|
|
||||||
object OpenServerSelection : LoginViewEvents()
|
object OpenServerSelection : LoginViewEvents()
|
||||||
object OnServerSelectionDone : LoginViewEvents()
|
data class OnServerSelectionDone(val serverType: ServerType) : LoginViewEvents()
|
||||||
data class OnLoginFlowRetrieved(val isSso: Boolean) : LoginViewEvents()
|
data class OnLoginFlowRetrieved(val isSso: Boolean) : LoginViewEvents()
|
||||||
object OnSignModeSelected : LoginViewEvents()
|
data class OnSignModeSelected(val signMode: SignMode) : LoginViewEvents()
|
||||||
object OnForgetPasswordClicked : LoginViewEvents()
|
object OnForgetPasswordClicked : LoginViewEvents()
|
||||||
object OnResetPasswordSendThreePidDone : LoginViewEvents()
|
object OnResetPasswordSendThreePidDone : LoginViewEvents()
|
||||||
object OnResetPasswordMailConfirmationSuccess : LoginViewEvents()
|
object OnResetPasswordMailConfirmationSuccess : LoginViewEvents()
|
||||||
|
|
|
@ -39,6 +39,7 @@ import im.vector.matrix.android.api.auth.registration.RegistrationResult
|
||||||
import im.vector.matrix.android.api.auth.registration.RegistrationWizard
|
import im.vector.matrix.android.api.auth.registration.RegistrationWizard
|
||||||
import im.vector.matrix.android.api.auth.registration.Stage
|
import im.vector.matrix.android.api.auth.registration.Stage
|
||||||
import im.vector.matrix.android.api.auth.wellknown.WellknownResult
|
import im.vector.matrix.android.api.auth.wellknown.WellknownResult
|
||||||
|
import im.vector.matrix.android.api.failure.Failure
|
||||||
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.riotx.R
|
import im.vector.riotx.R
|
||||||
|
@ -47,6 +48,7 @@ import im.vector.riotx.core.extensions.configureAndStart
|
||||||
import im.vector.riotx.core.extensions.exhaustive
|
import im.vector.riotx.core.extensions.exhaustive
|
||||||
import im.vector.riotx.core.platform.VectorViewModel
|
import im.vector.riotx.core.platform.VectorViewModel
|
||||||
import im.vector.riotx.core.resources.StringProvider
|
import im.vector.riotx.core.resources.StringProvider
|
||||||
|
import im.vector.riotx.core.utils.ensureTrailingSlash
|
||||||
import im.vector.riotx.features.call.WebRtcPeerConnectionManager
|
import im.vector.riotx.features.call.WebRtcPeerConnectionManager
|
||||||
import im.vector.riotx.features.notifications.PushRuleTriggerListener
|
import im.vector.riotx.features.notifications.PushRuleTriggerListener
|
||||||
import im.vector.riotx.features.session.SessionListener
|
import im.vector.riotx.features.session.SessionListener
|
||||||
|
@ -87,8 +89,12 @@ class LoginViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store the last action, to redo it after user has trusted the untrusted certificate
|
||||||
|
private var lastAction: LoginAction? = null
|
||||||
private var currentHomeServerConnectionConfig: HomeServerConnectionConfig? = null
|
private var currentHomeServerConnectionConfig: HomeServerConnectionConfig? = null
|
||||||
|
|
||||||
|
private val matrixOrgUrl = stringProvider.getString(R.string.matrix_org_server_url).ensureTrailingSlash()
|
||||||
|
|
||||||
val currentThreePid: String?
|
val currentThreePid: String?
|
||||||
get() = registrationWizard?.currentThreePid
|
get() = registrationWizard?.currentThreePid
|
||||||
|
|
||||||
|
@ -111,8 +117,8 @@ class LoginViewModel @AssistedInject constructor(
|
||||||
is LoginAction.UpdateServerType -> handleUpdateServerType(action)
|
is LoginAction.UpdateServerType -> handleUpdateServerType(action)
|
||||||
is LoginAction.UpdateSignMode -> handleUpdateSignMode(action)
|
is LoginAction.UpdateSignMode -> handleUpdateSignMode(action)
|
||||||
is LoginAction.InitWith -> handleInitWith(action)
|
is LoginAction.InitWith -> handleInitWith(action)
|
||||||
is LoginAction.UpdateHomeServer -> handleUpdateHomeserver(action)
|
is LoginAction.UpdateHomeServer -> handleUpdateHomeserver(action).also { lastAction = action }
|
||||||
is LoginAction.LoginOrRegister -> handleLoginOrRegister(action)
|
is LoginAction.LoginOrRegister -> handleLoginOrRegister(action).also { lastAction = action }
|
||||||
is LoginAction.LoginWithToken -> handleLoginWithToken(action)
|
is LoginAction.LoginWithToken -> handleLoginWithToken(action)
|
||||||
is LoginAction.WebLoginSuccess -> handleWebLoginSuccess(action)
|
is LoginAction.WebLoginSuccess -> handleWebLoginSuccess(action)
|
||||||
is LoginAction.ResetPassword -> handleResetPassword(action)
|
is LoginAction.ResetPassword -> handleResetPassword(action)
|
||||||
|
@ -126,10 +132,23 @@ class LoginViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleUserAcceptCertificate(action: LoginAction.UserAcceptCertificate) {
|
private fun handleUserAcceptCertificate(action: LoginAction.UserAcceptCertificate) {
|
||||||
// It happen when we get the login flow, so alter the homeserver config and retrieve again the login flow
|
// It happen when we get the login flow, or during direct authentication.
|
||||||
currentHomeServerConnectionConfig
|
// So alter the homeserver config and retrieve again the login flow
|
||||||
?.let { it.copy(allowedFingerprints = it.allowedFingerprints + action.fingerprint) }
|
when (val finalLastAction = lastAction) {
|
||||||
?.let { getLoginFlow(it) }
|
is LoginAction.UpdateHomeServer ->
|
||||||
|
currentHomeServerConnectionConfig
|
||||||
|
?.let { it.copy(allowedFingerprints = it.allowedFingerprints + action.fingerprint) }
|
||||||
|
?.let { getLoginFlow(it) }
|
||||||
|
is LoginAction.LoginOrRegister ->
|
||||||
|
handleDirectLogin(
|
||||||
|
finalLastAction,
|
||||||
|
HomeServerConnectionConfig.Builder()
|
||||||
|
// Will be replaced by the task
|
||||||
|
.withHomeServerUri("https://dummy.org")
|
||||||
|
.withAllowedFingerPrints(listOf(action.fingerprint))
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleLoginWithToken(action: LoginAction.LoginWithToken) {
|
private fun handleLoginWithToken(action: LoginAction.LoginWithToken) {
|
||||||
|
@ -321,7 +340,7 @@ class LoginViewModel @AssistedInject constructor(
|
||||||
LoginAction.ResetHomeServerType -> {
|
LoginAction.ResetHomeServerType -> {
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
serverType = ServerType.MatrixOrg
|
serverType = ServerType.Unknown
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,6 +352,7 @@ class LoginViewModel @AssistedInject constructor(
|
||||||
asyncHomeServerLoginFlowRequest = Uninitialized,
|
asyncHomeServerLoginFlowRequest = Uninitialized,
|
||||||
homeServerUrl = null,
|
homeServerUrl = null,
|
||||||
loginMode = LoginMode.Unknown,
|
loginMode = LoginMode.Unknown,
|
||||||
|
serverType = ServerType.Unknown,
|
||||||
loginModeSupportedTypes = emptyList()
|
loginModeSupportedTypes = emptyList()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -379,9 +399,9 @@ class LoginViewModel @AssistedInject constructor(
|
||||||
when (action.signMode) {
|
when (action.signMode) {
|
||||||
SignMode.SignUp -> startRegistrationFlow()
|
SignMode.SignUp -> startRegistrationFlow()
|
||||||
SignMode.SignIn -> startAuthenticationFlow()
|
SignMode.SignIn -> startAuthenticationFlow()
|
||||||
SignMode.SignInWithMatrixId -> _viewEvents.post(LoginViewEvents.OnSignModeSelected)
|
SignMode.SignInWithMatrixId -> _viewEvents.post(LoginViewEvents.OnSignModeSelected(SignMode.SignInWithMatrixId))
|
||||||
SignMode.Unknown -> Unit
|
SignMode.Unknown -> Unit
|
||||||
}.exhaustive
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleUpdateServerType(action: LoginAction.UpdateServerType) {
|
private fun handleUpdateServerType(action: LoginAction.UpdateServerType) {
|
||||||
|
@ -390,6 +410,15 @@ class LoginViewModel @AssistedInject constructor(
|
||||||
serverType = action.serverType
|
serverType = action.serverType
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
when (action.serverType) {
|
||||||
|
ServerType.Unknown -> Unit /* Should not happen */
|
||||||
|
ServerType.MatrixOrg ->
|
||||||
|
// Request login flow here
|
||||||
|
handle(LoginAction.UpdateHomeServer(matrixOrgUrl))
|
||||||
|
ServerType.Modular,
|
||||||
|
ServerType.Other -> _viewEvents.post(LoginViewEvents.OnServerSelectionDone(action.serverType))
|
||||||
|
}.exhaustive
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleInitWith(action: LoginAction.InitWith) {
|
private fun handleInitWith(action: LoginAction.InitWith) {
|
||||||
|
@ -427,7 +456,6 @@ class LoginViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(failure: Throwable) {
|
override fun onFailure(failure: Throwable) {
|
||||||
// TODO Handled JobCancellationException
|
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
asyncResetPassword = Fail(failure)
|
asyncResetPassword = Fail(failure)
|
||||||
|
@ -469,7 +497,6 @@ class LoginViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(failure: Throwable) {
|
override fun onFailure(failure: Throwable) {
|
||||||
// TODO Handled JobCancellationException
|
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
asyncResetMailConfirmed = Fail(failure)
|
asyncResetMailConfirmed = Fail(failure)
|
||||||
|
@ -485,23 +512,22 @@ class LoginViewModel @AssistedInject constructor(
|
||||||
SignMode.Unknown -> error("Developer error, invalid sign mode")
|
SignMode.Unknown -> error("Developer error, invalid sign mode")
|
||||||
SignMode.SignIn -> handleLogin(action)
|
SignMode.SignIn -> handleLogin(action)
|
||||||
SignMode.SignUp -> handleRegisterWith(action)
|
SignMode.SignUp -> handleRegisterWith(action)
|
||||||
SignMode.SignInWithMatrixId -> handleDirectLogin(action)
|
SignMode.SignInWithMatrixId -> handleDirectLogin(action, null)
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleDirectLogin(action: LoginAction.LoginOrRegister) {
|
private fun handleDirectLogin(action: LoginAction.LoginOrRegister, homeServerConnectionConfig: HomeServerConnectionConfig?) {
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
asyncLoginAction = Loading()
|
asyncLoginAction = Loading()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Handle certificate error in this case. Direct login is deactivated now, so we will handle that later
|
authenticationService.getWellKnownData(action.username, homeServerConnectionConfig, object : MatrixCallback<WellknownResult> {
|
||||||
authenticationService.getWellKnownData(action.username, null, object : MatrixCallback<WellknownResult> {
|
|
||||||
override fun onSuccess(data: WellknownResult) {
|
override fun onSuccess(data: WellknownResult) {
|
||||||
when (data) {
|
when (data) {
|
||||||
is WellknownResult.Prompt ->
|
is WellknownResult.Prompt ->
|
||||||
onWellknownSuccess(action, data)
|
onWellknownSuccess(action, data, homeServerConnectionConfig)
|
||||||
is WellknownResult.InvalidMatrixId -> {
|
is WellknownResult.InvalidMatrixId -> {
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
|
@ -522,23 +548,26 @@ class LoginViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(failure: Throwable) {
|
override fun onFailure(failure: Throwable) {
|
||||||
setState {
|
onDirectLoginError(failure)
|
||||||
copy(
|
|
||||||
asyncLoginAction = Fail(failure)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onWellknownSuccess(action: LoginAction.LoginOrRegister, wellKnownPrompt: WellknownResult.Prompt) {
|
private fun onWellknownSuccess(action: LoginAction.LoginOrRegister,
|
||||||
val homeServerConnectionConfig = HomeServerConnectionConfig(
|
wellKnownPrompt: WellknownResult.Prompt,
|
||||||
homeServerUri = Uri.parse(wellKnownPrompt.homeServerUrl),
|
homeServerConnectionConfig: HomeServerConnectionConfig?) {
|
||||||
identityServerUri = wellKnownPrompt.identityServerUrl?.let { Uri.parse(it) }
|
val alteredHomeServerConnectionConfig = homeServerConnectionConfig
|
||||||
)
|
?.copy(
|
||||||
|
homeServerUri = Uri.parse(wellKnownPrompt.homeServerUrl),
|
||||||
|
identityServerUri = wellKnownPrompt.identityServerUrl?.let { Uri.parse(it) }
|
||||||
|
)
|
||||||
|
?: HomeServerConnectionConfig(
|
||||||
|
homeServerUri = Uri.parse(wellKnownPrompt.homeServerUrl),
|
||||||
|
identityServerUri = wellKnownPrompt.identityServerUrl?.let { Uri.parse(it) }
|
||||||
|
)
|
||||||
|
|
||||||
authenticationService.directAuthentication(
|
authenticationService.directAuthentication(
|
||||||
homeServerConnectionConfig,
|
alteredHomeServerConnectionConfig,
|
||||||
action.username,
|
action.username,
|
||||||
action.password,
|
action.password,
|
||||||
action.initialDeviceName,
|
action.initialDeviceName,
|
||||||
|
@ -548,15 +577,29 @@ class LoginViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(failure: Throwable) {
|
override fun onFailure(failure: Throwable) {
|
||||||
setState {
|
onDirectLoginError(failure)
|
||||||
copy(
|
|
||||||
asyncLoginAction = Fail(failure)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onDirectLoginError(failure: Throwable) {
|
||||||
|
if (failure is Failure.UnrecognizedCertificateFailure) {
|
||||||
|
// Display this error in a dialog
|
||||||
|
_viewEvents.post(LoginViewEvents.Failure(failure))
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
asyncLoginAction = Uninitialized
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
asyncLoginAction = Fail(failure)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleLogin(action: LoginAction.LoginOrRegister) {
|
private fun handleLogin(action: LoginAction.LoginOrRegister) {
|
||||||
val safeLoginWizard = loginWizard
|
val safeLoginWizard = loginWizard
|
||||||
|
|
||||||
|
@ -584,7 +627,6 @@ class LoginViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(failure: Throwable) {
|
override fun onFailure(failure: Throwable) {
|
||||||
// TODO Handled JobCancellationException
|
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
asyncLoginAction = Fail(failure)
|
asyncLoginAction = Fail(failure)
|
||||||
|
@ -609,7 +651,7 @@ class LoginViewModel @AssistedInject constructor(
|
||||||
// Ensure Wizard is ready
|
// Ensure Wizard is ready
|
||||||
loginWizard
|
loginWizard
|
||||||
|
|
||||||
_viewEvents.post(LoginViewEvents.OnSignModeSelected)
|
_viewEvents.post(LoginViewEvents.OnSignModeSelected(SignMode.SignIn))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onFlowResponse(flowResult: FlowResult) {
|
private fun onFlowResponse(flowResult: FlowResult) {
|
||||||
|
@ -673,7 +715,10 @@ class LoginViewModel @AssistedInject constructor(
|
||||||
|
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
asyncHomeServerLoginFlowRequest = Loading()
|
asyncHomeServerLoginFlowRequest = Loading(),
|
||||||
|
// If user has entered https://matrix.org, ensure that server type is ServerType.MatrixOrg
|
||||||
|
// It is also useful to set the value again in the case of a certificate error on matrix.org
|
||||||
|
serverType = if (homeServerConnectionConfig.homeServerUri.toString() == matrixOrgUrl) ServerType.MatrixOrg else serverType
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,7 +727,9 @@ class LoginViewModel @AssistedInject constructor(
|
||||||
_viewEvents.post(LoginViewEvents.Failure(failure))
|
_viewEvents.post(LoginViewEvents.Failure(failure))
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
asyncHomeServerLoginFlowRequest = Uninitialized
|
asyncHomeServerLoginFlowRequest = Uninitialized,
|
||||||
|
// If we were trying to retrieve matrix.org login flow, also reset the serverType
|
||||||
|
serverType = if (serverType == ServerType.MatrixOrg) ServerType.Unknown else serverType
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ data class LoginViewState(
|
||||||
|
|
||||||
// User choices
|
// User choices
|
||||||
@PersistState
|
@PersistState
|
||||||
val serverType: ServerType = ServerType.MatrixOrg,
|
val serverType: ServerType = ServerType.Unknown,
|
||||||
@PersistState
|
@PersistState
|
||||||
val signMode: SignMode = SignMode.Unknown,
|
val signMode: SignMode = SignMode.Unknown,
|
||||||
@PersistState
|
@PersistState
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package im.vector.riotx.features.login
|
package im.vector.riotx.features.login
|
||||||
|
|
||||||
enum class ServerType {
|
enum class ServerType {
|
||||||
|
Unknown,
|
||||||
MatrixOrg,
|
MatrixOrg,
|
||||||
Modular,
|
Modular,
|
||||||
Other
|
Other
|
||||||
|
|
|
@ -93,8 +93,9 @@ class SoftLogoutFragment @Inject constructor(
|
||||||
softLogoutViewModel.handle(SoftLogoutAction.SignInAgain(password))
|
softLogoutViewModel.handle(SoftLogoutAction.SignInAgain(password))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun signinFallbackSubmit() {
|
override fun signinFallbackSubmit() = withState(loginViewModel) { state ->
|
||||||
loginViewModel.handle(LoginAction.PostViewEvent(LoginViewEvents.OnSignModeSelected))
|
// The loginViewModel has been prepared for a SSO/login fallback recovery (above)
|
||||||
|
loginViewModel.handle(LoginAction.PostViewEvent(LoginViewEvents.OnSignModeSelected(state.signMode)))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clearData() {
|
override fun clearData() {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<item android:drawable="@drawable/bg_login_server_checked" android:state_checked="true" />
|
<item android:drawable="@drawable/bg_login_server_checked" android:state_checked="true" />
|
||||||
|
<item android:drawable="@drawable/bg_login_server_checked" android:state_pressed="true" />
|
||||||
|
|
||||||
<item android:drawable="@drawable/bg_login_server" />
|
<item android:drawable="@drawable/bg_login_server" />
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,16 @@
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/loginPasswordNotice"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="start"
|
||||||
|
android:text="@string/login_signin_matrix_id_password_notice"
|
||||||
|
android:textAppearance="@style/TextAppearance.Vector.Login.Text.Small"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/loginServerTitle" />
|
app:layout_constraintTop_toBottomOf="@+id/loginServerTitle" />
|
||||||
|
|
||||||
|
<!-- Use a CheckableConstraintLayout to keep the pressed state when retrieving login flow -->
|
||||||
<im.vector.riotx.core.platform.CheckableConstraintLayout
|
<im.vector.riotx.core.platform.CheckableConstraintLayout
|
||||||
android:id="@+id/loginServerChoiceMatrixOrg"
|
android:id="@+id/loginServerChoiceMatrixOrg"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -84,7 +85,7 @@
|
||||||
|
|
||||||
</im.vector.riotx.core.platform.CheckableConstraintLayout>
|
</im.vector.riotx.core.platform.CheckableConstraintLayout>
|
||||||
|
|
||||||
<im.vector.riotx.core.platform.CheckableConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/loginServerChoiceModular"
|
android:id="@+id/loginServerChoiceModular"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -135,9 +136,9 @@
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="@+id/loginServerChoiceModularText" />
|
app:layout_constraintTop_toTopOf="@+id/loginServerChoiceModularText" />
|
||||||
|
|
||||||
</im.vector.riotx.core.platform.CheckableConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<im.vector.riotx.core.platform.CheckableConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/loginServerChoiceOther"
|
android:id="@+id/loginServerChoiceOther"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -178,45 +179,20 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceOtherTitle" />
|
app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceOtherTitle" />
|
||||||
|
|
||||||
</im.vector.riotx.core.platform.CheckableConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/loginServerSubmit"
|
|
||||||
style="@style/Style.Vector.Login.Button"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="24dp"
|
|
||||||
android:text="@string/login_continue"
|
|
||||||
android:transitionName="loginSubmitTransition"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/loginServerIKnowMyIdNotice"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceOther" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/loginServerIKnowMyIdNotice"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="24dp"
|
|
||||||
android:gravity="start"
|
|
||||||
android:text="@string/login_connect_using_matrix_id_notice"
|
|
||||||
android:textAppearance="@style/TextAppearance.Vector.Login.Text.Small"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/loginServerSubmit" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/loginServerIKnowMyIdSubmit"
|
android:id="@+id/loginServerIKnowMyIdSubmit"
|
||||||
style="@style/Style.Vector.Login.Button.Text"
|
style="@style/Style.Vector.Login.Button.Text"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
|
android:layout_marginBottom="32dp"
|
||||||
android:text="@string/login_connect_using_matrix_id_submit"
|
android:text="@string/login_connect_using_matrix_id_submit"
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/loginServerIKnowMyIdNotice" />
|
app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceOther" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|
|
@ -1995,10 +1995,11 @@ Not all features in Riot are implemented in RiotX yet. Main missing (and coming
|
||||||
</plurals>
|
</plurals>
|
||||||
|
|
||||||
<string name="login_connect_using_matrix_id_notice">Alternatively, if you already have an account and you know your Matrix identifier and your password, you can use this method:</string>
|
<string name="login_connect_using_matrix_id_notice">Alternatively, if you already have an account and you know your Matrix identifier and your password, you can use this method:</string>
|
||||||
<string name="login_connect_using_matrix_id_submit">Sign in with my Matrix identifier</string>
|
<string name="login_connect_using_matrix_id_submit">Sign in with Matrix ID</string>
|
||||||
<string name="login_signin_matrix_id_title">Sign in</string>
|
<string name="login_signin_matrix_id_title">Sign in with Matrix ID</string>
|
||||||
<string name="login_signin_matrix_id_notice">Enter your identifier and your password</string>
|
<string name="login_signin_matrix_id_notice">If you set up an account on a homeserver, use your Matrix ID (e.g. @user:domain.com) and password below.</string>
|
||||||
<string name="login_signin_matrix_id_hint">User identifier</string>
|
<string name="login_signin_matrix_id_hint">Matrix ID</string>
|
||||||
|
<string name="login_signin_matrix_id_password_notice">If you don’t know your password, go back to reset it.</string>
|
||||||
<string name="login_signin_matrix_id_error_invalid_matrix_id">This is not a valid user identifier. Expected format: \'@user:homeserver.org\'</string>
|
<string name="login_signin_matrix_id_error_invalid_matrix_id">This is not a valid user identifier. Expected format: \'@user:homeserver.org\'</string>
|
||||||
<string name="autodiscover_well_known_error">Unable to find a valid homeserver. Please check your identifier</string>
|
<string name="autodiscover_well_known_error">Unable to find a valid homeserver. Please check your identifier</string>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue