Auto-refresh displayed data after some time (#1068)

* Auto-refresh displayed data after some time

* Use refresh interval from settings

* Auto-refresh exams

* Add refresh utils

* Auto-refresh timetable

* Auto-refresh grade details and summary

* Auto-refresh grades

* Auto-refresh attendance summary

* Add cacheKey variables

* Auto-refres completed lessons

* Auto-refres conferences

* Auto-refres homework

* Auto-refresh messages

* Auto-refresh mobile devices

* Auto-refresh notes

* Fix tests

* Fix instrumentation tests

* Create AutoRefreshHelper
This commit is contained in:
Mikołaj Pich 2021-01-13 11:01:45 +01:00 committed by GitHub
parent 64cc49055b
commit a1d4b3d19e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 558 additions and 183 deletions

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.db.migrations package io.github.wulkanowy.data.db.migrations
import android.content.Context
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.room.Room import androidx.room.Room
import androidx.room.testing.MigrationTestHelper import androidx.room.testing.MigrationTestHelper
@ -22,10 +23,11 @@ abstract class AbstractMigrationTest {
) )
fun getMigratedRoomDatabase(): AppDatabase { fun getMigratedRoomDatabase(): AppDatabase {
val context = ApplicationProvider.getApplicationContext<Context>()
val database = Room.databaseBuilder(ApplicationProvider.getApplicationContext(), val database = Room.databaseBuilder(ApplicationProvider.getApplicationContext(),
AppDatabase::class.java, dbName) AppDatabase::class.java, dbName)
.addMigrations(*AppDatabase.getMigrations(SharedPrefProvider(PreferenceManager .addMigrations(*AppDatabase.getMigrations(SharedPrefProvider(PreferenceManager
.getDefaultSharedPreferences(ApplicationProvider.getApplicationContext()))) .getDefaultSharedPreferences(context)))
) )
.build() .build()
// close the database and release any stream resources when the test finishes // close the database and release any stream resources when the test finishes

View File

@ -6,7 +6,9 @@ import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class SharedPrefProvider @Inject constructor(private val sharedPref: SharedPreferences) { class SharedPrefProvider @Inject constructor(
private val sharedPref: SharedPreferences
) {
companion object { companion object {
const val APP_VERSION_CODE_KEY = "app_version_code" const val APP_VERSION_CODE_KEY = "app_version_code"

View File

@ -12,5 +12,5 @@ import javax.inject.Singleton
interface CompletedLessonsDao : BaseDao<CompletedLesson> { interface CompletedLessonsDao : BaseDao<CompletedLesson> {
@Query("SELECT * FROM CompletedLesson WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end") @Query("SELECT * FROM CompletedLesson 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<CompletedLesson>> fun loadAll(studentId: Int, diaryId: Int, from: LocalDate, end: LocalDate): Flow<List<CompletedLesson>>
} }

View File

@ -7,6 +7,8 @@ import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Absent import io.github.wulkanowy.sdk.pojo.Absent
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
@ -21,11 +23,14 @@ import javax.inject.Singleton
@Singleton @Singleton
class AttendanceRepository @Inject constructor( class AttendanceRepository @Inject constructor(
private val attendanceDb: AttendanceDao, private val attendanceDb: AttendanceDao,
private val sdk: Sdk private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) { ) {
private val cacheKey = "attendance"
fun getAttendance(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource( fun getAttendance(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday) }, query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday) },
fetch = { fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
@ -35,6 +40,8 @@ class AttendanceRepository @Inject constructor(
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
attendanceDb.deleteAll(old uniqueSubtract new) attendanceDb.deleteAll(old uniqueSubtract new)
attendanceDb.insertAll(new uniqueSubtract old) attendanceDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
}, },
filterResult = { it.filter { item -> item.date in start..end } } filterResult = { it.filter { item -> item.date in start..end } }
) )

View File

@ -5,6 +5,8 @@ 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.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
@ -14,11 +16,14 @@ import javax.inject.Singleton
@Singleton @Singleton
class AttendanceSummaryRepository @Inject constructor( class AttendanceSummaryRepository @Inject constructor(
private val attendanceDb: AttendanceSummaryDao, private val attendanceDb: AttendanceSummaryDao,
private val sdk: Sdk private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) { ) {
private val cacheKey = "attendance_summary"
fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int, forceRefresh: Boolean) = networkBoundResource( fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId) }, query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId) },
fetch = { fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
@ -28,6 +33,7 @@ class AttendanceSummaryRepository @Inject constructor(
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
attendanceDb.deleteAll(old uniqueSubtract new) attendanceDb.deleteAll(old uniqueSubtract new)
attendanceDb.insertAll(new uniqueSubtract old) attendanceDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
} }
) )
} }

View File

