From 157e04b239b669e56d291443f433669719079cde Mon Sep 17 00:00:00 2001 From: Faierbel Date: Sun, 21 Apr 2024 04:01:21 +0200 Subject: [PATCH] Add clearing all tables dependent on classId --- .../github/wulkanowy/data/db/dao/SchoolDao.kt | 14 ++++- .../wulkanowy/data/db/dao/SemesterDao.kt | 12 +++- .../wulkanowy/data/db/dao/StudentDao.kt | 6 +- .../wulkanowy/data/db/dao/TeacherDao.kt | 14 ++++- .../data/db/migrations/Migration63.kt | 11 +++- ...tudent.kt => NoCurrentStudentException.kt} | 0 .../data/exceptions/NoSuchStudentException.kt | 4 ++ .../data/repositories/SchoolRepository.kt | 2 +- .../data/repositories/StudentRepository.kt | 37 +++++++----- .../data/repositories/TeacherRepository.kt | 2 +- .../ui/modules/account/AccountPresenter.kt | 2 +- .../accountdetails/AccountDetailsPresenter.kt | 20 ++++++- .../accountquick/AccountQuickPresenter.kt | 8 ++- .../LoginStudentSelectPresenter.kt | 2 +- .../LuckyNumberWidgetConfigurePresenter.kt | 2 +- .../LuckyNumberWidgetProvider.kt | 2 +- .../ui/modules/main/MainPresenter.kt | 2 +- .../TimetableWidgetConfigurePresenter.kt | 30 +++++----- .../timetablewidget/TimetableWidgetFactory.kt | 2 +- .../TimetableWidgetProvider.kt | 22 +++++-- .../wulkanowy/data/db/dao/StudentDaoTest.kt | 60 ++++++++++++++++++- .../data/db/migrations/Migration63Test.kt | 29 ++------- .../repositories/SemesterRepositoryTest.kt | 8 ++- 23 files changed, 207 insertions(+), 84 deletions(-) rename app/src/main/java/io/github/wulkanowy/data/exceptions/{NoCurrentStudent.kt => NoCurrentStudentException.kt} (100%) create mode 100644 app/src/main/java/io/github/wulkanowy/data/exceptions/NoSuchStudentException.kt diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/SchoolDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/SchoolDao.kt index f39791f6..89def7cb 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/SchoolDao.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/SchoolDao.kt @@ -3,6 +3,7 @@ package io.github.wulkanowy.data.db.dao import androidx.room.Dao import androidx.room.Query import io.github.wulkanowy.data.db.entities.School +import io.github.wulkanowy.data.db.entities.Student import kotlinx.coroutines.flow.Flow import javax.inject.Singleton @@ -11,5 +12,16 @@ import javax.inject.Singleton interface SchoolDao : BaseDao { @Query("SELECT * FROM School WHERE student_id = :studentId AND class_id = :classId") - fun load(studentId: Int, classId: Int): Flow + fun loadWithClassId(studentId: Int, classId: Int): Flow + + @Query("SELECT * FROM School WHERE student_id = :studentId") + fun loadNoClassId(studentId: Int): Flow + + fun load(student: Student): Flow { + return if (student.isEduOne == true) { + loadNoClassId(student.studentId) + } else { + loadWithClassId(student.studentId, student.classId) + } + } } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/SemesterDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/SemesterDao.kt index aae6ca97..eef50bbf 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/SemesterDao.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/SemesterDao.kt @@ -16,10 +16,16 @@ interface SemesterDao : BaseDao { suspend fun insertSemesters(items: List): List @Query("SELECT * FROM Semesters WHERE (student_id = :studentId AND class_id = :classId)") - suspend fun loadAll(studentId: Int, classId: Int): List + suspend fun loadAllWithClassId(studentId: Int, classId: Int): List + + @Query("SELECT * FROM Semesters WHERE student_id = :studentId") + suspend fun loadAllNoClassId(studentId: Int): List suspend fun loadAll(student: Student): List { - val classId = if (student.isEduOne == true) 0 else student.classId - return loadAll(student.studentId, classId) + return if (student.isEduOne == true) { + loadAllNoClassId(student.studentId) + } else { + loadAllWithClassId(student.studentId, student.classId) + } } } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt index 07678c17..ec24be32 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt @@ -47,13 +47,9 @@ abstract class StudentDao { abstract suspend fun loadAll(): List @Transaction - @Query("SELECT * FROM Students JOIN Semesters ON (Students.student_id = Semesters.student_id AND Students.class_id = Semesters.class_id) OR (Students.student_id = Semesters.student_id AND Semesters.class_id = 0 AND Students.is_edu_one = 1)") + @Query("SELECT * FROM Students JOIN Semesters ON (Students.student_id = Semesters.student_id AND Students.class_id = Semesters.class_id)") abstract suspend fun loadStudentsWithSemesters(): Map> - @Transaction - @Query("SELECT * FROM Students JOIN Semesters ON (Students.student_id = Semesters.student_id AND Students.class_id = Semesters.class_id) OR (Students.student_id = Semesters.student_id AND Semesters.class_id = 0 AND Students.is_edu_one = 1) WHERE Students.id = :id") - abstract suspend fun loadStudentWithSemestersById(id: Long): Map> - @Query("UPDATE Students SET is_current = 1 WHERE id = :id") abstract suspend fun updateCurrent(id: Long) diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/TeacherDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/TeacherDao.kt index 6adac220..5485e87f 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/TeacherDao.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/TeacherDao.kt @@ -2,6 +2,7 @@ package io.github.wulkanowy.data.db.dao import androidx.room.Dao import androidx.room.Query +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Teacher import kotlinx.coroutines.flow.Flow import javax.inject.Singleton @@ -11,5 +12,16 @@ import javax.inject.Singleton interface TeacherDao : BaseDao { @Query("SELECT * FROM Teachers WHERE student_id = :studentId AND class_id = :classId") - fun loadAll(studentId: Int, classId: Int): Flow> + fun loadAllWithClassId(studentId: Int, classId: Int): Flow> + + @Query("SELECT * FROM Teachers WHERE student_id = :studentId") + fun loadAllNoClassId(studentId: Int): Flow> + + fun loadAll(student: Student): Flow> { + return if (student.isEduOne == true) { + loadAllNoClassId(student.studentId) + } else { + loadAllWithClassId(student.studentId, student.classId) + } + } } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration63.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration63.kt index f88d31fc..270a38fb 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration63.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration63.kt @@ -6,6 +6,15 @@ import androidx.sqlite.db.SupportSQLiteDatabase class Migration63 : AutoMigrationSpec { override fun onPostMigrate(db: SupportSQLiteDatabase) { - db.execSQL("UPDATE Students SET is_edu_one = NULL WHERE is_edu_one = 0") + db.execSQL("DROP TABLE IF EXISTS `Semesters`") + db.execSQL("DROP TABLE IF EXISTS `School`") + db.execSQL("DROP TABLE IF EXISTS `Teachers`") + + db.execSQL("CREATE TABLE IF NOT EXISTS `Semesters` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `kindergarten_diary_id` INTEGER NOT NULL DEFAULT 0, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL)") + db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id` ON `Semesters` (`student_id`, `diary_id`, `kindergarten_diary_id`, `semester_id`)") + db.execSQL("CREATE TABLE IF NOT EXISTS `School` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT NOT NULL, `contact` TEXT NOT NULL, `headmaster` TEXT NOT NULL, `pedagogue` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)") + db.execSQL("CREATE TABLE IF NOT EXISTS `Teachers` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)") + + db.execSQL("UPDATE Students SET is_edu_one = NULL") } } diff --git a/app/src/main/java/io/github/wulkanowy/data/exceptions/NoCurrentStudent.kt b/app/src/main/java/io/github/wulkanowy/data/exceptions/NoCurrentStudentException.kt similarity index 100% rename from app/src/main/java/io/github/wulkanowy/data/exceptions/NoCurrentStudent.kt rename to app/src/main/java/io/github/wulkanowy/data/exceptions/NoCurrentStudentException.kt diff --git a/app/src/main/java/io/github/wulkanowy/data/exceptions/NoSuchStudentException.kt b/app/src/main/java/io/github/wulkanowy/data/exceptions/NoSuchStudentException.kt new file mode 100644 index 00000000..072ab653 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/exceptions/NoSuchStudentException.kt @@ -0,0 +1,4 @@ +package io.github.wulkanowy.data.exceptions + +class NoSuchStudentException(id: Long) : + Exception("There is no student with id $id in database") diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolRepository.kt index c48abb6f..4317405b 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolRepository.kt @@ -36,7 +36,7 @@ class SchoolRepository @Inject constructor( ) it == null || forceRefresh || isExpired }, - query = { schoolDb.load(semester.studentId, semester.classId) }, + query = { schoolDb.load(student) }, fetch = { wulkanowySdkFactory.create(student, semester) .getSchool() diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt index c1d224a1..9cf021ba 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt @@ -12,6 +12,7 @@ import io.github.wulkanowy.data.db.entities.StudentName 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.exceptions.NoSuchStudentException import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToPojo import io.github.wulkanowy.data.pojos.RegisterUser @@ -65,7 +66,8 @@ class StudentRepository @Inject constructor( .mapToPojo(password) .also { it.logErrors() } - suspend fun getSavedStudents(decryptPass: Boolean = true): List { + @Deprecated("Semesters are not synced within this method and students with empty semesters are not returned") + suspend fun getSavedStudentsWithSemesters(decryptPass: Boolean = true): List { return studentDb.loadStudentsWithSemesters().map { (student, semesters) -> StudentWithSemesters( student = student.apply { @@ -80,22 +82,25 @@ class StudentRepository @Inject constructor( } } - suspend fun getSavedStudentById(id: Long, decryptPass: Boolean = true): StudentWithSemesters? = - studentDb.loadStudentWithSemestersById(id).let { res -> - StudentWithSemesters( - student = res.keys.firstOrNull() ?: return null, - semesters = res.values.first(), - ) - }.apply { - if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) { - student.password = withContext(dispatchers.io) { + suspend fun getSavedStudents(decryptPass: Boolean = true): List { + val students = studentDb.loadAll() + if (!decryptPass) return students + + return students.map { student -> + if (Sdk.Mode.valueOf(student.loginMode) == Sdk.Mode.HEBE) { + return@map student + } + + student.apply { + password = withContext(dispatchers.io) { scrambler.decrypt(student.password) } } } + } suspend fun getStudentById(id: Long, decryptPass: Boolean = true): Student { - val student = studentDb.loadById(id) ?: throw NoCurrentStudentException() + val student = studentDb.loadById(id) ?: throw NoSuchStudentException(id) if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) { student.password = withContext(dispatchers.io) { @@ -181,8 +186,8 @@ class StudentRepository @Inject constructor( } } - suspend fun switchStudent(studentWithSemesters: StudentWithSemesters) { - studentDb.switchCurrent(studentWithSemesters.student.id) + suspend fun switchStudent(student: Student) { + studentDb.switchCurrent(student.id) } suspend fun logoutStudent(student: Student) = studentDb.delete(student) @@ -190,8 +195,8 @@ class StudentRepository @Inject constructor( suspend fun updateStudentNickAndAvatar(studentNickAndAvatar: StudentNickAndAvatar) = studentDb.update(studentNickAndAvatar) - suspend fun isOneUniqueStudent() = getSavedStudents(false) - .distinctBy { it.student.studentName }.size == 1 + suspend fun isOneUniqueStudent() = studentDb.loadAll() + .distinctBy { it.studentName }.size == 1 suspend fun authorizePermission(student: Student, semester: Semester, pesel: String) = wulkanowySdkFactory.create(student, semester) @@ -199,7 +204,7 @@ class StudentRepository @Inject constructor( suspend fun refreshStudentAfterAuthorize(student: Student, semester: Semester) { val wulkanowySdk = wulkanowySdkFactory.create(student, semester) - val newCurrentApiStudent = runCatching { wulkanowySdk.getCurrentStudent() } + val newCurrentApiStudent = runCatching { wulkanowySdk.getCurrentStudent() } .onFailure { Timber.e(it, "Can't find student with id ${student.studentId}") } .getOrNull() ?: return diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/TeacherRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/TeacherRepository.kt index a5a6e3f9..ce8fbe4a 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/TeacherRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/TeacherRepository.kt @@ -35,7 +35,7 @@ class TeacherRepository @Inject constructor( val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, semester)) it.isEmpty() || forceRefresh || isExpired }, - query = { teacherDb.loadAll(semester.studentId, semester.classId) }, + query = { teacherDb.loadAll(student) }, fetch = { wulkanowySdkFactory.create(student, semester) .getTeachers() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt index 77c1ffe6..bd209735 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt @@ -33,7 +33,7 @@ class AccountPresenter @Inject constructor( } private fun loadData() { - resourceFlow { studentRepository.getSavedStudents(false) } + resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) } .logResourceStatus("load account data") .onResourceSuccess { view?.updateData(createAccountItems(it)) } .onResourceError(errorHandler::dispatch) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsPresenter.kt index 5d68ff2e..a3f6e0f0 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsPresenter.kt @@ -1,9 +1,15 @@ package io.github.wulkanowy.ui.modules.account.accountdetails -import io.github.wulkanowy.data.* import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.StudentWithSemesters +import io.github.wulkanowy.data.logResourceStatus +import io.github.wulkanowy.data.onResourceError +import io.github.wulkanowy.data.onResourceLoading +import io.github.wulkanowy.data.onResourceNotLoading +import io.github.wulkanowy.data.onResourceSuccess +import io.github.wulkanowy.data.repositories.SemesterRepository import io.github.wulkanowy.data.repositories.StudentRepository +import io.github.wulkanowy.data.resourceFlow import io.github.wulkanowy.services.sync.SyncManager import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler @@ -14,6 +20,7 @@ import javax.inject.Inject class AccountDetailsPresenter @Inject constructor( errorHandler: ErrorHandler, studentRepository: StudentRepository, + private val semeRepository: SemesterRepository, private val syncManager: SyncManager ) : BasePresenter(errorHandler, studentRepository) { @@ -46,7 +53,12 @@ class AccountDetailsPresenter @Inject constructor( } private fun loadData() { - resourceFlow { studentRepository.getSavedStudentById(studentId ?: -1) } + resourceFlow { + val student = studentRepository.getStudentById(studentId ?: -1) + val semesters = semeRepository.getSemesters(student) + + StudentWithSemesters(student, semesters) + } .logResourceStatus("loading account details view") .onResourceLoading { view?.run { @@ -85,7 +97,7 @@ class AccountDetailsPresenter @Inject constructor( Timber.i("Select student ${studentWithSemesters!!.student.id}") - resourceFlow { studentRepository.switchStudent(studentWithSemesters!!) } + resourceFlow { studentRepository.switchStudent(studentWithSemesters!!.student) } .logResourceStatus("change student") .onResourceSuccess { view?.recreateMainView() } .onResourceNotLoading { view?.popViewToMain() } @@ -122,10 +134,12 @@ class AccountDetailsPresenter @Inject constructor( syncManager.stopSyncWorker() openClearLoginView() } + studentWithSemesters?.student?.isCurrent == true -> { Timber.i("Logout result: Logout student and switch to another") recreateMainView() } + else -> { Timber.i("Logout result: Logout student") recreateMainView() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickPresenter.kt index 32c07f80..ca897991 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickPresenter.kt @@ -1,8 +1,12 @@ package io.github.wulkanowy.ui.modules.account.accountquick -import io.github.wulkanowy.data.* import io.github.wulkanowy.data.db.entities.StudentWithSemesters +import io.github.wulkanowy.data.logResourceStatus +import io.github.wulkanowy.data.onResourceError +import io.github.wulkanowy.data.onResourceNotLoading +import io.github.wulkanowy.data.onResourceSuccess import io.github.wulkanowy.data.repositories.StudentRepository +import io.github.wulkanowy.data.resourceFlow import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.ui.modules.account.AccountItem @@ -40,7 +44,7 @@ class AccountQuickPresenter @Inject constructor( return } - resourceFlow { studentRepository.switchStudent(studentWithSemesters) } + resourceFlow { studentRepository.switchStudent(studentWithSemesters.student) } .logResourceStatus("change student") .onResourceSuccess { view?.recreateMainView() } .onResourceNotLoading { view?.popView() } 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 34441418..7a7681f0 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 @@ -69,7 +69,7 @@ class LoginStudentSelectPresenter @Inject constructor( private fun loadData() { resetSelectedState() - resourceFlow { studentRepository.getSavedStudents(false) }.onEach { + resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) }.onEach { students = it.dataOrNull.orEmpty() when (it) { is Resource.Loading -> Timber.d("Login student select students load started") diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigurePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigurePresenter.kt index 7e53dad0..c91d23a7 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigurePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigurePresenter.kt @@ -35,7 +35,7 @@ class LuckyNumberWidgetConfigurePresenter @Inject constructor( } private fun loadData() { - resourceFlow { studentRepository.getSavedStudents(false) }.onEach { + resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) }.onEach { when (it) { is Resource.Loading -> Timber.d("Lucky number widget configure students data load") is Resource.Success -> { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetProvider.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetProvider.kt index e6de1781..9882f9b6 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetProvider.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetProvider.kt @@ -132,7 +132,7 @@ class LuckyNumberWidgetProvider : AppWidgetProvider() { private fun getLuckyNumber(studentId: Long, appWidgetId: Int) = runBlocking { try { val students = studentRepository.getSavedStudents() - val student = students.singleOrNull { it.student.id == studentId }?.student + val student = students.singleOrNull { it.id == studentId } val currentStudent = when { student != null -> student studentId != 0L && studentRepository.isCurrentStudentSet() -> { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt index a544381c..38a2320c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt @@ -85,7 +85,7 @@ class MainPresenter @Inject constructor( return } - resourceFlow { studentRepository.getSavedStudents(false) } + resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) } .logResourceStatus("load student avatar") .onResourceSuccess { studentsWitSemesters = it diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigurePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigurePresenter.kt index 87e89336..63291262 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigurePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigurePresenter.kt @@ -42,22 +42,24 @@ class TimetableWidgetConfigurePresenter @Inject constructor( } private fun loadData() { - resourceFlow { studentRepository.getSavedStudents(false) }.onEach { - when (it) { - is Resource.Loading -> Timber.d("Timetable widget configure students data load") - is Resource.Success -> { - val selectedStudentId = appWidgetId?.let { id -> - sharedPref.getLong(getStudentWidgetKey(id), 0) - } ?: -1 - when { - it.data.isEmpty() -> view?.openLoginView() - it.data.size == 1 && !isFromProvider -> onItemSelect(it.data.single().student) - else -> view?.updateData(it.data, selectedStudentId) + resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) } + .onEach { + when (it) { + is Resource.Loading -> Timber.d("Timetable widget configure students data load") + is Resource.Success -> { + val selectedStudentId = appWidgetId?.let { id -> + sharedPref.getLong(getStudentWidgetKey(id), 0) + } ?: -1 + when { + it.data.isEmpty() -> view?.openLoginView() + it.data.size == 1 && !isFromProvider -> onItemSelect(it.data.single().student) + else -> view?.updateData(it.data, selectedStudentId) + } } + + is Resource.Error -> errorHandler.dispatch(it.error) } - is Resource.Error -> errorHandler.dispatch(it.error) - } - }.launch() + }.launch() } private fun registerStudent(student: Student?) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetFactory.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetFactory.kt index e60d5488..7a95d100 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetFactory.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetFactory.kt @@ -95,7 +95,7 @@ class TimetableWidgetFactory( private suspend fun getStudent(studentId: Long): Student? { val students = studentRepository.getSavedStudents() - return students.singleOrNull { it.student.id == studentId }?.student + return students.singleOrNull { it.id == studentId } } private suspend fun getLessons( diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt index cc48539a..963ec4de 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt @@ -2,7 +2,11 @@ package io.github.wulkanowy.ui.modules.timetablewidget import android.app.PendingIntent import android.appwidget.AppWidgetManager -import android.appwidget.AppWidgetManager.* +import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_DELETED +import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE +import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID +import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS +import android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID import android.content.BroadcastReceiver import android.content.Context import android.content.Intent @@ -22,7 +26,14 @@ import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.services.widgets.TimetableWidgetService import io.github.wulkanowy.ui.modules.Destination import io.github.wulkanowy.ui.modules.splash.SplashActivity -import io.github.wulkanowy.utils.* +import io.github.wulkanowy.utils.AnalyticsHelper +import io.github.wulkanowy.utils.PendingIntentCompat +import io.github.wulkanowy.utils.capitalise +import io.github.wulkanowy.utils.nextOrSameSchoolDay +import io.github.wulkanowy.utils.nextSchoolDay +import io.github.wulkanowy.utils.nickOrName +import io.github.wulkanowy.utils.previousSchoolDay +import io.github.wulkanowy.utils.toFormattedString import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -244,7 +255,7 @@ class TimetableWidgetProvider : BroadcastReceiver() { private suspend fun getStudent(studentId: Long, appWidgetId: Int) = try { val students = studentRepository.getSavedStudents(false) - val student = students.singleOrNull { it.student.id == studentId }?.student + val student = students.singleOrNull { it.id == studentId } when { student != null -> student studentId != 0L && studentRepository.isCurrentStudentSet() -> { @@ -263,7 +274,10 @@ class TimetableWidgetProvider : BroadcastReceiver() { } private fun setupAccountView( - context: Context, student: Student, remoteViews: RemoteViews, widgetId: Int + context: Context, + student: Student, + remoteViews: RemoteViews, + widgetId: Int ) { val accountInitials = getAccountInitials(student.nickOrName) val accountPickerPendingIntent = createAccountPickerPendingIntent(context, widgetId) diff --git a/app/src/test/java/io/github/wulkanowy/data/db/dao/StudentDaoTest.kt b/app/src/test/java/io/github/wulkanowy/data/db/dao/StudentDaoTest.kt index 1a059070..ad828bb7 100644 --- a/app/src/test/java/io/github/wulkanowy/data/db/dao/StudentDaoTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/db/dao/StudentDaoTest.kt @@ -37,7 +37,7 @@ class StudentDaoTest { } @Test - fun `get students associated with correct semester`() = runTest { + fun `get students associated with correct semester with same studentId`() = runTest { val notEduOneStudent = getStudentEntity() .copy( isEduOne = false, @@ -96,6 +96,64 @@ class StudentDaoTest { ) } + @Test + fun `get students associated with correct semester with different studentId`() = runTest { + val notEduOneStudent = getStudentEntity() + .copy( + isEduOne = false, + classId = 42, + studentId = 100 + ) + .apply { id = 1 } + val eduOneStudent = getStudentEntity() + .copy( + isEduOne = true, + classId = 0, + studentId = 101 + ) + .apply { id = 2 } + + val semesterAssociatedWithNotEduOneStudent = getSemesterEntity() + .copy( + studentId = notEduOneStudent.studentId, + classId = notEduOneStudent.classId, + ) + .apply { id = 0 } + val semesterAssociatedWithEduOneStudent = getSemesterEntity() + .copy( + studentId = eduOneStudent.studentId, + classId = eduOneStudent.classId, + ) + .apply { id = 0 } + + studentDao.insertAll(listOf(notEduOneStudent, eduOneStudent)) + semesterDao.insertAll( + listOf( + semesterAssociatedWithNotEduOneStudent, + semesterAssociatedWithEduOneStudent + ) + ) + + val studentsWithSemesters = studentDao.loadStudentsWithSemesters() + val notEduOneSemestersResult = studentsWithSemesters.entries + .find { (student, _) -> student.id == notEduOneStudent.id } + ?.value + val eduOneSemestersResult = studentsWithSemesters.entries + .find { (student, _) -> student.id == eduOneStudent.id } + ?.value + + assertEquals(2, studentsWithSemesters.size) + + assertEquals(1, notEduOneSemestersResult?.size) + assertEquals(1, eduOneSemestersResult?.size) + + assertEquals(semesterAssociatedWithEduOneStudent, eduOneSemestersResult?.firstOrNull()) + assertEquals( + semesterAssociatedWithNotEduOneStudent, + notEduOneSemestersResult?.firstOrNull() + ) + } + @After fun closeDb() { db.close() diff --git a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration63Test.kt b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration63Test.kt index dcca9069..06528cfb 100644 --- a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration63Test.kt +++ b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration63Test.kt @@ -12,9 +12,7 @@ import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import kotlin.random.Random import kotlin.test.Test -import kotlin.test.assertNotNull import kotlin.test.assertNull -import kotlin.test.assertTrue @HiltAndroidTest @RunWith(RobolectricTestRunner::class) @@ -22,9 +20,10 @@ import kotlin.test.assertTrue class Migration63Test : AbstractMigrationTest() { @Test - fun `update is_edu_one to null if 0`() = runTest { + fun `update is_edu_one to null`() = runTest { with(helper.createDatabase(dbName, 62)) { createStudent(1, 0) + createStudent(2, 1) close() } @@ -32,31 +31,15 @@ class Migration63Test : AbstractMigrationTest() { val database = getMigratedRoomDatabase() val studentDb = database.studentDao - val student = studentDb.loadById(1) + val student1 = studentDb.loadById(1) + val student2 = studentDb.loadById(2) - assertNull(student!!.isEduOne) + assertNull(student1!!.isEduOne) + assertNull(student2!!.isEduOne) database.close() } - @Test - fun `check is_edu_one is stay same`() = runTest { - with(helper.createDatabase(dbName, 62)) { - createStudent(1, 1) - close() - } - - helper.runMigrationsAndValidate(dbName, 63, true) - - val database = getMigratedRoomDatabase() - val studentDb = database.studentDao - val student = studentDb.loadById(1) - - val isEduOne = assertNotNull(student!!.isEduOne) - assertTrue(isEduOne) - database.close() - } - private fun SupportSQLiteDatabase.createStudent(id: Long, isEduOneValue: Int) { insert("Students", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply { put("scrapper_base_url", "https://fakelog.cf") diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/SemesterRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/SemesterRepositoryTest.kt index 22712aae..2d15aa1a 100644 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/SemesterRepositoryTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/SemesterRepositoryTest.kt @@ -76,7 +76,9 @@ class SemesterRepositoryTest { getSemesterPojo(123, 2, now().minusMonths(3), now()) ) - coEvery { semesterDb.loadAll(student) } returns badSemesters.mapToEntities(student.studentId) + coEvery { + semesterDb.loadAll(student) + } returns badSemesters.mapToEntities(student.studentId) coEvery { sdk.getSemesters() } returns goodSemesters coEvery { semesterDb.removeOldAndSaveNew(any(), any()) } just Runs @@ -188,7 +190,9 @@ class SemesterRepositoryTest { getSemesterPojo(2, 2, now().plusMonths(5), now().plusMonths(11)), ) - coEvery { semesterDb.loadAll(student) } returns semestersWithNoCurrent + coEvery { + semesterDb.loadAll(student) + } returns semestersWithNoCurrent coEvery { sdk.getSemesters() } returns newSemesters coEvery { semesterDb.removeOldAndSaveNew(any(), any()) } just Runs