Soft Logout - request homeserver login flow
This commit is contained in:
parent
a464c910f8
commit
6811d31a6d
@ -41,6 +41,7 @@ class ErrorFormatter @Inject constructor(private val stringProvider: StringProvi
|
|||||||
stringProvider.getString(R.string.error_network_timeout)
|
stringProvider.getString(R.string.error_network_timeout)
|
||||||
throwable.ioException is UnknownHostException ->
|
throwable.ioException is UnknownHostException ->
|
||||||
// Invalid homeserver?
|
// Invalid homeserver?
|
||||||
|
// TODO Check network state, airplane mode, etc.
|
||||||
stringProvider.getString(R.string.login_error_unknown_host)
|
stringProvider.getString(R.string.login_error_unknown_host)
|
||||||
else ->
|
else ->
|
||||||
stringProvider.getString(R.string.error_no_network)
|
stringProvider.getString(R.string.error_no_network)
|
||||||
|
@ -19,6 +19,7 @@ package im.vector.riotx.features.signout
|
|||||||
import im.vector.riotx.core.platform.VectorViewModelAction
|
import im.vector.riotx.core.platform.VectorViewModelAction
|
||||||
|
|
||||||
sealed class SoftLogoutAction : VectorViewModelAction {
|
sealed class SoftLogoutAction : VectorViewModelAction {
|
||||||
|
object RetryLoginFlow : SoftLogoutAction()
|
||||||
data class SignInAgain(val password: String) : SoftLogoutAction()
|
data class SignInAgain(val password: String) : SoftLogoutAction()
|
||||||
// TODO Add reset pwd...
|
// TODO Add reset pwd...
|
||||||
}
|
}
|
||||||
|
@ -30,18 +30,22 @@ import im.vector.riotx.R
|
|||||||
import im.vector.riotx.core.dialogs.withColoredButton
|
import im.vector.riotx.core.dialogs.withColoredButton
|
||||||
import im.vector.riotx.core.error.ErrorFormatter
|
import im.vector.riotx.core.error.ErrorFormatter
|
||||||
import im.vector.riotx.core.extensions.hideKeyboard
|
import im.vector.riotx.core.extensions.hideKeyboard
|
||||||
|
import im.vector.riotx.core.extensions.setTextOrHide
|
||||||
import im.vector.riotx.core.extensions.showPassword
|
import im.vector.riotx.core.extensions.showPassword
|
||||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||||
import im.vector.riotx.features.MainActivity
|
import im.vector.riotx.features.MainActivity
|
||||||
import im.vector.riotx.features.MainActivityArgs
|
import im.vector.riotx.features.MainActivityArgs
|
||||||
|
import im.vector.riotx.features.login.LoginMode
|
||||||
import io.reactivex.rxkotlin.subscribeBy
|
import io.reactivex.rxkotlin.subscribeBy
|
||||||
import kotlinx.android.synthetic.main.fragment_soft_logout.*
|
import kotlinx.android.synthetic.main.fragment_soft_logout.*
|
||||||
|
import kotlinx.android.synthetic.main.item_error_retry.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In this screen:
|
* In this screen:
|
||||||
* - the user is asked to enter a password to sign in again to a homeserver.
|
* - the user is asked to enter a password to sign in again to a homeserver.
|
||||||
* - or to cleanup all the data
|
* - or to cleanup all the data
|
||||||
|
* TODO: migrate to Epoxy (along with all the login screen?)
|
||||||
*/
|
*/
|
||||||
class SoftLogoutFragment @Inject constructor(
|
class SoftLogoutFragment @Inject constructor(
|
||||||
private val errorFormatter: ErrorFormatter
|
private val errorFormatter: ErrorFormatter
|
||||||
@ -67,6 +71,11 @@ class SoftLogoutFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.itemErrorRetryButton)
|
||||||
|
fun retry() {
|
||||||
|
softLogoutViewModel.handle(SoftLogoutAction.RetryLoginFlow)
|
||||||
|
}
|
||||||
|
|
||||||
@OnClick(R.id.softLogoutSubmit)
|
@OnClick(R.id.softLogoutSubmit)
|
||||||
fun submit() {
|
fun submit() {
|
||||||
cleanupUi()
|
cleanupUi()
|
||||||
@ -75,29 +84,36 @@ class SoftLogoutFragment @Inject constructor(
|
|||||||
softLogoutViewModel.handle(SoftLogoutAction.SignInAgain(password))
|
softLogoutViewModel.handle(SoftLogoutAction.SignInAgain(password))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.softLogoutFormSsoSubmit)
|
||||||
|
fun ssoSubmit() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
@OnClick(R.id.softLogoutClearDataSubmit)
|
@OnClick(R.id.softLogoutClearDataSubmit)
|
||||||
fun clearData() = withState(softLogoutViewModel) { state ->
|
fun clearData() {
|
||||||
cleanupUi()
|
withState(softLogoutViewModel) { state ->
|
||||||
|
cleanupUi()
|
||||||
|
|
||||||
val messageResId = if (state.hasUnsavedKeys) {
|
val messageResId = if (state.hasUnsavedKeys) {
|
||||||
R.string.soft_logout_clear_data_dialog_content
|
R.string.soft_logout_clear_data_dialog_content
|
||||||
} else {
|
} else {
|
||||||
R.string.soft_logout_clear_data_dialog_e2e_warning_content
|
R.string.soft_logout_clear_data_dialog_e2e_warning_content
|
||||||
|
}
|
||||||
|
|
||||||
|
AlertDialog.Builder(requireActivity())
|
||||||
|
.setTitle(R.string.soft_logout_clear_data_dialog_title)
|
||||||
|
.setMessage(messageResId)
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.setPositiveButton(R.string.soft_logout_clear_data_submit) { _, _ ->
|
||||||
|
MainActivity.restartApp(requireActivity(), MainActivityArgs(
|
||||||
|
clearCache = true,
|
||||||
|
clearCredentials = true,
|
||||||
|
isUserLoggedOut = true
|
||||||
|
))
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
.withColoredButton(DialogInterface.BUTTON_POSITIVE)
|
||||||
}
|
}
|
||||||
|
|
||||||
AlertDialog.Builder(requireActivity())
|
|
||||||
.setTitle(R.string.soft_logout_clear_data_dialog_title)
|
|
||||||
.setMessage(messageResId)
|
|
||||||
.setNegativeButton(R.string.cancel, null)
|
|
||||||
.setPositiveButton(R.string.soft_logout_clear_data_submit) { _, _ ->
|
|
||||||
MainActivity.restartApp(requireActivity(), MainActivityArgs(
|
|
||||||
clearCache = true,
|
|
||||||
clearCredentials = true,
|
|
||||||
isUserLoggedOut = true
|
|
||||||
))
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
.withColoredButton(DialogInterface.BUTTON_POSITIVE)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cleanupUi() {
|
private fun cleanupUi() {
|
||||||
@ -114,6 +130,14 @@ class SoftLogoutFragment @Inject constructor(
|
|||||||
softLogoutE2eWarningNotice.isVisible = state.hasUnsavedKeys
|
softLogoutE2eWarningNotice.isVisible = state.hasUnsavedKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupForm(state: SoftLogoutViewState) {
|
||||||
|
softLogoutFormLoading.isVisible = state.asyncHomeServerLoginFlowRequest is Loading
|
||||||
|
softLogoutFormSsoSubmit.isVisible = state.asyncHomeServerLoginFlowRequest.invoke() == LoginMode.Sso
|
||||||
|
softLogoutFormPassword.isVisible = state.asyncHomeServerLoginFlowRequest.invoke() == LoginMode.Password
|
||||||
|
softLogoutFormError.isVisible = state.asyncHomeServerLoginFlowRequest is Fail
|
||||||
|
itemErrorRetryText.setTextOrHide((state.asyncHomeServerLoginFlowRequest as? Fail)?.error?.let { errorFormatter.toHumanReadable(it) })
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupSubmitButton() {
|
private fun setupSubmitButton() {
|
||||||
softLogoutPasswordField.textChanges()
|
softLogoutPasswordField.textChanges()
|
||||||
.map { it.trim().isNotEmpty() }
|
.map { it.trim().isNotEmpty() }
|
||||||
@ -156,6 +180,7 @@ class SoftLogoutFragment @Inject constructor(
|
|||||||
|
|
||||||
override fun invalidate() = withState(softLogoutViewModel) { state ->
|
override fun invalidate() = withState(softLogoutViewModel) { state ->
|
||||||
setupUi(state)
|
setupUi(state)
|
||||||
|
setupForm(state)
|
||||||
setupAutoFill()
|
setupAutoFill()
|
||||||
|
|
||||||
when (state.asyncLoginAction) {
|
when (state.asyncLoginAction) {
|
||||||
|
@ -20,12 +20,16 @@ import com.airbnb.mvrx.*
|
|||||||
import com.squareup.inject.assisted.Assisted
|
import com.squareup.inject.assisted.Assisted
|
||||||
import com.squareup.inject.assisted.AssistedInject
|
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.data.LoginFlowResult
|
||||||
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.LoginFlowTypes
|
||||||
import im.vector.riotx.core.di.ActiveSessionHolder
|
import im.vector.riotx.core.di.ActiveSessionHolder
|
||||||
import im.vector.riotx.core.extensions.hasUnsavedKeys
|
import im.vector.riotx.core.extensions.hasUnsavedKeys
|
||||||
import im.vector.riotx.core.extensions.toReducedUrl
|
import im.vector.riotx.core.extensions.toReducedUrl
|
||||||
import im.vector.riotx.core.platform.VectorViewModel
|
import im.vector.riotx.core.platform.VectorViewModel
|
||||||
|
import im.vector.riotx.features.login.LoginMode
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -33,8 +37,9 @@ import im.vector.riotx.core.platform.VectorViewModel
|
|||||||
class SoftLogoutViewModel @AssistedInject constructor(
|
class SoftLogoutViewModel @AssistedInject constructor(
|
||||||
@Assisted initialState: SoftLogoutViewState,
|
@Assisted initialState: SoftLogoutViewState,
|
||||||
private val session: Session,
|
private val session: Session,
|
||||||
private val activeSessionHolder: ActiveSessionHolder)
|
private val activeSessionHolder: ActiveSessionHolder,
|
||||||
: VectorViewModel<SoftLogoutViewState, SoftLogoutAction>(initialState) {
|
private val authenticationService: AuthenticationService
|
||||||
|
) : VectorViewModel<SoftLogoutViewState, SoftLogoutAction>(initialState) {
|
||||||
|
|
||||||
@AssistedInject.Factory
|
@AssistedInject.Factory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
@ -63,13 +68,83 @@ class SoftLogoutViewModel @AssistedInject constructor(
|
|||||||
|
|
||||||
private var currentTask: Cancelable? = null
|
private var currentTask: Cancelable? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
// Get the supported login flow
|
||||||
|
getSupportedLoginFlow()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSupportedLoginFlow() {
|
||||||
|
val homeServerConnectionConfig = session.sessionParams.homeServerConnectionConfig
|
||||||
|
|
||||||
|
currentTask?.cancel()
|
||||||
|
currentTask = null
|
||||||
|
authenticationService.cancelPendingLoginOrRegistration()
|
||||||
|
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
asyncHomeServerLoginFlowRequest = Loading()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentTask = authenticationService.getLoginFlow(homeServerConnectionConfig, object : MatrixCallback<LoginFlowResult> {
|
||||||
|
override fun onFailure(failure: Throwable) {
|
||||||
|
// TODO _viewEvents.post(LoginViewEvents.Error(failure))
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
asyncHomeServerLoginFlowRequest = Fail(failure)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSuccess(data: LoginFlowResult) {
|
||||||
|
when (data) {
|
||||||
|
is LoginFlowResult.Success -> {
|
||||||
|
val loginMode = when {
|
||||||
|
// SSO login is taken first
|
||||||
|
data.loginFlowResponse.flows.any { it.type == LoginFlowTypes.SSO } -> LoginMode.Sso
|
||||||
|
data.loginFlowResponse.flows.any { it.type == LoginFlowTypes.PASSWORD } -> LoginMode.Password
|
||||||
|
else -> LoginMode.Unsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((loginMode == LoginMode.Password && !data.isLoginAndRegistrationSupported)
|
||||||
|
|| loginMode == LoginMode.Unsupported) {
|
||||||
|
notSupported()
|
||||||
|
} else {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
asyncHomeServerLoginFlowRequest = Success(loginMode)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is LoginFlowResult.OutdatedHomeserver -> {
|
||||||
|
notSupported()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun notSupported() {
|
||||||
|
// Should not happen since it's a re-logout
|
||||||
|
// Notify the UI
|
||||||
|
// _viewEvents.post(LoginViewEvents.OutdatedHomeserver)
|
||||||
|
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
asyncHomeServerLoginFlowRequest = Fail(IllegalStateException("Should not happen"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// TODO Cleanup
|
// TODO Cleanup
|
||||||
// private val _viewEvents = PublishDataSource<LoginViewEvents>()
|
// private val _viewEvents = PublishDataSource<LoginViewEvents>()
|
||||||
// val viewEvents: DataSource<LoginViewEvents> = _viewEvents
|
// val viewEvents: DataSource<LoginViewEvents> = _viewEvents
|
||||||
|
|
||||||
override fun handle(action: SoftLogoutAction) {
|
override fun handle(action: SoftLogoutAction) {
|
||||||
when (action) {
|
when (action) {
|
||||||
is SoftLogoutAction.SignInAgain -> handleSignInAgain(action)
|
is SoftLogoutAction.RetryLoginFlow -> getSupportedLoginFlow()
|
||||||
|
is SoftLogoutAction.SignInAgain -> handleSignInAgain(action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,8 +20,10 @@ import com.airbnb.mvrx.Async
|
|||||||
import com.airbnb.mvrx.Loading
|
import com.airbnb.mvrx.Loading
|
||||||
import com.airbnb.mvrx.MvRxState
|
import com.airbnb.mvrx.MvRxState
|
||||||
import com.airbnb.mvrx.Uninitialized
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
import im.vector.riotx.features.login.LoginMode
|
||||||
|
|
||||||
data class SoftLogoutViewState(
|
data class SoftLogoutViewState(
|
||||||
|
val asyncHomeServerLoginFlowRequest: Async<LoginMode> = Uninitialized,
|
||||||
val asyncLoginAction: Async<Unit> = Uninitialized,
|
val asyncLoginAction: Async<Unit> = Uninitialized,
|
||||||
val homeServerUrl: String,
|
val homeServerUrl: String,
|
||||||
val userId: String,
|
val userId: String,
|
||||||
|
@ -55,73 +55,117 @@
|
|||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/softLogoutPasswordContainer"
|
android:id="@+id/softLogoutFormContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp">
|
android:layout_marginTop="16dp">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<!-- Displayed while loading -->
|
||||||
android:id="@+id/softLogoutPasswordFieldTil"
|
<ProgressBar
|
||||||
style="@style/VectorTextInputLayout"
|
android:id="@+id/softLogoutFormLoading"
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:hint="@string/soft_logout_signin_password_hint"
|
|
||||||
app:errorEnabled="true"
|
|
||||||
app:errorIconDrawable="@null">
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
|
||||||
android:id="@+id/softLogoutPasswordField"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ems="10"
|
|
||||||
android:inputType="textPassword"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:paddingEnd="48dp"
|
|
||||||
android:paddingRight="48dp"
|
|
||||||
tools:ignore="RtlSymmetry" />
|
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/softLogoutPasswordReveal"
|
|
||||||
android:layout_width="@dimen/layout_touch_size"
|
|
||||||
android:layout_height="@dimen/layout_touch_size"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:scaleType="center"
|
|
||||||
android:src="@drawable/ic_eye_black"
|
|
||||||
android:tint="?attr/colorAccent"
|
|
||||||
tools:contentDescription="@string/a11y_show_password" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/softLogoutForgetPasswordButton"
|
|
||||||
style="@style/Style.Vector.Login.Button.Text"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="start"
|
android:layout_gravity="center_horizontal" />
|
||||||
android:text="@string/auth_forgot_password" />
|
|
||||||
|
|
||||||
|
<!-- Displayed for SSO mode -->
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/softLogoutSubmit"
|
android:id="@+id/softLogoutFormSsoSubmit"
|
||||||
style="@style/Style.Vector.Login.Button"
|
style="@style/Style.Vector.Login.Button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_gravity="center_horizontal"
|
||||||
android:layout_gravity="end"
|
android:text="@string/login_signin_sso"
|
||||||
android:text="@string/soft_logout_signin_submit"
|
android:visibility="gone"
|
||||||
tools:enabled="false"
|
tools:visibility="visible" />
|
||||||
tools:ignore="RelativeOverlap" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
<!-- Displayed in case of error -->
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/softLogoutFormError"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<include layout="@layout/item_error_retry" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<!-- Displayed for password mode -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/softLogoutFormPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/softLogoutPasswordContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/softLogoutPasswordFieldTil"
|
||||||
|
style="@style/VectorTextInputLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/soft_logout_signin_password_hint"
|
||||||
|
app:errorEnabled="true"
|
||||||
|
app:errorIconDrawable="@null">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/softLogoutPasswordField"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ems="10"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:paddingEnd="48dp"
|
||||||
|
android:paddingRight="48dp"
|
||||||
|
tools:ignore="RtlSymmetry" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/softLogoutPasswordReveal"
|
||||||
|
android:layout_width="@dimen/layout_touch_size"
|
||||||
|
android:layout_height="@dimen/layout_touch_size"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:src="@drawable/ic_eye_black"
|
||||||
|
android:tint="?attr/colorAccent"
|
||||||
|
tools:contentDescription="@string/a11y_show_password" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/softLogoutForgetPasswordButton"
|
||||||
|
style="@style/Style.Vector.Login.Button.Text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="start"
|
||||||
|
android:text="@string/auth_forgot_password" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/softLogoutSubmit"
|
||||||
|
style="@style/Style.Vector.Login.Button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:text="@string/soft_logout_signin_submit"
|
||||||
|
tools:enabled="false"
|
||||||
|
tools:ignore="RelativeOverlap" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/progressBar"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?riotx_background"
|
android:background="?riotx_background"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user