From 1d7585071dc8bae2a1bc27eb79535d9cc963da89 Mon Sep 17 00:00:00 2001 From: Dominik Korsa Date: Sun, 17 Feb 2019 00:42:09 +0100 Subject: [PATCH] Update login form to Material Design 2 (#229) --- app/build.gradle | 1 + .../modules/login/form/LoginFormFragment.kt | 23 +++- .../modules/login/form/LoginFormPresenter.kt | 15 +++ .../ui/modules/login/form/LoginFormView.kt | 4 + .../login/symbol/LoginSymbolFragment.kt | 18 ++- .../login/symbol/LoginSymbolPresenter.kt | 4 + .../modules/login/symbol/LoginSymbolView.kt | 4 + .../wulkanowy/utils/EditTextExtension.kt | 16 +++ .../res/drawable/ic_login_outlined_border.xml | 11 ++ .../main/res/layout/fragment_login_form.xml | 125 ++++++++++++------ .../main/res/layout/fragment_login_symbol.xml | 59 +++++---- .../main/res/layout/item_widget_timetable.xml | 6 +- app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values/colors.xml | 2 - app/src/main/res/values/strings.xml | 3 +- 15 files changed, 218 insertions(+), 74 deletions(-) create mode 100644 app/src/main/java/io/github/wulkanowy/utils/EditTextExtension.kt create mode 100644 app/src/main/res/drawable/ic_login_outlined_border.xml diff --git a/app/build.gradle b/app/build.gradle index 6e9b6ffa..2923e5f5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -79,6 +79,7 @@ dependencies { implementation "androidx.appcompat:appcompat:1.0.2" implementation "androidx.cardview:cardview:1.0.0" implementation "com.google.android.material:material:1.0.0" + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.multidex:multidex:2.0.1' implementation 'com.takisoft.preferencex:preferencex:1.0.0' diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt index ea276acd..f5c7d1de 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt @@ -16,6 +16,8 @@ import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.login.LoginActivity import io.github.wulkanowy.utils.hideSoftInput +import io.github.wulkanowy.utils.setOnItemSelectedListener +import io.github.wulkanowy.utils.setOnTextChangedListener import io.github.wulkanowy.utils.showSoftInput import kotlinx.android.synthetic.main.fragment_login_form.* import javax.inject.Inject @@ -47,10 +49,15 @@ class LoginFormFragment : BaseFragment(), LoginFormView { ) } + loginFormName.setOnTextChangedListener { presenter.onNameTextChanged() } + loginFormPass.setOnTextChangedListener { presenter.onPassTextChanged() } + loginFormPass.setOnEditorActionListener { _, id, _ -> if (id == IME_ACTION_DONE || id == IME_NULL) loginFormSignIn.callOnClick() else false } + loginFormHost.setOnItemSelectedListener { presenter.onHostSelected() } + context?.let { loginFormHost.adapter = ArrayAdapter.createFromResource(it, R.array.endpoints_keys, android.R.layout.simple_spinner_item) .apply { setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) } @@ -58,33 +65,41 @@ class LoginFormFragment : BaseFragment(), LoginFormView { } override fun setErrorNameRequired() { - loginFormName.run { + loginFormNameLayout.run { requestFocus() error = getString(R.string.login_field_required) } } override fun setErrorPassRequired(focus: Boolean) { - loginFormPass.run { + loginFormPassLayout.run { if (focus) requestFocus() error = getString(R.string.login_field_required) } } override fun setErrorPassInvalid(focus: Boolean) { - loginFormPass.run { + loginFormPassLayout.run { if (focus) requestFocus() error = getString(R.string.login_invalid_password) } } override fun setErrorPassIncorrect() { - loginFormPass.run { + loginFormPassLayout.run { requestFocus() error = getString(R.string.login_incorrect_password) } } + override fun clearNameError() { + loginFormNameLayout.error = null + } + + override fun clearPassError() { + loginFormPassLayout.error = null + } + override fun showSoftKeyboard() { activity?.showSoftInput() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt index a2dbc7f3..e529501d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt @@ -31,6 +31,21 @@ class LoginFormPresenter @Inject constructor( } } + fun onHostSelected() { + view?.apply { + clearPassError() + clearNameError() + } + } + + fun onPassTextChanged() { + view?.clearPassError() + } + + fun onNameTextChanged() { + view?.clearNameError() + } + fun attemptLogin(email: String, password: String, endpoint: String) { if (!validateCredentials(email, password)) return diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt index d238675a..56d476a7 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt @@ -15,6 +15,10 @@ interface LoginFormView : BaseView { fun setErrorPassIncorrect() + fun clearNameError() + + fun clearPassError() + fun showSoftKeyboard() fun hideSoftKeyboard() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt index d00529a3..ab12b777 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt @@ -14,6 +14,7 @@ import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.login.LoginActivity import io.github.wulkanowy.utils.hideSoftInput +import io.github.wulkanowy.utils.setOnTextChangedListener import io.github.wulkanowy.utils.showSoftInput import kotlinx.android.synthetic.main.fragment_login_symbol.* import javax.inject.Inject @@ -29,6 +30,9 @@ class LoginSymbolFragment : BaseFragment(), LoginSymbolView { fun newInstance() = LoginSymbolFragment() } + override val symbolNameError: CharSequence? + get() = loginSymbolNameLayout.error + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_login_symbol, container, false) } @@ -41,6 +45,8 @@ class LoginSymbolFragment : BaseFragment(), LoginSymbolView { override fun initView() { loginSymbolSignIn.setOnClickListener { presenter.attemptLogin(loginSymbolName.text.toString()) } + loginSymbolName.setOnTextChangedListener { presenter.onSymbolTextChanged() } + loginSymbolName.apply { setOnEditorActionListener { _, id, _ -> if (id == IME_ACTION_DONE || id == IME_NULL) loginSymbolSignIn.callOnClick() else false @@ -54,22 +60,26 @@ class LoginSymbolFragment : BaseFragment(), LoginSymbolView { } override fun setErrorSymbolIncorrect() { - loginSymbolName.apply { + loginSymbolNameLayout.apply { requestFocus() error = getString(R.string.login_incorrect_symbol) } } override fun setErrorSymbolRequire() { - loginSymbolName.apply { + loginSymbolNameLayout.apply { requestFocus() error = getString(R.string.login_field_required) } } + override fun clearSymbolError() { + loginSymbolNameLayout.error = null + } + override fun clearAndFocusSymbol() { - loginSymbolName.apply { - text = null + loginSymbolNameLayout.apply { + editText?.text = null requestFocus() } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt index ad3a76e9..0adb9e16 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt @@ -29,6 +29,10 @@ class LoginSymbolPresenter @Inject constructor( } } + fun onSymbolTextChanged() { + view?.apply { if (symbolNameError != null) clearSymbolError() } + } + fun attemptLogin(symbol: String) { if (symbol.isBlank()) { view?.setErrorSymbolRequire() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt index d0e5f495..2e5143ef 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt @@ -5,12 +5,16 @@ import io.github.wulkanowy.ui.base.BaseView interface LoginSymbolView : BaseView { + val symbolNameError: CharSequence? + fun initView() fun setErrorSymbolIncorrect() fun setErrorSymbolRequire() + fun clearSymbolError() + fun clearAndFocusSymbol() fun showSoftKeyboard() diff --git a/app/src/main/java/io/github/wulkanowy/utils/EditTextExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/EditTextExtension.kt new file mode 100644 index 00000000..caa977ec --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/utils/EditTextExtension.kt @@ -0,0 +1,16 @@ +package io.github.wulkanowy.utils + +import android.text.Editable +import android.text.TextWatcher +import android.widget.EditText + +inline fun EditText.setOnTextChangedListener(crossinline listener: () -> Unit) { + addTextChangedListener(object : TextWatcher { + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + listener() + } + + override fun afterTextChanged(s: Editable?) {} + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} + }) +} diff --git a/app/src/main/res/drawable/ic_login_outlined_border.xml b/app/src/main/res/drawable/ic_login_outlined_border.xml new file mode 100644 index 00000000..ec62251e --- /dev/null +++ b/app/src/main/res/drawable/ic_login_outlined_border.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/layout/fragment_login_form.xml b/app/src/main/res/layout/fragment_login_form.xml index 753e072c..4498b452 100644 --- a/app/src/main/res/layout/fragment_login_form.xml +++ b/app/src/main/res/layout/fragment_login_form.xml @@ -1,5 +1,6 @@ - @@ -7,9 +8,6 @@ android:id="@+id/loginFormProgressContainer" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_alignParentStart="true" - android:layout_alignParentLeft="true" - android:layout_alignParentTop="true" android:gravity="center" android:visibility="gone"> @@ -17,14 +15,14 @@ style="?android:attr/progressBarStyleHorizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_below="@id/loginFormProgressText" + android:layout_below="@id/loginFormProgressTitle" android:layout_centerHorizontal="true" android:indeterminate="true" android:minWidth="220dp" android:minHeight="30dp" /> - - + android:padding="24dp"> + android:textSize="16sp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + android:layout_marginTop="24dp" + android:hint="@string/login_nickname_hint" + app:errorEnabled="true" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/loginFormHeader"> + android:layout_marginTop="10dp" + android:hint="@string/login_password_hint" + app:errorEnabled="true" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/loginFormNameLayout" + app:passwordToggleEnabled="true"> - + android:layout_marginTop="15dp" + android:background="@drawable/ic_login_outlined_border" + android:orientation="vertical" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/loginFormPassLayout"> - + + + + + + app:backgroundTint="@color/colorPrimary" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@+id/loginFormHostLayout" + app:layout_constraintVertical_bias="0.84" /> - - - + android:layout_gravity="center_vertical" + android:layout_marginEnd="16dp" + android:layout_marginRight="16dp" + android:maxLines="2" + android:textColor="?android:textColorSecondary" + android:textSize="12sp" + app:layout_constraintBottom_toBottomOf="@id/loginFormSignIn" + app:layout_constraintEnd_toStartOf="@+id/loginFormSignIn" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="@+id/loginFormSignIn" + tools:text="Version 1.0.0" /> + + + diff --git a/app/src/main/res/layout/fragment_login_symbol.xml b/app/src/main/res/layout/fragment_login_symbol.xml index d1fa40a4..6d632234 100644 --- a/app/src/main/res/layout/fragment_login_symbol.xml +++ b/app/src/main/res/layout/fragment_login_symbol.xml @@ -1,4 +1,4 @@ - @@ -33,33 +30,44 @@ android:text="@string/login_progress" /> - - + android:layout_marginStart="24dp" + android:layout_marginLeft="24dp" + android:layout_marginTop="24dp" + android:layout_marginEnd="24dp" + android:layout_marginRight="24dp"> + android:textSize="16sp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + android:layout_marginTop="24dp" + android:hint="@string/login_symbol_hint" + app:helperText="@string/login_symbol_helper" + app:helperTextEnabled="true" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/loginSymbolHeader"> - - - - + app:backgroundTint="@color/colorPrimary" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@+id/loginSymbolNameLayout" + app:layout_constraintVertical_bias="1" /> + + + diff --git a/app/src/main/res/layout/item_widget_timetable.xml b/app/src/main/res/layout/item_widget_timetable.xml index 2007b323..2185c61b 100644 --- a/app/src/main/res/layout/item_widget_timetable.xml +++ b/app/src/main/res/layout/item_widget_timetable.xml @@ -32,7 +32,7 @@ android:layout_toEndOf="@id/timetableWidgetItemNumber" android:layout_toRightOf="@id/timetableWidgetItemNumber" android:text="@string/app_name" - android:textColor="@color/second_text" + android:textColor="@android:color/secondary_text_light" android:textSize="13sp" /> diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 7669a88c..e31752ee 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -32,6 +32,7 @@ Nie znaleziono ucznia. Sprwadź symbol To pole jest wymagane Ten student jest już zalogowany + Symbol znajduje się na stronie dziennika w zakładce Dostęp Mobilny diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index db513976..6b79f622 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -14,8 +14,6 @@ #d65757 #3d5f9c - #474747 - #303030 #ffffff diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c93c7ce4..22e28baf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -22,7 +22,7 @@ Enter the VULCAN diary symbol Email or nick Password - Log + Register Symbol Sign in Logging in… @@ -32,6 +32,7 @@ Student not found. Check the symbol This field is required This student has already been logged in + The symbol is located on the register page in the Mobile Access tab