mirror of
https://github.com/wulkanowy/wulkanowy.git
synced 2025-01-31 17:42:44 +01:00
Refactor student selection screen (#2087)
This commit is contained in:
parent
83974b6550
commit
897eac050a
@ -186,7 +186,7 @@ ext {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "io.github.wulkanowy:sdk:1.8.3"
|
||||
implementation "io.github.wulkanowy:sdk:a3b97edd48"
|
||||
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
|
||||
|
||||
|
@ -0,0 +1,87 @@
|
||||
package io.github.wulkanowy.data.mappers
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.pojos.*
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.sdk.mapper.mapSemesters
|
||||
import java.time.Instant
|
||||
import io.github.wulkanowy.sdk.scrapper.register.RegisterStudent as SdkRegisterStudent
|
||||
import io.github.wulkanowy.sdk.scrapper.register.RegisterUser as SdkRegisterUser
|
||||
|
||||
fun SdkRegisterUser.mapToPojo(password: String) = RegisterUser(
|
||||
email = email,
|
||||
login = login,
|
||||
password = password,
|
||||
baseUrl = baseUrl,
|
||||
loginType = loginType,
|
||||
symbols = symbols.map { registerSymbol ->
|
||||
RegisterSymbol(
|
||||
symbol = registerSymbol.symbol,
|
||||
error = registerSymbol.error,
|
||||
userName = registerSymbol.userName,
|
||||
schools = registerSymbol.schools.map {
|
||||
RegisterUnit(
|
||||
userLoginId = it.userLoginId,
|
||||
schoolId = it.schoolId,
|
||||
schoolName = it.schoolName,
|
||||
schoolShortName = it.schoolShortName,
|
||||
parentIds = it.parentIds,
|
||||
studentIds = it.studentIds,
|
||||
employeeIds = it.employeeIds,
|
||||
error = it.error,
|
||||
students = it.subjects
|
||||
.filterIsInstance<SdkRegisterStudent>()
|
||||
.map { registerSubject ->
|
||||
RegisterStudent(
|
||||
studentId = registerSubject.studentId,
|
||||
studentName = registerSubject.studentName,
|
||||
studentSecondName = registerSubject.studentSecondName,
|
||||
studentSurname = registerSubject.studentSurname,
|
||||
className = registerSubject.className,
|
||||
classId = registerSubject.classId,
|
||||
isParent = registerSubject.isParent,
|
||||
semesters = registerSubject.semesters
|
||||
.mapSemesters()
|
||||
.mapToEntities(registerSubject.studentId),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
fun RegisterStudent.mapToStudentWithSemesters(
|
||||
user: RegisterUser,
|
||||
symbol: RegisterSymbol,
|
||||
unit: RegisterUnit,
|
||||
colors: List<Long>,
|
||||
): StudentWithSemesters = StudentWithSemesters(
|
||||
semesters = semesters,
|
||||
student = Student(
|
||||
email = user.login, // for compatibility
|
||||
userName = symbol.userName,
|
||||
userLoginId = unit.userLoginId,
|
||||
isParent = isParent,
|
||||
className = className,
|
||||
classId = classId,
|
||||
studentId = studentId,
|
||||
symbol = symbol.symbol,
|
||||
loginType = user.loginType.name,
|
||||
schoolName = unit.schoolName,
|
||||
schoolShortName = unit.schoolShortName,
|
||||
schoolSymbol = unit.schoolId,
|
||||
studentName = "$studentName $studentSurname",
|
||||
loginMode = Sdk.Mode.SCRAPPER.name,
|
||||
scrapperBaseUrl = user.baseUrl,
|
||||
mobileBaseUrl = "",
|
||||
certificateKey = "",
|
||||
privateKey = "",
|
||||
password = user.password,
|
||||
isCurrent = false,
|
||||
registrationDate = Instant.now(),
|
||||
).apply {
|
||||
avatarColor = colors.random()
|
||||
},
|
||||
)
|
@ -0,0 +1,43 @@
|
||||
package io.github.wulkanowy.data.pojos
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.sdk.scrapper.Scrapper
|
||||
|
||||
data class RegisterUser(
|
||||
val email: String,
|
||||
val password: String,
|
||||
val login: String, // may be the same as email
|
||||
val baseUrl: String,
|
||||
val loginType: Scrapper.LoginType,
|
||||
val symbols: List<RegisterSymbol>,
|
||||
) : java.io.Serializable
|
||||
|
||||
data class RegisterSymbol(
|
||||
val symbol: String,
|
||||
val error: Throwable?,
|
||||
val userName: String,
|
||||
val schools: List<RegisterUnit>,
|
||||
) : java.io.Serializable
|
||||
|
||||
data class RegisterUnit(
|
||||
val userLoginId: Int,
|
||||
val schoolId: String,
|
||||
val schoolName: String,
|
||||
val schoolShortName: String,
|
||||
val parentIds: List<Int>,
|
||||
val studentIds: List<Int>,
|
||||
val employeeIds: List<Int>,
|
||||
val error: Throwable?,
|
||||
val students: List<RegisterStudent>,
|
||||
) : java.io.Serializable
|
||||
|
||||
data class RegisterStudent(
|
||||
val studentId: Int,
|
||||
val studentName: String,
|
||||
val studentSecondName: String,
|
||||
val studentSurname: String,
|
||||
val className: String,
|
||||
val classId: Int,
|
||||
val isParent: Boolean,
|
||||
val semesters: List<Semester>,
|
||||
) : java.io.Serializable
|
@ -11,6 +11,8 @@ import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.mappers.mapToPojo
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import io.github.wulkanowy.utils.DispatchersProvider
|
||||
@ -52,6 +54,14 @@ class StudentRepository @Inject constructor(
|
||||
sdk.getStudentsFromScrapper(email, password, scrapperBaseUrl, symbol)
|
||||
.mapToEntities(password, appInfo.defaultColorsForAvatar)
|
||||
|
||||
suspend fun getUserSubjectsFromScrapper(
|
||||
email: String,
|
||||
password: String,
|
||||
scrapperBaseUrl: String,
|
||||
symbol: String
|
||||
): RegisterUser = sdk.getUserSubjectsFromScrapper(email, password, scrapperBaseUrl, symbol)
|
||||
.mapToPojo(password)
|
||||
|
||||
suspend fun getStudentsHybrid(
|
||||
email: String,
|
||||
password: String,
|
||||
|
@ -8,10 +8,11 @@ import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE
|
||||
import androidx.fragment.app.commit
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.databinding.ActivityLoginBinding
|
||||
import io.github.wulkanowy.ui.base.BaseActivity
|
||||
import io.github.wulkanowy.ui.modules.login.advanced.LoginAdvancedFragment
|
||||
@ -76,8 +77,8 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
|
||||
openFragment(LoginSymbolFragment.newInstance(loginData))
|
||||
}
|
||||
|
||||
fun navigateToStudentSelect(studentsWithSemesters: List<StudentWithSemesters>) {
|
||||
openFragment(LoginStudentSelectFragment.newInstance(studentsWithSemesters))
|
||||
fun navigateToStudentSelect(loginData: LoginData, registerUser: RegisterUser) {
|
||||
openFragment(LoginStudentSelectFragment.newInstance(loginData, registerUser))
|
||||
}
|
||||
|
||||
fun navigateToNotifications() {
|
||||
@ -105,6 +106,8 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
|
||||
}
|
||||
|
||||
private fun openFragment(fragment: Fragment, clearBackStack: Boolean = false) {
|
||||
supportFragmentManager.popBackStack(fragment::class.java.name, POP_BACK_STACK_INCLUSIVE)
|
||||
|
||||
supportFragmentManager.commit {
|
||||
replace(R.id.loginContainer, fragment)
|
||||
setReorderingAllowed(true)
|
||||
|
@ -6,4 +6,5 @@ data class LoginData(
|
||||
val login: String,
|
||||
val password: String,
|
||||
val baseUrl: String,
|
||||
val symbol: String?,
|
||||
) : Serializable
|
||||
|
@ -8,7 +8,7 @@ import android.widget.ArrayAdapter
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.databinding.FragmentLoginAdvancedBinding
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
@ -327,8 +327,8 @@ class LoginAdvancedFragment :
|
||||
(activity as? LoginActivity)?.navigateToSymbolFragment(loginData)
|
||||
}
|
||||
|
||||
override fun navigateToStudentSelect(studentsWithSemesters: List<StudentWithSemesters>) {
|
||||
(activity as? LoginActivity)?.navigateToStudentSelect(studentsWithSemesters)
|
||||
override fun navigateToStudentSelect(loginData: LoginData, registerUser: RegisterUser) {
|
||||
(activity as? LoginActivity)?.navigateToStudentSelect(loginData, registerUser)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -4,9 +4,15 @@ import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.logResourceStatus
|
||||
import io.github.wulkanowy.data.onResourceNotLoading
|
||||
import io.github.wulkanowy.data.pojos.RegisterStudent
|
||||
import io.github.wulkanowy.data.pojos.RegisterSymbol
|
||||
import io.github.wulkanowy.data.pojos.RegisterUnit
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.sdk.scrapper.Scrapper
|
||||
import io.github.wulkanowy.sdk.scrapper.getNormalizedSymbol
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
@ -149,11 +155,15 @@ class LoginAdvancedPresenter @Inject constructor(
|
||||
val loginData = LoginData(
|
||||
login = view?.formUsernameValue.orEmpty().trim(),
|
||||
password = view?.formPassValue.orEmpty().trim(),
|
||||
baseUrl = view?.formHostValue.orEmpty().trim()
|
||||
baseUrl = view?.formHostValue.orEmpty().trim(),
|
||||
symbol = view?.formSymbolValue.orEmpty().trim().getNormalizedSymbol(),
|
||||
)
|
||||
when (it.data.size) {
|
||||
0 -> view?.navigateToSymbol(loginData)
|
||||
else -> view?.navigateToStudentSelect(it.data)
|
||||
else -> view?.navigateToStudentSelect(
|
||||
loginData = loginData,
|
||||
registerUser = it.data.toRegisterUser(loginData),
|
||||
)
|
||||
}
|
||||
}
|
||||
is Resource.Error -> {
|
||||
@ -173,6 +183,58 @@ class LoginAdvancedPresenter @Inject constructor(
|
||||
}.launch("login")
|
||||
}
|
||||
|
||||
private fun List<StudentWithSemesters>.toRegisterUser(loginData: LoginData) = RegisterUser(
|
||||
email = loginData.login,
|
||||
password = loginData.password,
|
||||
login = loginData.login,
|
||||
baseUrl = loginData.baseUrl,
|
||||
loginType = firstOrNull()?.student?.loginType?.let(
|
||||
Scrapper.LoginType::valueOf
|
||||
) ?: Scrapper.LoginType.AUTO,
|
||||
symbols = this
|
||||
.groupBy { students -> students.student.symbol }
|
||||
.map { (symbol, students) ->
|
||||
RegisterSymbol(
|
||||
symbol = symbol,
|
||||
error = null,
|
||||
userName = "",
|
||||
schools = students
|
||||
.groupBy { student ->
|
||||
Triple(
|
||||
first = student.student.schoolSymbol,
|
||||
second = student.student.userLoginId,
|
||||
third = student.student.schoolShortName
|
||||
)
|
||||
}
|
||||
.map { (groupKey, students) ->
|
||||
val (schoolId, loginId, schoolName) = groupKey
|
||||
RegisterUnit(
|
||||
students = students.map {
|
||||
RegisterStudent(
|
||||
studentId = it.student.studentId,
|
||||
studentName = it.student.studentName,
|
||||
studentSecondName = it.student.studentName,
|
||||
studentSurname = it.student.studentName,
|
||||
className = it.student.className,
|
||||
classId = it.student.classId,
|
||||
isParent = it.student.isParent,
|
||||
semesters = it.semesters,
|
||||
)
|
||||
},
|
||||
userLoginId = loginId,
|
||||
schoolId = schoolId,
|
||||
schoolName = schoolName,
|
||||
schoolShortName = schoolName,
|
||||
parentIds = listOf(),
|
||||
studentIds = listOf(),
|
||||
employeeIds = listOf(),
|
||||
error = null
|
||||
)
|
||||
}
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
private suspend fun getStudentsAppropriatesToLoginType(): List<StudentWithSemesters> {
|
||||
val email = view?.formUsernameValue.orEmpty()
|
||||
val password = view?.formPassValue.orEmpty()
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.github.wulkanowy.ui.modules.login.advanced
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
|
||||
@ -72,7 +73,7 @@ interface LoginAdvancedView : BaseView {
|
||||
|
||||
fun navigateToSymbol(loginData: LoginData)
|
||||
|
||||
fun navigateToStudentSelect(studentsWithSemesters: List<StudentWithSemesters>)
|
||||
fun navigateToStudentSelect(loginData: LoginData, registerUser: RegisterUser)
|
||||
|
||||
fun setErrorPinRequired()
|
||||
|
||||
|
@ -9,7 +9,7 @@ import androidx.core.view.isVisible
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.databinding.FragmentLoginFormBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
@ -226,8 +226,8 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
|
||||
(activity as? LoginActivity)?.navigateToSymbolFragment(loginData)
|
||||
}
|
||||
|
||||
override fun navigateToStudentSelect(studentsWithSemesters: List<StudentWithSemesters>) {
|
||||
(activity as? LoginActivity)?.navigateToStudentSelect(studentsWithSemesters)
|
||||
override fun navigateToStudentSelect(loginData: LoginData, registerUser: RegisterUser) {
|
||||
(activity as? LoginActivity)?.navigateToStudentSelect(loginData, registerUser)
|
||||
}
|
||||
|
||||
override fun openAdvancedLogin() {
|
||||
|
@ -93,7 +93,7 @@ class LoginFormPresenter @Inject constructor(
|
||||
if (!validateCredentials(email, password, host)) return
|
||||
|
||||
resourceFlow {
|
||||
studentRepository.getStudentsScrapper(
|
||||
studentRepository.getUserSubjectsFromScrapper(
|
||||
email = email,
|
||||
password = password,
|
||||
scrapperBaseUrl = host,
|
||||
@ -109,14 +109,14 @@ class LoginFormPresenter @Inject constructor(
|
||||
}
|
||||
}
|
||||
.onResourceSuccess {
|
||||
when (it.size) {
|
||||
0 -> view?.navigateToSymbol(LoginData(email, password, host))
|
||||
else -> view?.navigateToStudentSelect(it)
|
||||
val loginData = LoginData(email, password, host, symbol)
|
||||
when (it.symbols.size) {
|
||||
0 -> view?.navigateToSymbol(loginData)
|
||||
else -> view?.navigateToStudentSelect(loginData, it)
|
||||
}
|
||||
analytics.logEvent(
|
||||
"registration_form",
|
||||
"success" to true,
|
||||
"students" to it.size,
|
||||
"scrapperBaseUrl" to host,
|
||||
"error" to "No error"
|
||||
)
|
||||
@ -134,7 +134,6 @@ class LoginFormPresenter @Inject constructor(
|
||||
analytics.logEvent(
|
||||
"registration_form",
|
||||
"success" to false,
|
||||
"students" to -1,
|
||||
"scrapperBaseUrl" to host,
|
||||
"error" to it.message.ifNullOrBlank { "No message" }
|
||||
)
|
||||
|
@ -1,6 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.login.form
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
|
||||
@ -60,7 +60,7 @@ interface LoginFormView : BaseView {
|
||||
|
||||
fun navigateToSymbol(loginData: LoginData)
|
||||
|
||||
fun navigateToStudentSelect(studentsWithSemesters: List<StudentWithSemesters>)
|
||||
fun navigateToStudentSelect(loginData: LoginData, registerUser: RegisterUser)
|
||||
|
||||
fun openPrivacyPolicyPage()
|
||||
|
||||
|
@ -2,65 +2,182 @@ package io.github.wulkanowy.ui.modules.login.studentselect
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.DiffUtil.ItemCallback
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.databinding.ItemLoginStudentSelectBinding
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.databinding.*
|
||||
import javax.inject.Inject
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
class LoginStudentSelectAdapter @Inject constructor() :
|
||||
RecyclerView.Adapter<LoginStudentSelectAdapter.ItemViewHolder>() {
|
||||
ListAdapter<LoginStudentSelectItem, RecyclerView.ViewHolder>(Differ) {
|
||||
|
||||
private val checkedList = mutableMapOf<Int, Boolean>()
|
||||
override fun getItemViewType(position: Int): Int = getItem(position).type.ordinal
|
||||
|
||||
var items = emptyList<Pair<StudentWithSemesters, Boolean>>()
|
||||
set(value) {
|
||||
field = value
|
||||
checkedList.clear()
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
return when (LoginStudentSelectItemType.values()[viewType]) {
|
||||
LoginStudentSelectItemType.EMPTY_SYMBOLS_HEADER -> EmptySymbolsHeaderViewHolder(
|
||||
ItemLoginStudentSelectEmptySymbolHeaderBinding.inflate(inflater, parent, false),
|
||||
)
|
||||
LoginStudentSelectItemType.SYMBOL_HEADER -> SymbolsHeaderViewHolder(
|
||||
ItemLoginStudentSelectHeaderSymbolBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
LoginStudentSelectItemType.SCHOOL_HEADER -> SchoolHeaderViewHolder(
|
||||
ItemLoginStudentSelectHeaderSchoolBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
LoginStudentSelectItemType.STUDENT -> StudentViewHolder(
|
||||
ItemLoginStudentSelectStudentBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
LoginStudentSelectItemType.HELP -> HelpViewHolder(
|
||||
ItemLoginStudentSelectHelpBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var onClickListener: (StudentWithSemesters, alreadySaved: Boolean) -> Unit = { _, _ -> }
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is EmptySymbolsHeaderViewHolder -> holder.bind(getItem(position) as LoginStudentSelectItem.EmptySymbolsHeader)
|
||||
is SymbolsHeaderViewHolder -> holder.bind(getItem(position) as LoginStudentSelectItem.SymbolHeader)
|
||||
is SchoolHeaderViewHolder -> holder.bind(getItem(position) as LoginStudentSelectItem.SchoolHeader)
|
||||
is StudentViewHolder -> holder.bind(getItem(position) as LoginStudentSelectItem.Student)
|
||||
is HelpViewHolder -> holder.bind(getItem(position) as LoginStudentSelectItem.Help)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
private class EmptySymbolsHeaderViewHolder(
|
||||
private val binding: ItemLoginStudentSelectEmptySymbolHeaderBinding,
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
|
||||
ItemLoginStudentSelectBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
)
|
||||
fun bind(item: LoginStudentSelectItem.EmptySymbolsHeader) {
|
||||
with(binding) {
|
||||
loginStudentSelectEmptySymbolChevron.rotation = if (item.isExpanded) 270f else 90f
|
||||
root.setOnClickListener { item.onClick() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
|
||||
val (studentAndSemesters, alreadySaved) = items[position]
|
||||
val student = studentAndSemesters.student
|
||||
val semesters = studentAndSemesters.semesters
|
||||
private class SymbolsHeaderViewHolder(
|
||||
private val binding: ItemLoginStudentSelectHeaderSymbolBinding,
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(item: LoginStudentSelectItem.SymbolHeader) {
|
||||
with(binding) {
|
||||
loginStudentSelectHeaderSymbolValue.text = buildString {
|
||||
append(root.context.getString(R.string.mobile_device_symbol))
|
||||
append(": ")
|
||||
append(item.humanReadableName ?: item.symbol.symbol)
|
||||
if (!item.humanReadableName.isNullOrBlank()) {
|
||||
append(" (${item.symbol.symbol})")
|
||||
}
|
||||
}
|
||||
loginStudentSelectHeaderSymbolUsername.text = item.symbol.userName
|
||||
loginStudentSelectHeaderSymbolUsername.isVisible = item.symbol.userName.isNotBlank()
|
||||
loginStudentSelectHeaderSymbolError.text = item.symbol.error?.message
|
||||
loginStudentSelectHeaderSymbolError.isVisible = item.symbol.error != null
|
||||
loginStudentSelectHeaderSymbolError.maxLines = when {
|
||||
item.isErrorExpanded -> Int.MAX_VALUE
|
||||
else -> 2
|
||||
}
|
||||
|
||||
if (item.symbol.error != null) {
|
||||
root.setOnClickListener { item.onClick(item.symbol) }
|
||||
} else root.setOnClickListener(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SchoolHeaderViewHolder(
|
||||
private val binding: ItemLoginStudentSelectHeaderSchoolBinding,
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(item: LoginStudentSelectItem.SchoolHeader) {
|
||||
with(binding) {
|
||||
loginStudentSelectHeaderSchoolName.text = buildString {
|
||||
append(item.unit.schoolName.trim())
|
||||
append(" (")
|
||||
append(item.unit.schoolShortName)
|
||||
append(")")
|
||||
}
|
||||
loginStudentSelectHeaderSchoolDetails.isVisible = item.unit.students.isEmpty()
|
||||
loginStudentSelectHeaderSchoolError.text = item.unit.error?.message
|
||||
loginStudentSelectHeaderSchoolError.isVisible = item.unit.error != null
|
||||
loginStudentSelectHeaderSchoolError.maxLines = when {
|
||||
item.isErrorExpanded -> Int.MAX_VALUE
|
||||
else -> 2
|
||||
}
|
||||
|
||||
if (item.unit.error != null) {
|
||||
root.setOnClickListener { item.onClick(item.unit) }
|
||||
} else root.setOnClickListener(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class StudentViewHolder(
|
||||
private val binding: ItemLoginStudentSelectStudentBinding,
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(item: LoginStudentSelectItem.Student) {
|
||||
val student = item.student
|
||||
val semesters = student.semesters
|
||||
val diary = semesters.maxByOrNull { it.semesterId }
|
||||
|
||||
with(holder.binding) {
|
||||
loginItemName.text = "${student.studentName} ${diary?.diaryName.orEmpty()}"
|
||||
loginItemSchool.text = student.schoolName
|
||||
loginItemName.isEnabled = !alreadySaved
|
||||
loginItemSchool.isEnabled = !alreadySaved
|
||||
loginItemSignedIn.visibility = if (alreadySaved) View.VISIBLE else View.GONE
|
||||
with(binding) {
|
||||
loginItemName.text = "${student.studentName} ${student.studentSurname}"
|
||||
loginItemName.isEnabled = item.isEnabled
|
||||
loginItemSignedIn.text = if (!item.isEnabled) {
|
||||
root.context.getString(R.string.login_signed_in)
|
||||
} else diary?.diaryName
|
||||
|
||||
with(loginItemCheck) {
|
||||
isEnabled = !alreadySaved
|
||||
keyListener = null
|
||||
isChecked = checkedList[position] ?: false
|
||||
isEnabled = item.isEnabled
|
||||
isChecked = item.isSelected || !item.isEnabled
|
||||
}
|
||||
|
||||
root.isEnabled = item.isEnabled
|
||||
root.setOnClickListener {
|
||||
onClickListener(studentAndSemesters, alreadySaved)
|
||||
|
||||
with(loginItemCheck) {
|
||||
if (isEnabled) {
|
||||
isChecked = !isChecked
|
||||
checkedList[position] = isChecked
|
||||
}
|
||||
item.onClick(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ItemViewHolder(val binding: ItemLoginStudentSelectBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
private class HelpViewHolder(
|
||||
private val binding: ItemLoginStudentSelectHelpBinding,
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(item: LoginStudentSelectItem.Help) {
|
||||
with(binding) {
|
||||
loginStudentSelectHelpSymbol.isVisible = item.isSymbolButtonVisible
|
||||
loginStudentSelectHelpSymbol.setOnClickListener { item.onEnterSymbolClick() }
|
||||
loginStudentSelectHelpMail.setOnClickListener { item.onContactUsClick() }
|
||||
loginStudentSelectHelpDiscord.setOnClickListener { item.onDiscordClick() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object Differ : ItemCallback<LoginStudentSelectItem>() {
|
||||
|
||||
override fun areItemsTheSame(
|
||||
oldItem: LoginStudentSelectItem, newItem: LoginStudentSelectItem
|
||||
): Boolean = when {
|
||||
oldItem is LoginStudentSelectItem.EmptySymbolsHeader && newItem is LoginStudentSelectItem.EmptySymbolsHeader -> true
|
||||
oldItem is LoginStudentSelectItem.SymbolHeader && newItem is LoginStudentSelectItem.SymbolHeader -> {
|
||||
oldItem.symbol == newItem.symbol
|
||||
}
|
||||
oldItem is LoginStudentSelectItem.Student && newItem is LoginStudentSelectItem.Student -> {
|
||||
oldItem.student == newItem.student
|
||||
}
|
||||
else -> oldItem == newItem
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: LoginStudentSelectItem, newItem: LoginStudentSelectItem
|
||||
): Boolean = oldItem == newItem
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,16 @@ package io.github.wulkanowy.ui.modules.login.studentselect
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.core.view.isVisible
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.databinding.FragmentLoginStudentSelectBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import io.github.wulkanowy.utils.openEmailClient
|
||||
import io.github.wulkanowy.utils.openInternetBrowser
|
||||
@ -36,12 +35,23 @@ class LoginStudentSelectFragment :
|
||||
@Inject
|
||||
lateinit var preferencesRepository: PreferencesRepository
|
||||
|
||||
companion object {
|
||||
const val ARG_STUDENTS = "STUDENTS"
|
||||
private lateinit var symbolsNames: Array<String>
|
||||
private lateinit var symbolsValues: Array<String>
|
||||
|
||||
fun newInstance(studentsWithSemesters: List<StudentWithSemesters>) =
|
||||
override val symbols: Map<String, String> by lazy {
|
||||
symbolsValues.zip(symbolsNames).toMap()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ARG_LOGIN = "LOGIN"
|
||||
private const val ARG_STUDENTS = "STUDENTS"
|
||||
|
||||
fun newInstance(loginData: LoginData, registerUser: RegisterUser) =
|
||||
LoginStudentSelectFragment().apply {
|
||||
arguments = bundleOf(ARG_STUDENTS to studentsWithSemesters)
|
||||
arguments = bundleOf(
|
||||
ARG_LOGIN to loginData,
|
||||
ARG_STUDENTS to registerUser,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,34 +59,32 @@ class LoginStudentSelectFragment :
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding = FragmentLoginStudentSelectBinding.bind(view)
|
||||
|
||||
symbolsNames = resources.getStringArray(R.array.symbols)
|
||||
symbolsValues = resources.getStringArray(R.array.symbols_values)
|
||||
|
||||
presenter.onAttachView(
|
||||
view = this,
|
||||
students = requireArguments().serializable(ARG_STUDENTS),
|
||||
loginData = requireArguments().serializable(ARG_LOGIN),
|
||||
registerUser = requireArguments().serializable(ARG_STUDENTS),
|
||||
)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
(requireActivity() as LoginActivity).showActionBar(true)
|
||||
|
||||
loginAdapter.onClickListener = presenter::onItemSelected
|
||||
|
||||
with(binding) {
|
||||
loginStudentSelectSignIn.setOnClickListener { presenter.onSignIn() }
|
||||
loginStudentSelectContactDiscord.setOnClickListener { presenter.onDiscordClick() }
|
||||
loginStudentSelectContactEmail.setOnClickListener { presenter.onEmailClick() }
|
||||
|
||||
with(loginStudentSelectRecycler) {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
adapter = loginAdapter
|
||||
}
|
||||
loginStudentSelectRecycler.adapter = loginAdapter
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateData(data: List<Pair<StudentWithSemesters, Boolean>>) {
|
||||
with(loginAdapter) {
|
||||
items = data
|
||||
notifyDataSetChanged()
|
||||
override fun updateData(data: List<LoginStudentSelectItem>) {
|
||||
loginAdapter.submitList(data)
|
||||
}
|
||||
|
||||
override fun navigateToSymbol(loginData: LoginData) {
|
||||
(requireActivity() as LoginActivity).navigateToSymbolFragment(loginData)
|
||||
}
|
||||
|
||||
override fun navigateToNext() {
|
||||
@ -84,26 +92,17 @@ class LoginStudentSelectFragment :
|
||||
}
|
||||
|
||||
override fun showProgress(show: Boolean) {
|
||||
binding.loginStudentSelectProgress.visibility = if (show) VISIBLE else GONE
|
||||
binding.loginStudentSelectProgress.isVisible = show
|
||||
}
|
||||
|
||||
override fun showContent(show: Boolean) {
|
||||
binding.loginStudentSelectContent.visibility = if (show) VISIBLE else GONE
|
||||
binding.loginStudentSelectContent.isVisible = show
|
||||
}
|
||||
|
||||
override fun enableSignIn(enable: Boolean) {
|
||||
binding.loginStudentSelectSignIn.isEnabled = enable
|
||||
}
|
||||
|
||||
override fun showContact(show: Boolean) {
|
||||
binding.loginStudentSelectContact.visibility = if (show) VISIBLE else GONE
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
presenter.onDetachView()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun openDiscordInvite() {
|
||||
context?.openInternetBrowser("https://discord.gg/vccAQBr", ::showMessage)
|
||||
}
|
||||
@ -124,4 +123,9 @@ class LoginStudentSelectFragment :
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
presenter.onDetachView()
|
||||
super.onDestroyView()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
package io.github.wulkanowy.ui.modules.login.studentselect
|
||||
|
||||
import io.github.wulkanowy.data.pojos.RegisterStudent
|
||||
import io.github.wulkanowy.data.pojos.RegisterSymbol
|
||||
import io.github.wulkanowy.data.pojos.RegisterUnit
|
||||
|
||||
sealed class LoginStudentSelectItem(val type: LoginStudentSelectItemType) {
|
||||
|
||||
data class EmptySymbolsHeader(
|
||||
val isExpanded: Boolean,
|
||||
val onClick: () -> Unit,
|
||||
) : LoginStudentSelectItem(LoginStudentSelectItemType.EMPTY_SYMBOLS_HEADER)
|
||||
|
||||
data class SymbolHeader(
|
||||
val symbol: RegisterSymbol,
|
||||
val humanReadableName: String?,
|
||||
val isErrorExpanded: Boolean,
|
||||
val onClick: (RegisterSymbol) -> Unit,
|
||||
) : LoginStudentSelectItem(LoginStudentSelectItemType.SYMBOL_HEADER)
|
||||
|
||||
data class SchoolHeader(
|
||||
val unit: RegisterUnit,
|
||||
val isErrorExpanded: Boolean,
|
||||
val onClick: (RegisterUnit) -> Unit,
|
||||
) : LoginStudentSelectItem(LoginStudentSelectItemType.SCHOOL_HEADER)
|
||||
|
||||
data class Student(
|
||||
val symbol: RegisterSymbol,
|
||||
val unit: RegisterUnit,
|
||||
val student: RegisterStudent,
|
||||
val isEnabled: Boolean,
|
||||
val isSelected: Boolean,
|
||||
val onClick: (Student) -> Unit,
|
||||
) : LoginStudentSelectItem(LoginStudentSelectItemType.STUDENT)
|
||||
|
||||
data class Help(
|
||||
val onEnterSymbolClick: () -> Unit,
|
||||
val onContactUsClick: () -> Unit,
|
||||
val onDiscordClick: () -> Unit,
|
||||
val isSymbolButtonVisible: Boolean,
|
||||
) : LoginStudentSelectItem(LoginStudentSelectItemType.HELP)
|
||||
}
|
||||
|
||||
enum class LoginStudentSelectItemType {
|
||||
EMPTY_SYMBOLS_HEADER,
|
||||
SYMBOL_HEADER,
|
||||
SCHOOL_HEADER,
|
||||
STUDENT,
|
||||
HELP,
|
||||
}
|
@ -1,15 +1,23 @@
|
||||
package io.github.wulkanowy.ui.modules.login.studentselect
|
||||
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.dataOrNull
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.logResourceStatus
|
||||
import io.github.wulkanowy.data.mappers.mapToStudentWithSemesters
|
||||
import io.github.wulkanowy.data.pojos.RegisterStudent
|
||||
import io.github.wulkanowy.data.pojos.RegisterSymbol
|
||||
import io.github.wulkanowy.data.pojos.RegisterUnit
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.sdk.scrapper.login.AccountPermissionException
|
||||
import io.github.wulkanowy.services.sync.SyncManager
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import io.github.wulkanowy.utils.ifNullOrBlank
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
@ -19,18 +27,30 @@ class LoginStudentSelectPresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val loginErrorHandler: LoginErrorHandler,
|
||||
private val syncManager: SyncManager,
|
||||
private val analytics: AnalyticsHelper
|
||||
private val analytics: AnalyticsHelper,
|
||||
private val appInfo: AppInfo,
|
||||
) : BasePresenter<LoginStudentSelectView>(loginErrorHandler, studentRepository) {
|
||||
|
||||
private var lastError: Throwable? = null
|
||||
|
||||
private val selectedStudents = mutableListOf<StudentWithSemesters>()
|
||||
private lateinit var registerUser: RegisterUser
|
||||
private lateinit var loginData: LoginData
|
||||
|
||||
fun onAttachView(view: LoginStudentSelectView, students: List<StudentWithSemesters>) {
|
||||
private lateinit var students: List<StudentWithSemesters>
|
||||
private var isEmptySymbolsExpanded = false
|
||||
private var expandedSymbolError: RegisterSymbol? = null
|
||||
private var expandedSchoolError: RegisterUnit? = null
|
||||
|
||||
private val selectedStudents = mutableListOf<LoginStudentSelectItem.Student>()
|
||||
|
||||
fun onAttachView(
|
||||
view: LoginStudentSelectView,
|
||||
loginData: LoginData,
|
||||
registerUser: RegisterUser,
|
||||
) {
|
||||
super.onAttachView(view)
|
||||
with(view) {
|
||||
initView()
|
||||
showContact(false)
|
||||
enableSignIn(false)
|
||||
loginErrorHandler.onStudentDuplicate = {
|
||||
showMessage(it)
|
||||
@ -38,50 +58,171 @@ class LoginStudentSelectPresenter @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
if (students.size == 1) registerStudents(students)
|
||||
loadData(students)
|
||||
this.loginData = loginData
|
||||
this.registerUser = registerUser
|
||||
loadData()
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
resetSelectedState()
|
||||
|
||||
resourceFlow { studentRepository.getSavedStudents(false) }.onEach {
|
||||
students = it.dataOrNull.orEmpty()
|
||||
when (it) {
|
||||
is Resource.Loading -> Timber.d("Login student select students load started")
|
||||
is Resource.Success -> refreshItems()
|
||||
is Resource.Error -> {
|
||||
errorHandler.dispatch(it.error)
|
||||
lastError = it.error
|
||||
refreshItems()
|
||||
}
|
||||
}
|
||||
}.launch()
|
||||
}
|
||||
|
||||
private fun createItems(): List<LoginStudentSelectItem> = buildList {
|
||||
val notEmptySymbols = registerUser.symbols.filter { it.schools.isNotEmpty() }
|
||||
val emptySymbols = registerUser.symbols.filter { it.schools.isEmpty() }
|
||||
|
||||
if (emptySymbols.isNotEmpty() && notEmptySymbols.isNotEmpty() && emptySymbols.any { it.symbol == loginData.symbol }) {
|
||||
add(createEmptySymbolItem(emptySymbols.first { it.symbol == loginData.symbol }))
|
||||
}
|
||||
|
||||
addAll(createNotEmptySymbolItems(notEmptySymbols, students))
|
||||
addAll(createEmptySymbolItems(emptySymbols, notEmptySymbols.isNotEmpty()))
|
||||
|
||||
val helpItem = LoginStudentSelectItem.Help(
|
||||
onEnterSymbolClick = ::onEnterSymbol,
|
||||
onContactUsClick = ::onEmailClick,
|
||||
onDiscordClick = ::onDiscordClick,
|
||||
isSymbolButtonVisible = "login" !in loginData.baseUrl,
|
||||
)
|
||||
add(helpItem)
|
||||
}
|
||||
|
||||
private fun createNotEmptySymbolItems(
|
||||
notEmptySymbols: List<RegisterSymbol>,
|
||||
students: List<StudentWithSemesters>,
|
||||
) = buildList {
|
||||
notEmptySymbols.forEach { registerSymbol ->
|
||||
val symbolHeader = LoginStudentSelectItem.SymbolHeader(
|
||||
symbol = registerSymbol,
|
||||
humanReadableName = view?.symbols?.get(registerSymbol.symbol),
|
||||
isErrorExpanded = expandedSymbolError == registerSymbol,
|
||||
onClick = ::onSymbolItemClick,
|
||||
)
|
||||
add(symbolHeader)
|
||||
|
||||
registerSymbol.schools.forEach { registerUnit ->
|
||||
val schoolHeader = LoginStudentSelectItem.SchoolHeader(
|
||||
unit = registerUnit,
|
||||
isErrorExpanded = expandedSchoolError == registerUnit,
|
||||
onClick = ::onUnitItemClick,
|
||||
)
|
||||
add(schoolHeader)
|
||||
|
||||
registerUnit.students.forEach {
|
||||
add(createStudentItem(it, registerSymbol, registerUnit, students))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createStudentItem(
|
||||
student: RegisterStudent,
|
||||
symbol: RegisterSymbol,
|
||||
school: RegisterUnit,
|
||||
students: List<StudentWithSemesters>,
|
||||
) = LoginStudentSelectItem.Student(
|
||||
symbol = symbol,
|
||||
unit = school,
|
||||
student = student,
|
||||
onClick = ::onItemSelected,
|
||||
isEnabled = students.none {
|
||||
it.student.email == registerUser.login
|
||||
&& it.student.symbol == symbol.symbol
|
||||
&& it.student.studentId == student.studentId
|
||||
&& it.student.schoolSymbol == school.schoolId
|
||||
&& it.student.classId == student.classId
|
||||
},
|
||||
isSelected = selectedStudents
|
||||
.filter { it.symbol.symbol == symbol.symbol }
|
||||
.filter { it.unit.schoolId == school.schoolId }
|
||||
.filter { it.student.studentId == student.studentId }
|
||||
.filter { it.student.classId == student.classId }
|
||||
.size == 1,
|
||||
)
|
||||
|
||||
private fun createEmptySymbolItems(
|
||||
emptySymbols: List<RegisterSymbol>,
|
||||
isNotEmptySymbolsExist: Boolean,
|
||||
) = buildList {
|
||||
val filteredEmptySymbols = emptySymbols.filter {
|
||||
it.error !is AccountPermissionException
|
||||
}.ifEmpty { emptySymbols.takeIf { !isNotEmptySymbolsExist }.orEmpty() }
|
||||
|
||||
if (filteredEmptySymbols.isNotEmpty() && isNotEmptySymbolsExist) {
|
||||
val emptyHeader = LoginStudentSelectItem.EmptySymbolsHeader(
|
||||
isExpanded = isEmptySymbolsExpanded,
|
||||
onClick = ::onEmptySymbolsToggle,
|
||||
)
|
||||
add(emptyHeader)
|
||||
if (isEmptySymbolsExpanded) {
|
||||
filteredEmptySymbols.forEach {
|
||||
add(createEmptySymbolItem(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (filteredEmptySymbols.isNotEmpty() && !isNotEmptySymbolsExist) {
|
||||
filteredEmptySymbols.forEach {
|
||||
add(createEmptySymbolItem(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createEmptySymbolItem(registerSymbol: RegisterSymbol) =
|
||||
LoginStudentSelectItem.SymbolHeader(
|
||||
symbol = registerSymbol,
|
||||
humanReadableName = view?.symbols?.get(registerSymbol.symbol),
|
||||
isErrorExpanded = expandedSymbolError == registerSymbol,
|
||||
onClick = ::onSymbolItemClick,
|
||||
)
|
||||
|
||||
fun onSignIn() {
|
||||
registerStudents(selectedStudents)
|
||||
}
|
||||
|
||||
fun onItemSelected(studentWithSemester: StudentWithSemesters, alreadySaved: Boolean) {
|
||||
if (alreadySaved) return
|
||||
private fun onEmptySymbolsToggle() {
|
||||
isEmptySymbolsExpanded = !isEmptySymbolsExpanded
|
||||
|
||||
refreshItems()
|
||||
}
|
||||
|
||||
private fun onItemSelected(item: LoginStudentSelectItem.Student) {
|
||||
if (!item.isEnabled) return
|
||||
|
||||
selectedStudents
|
||||
.removeAll { it == studentWithSemester }
|
||||
.let { if (!it) selectedStudents.add(studentWithSemester) }
|
||||
.removeAll {
|
||||
it.student.studentId == item.student.studentId &&
|
||||
it.student.classId == item.student.classId &&
|
||||
it.unit.schoolId == item.unit.schoolId &&
|
||||
it.symbol.symbol == item.symbol.symbol
|
||||
}
|
||||
.let { if (!it) selectedStudents.add(item) }
|
||||
|
||||
view?.enableSignIn(selectedStudents.isNotEmpty())
|
||||
refreshItems()
|
||||
}
|
||||
|
||||
private fun compareStudents(a: Student, b: Student): Boolean {
|
||||
return a.email == b.email
|
||||
&& a.symbol == b.symbol
|
||||
&& a.studentId == b.studentId
|
||||
&& a.schoolSymbol == b.schoolSymbol
|
||||
&& a.classId == b.classId
|
||||
private fun onSymbolItemClick(symbol: RegisterSymbol) {
|
||||
expandedSymbolError = if (symbol != expandedSymbolError) symbol else null
|
||||
refreshItems()
|
||||
}
|
||||
|
||||
private fun loadData(studentsWithSemesters: List<StudentWithSemesters>) {
|
||||
resetSelectedState()
|
||||
|
||||
resourceFlow { studentRepository.getSavedStudents(false) }.onEach {
|
||||
when (it) {
|
||||
is Resource.Loading -> Timber.d("Login student select students load started")
|
||||
is Resource.Success -> view?.updateData(studentsWithSemesters.map { studentWithSemesters ->
|
||||
studentWithSemesters to it.data.any { item ->
|
||||
compareStudents(studentWithSemesters.student, item.student)
|
||||
}
|
||||
})
|
||||
is Resource.Error -> {
|
||||
errorHandler.dispatch(it.error)
|
||||
lastError = it.error
|
||||
view?.updateData(studentsWithSemesters.map { student -> student to false })
|
||||
}
|
||||
}
|
||||
}.launch()
|
||||
private fun onUnitItemClick(unit: RegisterUnit) {
|
||||
expandedSchoolError = if (unit != expandedSchoolError) unit else null
|
||||
refreshItems()
|
||||
}
|
||||
|
||||
private fun resetSelectedState() {
|
||||
@ -89,7 +230,20 @@ class LoginStudentSelectPresenter @Inject constructor(
|
||||
view?.enableSignIn(false)
|
||||
}
|
||||
|
||||
private fun registerStudents(studentsWithSemesters: List<StudentWithSemesters>) {
|
||||
private fun refreshItems() {
|
||||
view?.updateData(createItems())
|
||||
}
|
||||
|
||||
private fun registerStudents(students: List<LoginStudentSelectItem>) {
|
||||
val studentsWithSemesters = students
|
||||
.filterIsInstance<LoginStudentSelectItem.Student>().map { item ->
|
||||
item.student.mapToStudentWithSemesters(
|
||||
user = registerUser,
|
||||
symbol = item.symbol,
|
||||
unit = item.unit,
|
||||
colors = appInfo.defaultColorsForAvatar,
|
||||
)
|
||||
}
|
||||
resourceFlow { studentRepository.saveStudents(studentsWithSemesters) }
|
||||
.logResourceStatus("registration")
|
||||
.onEach {
|
||||
@ -107,7 +261,6 @@ class LoginStudentSelectPresenter @Inject constructor(
|
||||
view?.apply {
|
||||
showProgress(false)
|
||||
showContent(true)
|
||||
showContact(true)
|
||||
}
|
||||
lastError = it.error
|
||||
loginErrorHandler.dispatch(it.error)
|
||||
@ -117,12 +270,22 @@ class LoginStudentSelectPresenter @Inject constructor(
|
||||
}.launch("register")
|
||||
}
|
||||
|
||||
fun onDiscordClick() {
|
||||
private fun onEnterSymbol() {
|
||||
view?.navigateToSymbol(loginData)
|
||||
}
|
||||
|
||||
private fun onDiscordClick() {
|
||||
view?.openDiscordInvite()
|
||||
}
|
||||
|
||||
fun onEmailClick() {
|
||||
view?.openEmail(lastError?.message.ifNullOrBlank { "empty" })
|
||||
private fun onEmailClick() {
|
||||
view?.openEmail(lastError?.message.ifNullOrBlank {
|
||||
registerUser.symbols.flatMap { symbol ->
|
||||
symbol.schools.map { it.error?.message } + symbol.error?.message
|
||||
}.filterNotNull().distinct().joinToString("; ") {
|
||||
it.take(46) + "..."
|
||||
}.ifEmpty { "blank" }
|
||||
})
|
||||
}
|
||||
|
||||
private fun logRegisterEvent(
|
||||
|
@ -1,13 +1,17 @@
|
||||
package io.github.wulkanowy.ui.modules.login.studentselect
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
|
||||
interface LoginStudentSelectView : BaseView {
|
||||
|
||||
val symbols: Map<String, String>
|
||||
|
||||
fun initView()
|
||||
|
||||
fun updateData(data: List<Pair<StudentWithSemesters, Boolean>>)
|
||||
fun updateData(data: List<LoginStudentSelectItem>)
|
||||
|
||||
fun navigateToSymbol(loginData: LoginData)
|
||||
|
||||
fun navigateToNext()
|
||||
|
||||
@ -17,8 +21,6 @@ interface LoginStudentSelectView : BaseView {
|
||||
|
||||
fun enableSignIn(enable: Boolean)
|
||||
|
||||
fun showContact(show: Boolean)
|
||||
|
||||
fun openDiscordInvite()
|
||||
|
||||
fun openEmail(lastError: String)
|
||||
|
@ -12,7 +12,7 @@ import androidx.core.text.parseAsHtml
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.databinding.FragmentLoginSymbolBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
@ -42,6 +42,8 @@ class LoginSymbolFragment :
|
||||
}
|
||||
}
|
||||
|
||||
override val symbolValue: String? get() = binding.loginSymbolName.text?.toString()
|
||||
|
||||
override val symbolNameError: CharSequence?
|
||||
get() = binding.loginSymbolNameLayout.error
|
||||
|
||||
@ -58,7 +60,7 @@ class LoginSymbolFragment :
|
||||
(requireActivity() as LoginActivity).showActionBar(true)
|
||||
|
||||
with(binding) {
|
||||
loginSymbolSignIn.setOnClickListener { presenter.attemptLogin(loginSymbolName.text.toString()) }
|
||||
loginSymbolSignIn.setOnClickListener { presenter.attemptLogin() }
|
||||
loginSymbolFaq.setOnClickListener { presenter.onFaqClick() }
|
||||
loginSymbolContactEmail.setOnClickListener { presenter.onEmailClick() }
|
||||
|
||||
@ -92,9 +94,13 @@ class LoginSymbolFragment :
|
||||
}
|
||||
|
||||
override fun setErrorSymbolRequire() {
|
||||
binding.loginSymbolNameLayout.apply {
|
||||
setErrorSymbol(getString(R.string.error_field_required))
|
||||
}
|
||||
|
||||
override fun setErrorSymbol(message: String) {
|
||||
with(binding.loginSymbolNameLayout) {
|
||||
requestFocus()
|
||||
error = getString(R.string.error_field_required)
|
||||
error = message
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,8 +131,8 @@ class LoginSymbolFragment :
|
||||
binding.loginSymbolContainer.visibility = if (show) VISIBLE else GONE
|
||||
}
|
||||
|
||||
override fun navigateToStudentSelect(studentsWithSemesters: List<StudentWithSemesters>) {
|
||||
(activity as? LoginActivity)?.navigateToStudentSelect(studentsWithSemesters)
|
||||
override fun navigateToStudentSelect(loginData: LoginData, registerUser: RegisterUser) {
|
||||
(activity as? LoginActivity)?.navigateToStudentSelect(loginData, registerUser)
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
|
@ -1,9 +1,12 @@
|
||||
package io.github.wulkanowy.ui.modules.login.symbol
|
||||
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.dataOrNull
|
||||
import io.github.wulkanowy.data.onResourceNotLoading
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.sdk.scrapper.getNormalizedSymbol
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
@ -23,9 +26,14 @@ class LoginSymbolPresenter @Inject constructor(
|
||||
|
||||
lateinit var loginData: LoginData
|
||||
|
||||
private var registerUser: RegisterUser? = null
|
||||
|
||||
fun onAttachView(view: LoginSymbolView, loginData: LoginData) {
|
||||
super.onAttachView(view)
|
||||
this.loginData = loginData
|
||||
loginErrorHandler.onBadCredentials = {
|
||||
view.setErrorSymbol(it.orEmpty())
|
||||
}
|
||||
with(view) {
|
||||
initView()
|
||||
showContact(false)
|
||||
@ -39,20 +47,24 @@ class LoginSymbolPresenter @Inject constructor(
|
||||
view?.apply { if (symbolNameError != null) clearSymbolError() }
|
||||
}
|
||||
|
||||
fun attemptLogin(symbol: String) {
|
||||
if (symbol.isBlank()) {
|
||||
fun attemptLogin() {
|
||||
if (view?.symbolValue.isNullOrBlank()) {
|
||||
view?.setErrorSymbolRequire()
|
||||
return
|
||||
}
|
||||
|
||||
loginData = loginData.copy(
|
||||
symbol = view?.symbolValue?.getNormalizedSymbol(),
|
||||
)
|
||||
resourceFlow {
|
||||
studentRepository.getStudentsScrapper(
|
||||
studentRepository.getUserSubjectsFromScrapper(
|
||||
email = loginData.login,
|
||||
password = loginData.password,
|
||||
scrapperBaseUrl = loginData.baseUrl,
|
||||
symbol = symbol,
|
||||
symbol = view?.symbolValue.orEmpty(),
|
||||
)
|
||||
}.onEach {
|
||||
registerUser = it.dataOrNull
|
||||
when (it) {
|
||||
is Resource.Loading -> view?.run {
|
||||
Timber.i("Login with symbol started")
|
||||
@ -61,7 +73,7 @@ class LoginSymbolPresenter @Inject constructor(
|
||||
showContent(false)
|
||||
}
|
||||
is Resource.Success -> {
|
||||
when (it.data.size) {
|
||||
when (it.data.symbols.size) {
|
||||
0 -> {
|
||||
Timber.i("Login with symbol result: Empty student list")
|
||||
view?.run {
|
||||
@ -71,15 +83,14 @@ class LoginSymbolPresenter @Inject constructor(
|
||||
}
|
||||
else -> {
|
||||
Timber.i("Login with symbol result: Success")
|
||||
view?.navigateToStudentSelect(requireNotNull(it.data))
|
||||
view?.navigateToStudentSelect(loginData, requireNotNull(it.data))
|
||||
}
|
||||
}
|
||||
analytics.logEvent(
|
||||
"registration_symbol",
|
||||
"success" to true,
|
||||
"students" to it.data.size,
|
||||
"scrapperBaseUrl" to loginData.baseUrl,
|
||||
"symbol" to symbol,
|
||||
"symbol" to view?.symbolValue,
|
||||
"error" to "No error"
|
||||
)
|
||||
}
|
||||
@ -90,7 +101,7 @@ class LoginSymbolPresenter @Inject constructor(
|
||||
"success" to false,
|
||||
"students" to -1,
|
||||
"scrapperBaseUrl" to loginData.baseUrl,
|
||||
"symbol" to symbol,
|
||||
"symbol" to view?.symbolValue,
|
||||
"error" to it.error.message.ifNullOrBlank { "No message" }
|
||||
)
|
||||
loginErrorHandler.dispatch(it.error)
|
||||
@ -111,6 +122,12 @@ class LoginSymbolPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
fun onEmailClick() {
|
||||
view?.openEmail(loginData.baseUrl, lastError?.message.ifNullOrBlank { "empty" })
|
||||
view?.openEmail(loginData.baseUrl, lastError?.message.ifNullOrBlank {
|
||||
registerUser?.symbols?.flatMap { symbol ->
|
||||
symbol.schools.map { it.error?.message } + symbol.error?.message
|
||||
}?.filterNotNull()?.distinct()?.joinToString(";") {
|
||||
it.take(46) + "..."
|
||||
} ?: "blank"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
package io.github.wulkanowy.ui.modules.login.symbol
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
|
||||
interface LoginSymbolView : BaseView {
|
||||
|
||||
val symbolValue: String?
|
||||
|
||||
val symbolNameError: CharSequence?
|
||||
|
||||
fun initView()
|
||||
@ -15,6 +18,8 @@ interface LoginSymbolView : BaseView {
|
||||
|
||||
fun setErrorSymbolRequire()
|
||||
|
||||
fun setErrorSymbol(message: String)
|
||||
|
||||
fun clearSymbolError()
|
||||
|
||||
fun clearAndFocusSymbol()
|
||||
@ -27,7 +32,7 @@ interface LoginSymbolView : BaseView {
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
|
||||
fun navigateToStudentSelect(studentsWithSemesters: List<StudentWithSemesters>)
|
||||
fun navigateToStudentSelect(loginData: LoginData, registerUser: RegisterUser)
|
||||
|
||||
fun showContact(show: Boolean)
|
||||
|
||||
|
@ -3,92 +3,14 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/loginStudentSelectProgress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone" />
|
||||
android:orientation="vertical"
|
||||
tools:context=".ui.modules.login.studentselect.LoginStudentSelectFragment">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/loginStudentSelectContent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/loginStudentSelectContact"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible">
|
||||
|
||||
<View
|
||||
android:id="@+id/loginStudentSelectContactTopDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?android:attr/listDivider" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loginStudentSelectContactHeader"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginLeft="32dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:layout_marginRight="32dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="@string/login_contact_header"
|
||||
android:textSize="14sp"
|
||||
app:fontFamily="sans-serif-medium" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/loginStudentSelectContactButtons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/loginStudentSelectContactEmail"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/login_contact_email"
|
||||
app:icon="@drawable/ic_more_messages" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/loginStudentSelectContactDiscord"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/login_contact_discord"
|
||||
app:icon="@drawable/ic_about_discord" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/loginStudentSelectContactBottomDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="?android:attr/listDivider" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loginStudentSelectHeader"
|
||||
android:layout_width="match_parent"
|
||||
@ -106,22 +28,24 @@
|
||||
app:layout_constraintBottom_toTopOf="@id/loginStudentSelectRecycler"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/loginStudentSelectContact"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/loginStudentSelectRecycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="144dp"
|
||||
android:fadingEdge="vertical"
|
||||
android:fadingEdgeLength="100dp"
|
||||
android:requiresFadingEdge="vertical"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constrainedHeight="true"
|
||||
app:layout_constraintBottom_toTopOf="@id/loginStudentSelectSignIn"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHeight_max="432dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/loginStudentSelectHeader"
|
||||
tools:itemCount="6"
|
||||
tools:listitem="@layout/item_login_student_select" />
|
||||
tools:itemCount="33"
|
||||
tools:listitem="@layout/item_login_student_select_student" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/loginStudentSelectSignIn"
|
||||
@ -136,4 +60,12 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/loginStudentSelectRecycler" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/loginStudentSelectProgress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
|
@ -0,0 +1,38 @@
|
||||
<?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:layout_marginTop="8dp"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingHorizontal="16dp">
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/login_student_select_empty_symbol_header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="16dp"
|
||||
android:text="@string/login_other_search_locations"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/login_student_select_empty_symbol_chevron"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:rotation="90"
|
||||
android:src="@drawable/ic_chevron_right"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="?android:textColorPrimary"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -0,0 +1,38 @@
|
||||
<?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:paddingHorizontal="24dp"
|
||||
android:paddingVertical="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/login_student_select_header_school_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Publiczna szkoła Wulkanowego" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/login_student_select_header_school_details"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:text="@string/login_no_active_student"
|
||||
android:textColor="?colorTimetableChange"
|
||||
app:layout_constraintTop_toBottomOf="@id/login_student_select_header_school_name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/login_student_select_header_school_error"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:textColor="?colorError"
|
||||
app:layout_constraintTop_toBottomOf="@id/login_student_select_header_school_details"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -0,0 +1,38 @@
|
||||
<?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:paddingHorizontal="16dp"
|
||||
android:paddingVertical="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/login_student_select_header_symbol_value"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="powiatjaroslawski" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/login_student_select_header_symbol_username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
app:layout_constraintTop_toBottomOf="@id/login_student_select_header_symbol_value"
|
||||
tools:text="Jan Kowalski" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/login_student_select_header_symbol_error"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:textColor="?colorError"
|
||||
app:layout_constraintTop_toBottomOf="@id/login_student_select_header_symbol_username"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
61
app/src/main/res/layout/item_login_student_select_help.xml
Normal file
61
app/src/main/res/layout/item_login_student_select_help.xml
Normal file
@ -0,0 +1,61 @@
|
||||
<?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:paddingHorizontal="16dp"
|
||||
android:paddingVertical="8dp">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/login_student_select_help_symbol"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/login_symbol_enter"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/login_student_select_help_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/login_contact_header"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/login_student_select_help_mail"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/login_student_select_help_symbol" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/login_student_select_help_mail"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:contentDescription="@string/login_contact_email"
|
||||
app:icon="@drawable/ic_more_messages"
|
||||
app:iconGravity="textStart"
|
||||
app:iconPadding="0dp"
|
||||
app:layout_constraintEnd_toEndOf="@id/login_student_select_help_title"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toEndOf="@id/login_student_select_help_title"
|
||||
app:layout_constraintTop_toBottomOf="@id/login_student_select_help_symbol" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/login_student_select_help_discord"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:contentDescription="@string/login_contact_discord"
|
||||
app:icon="@drawable/ic_about_discord"
|
||||
app:iconGravity="textStart"
|
||||
app:iconPadding="0dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/login_student_select_help_mail"
|
||||
app:layout_constraintTop_toTopOf="@id/login_student_select_help_mail" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -4,7 +4,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackground"
|
||||
android:minHeight="72dp"
|
||||
android:minHeight="56dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
tools:context=".ui.modules.login.studentselect.LoginStudentSelectAdapter">
|
||||
@ -14,9 +14,10 @@
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="28dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:clickable="false"
|
||||
tools:text=" " />
|
||||
|
||||
<TextView
|
||||
@ -32,34 +33,18 @@
|
||||
tools:text="@tools:sample/full_names" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loginItemSchool"
|
||||
android:id="@+id/loginItemSignedIn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/loginItemName"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_toEndOf="@id/loginItemCheck"
|
||||
android:ellipsize="end"
|
||||
android:gravity="bottom"
|
||||
android:maxLines="2"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="14sp"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loginItemSignedIn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="20dp"
|
||||
android:layout_below="@id/loginItemSchool"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_toEndOf="@id/loginItemCheck"
|
||||
android:ellipsize="end"
|
||||
android:enabled="false"
|
||||
android:gravity="bottom"
|
||||
android:maxLines="1"
|
||||
android:minHeight="20dp"
|
||||
android:text="@string/login_signed_in"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
android:textSize="14sp" />
|
||||
</RelativeLayout>
|
@ -55,7 +55,7 @@
|
||||
<string name="login_invalid_symbol">Invalid symbol</string>
|
||||
<string name="login_incorrect_symbol">Student not found. Validate the symbol and the chosen variation of the UONET+ register</string>
|
||||
<string name="login_duplicate_student">Selected student is already logged in</string>
|
||||
<string name="login_symbol_helper">The symbol can be found on the register page in <b>Uczeń</b> → <b>Dostęp Mobilny</b> → <b>Zarejestruj urządzenie mobilne</b>.\n\nMake sure that you have set the appropriate register variant in the <b>UONET+ register variant</b> field on the previous screen</string>
|
||||
<string name="login_symbol_helper">The symbol can be found on the register page in <b>Uczeń</b> → <b>Dostęp Mobilny</b> → <b>Wygeneruj kod dostępu</b>.\n\nMake sure that you have set the appropriate register variant in the <b>UONET+ register variant</b> field on the first login screen</string>
|
||||
<string name="login_select_student">Select students to log in to the application</string>
|
||||
<string name="login_advanced">Other options</string>
|
||||
<string name="login_advanced_warning_mobile_api">In this mode, a lucky number does not work, a class grade stats, summary of attendance, excuse for absence, completed lessons, school information and preview of the list of registered devices</string>
|
||||
@ -74,6 +74,9 @@
|
||||
<string name="login_recover">Recover</string>
|
||||
<string name="login_signed_in">Student is already signed in</string>
|
||||
<string name="login_host_standard">Standard</string>
|
||||
<string name="login_other_search_locations">Other search locations</string>
|
||||
<string name="login_no_active_student">No active students found</string>
|
||||
<string name="login_symbol_enter">Enter a different symbol</string>
|
||||
<!--Notifications-->
|
||||
<string name="notifications_header_title">Enable notifications</string>
|
||||
<string name="notifications_header_description">Enable notifications so you don\'t miss message from teacher or new grade</string>
|
||||
|
@ -1,9 +1,9 @@
|
||||
package io.github.wulkanowy.ui.modules.login.form
|
||||
|
||||
import io.github.wulkanowy.MainCoroutineRule
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.sdk.scrapper.Scrapper
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.mockk.*
|
||||
@ -12,7 +12,6 @@ import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.io.IOException
|
||||
import java.time.Instant
|
||||
|
||||
class LoginFormPresenterTest {
|
||||
|
||||
@ -33,6 +32,15 @@ class LoginFormPresenterTest {
|
||||
|
||||
private lateinit var presenter: LoginFormPresenter
|
||||
|
||||
private val registerUser = RegisterUser(
|
||||
email = "",
|
||||
password = "",
|
||||
login = "",
|
||||
baseUrl = "",
|
||||
loginType = Scrapper.LoginType.AUTO,
|
||||
symbols = listOf(),
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockKAnnotations.init(this)
|
||||
@ -104,32 +112,9 @@ class LoginFormPresenterTest {
|
||||
|
||||
@Test
|
||||
fun loginTest() {
|
||||
val studentTest = Student(
|
||||
email = "test@",
|
||||
password = "123",
|
||||
scrapperBaseUrl = "https://fakelog.cf/?email",
|
||||
loginType = "AUTO",
|
||||
studentName = "",
|
||||
schoolSymbol = "",
|
||||
schoolName = "",
|
||||
studentId = 0,
|
||||
classId = 1,
|
||||
isCurrent = false,
|
||||
symbol = "",
|
||||
registrationDate = Instant.now(),
|
||||
className = "",
|
||||
mobileBaseUrl = "",
|
||||
privateKey = "",
|
||||
certificateKey = "",
|
||||
loginMode = "",
|
||||
userLoginId = 0,
|
||||
schoolShortName = "",
|
||||
isParent = false,
|
||||
userName = ""
|
||||
)
|
||||
coEvery { repository.getStudentsScrapper(any(), any(), any(), any()) } returns listOf(
|
||||
StudentWithSemesters(studentTest, emptyList())
|
||||
)
|
||||
coEvery {
|
||||
repository.getUserSubjectsFromScrapper(any(), any(), any(), any())
|
||||
} returns registerUser
|
||||
|
||||
every { loginFormView.formUsernameValue } returns "@"
|
||||
every { loginFormView.formPassValue } returns "123456"
|
||||
@ -146,7 +131,9 @@ class LoginFormPresenterTest {
|
||||
|
||||
@Test
|
||||
fun loginEmptyTest() {
|
||||
coEvery { repository.getStudentsScrapper(any(), any(), any(), any()) } returns listOf()
|
||||
coEvery {
|
||||
repository.getUserSubjectsFromScrapper(any(), any(), any(), any())
|
||||
} returns registerUser
|
||||
every { loginFormView.formUsernameValue } returns "@"
|
||||
every { loginFormView.formPassValue } returns "123456"
|
||||
every { loginFormView.formHostValue } returns "https://fakelog.cf/?email"
|
||||
@ -162,7 +149,9 @@ class LoginFormPresenterTest {
|
||||
|
||||
@Test
|
||||
fun loginEmptyTwiceTest() {
|
||||
coEvery { repository.getStudentsScrapper(any(), any(), any(), any()) } returns listOf()
|
||||
coEvery {
|
||||
repository.getUserSubjectsFromScrapper(any(), any(), any(), any())
|
||||
} returns registerUser
|
||||
every { loginFormView.formUsernameValue } returns "@"
|
||||
every { loginFormView.formPassValue } returns "123456"
|
||||
every { loginFormView.formHostValue } returns "https://fakelog.cf/?email"
|
||||
@ -180,7 +169,14 @@ class LoginFormPresenterTest {
|
||||
@Test
|
||||
fun loginErrorTest() {
|
||||
val testException = IOException("test")
|
||||
coEvery { repository.getStudentsScrapper(any(), any(), any(), any()) } throws testException
|
||||
coEvery {
|
||||
repository.getUserSubjectsFromScrapper(
|
||||
any(),
|
||||
any(),
|
||||
any(),
|
||||
any()
|
||||
)
|
||||
} throws testException
|
||||
every { loginFormView.formUsernameValue } returns "@"
|
||||
every { loginFormView.formPassValue } returns "123456"
|
||||
every { loginFormView.formHostValue } returns "https://fakelog.cf/?email"
|
||||
|
@ -1,18 +1,22 @@
|
||||
package io.github.wulkanowy.ui.modules.login.studentselect
|
||||
|
||||
import io.github.wulkanowy.MainCoroutineRule
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.pojos.RegisterStudent
|
||||
import io.github.wulkanowy.data.pojos.RegisterSymbol
|
||||
import io.github.wulkanowy.data.pojos.RegisterUnit
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.sdk.scrapper.Scrapper
|
||||
import io.github.wulkanowy.services.sync.SyncManager
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import io.mockk.*
|
||||
import io.mockk.impl.annotations.MockK
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.time.Instant
|
||||
|
||||
class LoginStudentSelectPresenterTest {
|
||||
|
||||
@ -22,7 +26,7 @@ class LoginStudentSelectPresenterTest {
|
||||
@MockK(relaxed = true)
|
||||
lateinit var errorHandler: LoginErrorHandler
|
||||
|
||||
@MockK(relaxed = true)
|
||||
@MockK
|
||||
lateinit var loginStudentSelectView: LoginStudentSelectView
|
||||
|
||||
@MockK
|
||||
@ -34,33 +38,55 @@ class LoginStudentSelectPresenterTest {
|
||||
@MockK(relaxed = true)
|
||||
lateinit var syncManager: SyncManager
|
||||
|
||||
private val appInfo = AppInfo()
|
||||
|
||||
private lateinit var presenter: LoginStudentSelectPresenter
|
||||
|
||||
private val testStudent by lazy {
|
||||
Student(
|
||||
email = "test",
|
||||
password = "test123",
|
||||
scrapperBaseUrl = "https://fakelog.cf",
|
||||
loginType = "AUTO",
|
||||
symbol = "",
|
||||
isCurrent = false,
|
||||
studentId = 0,
|
||||
schoolName = "",
|
||||
schoolSymbol = "",
|
||||
classId = 1,
|
||||
studentName = "",
|
||||
registrationDate = Instant.now(),
|
||||
className = "",
|
||||
loginMode = "",
|
||||
certificateKey = "",
|
||||
privateKey = "",
|
||||
mobileBaseUrl = "",
|
||||
schoolShortName = "",
|
||||
userLoginId = 1,
|
||||
isParent = false,
|
||||
userName = ""
|
||||
private val loginData = LoginData(
|
||||
login = "",
|
||||
password = "",
|
||||
baseUrl = "",
|
||||
symbol = null,
|
||||
)
|
||||
|
||||
private val subject = RegisterStudent(
|
||||
studentId = 0,
|
||||
studentName = "",
|
||||
studentSecondName = "",
|
||||
studentSurname = "",
|
||||
className = "",
|
||||
classId = 0,
|
||||
isParent = false,
|
||||
semesters = listOf(),
|
||||
)
|
||||
|
||||
private val school = RegisterUnit(
|
||||
userLoginId = 0,
|
||||
schoolId = "",
|
||||
schoolName = "",
|
||||
schoolShortName = "",
|
||||
parentIds = listOf(),
|
||||
studentIds = listOf(),
|
||||
employeeIds = listOf(),
|
||||
error = null,
|
||||
students = listOf(subject)
|
||||
)
|
||||
|
||||
private val symbol = RegisterSymbol(
|
||||
symbol = "",
|
||||
error = null,
|
||||
userName = "",
|
||||
schools = listOf(school),
|
||||
)
|
||||
|
||||
private val registerUser = RegisterUser(
|
||||
email = "",
|
||||
password = "",
|
||||
login = "",
|
||||
baseUrl = "",
|
||||
loginType = Scrapper.LoginType.AUTO,
|
||||
symbols = listOf(symbol),
|
||||
)
|
||||
}
|
||||
|
||||
private val testException by lazy { RuntimeException("Problem") }
|
||||
|
||||
@ -69,30 +95,44 @@ class LoginStudentSelectPresenterTest {
|
||||
MockKAnnotations.init(this)
|
||||
|
||||
clearMocks(studentRepository, loginStudentSelectView)
|
||||
|
||||
coEvery { studentRepository.getSavedStudents(false) } returns emptyList()
|
||||
|
||||
every { loginStudentSelectView.initView() } just Runs
|
||||
every { loginStudentSelectView.showContact(any()) } just Runs
|
||||
every { loginStudentSelectView.symbols } returns emptyMap()
|
||||
|
||||
every { loginStudentSelectView.enableSignIn(any()) } just Runs
|
||||
every { loginStudentSelectView.showProgress(any()) } just Runs
|
||||
every { loginStudentSelectView.showContent(any()) } just Runs
|
||||
|
||||
presenter = LoginStudentSelectPresenter(studentRepository, errorHandler, syncManager, analytics)
|
||||
presenter.onAttachView(loginStudentSelectView, emptyList())
|
||||
presenter = LoginStudentSelectPresenter(
|
||||
studentRepository = studentRepository,
|
||||
loginErrorHandler = errorHandler,
|
||||
syncManager = syncManager,
|
||||
analytics = analytics,
|
||||
appInfo = appInfo,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun initViewTest() {
|
||||
presenter.onAttachView(loginStudentSelectView, loginData, registerUser)
|
||||
verify { loginStudentSelectView.initView() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onSelectedStudentTest() {
|
||||
coEvery {
|
||||
studentRepository.saveStudents(listOf(StudentWithSemesters(testStudent, emptyList())))
|
||||
} just Runs
|
||||
val itemsSlot = slot<List<LoginStudentSelectItem>>()
|
||||
every { loginStudentSelectView.updateData(capture(itemsSlot)) } just Runs
|
||||
presenter.onAttachView(loginStudentSelectView, loginData, registerUser)
|
||||
|
||||
coEvery { studentRepository.saveStudents(any()) } just Runs
|
||||
|
||||
every { loginStudentSelectView.navigateToNext() } just Runs
|
||||
|
||||
presenter.onItemSelected(StudentWithSemesters(testStudent, emptyList()), false)
|
||||
itemsSlot.captured.filterIsInstance<LoginStudentSelectItem.Student>().first().let {
|
||||
it.onClick(it)
|
||||
}
|
||||
presenter.onSignIn()
|
||||
|
||||
verify { loginStudentSelectView.showContent(false) }
|
||||
@ -102,13 +142,15 @@ class LoginStudentSelectPresenterTest {
|
||||
|
||||
@Test
|
||||
fun onSelectedStudentErrorTest() {
|
||||
coEvery {
|
||||
studentRepository.saveStudents(listOf(StudentWithSemesters(testStudent, emptyList())))
|
||||
} throws testException
|
||||
val itemsSlot = slot<List<LoginStudentSelectItem>>()
|
||||
every { loginStudentSelectView.updateData(capture(itemsSlot)) } just Runs
|
||||
presenter.onAttachView(loginStudentSelectView, loginData, registerUser)
|
||||
|
||||
coEvery { studentRepository.logoutStudent(testStudent) } just Runs
|
||||
coEvery { studentRepository.saveStudents(any()) } throws testException
|
||||
|
||||
presenter.onItemSelected(StudentWithSemesters(testStudent, emptyList()), false)
|
||||
itemsSlot.captured.filterIsInstance<LoginStudentSelectItem.Student>().first().let {
|
||||
it.onClick(it)
|
||||
}
|
||||
presenter.onSignIn()
|
||||
|
||||
verify { loginStudentSelectView.showContent(false) }
|
||||
|
Loading…
x
Reference in New Issue
Block a user