mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-26 19:36:08 +03:00
SoftLogout: use Epoxy
This commit is contained in:
parent
6811d31a6d
commit
00d0c34363
22 changed files with 763 additions and 305 deletions
|
@ -20,6 +20,8 @@ import im.vector.riotx.core.platform.VectorViewModelAction
|
|||
|
||||
sealed class SoftLogoutAction : VectorViewModelAction {
|
||||
object RetryLoginFlow : SoftLogoutAction()
|
||||
object TogglePassword : SoftLogoutAction()
|
||||
|
||||
data class SignInAgain(val password: String) : SoftLogoutAction()
|
||||
// TODO Add reset pwd...
|
||||
}
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* 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.riotx.features.signout
|
||||
|
||||
import com.airbnb.epoxy.EpoxyController
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Incomplete
|
||||
import com.airbnb.mvrx.Success
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.loadingItem
|
||||
import im.vector.riotx.core.error.ErrorFormatter
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import im.vector.riotx.features.login.LoginMode
|
||||
import im.vector.riotx.features.signout.epoxy.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class SoftLogoutController @Inject constructor(
|
||||
private val stringProvider: StringProvider,
|
||||
private val errorFormatter: ErrorFormatter
|
||||
) : EpoxyController() {
|
||||
|
||||
var listener: Listener? = null
|
||||
|
||||
private var viewState: SoftLogoutViewState? = null
|
||||
|
||||
init {
|
||||
// We are requesting a model build directly as the first build of epoxy is on the main thread.
|
||||
// It avoids to build the whole list of breadcrumbs on the main thread.
|
||||
requestModelBuild()
|
||||
}
|
||||
|
||||
fun update(viewState: SoftLogoutViewState) {
|
||||
this.viewState = viewState
|
||||
requestModelBuild()
|
||||
}
|
||||
|
||||
override fun buildModels() {
|
||||
val safeViewState = viewState ?: return
|
||||
|
||||
buildHeader(safeViewState)
|
||||
buildForm(safeViewState)
|
||||
buildClearDataSection()
|
||||
}
|
||||
|
||||
private fun buildHeader(state: SoftLogoutViewState) {
|
||||
loginHeaderItem {
|
||||
id("header")
|
||||
}
|
||||
loginTitleItem {
|
||||
id("title")
|
||||
text(stringProvider.getString(R.string.soft_logout_title))
|
||||
}
|
||||
loginTitleSmallItem {
|
||||
id("signTitle")
|
||||
text(stringProvider.getString(R.string.soft_logout_signin_title))
|
||||
}
|
||||
loginTextItem {
|
||||
id("signText1")
|
||||
text(stringProvider.getString(R.string.soft_logout_signin_notice,
|
||||
state.homeServerUrl,
|
||||
state.userDisplayName,
|
||||
state.userId))
|
||||
}
|
||||
if (state.hasUnsavedKeys) {
|
||||
loginTextItem {
|
||||
id("signText2")
|
||||
text(stringProvider.getString(R.string.soft_logout_signin_e2e_warning_notice))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildForm(state: SoftLogoutViewState) {
|
||||
when (state.asyncHomeServerLoginFlowRequest) {
|
||||
is Incomplete -> {
|
||||
loadingItem {
|
||||
id("loading")
|
||||
}
|
||||
}
|
||||
is Fail -> {
|
||||
loginErrorWithRetryItem {
|
||||
id("errorRetry")
|
||||
text(errorFormatter.toHumanReadable(state.asyncHomeServerLoginFlowRequest.error))
|
||||
listener { listener?.retry() }
|
||||
}
|
||||
}
|
||||
is Success -> {
|
||||
when (state.asyncHomeServerLoginFlowRequest.invoke()) {
|
||||
LoginMode.Password -> {
|
||||
loginPasswordFormItem {
|
||||
id("passwordForm")
|
||||
stringProvider(stringProvider)
|
||||
passwordShown(state.passwordShown)
|
||||
errorText((state.asyncLoginAction as? Fail)?.error?.let { errorFormatter.toHumanReadable(it) })
|
||||
passwordRevealClickListener { listener?.revealPasswordClicked() }
|
||||
forgetPasswordClickListener { listener?.forgetPasswordClicked() }
|
||||
submitClickListener { password -> listener?.submit(password) }
|
||||
}
|
||||
}
|
||||
LoginMode.Sso -> {
|
||||
loginCenterButtonItem {
|
||||
id("sso")
|
||||
listener { listener?.ssoSubmit() }
|
||||
}
|
||||
}
|
||||
LoginMode.Unknown -> Unit // Should not happen
|
||||
LoginMode.Unsupported -> Unit // Should not happen
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildClearDataSection() {
|
||||
loginTitleSmallItem {
|
||||
id("clearDataTitle")
|
||||
text(stringProvider.getString(R.string.soft_logout_clear_data_title))
|
||||
}
|
||||
loginTextItem {
|
||||
id("clearDataText")
|
||||
text(stringProvider.getString(R.string.soft_logout_clear_data_notice))
|
||||
}
|
||||
loginRedButtonItem {
|
||||
id("clearDataSubmit")
|
||||
text(stringProvider.getString(R.string.soft_logout_clear_data_submit))
|
||||
listener { listener?.clearData() }
|
||||
}
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
fun retry()
|
||||
fun submit(password: String)
|
||||
fun ssoSubmit()
|
||||
fun clearData()
|
||||
fun forgetPasswordClicked()
|
||||
fun revealPasswordClicked()
|
||||
}
|
||||
}
|
|
@ -17,87 +17,78 @@
|
|||
package im.vector.riotx.features.signout
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.autofill.HintConstants
|
||||
import androidx.core.view.isVisible
|
||||
import butterknife.OnClick
|
||||
import com.airbnb.mvrx.*
|
||||
import com.jakewharton.rxbinding3.widget.textChanges
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.dialogs.withColoredButton
|
||||
import im.vector.riotx.core.error.ErrorFormatter
|
||||
import im.vector.riotx.core.extensions.cleanup
|
||||
import im.vector.riotx.core.extensions.configureWith
|
||||
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.platform.VectorBaseFragment
|
||||
import im.vector.riotx.features.MainActivity
|
||||
import im.vector.riotx.features.MainActivityArgs
|
||||
import im.vector.riotx.features.login.LoginMode
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
import kotlinx.android.synthetic.main.fragment_soft_logout.*
|
||||
import kotlinx.android.synthetic.main.item_error_retry.*
|
||||
import kotlinx.android.synthetic.main.fragment_generic_recycler.*
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* In this screen:
|
||||
* - the user is asked to enter a password to sign in again to a homeserver.
|
||||
* - or to cleanup all the data
|
||||
* TODO: migrate to Epoxy (along with all the login screen?)
|
||||
*/
|
||||
class SoftLogoutFragment @Inject constructor(
|
||||
private val errorFormatter: ErrorFormatter
|
||||
) : VectorBaseFragment() {
|
||||
|
||||
private var passwordShown = false
|
||||
private val errorFormatter: ErrorFormatter,
|
||||
private val softLogoutController: SoftLogoutController
|
||||
) : VectorBaseFragment(), SoftLogoutController.Listener {
|
||||
|
||||
private val softLogoutViewModel: SoftLogoutViewModel by activityViewModel()
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_soft_logout
|
||||
override fun getLayoutResId() = R.layout.fragment_generic_recycler
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
setupSubmitButton()
|
||||
setupPasswordReveal()
|
||||
setupAutoFill()
|
||||
setupRecyclerView()
|
||||
|
||||
// TODO setupSubmitButton()
|
||||
// TODO setupPasswordReveal()
|
||||
}
|
||||
|
||||
private fun setupAutoFill() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
softLogoutPasswordField.setAutofillHints(HintConstants.AUTOFILL_HINT_PASSWORD)
|
||||
}
|
||||
private fun setupRecyclerView() {
|
||||
recyclerView.configureWith(softLogoutController)
|
||||
softLogoutController.listener = this
|
||||
}
|
||||
|
||||
@OnClick(R.id.itemErrorRetryButton)
|
||||
fun retry() {
|
||||
override fun onDestroyView() {
|
||||
recyclerView.cleanup()
|
||||
softLogoutController.listener = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun retry() {
|
||||
softLogoutViewModel.handle(SoftLogoutAction.RetryLoginFlow)
|
||||
}
|
||||
|
||||
@OnClick(R.id.softLogoutSubmit)
|
||||
fun submit() {
|
||||
override fun submit(password: String) {
|
||||
cleanupUi()
|
||||
|
||||
val password = softLogoutPasswordField.text.toString()
|
||||
softLogoutViewModel.handle(SoftLogoutAction.SignInAgain(password))
|
||||
}
|
||||
|
||||
@OnClick(R.id.softLogoutFormSsoSubmit)
|
||||
fun ssoSubmit() {
|
||||
override fun ssoSubmit() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@OnClick(R.id.softLogoutClearDataSubmit)
|
||||
fun clearData() {
|
||||
override fun clearData() {
|
||||
withState(softLogoutViewModel) { state ->
|
||||
cleanupUi()
|
||||
|
||||
val messageResId = if (state.hasUnsavedKeys) {
|
||||
R.string.soft_logout_clear_data_dialog_content
|
||||
} else {
|
||||
R.string.soft_logout_clear_data_dialog_e2e_warning_content
|
||||
} else {
|
||||
R.string.soft_logout_clear_data_dialog_content
|
||||
}
|
||||
|
||||
AlertDialog.Builder(requireActivity())
|
||||
|
@ -117,83 +108,30 @@ class SoftLogoutFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun cleanupUi() {
|
||||
softLogoutSubmit.hideKeyboard()
|
||||
softLogoutPasswordFieldTil.error = null
|
||||
}
|
||||
|
||||
private fun setupUi(state: SoftLogoutViewState) {
|
||||
softLogoutNotice.text = getString(R.string.soft_logout_signin_notice,
|
||||
state.homeServerUrl,
|
||||
state.userDisplayName,
|
||||
state.userId)
|
||||
|
||||
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) })
|
||||
recyclerView.hideKeyboard()
|
||||
// TODO softLogoutPasswordFieldTil.error = null
|
||||
}
|
||||
|
||||
private fun setupSubmitButton() {
|
||||
softLogoutPasswordField.textChanges()
|
||||
.map { it.trim().isNotEmpty() }
|
||||
.subscribeBy {
|
||||
softLogoutPasswordFieldTil.error = null
|
||||
softLogoutSubmit.isEnabled = it
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
// softLogoutPasswordField.textChanges()
|
||||
// .map { it.trim().isNotEmpty() }
|
||||
// .subscribeBy {
|
||||
// softLogoutPasswordFieldTil.error = null
|
||||
// softLogoutSubmit.isEnabled = it
|
||||
// }
|
||||
// .disposeOnDestroyView()
|
||||
}
|
||||
|
||||
@OnClick(R.id.softLogoutForgetPasswordButton)
|
||||
fun forgetPasswordClicked() {
|
||||
override fun forgetPasswordClicked() {
|
||||
// TODO
|
||||
// loginSharedActionViewModel.post(LoginNavigation.OnForgetPasswordClicked)
|
||||
}
|
||||
|
||||
private fun setupPasswordReveal() {
|
||||
passwordShown = false
|
||||
|
||||
softLogoutPasswordReveal.setOnClickListener {
|
||||
passwordShown = !passwordShown
|
||||
|
||||
renderPasswordField()
|
||||
}
|
||||
|
||||
renderPasswordField()
|
||||
}
|
||||
|
||||
private fun renderPasswordField() {
|
||||
softLogoutPasswordField.showPassword(passwordShown)
|
||||
|
||||
if (passwordShown) {
|
||||
softLogoutPasswordReveal.setImageResource(R.drawable.ic_eye_closed_black)
|
||||
softLogoutPasswordReveal.contentDescription = getString(R.string.a11y_hide_password)
|
||||
} else {
|
||||
softLogoutPasswordReveal.setImageResource(R.drawable.ic_eye_black)
|
||||
softLogoutPasswordReveal.contentDescription = getString(R.string.a11y_show_password)
|
||||
}
|
||||
override fun revealPasswordClicked() {
|
||||
softLogoutViewModel.handle(SoftLogoutAction.TogglePassword)
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(softLogoutViewModel) { state ->
|
||||
setupUi(state)
|
||||
setupForm(state)
|
||||
setupAutoFill()
|
||||
|
||||
when (state.asyncLoginAction) {
|
||||
is Loading -> {
|
||||
// Ensure password is hidden
|
||||
passwordShown = false
|
||||
renderPasswordField()
|
||||
}
|
||||
is Fail -> {
|
||||
softLogoutPasswordFieldTil.error = errorFormatter.toHumanReadable(state.asyncLoginAction.error)
|
||||
}
|
||||
// Success is handled by the SoftLogoutActivity
|
||||
is Success -> Unit
|
||||
}
|
||||
softLogoutController.update(state)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,11 +145,28 @@ class SoftLogoutViewModel @AssistedInject constructor(
|
|||
when (action) {
|
||||
is SoftLogoutAction.RetryLoginFlow -> getSupportedLoginFlow()
|
||||
is SoftLogoutAction.SignInAgain -> handleSignInAgain(action)
|
||||
is SoftLogoutAction.TogglePassword -> handleTogglePassword()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleTogglePassword() {
|
||||
withState {
|
||||
setState {
|
||||
copy(
|
||||
passwordShown = !this.passwordShown
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSignInAgain(action: SoftLogoutAction.SignInAgain) {
|
||||
setState { copy(asyncLoginAction = Loading()) }
|
||||
setState {
|
||||
copy(
|
||||
asyncLoginAction = Loading(),
|
||||
// Ensure password is hidden
|
||||
passwordShown = false
|
||||
)
|
||||
}
|
||||
currentTask = session.signInAgain(action.password,
|
||||
object : MatrixCallback<Unit> {
|
||||
override fun onFailure(failure: Throwable) {
|
||||
|
|
|
@ -28,7 +28,8 @@ data class SoftLogoutViewState(
|
|||
val homeServerUrl: String,
|
||||
val userId: String,
|
||||
val userDisplayName: String,
|
||||
val hasUnsavedKeys: Boolean
|
||||
val hasUnsavedKeys: Boolean,
|
||||
val passwordShown: Boolean = false
|
||||
) : MvRxState {
|
||||
|
||||
fun isLoading(): Boolean {
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.riotx.features.signout.epoxy
|
||||
|
||||
import android.widget.Button
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotx.core.extensions.setTextOrHide
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_login_centered_button)
|
||||
abstract class LoginCenterButtonItem : VectorEpoxyModel<LoginCenterButtonItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute var text: String? = null
|
||||
@EpoxyAttribute var listener: (() -> Unit)? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
|
||||
holder.button.setTextOrHide(text)
|
||||
holder.button.setOnClickListener {
|
||||
listener?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val button by bind<Button>(R.id.itemLoginCenteredButton)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.riotx.features.signout.epoxy
|
||||
|
||||
import android.widget.Button
|
||||
import android.widget.TextView
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_login_error_retry)
|
||||
abstract class LoginErrorWithRetryItem : VectorEpoxyModel<LoginErrorWithRetryItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
var text: String? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var listener: (() -> Unit)? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
holder.textView.text = text
|
||||
holder.buttonView.setOnClickListener { listener?.invoke() }
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val textView by bind<TextView>(R.id.itemLoginErrorRetryText)
|
||||
val buttonView by bind<Button>(R.id.itemLoginErrorRetryButton)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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.riotx.features.signout.epoxy
|
||||
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_login_header)
|
||||
abstract class LoginHeaderItem : VectorEpoxyModel<LoginHeaderItem.Holder>() {
|
||||
class Holder : VectorEpoxyHolder()
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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.riotx.features.signout.epoxy
|
||||
|
||||
import android.os.Build
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import androidx.autofill.HintConstants
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotx.core.extensions.showPassword
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_login_password_form)
|
||||
abstract class LoginPasswordFormItem : VectorEpoxyModel<LoginPasswordFormItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute var passwordShown: Boolean = false
|
||||
@EpoxyAttribute var errorText: String? = null
|
||||
@EpoxyAttribute lateinit var stringProvider: StringProvider
|
||||
@EpoxyAttribute var passwordRevealClickListener: (() -> Unit)? = null
|
||||
@EpoxyAttribute var forgetPasswordClickListener: (() -> Unit)? = null
|
||||
@EpoxyAttribute var submitClickListener: ((String) -> Unit)? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
|
||||
setupAutoFill(holder)
|
||||
holder.passwordFieldTil.error = errorText
|
||||
renderPasswordField(holder)
|
||||
holder.passwordReveal.setOnClickListener { passwordRevealClickListener?.invoke() }
|
||||
holder.forgetPassword.setOnClickListener { forgetPasswordClickListener?.invoke() }
|
||||
holder.submit.setOnClickListener { submitClickListener?.invoke(holder.passwordField.text.toString()) }
|
||||
}
|
||||
|
||||
private fun setupAutoFill(holder: Holder) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
holder.passwordField.setAutofillHints(HintConstants.AUTOFILL_HINT_PASSWORD)
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderPasswordField(holder: Holder) {
|
||||
holder.passwordField.showPassword(passwordShown)
|
||||
|
||||
if (passwordShown) {
|
||||
holder.passwordReveal.setImageResource(R.drawable.ic_eye_closed_black)
|
||||
holder.passwordReveal.contentDescription = stringProvider.getString(R.string.a11y_hide_password)
|
||||
} else {
|
||||
holder.passwordReveal.setImageResource(R.drawable.ic_eye_black)
|
||||
holder.passwordReveal.contentDescription = stringProvider.getString(R.string.a11y_show_password)
|
||||
}
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val passwordField by bind<TextInputEditText>(R.id.itemLoginPasswordFormPasswordField)
|
||||
val passwordFieldTil by bind<TextInputLayout>(R.id.itemLoginPasswordFormPasswordFieldTil)
|
||||
val passwordReveal by bind<ImageView>(R.id.itemLoginPasswordFormPasswordReveal)
|
||||
val forgetPassword by bind<Button>(R.id.itemLoginPasswordFormForgetPasswordButton)
|
||||
val submit by bind<Button>(R.id.itemLoginPasswordFormSubmit)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.riotx.features.signout.epoxy
|
||||
|
||||
import android.widget.Button
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotx.core.extensions.setTextOrHide
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_login_red_button)
|
||||
abstract class LoginRedButtonItem : VectorEpoxyModel<LoginRedButtonItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute var text: String? = null
|
||||
@EpoxyAttribute var listener: (() -> Unit)? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
|
||||
holder.button.setTextOrHide(text)
|
||||
holder.button.setOnClickListener {
|
||||
listener?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val button by bind<Button>(R.id.itemLoginRedButton)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.riotx.features.signout.epoxy
|
||||
|
||||
import android.widget.TextView
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotx.core.extensions.setTextOrHide
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_login_text)
|
||||
abstract class LoginTextItem : VectorEpoxyModel<LoginTextItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute var text: String? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
|
||||
holder.textView.setTextOrHide(text)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val textView by bind<TextView>(R.id.itemLoginText)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.riotx.features.signout.epoxy
|
||||
|
||||
import android.widget.TextView
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotx.core.extensions.setTextOrHide
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_login_title)
|
||||
abstract class LoginTitleItem : VectorEpoxyModel<LoginTitleItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute var text: String? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
|
||||
holder.textView.setTextOrHide(text)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val textView by bind<TextView>(R.id.itemLoginTitleText)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.riotx.features.signout.epoxy
|
||||
|
||||
import android.widget.TextView
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotx.core.extensions.setTextOrHide
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_login_title_small)
|
||||
abstract class LoginTitleSmallItem : VectorEpoxyModel<LoginTitleSmallItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute var text: String? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
|
||||
holder.textView.setTextOrHide(text)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val textView by bind<TextView>(R.id.itemLoginTitleSmallText)
|
||||
}
|
||||
}
|
|
@ -1,200 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/softLogout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?riotx_background">
|
||||
|
||||
<!-- Missing attributes are in the style -->
|
||||
<ImageView
|
||||
style="@style/LoginLogo"
|
||||
tools:ignore="ContentDescription,MissingConstraints" />
|
||||
|
||||
<!-- Missing attributes are in the style -->
|
||||
<androidx.core.widget.NestedScrollView
|
||||
style="@style/LoginFormScrollView"
|
||||
tools:ignore="MissingConstraints">
|
||||
|
||||
<LinearLayout
|
||||
style="@style/LoginFormContainer"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/soft_logout_title"
|
||||
android:textAppearance="@style/TextAppearance.Vector.Login.Title" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_vertical_margin"
|
||||
android:text="@string/soft_logout_signin_title"
|
||||
android:textAppearance="@style/TextAppearance.Vector.Login.Title.Small" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/softLogoutNotice"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="start"
|
||||
android:textAppearance="@style/TextAppearance.Vector.Login.Text"
|
||||
tools:text="@string/soft_logout_signin_notice" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/softLogoutE2eWarningNotice"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="start"
|
||||
android:text="@string/soft_logout_signin_e2e_warning_notice"
|
||||
android:textAppearance="@style/TextAppearance.Vector.Login.Text"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/softLogoutFormContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp">
|
||||
|
||||
<!-- Displayed while loading -->
|
||||
<ProgressBar
|
||||
android:id="@+id/softLogoutFormLoading"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal" />
|
||||
|
||||
<!-- Displayed for SSO mode -->
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/softLogoutFormSsoSubmit"
|
||||
style="@style/Style.Vector.Login.Button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:text="@string/login_signin_sso"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<!-- 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
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_vertical_margin"
|
||||
android:text="@string/soft_logout_clear_data_title"
|
||||
android:textAppearance="@style/TextAppearance.Vector.Login.Title.Small" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="start"
|
||||
android:text="@string/soft_logout_clear_data_notice"
|
||||
android:textAppearance="@style/TextAppearance.Vector.Login.Text" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/softLogoutClearDataSubmit"
|
||||
style="@style/Style.Vector.Login.Button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/soft_logout_clear_data_submit"
|
||||
app:backgroundTint="@color/vector_error_color" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
10
vector/src/main/res/layout/item_login_centered_button.xml
Normal file
10
vector/src/main/res/layout/item_login_centered_button.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.button.MaterialButton xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/itemLoginCenteredButton"
|
||||
style="@style/Style.Vector.Login.Button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="16dp"
|
||||
tools:text="@string/login_signin_sso" />
|
35
vector/src/main/res/layout/item_login_error_retry.xml
Normal file
35
vector/src/main/res/layout/item_login_error_retry.xml
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?riotx_background"
|
||||
android:paddingStart="32dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="32dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/itemLoginErrorRetryText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:textColor="@color/riotx_notice"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Error" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/itemLoginErrorRetryButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="@string/global_retry"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/itemLoginErrorRetryText" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
8
vector/src/main/res/layout/item_login_header.xml
Normal file
8
vector/src/main/res/layout/item_login_header.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="32dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/riotx_logo" />
|
78
vector/src/main/res/layout/item_login_password_form.xml
Normal file
78
vector/src/main/res/layout/item_login_password_form.xml
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="36dp"
|
||||
android:paddingEnd="36dp">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/itemLoginPasswordFormPasswordFieldTil"
|
||||
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/itemLoginPasswordFormPasswordField"
|
||||
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/itemLoginPasswordFormPasswordReveal"
|
||||
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/itemLoginPasswordFormForgetPasswordButton"
|
||||
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/itemLoginPasswordFormSubmit"
|
||||
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>
|
19
vector/src/main/res/layout/item_login_red_button.xml
Normal file
19
vector/src/main/res/layout/item_login_red_button.xml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/itemLoginRedButton"
|
||||
style="@style/Style.Vector.Login.Button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="36dp"
|
||||
app:backgroundTint="@color/vector_error_color"
|
||||
tools:text="@string/soft_logout_clear_data_submit" />
|
||||
|
||||
</FrameLayout>
|
12
vector/src/main/res/layout/item_login_text.xml
Normal file
12
vector/src/main/res/layout/item_login_text.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/itemLoginText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="12dp"
|
||||
android:paddingStart="36dp"
|
||||
android:paddingEnd="36dp"
|
||||
android:textAppearance="@style/TextAppearance.Vector.Login.Text"
|
||||
tools:text="Login Title" />
|
12
vector/src/main/res/layout/item_login_title.xml
Normal file
12
vector/src/main/res/layout/item_login_title.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/itemLoginTitleText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="32dp"
|
||||
android:paddingStart="36dp"
|
||||
android:paddingEnd="36dp"
|
||||
android:textAppearance="@style/TextAppearance.Vector.Login.Title"
|
||||
tools:text="Login Title" />
|
12
vector/src/main/res/layout/item_login_title_small.xml
Normal file
12
vector/src/main/res/layout/item_login_title_small.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/itemLoginTitleSmallText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingStart="36dp"
|
||||
android:paddingEnd="36dp"
|
||||
android:textAppearance="@style/TextAppearance.Vector.Login.Title.Small"
|
||||
tools:text="Login Title" />
|
Loading…
Reference in a new issue