Compare commits
19 Commits
bugfix/cla
...
2.6.6
Author | SHA1 | Date | |
---|---|---|---|
5ee7fee09d | |||
594d2dbec5 | |||
26596e8254 | |||
ff56348586 | |||
6e472d6c5c | |||
6f4826249c | |||
2f3e1b6aae | |||
a69361708e | |||
567d868f76 | |||
12030efee2 | |||
3cbe98d7b8 | |||
503a97bc4c | |||
04c382643d | |||
fc140ad9c1 | |||
ae6a35121b | |||
78a2cc89e9 | |||
558addd097 | |||
e8f9c57c34 | |||
4d67de8e5f |
@ -27,8 +27,8 @@ android {
|
||||
testApplicationId "io.github.tests.wulkanowy"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 34
|
||||
versionCode 161
|
||||
versionName "2.6.1"
|
||||
versionCode 166
|
||||
versionName "2.6.6"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
resValue "string", "app_name", "Wulkanowy"
|
||||
@ -160,7 +160,7 @@ play {
|
||||
defaultToAppBundles = false
|
||||
track = 'production'
|
||||
releaseStatus = ReleaseStatus.IN_PROGRESS
|
||||
userFraction = 0.25d
|
||||
userFraction = 0.99d
|
||||
updatePriority = 1
|
||||
enabled.set(false)
|
||||
}
|
||||
@ -191,7 +191,7 @@ ext {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'io.github.wulkanowy:sdk:2.6.0'
|
||||
implementation 'io.github.wulkanowy:sdk:2.6.5'
|
||||
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
|
||||
|
||||
|
@ -13,8 +13,8 @@ import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import io.github.wulkanowy.data.api.AdminMessageService
|
||||
import io.github.wulkanowy.data.api.SchoolsService
|
||||
import io.github.wulkanowy.data.api.services.SchoolsService
|
||||
import io.github.wulkanowy.data.api.services.WulkanowyService
|
||||
import io.github.wulkanowy.data.db.AppDatabase
|
||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
@ -71,7 +71,7 @@ internal class DataModule {
|
||||
okHttpClient: OkHttpClient,
|
||||
json: Json,
|
||||
appInfo: AppInfo
|
||||
): AdminMessageService = Retrofit.Builder()
|
||||
): WulkanowyService = Retrofit.Builder()
|
||||
.baseUrl(appInfo.messagesBaseUrl)
|
||||
.client(okHttpClient)
|
||||
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
|
||||
|
@ -5,6 +5,7 @@ import io.github.wulkanowy.data.db.dao.StudentDao
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.StudentIsEduOne
|
||||
import io.github.wulkanowy.data.repositories.WulkanowyRepository
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.RemoteConfigHelper
|
||||
import io.github.wulkanowy.utils.WebkitCookieManagerProxy
|
||||
@ -20,6 +21,7 @@ class WulkanowySdkFactory @Inject constructor(
|
||||
private val remoteConfig: RemoteConfigHelper,
|
||||
private val webkitCookieManagerProxy: WebkitCookieManagerProxy,
|
||||
private val studentDb: StudentDao,
|
||||
private val wulkanowyRepository: WulkanowyRepository,
|
||||
) {
|
||||
|
||||
private val eduOneMutex = Mutex()
|
||||
@ -36,14 +38,30 @@ class WulkanowySdkFactory @Inject constructor(
|
||||
addInterceptor(chuckerInterceptor, network = true)
|
||||
}
|
||||
|
||||
fun create() = sdk
|
||||
fun createBase() = sdk
|
||||
|
||||
suspend fun create(): Sdk {
|
||||
val mapping = wulkanowyRepository.getMapping()
|
||||
|
||||
return createBase().apply {
|
||||
if (mapping != null) {
|
||||
endpointsMapping = mapping.endpoints
|
||||
vTokenMapping = mapping.vTokens
|
||||
vTokenSchemeMapping = mapping.vTokenScheme
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun create(student: Student, semester: Semester? = null): Sdk {
|
||||
val overrideIsEduOne = checkEduOneAndMigrateIfNecessary(student)
|
||||
return buildSdk(student, semester, overrideIsEduOne)
|
||||
}
|
||||
|
||||
private fun buildSdk(student: Student, semester: Semester?, isStudentEduOne: Boolean): Sdk {
|
||||
private suspend fun buildSdk(
|
||||
student: Student,
|
||||
semester: Semester?,
|
||||
isStudentEduOne: Boolean
|
||||
): Sdk {
|
||||
return create().apply {
|
||||
email = student.email
|
||||
password = student.password
|
||||
|
@ -0,0 +1,17 @@
|
||||
package io.github.wulkanowy.data.api.models
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Mapping(
|
||||
|
||||
@SerialName("endpoints")
|
||||
val endpoints: Map<String, Map<String, Map<String, String>>>,
|
||||
|
||||
@SerialName("vTokens")
|
||||
val vTokens: Map<String, Map<String, Map<String, String>>>,
|
||||
|
||||
@SerialName("vTokenScheme")
|
||||
val vTokenScheme: Map<String, Map<String, String>> = emptyMap(),
|
||||
)
|
@ -1,4 +1,4 @@
|
||||
package io.github.wulkanowy.data.api
|
||||
package io.github.wulkanowy.data.api.services
|
||||
|
||||
import io.github.wulkanowy.data.pojos.IntegrityRequest
|
||||
import io.github.wulkanowy.data.pojos.LoginEvent
|
@ -1,12 +1,16 @@
|
||||
package io.github.wulkanowy.data.api
|
||||
package io.github.wulkanowy.data.api.services
|
||||
|
||||
import io.github.wulkanowy.data.api.models.Mapping
|
||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||
import retrofit2.http.GET
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
interface AdminMessageService {
|
||||
interface WulkanowyService {
|
||||
|
||||
@GET("/v1.json")
|
||||
suspend fun getAdminMessages(): List<AdminMessage>
|
||||
}
|
||||
|
||||
@GET("/mapping2.json")
|
||||
suspend fun getMapping(): Mapping
|
||||
}
|
@ -3,7 +3,6 @@ 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
|
||||
|
||||
@ -12,16 +11,5 @@ import javax.inject.Singleton
|
||||
interface SchoolDao : BaseDao<School> {
|
||||
|
||||
@Query("SELECT * FROM School WHERE student_id = :studentId AND class_id = :classId")
|
||||
fun loadWithClassId(studentId: Int, classId: Int): Flow<School?>
|
||||
|
||||
@Query("SELECT * FROM School WHERE student_id = :studentId")
|
||||
fun loadNoClassId(studentId: Int): Flow<School?>
|
||||
|
||||
fun load(student: Student): Flow<School?> {
|
||||
return if (student.isEduOne == true) {
|
||||
loadNoClassId(student.studentId)
|
||||
} else {
|
||||
loadWithClassId(student.studentId, student.classId)
|
||||
}
|
||||
}
|
||||
fun load(studentId: Int, classId: Int): Flow<School?>
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@ -15,17 +14,6 @@ interface SemesterDao : BaseDao<Semester> {
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
suspend fun insertSemesters(items: List<Semester>): List<Long>
|
||||
|
||||
@Query("SELECT * FROM Semesters WHERE (student_id = :studentId AND class_id = :classId)")
|
||||
suspend fun loadAllWithClassId(studentId: Int, classId: Int): List<Semester>
|
||||
|
||||
@Query("SELECT * FROM Semesters WHERE student_id = :studentId")
|
||||
suspend fun loadAllNoClassId(studentId: Int): List<Semester>
|
||||
|
||||
suspend fun loadAll(student: Student): List<Semester> {
|
||||
return if (student.isEduOne == true) {
|
||||
loadAllNoClassId(student.studentId)
|
||||
} else {
|
||||
loadAllWithClassId(student.studentId, student.classId)
|
||||
}
|
||||
}
|
||||
@Query("SELECT * FROM Semesters WHERE (student_id = :studentId AND class_id = :classId) OR (student_id = :studentId AND class_id = 0)")
|
||||
suspend fun loadAll(studentId: Int, classId: Int): List<Semester>
|
||||
}
|
||||
|
@ -47,9 +47,13 @@ abstract class StudentDao {
|
||||
abstract suspend fun loadAll(): List<Student>
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM Students JOIN Semesters ON (Students.student_id = Semesters.student_id AND Students.class_id = Semesters.class_id)")
|
||||
@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)")
|
||||
abstract suspend fun loadStudentsWithSemesters(): Map<Student, List<Semester>>
|
||||
|
||||
@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) WHERE Students.id = :id")
|
||||
abstract suspend fun loadStudentWithSemestersById(id: Long): Map<Student, List<Semester>>
|
||||
|
||||
@Query("UPDATE Students SET is_current = 1 WHERE id = :id")
|
||||
abstract suspend fun updateCurrent(id: Long)
|
||||
|
||||
|
@ -2,7 +2,6 @@ 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
|
||||
@ -12,16 +11,5 @@ import javax.inject.Singleton
|
||||
interface TeacherDao : BaseDao<Teacher> {
|
||||
|
||||
@Query("SELECT * FROM Teachers WHERE student_id = :studentId AND class_id = :classId")
|
||||
fun loadAllWithClassId(studentId: Int, classId: Int): Flow<List<Teacher>>
|
||||
|
||||
@Query("SELECT * FROM Teachers WHERE student_id = :studentId")
|
||||
fun loadAllNoClassId(studentId: Int): Flow<List<Teacher>>
|
||||
|
||||
fun loadAll(student: Student): Flow<List<Teacher>> {
|
||||
return if (student.isEduOne == true) {
|
||||
loadAllNoClassId(student.studentId)
|
||||
} else {
|
||||
loadAllWithClassId(student.studentId, student.classId)
|
||||
}
|
||||
}
|
||||
fun loadAll(studentId: Int, classId: Int): Flow<List<Teacher>>
|
||||
}
|
||||
|
@ -6,15 +6,6 @@ import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
class Migration63 : AutoMigrationSpec {
|
||||
|
||||
override fun onPostMigrate(db: SupportSQLiteDatabase) {
|
||||
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")
|
||||
db.execSQL("UPDATE Students SET is_edu_one = NULL WHERE is_edu_one = 0")
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
package io.github.wulkanowy.data.exceptions
|
||||
|
||||
class NoSuchStudentException(id: Long) :
|
||||
Exception("There is no student with id $id in database")
|
@ -9,6 +9,7 @@ import com.fredporciuncula.flow.preferences.Preference
|
||||
import com.fredporciuncula.flow.preferences.Serializer
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.api.models.Mapping
|
||||
import io.github.wulkanowy.data.enums.AppTheme
|
||||
import io.github.wulkanowy.data.enums.AttendanceCalculatorSortingMode
|
||||
import io.github.wulkanowy.data.enums.GradeColorTheme
|
||||
@ -375,6 +376,15 @@ class PreferencesRepository @Inject constructor(
|
||||
get() = sharedPref.getString(PREF_KEY_INSTALLATION_ID, null).orEmpty()
|
||||
private set(value) = sharedPref.edit { putString(PREF_KEY_INSTALLATION_ID, value) }
|
||||
|
||||
var mapping: Mapping?
|
||||
get() {
|
||||
val value = sharedPref.getString("mapping", null)
|
||||
return value?.let { json.decodeFromString(it) }
|
||||
}
|
||||
set(value) = sharedPref.edit(commit = true) {
|
||||
putString("mapping", value?.let { json.encodeToString(it) })
|
||||
}
|
||||
|
||||
init {
|
||||
if (installationId.isEmpty()) {
|
||||
installationId = UUID.randomUUID().toString()
|
||||
|
@ -36,7 +36,7 @@ class SchoolRepository @Inject constructor(
|
||||
)
|
||||
it == null || forceRefresh || isExpired
|
||||
},
|
||||
query = { schoolDb.load(student) },
|
||||
query = { schoolDb.load(semester.studentId, semester.classId) },
|
||||
fetch = {
|
||||
wulkanowySdkFactory.create(student, semester)
|
||||
.getSchool()
|
||||
|
@ -1,7 +1,7 @@
|
||||
package io.github.wulkanowy.data.repositories
|
||||
|
||||
import io.github.wulkanowy.data.WulkanowySdkFactory
|
||||
import io.github.wulkanowy.data.api.SchoolsService
|
||||
import io.github.wulkanowy.data.api.services.SchoolsService
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
|
@ -27,11 +27,11 @@ class SemesterRepository @Inject constructor(
|
||||
forceRefresh: Boolean = false,
|
||||
refreshOnNoCurrent: Boolean = false
|
||||
) = withContext(dispatchers.io) {
|
||||
val semesters = semesterDb.loadAll(student)
|
||||
val semesters = semesterDb.loadAll(student.studentId, student.classId)
|
||||
|
||||
if (isShouldFetch(student, semesters, forceRefresh, refreshOnNoCurrent)) {
|
||||
refreshSemesters(student)
|
||||
semesterDb.loadAll(student)
|
||||
semesterDb.loadAll(student.studentId, student.classId)
|
||||
} else semesters
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ class SemesterRepository @Inject constructor(
|
||||
return
|
||||
}
|
||||
|
||||
val old = semesterDb.loadAll(student)
|
||||
val old = semesterDb.loadAll(student.studentId, student.classId)
|
||||
semesterDb.removeOldAndSaveNew(
|
||||
oldItems = old uniqueSubtract new,
|
||||
newItems = new uniqueSubtract old,
|
||||
|
@ -12,7 +12,6 @@ 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
|
||||
@ -66,8 +65,7 @@ class StudentRepository @Inject constructor(
|
||||
.mapToPojo(password)
|
||||
.also { it.logErrors() }
|
||||
|
||||
@Deprecated("Semesters are not synced within this method and students with empty semesters are not returned")
|
||||
suspend fun getSavedStudentsWithSemesters(decryptPass: Boolean = true): List<StudentWithSemesters> {
|
||||
suspend fun getSavedStudents(decryptPass: Boolean = true): List<StudentWithSemesters> {
|
||||
return studentDb.loadStudentsWithSemesters().map { (student, semesters) ->
|
||||
StudentWithSemesters(
|
||||
student = student.apply {
|
||||
@ -82,25 +80,22 @@ class StudentRepository @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getSavedStudents(decryptPass: Boolean = true): List<Student> {
|
||||
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) {
|
||||
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) {
|
||||
scrambler.decrypt(student.password)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getStudentById(id: Long, decryptPass: Boolean = true): Student {
|
||||
val student = studentDb.loadById(id) ?: throw NoSuchStudentException(id)
|
||||
val student = studentDb.loadById(id) ?: throw NoCurrentStudentException()
|
||||
|
||||
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
|
||||
student.password = withContext(dispatchers.io) {
|
||||
@ -128,7 +123,7 @@ class StudentRepository @Inject constructor(
|
||||
return
|
||||
}
|
||||
|
||||
val currentStudentSemesters = semesterDb.loadAll(student)
|
||||
val currentStudentSemesters = semesterDb.loadAll(student.studentId, student.classId)
|
||||
if (currentStudentSemesters.isEmpty()) {
|
||||
Timber.d("Check isAuthorized: apply empty semesters workaround")
|
||||
semesterDb.insertSemesters(
|
||||
@ -186,8 +181,8 @@ class StudentRepository @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun switchStudent(student: Student) {
|
||||
studentDb.switchCurrent(student.id)
|
||||
suspend fun switchStudent(studentWithSemesters: StudentWithSemesters) {
|
||||
studentDb.switchCurrent(studentWithSemesters.student.id)
|
||||
}
|
||||
|
||||
suspend fun logoutStudent(student: Student) = studentDb.delete(student)
|
||||
@ -195,8 +190,8 @@ class StudentRepository @Inject constructor(
|
||||
suspend fun updateStudentNickAndAvatar(studentNickAndAvatar: StudentNickAndAvatar) =
|
||||
studentDb.update(studentNickAndAvatar)
|
||||
|
||||
suspend fun isOneUniqueStudent() = studentDb.loadAll()
|
||||
.distinctBy { it.studentName }.size == 1
|
||||
suspend fun isOneUniqueStudent() = getSavedStudents(false)
|
||||
.distinctBy { it.student.studentName }.size == 1
|
||||
|
||||
suspend fun authorizePermission(student: Student, semester: Semester, pesel: String) =
|
||||
wulkanowySdkFactory.create(student, semester)
|
||||
@ -204,7 +199,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
|
||||
|
||||
@ -214,7 +209,7 @@ class StudentRepository @Inject constructor(
|
||||
|
||||
studentDb.update(studentName)
|
||||
semesterDb.removeOldAndSaveNew(
|
||||
oldItems = semesterDb.loadAll(student),
|
||||
oldItems = semesterDb.loadAll(student.studentId, semester.classId),
|
||||
newItems = newCurrentApiStudent.semesters.mapToEntities(newCurrentApiStudent.studentId)
|
||||
)
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ class TeacherRepository @Inject constructor(
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||
it.isEmpty() || forceRefresh || isExpired
|
||||
},
|
||||
query = { teacherDb.loadAll(student) },
|
||||
query = { teacherDb.loadAll(semester.studentId, semester.classId) },
|
||||
fetch = {
|
||||
wulkanowySdkFactory.create(student, semester)
|
||||
.getTeachers()
|
||||
|
@ -1,20 +1,23 @@
|
||||
package io.github.wulkanowy.data.repositories
|
||||
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.api.AdminMessageService
|
||||
import io.github.wulkanowy.data.api.models.Mapping
|
||||
import io.github.wulkanowy.data.api.services.WulkanowyService
|
||||
import io.github.wulkanowy.data.db.dao.AdminMessageDao
|
||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filterNot
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class AdminMessageRepository @Inject constructor(
|
||||
private val adminMessageService: AdminMessageService,
|
||||
class WulkanowyRepository @Inject constructor(
|
||||
private val wulkanowyService: WulkanowyService,
|
||||
private val adminMessageDao: AdminMessageDao,
|
||||
private val preferencesRepository: PreferencesRepository,
|
||||
) {
|
||||
|
||||
private val saveFetchResultMutex = Mutex()
|
||||
@ -24,11 +27,28 @@ class AdminMessageRepository @Inject constructor(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { false },
|
||||
query = { adminMessageDao.loadAll() },
|
||||
fetch = { adminMessageService.getAdminMessages() },
|
||||
fetch = { wulkanowyService.getAdminMessages() },
|
||||
shouldFetch = { true },
|
||||
saveFetchResult = { oldItems, newItems ->
|
||||
adminMessageDao.removeOldAndSaveNew(oldItems, newItems)
|
||||
},
|
||||
)
|
||||
.filterNot { it is Resource.Intermediate }
|
||||
|
||||
suspend fun getMapping(): Mapping? {
|
||||
var savedMapping = preferencesRepository.mapping
|
||||
|
||||
if (savedMapping == null) {
|
||||
fetchMapping()
|
||||
savedMapping = preferencesRepository.mapping
|
||||
}
|
||||
|
||||
return savedMapping
|
||||
}
|
||||
|
||||
suspend fun fetchMapping() {
|
||||
runCatching { wulkanowyService.getMapping() }
|
||||
.onFailure { Timber.e(it) }
|
||||
.onSuccess { preferencesRepository.mapping = it }
|
||||
}
|
||||
}
|
@ -5,14 +5,14 @@ import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.enums.MessageType
|
||||
import io.github.wulkanowy.data.mapResourceData
|
||||
import io.github.wulkanowy.data.repositories.AdminMessageRepository
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.WulkanowyRepository
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import javax.inject.Inject
|
||||
|
||||
class GetAppropriateAdminMessageUseCase @Inject constructor(
|
||||
private val adminMessageRepository: AdminMessageRepository,
|
||||
private val wulkanowyRepository: WulkanowyRepository,
|
||||
private val preferencesRepository: PreferencesRepository,
|
||||
private val appInfo: AppInfo
|
||||
) {
|
||||
@ -22,7 +22,7 @@ class GetAppropriateAdminMessageUseCase @Inject constructor(
|
||||
}
|
||||
|
||||
operator fun invoke(scrapperBaseUrl: String, type: MessageType): Flow<Resource<AdminMessage?>> {
|
||||
return adminMessageRepository.getAdminMessages().mapResourceData { adminMessages ->
|
||||
return wulkanowyRepository.getAdminMessages().mapResourceData { adminMessages ->
|
||||
adminMessages
|
||||
.asSequence()
|
||||
.filter { it.isNotDismissed() }
|
||||
|
@ -59,7 +59,7 @@ class GetMailboxByStudentUseCase @Inject constructor(
|
||||
private fun String.getUnauthorizedVersion(): String {
|
||||
return normalizeStudentName().split(" ")
|
||||
.joinToString(" ") {
|
||||
it.first() + "*".repeat(it.length - 1)
|
||||
it.firstOrNull()?.toString().orEmpty() + "*".repeat((it.length - 1).coerceAtLeast(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ class AccountPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) }
|
||||
resourceFlow { studentRepository.getSavedStudents(false) }
|
||||
.logResourceStatus("load account data")
|
||||
.onResourceSuccess { view?.updateData(createAccountItems(it)) }
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
|
@ -1,15 +1,9 @@
|
||||
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
|
||||
@ -20,7 +14,6 @@ import javax.inject.Inject
|
||||
class AccountDetailsPresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val semeRepository: SemesterRepository,
|
||||
private val syncManager: SyncManager
|
||||
) : BasePresenter<AccountDetailsView>(errorHandler, studentRepository) {
|
||||
|
||||
@ -53,12 +46,7 @@ class AccountDetailsPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
resourceFlow {
|
||||
val student = studentRepository.getStudentById(studentId ?: -1)
|
||||
val semesters = semeRepository.getSemesters(student)
|
||||
|
||||
StudentWithSemesters(student, semesters)
|
||||
}
|
||||
resourceFlow { studentRepository.getSavedStudentById(studentId ?: -1) }
|
||||
.logResourceStatus("loading account details view")
|
||||
.onResourceLoading {
|
||||
view?.run {
|
||||
@ -97,7 +85,7 @@ class AccountDetailsPresenter @Inject constructor(
|
||||
|
||||
Timber.i("Select student ${studentWithSemesters!!.student.id}")
|
||||
|
||||
resourceFlow { studentRepository.switchStudent(studentWithSemesters!!.student) }
|
||||
resourceFlow { studentRepository.switchStudent(studentWithSemesters!!) }
|
||||
.logResourceStatus("change student")
|
||||
.onResourceSuccess { view?.recreateMainView() }
|
||||
.onResourceNotLoading { view?.popViewToMain() }
|
||||
@ -134,12 +122,10 @@ 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()
|
||||
|
@ -1,12 +1,8 @@
|
||||
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
|
||||
@ -44,7 +40,7 @@ class AccountQuickPresenter @Inject constructor(
|
||||
return
|
||||
}
|
||||
|
||||
resourceFlow { studentRepository.switchStudent(studentWithSemesters.student) }
|
||||
resourceFlow { studentRepository.switchStudent(studentWithSemesters) }
|
||||
.logResourceStatus("change student")
|
||||
.onResourceSuccess { view?.recreateMainView() }
|
||||
.onResourceNotLoading { view?.popView() }
|
||||
|
@ -59,7 +59,7 @@ class CaptchaDialog : BaseDialogFragment<DialogCaptchaBinding>() {
|
||||
webView = this
|
||||
with(settings) {
|
||||
javaScriptEnabled = true
|
||||
userAgentString = wulkanowySdkFactory.create().userAgent
|
||||
userAgentString = wulkanowySdkFactory.createBase().userAgent
|
||||
}
|
||||
|
||||
webViewClient = object : WebViewClient() {
|
||||
|
@ -118,5 +118,6 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
inAppUpdateHelper.onResume()
|
||||
presenter.updateSdkMappings()
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,15 @@
|
||||
package io.github.wulkanowy.ui.modules.login
|
||||
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.WulkanowyRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class LoginPresenter @Inject constructor(
|
||||
private val wulkanowyRepository: WulkanowyRepository,
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository
|
||||
) : BasePresenter<LoginView>(errorHandler, studentRepository) {
|
||||
@ -16,4 +19,11 @@ class LoginPresenter @Inject constructor(
|
||||
view.initView()
|
||||
Timber.i("Login view was initialized")
|
||||
}
|
||||
|
||||
fun updateSdkMappings() {
|
||||
presenterScope.launch {
|
||||
runCatching { wulkanowyRepository.fetchMapping() }
|
||||
.onFailure { Timber.e(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ class LoginStudentSelectPresenter @Inject constructor(
|
||||
private fun loadData() {
|
||||
resetSelectedState()
|
||||
|
||||
resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) }.onEach {
|
||||
resourceFlow { studentRepository.getSavedStudents(false) }.onEach {
|
||||
students = it.dataOrNull.orEmpty()
|
||||
when (it) {
|
||||
is Resource.Loading -> Timber.d("Login student select students load started")
|
||||
|
@ -35,7 +35,7 @@ class LuckyNumberWidgetConfigurePresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) }.onEach {
|
||||
resourceFlow { studentRepository.getSavedStudents(false) }.onEach {
|
||||
when (it) {
|
||||
is Resource.Loading -> Timber.d("Lucky number widget configure students data load")
|
||||
is Resource.Success -> {
|
||||
|
@ -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.id == studentId }
|
||||
val student = students.singleOrNull { it.student.id == studentId }?.student
|
||||
val currentStudent = when {
|
||||
student != null -> student
|
||||
studentId != 0L && studentRepository.isCurrentStudentSet() -> {
|
||||
|
@ -138,6 +138,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
inAppUpdateHelper.onResume()
|
||||
presenter.updateSdkMappings()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
|
@ -6,6 +6,7 @@ import io.github.wulkanowy.data.onResourceError
|
||||
import io.github.wulkanowy.data.onResourceSuccess
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.WulkanowyRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.services.sync.SyncManager
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
@ -29,6 +30,7 @@ class MainPresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val preferencesRepository: PreferencesRepository,
|
||||
private val wulkanowyRepository: WulkanowyRepository,
|
||||
private val syncManager: SyncManager,
|
||||
private val analytics: AnalyticsHelper,
|
||||
private val json: Json,
|
||||
@ -85,7 +87,7 @@ class MainPresenter @Inject constructor(
|
||||
return
|
||||
}
|
||||
|
||||
resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) }
|
||||
resourceFlow { studentRepository.getSavedStudents(false) }
|
||||
.logResourceStatus("load student avatar")
|
||||
.onResourceSuccess {
|
||||
studentsWitSemesters = it
|
||||
@ -199,4 +201,11 @@ class MainPresenter @Inject constructor(
|
||||
.onFailure { errorHandler.dispatch(it) }
|
||||
}
|
||||
}
|
||||
|
||||
fun updateSdkMappings() {
|
||||
presenterScope.launch {
|
||||
runCatching { wulkanowyRepository.fetchMapping() }
|
||||
.onFailure { Timber.e(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,24 +42,22 @@ class TimetableWidgetConfigurePresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
is Resource.Error -> errorHandler.dispatch(it.error)
|
||||
}
|
||||
}.launch()
|
||||
is Resource.Error -> errorHandler.dispatch(it.error)
|
||||
}
|
||||
}.launch()
|
||||
}
|
||||
|
||||
private fun registerStudent(student: Student?) {
|
||||
|
@ -95,7 +95,7 @@ class TimetableWidgetFactory(
|
||||
|
||||
private suspend fun getStudent(studentId: Long): Student? {
|
||||
val students = studentRepository.getSavedStudents()
|
||||
return students.singleOrNull { it.id == studentId }
|
||||
return students.singleOrNull { it.student.id == studentId }?.student
|
||||
}
|
||||
|
||||
private suspend fun getLessons(
|
||||
|
@ -2,11 +2,7 @@ package io.github.wulkanowy.ui.modules.timetablewidget
|
||||
|
||||
import android.app.PendingIntent
|
||||
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.appwidget.AppWidgetManager.*
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@ -26,14 +22,7 @@ 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.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 io.github.wulkanowy.utils.*
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
@ -255,7 +244,7 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
||||
|
||||
private suspend fun getStudent(studentId: Long, appWidgetId: Int) = try {
|
||||
val students = studentRepository.getSavedStudents(false)
|
||||
val student = students.singleOrNull { it.id == studentId }
|
||||
val student = students.singleOrNull { it.student.id == studentId }?.student
|
||||
when {
|
||||
student != null -> student
|
||||
studentId != 0L && studentRepository.isCurrentStudentSet() -> {
|
||||
@ -274,10 +263,7 @@ 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)
|
||||
|
@ -1,8 +1,5 @@
|
||||
Wersja 2.6.1
|
||||
Wersja 2.6.6
|
||||
|
||||
— dodaliśmy kalkulator frekwencji
|
||||
— dodaliśmy wyświetlanie lekcji dodatkowych w planie lekcji
|
||||
— ulepszyliśmy wyjaśnienie na ekranie z miejscem na wpisanie numeru PESEL
|
||||
— naprawiliśmy rzadkie sytuacje, gdy plan lekcji nakładał się na informację o jego braku
|
||||
— to tylko kolejna aktualizacja, która obchodzi blokadę firmy, której nazwy nie napiszemy. Pewnie zaraz znowu zostaniemy zablokowani, ale co tam
|
||||
|
||||
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
||||
|
@ -28,7 +28,7 @@
|
||||
<string name="student_info_title">Student info</string>
|
||||
<string name="dashboard_title">Dashboard</string>
|
||||
<string name="notifications_center_title">Notifications center</string>
|
||||
<string name="menu_order_title">Menu configuartion</string>
|
||||
<string name="menu_order_title">Menu configuration</string>
|
||||
|
||||
|
||||
<!--Subtitles-->
|
||||
|
@ -8,6 +8,7 @@ import io.mockk.mockk
|
||||
|
||||
fun createWulkanowySdkFactoryMock(sdk: Sdk) = mockk<WulkanowySdkFactory>()
|
||||
.apply {
|
||||
every { create() } returns sdk
|
||||
every { createBase() } returns sdk
|
||||
coEvery { create() } returns sdk
|
||||
coEvery { create(any(), any()) } returns sdk
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import io.github.wulkanowy.sdk.pojo.RegisterStudent
|
||||
import io.mockk.Runs
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.spyk
|
||||
@ -40,11 +39,12 @@ class WulkanowySdkFactoryTest {
|
||||
chuckerInterceptor = mockk(),
|
||||
remoteConfig = mockk(relaxed = true),
|
||||
webkitCookieManagerProxy = mockk(),
|
||||
studentDb = studentDao
|
||||
studentDb = studentDao,
|
||||
wulkanowyRepository = mockk(relaxed = true),
|
||||
)
|
||||
)
|
||||
|
||||
every { wulkanowySdkFactory.create() } returns sdk
|
||||
coEvery { wulkanowySdkFactory.create() } returns sdk
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1,161 +0,0 @@
|
||||
package io.github.wulkanowy.data.db.dao
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.room.Room
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import dagger.hilt.android.testing.HiltTestApplication
|
||||
import io.github.wulkanowy.data.db.AppDatabase
|
||||
import io.github.wulkanowy.getSemesterEntity
|
||||
import io.github.wulkanowy.getStudentEntity
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [Build.VERSION_CODES.O_MR1], application = HiltTestApplication::class)
|
||||
class StudentDaoTest {
|
||||
|
||||
private lateinit var studentDao: StudentDao
|
||||
private lateinit var semesterDao: SemesterDao
|
||||
private lateinit var db: AppDatabase
|
||||
|
||||
@Before
|
||||
fun createDb() {
|
||||
val context: Context = ApplicationProvider.getApplicationContext()
|
||||
db = Room.inMemoryDatabaseBuilder(
|
||||
context = context,
|
||||
klass = AppDatabase::class.java
|
||||
).build()
|
||||
studentDao = db.studentDao
|
||||
semesterDao = db.semesterDao
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get students associated with correct semester with same studentId`() = runTest {
|
||||
val notEduOneStudent = getStudentEntity()
|
||||
.copy(
|
||||
isEduOne = false,
|
||||
classId = 42,
|
||||
studentId = 100
|
||||
)
|
||||
.apply { id = 1 }
|
||||
val eduOneStudent = getStudentEntity()
|
||||
.copy(
|
||||
isEduOne = true,
|
||||
classId = 0,
|
||||
studentId = 100
|
||||
)
|
||||
.apply { id = 2 }
|
||||
|
||||
val semesterAssociatedWithNotEduOneStudent = getSemesterEntity()
|
||||
.copy(
|
||||
studentId = notEduOneStudent.studentId,
|
||||
classId = notEduOneStudent.classId,
|
||||
diaryId = 1 // make semester unique
|
||||
)
|
||||
.apply { id = 0 }
|
||||
val semesterAssociatedWithEduOneStudent = getSemesterEntity()
|
||||
.copy(
|
||||
studentId = eduOneStudent.studentId,
|
||||
classId = eduOneStudent.classId,
|
||||
diaryId = 2 // make semester unique
|
||||
)
|
||||
.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()
|
||||
)
|
||||
}
|
||||
|
||||
@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()
|
||||
}
|
||||
}
|
@ -12,7 +12,9 @@ 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)
|
||||
@ -20,10 +22,9 @@ import kotlin.test.assertNull
|
||||
class Migration63Test : AbstractMigrationTest() {
|
||||
|
||||
@Test
|
||||
fun `update is_edu_one to null`() = runTest {
|
||||
fun `update is_edu_one to null if 0`() = runTest {
|
||||
with(helper.createDatabase(dbName, 62)) {
|
||||
createStudent(1, 0)
|
||||
createStudent(2, 1)
|
||||
close()
|
||||
}
|
||||
|
||||
@ -31,15 +32,31 @@ class Migration63Test : AbstractMigrationTest() {
|
||||
|
||||
val database = getMigratedRoomDatabase()
|
||||
val studentDb = database.studentDao
|
||||
val student1 = studentDb.loadById(1)
|
||||
val student2 = studentDb.loadById(2)
|
||||
val student = studentDb.loadById(1)
|
||||
|
||||
assertNull(student1!!.isEduOne)
|
||||
assertNull(student2!!.isEduOne)
|
||||
assertNull(student!!.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")
|
||||
|
@ -50,7 +50,7 @@ class SemesterRepositoryTest {
|
||||
getSemesterPojo(1, 2, now().minusMonths(3), now())
|
||||
)
|
||||
|
||||
coEvery { semesterDb.loadAll(student) } returns emptyList()
|
||||
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns emptyList()
|
||||
coEvery { sdk.getSemesters() } returns semesters
|
||||
coEvery { semesterDb.removeOldAndSaveNew(any(), any()) } just Runs
|
||||
|
||||
@ -77,7 +77,10 @@ class SemesterRepositoryTest {
|
||||
)
|
||||
|
||||
coEvery {
|
||||
semesterDb.loadAll(student)
|
||||
semesterDb.loadAll(
|
||||
student.studentId,
|
||||
student.classId
|
||||
)
|
||||
} returns badSemesters.mapToEntities(student.studentId)
|
||||
coEvery { sdk.getSemesters() } returns goodSemesters
|
||||
coEvery { semesterDb.removeOldAndSaveNew(any(), any()) } just Runs
|
||||
@ -100,7 +103,7 @@ class SemesterRepositoryTest {
|
||||
getSemesterPojo(2, 3, now(), now().plusMonths(6)),
|
||||
)
|
||||
|
||||
coEvery { semesterDb.loadAll(any()) } returnsMany listOf(
|
||||
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returnsMany listOf(
|
||||
badSemesters.mapToEntities(student.studentId),
|
||||
badSemesters.mapToEntities(student.studentId),
|
||||
goodSemesters.mapToEntities(student.studentId)
|
||||
@ -122,7 +125,7 @@ class SemesterRepositoryTest {
|
||||
getSemesterEntity(1, 2, now().minusMonths(6), now().minusMonths(1))
|
||||
)
|
||||
|
||||
coEvery { semesterDb.loadAll(student) } returns semesters
|
||||
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns semesters
|
||||
|
||||
val items = runBlocking { semesterRepository.getSemesters(student) }
|
||||
assertEquals(2, items.size)
|
||||
@ -135,7 +138,7 @@ class SemesterRepositoryTest {
|
||||
getSemesterEntity(1, 2, now().minusMonths(3), now())
|
||||
)
|
||||
|
||||
coEvery { semesterDb.loadAll(student) } returns semesters
|
||||
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns semesters
|
||||
|
||||
val items = runBlocking { semesterRepository.getSemesters(student) }
|
||||
assertEquals(2, items.size)
|
||||
@ -148,7 +151,7 @@ class SemesterRepositoryTest {
|
||||
getSemesterEntity(1, 2, now(), now())
|
||||
)
|
||||
|
||||
coEvery { semesterDb.loadAll(student) } returns semesters
|
||||
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns semesters
|
||||
|
||||
val items = runBlocking { semesterRepository.getSemesters(student) }
|
||||
assertEquals(2, items.size)
|
||||
@ -161,7 +164,7 @@ class SemesterRepositoryTest {
|
||||
getSemesterPojo(1, 2, now().minusMonths(3), now())
|
||||
)
|
||||
|
||||
coEvery { semesterDb.loadAll(student) } returns emptyList()
|
||||
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns emptyList()
|
||||
coEvery { sdk.getSemesters() } returns semesters
|
||||
coEvery { semesterDb.removeOldAndSaveNew(any(), any()) } just Runs
|
||||
|
||||
@ -191,7 +194,10 @@ class SemesterRepositoryTest {
|
||||
)
|
||||
|
||||
coEvery {
|
||||
semesterDb.loadAll(student)
|
||||
semesterDb.loadAll(
|
||||
student.studentId,
|
||||
student.classId
|
||||
)
|
||||
} returns semestersWithNoCurrent
|
||||
coEvery { sdk.getSemesters() } returns newSemesters
|
||||
coEvery { semesterDb.removeOldAndSaveNew(any(), any()) } just Runs
|
||||
@ -208,7 +214,7 @@ class SemesterRepositoryTest {
|
||||
getSemesterEntity(1, 2, now().minusMonths(1), now().plusMonths(1))
|
||||
)
|
||||
|
||||
coEvery { semesterDb.loadAll(student) } returns semesters
|
||||
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns semesters
|
||||
|
||||
val items = semesterRepository.getSemesters(student, refreshOnNoCurrent = true)
|
||||
assertEquals(2, items.size)
|
||||
@ -221,14 +227,14 @@ class SemesterRepositoryTest {
|
||||
getSemesterEntity(1, 1, now(), now())
|
||||
)
|
||||
|
||||
coEvery { semesterDb.loadAll(student) } returns semesters
|
||||
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns semesters
|
||||
|
||||
runBlocking { semesterRepository.getCurrentSemester(student) }
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException::class)
|
||||
fun getCurrentSemester_emptyList() {
|
||||
coEvery { semesterDb.loadAll(student) } returns emptyList()
|
||||
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns emptyList()
|
||||
coEvery { sdk.getSemesters() } returns emptyList()
|
||||
|
||||
runBlocking { semesterRepository.getCurrentSemester(student) }
|
||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.main
|
||||
import io.github.wulkanowy.MainCoroutineRule
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.WulkanowyRepository
|
||||
import io.github.wulkanowy.services.sync.SyncManager
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AdsHelper
|
||||
@ -31,6 +32,9 @@ class MainPresenterTest {
|
||||
@MockK
|
||||
lateinit var studentRepository: StudentRepository
|
||||
|
||||
@MockK(relaxed = true)
|
||||
lateinit var wulkanowyRepository: WulkanowyRepository
|
||||
|
||||
@MockK(relaxed = true)
|
||||
lateinit var prefRepository: PreferencesRepository
|
||||
|
||||
@ -65,7 +69,8 @@ class MainPresenterTest {
|
||||
analytics = analytics,
|
||||
json = Json,
|
||||
appInfo = appInfo,
|
||||
adsHelper = adsHelper
|
||||
adsHelper = adsHelper,
|
||||
wulkanowyRepository = wulkanowyRepository
|
||||
)
|
||||
presenter.onAttachView(mainView, null)
|
||||
}
|
||||
|
Reference in New Issue
Block a user