forked from github/wulkanowy-mirror
Display day header from website in timetable (#1269)
This commit is contained in:
parent
7bc5219d81
commit
aeb3b2a030
@ -160,7 +160,7 @@ ext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "io.github.wulkanowy:sdk:1.1.3"
|
implementation "io.github.wulkanowy:sdk:877b9135"
|
||||||
|
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||||
|
|
||||||
|
2204
app/schemas/io.github.wulkanowy.data.db.AppDatabase/37.json
Normal file
2204
app/schemas/io.github.wulkanowy.data.db.AppDatabase/37.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -181,4 +181,8 @@ internal class RepositoryModule {
|
|||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideStudentInfoDao(database: AppDatabase) = database.studentInfoDao
|
fun provideStudentInfoDao(database: AppDatabase) = database.studentInfoDao
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideTimetableHeaderDao(database: AppDatabase) = database.timetableHeaderDao
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import io.github.wulkanowy.data.db.dao.SubjectDao
|
|||||||
import io.github.wulkanowy.data.db.dao.TeacherDao
|
import io.github.wulkanowy.data.db.dao.TeacherDao
|
||||||
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
|
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
|
||||||
import io.github.wulkanowy.data.db.dao.TimetableDao
|
import io.github.wulkanowy.data.db.dao.TimetableDao
|
||||||
|
import io.github.wulkanowy.data.db.dao.TimetableHeaderDao
|
||||||
import io.github.wulkanowy.data.db.entities.Attendance
|
import io.github.wulkanowy.data.db.entities.Attendance
|
||||||
import io.github.wulkanowy.data.db.entities.AttendanceSummary
|
import io.github.wulkanowy.data.db.entities.AttendanceSummary
|
||||||
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
||||||
@ -58,6 +59,7 @@ import io.github.wulkanowy.data.db.entities.Subject
|
|||||||
import io.github.wulkanowy.data.db.entities.Teacher
|
import io.github.wulkanowy.data.db.entities.Teacher
|
||||||
import io.github.wulkanowy.data.db.entities.Timetable
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||||
|
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration10
|
import io.github.wulkanowy.data.db.migrations.Migration10
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration11
|
import io.github.wulkanowy.data.db.migrations.Migration11
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration12
|
import io.github.wulkanowy.data.db.migrations.Migration12
|
||||||
@ -87,6 +89,7 @@ import io.github.wulkanowy.data.db.migrations.Migration33
|
|||||||
import io.github.wulkanowy.data.db.migrations.Migration34
|
import io.github.wulkanowy.data.db.migrations.Migration34
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration35
|
import io.github.wulkanowy.data.db.migrations.Migration35
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration36
|
import io.github.wulkanowy.data.db.migrations.Migration36
|
||||||
|
import io.github.wulkanowy.data.db.migrations.Migration37
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration4
|
import io.github.wulkanowy.data.db.migrations.Migration4
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration5
|
import io.github.wulkanowy.data.db.migrations.Migration5
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration6
|
import io.github.wulkanowy.data.db.migrations.Migration6
|
||||||
@ -125,6 +128,7 @@ import javax.inject.Singleton
|
|||||||
Conference::class,
|
Conference::class,
|
||||||
TimetableAdditional::class,
|
TimetableAdditional::class,
|
||||||
StudentInfo::class,
|
StudentInfo::class,
|
||||||
|
TimetableHeader::class,
|
||||||
],
|
],
|
||||||
version = AppDatabase.VERSION_SCHEMA,
|
version = AppDatabase.VERSION_SCHEMA,
|
||||||
exportSchema = true
|
exportSchema = true
|
||||||
@ -133,7 +137,7 @@ import javax.inject.Singleton
|
|||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val VERSION_SCHEMA = 36
|
const val VERSION_SCHEMA = 37
|
||||||
|
|
||||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
||||||
Migration2(),
|
Migration2(),
|
||||||
@ -170,7 +174,8 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
Migration33(),
|
Migration33(),
|
||||||
Migration34(),
|
Migration34(),
|
||||||
Migration35(appInfo),
|
Migration35(appInfo),
|
||||||
Migration36()
|
Migration36(),
|
||||||
|
Migration37(),
|
||||||
)
|
)
|
||||||
|
|
||||||
fun newInstance(
|
fun newInstance(
|
||||||
@ -236,4 +241,6 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
abstract val timetableAdditionalDao: TimetableAdditionalDao
|
abstract val timetableAdditionalDao: TimetableAdditionalDao
|
||||||
|
|
||||||
abstract val studentInfoDao: StudentInfoDao
|
abstract val studentInfoDao: StudentInfoDao
|
||||||
|
|
||||||
|
abstract val timetableHeaderDao: TimetableHeaderDao
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package io.github.wulkanowy.data.db.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import java.time.LocalDate
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
@Singleton
|
||||||
|
interface TimetableHeaderDao : BaseDao<TimetableHeader> {
|
||||||
|
|
||||||
|
@Query("SELECT * FROM TimetableHeaders WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
|
||||||
|
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<TimetableHeader>>
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package io.github.wulkanowy.data.db.entities
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import java.io.Serializable
|
||||||
|
import java.time.LocalDate
|
||||||
|
|
||||||
|
@Entity(tableName = "TimetableHeaders")
|
||||||
|
data class TimetableHeader(
|
||||||
|
|
||||||
|
@ColumnInfo(name = "student_id")
|
||||||
|
val studentId: Int,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "diary_id")
|
||||||
|
val diaryId: Int,
|
||||||
|
|
||||||
|
val date: LocalDate,
|
||||||
|
|
||||||
|
val content: String,
|
||||||
|
) : Serializable {
|
||||||
|
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
var id: Long = 0
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration37 : Migration(36, 37) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS TimetableHeaders (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
student_id INTEGER NOT NULL,
|
||||||
|
diary_id INTEGER NOT NULL,
|
||||||
|
date INTEGER NOT NULL,
|
||||||
|
content TEXT NOT NULL
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -3,9 +3,19 @@ package io.github.wulkanowy.data.mappers
|
|||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Timetable
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||||
|
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
||||||
|
import io.github.wulkanowy.data.pojos.TimetableFull
|
||||||
|
import io.github.wulkanowy.sdk.pojo.TimetableFull as SdkTimetableFull
|
||||||
|
import io.github.wulkanowy.sdk.pojo.TimetableDayHeader as SdkTimetableHeader
|
||||||
import io.github.wulkanowy.sdk.pojo.Timetable as SdkTimetable
|
import io.github.wulkanowy.sdk.pojo.Timetable as SdkTimetable
|
||||||
import io.github.wulkanowy.sdk.pojo.TimetableAdditional as SdkTimetableAdditional
|
import io.github.wulkanowy.sdk.pojo.TimetableAdditional as SdkTimetableAdditional
|
||||||
|
|
||||||
|
fun SdkTimetableFull.mapToEntities(semester: Semester) = TimetableFull(
|
||||||
|
lessons = lessons.mapToEntities(semester),
|
||||||
|
additional = additional.mapToEntities(semester),
|
||||||
|
headers = headers.mapToEntities(semester)
|
||||||
|
)
|
||||||
|
|
||||||
fun List<SdkTimetable>.mapToEntities(semester: Semester) = map {
|
fun List<SdkTimetable>.mapToEntities(semester: Semester) = map {
|
||||||
Timetable(
|
Timetable(
|
||||||
studentId = semester.studentId,
|
studentId = semester.studentId,
|
||||||
@ -39,3 +49,13 @@ fun List<SdkTimetableAdditional>.mapToEntities(semester: Semester) = map {
|
|||||||
end = it.end
|
end = it.end
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmName("mapToEntitiesTimetableHeaders")
|
||||||
|
fun List<SdkTimetableHeader>.mapToEntities(semester: Semester) = map {
|
||||||
|
TimetableHeader(
|
||||||
|
studentId = semester.studentId,
|
||||||
|
diaryId = semester.diaryId,
|
||||||
|
date = it.date,
|
||||||
|
content = it.content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
package io.github.wulkanowy.data.pojos
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
|
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||||
|
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
||||||
|
|
||||||
|
data class TimetableFull(
|
||||||
|
val lessons: List<Timetable>,
|
||||||
|
val additional: List<TimetableAdditional>,
|
||||||
|
val headers: List<TimetableHeader>,
|
||||||
|
)
|
@ -2,11 +2,14 @@ package io.github.wulkanowy.data.repositories
|
|||||||
|
|
||||||
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
|
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
|
||||||
import io.github.wulkanowy.data.db.dao.TimetableDao
|
import io.github.wulkanowy.data.db.dao.TimetableDao
|
||||||
|
import io.github.wulkanowy.data.db.dao.TimetableHeaderDao
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.db.entities.Timetable
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||||
|
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
|
import io.github.wulkanowy.data.pojos.TimetableFull
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
|
import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
|
||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
@ -16,8 +19,8 @@ import io.github.wulkanowy.utils.monday
|
|||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
import io.github.wulkanowy.utils.sunday
|
import io.github.wulkanowy.utils.sunday
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -27,6 +30,7 @@ import javax.inject.Singleton
|
|||||||
class TimetableRepository @Inject constructor(
|
class TimetableRepository @Inject constructor(
|
||||||
private val timetableDb: TimetableDao,
|
private val timetableDb: TimetableDao,
|
||||||
private val timetableAdditionalDb: TimetableAdditionalDao,
|
private val timetableAdditionalDb: TimetableAdditionalDao,
|
||||||
|
private val timetableHeaderDb: TimetableHeaderDao,
|
||||||
private val sdk: Sdk,
|
private val sdk: Sdk,
|
||||||
private val schedulerHelper: TimetableNotificationSchedulerHelper,
|
private val schedulerHelper: TimetableNotificationSchedulerHelper,
|
||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
@ -36,53 +40,111 @@ class TimetableRepository @Inject constructor(
|
|||||||
|
|
||||||
private val cacheKey = "timetable"
|
private val cacheKey = "timetable"
|
||||||
|
|
||||||
fun getTimetable(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean, refreshAdditional: Boolean = false) = networkBoundResource(
|
fun getTimetable(
|
||||||
|
student: Student, semester: Semester, start: LocalDate, end: LocalDate,
|
||||||
|
forceRefresh: Boolean, refreshAdditional: Boolean = false
|
||||||
|
) = networkBoundResource(
|
||||||
mutex = saveFetchResultMutex,
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { (timetable, additional) -> timetable.isEmpty() || (additional.isEmpty() && refreshAdditional) || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
shouldFetch = { (timetable, additional, headers) ->
|
||||||
query = {
|
val refreshKey = getRefreshKey(cacheKey, semester, start, end)
|
||||||
timetableDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)
|
val isShouldRefresh = refreshHelper.isShouldBeRefreshed(refreshKey)
|
||||||
.map { schedulerHelper.scheduleNotifications(it, student); it }
|
val isRefreshAdditional = additional.isEmpty() && refreshAdditional
|
||||||
.combine(timetableAdditionalDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)) { timetable, additional ->
|
|
||||||
timetable to additional
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fetch = {
|
|
||||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
|
||||||
.getTimetable(start.monday, end.sunday)
|
|
||||||
.let { (normal, additional) -> normal.mapToEntities(semester) to additional.mapToEntities(semester) }
|
|
||||||
|
|
||||||
|
val isNoData = timetable.isEmpty() || isRefreshAdditional || headers.isEmpty()
|
||||||
|
|
||||||
|
isNoData || forceRefresh || isShouldRefresh
|
||||||
},
|
},
|
||||||
saveFetchResult = { (oldTimetable, oldAdditional), (newTimetable, newAdditional) ->
|
query = { getFullTimetableFromDatabase(student, semester, start, end) },
|
||||||
refreshTimetable(student, oldTimetable, newTimetable)
|
fetch = {
|
||||||
refreshAdditional(oldAdditional, newAdditional)
|
val timetableFull = sdk.init(student)
|
||||||
|
.switchDiary(semester.diaryId, semester.schoolYear)
|
||||||
|
.getTimetableFull(start.monday, end.sunday)
|
||||||
|
|
||||||
|
timetableFull.mapToEntities(semester)
|
||||||
|
},
|
||||||
|
saveFetchResult = { timetableOld, timetableNew ->
|
||||||
|
refreshTimetable(student, timetableOld.lessons, timetableNew.lessons)
|
||||||
|
refreshAdditional(timetableOld.additional, timetableNew.additional)
|
||||||
|
refreshDayHeaders(timetableOld.headers, timetableNew.headers)
|
||||||
|
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
|
||||||
},
|
},
|
||||||
filterResult = { (timetable, additional) ->
|
filterResult = { (timetable, additional, headers) ->
|
||||||
timetable.filter { item ->
|
TimetableFull(
|
||||||
item.date in start..end
|
lessons = timetable.filter { it.date in start..end },
|
||||||
} to additional.filter { item ->
|
additional = additional.filter { it.date in start..end },
|
||||||
item.date in start..end
|
headers = headers.filter { it.date in start..end }
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
private suspend fun refreshTimetable(student: Student, old: List<Timetable>, new: List<Timetable>) {
|
private fun getFullTimetableFromDatabase(
|
||||||
timetableDb.deleteAll(old.uniqueSubtract(new).also { schedulerHelper.cancelScheduled(it) })
|
student: Student, semester: Semester,
|
||||||
timetableDb.insertAll(new.uniqueSubtract(old).also { schedulerHelper.scheduleNotifications(it, student) }.map { item ->
|
start: LocalDate, end: LocalDate
|
||||||
item.also { new ->
|
): Flow<TimetableFull> {
|
||||||
old.singleOrNull { new.start == it.start }?.let { old ->
|
val timetableFlow = timetableDb.loadAll(
|
||||||
return@map new.copy(
|
diaryId = semester.diaryId,
|
||||||
room = if (new.room.isEmpty()) old.room else new.room,
|
studentId = semester.studentId,
|
||||||
teacher = if (new.teacher.isEmpty() && !new.changes && !old.changes) old.teacher else new.teacher
|
from = start.monday,
|
||||||
)
|
end = end.sunday
|
||||||
}
|
)
|
||||||
}
|
val headersFlow = timetableHeaderDb.loadAll(
|
||||||
})
|
diaryId = semester.diaryId,
|
||||||
|
studentId = semester.studentId,
|
||||||
|
from = start.monday,
|
||||||
|
end = end.sunday
|
||||||
|
)
|
||||||
|
val additionalFlow = timetableAdditionalDb.loadAll(
|
||||||
|
diaryId = semester.diaryId,
|
||||||
|
studentId = semester.studentId,
|
||||||
|
from = start.monday,
|
||||||
|
end = end.sunday
|
||||||
|
)
|
||||||
|
return combine(timetableFlow, headersFlow, additionalFlow) { lessons, headers, additional ->
|
||||||
|
schedulerHelper.scheduleNotifications(lessons, student)
|
||||||
|
|
||||||
|
TimetableFull(
|
||||||
|
lessons = lessons,
|
||||||
|
headers = headers,
|
||||||
|
additional = additional
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun refreshAdditional(old: List<TimetableAdditional>, new: List<TimetableAdditional>) {
|
private suspend fun refreshTimetable(
|
||||||
timetableAdditionalDb.deleteAll(old.uniqueSubtract(new))
|
student: Student,
|
||||||
timetableAdditionalDb.insertAll(new.uniqueSubtract(old))
|
lessonsOld: List<Timetable>, lessonsNew: List<Timetable>
|
||||||
|
) {
|
||||||
|
val lessonsToRemove = lessonsOld uniqueSubtract lessonsNew
|
||||||
|
val lessonsToAdd = (lessonsNew uniqueSubtract lessonsOld).map { new ->
|
||||||
|
val matchingOld = lessonsOld.singleOrNull { new.start == it.start }
|
||||||
|
if (matchingOld != null) {
|
||||||
|
val useOldTeacher = new.teacher.isEmpty() && !new.changes && !matchingOld.changes
|
||||||
|
new.copy(
|
||||||
|
room = if (new.room.isEmpty()) matchingOld.room else new.room,
|
||||||
|
teacher = if (useOldTeacher) matchingOld.teacher
|
||||||
|
else new.teacher
|
||||||
|
)
|
||||||
|
} else new
|
||||||
|
}
|
||||||
|
|
||||||
|
timetableDb.deleteAll(lessonsToRemove)
|
||||||
|
timetableDb.insertAll(lessonsToAdd)
|
||||||
|
|
||||||
|
schedulerHelper.cancelScheduled(lessonsToRemove, student)
|
||||||
|
schedulerHelper.scheduleNotifications(lessonsToAdd, student)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun refreshAdditional(
|
||||||
|
old: List<TimetableAdditional>,
|
||||||
|
new: List<TimetableAdditional>
|
||||||
|
) {
|
||||||
|
timetableAdditionalDb.deleteAll(old uniqueSubtract new)
|
||||||
|
timetableAdditionalDb.insertAll(new uniqueSubtract old)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun refreshDayHeaders(old: List<TimetableHeader>, new: List<TimetableHeader>) {
|
||||||
|
timetableHeaderDb.deleteAll(old uniqueSubtract new)
|
||||||
|
timetableHeaderDb.insertAll(new uniqueSubtract old)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,8 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
|
|||||||
lesson: Timetable
|
lesson: Timetable
|
||||||
) = day.getOrNull(index - 1)?.end ?: lesson.start.minusMinutes(30)
|
) = day.getOrNull(index - 1)?.end ?: lesson.start.minusMinutes(30)
|
||||||
|
|
||||||
suspend fun cancelScheduled(lessons: List<Timetable>, studentId: Int = 1) {
|
suspend fun cancelScheduled(lessons: List<Timetable>, student: Student) {
|
||||||
|
val studentId = student.studentId
|
||||||
withContext(dispatchersProvider.backgroundThread) {
|
withContext(dispatchersProvider.backgroundThread) {
|
||||||
lessons.sortedBy { it.start }.forEachIndexed { index, lesson ->
|
lessons.sortedBy { it.start }.forEachIndexed { index, lesson ->
|
||||||
val upcomingTime = getUpcomingLessonTime(index, lessons, lesson)
|
val upcomingTime = getUpcomingLessonTime(index, lessons, lesson)
|
||||||
@ -78,7 +79,7 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
|
|||||||
|
|
||||||
suspend fun scheduleNotifications(lessons: List<Timetable>, student: Student) {
|
suspend fun scheduleNotifications(lessons: List<Timetable>, student: Student) {
|
||||||
if (!preferencesRepository.isUpcomingLessonsNotificationsEnable) {
|
if (!preferencesRepository.isUpcomingLessonsNotificationsEnable) {
|
||||||
return cancelScheduled(lessons, student.studentId)
|
return cancelScheduled(lessons, student)
|
||||||
}
|
}
|
||||||
|
|
||||||
withContext(dispatchersProvider.backgroundThread) {
|
withContext(dispatchersProvider.backgroundThread) {
|
||||||
@ -89,7 +90,7 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
|
|||||||
val canceled = day.filter { it.canceled }
|
val canceled = day.filter { it.canceled }
|
||||||
val active = day.filter { !it.canceled }
|
val active = day.filter { !it.canceled }
|
||||||
|
|
||||||
cancelScheduled(canceled)
|
cancelScheduled(canceled, student)
|
||||||
active.forEachIndexed { index, lesson ->
|
active.forEachIndexed { index, lesson ->
|
||||||
val intent = createIntent(student, lesson, active.getOrNull(index + 1))
|
val intent = createIntent(student, lesson, active.getOrNull(index + 1))
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import android.view.MenuItem
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog
|
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
@ -71,7 +72,9 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
|
|||||||
with(binding) {
|
with(binding) {
|
||||||
timetableSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
|
timetableSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
|
||||||
timetableSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
|
timetableSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
|
||||||
timetableSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh))
|
timetableSwipe.setProgressBackgroundColorSchemeColor(
|
||||||
|
requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)
|
||||||
|
)
|
||||||
timetableErrorRetry.setOnClickListener { presenter.onRetry() }
|
timetableErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||||
timetableErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
timetableErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||||
|
|
||||||
@ -95,7 +98,12 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateData(data: List<Timetable>, showWholeClassPlanType: String, showGroupsInPlanType: Boolean, showTimetableTimers: Boolean) {
|
override fun updateData(
|
||||||
|
data: List<Timetable>,
|
||||||
|
showWholeClassPlanType: String,
|
||||||
|
showGroupsInPlanType: Boolean,
|
||||||
|
showTimetableTimers: Boolean
|
||||||
|
) {
|
||||||
with(timetableAdapter) {
|
with(timetableAdapter) {
|
||||||
items = data.toMutableList()
|
items = data.toMutableList()
|
||||||
showTimers = showTimetableTimers
|
showTimers = showTimetableTimers
|
||||||
@ -136,6 +144,13 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
|
|||||||
binding.timetableEmpty.visibility = if (show) VISIBLE else GONE
|
binding.timetableEmpty.visibility = if (show) VISIBLE else GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setDayHeaderMessage(message: String?) {
|
||||||
|
binding.timetableEmptyMessage.visibility = if (message.isNullOrEmpty()) GONE else VISIBLE
|
||||||
|
binding.timetableEmptyMessage.text = HtmlCompat.fromHtml(
|
||||||
|
message.orEmpty(), HtmlCompat.FROM_HTML_MODE_COMPACT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun showErrorView(show: Boolean) {
|
override fun showErrorView(show: Boolean) {
|
||||||
binding.timetableError.visibility = if (show) VISIBLE else GONE
|
binding.timetableError.visibility = if (show) VISIBLE else GONE
|
||||||
}
|
}
|
||||||
@ -172,8 +187,10 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
|
|||||||
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
|
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
|
||||||
presenter.onDateSet(year, month + 1, dayOfMonth)
|
presenter.onDateSet(year, month + 1, dayOfMonth)
|
||||||
}
|
}
|
||||||
val datePickerDialog = DatePickerDialog.newInstance(dateSetListener,
|
val datePickerDialog = DatePickerDialog.newInstance(
|
||||||
currentDate.year, currentDate.monthValue - 1, currentDate.dayOfMonth)
|
dateSetListener,
|
||||||
|
currentDate.year, currentDate.monthValue - 1, currentDate.dayOfMonth
|
||||||
|
)
|
||||||
|
|
||||||
with(datePickerDialog) {
|
with(datePickerDialog) {
|
||||||
setDateRangeLimiter(SchooldaysRangeLimiter())
|
setDateRangeLimiter(SchooldaysRangeLimiter())
|
||||||
|
@ -138,32 +138,37 @@ class TimetablePresenter @Inject constructor(
|
|||||||
flowWithResourceIn {
|
flowWithResourceIn {
|
||||||
val student = studentRepository.getCurrentStudent()
|
val student = studentRepository.getCurrentStudent()
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val semester = semesterRepository.getCurrentSemester(student)
|
||||||
timetableRepository.getTimetable(student, semester, currentDate, currentDate, forceRefresh)
|
timetableRepository.getTimetable(
|
||||||
|
student, semester, currentDate, currentDate, forceRefresh
|
||||||
|
)
|
||||||
}.onEach {
|
}.onEach {
|
||||||
when (it.status) {
|
when (it.status) {
|
||||||
Status.LOADING -> {
|
Status.LOADING -> {
|
||||||
if (!it.data?.first.isNullOrEmpty()) {
|
if (!it.data?.lessons.isNullOrEmpty()) {
|
||||||
view?.run {
|
view?.run {
|
||||||
enableSwipe(true)
|
enableSwipe(true)
|
||||||
showRefresh(true)
|
showRefresh(true)
|
||||||
showProgress(false)
|
showProgress(false)
|
||||||
showContent(true)
|
showContent(true)
|
||||||
updateData(it.data!!.first)
|
updateData(it.data!!.lessons)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Status.SUCCESS -> {
|
Status.SUCCESS -> {
|
||||||
Timber.i("Loading timetable result: Success")
|
Timber.i("Loading timetable result: Success")
|
||||||
view?.apply {
|
view?.apply {
|
||||||
updateData(it.data!!.first)
|
updateData(it.data!!.lessons)
|
||||||
showEmpty(it.data.first.isEmpty())
|
showEmpty(it.data.lessons.isEmpty())
|
||||||
|
setDayHeaderMessage(it.data.headers.singleOrNull { header ->
|
||||||
|
header.date == currentDate
|
||||||
|
}?.content)
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
showContent(it.data.first.isNotEmpty())
|
showContent(it.data.lessons.isNotEmpty())
|
||||||
}
|
}
|
||||||
analytics.logEvent(
|
analytics.logEvent(
|
||||||
"load_data",
|
"load_data",
|
||||||
"type" to "timetable",
|
"type" to "timetable",
|
||||||
"items" to it.data!!.first.size
|
"items" to it.data!!.lessons.size
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Status.ERROR -> {
|
Status.ERROR -> {
|
||||||
|
@ -24,6 +24,8 @@ interface TimetableView : BaseView {
|
|||||||
|
|
||||||
fun showEmpty(show: Boolean)
|
fun showEmpty(show: Boolean)
|
||||||
|
|
||||||
|
fun setDayHeaderMessage(message: String?)
|
||||||
|
|
||||||
fun showErrorView(show: Boolean)
|
fun showErrorView(show: Boolean)
|
||||||
|
|
||||||
fun setErrorDetails(message: String)
|
fun setErrorDetails(message: String)
|
||||||
|
@ -110,15 +110,15 @@ class AdditionalLessonsPresenter @Inject constructor(
|
|||||||
Status.SUCCESS -> {
|
Status.SUCCESS -> {
|
||||||
Timber.i("Loading additional lessons lessons result: Success")
|
Timber.i("Loading additional lessons lessons result: Success")
|
||||||
view?.apply {
|
view?.apply {
|
||||||
updateData(it.data!!.second.sortedBy { item -> item.date })
|
updateData(it.data!!.additional.sortedBy { item -> item.date })
|
||||||
showEmpty(it.data.second.isEmpty())
|
showEmpty(it.data.additional.isEmpty())
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
showContent(it.data.second.isNotEmpty())
|
showContent(it.data.additional.isNotEmpty())
|
||||||
}
|
}
|
||||||
analytics.logEvent(
|
analytics.logEvent(
|
||||||
"load_data",
|
"load_data",
|
||||||
"type" to "additional_lessons",
|
"type" to "additional_lessons",
|
||||||
"items" to it.data!!.second.size
|
"items" to it.data!!.additional.size
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Status.ERROR -> {
|
Status.ERROR -> {
|
||||||
|
@ -107,7 +107,7 @@ class TimetableWidgetFactory(
|
|||||||
|
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val semester = semesterRepository.getCurrentSemester(student)
|
||||||
timetableRepository.getTimetable(student, semester, date, date, false)
|
timetableRepository.getTimetable(student, semester, date, date, false)
|
||||||
.toFirstResult().data?.first.orEmpty()
|
.toFirstResult().data?.lessons.orEmpty()
|
||||||
.sortedWith(compareBy({ it.number }, { !it.isStudentPlan }))
|
.sortedWith(compareBy({ it.number }, { !it.isStudentPlan }))
|
||||||
.filter { if (prefRepository.showWholeClassPlan == "no") it.isStudentPlan else true }
|
.filter { if (prefRepository.showWholeClassPlan == "no") it.isStudentPlan else true }
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:indeterminate="true" />
|
android:indeterminate="true"
|
||||||
|
tools:visibility="gone" />
|
||||||
|
|
||||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
android:id="@+id/timetableSwipe"
|
android:id="@+id/timetableSwipe"
|
||||||
@ -26,7 +27,8 @@
|
|||||||
android:id="@+id/timetableRecycler"
|
android:id="@+id/timetableRecycler"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:listitem="@layout/item_timetable" />
|
tools:listitem="@layout/item_timetable"
|
||||||
|
tools:visibility="visible" />
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@ -53,6 +55,18 @@
|
|||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@string/timetable_no_items"
|
android:text="@string/timetable_no_items"
|
||||||
android:textSize="20sp" />
|
android:textSize="20sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/timetableEmptyMessage"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:lineSpacingMultiplier="1.2"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:maxLines="4"
|
||||||
|
tools:text="@tools:sample/lorem/random" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -121,7 +121,7 @@
|
|||||||
app:layout_constraintStart_toEndOf="@+id/timetableItemTeacher"
|
app:layout_constraintStart_toEndOf="@+id/timetableItemTeacher"
|
||||||
app:layout_constraintTop_toTopOf="@+id/timetableItemTimeFinish"
|
app:layout_constraintTop_toTopOf="@+id/timetableItemTimeFinish"
|
||||||
tools:text="Lekcja odwołana: uczniowie zwolnieni do domu"
|
tools:text="Lekcja odwołana: uczniowie zwolnieni do domu"
|
||||||
tools:visibility="visible" />
|
tools:visibility="gone" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Barrier
|
<androidx.constraintlayout.widget.Barrier
|
||||||
android:id="@+id/timetableItemTimeBarrier"
|
android:id="@+id/timetableItemTimeBarrier"
|
||||||
|
@ -2,10 +2,12 @@ package io.github.wulkanowy.data.repositories
|
|||||||
|
|
||||||
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
|
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
|
||||||
import io.github.wulkanowy.data.db.dao.TimetableDao
|
import io.github.wulkanowy.data.db.dao.TimetableDao
|
||||||
|
import io.github.wulkanowy.data.db.dao.TimetableHeaderDao
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
import io.github.wulkanowy.getSemesterEntity
|
import io.github.wulkanowy.getSemesterEntity
|
||||||
import io.github.wulkanowy.getStudentEntity
|
import io.github.wulkanowy.getStudentEntity
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
|
import io.github.wulkanowy.sdk.pojo.TimetableFull
|
||||||
import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
|
import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
|
||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
import io.github.wulkanowy.utils.toFirstResult
|
import io.github.wulkanowy.utils.toFirstResult
|
||||||
@ -41,6 +43,9 @@ class TimetableRepositoryTest {
|
|||||||
@MockK
|
@MockK
|
||||||
private lateinit var timetableAdditionalDao: TimetableAdditionalDao
|
private lateinit var timetableAdditionalDao: TimetableAdditionalDao
|
||||||
|
|
||||||
|
@MockK
|
||||||
|
private lateinit var timetableHeaderDao: TimetableHeaderDao
|
||||||
|
|
||||||
@MockK(relaxUnitFun = true)
|
@MockK(relaxUnitFun = true)
|
||||||
private lateinit var refreshHelper: AutoRefreshHelper
|
private lateinit var refreshHelper: AutoRefreshHelper
|
||||||
|
|
||||||
@ -59,7 +64,7 @@ class TimetableRepositoryTest {
|
|||||||
MockKAnnotations.init(this)
|
MockKAnnotations.init(this)
|
||||||
every { refreshHelper.isShouldBeRefreshed(any()) } returns false
|
every { refreshHelper.isShouldBeRefreshed(any()) } returns false
|
||||||
|
|
||||||
timetableRepository = TimetableRepository(timetableDb, timetableAdditionalDao, sdk, timetableNotificationSchedulerHelper, refreshHelper)
|
timetableRepository = TimetableRepository(timetableDb, timetableAdditionalDao, timetableHeaderDao, sdk, timetableNotificationSchedulerHelper, refreshHelper)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -71,7 +76,7 @@ class TimetableRepositoryTest {
|
|||||||
createTimetableRemote(of(2021, 1, 4, 9, 40), 3, "", "W-F"),
|
createTimetableRemote(of(2021, 1, 4, 9, 40), 3, "", "W-F"),
|
||||||
createTimetableRemote(of(2021, 1, 4, 10, 30), 4, "", "W-F")
|
createTimetableRemote(of(2021, 1, 4, 10, 30), 4, "", "W-F")
|
||||||
)
|
)
|
||||||
coEvery { sdk.getTimetable(any(), any()) } returns (remoteList to emptyList())
|
coEvery { sdk.getTimetableFull(any(), any()) } returns TimetableFull(emptyList(), remoteList, emptyList())
|
||||||
|
|
||||||
val localList = listOf(
|
val localList = listOf(
|
||||||
createTimetableRemote(of(2021, 1, 4, 8, 0), 1, "123", "Przyroda"),
|
createTimetableRemote(of(2021, 1, 4, 8, 0), 1, "123", "Przyroda"),
|
||||||
@ -87,13 +92,17 @@ class TimetableRepositoryTest {
|
|||||||
coEvery { timetableAdditionalDao.insertAll(emptyList()) } returns listOf(1, 2, 3)
|
coEvery { timetableAdditionalDao.insertAll(emptyList()) } returns listOf(1, 2, 3)
|
||||||
coEvery { timetableAdditionalDao.deleteAll(emptyList()) } just Runs
|
coEvery { timetableAdditionalDao.deleteAll(emptyList()) } just Runs
|
||||||
|
|
||||||
|
coEvery { timetableHeaderDao.loadAll(1, 1, startDate, endDate) } returns flowOf(listOf())
|
||||||
|
coEvery { timetableHeaderDao.insertAll(emptyList()) } returns listOf(1, 2, 3)
|
||||||
|
coEvery { timetableHeaderDao.deleteAll(emptyList()) } just Runs
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
val res = runBlocking {
|
val res = runBlocking {
|
||||||
timetableRepository.getTimetable(student, semester, startDate, endDate, true).toFirstResult()
|
timetableRepository.getTimetable(student, semester, startDate, endDate, true).toFirstResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
assertEquals(4, res.data?.first.orEmpty().size)
|
assertEquals(4, res.data?.lessons.orEmpty().size)
|
||||||
coVerify {
|
coVerify {
|
||||||
timetableDb.insertAll(withArg {
|
timetableDb.insertAll(withArg {
|
||||||
assertEquals(4, it.size)
|
assertEquals(4, it.size)
|
||||||
@ -124,7 +133,7 @@ class TimetableRepositoryTest {
|
|||||||
createTimetableRemote(of(2021, 1, 6, 9, 40), 3, "125", "Matematyka", "Paweł Środowski", false),
|
createTimetableRemote(of(2021, 1, 6, 9, 40), 3, "125", "Matematyka", "Paweł Środowski", false),
|
||||||
createTimetableRemote(of(2021, 1, 6, 10, 40), 4, "126", "Matematyka", "Paweł Czwartkowski", true)
|
createTimetableRemote(of(2021, 1, 6, 10, 40), 4, "126", "Matematyka", "Paweł Czwartkowski", true)
|
||||||
)
|
)
|
||||||
coEvery { sdk.getTimetable(startDate, endDate) } returns (remoteList to emptyList())
|
coEvery { sdk.getTimetableFull(startDate, endDate) } returns TimetableFull(emptyList(), remoteList, emptyList())
|
||||||
|
|
||||||
val localList = listOf(
|
val localList = listOf(
|
||||||
createTimetableRemote(of(2021, 1, 4, 8, 0), 1, "123", "Matematyka", "Paweł Poniedziałkowski", false),
|
createTimetableRemote(of(2021, 1, 4, 8, 0), 1, "123", "Matematyka", "Paweł Poniedziałkowski", false),
|
||||||
@ -150,12 +159,16 @@ class TimetableRepositoryTest {
|
|||||||
coEvery { timetableAdditionalDao.insertAll(emptyList()) } returns listOf(1, 2, 3)
|
coEvery { timetableAdditionalDao.insertAll(emptyList()) } returns listOf(1, 2, 3)
|
||||||
coEvery { timetableAdditionalDao.deleteAll(emptyList()) } just Runs
|
coEvery { timetableAdditionalDao.deleteAll(emptyList()) } just Runs
|
||||||
|
|
||||||
|
coEvery { timetableHeaderDao.loadAll(1, 1, startDate, endDate) } returns flowOf(listOf())
|
||||||
|
coEvery { timetableHeaderDao.insertAll(emptyList()) } returns listOf(1, 2, 3)
|
||||||
|
coEvery { timetableHeaderDao.deleteAll(emptyList()) } just Runs
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
val res = runBlocking { timetableRepository.getTimetable(student, semester, startDate, endDate, true).toFirstResult() }
|
val res = runBlocking { timetableRepository.getTimetable(student, semester, startDate, endDate, true).toFirstResult() }
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
assertEquals(null, res.error)
|
assertEquals(null, res.error)
|
||||||
assertEquals(12, res.data!!.first.size)
|
assertEquals(12, res.data!!.lessons.size)
|
||||||
|
|
||||||
coVerify {
|
coVerify {
|
||||||
timetableDb.insertAll(withArg {
|
timetableDb.insertAll(withArg {
|
||||||
@ -187,7 +200,7 @@ class TimetableRepositoryTest {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// prepare
|
// prepare
|
||||||
coEvery { sdk.getTimetable(startDate, endDate) } returns (remoteList to emptyList())
|
coEvery { sdk.getTimetableFull(startDate, endDate) } returns TimetableFull(emptyList(), remoteList, emptyList())
|
||||||
coEvery { timetableDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
coEvery { timetableDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
||||||
flowOf(remoteList.mapToEntities(semester)),
|
flowOf(remoteList.mapToEntities(semester)),
|
||||||
flowOf(remoteList.mapToEntities(semester))
|
flowOf(remoteList.mapToEntities(semester))
|
||||||
@ -199,13 +212,17 @@ class TimetableRepositoryTest {
|
|||||||
coEvery { timetableAdditionalDao.deleteAll(emptyList()) } just Runs
|
coEvery { timetableAdditionalDao.deleteAll(emptyList()) } just Runs
|
||||||
coEvery { timetableAdditionalDao.insertAll(emptyList()) } returns listOf(1, 2, 3)
|
coEvery { timetableAdditionalDao.insertAll(emptyList()) } returns listOf(1, 2, 3)
|
||||||
|
|
||||||
|
coEvery { timetableHeaderDao.loadAll(1, 1, startDate, endDate) } returns flowOf(listOf())
|
||||||
|
coEvery { timetableHeaderDao.insertAll(emptyList()) } returns listOf(1, 2, 3)
|
||||||
|
coEvery { timetableHeaderDao.deleteAll(emptyList()) } just Runs
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
val res = runBlocking { timetableRepository.getTimetable(student, semester, startDate, endDate, true).toFirstResult() }
|
val res = runBlocking { timetableRepository.getTimetable(student, semester, startDate, endDate, true).toFirstResult() }
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
assertEquals(null, res.error)
|
assertEquals(null, res.error)
|
||||||
assertEquals(2, res.data?.first?.size)
|
assertEquals(2, res.data?.lessons?.size)
|
||||||
coVerify { sdk.getTimetable(startDate, endDate) }
|
coVerify { sdk.getTimetableFull(startDate, endDate) }
|
||||||
coVerify { timetableDb.loadAll(1, 1, startDate, endDate) }
|
coVerify { timetableDb.loadAll(1, 1, startDate, endDate) }
|
||||||
coVerify { timetableDb.insertAll(match { it.isEmpty() }) }
|
coVerify { timetableDb.insertAll(match { it.isEmpty() }) }
|
||||||
coVerify { timetableDb.deleteAll(match { it.isEmpty() }) }
|
coVerify { timetableDb.deleteAll(match { it.isEmpty() }) }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user