diff --git a/app/build.gradle b/app/build.gradle index 590370339..5780d02be 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -86,7 +86,7 @@ play { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation('com.github.wulkanowy:api:fe4ffeb') { exclude module: "threetenbp" } + implementation 'com.github.wulkanowy:api:3335bd6' implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "androidx.appcompat:appcompat:1.0.2" diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/student/StudentLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/student/StudentLocalTest.kt index b27446faf..cecd80992 100644 --- a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/student/StudentLocalTest.kt +++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/student/StudentLocalTest.kt @@ -39,7 +39,7 @@ class StudentLocalTest { @Test fun saveAndReadTest() { - studentLocal.saveStudent(Student(email = "test", password = "test123", schoolSymbol = "23", endpoint = "fakelog.cf", loginType = "AUTO", isCurrent = true, studentName = "", schoolName = "", studentId = 0, classId = 1, symbol = "", registrationDate = now(), className = "")) + studentLocal.saveStudents(listOf(Student(email = "test", password = "test123", schoolSymbol = "23", endpoint = "fakelog.cf", loginType = "AUTO", isCurrent = true, studentName = "", schoolName = "", studentId = 0, classId = 1, symbol = "", registrationDate = now(), className = ""))) .blockingGet() val student = studentLocal.getCurrentStudent(true).blockingGet() diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f0dd9cb40..5b2819263 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -34,6 +34,7 @@ android:name=".ui.modules.login.LoginActivity" android:configChanges="orientation|screenSize" android:label="@string/login_title" + android:theme="@style/WulkanowyTheme.NoActionBar" android:windowSoftInputMode="adjustResize" /> ): List @Delete fun delete(student: Student) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentLocal.kt index 7bbd283fb..e6d744213 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentLocal.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentLocal.kt @@ -17,8 +17,8 @@ class StudentLocal @Inject constructor( private val context: Context ) { - fun saveStudent(student: Student): Single { - return Single.fromCallable { studentDb.insert(student.copy(password = encrypt(student.password, context))) } + fun saveStudents(students: List): Single> { + return Single.fromCallable { studentDb.insertAll(students.map { it.copy(password = encrypt(it.password, context)) }) } } fun getStudents(decryptPass: Boolean): Maybe> { diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRepository.kt index b4b7c8289..e0ab6bf67 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRepository.kt @@ -41,8 +41,8 @@ class StudentRepository @Inject constructor( .toSingle() } - fun saveStudent(student: Student): Single { - return local.saveStudent(student) + fun saveStudents(students: List): Single> { + return local.saveStudents(students) } fun switchStudent(student: Student): Completable { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt index 2bcb6b4e9..9f3217759 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt @@ -8,7 +8,6 @@ import android.view.View import android.view.View.GONE import android.view.View.VISIBLE import android.view.ViewGroup -import androidx.appcompat.app.AppCompatActivity import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager import eu.davidea.flexibleadapter.items.AbstractFlexibleItem @@ -45,6 +44,7 @@ class LoginStudentSelectFragment : BaseFragment(), LoginStudentSelectView { } override fun initView() { + loginStudentSelectSignIn.setOnClickListener { presenter.onSignIn() } loginAdapter.apply { setOnItemClickListener { presenter.onItemSelected(it) } } loginStudentSelectRecycler.apply { @@ -54,7 +54,7 @@ class LoginStudentSelectFragment : BaseFragment(), LoginStudentSelectView { } override fun updateData(data: List) { - loginAdapter.updateDataSet(data, true) + loginAdapter.updateDataSet(data) } override fun openMainView() { @@ -69,11 +69,11 @@ class LoginStudentSelectFragment : BaseFragment(), LoginStudentSelectView { } override fun showContent(show: Boolean) { - loginStudentSelectRecycler.visibility = if (show) VISIBLE else GONE + loginStudentSelectContent.visibility = if (show) VISIBLE else GONE } - override fun showActionBar(show: Boolean) { - (activity as? AppCompatActivity)?.supportActionBar?.run { if (show) show() else hide() } + override fun enableSignIn(enable: Boolean) { + loginStudentSelectSignIn.isEnabled = enable } fun onParentInitStudentSelectFragment(students: List) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectItem.kt index 65940a980..27723c538 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectItem.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectItem.kt @@ -13,15 +13,15 @@ import kotlinx.android.synthetic.main.item_login_student_select.* class LoginStudentSelectItem(val student: Student) : AbstractFlexibleItem() { - override fun getLayoutRes(): Int = R.layout.item_login_student_select + override fun getLayoutRes() = R.layout.item_login_student_select override fun createViewHolder(view: View, adapter: FlexibleAdapter>): ItemViewHolder { return ItemViewHolder(view, adapter) } @SuppressLint("SetTextI18n") - override fun bindViewHolder(adapter: FlexibleAdapter>, holder: ItemViewHolder, position: Int, payloads: MutableList?) { - holder.run { + override fun bindViewHolder(adapter: FlexibleAdapter>, holder: ItemViewHolder, position: Int, payloads: MutableList) { + holder.apply { loginItemName.text = "${student.studentName} ${student.className}" loginItemSchool.text = student.schoolName } @@ -43,7 +43,17 @@ class LoginStudentSelectItem(val student: Student) : AbstractFlexibleItem) : FlexibleViewHolder(view, adapter), LayoutContainer { + override val containerView: View get() = itemView + + init { + loginItemCheck.setOnClickListener { super.onClick(loginItemContainer) } + } + + override fun onClick(view: View?) { + super.onClick(view) + loginItemCheck.apply { isChecked = !isChecked } + } } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt index 6c2acb3bd..21dde7b86 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt @@ -8,7 +8,6 @@ import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.modules.login.LoginErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider -import io.reactivex.Single import timber.log.Timber import java.io.Serializable import javax.inject.Inject @@ -22,10 +21,13 @@ class LoginStudentSelectPresenter @Inject constructor( var students = emptyList() + var selectedStudents = mutableListOf() + fun onAttachView(view: LoginStudentSelectView, students: Serializable?) { super.onAttachView(view) view.run { initView() + enableSignIn(false) errorHandler.onStudentDuplicate = { showMessage(it) Timber.i("The student already registered in the app was selected") @@ -37,13 +39,21 @@ class LoginStudentSelectPresenter @Inject constructor( } } + fun onSignIn() { + registerStudents(selectedStudents) + } + fun onParentInitStudentSelectView(students: List) { loadData(students) + if (students.size == 1) registerStudents(students) } fun onItemSelected(item: AbstractFlexibleItem<*>?) { if (item is LoginStudentSelectItem) { - registerStudent(item.student) + selectedStudents.removeAll { it == item.student } + .let { if (!it) selectedStudents.add(item.student) } + + view?.enableSignIn(selectedStudents.isNotEmpty()) } } @@ -54,33 +64,30 @@ class LoginStudentSelectPresenter @Inject constructor( } } - private fun registerStudent(student: Student) { - disposable.add(studentRepository.saveStudent(student) - .map { student.apply { id = it } } - .onErrorResumeNext { studentRepository.logoutStudent(student).andThen(Single.error(it)) } - .flatMapCompletable { studentRepository.switchStudent(student) } + private fun registerStudents(students: List) { + disposable.add(studentRepository.saveStudents(students) + .map { students.first().apply { id = it.first() } } + .flatMapCompletable { studentRepository.switchStudent(it) } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) .doOnSubscribe { view?.apply { showProgress(true) showContent(false) - showActionBar(false) } Timber.i("Registration started") } .subscribe({ - analytics.logEvent("registration_student_select", SUCCESS to true, "endpoint" to student.endpoint, "symbol" to student.symbol, "error" to "No error") + students.forEach { analytics.logEvent("registration_student_select", SUCCESS to true, "endpoint" to it.endpoint, "symbol" to it.symbol, "error" to "No error") } Timber.i("Registration result: Success") view?.openMainView() - }, { - analytics.logEvent("registration_student_select", SUCCESS to false, "endpoint" to student.endpoint, "symbol" to student.symbol, "error" to it.localizedMessage) + }, { error -> + students.forEach { analytics.logEvent("registration_student_select", SUCCESS to false, "endpoint" to it.endpoint, "symbol" to it.symbol, "error" to error.localizedMessage) } Timber.i("Registration result: An exception occurred ") - errorHandler.dispatch(it) + errorHandler.dispatch(error) view?.apply { showProgress(false) showContent(true) - showActionBar(true) } })) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectView.kt index 824f421fe..3967313c3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectView.kt @@ -14,5 +14,5 @@ interface LoginStudentSelectView : BaseView { fun showContent(show: Boolean) - fun showActionBar(show: Boolean) + fun enableSignIn(enable: Boolean) } diff --git a/app/src/main/res/layout/fragment_login_form.xml b/app/src/main/res/layout/fragment_login_form.xml index 197db570f..34f1f9959 100644 --- a/app/src/main/res/layout/fragment_login_form.xml +++ b/app/src/main/res/layout/fragment_login_form.xml @@ -30,7 +30,7 @@ android:layout_height="wrap_content" android:layout_marginStart="32dp" android:layout_marginLeft="32dp" - android:layout_marginTop="48dp" + android:layout_marginTop="32dp" android:layout_marginEnd="32dp" android:layout_marginRight="32dp" android:gravity="center_horizontal" @@ -150,7 +150,7 @@ android:layout_marginTop="48dp" android:layout_marginEnd="24dp" android:layout_marginRight="24dp" - android:layout_marginBottom="48dp" + android:layout_marginBottom="16dp" android:text="@string/login_sign_in" android:textAppearance="?android:textAppearanceSmall" android:textColor="@android:color/white" diff --git a/app/src/main/res/layout/fragment_login_student_select.xml b/app/src/main/res/layout/fragment_login_student_select.xml index 72af7293a..a94978bbf 100644 --- a/app/src/main/res/layout/fragment_login_student_select.xml +++ b/app/src/main/res/layout/fragment_login_student_select.xml @@ -1,4 +1,5 @@ - + android:layout_height="match_parent"> + + + + + + + diff --git a/app/src/main/res/layout/fragment_login_symbol.xml b/app/src/main/res/layout/fragment_login_symbol.xml index 6cdf7ef03..6c820889f 100644 --- a/app/src/main/res/layout/fragment_login_symbol.xml +++ b/app/src/main/res/layout/fragment_login_symbol.xml @@ -29,7 +29,7 @@ android:layout_height="wrap_content" android:layout_marginStart="32dp" android:layout_marginLeft="32dp" - android:layout_marginTop="48dp" + android:layout_marginTop="32dp" android:layout_marginEnd="32dp" android:layout_marginRight="32dp" android:gravity="center_horizontal" @@ -79,11 +79,10 @@ style="@style/Widget.MaterialComponents.Button" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center_vertical" android:layout_marginTop="48dp" android:layout_marginEnd="24dp" android:layout_marginRight="24dp" - android:layout_marginBottom="48dp" + android:layout_marginBottom="16dp" android:text="@string/login_sign_in" android:textAppearance="?android:textAppearanceSmall" android:textColor="@android:color/white" @@ -91,8 +90,7 @@ 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" /> + app:layout_constraintTop_toBottomOf="@+id/loginSymbolNameLayout" /> diff --git a/app/src/main/res/layout/item_login_student_select.xml b/app/src/main/res/layout/item_login_student_select.xml index f13eb6010..eb74cebbe 100644 --- a/app/src/main/res/layout/item_login_student_select.xml +++ b/app/src/main/res/layout/item_login_student_select.xml @@ -1,46 +1,42 @@ - + android:background="?selectableItemBackground" + android:orientation="horizontal"> - + + app:firstBaselineToTopHeight="32dp" + tools:text="Jan Kowalski" /> - + app:firstBaselineToTopHeight="20dp" + tools:text="Szkoła Wulkanowego nr 1" /> diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index aee503b82..b2689133e 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -3,7 +3,7 @@ - Wybierz ucznia + Logowanie Wulkanowy Oceny Frekwencja @@ -31,8 +31,9 @@ Dane logowania są niepoprawne Nie znaleziono ucznia. Sprawdź symbol To pole jest wymagane - Ten student jest już zalogowany + Wybrany uczeń jest już zalogowany Symbol znajduje się na stronie dziennika w zakładce Dostęp Mobilny + Wybierz uczniów do zalogowania w aplikacji Polityka prywatności diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8dc6a25cb..6195c36cb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,7 +3,7 @@ - Select student + Login Wulkanowy Grades Attendance @@ -31,8 +31,9 @@ Login details are incorrect Student not found. Check the symbol This field is required - This student has already been logged in + The selected student is already logged in The symbol is located on the register page in the Mobile Access tab + Select students to log in to the application Privacy policy diff --git a/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt b/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt index 192602b78..17c16f415 100644 --- a/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt +++ b/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt @@ -51,9 +51,10 @@ class LoginStudentSelectPresenterTest { @Test fun onSelectedStudentTest() { - doReturn(Single.just(1L)).`when`(studentRepository).saveStudent(testStudent) + doReturn(Single.just(listOf(1L))).`when`(studentRepository).saveStudents(listOf(testStudent)) doReturn(Completable.complete()).`when`(studentRepository).switchStudent(testStudent) presenter.onItemSelected(LoginStudentSelectItem(testStudent)) + presenter.onSignIn() verify(loginStudentSelectView).showContent(false) verify(loginStudentSelectView).showProgress(true) verify(loginStudentSelectView).openMainView() @@ -61,9 +62,10 @@ class LoginStudentSelectPresenterTest { @Test fun onSelectedStudentErrorTest() { - doReturn(Single.error(testException)).`when`(studentRepository).saveStudent(testStudent) + doReturn(Single.error(testException)).`when`(studentRepository).saveStudents(listOf(testStudent)) doReturn(Completable.complete()).`when`(studentRepository).logoutStudent(testStudent) presenter.onItemSelected(LoginStudentSelectItem(testStudent)) + presenter.onSignIn() verify(loginStudentSelectView).showContent(false) verify(loginStudentSelectView).showProgress(true) verify(errorHandler).dispatch(testException)