@ -5,6 +5,8 @@ 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.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
@ -17,12 +19,15 @@ import javax.inject.Singleton
@Singleton @Singleton
class CompletedLessonsRepository @Inject constructor( class CompletedLessonsRepository @Inject constructor(
private val completedLessonsDb: CompletedLessonsDao, private val completedLessonsDb: CompletedLessonsDao,
private val sdk: Sdk private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) { ) {
private val cacheKey = "completed"
fun getCompletedLessons(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource( fun getCompletedLessons(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
query = { completedLessonsDb.loadAll(semester.diaryId, semester.studentId, start, end) }, query = { completedLessonsDb.loadAll(semester.studentId, semester.diaryId, start.monday, end.sunday) },
fetch = { fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getCompletedLessons(start.monday, end.sunday) .getCompletedLessons(start.monday, end.sunday)
@ -31,6 +36,7 @@ class CompletedLessonsRepository @Inject constructor(
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
completedLessonsDb.deleteAll(old uniqueSubtract new) completedLessonsDb.deleteAll(old uniqueSubtract new)
completedLessonsDb.insertAll(new uniqueSubtract old) completedLessonsDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
}, },
filterResult = { it.filter { item -> item.date in start..end } } filterResult = { it.filter { item -> item.date in start..end } }
) )

View File

@ -5,6 +5,8 @@ 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.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
@ -14,11 +16,14 @@ import javax.inject.Singleton
@Singleton @Singleton
class ConferenceRepository @Inject constructor( class ConferenceRepository @Inject constructor(
private val conferenceDb: ConferenceDao, private val conferenceDb: ConferenceDao,
private val sdk: Sdk private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) { ) {
private val cacheKey = "conference"
fun getConferences(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource( fun getConferences(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
query = { conferenceDb.loadAll(semester.diaryId, student.studentId) }, query = { conferenceDb.loadAll(semester.diaryId, student.studentId) },
fetch = { fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
@ -28,6 +33,7 @@ class ConferenceRepository @Inject constructor(
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
conferenceDb.deleteAll(old uniqueSubtract new) conferenceDb.deleteAll(old uniqueSubtract new)
conferenceDb.insertAll(new uniqueSubtract old) conferenceDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
} }
) )
} }

View File

@ -5,7 +5,9 @@ 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.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.endExamsDay import io.github.wulkanowy.utils.endExamsDay
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.startExamsDay import io.github.wulkanowy.utils.startExamsDay
@ -17,11 +19,14 @@ import javax.inject.Singleton
@Singleton @Singleton
class ExamRepository @Inject constructor( class ExamRepository @Inject constructor(
private val examDb: ExamDao, private val examDb: ExamDao,
private val sdk: Sdk private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) { ) {
private val cacheKey = "exam"
fun getExams(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource( fun getExams(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
query = { examDb.loadAll(semester.diaryId, semester.studentId, start.startExamsDay, start.endExamsDay) }, query = { examDb.loadAll(semester.diaryId, semester.studentId, start.startExamsDay, start.endExamsDay) },
fetch = { fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
@ -31,6 +36,7 @@ class ExamRepository @Inject constructor(
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
examDb.deleteAll(old uniqueSubtract new) examDb.deleteAll(old uniqueSubtract new)
examDb.insertAll(new uniqueSubtract old) examDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
}, },
filterResult = { it.filter { item -> item.date in start..end } } filterResult = { it.filter { item -> item.date in start..end } }
) )

View File

@ -8,6 +8,8 @@ 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.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
@ -22,11 +24,14 @@ import javax.inject.Singleton
class GradeRepository @Inject constructor( class GradeRepository @Inject constructor(
private val gradeDb: GradeDao, private val gradeDb: GradeDao,
private val gradeSummaryDb: GradeSummaryDao, private val gradeSummaryDb: GradeSummaryDao,
private val sdk: Sdk private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) { ) {
private val cacheKey = "grade"
fun getGrades(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource( fun getGrades(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
shouldFetch = { (details, summaries) -> details.isEmpty() || summaries.isEmpty() || forceRefresh }, shouldFetch = { (details, summaries) -> details.isEmpty() || summaries.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
query = { query = {
gradeDb.loadAll(semester.semesterId, semester.studentId).combine(gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)) { details, summaries -> gradeDb.loadAll(semester.semesterId, semester.studentId).combine(gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)) { details, summaries ->
details to summaries details to summaries
@ -42,6 +47,8 @@ class GradeRepository @Inject constructor(
saveFetchResult = { (oldDetails, oldSummary), (newDetails, newSummary) -> saveFetchResult = { (oldDetails, oldSummary), (newDetails, newSummary) ->
refreshGradeDetails(student, oldDetails, newDetails, notify) refreshGradeDetails(student, oldDetails, newDetails, notify)
refreshGradeSummaries(oldSummary, newSummary, notify) refreshGradeSummaries(oldSummary, newSummary, notify)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
} }
) )

View File

@ -12,6 +12,8 @@ import io.github.wulkanowy.data.mappers.mapPointsToStatisticsItems
import io.github.wulkanowy.data.mappers.mapSemesterToStatisticItems import io.github.wulkanowy.data.mappers.mapSemesterToStatisticItems
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
@ -24,11 +26,16 @@ class GradeStatisticsRepository @Inject constructor(
private val gradePartialStatisticsDb: GradePartialStatisticsDao, private val gradePartialStatisticsDb: GradePartialStatisticsDao,
private val gradePointsStatisticsDb: GradePointsStatisticsDao, private val gradePointsStatisticsDb: GradePointsStatisticsDao,
private val gradeSemesterStatisticsDb: GradeSemesterStatisticsDao, private val gradeSemesterStatisticsDb: GradeSemesterStatisticsDao,
private val sdk: Sdk private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) { ) {
private val partialCacheKey = "grade_stats_partial"
private val semesterCacheKey = "grade_stats_semester"
private val pointsCacheKey = "grade_stats_points"
fun getGradesPartialStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource( fun getGradesPartialStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(partialCacheKey, semester)) },
query = { gradePartialStatisticsDb.loadAll(semester.semesterId, semester.studentId) }, query = { gradePartialStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = { fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
@ -38,6 +45,7 @@ class GradeStatisticsRepository @Inject constructor(
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
gradePartialStatisticsDb.deleteAll(old uniqueSubtract new) gradePartialStatisticsDb.deleteAll(old uniqueSubtract new)
gradePartialStatisticsDb.insertAll(new uniqueSubtract old) gradePartialStatisticsDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(partialCacheKey, semester))
}, },
mapResult = { items -> mapResult = { items ->
when (subjectName) { when (subjectName) {
@ -63,7 +71,7 @@ class GradeStatisticsRepository @Inject constructor(
) )
fun getGradesSemesterStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource( fun getGradesSemesterStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(semesterCacheKey, semester)) },
query = { gradeSemesterStatisticsDb.loadAll(semester.semesterId, semester.studentId) }, query = { gradeSemesterStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = { fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
@ -73,6 +81,7 @@ class GradeStatisticsRepository @Inject constructor(
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
gradeSemesterStatisticsDb.deleteAll(old uniqueSubtract new) gradeSemesterStatisticsDb.deleteAll(old uniqueSubtract new)
gradeSemesterStatisticsDb.insertAll(new uniqueSubtract old) gradeSemesterStatisticsDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(semesterCacheKey, semester))
}, },
mapResult = { items -> mapResult = { items ->
val itemsWithAverage = items.map { item -> val itemsWithAverage = items.map { item ->
@ -103,7 +112,7 @@ class GradeStatisticsRepository @Inject constructor(
) )
fun getGradesPointsStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource( fun getGradesPointsStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(pointsCacheKey, semester)) },
query = { gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId) }, query = { gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = { fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
@ -113,6 +122,7 @@ class GradeStatisticsRepository @Inject constructor(
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
gradePointsStatisticsDb.deleteAll(old uniqueSubtract new) gradePointsStatisticsDb.deleteAll(old uniqueSubtract new)
gradePointsStatisticsDb.insertAll(new uniqueSubtract old) gradePointsStatisticsDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(pointsCacheKey, semester))
}, },
mapResult = { items -> mapResult = { items ->
when (subjectName) { when (subjectName) {

View File

@ -6,6 +6,8 @@ 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.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
@ -18,11 +20,14 @@ import javax.inject.Singleton
@Singleton @Singleton
class HomeworkRepository @Inject constructor( class HomeworkRepository @Inject constructor(
private val homeworkDb: HomeworkDao, private val homeworkDb: HomeworkDao,
private val sdk: Sdk private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) { ) {
private val cacheKey = "homework"
fun getHomework(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource( fun getHomework(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
query = { homeworkDb.loadAll(semester.semesterId, semester.studentId, start.monday, end.sunday) }, query = { homeworkDb.loadAll(semester.semesterId, semester.studentId, start.monday, end.sunday) },
fetch = { fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
@ -32,6 +37,8 @@ class HomeworkRepository @Inject constructor(
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
homeworkDb.deleteAll(old uniqueSubtract new) homeworkDb.deleteAll(old uniqueSubtract new)
homeworkDb.insertAll(new uniqueSubtract old) homeworkDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
} }
) )

View File

@ -6,13 +6,15 @@ import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.Recipient import io.github.wulkanowy.data.db.entities.Recipient
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.mappers.mapFromEntities
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.enums.MessageFolder import io.github.wulkanowy.data.enums.MessageFolder
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
import io.github.wulkanowy.data.mappers.mapFromEntities
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Folder import io.github.wulkanowy.sdk.pojo.Folder
import io.github.wulkanowy.sdk.pojo.SentMessage import io.github.wulkanowy.sdk.pojo.SentMessage
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
@ -27,12 +29,15 @@ import javax.inject.Singleton
class MessageRepository @Inject constructor( class MessageRepository @Inject constructor(
private val messagesDb: MessagesDao, private val messagesDb: MessagesDao,
private val messageAttachmentDao: MessageAttachmentDao, private val messageAttachmentDao: MessageAttachmentDao,
private val sdk: Sdk private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) { ) {
private val cacheKey = "message"
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
fun getMessages(student: Student, semester: Semester, folder: MessageFolder, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource( fun getMessages(student: Student, semester: Semester, folder: MessageFolder, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, student, folder)) },
query = { messagesDb.loadAll(student.id.toInt(), folder.id) }, query = { messagesDb.loadAll(student.id.toInt(), folder.id) },
fetch = { sdk.init(student).getMessages(Folder.valueOf(folder.name), now().minusMonths(3), now()).mapToEntities(student) }, fetch = { sdk.init(student).getMessages(Folder.valueOf(folder.name), now().minusMonths(3), now()).mapToEntities(student) },
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
@ -40,6 +45,8 @@ class MessageRepository @Inject constructor(
messagesDb.insertAll((new uniqueSubtract old).onEach { messagesDb.insertAll((new uniqueSubtract old).onEach {
it.isNotified = !notify it.isNotified = !notify
}) })
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student, folder))
} }
) )

View File

@ -8,6 +8,8 @@ import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.mappers.mapToMobileDeviceToken import io.github.wulkanowy.data.mappers.mapToMobileDeviceToken
import io.github.wulkanowy.data.pojos.MobileDeviceToken import io.github.wulkanowy.data.pojos.MobileDeviceToken
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
@ -17,11 +19,14 @@ import javax.inject.Singleton
@Singleton @Singleton
class MobileDeviceRepository @Inject constructor( class MobileDeviceRepository @Inject constructor(
private val mobileDb: MobileDeviceDao, private val mobileDb: MobileDeviceDao,
private val sdk: Sdk private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) { ) {
private val cacheKey = "devices"
fun getDevices(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource( fun getDevices(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, student)) },
query = { mobileDb.loadAll(semester.studentId) }, query = { mobileDb.loadAll(semester.studentId) },
fetch = { fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
@ -31,6 +36,8 @@ class MobileDeviceRepository @Inject constructor(
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
mobileDb.deleteAll(old uniqueSubtract new) mobileDb.deleteAll(old uniqueSubtract new)
mobileDb.insertAll(new uniqueSubtract old) mobileDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
} }
) )

View File

@ -6,6 +6,8 @@ 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.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
@ -17,11 +19,14 @@ import javax.inject.Singleton
@Singleton @Singleton
class NoteRepository @Inject constructor( class NoteRepository @Inject constructor(
private val noteDb: NoteDao, private val noteDb: NoteDao,
private val sdk: Sdk private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) { ) {
private val cacheKey = "note"
fun getNotes(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource( fun getNotes(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
query = { noteDb.loadAll(student.studentId) }, query = { noteDb.loadAll(student.studentId) },
fetch = { fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
@ -36,6 +41,8 @@ class NoteRepository @Inject constructor(
if (notify) isNotified = false if (notify) isNotified = false
} }
}) })
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
} }
) )

View File

@ -9,6 +9,8 @@ import io.github.wulkanowy.data.db.entities.TimetableAdditional
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
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.getRefreshKey
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
@ -25,11 +27,14 @@ class TimetableRepository @Inject constructor(
private val timetableDb: TimetableDao, private val timetableDb: TimetableDao,
private val timetableAdditionalDb: TimetableAdditionalDao, private val timetableAdditionalDb: TimetableAdditionalDao,
private val sdk: Sdk, private val sdk: Sdk,
private val schedulerHelper: TimetableNotificationSchedulerHelper private val schedulerHelper: TimetableNotificationSchedulerHelper,
private val refreshHelper: AutoRefreshHelper,
) { ) {
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(
shouldFetch = { (timetable, additional) -> timetable.isEmpty() || (additional.isEmpty() && refreshAdditional) || forceRefresh }, shouldFetch = { (timetable, additional) -> timetable.isEmpty() || (additional.isEmpty() && refreshAdditional) || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
query = { query = {
timetableDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday) timetableDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)
.map { schedulerHelper.scheduleNotifications(it, student); it } .map { schedulerHelper.scheduleNotifications(it, student); it }
@ -47,6 +52,7 @@ class TimetableRepository @Inject constructor(
refreshTimetable(student, oldTimetable, newTimetable) refreshTimetable(student, oldTimetable, newTimetable)
refreshAdditional(oldAdditional, newAdditional) refreshAdditional(oldAdditional, newAdditional)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
}, },
filterResult = { (timetable, additional) -> filterResult = { (timetable, additional) ->
timetable.filter { item -> timetable.filter { item ->

View File

@ -191,8 +191,8 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag
binding. attendanceRecycler.visibility = if (show) VISIBLE else GONE binding. attendanceRecycler.visibility = if (show) VISIBLE else GONE
} }
override fun hideRefresh() { override fun showRefresh(show: Boolean) {
binding.attendanceSwipe.isRefreshing = false binding.attendanceSwipe.isRefreshing = show
} }
override fun showPreButton(show: Boolean) { override fun showPreButton(show: Boolean) {

View File

@ -51,23 +51,23 @@ class AttendancePresenter @Inject constructor(
view.initView() view.initView()
Timber.i("Attendance view was initialized") Timber.i("Attendance view was initialized")
errorHandler.showErrorMessage = ::showErrorViewOnError errorHandler.showErrorMessage = ::showErrorViewOnError
loadData(ofEpochDay(date ?: baseDate.toEpochDay())) reloadView(ofEpochDay(date ?: baseDate.toEpochDay()))
loadData()
if (currentDate.isHolidays) setBaseDateOnHolidays() if (currentDate.isHolidays) setBaseDateOnHolidays()
reloadView()
} }
fun onPreviousDay() { fun onPreviousDay() {
view?.finishActionMode() view?.finishActionMode()
attendanceToExcuseList.clear() attendanceToExcuseList.clear()
loadData(currentDate.previousSchoolDay) reloadView(currentDate.previousSchoolDay)
reloadView() loadData()
} }
fun onNextDay() { fun onNextDay() {
view?.finishActionMode() view?.finishActionMode()
attendanceToExcuseList.clear() attendanceToExcuseList.clear()
loadData(currentDate.nextSchoolDay) reloadView(currentDate.nextSchoolDay)
reloadView() loadData()
} }
fun onPickDate() { fun onPickDate() {
@ -75,13 +75,13 @@ class AttendancePresenter @Inject constructor(
} }
fun onDateSet(year: Int, month: Int, day: Int) { fun onDateSet(year: Int, month: Int, day: Int) {
loadData(LocalDate.of(year, month, day)) reloadView(LocalDate.of(year, month, day))
reloadView() loadData()
} }
fun onSwipeRefresh() { fun onSwipeRefresh() {
Timber.i("Force refreshing the attendance") Timber.i("Force refreshing the attendance")
loadData(currentDate, true) loadData(true)
} }
fun onRetry() { fun onRetry() {
@ -89,7 +89,7 @@ class AttendancePresenter @Inject constructor(
showErrorView(false) showErrorView(false)
showProgress(true) showProgress(true)
} }
loadData(currentDate, true) loadData(true)
} }
fun onDetailsClick() { fun onDetailsClick() {
@ -102,8 +102,8 @@ class AttendancePresenter @Inject constructor(
if (view.currentStackSize == 1) { if (view.currentStackSize == 1) {
baseDate.also { baseDate.also {
if (currentDate != it) { if (currentDate != it) {
loadData(it) reloadView(it)
reloadView() loadData()
} else if (!view.isViewEmpty) view.resetView() } else if (!view.isViewEmpty) view.resetView()
} }
} else view.popView() } else view.popView()
@ -184,17 +184,27 @@ class AttendancePresenter @Inject constructor(
}.launch("holidays") }.launch("holidays")
} }
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) { private fun loadData(forceRefresh: Boolean = false) {
Timber.i("Loading attendance data started") Timber.i("Loading attendance data started")
currentDate = date
flowWithResourceIn { flowWithResourceIn {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
val semester = semesterRepository.getCurrentSemester(student) val semester = semesterRepository.getCurrentSemester(student)
attendanceRepository.getAttendance(student, semester, date, date, forceRefresh) attendanceRepository.getAttendance(student, semester, currentDate, currentDate, forceRefresh)
}.onEach { }.onEach {
when (it.status) { when (it.status) {
Status.LOADING -> view?.showExcuseButton(false) Status.LOADING -> {
view?.showExcuseButton(false)
if (!it.data.isNullOrEmpty()) {
view?.run {
enableSwipe(true)
showRefresh(true)
showProgress(false)
showContent(true)
updateData(it.data)
}
}
}
Status.SUCCESS -> { Status.SUCCESS -> {
Timber.i("Loading attendance result: Success") Timber.i("Loading attendance result: Success")
view?.apply { view?.apply {
@ -220,7 +230,7 @@ class AttendancePresenter @Inject constructor(
} }
}.afterLoading { }.afterLoading {
view?.run { view?.run {
hideRefresh() showRefresh(false)
showProgress(false) showProgress(false)
enableSwipe(true) enableSwipe(true)
} }
@ -250,12 +260,12 @@ class AttendancePresenter @Inject constructor(
showContent(true) showContent(true)
showProgress(false) showProgress(false)
} }
loadData(currentDate, forceRefresh = true) loadData(forceRefresh = true)
} }
Status.ERROR -> { Status.ERROR -> {
Timber.i("Excusing for absence result: An exception occurred") Timber.i("Excusing for absence result: An exception occurred")
errorHandler.dispatch(it.error!!) errorHandler.dispatch(it.error!!)
loadData(currentDate) loadData()
} }
} }
}.launch("excuse") }.launch("excuse")
@ -272,11 +282,14 @@ class AttendancePresenter @Inject constructor(
} }
} }
private fun reloadView() { private fun reloadView(date: LocalDate) {
currentDate = date
Timber.i("Reload attendance view with the date ${currentDate.toFormattedString()}") Timber.i("Reload attendance view with the date ${currentDate.toFormattedString()}")
view?.apply { view?.apply {
showProgress(true) showProgress(true)
enableSwipe(false) enableSwipe(false)
showRefresh(false)
showContent(false) showContent(false)
showEmpty(false) showEmpty(false)
showErrorView(false) showErrorView(false)

View File

@ -24,7 +24,7 @@ interface AttendanceView : BaseView {
fun clearData() fun clearData()
fun hideRefresh() fun showRefresh(show: Boolean)
fun resetView() fun resetView()

View File

@ -121,8 +121,8 @@ class AttendanceSummaryFragment :
binding.attendanceSummarySubjectsContainer.visibility = if (show) VISIBLE else INVISIBLE binding.attendanceSummarySubjectsContainer.visibility = if (show) VISIBLE else INVISIBLE
} }
override fun hideRefresh() { override fun showRefresh(show: Boolean) {
binding.attendanceSummarySwipe.isRefreshing = false binding.attendanceSummarySwipe.isRefreshing = show
} }
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.ui.modules.attendance.summary package io.github.wulkanowy.ui.modules.attendance.summary
import io.github.wulkanowy.data.Status import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.Subject import io.github.wulkanowy.data.db.entities.Subject
import io.github.wulkanowy.data.repositories.AttendanceSummaryRepository import io.github.wulkanowy.data.repositories.AttendanceSummaryRepository
import io.github.wulkanowy.data.repositories.SemesterRepository import io.github.wulkanowy.data.repositories.SemesterRepository
@ -74,6 +75,8 @@ class AttendanceSummaryPresenter @Inject constructor(
} }
private fun loadData(subjectId: Int, forceRefresh: Boolean = false) { private fun loadData(subjectId: Int, forceRefresh: Boolean = false) {
Timber.i("Loading attendance summary data started")
currentSubjectId = subjectId currentSubjectId = subjectId
flowWithResourceIn { flowWithResourceIn {
@ -82,15 +85,23 @@ class AttendanceSummaryPresenter @Inject constructor(
attendanceSummaryRepository.getAttendanceSummary(student, semester, subjectId, forceRefresh) attendanceSummaryRepository.getAttendanceSummary(student, semester, subjectId, forceRefresh)
}.onEach { }.onEach {
when (it.status) { when (it.status) {
Status.LOADING -> Timber.i("Loading attendance summary data started") Status.LOADING -> {
if (!it.data.isNullOrEmpty()) {
view?.run {
enableSwipe(true)
showRefresh(true)
showProgress(false)
showContent(true)
updateDataSet(sortItems(it.data))
}
}
}
Status.SUCCESS -> { Status.SUCCESS -> {
Timber.i("Loading attendance summary result: Success") Timber.i("Loading attendance summary result: Success")
view?.apply { view?.apply {
showEmpty(it.data!!.isEmpty()) showEmpty(it.data!!.isEmpty())
showContent(it.data.isNotEmpty()) showContent(it.data.isNotEmpty())
updateDataSet(it.data.sortedByDescending { item -> updateDataSet(sortItems(it.data))
if (item.month.value <= Month.JUNE.value) item.month.value + 12 else item.month.value
})
} }
analytics.logEvent( analytics.logEvent(
"load_data", "load_data",
@ -106,13 +117,17 @@ class AttendanceSummaryPresenter @Inject constructor(
} }
}.afterLoading { }.afterLoading {
view?.run { view?.run {
hideRefresh() showRefresh(false)
showProgress(false) showProgress(false)
enableSwipe(true) enableSwipe(true)
} }
}.launch() }.launch()
} }
private fun sortItems(items: List<AttendanceSummary>) = items.sortedByDescending { item ->
if (item.month.value <= Month.JUNE.value) item.month.value + 12 else item.month.value
}
private fun showErrorViewOnError(message: String, error: Throwable) { private fun showErrorViewOnError(message: String, error: Throwable) {
view?.run { view?.run {
if (isViewEmpty) { if (isViewEmpty) {

View File

@ -9,7 +9,7 @@ interface AttendanceSummaryView : BaseView {
fun initView() fun initView()
fun hideRefresh() fun showRefresh(show: Boolean)
fun showContent(show: Boolean) fun showContent(show: Boolean)

View File

@ -67,8 +67,8 @@ class ConferenceFragment : BaseFragment<FragmentConferenceBinding>(R.layout.frag
} }
} }
override fun hideRefresh() { override fun showRefresh(show: Boolean) {
binding.conferenceSwipe.isRefreshing = false binding.conferenceSwipe.isRefreshing = show
} }
override fun showProgress(show: Boolean) { override fun showProgress(show: Boolean) {

View File

@ -59,13 +59,25 @@ class ConferencePresenter @Inject constructor(
} }
private fun loadData(forceRefresh: Boolean = false) { private fun loadData(forceRefresh: Boolean = false) {
Timber.i("Loading conference data started")
flowWithResourceIn { flowWithResourceIn {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
val semester = semesterRepository.getCurrentSemester(student) val semester = semesterRepository.getCurrentSemester(student)
conferenceRepository.getConferences(student, semester, forceRefresh) conferenceRepository.getConferences(student, semester, forceRefresh)
}.onEach { }.onEach {
when (it.status) { when (it.status) {
Status.LOADING -> Timber.i("Loading conference data started") Status.LOADING -> {
if (!it.data.isNullOrEmpty()) {
view?.run {
enableSwipe(true)
showRefresh(true)
showProgress(false)
showContent(true)
updateData(it.data.sortedByDescending { conference -> conference.date })
}
}
}
Status.SUCCESS -> { Status.SUCCESS -> {
Timber.i("Loading conference result: Success") Timber.i("Loading conference result: Success")
view?.run { view?.run {
@ -87,7 +99,7 @@ class ConferencePresenter @Inject constructor(
} }
}.afterLoading { }.afterLoading {
view?.run { view?.run {
hideRefresh() showRefresh(false)
showProgress(false) showProgress(false)
enableSwipe(true) enableSwipe(true)
} }

View File

@ -13,7 +13,7 @@ interface ConferenceView : BaseView {
fun clearData() fun clearData()
fun hideRefresh() fun showRefresh(show: Boolean)
fun showEmpty(show: Boolean) fun showEmpty(show: Boolean)

View File

@ -65,8 +65,8 @@ class ExamFragment : BaseFragment<FragmentExamBinding>(R.layout.fragment_exam),
} }
} }
override fun hideRefresh() { override fun showRefresh(show: Boolean) {
binding.examSwipe.isRefreshing = false binding.examSwipe.isRefreshing = show
} }
override fun updateData(data: List<ExamItem<*>>) { override fun updateData(data: List<ExamItem<*>>) {

View File

@ -45,24 +45,24 @@ class ExamPresenter @Inject constructor(
view.initView() view.initView()
Timber.i("Exam view was initialized") Timber.i("Exam view was initialized")
errorHandler.showErrorMessage = ::showErrorViewOnError errorHandler.showErrorMessage = ::showErrorViewOnError
loadData(ofEpochDay(date ?: baseDate.toEpochDay())) reloadView(ofEpochDay(date ?: baseDate.toEpochDay()))
loadData()
if (currentDate.isHolidays) setBaseDateOnHolidays() if (currentDate.isHolidays) setBaseDateOnHolidays()
reloadView()
} }
fun onPreviousWeek() { fun onPreviousWeek() {
loadData(currentDate.minusDays(7)) reloadView(currentDate.minusDays(7))
reloadView() loadData()
} }
fun onNextWeek() { fun onNextWeek() {
loadData(currentDate.plusDays(7)) reloadView(currentDate.plusDays(7))
reloadView() loadData()
} }
fun onSwipeRefresh() { fun onSwipeRefresh() {
Timber.i("Force refreshing the exam") Timber.i("Force refreshing the exam")
loadData(currentDate, true) loadData(true)
} }
fun onRetry() { fun onRetry() {
@ -70,7 +70,7 @@ class ExamPresenter @Inject constructor(
showErrorView(false) showErrorView(false)
showProgress(true) showProgress(true)
} }
loadData(currentDate, true) loadData(true)
} }
fun onDetailsClick() { fun onDetailsClick() {
@ -86,8 +86,8 @@ class ExamPresenter @Inject constructor(
Timber.i("Exam view is reselected") Timber.i("Exam view is reselected")
baseDate.also { baseDate.also {
if (currentDate != it) { if (currentDate != it) {
loadData(it) reloadView(it)
reloadView() loadData()
} else if (view?.isViewEmpty == false) view?.resetView() } else if (view?.isViewEmpty == false) view?.resetView()
} }
} }
@ -105,8 +105,8 @@ class ExamPresenter @Inject constructor(
}.launch("holidays") }.launch("holidays")
} }
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) { private fun loadData(forceRefresh: Boolean = false) {
currentDate = date Timber.i("Loading exam data started")
flowWithResourceIn { flowWithResourceIn {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
@ -114,7 +114,17 @@ class ExamPresenter @Inject constructor(
examRepository.getExams(student, semester, currentDate.monday, currentDate.sunday, forceRefresh) examRepository.getExams(student, semester, currentDate.monday, currentDate.sunday, forceRefresh)
}.onEach { }.onEach {
when (it.status) { when (it.status) {
Status.LOADING -> Timber.i("Loading exam data started") Status.LOADING -> {
if (!it.data.isNullOrEmpty()) {
view?.run {
enableSwipe(true)
showRefresh(true)
showProgress(false)
showContent(true)
updateData(createExamItems(it.data))
}
}
}
Status.SUCCESS -> { Status.SUCCESS -> {
Timber.i("Loading exam result: Success") Timber.i("Loading exam result: Success")
view?.apply { view?.apply {
@ -136,7 +146,7 @@ class ExamPresenter @Inject constructor(
} }
}.afterLoading { }.afterLoading {
view?.run { view?.run {
hideRefresh() showRefresh(false)
showProgress(false) showProgress(false)
enableSwipe(true) enableSwipe(true)
} }
@ -162,7 +172,9 @@ class ExamPresenter @Inject constructor(
}.flatten() }.flatten()
} }
private fun reloadView() { private fun reloadView(date: LocalDate) {
currentDate = date
Timber.i("Reload exam view with the date ${currentDate.toFormattedString()}") Timber.i("Reload exam view with the date ${currentDate.toFormattedString()}")
view?.apply { view?.apply {
showProgress(true) showProgress(true)

View File

@ -15,7 +15,7 @@ interface ExamView : BaseView {
fun clearData() fun clearData()
fun hideRefresh() fun showRefresh(show: Boolean)
fun resetView() fun resetView()

View File

@ -137,15 +137,35 @@ class GradeDetailsPresenter @Inject constructor(
} }
private fun loadData(semesterId: Int, forceRefresh: Boolean) { private fun loadData(semesterId: Int, forceRefresh: Boolean) {
Timber.i("Loading grade details data started")
flowWithResourceIn { flowWithResourceIn {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
averageProvider.getGradesDetailsWithAverage(student, semesterId, forceRefresh) averageProvider.getGradesDetailsWithAverage(student, semesterId, forceRefresh)
}.onEach { }.onEach {
when (it.status) { when (it.status) {
Status.LOADING -> Timber.i("Loading grade details data started") Status.LOADING -> {
val items = createGradeItems(it.data.orEmpty())
if (items.isNotEmpty()) {
Timber.i("Loading gradle details result: load cached data")
view?.run {
updateNewGradesAmount(it.data.orEmpty())
enableSwipe(true)
showRefresh(true)
showProgress(false)
showContent(true)
updateData(
data = items,
isGradeExpandable = preferencesRepository.isGradeExpandable,
gradeColorTheme = preferencesRepository.gradeColorTheme
)
notifyParentDataLoaded(semesterId)
}
}
}
Status.SUCCESS -> { Status.SUCCESS -> {
Timber.i("Loading grade details result: Success") Timber.i("Loading grade details result: Success")
newGradesAmount = it.data!!.sumBy { item -> item.grades.sumBy { grade -> if (!grade.isRead) 1 else 0 } } updateNewGradesAmount(it.data!!)
updateMarkAsDoneButton() updateMarkAsDoneButton()
val items = createGradeItems(it.data) val items = createGradeItems(it.data)
view?.run { view?.run {
@ -179,6 +199,10 @@ class GradeDetailsPresenter @Inject constructor(
}.launch() }.launch()
} }
private fun updateNewGradesAmount(grades: List<GradeDetailsWithAverage>) {
newGradesAmount = grades.sumBy { item -> item.grades.sumBy { grade -> if (!grade.isRead) 1 else 0 } }
}
private fun showErrorViewOnError(message: String, error: Throwable) { private fun showErrorViewOnError(message: String, error: Throwable) {
view?.run { view?.run {
if (isViewEmpty) { if (isViewEmpty) {

View File

@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.grade.statistics
import io.github.wulkanowy.data.Status import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.db.entities.Subject import io.github.wulkanowy.data.db.entities.Subject
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
import io.github.wulkanowy.data.repositories.GradeStatisticsRepository import io.github.wulkanowy.data.repositories.GradeStatisticsRepository
import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.SemesterRepository import io.github.wulkanowy.data.repositories.SemesterRepository
@ -143,6 +144,8 @@ class GradeStatisticsPresenter @Inject constructor(
} }
private fun loadDataByType(semesterId: Int, subjectName: String, type: ViewType, forceRefresh: Boolean = false) { private fun loadDataByType(semesterId: Int, subjectName: String, type: ViewType, forceRefresh: Boolean = false) {
Timber.i("Loading grade stats data started")
currentSubjectName = if (preferencesRepository.showAllSubjectsOnStatisticsList) "Wszystkie" else subjectName currentSubjectName = if (preferencesRepository.showAllSubjectsOnStatisticsList) "Wszystkie" else subjectName
currentType = type currentType = type
@ -160,17 +163,24 @@ class GradeStatisticsPresenter @Inject constructor(
} }
}.onEach { }.onEach {
when (it.status) { when (it.status) {
Status.LOADING -> Timber.i("Loading grade stats data started") Status.LOADING -> {
val isNoContent = it.data == null || checkIsNoContent(it.data, type)
if (!isNoContent) {
view?.run {
showEmpty(isNoContent)
showContent(!isNoContent)
showErrorView(false)
enableSwipe(true)
showRefresh(true)
updateData(it.data!!, preferencesRepository.gradeColorTheme, preferencesRepository.showAllSubjectsOnStatisticsList)
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)
}
}
}
Status.SUCCESS -> { Status.SUCCESS -> {
Timber.i("Loading grade stats result: Success") Timber.i("Loading grade stats result: Success")
view?.run { view?.run {
val isNoContent = it.data!!.isEmpty() || when (type) { val isNoContent = checkIsNoContent(it.data!!, type)
ViewType.SEMESTER -> it.data.firstOrNull()?.semester?.amounts.orEmpty().sum() == 0
ViewType.PARTIAL -> it.data.firstOrNull()?.partial?.classAmounts.orEmpty().sum() == 0
ViewType.POINTS -> it.data.firstOrNull()?.points?.let { points ->
points.student == .0 && points.others == .0
} ?: false
}
showEmpty(isNoContent) showEmpty(isNoContent)
showContent(!isNoContent) showContent(!isNoContent)
showErrorView(false) showErrorView(false)
@ -198,6 +208,16 @@ class GradeStatisticsPresenter @Inject constructor(
}.launch("load") }.launch("load")
} }
private fun checkIsNoContent(items: List<GradeStatisticsItem>, type: ViewType): Boolean {
return items.isEmpty() || when (type) {
ViewType.SEMESTER -> items.firstOrNull()?.semester?.amounts.orEmpty().sum() == 0
ViewType.PARTIAL -> items.firstOrNull()?.partial?.classAmounts.orEmpty().sum() == 0
ViewType.POINTS -> items.firstOrNull()?.points?.let { points ->
points.student == .0 && points.others == .0
} ?: false
}
}
private fun showErrorViewOnError(message: String, error: Throwable) { private fun showErrorViewOnError(message: String, error: Throwable) {
view?.run { view?.run {
if (isViewEmpty) { if (isViewEmpty) {

View File

@ -37,12 +37,26 @@ class GradeSummaryPresenter @Inject constructor(
} }
private fun loadData(semesterId: Int, forceRefresh: Boolean) { private fun loadData(semesterId: Int, forceRefresh: Boolean) {
Timber.i("Loading grade summary started")
flowWithResourceIn { flowWithResourceIn {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
averageProvider.getGradesDetailsWithAverage(student, semesterId, forceRefresh) averageProvider.getGradesDetailsWithAverage(student, semesterId, forceRefresh)
}.onEach { }.onEach {
when (it.status) { when (it.status) {
Status.LOADING -> Timber.i("Loading grade summary started") Status.LOADING -> {
val items = createGradeSummaryItems(it.data.orEmpty())
if (items.isNotEmpty()) {
Timber.i("Loading grade summary result: load cached data")
view?.run {
enableSwipe(true)
showRefresh(true)
showProgress(false)
showContent(true)
updateData(items)
}
}
}
Status.SUCCESS -> { Status.SUCCESS -> {
Timber.i("Loading grade summary result: Success") Timber.i("Loading grade summary result: Success")
val items = createGradeSummaryItems(it.data!!) val items = createGradeSummaryItems(it.data!!)

View File

@ -83,8 +83,8 @@ class HomeworkFragment : BaseFragment<FragmentHomeworkBinding>(R.layout.fragment
binding.homeworkNavDate.text = date binding.homeworkNavDate.text = date
} }
override fun hideRefresh() { override fun showRefresh(show: Boolean) {
binding.homeworkSwipe.isRefreshing = false binding.homeworkSwipe.isRefreshing = show
} }
override fun showEmpty(show: Boolean) { override fun showEmpty(show: Boolean) {

View File

@ -44,24 +44,24 @@ class HomeworkPresenter @Inject constructor(
view.initView() view.initView()
Timber.i("Homework view was initialized") Timber.i("Homework view was initialized")
errorHandler.showErrorMessage = ::showErrorViewOnError errorHandler.showErrorMessage = ::showErrorViewOnError
loadData(ofEpochDay(date ?: baseDate.toEpochDay())) reloadView(ofEpochDay(date ?: baseDate.toEpochDay()))
loadData()
if (currentDate.isHolidays) setBaseDateOnHolidays() if (currentDate.isHolidays) setBaseDateOnHolidays()
reloadView()
} }
fun onPreviousDay() { fun onPreviousDay() {
loadData(currentDate.minusDays(7)) reloadView(currentDate.minusDays(7))
reloadView() loadData()
} }
fun onNextDay() { fun onNextDay() {
loadData(currentDate.plusDays(7)) reloadView(currentDate.plusDays(7))
reloadView() loadData()
} }
fun onSwipeRefresh() { fun onSwipeRefresh() {
Timber.i("Force refreshing the homework") Timber.i("Force refreshing the homework")
loadData(currentDate, true) loadData(true)
} }
fun onRetry() { fun onRetry() {
@ -69,7 +69,7 @@ class HomeworkPresenter @Inject constructor(
showErrorView(false) showErrorView(false)
showProgress(true) showProgress(true)
} }
loadData(currentDate, true) loadData(true)
} }
fun onDetailsClick() { fun onDetailsClick() {
@ -94,16 +94,26 @@ class HomeworkPresenter @Inject constructor(
}.launch("holidays") }.launch("holidays")
} }
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) { private fun loadData(forceRefresh: Boolean = false) {
currentDate = date Timber.i("Loading homework data started")
flowWithResourceIn { flowWithResourceIn {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
val semester = semesterRepository.getCurrentSemester(student) val semester = semesterRepository.getCurrentSemester(student)
homeworkRepository.getHomework(student, semester, date, date, forceRefresh) homeworkRepository.getHomework(student, semester, currentDate, currentDate, forceRefresh)
}.onEach { }.onEach {
when (it.status) { when (it.status) {
Status.LOADING -> Timber.i("Loading homework data started") Status.LOADING -> {
if (!it.data.isNullOrEmpty()) {
view?.run {
enableSwipe(true)
showRefresh(true)
showProgress(false)
showContent(true)
updateData(createHomeworkItem(it.data))
}
}
}
Status.SUCCESS -> { Status.SUCCESS -> {
Timber.i("Loading homework result: Success") Timber.i("Loading homework result: Success")
view?.apply { view?.apply {
@ -125,7 +135,7 @@ class HomeworkPresenter @Inject constructor(
} }
}.afterLoading { }.afterLoading {
view?.run { view?.run {
hideRefresh() showRefresh(false)
showProgress(false) showProgress(false)
enableSwipe(true) enableSwipe(true)
} }
@ -151,7 +161,9 @@ class HomeworkPresenter @Inject constructor(
}.flatten() }.flatten()
} }
private fun reloadView() { private fun reloadView(date: LocalDate) {
currentDate = date
Timber.i("Reload homework view with the date ${currentDate.toFormattedString()}") Timber.i("Reload homework view with the date ${currentDate.toFormattedString()}")
view?.apply { view?.apply {
showProgress(true) showProgress(true)

View File

@ -15,7 +15,7 @@ interface HomeworkView : BaseView {
fun updateNavigationWeek(date: String) fun updateNavigationWeek(date: String)
fun hideRefresh() fun showRefresh(show: Boolean)
fun showEmpty(show: Boolean) fun showEmpty(show: Boolean)

View File

@ -85,13 +85,27 @@ class MessageTabPresenter @Inject constructor(
} }
private fun loadData(forceRefresh: Boolean) { private fun loadData(forceRefresh: Boolean) {
Timber.i("Loading $folder message data started")
flowWithResourceIn { flowWithResourceIn {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
val semester = semesterRepository.getCurrentSemester(student) val semester = semesterRepository.getCurrentSemester(student)
messageRepository.getMessages(student, semester, folder, forceRefresh) messageRepository.getMessages(student, semester, folder, forceRefresh)
}.onEach { }.onEach {
when (it.status) { when (it.status) {
Status.LOADING -> Timber.i("Loading $folder message data started") Status.LOADING -> {
if (!it.data.isNullOrEmpty()) {
view?.run {
enableSwipe(true)
showRefresh(true)
showProgress(false)
showContent(true)
messages = it.data
updateData(getFilteredData(lastSearchQuery))
notifyParentDataLoaded()
}
}
}
Status.SUCCESS -> { Status.SUCCESS -> {
Timber.i("Loading $folder message result: Success") Timber.i("Loading $folder message result: Success")
messages = it.data!! messages = it.data!!

View File

@ -100,8 +100,8 @@ class MobileDeviceFragment :
} }
} }
override fun hideRefresh() { override fun showRefresh(show: Boolean) {
binding.mobileDevicesSwipe.isRefreshing = false binding.mobileDevicesSwipe.isRefreshing = show
} }
override fun showProgress(show: Boolean) { override fun showProgress(show: Boolean) {

View File

@ -51,13 +51,25 @@ class MobileDevicePresenter @Inject constructor(
} }
private fun loadData(forceRefresh: Boolean = false) { private fun loadData(forceRefresh: Boolean = false) {
Timber.i("Loading mobile devices data started")
flowWithResourceIn { flowWithResourceIn {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
val semester = semesterRepository.getCurrentSemester(student) val semester = semesterRepository.getCurrentSemester(student)
mobileDeviceRepository.getDevices(student, semester, forceRefresh) mobileDeviceRepository.getDevices(student, semester, forceRefresh)
}.onEach { }.onEach {
when (it.status) { when (it.status) {
Status.LOADING -> Timber.i("Loading mobile devices data started") Status.LOADING -> {
if (!it.data.isNullOrEmpty()) {
view?.run {
enableSwipe(true)
showRefresh(true)
showProgress(false)
showContent(true)
updateData(it.data)
}
}
}
Status.SUCCESS -> { Status.SUCCESS -> {
Timber.i("Loading mobile devices result: Success") Timber.i("Loading mobile devices result: Success")
view?.run { view?.run {
@ -79,7 +91,7 @@ class MobileDevicePresenter @Inject constructor(
} }
}.afterLoading { }.afterLoading {
view?.run { view?.run {
hideRefresh() showRefresh(false)
showProgress(false) showProgress(false)
enableSwipe(true) enableSwipe(true)
} }

View File

@ -17,7 +17,7 @@ interface MobileDeviceView : BaseView {
fun showUndo(device: MobileDevice, position: Int) fun showUndo(device: MobileDevice, position: Int)
fun hideRefresh() fun showRefresh(show: Boolean)
fun showProgress(show: Boolean) fun showProgress(show: Boolean)

View File

@ -105,8 +105,8 @@ class NoteFragment : BaseFragment<FragmentNoteBinding>(R.layout.fragment_note),
binding.noteRecycler.visibility = if (show) VISIBLE else GONE binding.noteRecycler.visibility = if (show) VISIBLE else GONE
} }
override fun hideRefresh() { override fun showRefresh(show: Boolean) {
binding.noteSwipe.isRefreshing = false binding.noteSwipe.isRefreshing = show
} }
override fun onDestroyView() { override fun onDestroyView() {

View File

@ -52,13 +52,25 @@ class NotePresenter @Inject constructor(
} }
private fun loadData(forceRefresh: Boolean = false) { private fun loadData(forceRefresh: Boolean = false) {
Timber.i("Loading note data started")
flowWithResourceIn { flowWithResourceIn {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
val semester = semesterRepository.getCurrentSemester(student) val semester = semesterRepository.getCurrentSemester(student)
noteRepository.getNotes(student, semester, forceRefresh) noteRepository.getNotes(student, semester, forceRefresh)
}.onEach { }.onEach {
when (it.status) { when (it.status) {
Status.LOADING -> Timber.i("Loading note data started") Status.LOADING -> {
if (!it.data.isNullOrEmpty()) {
view?.run {
enableSwipe(true)
showRefresh(true)
showProgress(false)
showContent(true)
updateData(it.data)
}
}
}
Status.SUCCESS -> { Status.SUCCESS -> {
Timber.i("Loading note result: Success") Timber.i("Loading note result: Success")
view?.apply { view?.apply {
@ -80,7 +92,7 @@ class NotePresenter @Inject constructor(
} }
}.afterLoading { }.afterLoading {
view?.run { view?.run {
hideRefresh() showRefresh(false)
showProgress(false) showProgress(false)
enableSwipe(true) enableSwipe(true)
} }

View File

@ -27,7 +27,7 @@ interface NoteView : BaseView {
fun showContent(show: Boolean) fun showContent(show: Boolean)
fun hideRefresh() fun showRefresh(show: Boolean)
fun showNoteDialog(note: Note) fun showNoteDialog(note: Note)
} }

View File

@ -113,8 +113,8 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
binding.timetableNavDate.text = date binding.timetableNavDate.text = date
} }
override fun hideRefresh() { override fun showRefresh(show: Boolean) {
binding.timetableSwipe.isRefreshing = false binding.timetableSwipe.isRefreshing = show
} }
override fun resetView() { override fun resetView() {

View File

@ -34,7 +34,7 @@ class TimetablePresenter @Inject constructor(
private val timetableRepository: TimetableRepository, private val timetableRepository: TimetableRepository,
private val semesterRepository: SemesterRepository, private val semesterRepository: SemesterRepository,
private val prefRepository: PreferencesRepository, private val prefRepository: PreferencesRepository,
private val analytics: AnalyticsHelper private val analytics: AnalyticsHelper,
) : BasePresenter<TimetableView>(errorHandler, studentRepository) { ) : BasePresenter<TimetableView>(errorHandler, studentRepository) {
private var baseDate: LocalDate = now().nextOrSameSchoolDay private var baseDate: LocalDate = now().nextOrSameSchoolDay
@ -49,19 +49,19 @@ class TimetablePresenter @Inject constructor(
view.initView() view.initView()
Timber.i("Timetable was initialized") Timber.i("Timetable was initialized")
errorHandler.showErrorMessage = ::showErrorViewOnError errorHandler.showErrorMessage = ::showErrorViewOnError
loadData(ofEpochDay(date ?: baseDate.toEpochDay())) reloadView(ofEpochDay(date ?: baseDate.toEpochDay()))
loadData()
if (currentDate.isHolidays) setBaseDateOnHolidays() if (currentDate.isHolidays) setBaseDateOnHolidays()
reloadView()
} }
fun onPreviousDay() { fun onPreviousDay() {
loadData(currentDate.previousSchoolDay) reloadView(currentDate.previousSchoolDay)
reloadView() loadData()
} }
fun onNextDay() { fun onNextDay() {
loadData(currentDate.nextSchoolDay) reloadView(currentDate.nextSchoolDay)
reloadView() loadData()
} }
fun onPickDate() { fun onPickDate() {
@ -69,13 +69,13 @@ class TimetablePresenter @Inject constructor(
} }
fun onDateSet(year: Int, month: Int, day: Int) { fun onDateSet(year: Int, month: Int, day: Int) {
loadData(of(year, month, day)) reloadView(of(year, month, day))
reloadView() loadData()
} }
fun onSwipeRefresh() { fun onSwipeRefresh() {
Timber.i("Force refreshing the timetable") Timber.i("Force refreshing the timetable")
loadData(currentDate, true) loadData(true)
} }
fun onRetry() { fun onRetry() {
@ -83,7 +83,7 @@ class TimetablePresenter @Inject constructor(
showErrorView(false) showErrorView(false)
showProgress(true) showProgress(true)
} }
loadData(currentDate, true) loadData(true)
} }
fun onDetailsClick() { fun onDetailsClick() {
@ -96,8 +96,8 @@ class TimetablePresenter @Inject constructor(
if (view.currentStackSize == 1) { if (view.currentStackSize == 1) {
baseDate.also { baseDate.also {
if (currentDate != it) { if (currentDate != it) {
loadData(it) reloadView(it)
reloadView() loadData()
} else if (!view.isViewEmpty) view.resetView() } else if (!view.isViewEmpty) view.resetView()
} }
} else view.popView() } else view.popView()
@ -132,27 +132,30 @@ class TimetablePresenter @Inject constructor(
}.launch("holidays") }.launch("holidays")
} }
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) { private fun loadData(forceRefresh: Boolean = false) {
currentDate = date Timber.i("Loading timetable data started")
flowWithResourceIn { flowWithResourceIn {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
val semester = semesterRepository.getCurrentSemester(student) val semester = semesterRepository.getCurrentSemester(student)
timetableRepository.getTimetable(student, semester, date, date, forceRefresh) timetableRepository.getTimetable(student, semester, currentDate, currentDate, forceRefresh)
}.onEach { }.onEach {
when (it.status) { when (it.status) {
Status.LOADING -> Timber.i("Loading timetable data started") Status.LOADING -> {
if (!it.data?.first.isNullOrEmpty()) {
view?.run {
enableSwipe(true)
showRefresh(true)
showProgress(false)
showContent(true)
updateData(it.data!!.first)
}
}
}
Status.SUCCESS -> { Status.SUCCESS -> {
Timber.i("Loading timetable result: Success") Timber.i("Loading timetable result: Success")
view?.apply { view?.apply {
updateData( updateData(it.data!!.first)
showWholeClassPlanType = prefRepository.showWholeClassPlan,
showGroupsInPlanType = prefRepository.showGroupsInPlan,
showTimetableTimers = prefRepository.showTimetableTimers,
data = it.data!!.first
.filter { item -> if (prefRepository.showWholeClassPlan == "no") item.isStudentPlan else true }
.sortedWith(compareBy({ item -> item.number }, { item -> !item.isStudentPlan }))
)
showEmpty(it.data.first.isEmpty()) showEmpty(it.data.first.isEmpty())
showErrorView(false) showErrorView(false)
showContent(it.data.first.isNotEmpty()) showContent(it.data.first.isNotEmpty())
@ -170,13 +173,26 @@ class TimetablePresenter @Inject constructor(
} }
}.afterLoading { }.afterLoading {
view?.run { view?.run {
hideRefresh() showRefresh(false)
showProgress(false) showProgress(false)
enableSwipe(true) enableSwipe(true)
} }
}.launch() }.launch()
} }
private fun updateData(lessons: List<Timetable>) {
view?.updateData(
showWholeClassPlanType = prefRepository.showWholeClassPlan,
showGroupsInPlanType = prefRepository.showGroupsInPlan,
showTimetableTimers = prefRepository.showTimetableTimers,
data = createItems(lessons)
)
}
private fun createItems(items: List<Timetable>) = items.filter { item ->
if (prefRepository.showWholeClassPlan == "no") item.isStudentPlan else true
}.sortedWith(compareBy({ item -> item.number }, { item -> !item.isStudentPlan }))
private fun showErrorViewOnError(message: String, error: Throwable) { private fun showErrorViewOnError(message: String, error: Throwable) {
view?.run { view?.run {
if (isViewEmpty) { if (isViewEmpty) {
@ -188,7 +204,9 @@ class TimetablePresenter @Inject constructor(
} }
} }
private fun reloadView() { private fun reloadView(date: LocalDate) {
currentDate = date
Timber.i("Reload timetable view with the date ${currentDate.toFormattedString()}") Timber.i("Reload timetable view with the date ${currentDate.toFormattedString()}")
view?.apply { view?.apply {
showProgress(true) showProgress(true)

View File

@ -18,7 +18,7 @@ interface TimetableView : BaseView {
fun clearData() fun clearData()
fun hideRefresh() fun showRefresh(show: Boolean)
fun resetView() fun resetView()

View File

@ -89,8 +89,8 @@ class CompletedLessonsFragment :
binding.completedLessonsNavDate.text = date binding.completedLessonsNavDate.text = date
} }
override fun hideRefresh() { override fun showRefresh(show: Boolean) {
binding.completedLessonsSwipe.isRefreshing = false binding.completedLessonsSwipe.isRefreshing = show
} }
override fun showEmpty(show: Boolean) { override fun showEmpty(show: Boolean) {

View File

@ -50,19 +50,19 @@ class CompletedLessonsPresenter @Inject constructor(
this.view?.showEmpty(true) this.view?.showEmpty(true)
Timber.i("Completed lessons feature disabled by school") Timber.i("Completed lessons feature disabled by school")
} }
loadData(ofEpochDay(date ?: baseDate.toEpochDay())) reloadView(ofEpochDay(date ?: baseDate.toEpochDay()))
loadData()
if (currentDate.isHolidays) setBaseDateOnHolidays() if (currentDate.isHolidays) setBaseDateOnHolidays()
reloadView()
} }
fun onPreviousDay() { fun onPreviousDay() {
loadData(currentDate.previousSchoolDay) reloadView(currentDate.previousSchoolDay)
reloadView() loadData()
} }
fun onNextDay() { fun onNextDay() {
loadData(currentDate.nextSchoolDay) reloadView(currentDate.nextSchoolDay)
reloadView() loadData()
} }
fun onPickDate() { fun onPickDate() {
@ -70,13 +70,13 @@ class CompletedLessonsPresenter @Inject constructor(
} }
fun onDateSet(year: Int, month: Int, day: Int) { fun onDateSet(year: Int, month: Int, day: Int) {
loadData(LocalDate.of(year, month, day)) reloadView(LocalDate.of(year, month, day))
reloadView() loadData()
} }
fun onSwipeRefresh() { fun onSwipeRefresh() {
Timber.i("Force refreshing the completed lessons") Timber.i("Force refreshing the completed lessons")
loadData(currentDate, true) loadData(true)
} }
fun onRetry() { fun onRetry() {
@ -84,7 +84,7 @@ class CompletedLessonsPresenter @Inject constructor(
showErrorView(false) showErrorView(false)
showProgress(true) showProgress(true)
} }
loadData(currentDate, true) loadData(true)
} }
fun onDetailsClick() { fun onDetailsClick() {
@ -109,16 +109,26 @@ class CompletedLessonsPresenter @Inject constructor(
}.launch("holidays") }.launch("holidays")
} }
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) { private fun loadData(forceRefresh: Boolean = false) {
currentDate = date Timber.i("Loading completed lessons data started")
flowWithResourceIn { flowWithResourceIn {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
val semester = semesterRepository.getCurrentSemester(student) val semester = semesterRepository.getCurrentSemester(student)
completedLessonsRepository.getCompletedLessons(student, semester, date, date, forceRefresh) completedLessonsRepository.getCompletedLessons(student, semester, currentDate, currentDate, forceRefresh)
}.onEach { }.onEach {
when (it.status) { when (it.status) {
Status.LOADING -> Timber.i("Loading completed lessons data started") Status.LOADING -> {
if (!it.data.isNullOrEmpty()) {
view?.run {
enableSwipe(true)
showRefresh(true)
showProgress(false)
showContent(true)
updateData(it.data.sortedBy { item -> item.number })
}
}
}
Status.SUCCESS -> { Status.SUCCESS -> {
Timber.i("Loading completed lessons lessons result: Success") Timber.i("Loading completed lessons lessons result: Success")
view?.apply { view?.apply {
@ -140,7 +150,7 @@ class CompletedLessonsPresenter @Inject constructor(
} }
}.afterLoading { }.afterLoading {
view?.run { view?.run {
hideRefresh() showRefresh(false)
showProgress(false) showProgress(false)
enableSwipe(true) enableSwipe(true)
} }
@ -158,7 +168,9 @@ class CompletedLessonsPresenter @Inject constructor(
} }
} }
private fun reloadView() { private fun reloadView(date: LocalDate) {
currentDate = date
Timber.i("Reload completed lessons view with the date ${currentDate.toFormattedString()}") Timber.i("Reload completed lessons view with the date ${currentDate.toFormattedString()}")
view?.apply { view?.apply {
showProgress(true) showProgress(true)

View File

@ -16,7 +16,7 @@ interface CompletedLessonsView : BaseView {
fun updateNavigationDay(date: String) fun updateNavigationDay(date: String)
fun hideRefresh() fun showRefresh(show: Boolean)
fun showEmpty(show: Boolean) fun showEmpty(show: Boolean)

View File

@ -84,7 +84,7 @@ fun <T> flowWithResourceIn(block: suspend () -> Flow<Resource<T>>) = flow {
block() block()
.catch { emit(Resource.error(it)) } .catch { emit(Resource.error(it)) }
.collect { .collect {
if (it.status != Status.LOADING) { // LOADING is already emitted if (it.status != Status.LOADING || (it.status == Status.LOADING && it.data != null)) { // LOADING without data is already emitted
emit(it) emit(it)
} }
} }

View File

@ -0,0 +1,50 @@
package io.github.wulkanowy.utils
import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.enums.MessageFolder
import timber.log.Timber
import java.time.LocalDate
import java.time.LocalDateTime
import javax.inject.Inject
fun getRefreshKey(name: String, semester: Semester, start: LocalDate, end: LocalDate): String {
return "${name}_${semester.studentId}_${semester.semesterId}_${start.monday}_${end.sunday}"
}
fun getRefreshKey(name: String, semester: Semester): String {
return "${name}_${semester.studentId}_${semester.semesterId}"
}
fun getRefreshKey(name: String, student: Student): String {
return "${name}_${student.userLoginId}"
}
fun getRefreshKey(name: String, student: Student, folder: MessageFolder): String {
return "${name}_${student.id}_${folder.id}"
}
class AutoRefreshHelper @Inject constructor(
@ApplicationContext private val context: Context,
private val sharedPref: SharedPrefProvider
) {
fun isShouldBeRefreshed(key: String): Boolean {
val timestamp = sharedPref.getLong(key, 0).toLocalDateTime()
val servicesInterval = sharedPref.getString(context.getString(R.string.pref_key_services_interval), context.getString(R.string.pref_default_services_interval)).toLong()
val shouldBeRefreshed = timestamp < LocalDateTime.now().minusMinutes(servicesInterval)
Timber.d("Check if $key need to be refreshed: $shouldBeRefreshed (last refresh: $timestamp, interval: $servicesInterval min)")
return shouldBeRefreshed
}
fun updateLastRefreshTimestamp(key: String) {
sharedPref.putLong(key, LocalDateTime.now().toTimestamp())
}
}

View File

@ -5,11 +5,13 @@ 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.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.toFirstResult import io.github.wulkanowy.utils.toFirstResult
import io.mockk.MockKAnnotations import io.mockk.MockKAnnotations
import io.mockk.Runs import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
@ -30,6 +32,9 @@ class AttendanceRepositoryTest {
@MockK @MockK
private lateinit var attendanceDb: AttendanceDao private lateinit var attendanceDb: AttendanceDao
@MockK(relaxUnitFun = true)
private lateinit var refreshHelper: AutoRefreshHelper
private val semester = getSemesterEntity() private val semester = getSemesterEntity()
private val student = getStudentEntity() private val student = getStudentEntity()
@ -48,8 +53,9 @@ class AttendanceRepositoryTest {
@Before @Before
fun setUp() { fun setUp() {
MockKAnnotations.init(this) MockKAnnotations.init(this)
every { refreshHelper.isShouldBeRefreshed(any()) } returns false
attendanceRepository = AttendanceRepository(attendanceDb, sdk) attendanceRepository = AttendanceRepository(attendanceDb, sdk, refreshHelper)
} }
@Test @Test

View File

@ -5,11 +5,13 @@ 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.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.toFirstResult import io.github.wulkanowy.utils.toFirstResult
import io.mockk.MockKAnnotations import io.mockk.MockKAnnotations
import io.mockk.Runs import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
@ -30,6 +32,9 @@ class CompletedLessonsRepositoryTest {
@MockK @MockK
private lateinit var completedLessonDb: CompletedLessonsDao private lateinit var completedLessonDb: CompletedLessonsDao
@MockK(relaxUnitFun = true)
private lateinit var refreshHelper: AutoRefreshHelper
private val semester = getSemesterEntity() private val semester = getSemesterEntity()
private val student = getStudentEntity() private val student = getStudentEntity()
@ -48,8 +53,9 @@ class CompletedLessonsRepositoryTest {
@Before @Before
fun initApi() { fun initApi() {
MockKAnnotations.init(this) MockKAnnotations.init(this)
every { refreshHelper.isShouldBeRefreshed(any()) } returns false
completedLessonRepository = CompletedLessonsRepository(completedLessonDb, sdk) completedLessonRepository = CompletedLessonsRepository(completedLessonDb, sdk, refreshHelper)
} }
@Test @Test

View File

@ -5,11 +5,13 @@ 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.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.toFirstResult import io.github.wulkanowy.utils.toFirstResult
import io.mockk.MockKAnnotations import io.mockk.MockKAnnotations
import io.mockk.Runs import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
@ -29,6 +31,9 @@ class ExamRemoteTest {
@MockK @MockK
private lateinit var examDb: ExamDao private lateinit var examDb: ExamDao
@MockK(relaxUnitFun = true)
private lateinit var refreshHelper: AutoRefreshHelper
private val semester = getSemesterEntity() private val semester = getSemesterEntity()
private val student = getStudentEntity() private val student = getStudentEntity()
@ -49,8 +54,9 @@ class ExamRemoteTest {
@Before @Before
fun setUp() { fun setUp() {
MockKAnnotations.init(this) MockKAnnotations.init(this)
every { refreshHelper.isShouldBeRefreshed(any()) } returns false
examRepository = ExamRepository(examDb, sdk) examRepository = ExamRepository(examDb, sdk, refreshHelper)
} }
@Test @Test

View File

@ -6,11 +6,13 @@ 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.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.toFirstResult import io.github.wulkanowy.utils.toFirstResult
import io.mockk.MockKAnnotations import io.mockk.MockKAnnotations
import io.mockk.Runs import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
@ -36,6 +38,9 @@ class GradeRepositoryTest {
@MockK @MockK
private lateinit var gradeSummaryDb: GradeSummaryDao private lateinit var gradeSummaryDb: GradeSummaryDao
@MockK(relaxUnitFun = true)
private lateinit var refreshHelper: AutoRefreshHelper
private val semester = getSemesterEntity() private val semester = getSemesterEntity()
private val student = getStudentEntity() private val student = getStudentEntity()
@ -45,8 +50,9 @@ class GradeRepositoryTest {
@Before @Before
fun initApi() { fun initApi() {
MockKAnnotations.init(this) MockKAnnotations.init(this)
every { refreshHelper.isShouldBeRefreshed(any()) } returns false
gradeRepository = GradeRepository(gradeDb, gradeSummaryDb, sdk) gradeRepository = GradeRepository(gradeDb, gradeSummaryDb, sdk, refreshHelper)
coEvery { gradeDb.deleteAll(any()) } just Runs coEvery { gradeDb.deleteAll(any()) } just Runs
coEvery { gradeDb.insertAll(any()) } returns listOf() coEvery { gradeDb.insertAll(any()) } returns listOf()

View File

@ -9,11 +9,13 @@ import io.github.wulkanowy.getStudentEntity
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.GradeStatisticsItem import io.github.wulkanowy.sdk.pojo.GradeStatisticsItem
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSubject import io.github.wulkanowy.sdk.pojo.GradeStatisticsSubject
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.toFirstResult import io.github.wulkanowy.utils.toFirstResult
import io.mockk.MockKAnnotations import io.mockk.MockKAnnotations
import io.mockk.Runs import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
@ -37,6 +39,9 @@ class GradeStatisticsRepositoryTest {
@MockK @MockK
private lateinit var gradeSemesterStatisticsDb: GradeSemesterStatisticsDao private lateinit var gradeSemesterStatisticsDb: GradeSemesterStatisticsDao
@MockK(relaxUnitFun = true)
private lateinit var refreshHelper: AutoRefreshHelper
private val semester = getSemesterEntity() private val semester = getSemesterEntity()
private val student = getStudentEntity() private val student = getStudentEntity()
@ -51,8 +56,9 @@ class GradeStatisticsRepositoryTest {
@Before @Before
fun setUp() { fun setUp() {
MockKAnnotations.init(this) MockKAnnotations.init(this)
every { refreshHelper.isShouldBeRefreshed(any()) } returns false
gradeStatisticsRepository = GradeStatisticsRepository(gradePartialStatisticsDb, gradePointsStatisticsDb, gradeSemesterStatisticsDb, sdk) gradeStatisticsRepository = GradeStatisticsRepository(gradePartialStatisticsDb, gradePointsStatisticsDb, gradeSemesterStatisticsDb, sdk, refreshHelper)
} }
@Test @Test

View File

@ -8,11 +8,13 @@ import io.github.wulkanowy.data.db.entities.MessageWithAttachment
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.MessageDetails import io.github.wulkanowy.sdk.pojo.MessageDetails
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.toFirstResult import io.github.wulkanowy.utils.toFirstResult
import io.mockk.MockKAnnotations import io.mockk.MockKAnnotations
import io.mockk.Runs import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
@ -36,6 +38,9 @@ class MessageRepositoryTest {
@MockK @MockK
private lateinit var messageAttachmentDao: MessageAttachmentDao private lateinit var messageAttachmentDao: MessageAttachmentDao
@MockK(relaxUnitFun = true)
private lateinit var refreshHelper: AutoRefreshHelper
private val student = getStudentEntity() private val student = getStudentEntity()
private lateinit var messageRepository: MessageRepository private lateinit var messageRepository: MessageRepository
@ -43,8 +48,9 @@ class MessageRepositoryTest {
@Before @Before
fun setUp() { fun setUp() {
MockKAnnotations.init(this) MockKAnnotations.init(this)
every { refreshHelper.isShouldBeRefreshed(any()) } returns false
messageRepository = MessageRepository(messageDb, messageAttachmentDao, sdk) messageRepository = MessageRepository(messageDb, messageAttachmentDao, sdk, refreshHelper)
} }
@Test(expected = NoSuchElementException::class) @Test(expected = NoSuchElementException::class)

View File

@ -6,11 +6,13 @@ 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.Device import io.github.wulkanowy.sdk.pojo.Device
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.toFirstResult import io.github.wulkanowy.utils.toFirstResult
import io.mockk.MockKAnnotations import io.mockk.MockKAnnotations
import io.mockk.Runs import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
@ -29,6 +31,9 @@ class MobileDeviceRepositoryTest {
@MockK @MockK
private lateinit var mobileDeviceDb: MobileDeviceDao private lateinit var mobileDeviceDb: MobileDeviceDao
@MockK(relaxUnitFun = true)
private lateinit var refreshHelper: AutoRefreshHelper
private val semester = getSemesterEntity() private val semester = getSemesterEntity()
private val student = getStudentEntity() private val student = getStudentEntity()
@ -43,8 +48,9 @@ class MobileDeviceRepositoryTest {
@Before @Before
fun initTest() { fun initTest() {
MockKAnnotations.init(this) MockKAnnotations.init(this)
every { refreshHelper.isShouldBeRefreshed(any()) } returns false
mobileDeviceRepository = MobileDeviceRepository(mobileDeviceDb, sdk) mobileDeviceRepository = MobileDeviceRepository(mobileDeviceDb, sdk, refreshHelper)
} }
@Test @Test

View File

@ -7,11 +7,13 @@ 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.services.alarm.TimetableNotificationSchedulerHelper import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.toFirstResult import io.github.wulkanowy.utils.toFirstResult
import io.mockk.MockKAnnotations import io.mockk.MockKAnnotations
import io.mockk.Runs import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
@ -39,6 +41,9 @@ class TimetableRepositoryTest {
@MockK @MockK
private lateinit var timetableAdditionalDao: TimetableAdditionalDao private lateinit var timetableAdditionalDao: TimetableAdditionalDao
@MockK(relaxUnitFun = true)
private lateinit var refreshHelper: AutoRefreshHelper
private val student = getStudentEntity() private val student = getStudentEntity()
private val semester = getSemesterEntity() private val semester = getSemesterEntity()
@ -52,7 +57,9 @@ class TimetableRepositoryTest {
@Before @Before
fun initApi() { fun initApi() {
MockKAnnotations.init(this) MockKAnnotations.init(this)
timetableRepository = TimetableRepository(timetableDb, timetableAdditionalDao, sdk, timetableNotificationSchedulerHelper) every { refreshHelper.isShouldBeRefreshed(any()) } returns false
timetableRepository = TimetableRepository(timetableDb, timetableAdditionalDao, sdk, timetableNotificationSchedulerHelper, refreshHelper)
} }
@Test @Test