mirror of
https://github.com/wulkanowy/wulkanowy.git
synced 2025-02-22 18:34:45 +01:00
Merge branch 'release/1.6.0'
This commit is contained in:
commit
b371fd6709
12
.editorconfig
Normal file
12
.editorconfig
Normal file
@ -0,0 +1,12 @@
|
||||
[*]
|
||||
charset=utf-8
|
||||
end_of_line=lf
|
||||
insert_final_newline=true
|
||||
indent_style=space
|
||||
indent_size=4
|
||||
|
||||
[*.json]
|
||||
indent_size=2
|
||||
|
||||
[*.{kt,kts}]
|
||||
disabled_rules=import-ordering,no-wildcard-imports
|
2
LICENSE
2
LICENSE
@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2021 Wulkanowy
|
||||
Copyright 2022 Wulkanowy
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -22,8 +22,8 @@ android {
|
||||
testApplicationId "io.github.tests.wulkanowy"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 31
|
||||
versionCode 103
|
||||
versionName "1.5.0"
|
||||
versionCode 104
|
||||
versionName "1.6.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
resValue "string", "app_name", "Wulkanowy"
|
||||
@ -73,6 +73,8 @@ android {
|
||||
buildConfigField "String", "MESSAGES_BASE_URL", "\"https://messages.wulkanowy.net.pl\""
|
||||
}
|
||||
debug {
|
||||
minifyEnabled false
|
||||
shrinkResources false
|
||||
resValue "string", "app_name", "Wulkanowy DEV"
|
||||
applicationIdSuffix ".dev"
|
||||
versionNameSuffix "-dev"
|
||||
@ -169,14 +171,14 @@ huaweiPublish {
|
||||
ext {
|
||||
work_manager = "2.7.1"
|
||||
android_hilt = "1.0.0"
|
||||
room = "2.4.0"
|
||||
room = "2.4.2"
|
||||
chucker = "3.5.2"
|
||||
mockk = "1.12.1"
|
||||
mockk = "1.12.2"
|
||||
coroutines = "1.6.0"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "io.github.wulkanowy:sdk:1.5.0"
|
||||
implementation "io.github.wulkanowy:sdk:1.6.0"
|
||||
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||
|
||||
@ -184,19 +186,19 @@ dependencies {
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
|
||||
|
||||
implementation "androidx.core:core-ktx:1.7.0"
|
||||
implementation 'androidx.core:core-splashscreen:1.0.0-alpha02'
|
||||
implementation 'androidx.core:core-splashscreen:1.0.0-beta02'
|
||||
implementation "androidx.activity:activity-ktx:1.4.0"
|
||||
implementation "androidx.appcompat:appcompat:1.4.0"
|
||||
implementation "androidx.fragment:fragment-ktx:1.4.0"
|
||||
implementation "androidx.appcompat:appcompat:1.4.1"
|
||||
implementation "androidx.fragment:fragment-ktx:1.4.1"
|
||||
implementation "androidx.annotation:annotation:1.3.0"
|
||||
|
||||
implementation "androidx.preference:preference-ktx:1.1.1"
|
||||
implementation "androidx.preference:preference-ktx:1.2.0"
|
||||
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
||||
implementation "androidx.viewpager2:viewpager2:1.1.0-beta01"
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.1.2"
|
||||
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
|
||||
implementation "com.google.android.material:material:1.4.0"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.1.3"
|
||||
implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
|
||||
implementation "com.google.android.material:material:1.5.0"
|
||||
implementation "com.github.wulkanowy:material-chips-input:2.3.1"
|
||||
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
|
||||
implementation 'com.github.lopspower:CircularImageView:4.2.0'
|
||||
@ -204,7 +206,7 @@ dependencies {
|
||||
implementation "androidx.work:work-runtime-ktx:$work_manager"
|
||||
playImplementation "androidx.work:work-gcm:$work_manager"
|
||||
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1"
|
||||
|
||||
implementation "androidx.room:room-runtime:$room"
|
||||
implementation "androidx.room:room-ktx:$room"
|
||||
@ -228,24 +230,25 @@ dependencies {
|
||||
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
||||
implementation "io.coil-kt:coil:1.4.0"
|
||||
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
|
||||
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
|
||||
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
|
||||
implementation 'com.fredporciuncula:flow-preferences:1.6.0'
|
||||
|
||||
playImplementation platform('com.google.firebase:firebase-bom:29.0.3')
|
||||
playImplementation platform('com.google.firebase:firebase-bom:29.3.0')
|
||||
playImplementation 'com.google.firebase:firebase-analytics-ktx'
|
||||
playImplementation 'com.google.firebase:firebase-messaging:'
|
||||
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
||||
playImplementation 'com.google.android.play:core:1.10.2'
|
||||
playImplementation 'com.google.android.play:core:1.10.3'
|
||||
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
||||
playImplementation 'com.google.android.gms:play-services-ads:20.5.0'
|
||||
playImplementation 'com.google.android.gms:play-services-ads:20.6.0'
|
||||
|
||||
hmsImplementation 'com.huawei.hms:hianalytics:6.3.2.300'
|
||||
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.3.200'
|
||||
hmsImplementation 'com.huawei.hms:hianalytics:6.4.1.300'
|
||||
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.5.200'
|
||||
|
||||
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
||||
|
||||
debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker"
|
||||
debugImplementation 'com.github.amitshekhariitbhu.Android-Debug-Database:debug-db:1.0.6'
|
||||
debugImplementation 'com.github.haroldadmin:WhatTheStack:1.0.0-alpha04'
|
||||
|
||||
testImplementation "junit:junit:4.13.2"
|
||||
testImplementation "io.mockk:mockk:$mockk"
|
||||
|
2445
app/schemas/io.github.wulkanowy.data.db.AppDatabase/48.json
Normal file
2445
app/schemas/io.github.wulkanowy.data.db.AppDatabase/48.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,23 +1,173 @@
|
||||
package io.github.wulkanowy.data
|
||||
|
||||
data class Resource<T>(val status: Status, val data: T?, val error: Throwable?) {
|
||||
companion object {
|
||||
fun <T> success(data: T?): Resource<T> {
|
||||
return Resource(Status.SUCCESS, data, null)
|
||||
}
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import timber.log.Timber
|
||||
|
||||
fun <T> error(error: Throwable?, data: T? = null): Resource<T> {
|
||||
return Resource(Status.ERROR, data, error)
|
||||
}
|
||||
sealed class Resource<T> {
|
||||
|
||||
fun <T> loading(data: T? = null): Resource<T> {
|
||||
return Resource(Status.LOADING, data, null)
|
||||
}
|
||||
open class Loading<T> : Resource<T>()
|
||||
|
||||
data class Intermediate<T>(val data: T) : Loading<T>()
|
||||
|
||||
data class Success<T>(val data: T) : Resource<T>()
|
||||
|
||||
data class Error<T>(val error: Throwable) : Resource<T>()
|
||||
}
|
||||
|
||||
val <T> Resource<T>.dataOrNull: T?
|
||||
get() = when (this) {
|
||||
is Resource.Success -> this.data
|
||||
is Resource.Intermediate -> this.data
|
||||
is Resource.Loading -> null
|
||||
is Resource.Error -> null
|
||||
}
|
||||
|
||||
val <T> Resource<T>.errorOrNull: Throwable?
|
||||
get() = when (this) {
|
||||
is Resource.Error -> this.error
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun <T> resourceFlow(block: suspend () -> T) = flow {
|
||||
emit(Resource.Loading())
|
||||
emit(Resource.Success(block()))
|
||||
}.catch { emit(Resource.Error(it)) }
|
||||
|
||||
fun <T> flatResourceFlow(block: suspend () -> Flow<Resource<T>>) = flow {
|
||||
emit(Resource.Loading())
|
||||
emitAll(block().filter { it is Resource.Intermediate || it !is Resource.Loading })
|
||||
}.catch { emit(Resource.Error(it)) }
|
||||
|
||||
fun <T, U> Resource<T>.mapData(block: (T) -> U) = when (this) {
|
||||
is Resource.Success -> Resource.Success(block(this.data))
|
||||
is Resource.Intermediate -> Resource.Intermediate(block(this.data))
|
||||
is Resource.Loading -> Resource.Loading()
|
||||
is Resource.Error -> Resource.Error(this.error)
|
||||
}
|
||||
|
||||
fun <T> Flow<Resource<T>>.logResourceStatus(name: String, showData: Boolean = false) = onEach {
|
||||
val description = when (it) {
|
||||
is Resource.Loading -> "started"
|
||||
is Resource.Intermediate -> "intermediate data received" + if (showData) " (data: `${it.data}`)" else ""
|
||||
is Resource.Success -> "success" + if (showData) " (data: `${it.data}`)" else ""
|
||||
is Resource.Error -> "exception occurred: ${it.error}"
|
||||
}
|
||||
Timber.i("$name: $description")
|
||||
}
|
||||
|
||||
fun <T, U> Flow<Resource<T>>.mapResourceData(block: (T) -> U) = map {
|
||||
it.mapData(block)
|
||||
}
|
||||
|
||||
fun <T> Flow<Resource<T>>.onResourceData(block: suspend (T) -> Unit) = onEach {
|
||||
when (it) {
|
||||
is Resource.Success -> block(it.data)
|
||||
is Resource.Intermediate -> block(it.data)
|
||||
is Resource.Error,
|
||||
is Resource.Loading -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
enum class Status {
|
||||
LOADING,
|
||||
SUCCESS,
|
||||
ERROR
|
||||
fun <T> Flow<Resource<T>>.onResourceLoading(block: suspend () -> Unit) = onEach {
|
||||
if (it is Resource.Loading) {
|
||||
block()
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Flow<Resource<T>>.onResourceIntermediate(block: suspend (T) -> Unit) = onEach {
|
||||
if (it is Resource.Intermediate) {
|
||||
block(it.data)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Flow<Resource<T>>.onResourceSuccess(block: suspend (T) -> Unit) = onEach {
|
||||
if (it is Resource.Success) {
|
||||
block(it.data)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Flow<Resource<T>>.onResourceError(block: (Throwable) -> Unit) = onEach {
|
||||
if (it is Resource.Error) {
|
||||
block(it.error)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Flow<Resource<T>>.onResourceNotLoading(block: () -> Unit) = onEach {
|
||||
if (it !is Resource.Loading) {
|
||||
block()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun <T> Flow<Resource<T>>.toFirstResult() = filter { it !is Resource.Loading }.first()
|
||||
|
||||
suspend fun <T> Flow<Resource<T>>.waitForResult() = takeWhile { it is Resource.Loading }.collect()
|
||||
|
||||
inline fun <ResultType, RequestType> networkBoundResource(
|
||||
mutex: Mutex = Mutex(),
|
||||
showSavedOnLoading: Boolean = true,
|
||||
crossinline isResultEmpty: (ResultType) -> Boolean,
|
||||
crossinline query: () -> Flow<ResultType>,
|
||||
crossinline fetch: suspend (ResultType) -> RequestType,
|
||||
crossinline saveFetchResult: suspend (old: ResultType, new: RequestType) -> Unit,
|
||||
crossinline onFetchFailed: (Throwable) -> Unit = { },
|
||||
crossinline shouldFetch: (ResultType) -> Boolean = { true },
|
||||
crossinline filterResult: (ResultType) -> ResultType = { it }
|
||||
) = flow {
|
||||
emit(Resource.Loading())
|
||||
|
||||
val data = query().first()
|
||||
emitAll(if (shouldFetch(data)) {
|
||||
val filteredResult = filterResult(data)
|
||||
|
||||
if (showSavedOnLoading && !isResultEmpty(filteredResult)) {
|
||||
emit(Resource.Intermediate(filteredResult))
|
||||
}
|
||||
|
||||
try {
|
||||
val newData = fetch(data)
|
||||
mutex.withLock { saveFetchResult(query().first(), newData) }
|
||||
query().map { Resource.Success(filterResult(it)) }
|
||||
} catch (throwable: Throwable) {
|
||||
onFetchFailed(throwable)
|
||||
query().map { Resource.Error(throwable) }
|
||||
}
|
||||
} else {
|
||||
query().map { Resource.Success(filterResult(it)) }
|
||||
})
|
||||
}
|
||||
|
||||
@JvmName("networkBoundResourceWithMap")
|
||||
inline fun <ResultType, RequestType, T> networkBoundResource(
|
||||
mutex: Mutex = Mutex(),
|
||||
showSavedOnLoading: Boolean = true,
|
||||
crossinline isResultEmpty: (T) -> Boolean,
|
||||
crossinline query: () -> Flow<ResultType>,
|
||||
crossinline fetch: suspend (ResultType) -> RequestType,
|
||||
crossinline saveFetchResult: suspend (old: ResultType, new: RequestType) -> Unit,
|
||||
crossinline onFetchFailed: (Throwable) -> Unit = { },
|
||||
crossinline shouldFetch: (ResultType) -> Boolean = { true },
|
||||
crossinline mapResult: (ResultType) -> T
|
||||
) = flow {
|
||||
emit(Resource.Loading())
|
||||
|
||||
val data = query().first()
|
||||
emitAll(if (shouldFetch(data)) {
|
||||
val mappedResult = mapResult(data)
|
||||
|
||||
if (showSavedOnLoading && !isResultEmpty(mappedResult)) {
|
||||
emit(Resource.Intermediate(mappedResult))
|
||||
}
|
||||
try {
|
||||
val newData = fetch(data)
|
||||
mutex.withLock { saveFetchResult(query().first(), newData) }
|
||||
query().map { Resource.Success(mapResult(it)) }
|
||||
} catch (throwable: Throwable) {
|
||||
onFetchFailed(throwable)
|
||||
query().map { Resource.Error(throwable) }
|
||||
}
|
||||
} else {
|
||||
query().map { Resource.Success(mapResult(it)) }
|
||||
})
|
||||
}
|
||||
|
@ -1,72 +1,10 @@
|
||||
package io.github.wulkanowy.data.db
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.AutoMigration
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.*
|
||||
import androidx.room.RoomDatabase.JournalMode.TRUNCATE
|
||||
import androidx.room.TypeConverters
|
||||
import io.github.wulkanowy.data.db.dao.AdminMessageDao
|
||||
import io.github.wulkanowy.data.db.dao.AttendanceDao
|
||||
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
|
||||
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
|
||||
import io.github.wulkanowy.data.db.dao.ConferenceDao
|
||||
import io.github.wulkanowy.data.db.dao.ExamDao
|
||||
import io.github.wulkanowy.data.db.dao.GradeDao
|
||||
import io.github.wulkanowy.data.db.dao.GradePartialStatisticsDao
|
||||
import io.github.wulkanowy.data.db.dao.GradePointsStatisticsDao
|
||||
import io.github.wulkanowy.data.db.dao.GradeSemesterStatisticsDao
|
||||
import io.github.wulkanowy.data.db.dao.GradeSummaryDao
|
||||
import io.github.wulkanowy.data.db.dao.HomeworkDao
|
||||
import io.github.wulkanowy.data.db.dao.LuckyNumberDao
|
||||
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||
import io.github.wulkanowy.data.db.dao.MobileDeviceDao
|
||||
import io.github.wulkanowy.data.db.dao.NoteDao
|
||||
import io.github.wulkanowy.data.db.dao.NotificationDao
|
||||
import io.github.wulkanowy.data.db.dao.RecipientDao
|
||||
import io.github.wulkanowy.data.db.dao.ReportingUnitDao
|
||||
import io.github.wulkanowy.data.db.dao.SchoolAnnouncementDao
|
||||
import io.github.wulkanowy.data.db.dao.SchoolDao
|
||||
import io.github.wulkanowy.data.db.dao.SemesterDao
|
||||
import io.github.wulkanowy.data.db.dao.StudentDao
|
||||
import io.github.wulkanowy.data.db.dao.StudentInfoDao
|
||||
import io.github.wulkanowy.data.db.dao.SubjectDao
|
||||
import io.github.wulkanowy.data.db.dao.TeacherDao
|
||||
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
|
||||
import io.github.wulkanowy.data.db.dao.TimetableDao
|
||||
import io.github.wulkanowy.data.db.dao.TimetableHeaderDao
|
||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||
import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.github.wulkanowy.data.db.entities.AttendanceSummary
|
||||
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
||||
import io.github.wulkanowy.data.db.entities.Conference
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
|
||||
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
||||
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
|
||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
import io.github.wulkanowy.data.db.entities.Homework
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
||||
import io.github.wulkanowy.data.db.entities.MobileDevice
|
||||
import io.github.wulkanowy.data.db.entities.Note
|
||||
import io.github.wulkanowy.data.db.entities.Notification
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||
import io.github.wulkanowy.data.db.entities.School
|
||||
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.StudentInfo
|
||||
import io.github.wulkanowy.data.db.entities.Subject
|
||||
import io.github.wulkanowy.data.db.entities.Teacher
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
||||
import io.github.wulkanowy.data.db.dao.*
|
||||
import io.github.wulkanowy.data.db.entities.*
|
||||
import io.github.wulkanowy.data.db.migrations.*
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import javax.inject.Singleton
|
||||
@ -108,6 +46,7 @@ import javax.inject.Singleton
|
||||
autoMigrations = [
|
||||
AutoMigration(from = 44, to = 45),
|
||||
AutoMigration(from = 46, to = 47),
|
||||
AutoMigration(from = 47, to = 48),
|
||||
],
|
||||
version = AppDatabase.VERSION_SCHEMA,
|
||||
exportSchema = true
|
||||
@ -116,7 +55,7 @@ import javax.inject.Singleton
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
companion object {
|
||||
const val VERSION_SCHEMA = 47
|
||||
const val VERSION_SCHEMA = 48
|
||||
|
||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
||||
Migration2(),
|
||||
|
@ -1,11 +1,14 @@
|
||||
package io.github.wulkanowy.data.db
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import io.github.wulkanowy.ui.modules.Destination
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.time.*
|
||||
import java.util.*
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.time.Month
|
||||
@ -58,4 +61,11 @@ class Converters {
|
||||
emptyList() // handle errors from old gson Pair serialized data
|
||||
}
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun destinationToString(destination: Destination) = json.encodeToString(destination)
|
||||
|
||||
@TypeConverter
|
||||
fun stringToDestination(destination: String): Destination = json.decodeFromString(destination)
|
||||
|
||||
}
|
||||
|
@ -33,6 +33,10 @@ abstract class StudentDao {
|
||||
@Query("SELECT * FROM Students")
|
||||
abstract suspend fun loadStudentsWithSemesters(): List<StudentWithSemesters>
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM Students WHERE id = :id")
|
||||
abstract suspend fun loadStudentWithSemestersById(id: Long): StudentWithSemesters?
|
||||
|
||||
@Query("UPDATE Students SET is_current = 1 WHERE id = :id")
|
||||
abstract suspend fun updateCurrent(id: Long)
|
||||
|
||||
|
@ -24,5 +24,8 @@ data class GradeSemesterStatistics(
|
||||
var id: Long = 0
|
||||
|
||||
@Transient
|
||||
var average: String = ""
|
||||
var classAverage: String = ""
|
||||
|
||||
@Transient
|
||||
var studentAverage: String = ""
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import io.github.wulkanowy.services.sync.notifications.NotificationType
|
||||
import io.github.wulkanowy.ui.modules.Destination
|
||||
import java.time.Instant
|
||||
|
||||
@Entity(tableName = "Notifications")
|
||||
@ -18,6 +19,9 @@ data class Notification(
|
||||
|
||||
val type: NotificationType,
|
||||
|
||||
@ColumnInfo(defaultValue = "{\"type\":\"io.github.wulkanowy.ui.modules.Destination.Dashboard\"}")
|
||||
val destination: Destination,
|
||||
|
||||
val date: Instant,
|
||||
|
||||
val data: String? = null
|
||||
|
@ -1,10 +1,10 @@
|
||||
package io.github.wulkanowy.data.pojos
|
||||
|
||||
import android.content.Intent
|
||||
import io.github.wulkanowy.services.sync.notifications.NotificationType
|
||||
import io.github.wulkanowy.ui.modules.Destination
|
||||
|
||||
data class NotificationData(
|
||||
val intentToStart: Intent,
|
||||
val destination: Destination,
|
||||
val title: String,
|
||||
val content: String
|
||||
)
|
||||
@ -13,7 +13,7 @@ data class GroupNotificationData(
|
||||
val notificationDataList: List<NotificationData>,
|
||||
val title: String,
|
||||
val content: String,
|
||||
val intentToStart: Intent,
|
||||
val destination: Destination,
|
||||
val type: NotificationType
|
||||
)
|
||||
|
||||
|
@ -3,8 +3,8 @@ package io.github.wulkanowy.data.repositories
|
||||
import io.github.wulkanowy.data.api.AdminMessageService
|
||||
import io.github.wulkanowy.data.db.dao.AdminMessageDao
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import io.github.wulkanowy.utils.networkBoundResource
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -19,6 +19,7 @@ class AdminMessageRepository @Inject constructor(
|
||||
|
||||
suspend fun getAdminMessages(student: Student) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it == null },
|
||||
query = { adminMessageDao.loadAll() },
|
||||
fetch = { adminMessageService.getAdminMessages() },
|
||||
shouldFetch = { true },
|
||||
|
@ -5,6 +5,7 @@ import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.sdk.pojo.Absent
|
||||
import io.github.wulkanowy.utils.*
|
||||
@ -36,6 +37,7 @@ class AttendanceRepository @Inject constructor(
|
||||
notify: Boolean = false,
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it.isEmpty() },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
||||
key = getRefreshKey(cacheKey, semester, start, end)
|
||||
|
@ -4,8 +4,12 @@ import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.*
|
||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||
import io.github.wulkanowy.utils.getRefreshKey
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -28,6 +32,7 @@ class AttendanceSummaryRepository @Inject constructor(
|
||||
forceRefresh: Boolean,
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it.isEmpty() },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||
it.isEmpty() || forceRefresh || isExpired
|
||||
|
@ -4,6 +4,7 @@ import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
@ -30,6 +31,7 @@ class CompletedLessonsRepository @Inject constructor(
|
||||
forceRefresh: Boolean,
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it.isEmpty() },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
||||
key = getRefreshKey(cacheKey, semester, start, end)
|
||||
|
@ -5,8 +5,12 @@ import io.github.wulkanowy.data.db.entities.Conference
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.*
|
||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||
import io.github.wulkanowy.utils.getRefreshKey
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import java.time.Instant
|
||||
@ -32,6 +36,7 @@ class ConferenceRepository @Inject constructor(
|
||||
startDate: Instant = Instant.EPOCH,
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it.isEmpty() },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||
it.isEmpty() || forceRefresh || isExpired
|
||||
|
@ -5,6 +5,7 @@ import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@ -33,6 +34,7 @@ class ExamRepository @Inject constructor(
|
||||
notify: Boolean = false,
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it.isEmpty() },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
||||
key = getRefreshKey(cacheKey, semester, start, end)
|
||||
|
@ -7,6 +7,7 @@ import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@ -36,6 +37,10 @@ class GradeRepository @Inject constructor(
|
||||
notify: Boolean = false,
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = {
|
||||
//When details is empty and summary is not, app will not use summary cache - edge case
|
||||
it.first.isEmpty()
|
||||
},
|
||||
shouldFetch = { (details, summaries) ->
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||
details.isEmpty() || summaries.isEmpty() || forceRefresh || isExpired
|
||||
|
@ -11,8 +11,12 @@ import io.github.wulkanowy.data.mappers.mapPartialToStatisticItems
|
||||
import io.github.wulkanowy.data.mappers.mapPointsToStatisticsItems
|
||||
import io.github.wulkanowy.data.mappers.mapSemesterToStatisticItems
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.*
|
||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||
import io.github.wulkanowy.utils.getRefreshKey
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
@ -42,6 +46,7 @@ class GradeStatisticsRepository @Inject constructor(
|
||||
forceRefresh: Boolean,
|
||||
) = networkBoundResource(
|
||||
mutex = partialMutex,
|
||||
isResultEmpty = { it.isEmpty() },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
||||
key = getRefreshKey(partialCacheKey, semester)
|
||||
@ -63,20 +68,16 @@ class GradeStatisticsRepository @Inject constructor(
|
||||
mapResult = { items ->
|
||||
when (subjectName) {
|
||||
"Wszystkie" -> {
|
||||
val numerator = items.map {
|
||||
it.classAverage.replace(",", ".").toDoubleOrNull() ?: .0
|
||||
}.filterNot { it == .0 }
|
||||
(items.reversed() + GradePartialStatistics(
|
||||
val summaryItem = GradePartialStatistics(
|
||||
studentId = semester.studentId,
|
||||
semesterId = semester.semesterId,
|
||||
subject = subjectName,
|
||||
classAverage = if (numerator.isEmpty()) "" else numerator.average().let {
|
||||
"%.2f".format(Locale.FRANCE, it)
|
||||
},
|
||||
studentAverage = "",
|
||||
classAverage = items.map { it.classAverage }.getSummaryAverage(),
|
||||
studentAverage = items.map { it.studentAverage }.getSummaryAverage(),
|
||||
classAmounts = items.map { it.classAmounts }.sumGradeAmounts(),
|
||||
studentAmounts = items.map { it.studentAmounts }.sumGradeAmounts()
|
||||
)).reversed()
|
||||
)
|
||||
listOf(summaryItem) + items
|
||||
}
|
||||
else -> items.filter { it.subject == subjectName }
|
||||
}.mapPartialToStatisticItems()
|
||||
@ -90,6 +91,7 @@ class GradeStatisticsRepository @Inject constructor(
|
||||
forceRefresh: Boolean,
|
||||
) = networkBoundResource(
|
||||
mutex = semesterMutex,
|
||||
isResultEmpty = { it.isEmpty() },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
||||
key = getRefreshKey(semesterCacheKey, semester)
|
||||
@ -112,29 +114,29 @@ class GradeStatisticsRepository @Inject constructor(
|
||||
val itemsWithAverage = items.map { item ->
|
||||
item.copy().apply {
|
||||
val denominator = item.amounts.sum()
|
||||
average = if (denominator == 0) "" else {
|
||||
classAverage = if (denominator == 0) "" else {
|
||||
(item.amounts.mapIndexed { gradeValue, amount ->
|
||||
(gradeValue + 1) * amount
|
||||
}.sum().toDouble() / denominator).let {
|
||||
"%.2f".format(Locale.FRANCE, it)
|
||||
}
|
||||
}.sum().toDouble() / denominator).asAverageString()
|
||||
}
|
||||
}
|
||||
}
|
||||
when (subjectName) {
|
||||
"Wszystkie" -> (itemsWithAverage.reversed() + GradeSemesterStatistics(
|
||||
studentId = semester.studentId,
|
||||
semesterId = semester.semesterId,
|
||||
subject = subjectName,
|
||||
amounts = itemsWithAverage.map { it.amounts }.sumGradeAmounts(),
|
||||
studentGrade = 0
|
||||
).apply {
|
||||
average = itemsWithAverage.mapNotNull {
|
||||
it.average.replace(",", ".").toDoubleOrNull()
|
||||
}.average().let {
|
||||
"%.2f".format(Locale.FRANCE, it)
|
||||
"Wszystkie" -> {
|
||||
val summaryItem = GradeSemesterStatistics(
|
||||
studentId = semester.studentId,
|
||||
semesterId = semester.semesterId,
|
||||
subject = subjectName,
|
||||
amounts = itemsWithAverage.map { it.amounts }.sumGradeAmounts(),
|
||||
studentGrade = 0,
|
||||
).apply {
|
||||
classAverage = itemsWithAverage.map { it.classAverage }.getSummaryAverage()
|
||||
studentAverage = items
|
||||
.mapNotNull { summary -> summary.studentGrade.takeIf { it != 0 } }
|
||||
.average().asAverageString()
|
||||
}
|
||||
}).reversed()
|
||||
listOf(summaryItem) + itemsWithAverage
|
||||
}
|
||||
else -> itemsWithAverage.filter { it.subject == subjectName }
|
||||
}.mapSemesterToStatisticItems()
|
||||
}
|
||||
@ -147,6 +149,7 @@ class GradeStatisticsRepository @Inject constructor(
|
||||
forceRefresh: Boolean,
|
||||
) = networkBoundResource(
|
||||
mutex = pointsMutex,
|
||||
isResultEmpty = { it.isEmpty() },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(pointsCacheKey, semester))
|
||||
it.isEmpty() || forceRefresh || isExpired
|
||||
@ -171,6 +174,19 @@ class GradeStatisticsRepository @Inject constructor(
|
||||
}
|
||||
)
|
||||
|
||||
private fun List<String>.getSummaryAverage(): String {
|
||||
val averages = mapNotNull {
|
||||
it.replace(",", ".").toDoubleOrNull()
|
||||
}
|
||||
|
||||
return averages.average()
|
||||
.asAverageString()
|
||||
.takeIf { averages.isNotEmpty() }
|
||||
.orEmpty()
|
||||
}
|
||||
|
||||
private fun Double.asAverageString(): String = "%.2f".format(Locale.FRANCE, this)
|
||||
|
||||
private fun List<List<Int>>.sumGradeAmounts(): List<Int> {
|
||||
val result = mutableListOf(0, 0, 0, 0, 0, 0)
|
||||
forEach {
|
||||
|
@ -5,6 +5,7 @@ import io.github.wulkanowy.data.db.entities.Homework
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
@ -32,6 +33,7 @@ class HomeworkRepository @Inject constructor(
|
||||
notify: Boolean = false,
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it.isEmpty() },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
||||
key = getRefreshKey(cacheKey, semester, start, end)
|
||||
|
@ -4,9 +4,9 @@ import io.github.wulkanowy.data.db.dao.LuckyNumberDao
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.mappers.mapToEntity
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.github.wulkanowy.utils.networkBoundResource
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
@ -29,6 +29,7 @@ class LuckyNumberRepository @Inject constructor(
|
||||
notify: Boolean = false,
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it == null },
|
||||
shouldFetch = { it == null || forceRefresh },
|
||||
query = { luckyNumberDb.load(student.studentId, now()) },
|
||||
fetch = {
|
||||
|
@ -7,15 +7,12 @@ import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.*
|
||||
import io.github.wulkanowy.data.enums.MessageFolder
|
||||
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.data.networkBoundResource
|
||||
import io.github.wulkanowy.data.pojos.MessageDraft
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.sdk.pojo.Folder
|
||||
@ -23,7 +20,6 @@ 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.networkBoundResource
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
@ -59,6 +55,7 @@ class MessageRepository @Inject constructor(
|
||||
notify: Boolean = false,
|
||||
): Flow<Resource<List<Message>>> = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it.isEmpty() },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
||||
key = getRefreshKey(cacheKey, student, folder)
|
||||
@ -106,8 +103,9 @@ class MessageRepository @Inject constructor(
|
||||
message: Message,
|
||||
markAsRead: Boolean = false,
|
||||
): Flow<Resource<MessageWithAttachment?>> = networkBoundResource(
|
||||
isResultEmpty = { it?.message?.content.isNullOrBlank() },
|
||||
shouldFetch = {
|
||||
checkNotNull(it, { "This message no longer exist!" })
|
||||
checkNotNull(it) { "This message no longer exist!" }
|
||||
Timber.d("Message content in db empty: ${it.message.content.isEmpty()}")
|
||||
it.message.unread || it.message.content.isEmpty()
|
||||
},
|
||||
@ -123,7 +121,7 @@ class MessageRepository @Inject constructor(
|
||||
}
|
||||
},
|
||||
saveFetchResult = { old, (downloadedMessage, attachments) ->
|
||||
checkNotNull(old, { "Fetched message no longer exist!" })
|
||||
checkNotNull(old) { "Fetched message no longer exist!" }
|
||||
messagesDb.updateAll(listOf(old.message.apply {
|
||||
id = old.message.id
|
||||
unread = !markAsRead
|
||||
@ -153,20 +151,27 @@ class MessageRepository @Inject constructor(
|
||||
recipients = recipients.mapFromEntities()
|
||||
)
|
||||
|
||||
suspend fun deleteMessage(student: Student, message: Message) {
|
||||
val isDeleted = sdk.init(student).deleteMessages(
|
||||
messages = listOf(message.messageId), message.folderId
|
||||
)
|
||||
suspend fun deleteMessages(student: Student, messages: List<Message>) {
|
||||
val folderId = messages.first().folderId
|
||||
val isDeleted = sdk.init(student)
|
||||
.deleteMessages(messages = messages.map { it.messageId }, folderId = folderId)
|
||||
|
||||
if (message.folderId != MessageFolder.TRASHED.id && isDeleted) {
|
||||
val deletedMessage = message.copy(folderId = MessageFolder.TRASHED.id).apply {
|
||||
id = message.id
|
||||
content = message.content
|
||||
if (folderId != MessageFolder.TRASHED.id && isDeleted) {
|
||||
val deletedMessages = messages.map {
|
||||
it.copy(folderId = MessageFolder.TRASHED.id)
|
||||
.apply {
|
||||
id = it.id
|
||||
content = it.content
|
||||
}
|
||||
}
|
||||
messagesDb.updateAll(listOf(deletedMessage))
|
||||
} else messagesDb.deleteAll(listOf(message))
|
||||
|
||||
messagesDb.updateAll(deletedMessages)
|
||||
} else messagesDb.deleteAll(messages)
|
||||
}
|
||||
|
||||
suspend fun deleteMessage(student: Student, message: Message) =
|
||||
deleteMessages(student, listOf(message))
|
||||
|
||||
var draftMessage: MessageDraft?
|
||||
get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_send_draft))
|
||||
?.let { json.decodeFromString(it) }
|
||||
|
@ -6,9 +6,13 @@ import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.mappers.mapToMobileDeviceToken
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.data.pojos.MobileDeviceToken
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.*
|
||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||
import io.github.wulkanowy.utils.getRefreshKey
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -30,6 +34,7 @@ class MobileDeviceRepository @Inject constructor(
|
||||
forceRefresh: Boolean,
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it.isEmpty() },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
|
||||
it.isEmpty() || forceRefresh || isExpired
|
||||
|
@ -5,6 +5,7 @@ import io.github.wulkanowy.data.db.entities.Note
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@ -30,6 +31,7 @@ class NoteRepository @Inject constructor(
|
||||
notify: Boolean = false,
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it.isEmpty() },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
||||
getRefreshKey(cacheKey, semester)
|
||||
|
@ -4,11 +4,11 @@ import io.github.wulkanowy.data.db.dao.SchoolAnnouncementDao
|
||||
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
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.networkBoundResource
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
@ -31,6 +31,7 @@ class SchoolAnnouncementRepository @Inject constructor(
|
||||
forceRefresh: Boolean, notify: Boolean = false
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it.isEmpty() },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
|
||||
it.isEmpty() || forceRefresh || isExpired
|
||||
|
@ -4,11 +4,11 @@ import io.github.wulkanowy.data.db.dao.SchoolDao
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.mappers.mapToEntity
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
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.networkBoundResource
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -30,6 +30,7 @@ class SchoolRepository @Inject constructor(
|
||||
forceRefresh: Boolean,
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it == null },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
||||
key = getRefreshKey(cacheKey, student)
|
||||
|
@ -4,9 +4,9 @@ import io.github.wulkanowy.data.db.dao.StudentInfoDao
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.mappers.mapToEntity
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.github.wulkanowy.utils.networkBoundResource
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -25,6 +25,7 @@ class StudentInfoRepository @Inject constructor(
|
||||
forceRefresh: Boolean,
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it == null },
|
||||
shouldFetch = { it == null || forceRefresh },
|
||||
query = { studentInfoDao.loadStudentInfo(student.studentId) },
|
||||
fetch = {
|
||||
|
@ -73,6 +73,15 @@ class StudentRepository @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getSavedStudentById(id: Long, decryptPass: Boolean = true) =
|
||||
studentDb.loadStudentWithSemestersById(id)?.apply {
|
||||
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
|
||||
student.password = withContext(dispatchers.io) {
|
||||
decrypt(student.password)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getStudentById(id: Long, decryptPass: Boolean = true): Student {
|
||||
val student = studentDb.loadById(id) ?: throw NoCurrentStudentException()
|
||||
|
||||
|
@ -4,8 +4,12 @@ import io.github.wulkanowy.data.db.dao.SubjectDao
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.*
|
||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||
import io.github.wulkanowy.utils.getRefreshKey
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -27,6 +31,7 @@ class SubjectRepository @Inject constructor(
|
||||
forceRefresh: Boolean = false,
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it.isEmpty() },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||
it.isEmpty() || forceRefresh || isExpired
|
||||
|
@ -4,8 +4,12 @@ import io.github.wulkanowy.data.db.dao.TeacherDao
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.*
|
||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||
import io.github.wulkanowy.utils.getRefreshKey
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -27,6 +31,7 @@ class TeacherRepository @Inject constructor(
|
||||
forceRefresh: Boolean,
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it.isEmpty() },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||
it.isEmpty() || forceRefresh || isExpired
|
||||
|
@ -5,6 +5,7 @@ import io.github.wulkanowy.data.db.dao.TimetableDao
|
||||
import io.github.wulkanowy.data.db.dao.TimetableHeaderDao
|
||||
import io.github.wulkanowy.data.db.entities.*
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.data.pojos.TimetableFull
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
|
||||
@ -30,6 +31,10 @@ class TimetableRepository @Inject constructor(
|
||||
|
||||
private val cacheKey = "timetable"
|
||||
|
||||
enum class TimetableType {
|
||||
NORMAL, ADDITIONAL
|
||||
}
|
||||
|
||||
fun getTimetable(
|
||||
student: Student,
|
||||
semester: Semester,
|
||||
@ -37,9 +42,16 @@ class TimetableRepository @Inject constructor(
|
||||
end: LocalDate,
|
||||
forceRefresh: Boolean,
|
||||
refreshAdditional: Boolean = false,
|
||||
notify: Boolean = false
|
||||
notify: Boolean = false,
|
||||
timetableType: TimetableType = TimetableType.NORMAL
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = {
|
||||
when (timetableType) {
|
||||
TimetableType.NORMAL -> it.lessons.isEmpty()
|
||||
TimetableType.ADDITIONAL -> it.additional.isEmpty()
|
||||
}
|
||||
},
|
||||
shouldFetch = { (timetable, additional, headers) ->
|
||||
val refreshKey = getRefreshKey(cacheKey, semester, start, end)
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(refreshKey)
|
||||
|
@ -0,0 +1,32 @@
|
||||
package io.github.wulkanowy.data.serializers
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.nullable
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import java.time.LocalDate
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
object LocalDateSerializer : KSerializer<LocalDate?> {
|
||||
|
||||
override val descriptor = PrimitiveSerialDescriptor("LocalDate", PrimitiveKind.LONG).nullable
|
||||
|
||||
override fun serialize(encoder: Encoder, value: LocalDate?) {
|
||||
if (value == null) {
|
||||
encoder.encodeNull()
|
||||
} else {
|
||||
encoder.encodeNotNullMark()
|
||||
encoder.encodeLong(value.toEpochDay())
|
||||
}
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): LocalDate? =
|
||||
if (decoder.decodeNotNullMark()) {
|
||||
LocalDate.ofEpochDay(decoder.decodeLong())
|
||||
} else {
|
||||
decoder.decodeNull()
|
||||
}
|
||||
}
|
@ -10,19 +10,18 @@ import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.onResourceError
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.services.sync.channels.UpcomingLessonsChannel.Companion.CHANNEL_ID
|
||||
import io.github.wulkanowy.ui.modules.Destination
|
||||
import io.github.wulkanowy.ui.modules.splash.SplashActivity
|
||||
import io.github.wulkanowy.utils.PendingIntentCompat
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.getCompatColor
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -59,7 +58,7 @@ class TimetableNotificationReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
Timber.d("Receiving intent... ${intent.toUri(0)}")
|
||||
|
||||
flowWithResource {
|
||||
resourceFlow {
|
||||
val showStudentName = !studentRepository.isOneUniqueStudent()
|
||||
val student = studentRepository.getCurrentStudent(false)
|
||||
val studentId = intent.getIntExtra(STUDENT_ID, 0)
|
||||
@ -69,9 +68,9 @@ class TimetableNotificationReceiver : BroadcastReceiver() {
|
||||
} else {
|
||||
Timber.d("Notification studentId($studentId) differs from current(${student.studentId})")
|
||||
}
|
||||
}.onEach {
|
||||
if (it.status == Status.ERROR) Timber.e(it.error!!)
|
||||
}.launchIn(GlobalScope)
|
||||
}
|
||||
.onResourceError { Timber.e(it) }
|
||||
.launchIn(GlobalScope)
|
||||
}
|
||||
|
||||
private fun prepareNotification(context: Context, intent: Intent, showStudentName: Boolean) {
|
||||
|
@ -15,6 +15,9 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
class ShortcutsHelper @Inject constructor(@ApplicationContext private val context: Context) {
|
||||
|
||||
// Destination cannot be used here as shortcuts
|
||||
// require their intents to only use primitive types (see PersistableBundle.isValidType).
|
||||
|
||||
private val destinations = mapOf(
|
||||
"grade" to Destination.Grade,
|
||||
"attendance" to Destination.Attendance,
|
||||
|
@ -14,6 +14,7 @@ import io.github.wulkanowy.data.pojos.GroupNotificationData
|
||||
import io.github.wulkanowy.data.pojos.NotificationData
|
||||
import io.github.wulkanowy.data.repositories.NotificationRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.modules.splash.SplashActivity
|
||||
import io.github.wulkanowy.utils.PendingIntentCompat
|
||||
import io.github.wulkanowy.utils.getCompatBitmap
|
||||
import io.github.wulkanowy.utils.getCompatColor
|
||||
@ -47,7 +48,7 @@ class AppNotificationManager @Inject constructor(
|
||||
PendingIntent.getActivity(
|
||||
context,
|
||||
Random.nextInt(),
|
||||
notificationData.intentToStart,
|
||||
SplashActivity.getStartIntent(context, notificationData.destination),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||
)
|
||||
)
|
||||
@ -92,7 +93,7 @@ class AppNotificationManager @Inject constructor(
|
||||
PendingIntent.getActivity(
|
||||
context,
|
||||
Random.nextInt(),
|
||||
notificationData.intentToStart,
|
||||
SplashActivity.getStartIntent(context, notificationData.destination),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||
)
|
||||
)
|
||||
@ -146,7 +147,7 @@ class AppNotificationManager @Inject constructor(
|
||||
PendingIntent.getActivity(
|
||||
context,
|
||||
Random.nextInt(),
|
||||
groupNotificationData.intentToStart,
|
||||
SplashActivity.getStartIntent(context, groupNotificationData.destination),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||
)
|
||||
)
|
||||
@ -168,6 +169,7 @@ class AppNotificationManager @Inject constructor(
|
||||
studentId = student.id,
|
||||
title = notificationData.title,
|
||||
content = notificationData.content,
|
||||
destination = notificationData.destination,
|
||||
type = notificationType,
|
||||
date = Instant.now(),
|
||||
)
|
||||
|
@ -8,7 +8,6 @@ import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.pojos.GroupNotificationData
|
||||
import io.github.wulkanowy.data.pojos.NotificationData
|
||||
import io.github.wulkanowy.ui.modules.Destination
|
||||
import io.github.wulkanowy.ui.modules.splash.SplashActivity
|
||||
import io.github.wulkanowy.utils.getPlural
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import java.time.Instant
|
||||
@ -23,8 +22,9 @@ class ChangeTimetableNotification @Inject constructor(
|
||||
suspend fun notify(items: List<Timetable>, student: Student) {
|
||||
val currentTime = Instant.now()
|
||||
val changedLessons = items.filter { (it.canceled || it.changes) && it.start > currentTime }
|
||||
val notificationDataList = changedLessons.groupBy { it.date }
|
||||
.map { (date, lessons) ->
|
||||
val lessonsByDate = changedLessons.groupBy { it.date }
|
||||
val notificationDataList = lessonsByDate
|
||||
.flatMap { (date, lessons) ->
|
||||
getNotificationContents(date, lessons).map {
|
||||
NotificationData(
|
||||
title = context.getPlural(
|
||||
@ -32,14 +32,10 @@ class ChangeTimetableNotification @Inject constructor(
|
||||
1
|
||||
),
|
||||
content = it,
|
||||
intentToStart = SplashActivity.getStartIntent(
|
||||
context = context,
|
||||
destination = Destination.Timetable(date)
|
||||
)
|
||||
destination = Destination.Timetable(date)
|
||||
)
|
||||
}
|
||||
}
|
||||
.flatten()
|
||||
.ifEmpty { return }
|
||||
|
||||
val groupNotificationData = GroupNotificationData(
|
||||
@ -53,7 +49,7 @@ class ChangeTimetableNotification @Inject constructor(
|
||||
changedLessons.size,
|
||||
changedLessons.size
|
||||
),
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Timetable()),
|
||||
destination = Destination.Timetable(lessonsByDate.toSortedMap().firstKey()),
|
||||
type = NotificationType.CHANGE_TIMETABLE
|
||||
)
|
||||
|
||||
|
@ -31,7 +31,7 @@ class NewAttendanceNotification @Inject constructor(
|
||||
NotificationData(
|
||||
title = context.getPlural(R.plurals.attendance_notify_new_items_title, 1),
|
||||
content = it,
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Attendance)
|
||||
destination = Destination.Attendance
|
||||
)
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ class NewAttendanceNotification @Inject constructor(
|
||||
notificationDataList.size,
|
||||
notificationDataList.size
|
||||
),
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Attendance),
|
||||
destination = Destination.Attendance,
|
||||
type = NotificationType.NEW_ATTENDANCE
|
||||
)
|
||||
|
||||
|
@ -31,7 +31,7 @@ class NewConferenceNotification @Inject constructor(
|
||||
NotificationData(
|
||||
title = context.getPlural(R.plurals.conference_notify_new_item_title, 1),
|
||||
content = it,
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Conference)
|
||||
destination = Destination.Conference
|
||||
)
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ class NewConferenceNotification @Inject constructor(
|
||||
lines.size,
|
||||
lines.size
|
||||
),
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Conference),
|
||||
destination = Destination.Conference,
|
||||
type = NotificationType.NEW_CONFERENCE
|
||||
)
|
||||
|
||||
|
@ -31,7 +31,7 @@ class NewExamNotification @Inject constructor(
|
||||
NotificationData(
|
||||
title = context.getPlural(R.plurals.exam_notify_new_item_title, 1),
|
||||
content = it,
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Exam),
|
||||
destination = Destination.Exam,
|
||||
)
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ class NewExamNotification @Inject constructor(
|
||||
lines.size,
|
||||
lines.size
|
||||
),
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Exam),
|
||||
destination = Destination.Exam,
|
||||
type = NotificationType.NEW_EXAM
|
||||
)
|
||||
|
||||
|
@ -26,7 +26,7 @@ class NewGradeNotification @Inject constructor(
|
||||
append("${it.subject}: ${it.entry}")
|
||||
if (it.comment.isNotBlank()) append(" (${it.comment})")
|
||||
},
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Grade),
|
||||
destination = Destination.Grade,
|
||||
)
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ class NewGradeNotification @Inject constructor(
|
||||
notificationDataList = notificationDataList,
|
||||
title = context.getPlural(R.plurals.grade_new_items, items.size),
|
||||
content = context.getPlural(R.plurals.grade_notify_new_items, items.size, items.size),
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Grade),
|
||||
destination = Destination.Grade,
|
||||
type = NotificationType.NEW_GRADE_DETAILS
|
||||
)
|
||||
|
||||
@ -46,7 +46,7 @@ class NewGradeNotification @Inject constructor(
|
||||
NotificationData(
|
||||
title = context.getPlural(R.plurals.grade_new_items_predicted, 1),
|
||||
content = "${it.subject}: ${it.predictedGrade}",
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Grade),
|
||||
destination = Destination.Grade,
|
||||
)
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ class NewGradeNotification @Inject constructor(
|
||||
items.size,
|
||||
items.size
|
||||
),
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Grade),
|
||||
destination = Destination.Grade,
|
||||
type = NotificationType.NEW_GRADE_PREDICTED
|
||||
)
|
||||
|
||||
@ -70,7 +70,7 @@ class NewGradeNotification @Inject constructor(
|
||||
NotificationData(
|
||||
title = context.getPlural(R.plurals.grade_new_items_final, 1),
|
||||
content = "${it.subject}: ${it.finalGrade}",
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Grade),
|
||||
destination = Destination.Grade,
|
||||
)
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ class NewGradeNotification @Inject constructor(
|
||||
items.size,
|
||||
items.size
|
||||
),
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Grade),
|
||||
destination = Destination.Grade,
|
||||
type = NotificationType.NEW_GRADE_FINAL
|
||||
)
|
||||
|
||||
|
@ -31,7 +31,7 @@ class NewHomeworkNotification @Inject constructor(
|
||||
NotificationData(
|
||||
title = context.getPlural(R.plurals.homework_notify_new_item_title, 1),
|
||||
content = it,
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Homework),
|
||||
destination = Destination.Homework,
|
||||
)
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ class NewHomeworkNotification @Inject constructor(
|
||||
lines.size,
|
||||
lines.size
|
||||
),
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Homework),
|
||||
destination = Destination.Homework,
|
||||
type = NotificationType.NEW_HOMEWORK,
|
||||
notificationDataList = notificationDataList
|
||||
)
|
||||
|
@ -22,7 +22,7 @@ class NewLuckyNumberNotification @Inject constructor(
|
||||
R.string.lucky_number_notify_new_item,
|
||||
item.luckyNumber.toString()
|
||||
),
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.LuckyNumber)
|
||||
destination = Destination.LuckyNumber
|
||||
)
|
||||
|
||||
appNotificationManager.sendSingleNotification(
|
||||
|
@ -22,7 +22,7 @@ class NewMessageNotification @Inject constructor(
|
||||
NotificationData(
|
||||
title = context.getPlural(R.plurals.message_new_items, 1),
|
||||
content = "${it.sender}: ${it.subject}",
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Message),
|
||||
destination = Destination.Message,
|
||||
)
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ class NewMessageNotification @Inject constructor(
|
||||
notificationDataList = notificationDataList,
|
||||
title = context.getPlural(R.plurals.message_new_items, items.size),
|
||||
content = context.getPlural(R.plurals.message_notify_new_items, items.size, items.size),
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Message),
|
||||
destination = Destination.Message,
|
||||
type = NotificationType.NEW_MESSAGE
|
||||
)
|
||||
|
||||
|
@ -29,13 +29,13 @@ class NewNoteNotification @Inject constructor(
|
||||
NotificationData(
|
||||
title = context.getPlural(titleRes, 1),
|
||||
content = "${it.teacher}: ${it.category}",
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Note),
|
||||
destination = Destination.Note,
|
||||
)
|
||||
}
|
||||
|
||||
val groupNotificationData = GroupNotificationData(
|
||||
notificationDataList = notificationDataList,
|
||||
intentToStart = SplashActivity.getStartIntent(context, Destination.Note),
|
||||
destination = Destination.Note,
|
||||
title = context.getPlural(R.plurals.note_new_items, items.size),
|
||||
content = context.getPlural(R.plurals.note_notify_new_items, items.size, items.size),
|
||||
type = NotificationType.NEW_NOTE
|
||||
|
@ -21,10 +21,7 @@ class NewSchoolAnnouncementNotification @Inject constructor(
|
||||
suspend fun notify(items: List<SchoolAnnouncement>, student: Student) {
|
||||
val notificationDataList = items.map {
|
||||
NotificationData(
|
||||
intentToStart = SplashActivity.getStartIntent(
|
||||
context = context,
|
||||
destination = Destination.SchoolAnnouncement
|
||||
),
|
||||
destination = Destination.SchoolAnnouncement,
|
||||
title = context.getPlural(
|
||||
R.plurals.school_announcement_notify_new_item_title,
|
||||
1
|
||||
@ -34,10 +31,7 @@ class NewSchoolAnnouncementNotification @Inject constructor(
|
||||
}
|
||||
val groupNotificationData = GroupNotificationData(
|
||||
type = NotificationType.NEW_ANNOUNCEMENT,
|
||||
intentToStart = SplashActivity.getStartIntent(
|
||||
context = context,
|
||||
destination = Destination.SchoolAnnouncement
|
||||
),
|
||||
destination = Destination.SchoolAnnouncement,
|
||||
title = context.getPlural(
|
||||
R.plurals.school_announcement_notify_new_item_title,
|
||||
items.size
|
||||
|
@ -3,7 +3,7 @@ package io.github.wulkanowy.services.sync.works
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.AttendanceSummaryRepository
|
||||
import io.github.wulkanowy.utils.waitForResult
|
||||
import io.github.wulkanowy.data.waitForResult
|
||||
import javax.inject.Inject
|
||||
|
||||
class AttendanceSummaryWork @Inject constructor(
|
||||
|
@ -3,9 +3,9 @@ package io.github.wulkanowy.services.sync.works
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.AttendanceRepository
|
||||
import io.github.wulkanowy.data.waitForResult
|
||||
import io.github.wulkanowy.services.sync.notifications.NewAttendanceNotification
|
||||
import io.github.wulkanowy.utils.previousOrSameSchoolDay
|
||||
import io.github.wulkanowy.utils.waitForResult
|
||||
import kotlinx.coroutines.flow.first
|
||||
import java.time.LocalDate.now
|
||||
import javax.inject.Inject
|
||||
|
@ -3,9 +3,9 @@ package io.github.wulkanowy.services.sync.works
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.CompletedLessonsRepository
|
||||
import io.github.wulkanowy.data.waitForResult
|
||||
import io.github.wulkanowy.utils.monday
|
||||
import io.github.wulkanowy.utils.sunday
|
||||
import io.github.wulkanowy.utils.waitForResult
|
||||
import java.time.LocalDate.now
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -3,8 +3,8 @@ package io.github.wulkanowy.services.sync.works
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.ConferenceRepository
|
||||
import io.github.wulkanowy.data.waitForResult
|
||||
import io.github.wulkanowy.services.sync.notifications.NewConferenceNotification
|
||||
import io.github.wulkanowy.utils.waitForResult
|
||||
import kotlinx.coroutines.flow.first
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -3,8 +3,8 @@ package io.github.wulkanowy.services.sync.works
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.ExamRepository
|
||||
import io.github.wulkanowy.data.waitForResult
|
||||
import io.github.wulkanowy.services.sync.notifications.NewExamNotification
|
||||
import io.github.wulkanowy.utils.waitForResult
|
||||
import kotlinx.coroutines.flow.first
|
||||
import java.time.LocalDate.now
|
||||
import javax.inject.Inject
|
||||
|
@ -3,7 +3,8 @@ package io.github.wulkanowy.services.sync.works
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.GradeStatisticsRepository
|
||||
import io.github.wulkanowy.utils.waitForResult
|
||||
import io.github.wulkanowy.data.waitForResult
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class GradeStatisticsWork @Inject constructor(
|
||||
|
@ -3,8 +3,8 @@ package io.github.wulkanowy.services.sync.works
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.GradeRepository
|
||||
import io.github.wulkanowy.data.waitForResult
|
||||
import io.github.wulkanowy.services.sync.notifications.NewGradeNotification
|
||||
import io.github.wulkanowy.utils.waitForResult
|
||||
import kotlinx.coroutines.flow.first
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -3,9 +3,9 @@ package io.github.wulkanowy.services.sync.works
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.HomeworkRepository
|
||||
import io.github.wulkanowy.data.waitForResult
|
||||
import io.github.wulkanowy.services.sync.notifications.NewHomeworkNotification
|
||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||
import io.github.wulkanowy.utils.waitForResult
|
||||
import kotlinx.coroutines.flow.first
|
||||
import java.time.LocalDate.now
|
||||
import javax.inject.Inject
|
||||
|
@ -3,8 +3,8 @@ package io.github.wulkanowy.services.sync.works
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
|
||||
import io.github.wulkanowy.data.waitForResult
|
||||
import io.github.wulkanowy.services.sync.notifications.NewLuckyNumberNotification
|
||||
import io.github.wulkanowy.utils.waitForResult
|
||||
import javax.inject.Inject
|
||||
|
||||
class LuckyNumberWork @Inject constructor(
|
||||
|
@ -4,8 +4,8 @@ import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
|
||||
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||
import io.github.wulkanowy.data.waitForResult
|
||||
import io.github.wulkanowy.services.sync.notifications.NewMessageNotification
|
||||
import io.github.wulkanowy.utils.waitForResult
|
||||
import kotlinx.coroutines.flow.first
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -3,8 +3,8 @@ package io.github.wulkanowy.services.sync.works
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.NoteRepository
|
||||
import io.github.wulkanowy.data.waitForResult
|
||||
import io.github.wulkanowy.services.sync.notifications.NewNoteNotification
|
||||
import io.github.wulkanowy.utils.waitForResult
|
||||
import kotlinx.coroutines.flow.first
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -3,8 +3,8 @@ package io.github.wulkanowy.services.sync.works
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.SchoolAnnouncementRepository
|
||||
import io.github.wulkanowy.data.waitForResult
|
||||
import io.github.wulkanowy.services.sync.notifications.NewSchoolAnnouncementNotification
|
||||
import io.github.wulkanowy.utils.waitForResult
|
||||
import kotlinx.coroutines.flow.first
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -3,7 +3,8 @@ package io.github.wulkanowy.services.sync.works
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.TeacherRepository
|
||||
import io.github.wulkanowy.utils.waitForResult
|
||||
import io.github.wulkanowy.data.waitForResult
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class TeacherWork @Inject constructor(private val teacherRepository: TeacherRepository) : Work {
|
||||
|
@ -3,9 +3,9 @@ package io.github.wulkanowy.services.sync.works
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
import io.github.wulkanowy.data.waitForResult
|
||||
import io.github.wulkanowy.services.sync.notifications.ChangeTimetableNotification
|
||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||
import io.github.wulkanowy.utils.waitForResult
|
||||
import kotlinx.coroutines.flow.first
|
||||
import java.time.LocalDate.now
|
||||
import javax.inject.Inject
|
||||
|
@ -1,17 +1,10 @@
|
||||
package io.github.wulkanowy.ui.base
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.cancelChildren
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
|
||||
open class BasePresenter<T : BaseView>(
|
||||
@ -37,28 +30,28 @@ open class BasePresenter<T : BaseView>(
|
||||
}
|
||||
|
||||
fun onExpiredLoginSelected() {
|
||||
flowWithResource {
|
||||
val student = studentRepository.getCurrentStudent(false)
|
||||
studentRepository.logoutStudent(student)
|
||||
Timber.i("Attempt to switch the student after the session expires")
|
||||
|
||||
val students = studentRepository.getSavedStudents(false)
|
||||
if (students.isNotEmpty()) {
|
||||
Timber.i("Switching current student")
|
||||
studentRepository.switchStudent(students[0])
|
||||
presenterScope.launch {
|
||||
runCatching {
|
||||
val student = studentRepository.getCurrentStudent(false)
|
||||
studentRepository.logoutStudent(student)
|
||||
|
||||
val students = studentRepository.getSavedStudents(false)
|
||||
if (students.isNotEmpty()) {
|
||||
Timber.i("Switching current student")
|
||||
studentRepository.switchStudent(students[0])
|
||||
}
|
||||
}
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Attempt to switch the student after the session expires")
|
||||
Status.SUCCESS -> {
|
||||
.onFailure {
|
||||
Timber.i("Switch student result: An exception occurred")
|
||||
errorHandler.dispatch(it)
|
||||
}
|
||||
.onSuccess {
|
||||
Timber.i("Switch student result: Open login view")
|
||||
view?.openClearLoginView()
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Switch student result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
}
|
||||
}.launch("expired")
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Flow<T>.launch(individualJobTag: String = "load"): Job {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.github.wulkanowy.ui.modules
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import io.github.wulkanowy.data.serializers.LocalDateSerializer
|
||||
import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment
|
||||
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
|
||||
import io.github.wulkanowy.ui.modules.dashboard.DashboardFragment
|
||||
@ -14,18 +15,19 @@ import io.github.wulkanowy.ui.modules.note.NoteFragment
|
||||
import io.github.wulkanowy.ui.modules.schoolandteachers.school.SchoolFragment
|
||||
import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment
|
||||
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
||||
import java.io.Serializable
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.time.LocalDate
|
||||
|
||||
sealed interface Destination : Serializable {
|
||||
@Serializable
|
||||
sealed class Destination private constructor() : java.io.Serializable {
|
||||
|
||||
/*
|
||||
Type in children classes have to be as getter to avoid null in enums
|
||||
https://stackoverflow.com/questions/68866453/kotlin-enum-val-is-returning-null-despite-being-set-at-compile-time
|
||||
*/
|
||||
val type: Type
|
||||
abstract val type: Type
|
||||
|
||||
val fragment: Fragment
|
||||
abstract val fragment: Fragment
|
||||
|
||||
enum class Type(val defaultDestination: Destination) {
|
||||
DASHBOARD(Dashboard),
|
||||
@ -43,94 +45,84 @@ sealed interface Destination : Serializable {
|
||||
MESSAGE(Message);
|
||||
}
|
||||
|
||||
object Dashboard : Destination {
|
||||
|
||||
@Serializable
|
||||
object Dashboard : Destination() {
|
||||
override val type get() = Type.DASHBOARD
|
||||
|
||||
override val fragment get() = DashboardFragment.newInstance()
|
||||
}
|
||||
|
||||
object Grade : Destination {
|
||||
|
||||
@Serializable
|
||||
object Grade : Destination() {
|
||||
override val type get() = Type.GRADE
|
||||
|
||||
override val fragment get() = GradeFragment.newInstance()
|
||||
}
|
||||
|
||||
object Attendance : Destination {
|
||||
|
||||
@Serializable
|
||||
object Attendance : Destination() {
|
||||
override val type get() = Type.ATTENDANCE
|
||||
|
||||
override val fragment get() = AttendanceFragment.newInstance()
|
||||
}
|
||||
|
||||
object Exam : Destination {
|
||||
|
||||
@Serializable
|
||||
object Exam : Destination() {
|
||||
override val type get() = Type.EXAM
|
||||
|
||||
override val fragment get() = ExamFragment.newInstance()
|
||||
}
|
||||
|
||||
data class Timetable(val date: LocalDate? = null) : Destination {
|
||||
|
||||
@Serializable
|
||||
data class Timetable(
|
||||
@Serializable(with = LocalDateSerializer::class)
|
||||
private val date: LocalDate? = null
|
||||
) : Destination() {
|
||||
override val type get() = Type.TIMETABLE
|
||||
|
||||
override val fragment get() = TimetableFragment.newInstance(date)
|
||||
}
|
||||
|
||||
object Homework : Destination {
|
||||
|
||||
@Serializable
|
||||
object Homework : Destination() {
|
||||
override val type get() = Type.HOMEWORK
|
||||
|
||||
override val fragment get() = HomeworkFragment.newInstance()
|
||||
}
|
||||
|
||||
object Note : Destination {
|
||||
|
||||
@Serializable
|
||||
object Note : Destination() {
|
||||
override val type get() = Type.NOTE
|
||||
|
||||
override val fragment get() = NoteFragment.newInstance()
|
||||
}
|
||||
|
||||
object Conference : Destination {
|
||||
|
||||
@Serializable
|
||||
object Conference : Destination() {
|
||||
override val type get() = Type.CONFERENCE
|
||||
|
||||
override val fragment get() = ConferenceFragment.newInstance()
|
||||
}
|
||||
|
||||
object SchoolAnnouncement : Destination {
|
||||
|
||||
@Serializable
|
||||
object SchoolAnnouncement : Destination() {
|
||||
override val type get() = Type.SCHOOL_ANNOUNCEMENT
|
||||
|
||||
override val fragment get() = SchoolAnnouncementFragment.newInstance()
|
||||
}
|
||||
|
||||
object School : Destination {
|
||||
|
||||
@Serializable
|
||||
object School : Destination() {
|
||||
override val type get() = Type.SCHOOL
|
||||
|
||||
override val fragment get() = SchoolFragment.newInstance()
|
||||
}
|
||||
|
||||
object LuckyNumber : Destination {
|
||||
|
||||
@Serializable
|
||||
object LuckyNumber : Destination() {
|
||||
override val type get() = Type.LUCKY_NUMBER
|
||||
|
||||
override val fragment get() = LuckyNumberFragment.newInstance()
|
||||
}
|
||||
|
||||
object More : Destination {
|
||||
|
||||
@Serializable
|
||||
object More : Destination() {
|
||||
override val type get() = Type.MORE
|
||||
|
||||
override val fragment get() = MoreFragment.newInstance()
|
||||
}
|
||||
|
||||
object Message : Destination {
|
||||
|
||||
@Serializable
|
||||
object Message : Destination() {
|
||||
override val type get() = Type.MESSAGE
|
||||
|
||||
override val fragment get() = MessageFragment.newInstance()
|
||||
}
|
||||
}
|
@ -1,13 +1,11 @@
|
||||
package io.github.wulkanowy.ui.modules.about.contributor
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.pojos.Contributor
|
||||
import io.github.wulkanowy.data.repositories.AppCreatorRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import javax.inject.Inject
|
||||
|
||||
class ContributorPresenter @Inject constructor(
|
||||
@ -31,15 +29,11 @@ class ContributorPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
flowWithResource { appCreatorRepository.getAppCreators() }.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> view?.showProgress(true)
|
||||
Status.SUCCESS -> view?.run {
|
||||
showProgress(false)
|
||||
updateData(it.data!!)
|
||||
}
|
||||
Status.ERROR -> errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
}.launch()
|
||||
resourceFlow { appCreatorRepository.getAppCreators() }
|
||||
.onResourceLoading { view?.showProgress(true) }
|
||||
.onResourceSuccess { view?.updateData(it) }
|
||||
.onResourceNotLoading { view?.showProgress(false) }
|
||||
.onResourceError { errorHandler.dispatch(it) }
|
||||
.launch()
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,12 @@
|
||||
package io.github.wulkanowy.ui.modules.about.license
|
||||
|
||||
import com.mikepenz.aboutlibraries.entity.Library
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.DispatchersProvider
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class LicensePresenter @Inject constructor(
|
||||
@ -30,18 +26,16 @@ class LicensePresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
flowWithResource {
|
||||
withContext(dispatchers.io) {
|
||||
view?.appLibraries.orEmpty()
|
||||
presenterScope.launch {
|
||||
runCatching {
|
||||
withContext(dispatchers.io) {
|
||||
view?.appLibraries.orEmpty()
|
||||
}
|
||||
}
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.d("License data load started")
|
||||
Status.SUCCESS -> view?.updateData(it.data!!)
|
||||
Status.ERROR -> errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
}.afterLoading {
|
||||
.onFailure { errorHandler.dispatch(it) }
|
||||
.onSuccess { view?.updateData(it) }
|
||||
|
||||
view?.showProgress(false)
|
||||
}.launch()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
package io.github.wulkanowy.ui.modules.account
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.logResourceStatus
|
||||
import io.github.wulkanowy.data.onResourceError
|
||||
import io.github.wulkanowy.data.onResourceSuccess
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -32,20 +33,10 @@ class AccountPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
flowWithResource { studentRepository.getSavedStudents(false) }
|
||||
.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Loading account data started")
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading account result: Success")
|
||||
view?.updateData(createAccountItems(it.data!!))
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading account result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
resourceFlow { studentRepository.getSavedStudents(false) }
|
||||
.logResourceStatus("load account data")
|
||||
.onResourceSuccess { view?.updateData(createAccountItems(it)) }
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch("load")
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.account.accountdetails
|
||||
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
@ -9,10 +8,6 @@ import io.github.wulkanowy.services.sync.SyncManager
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -51,40 +46,25 @@ class AccountDetailsPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
flowWithResource { studentRepository.getSavedStudents() }
|
||||
.map { studentWithSemesters ->
|
||||
Resource(
|
||||
data = studentWithSemesters.data?.single { it.student.id == studentId },
|
||||
status = studentWithSemesters.status,
|
||||
error = studentWithSemesters.error
|
||||
)
|
||||
}
|
||||
.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
view?.run {
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
}
|
||||
Timber.i("Loading account details view started")
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading account details view result: Success")
|
||||
studentWithSemesters = it.data
|
||||
view?.run {
|
||||
showAccountData(studentWithSemesters!!.student)
|
||||
enableSelectStudentButton(!studentWithSemesters!!.student.isCurrent)
|
||||
showContent(true)
|
||||
showErrorView(false)
|
||||
}
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading account details view result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
resourceFlow { studentRepository.getSavedStudentById(studentId ?: -1) }
|
||||
.logResourceStatus("loading account details view")
|
||||
.onResourceLoading {
|
||||
view?.run {
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
}
|
||||
}
|
||||
.afterLoading { view?.showProgress(false) }
|
||||
.onResourceSuccess {
|
||||
studentWithSemesters = it
|
||||
view?.run {
|
||||
showAccountData(studentWithSemesters!!.student)
|
||||
enableSelectStudentButton(!studentWithSemesters!!.student.isCurrent)
|
||||
showContent(true)
|
||||
showErrorView(false)
|
||||
}
|
||||
}
|
||||
.onResourceNotLoading { view?.showProgress(false) }
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch()
|
||||
}
|
||||
|
||||
@ -105,22 +85,12 @@ class AccountDetailsPresenter @Inject constructor(
|
||||
|
||||
Timber.i("Select student ${studentWithSemesters!!.student.id}")
|
||||
|
||||
flowWithResource { studentRepository.switchStudent(studentWithSemesters!!) }
|
||||
.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Attempt to change a student")
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Change a student result: Success")
|
||||
view?.recreateMainView()
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Change a student result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
}
|
||||
}.afterLoading {
|
||||
view?.popViewToMain()
|
||||
}.launch("switch")
|
||||
resourceFlow { studentRepository.switchStudent(studentWithSemesters!!) }
|
||||
.logResourceStatus("change student")
|
||||
.onResourceSuccess { view?.recreateMainView() }
|
||||
.onResourceNotLoading { view?.popViewToMain() }
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch("switch")
|
||||
}
|
||||
|
||||
fun onRemoveSelected() {
|
||||
@ -131,7 +101,7 @@ class AccountDetailsPresenter @Inject constructor(
|
||||
fun onLogoutConfirm() {
|
||||
if (studentWithSemesters == null) return
|
||||
|
||||
flowWithResource {
|
||||
resourceFlow {
|
||||
val studentToLogout = studentWithSemesters!!.student
|
||||
|
||||
studentRepository.logoutStudent(studentToLogout)
|
||||
@ -141,13 +111,13 @@ class AccountDetailsPresenter @Inject constructor(
|
||||
studentRepository.switchStudent(students[0])
|
||||
}
|
||||
|
||||
return@flowWithResource students
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Attempt to logout user")
|
||||
Status.SUCCESS -> view?.run {
|
||||
students
|
||||
}
|
||||
.logResourceStatus("logout user")
|
||||
.onResourceSuccess {
|
||||
view?.run {
|
||||
when {
|
||||
it.data!!.isEmpty() -> {
|
||||
it.isEmpty() -> {
|
||||
Timber.i("Logout result: Open login view")
|
||||
syncManager.stopSyncWorker()
|
||||
openClearLoginView()
|
||||
@ -162,18 +132,16 @@ class AccountDetailsPresenter @Inject constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Logout result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
.onResourceNotLoading {
|
||||
if (studentWithSemesters?.student?.isCurrent == true) {
|
||||
view?.popViewToMain()
|
||||
} else {
|
||||
view?.popViewToAccounts()
|
||||
}
|
||||
}
|
||||
}.afterLoading {
|
||||
if (studentWithSemesters?.student?.isCurrent == true) {
|
||||
view?.popViewToMain()
|
||||
} else {
|
||||
view?.popViewToAccounts()
|
||||
}
|
||||
}.launch("logout")
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch("logout")
|
||||
}
|
||||
|
||||
private fun showErrorViewOnError(message: String, error: Throwable) {
|
||||
|
@ -1,15 +1,12 @@
|
||||
package io.github.wulkanowy.ui.modules.account.accountedit
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -38,43 +35,26 @@ class AccountEditPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
flowWithResource {
|
||||
studentRepository.getStudentById(student.id, false).avatarColor
|
||||
}.onEach { resource ->
|
||||
when (resource.status) {
|
||||
Status.LOADING -> Timber.i("Attempt to load student")
|
||||
Status.SUCCESS -> {
|
||||
view?.updateSelectedColorData(resource.data?.toInt()!!)
|
||||
Timber.i("Attempt to load student: Success")
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Attempt to load student: An exception occurred")
|
||||
errorHandler.dispatch(resource.error!!)
|
||||
}
|
||||
}
|
||||
}.launch("load_data")
|
||||
resourceFlow { studentRepository.getStudentById(student.id, false).avatarColor }
|
||||
.logResourceStatus("load student")
|
||||
.onResourceSuccess { view?.updateSelectedColorData(it.toInt()) }
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch("load_data")
|
||||
}
|
||||
|
||||
fun changeStudentNickAndAvatar(nick: String, avatarColor: Int) {
|
||||
flowWithResource {
|
||||
val studentNick =
|
||||
StudentNickAndAvatar(nick = nick.trim(), avatarColor = avatarColor.toLong())
|
||||
.apply { id = student.id }
|
||||
resourceFlow {
|
||||
val studentNick = StudentNickAndAvatar(
|
||||
nick = nick.trim(),
|
||||
avatarColor = avatarColor.toLong()
|
||||
).apply { id = student.id }
|
||||
|
||||
studentRepository.updateStudentNickAndAvatar(studentNick)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Attempt to change a student nick and avatar")
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Change a student nick and avatar result: Success")
|
||||
view?.recreateMainView()
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Change a student nick and avatar result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
.afterLoading { view?.popView() }
|
||||
.logResourceStatus("change student nick and avatar")
|
||||
.onResourceSuccess { view?.recreateMainView() }
|
||||
.onResourceNotLoading { view?.popView() }
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch("update_student")
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,11 @@
|
||||
package io.github.wulkanowy.ui.modules.account.accountquick
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.ui.modules.account.AccountItem
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -43,21 +40,11 @@ class AccountQuickPresenter @Inject constructor(
|
||||
return
|
||||
}
|
||||
|
||||
flowWithResource { studentRepository.switchStudent(studentWithSemesters) }
|
||||
.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Attempt to change a student")
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Change a student result: Success")
|
||||
view?.recreateMainView()
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Change a student result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
.afterLoading { view?.popView() }
|
||||
resourceFlow { studentRepository.switchStudent(studentWithSemesters) }
|
||||
.logResourceStatus("change student")
|
||||
.onResourceSuccess { view?.recreateMainView() }
|
||||
.onResourceNotLoading { view?.popView() }
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch("switch")
|
||||
}
|
||||
|
||||
|
@ -2,14 +2,8 @@ package io.github.wulkanowy.ui.modules.attendance
|
||||
|
||||
import android.content.DialogInterface.BUTTON_POSITIVE
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.INVISIBLE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.*
|
||||
import android.view.View.*
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.core.view.isVisible
|
||||
@ -68,7 +62,7 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag
|
||||
private val actionModeCallback = object : ActionMode.Callback {
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
val inflater = mode.menuInflater
|
||||
inflater.inflate(R.menu.context_menu_excuse, menu)
|
||||
inflater.inflate(R.menu.context_menu_attendance, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package io.github.wulkanowy.ui.modules.attendance
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.github.wulkanowy.data.repositories.AttendanceRepository
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
@ -9,18 +9,7 @@ import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.capitalise
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import io.github.wulkanowy.utils.getLastSchoolDayIfHoliday
|
||||
import io.github.wulkanowy.utils.isExcusableOrNotExcused
|
||||
import io.github.wulkanowy.utils.isHolidays
|
||||
import io.github.wulkanowy.utils.nextSchoolDay
|
||||
import io.github.wulkanowy.utils.previousOrSameSchoolDay
|
||||
import io.github.wulkanowy.utils.previousSchoolDay
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.*
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -213,93 +202,77 @@ class AttendancePresenter @Inject constructor(
|
||||
|
||||
var isParent = false
|
||||
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
isParent = student.isParent
|
||||
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
attendanceRepository.getAttendance(
|
||||
student,
|
||||
semester,
|
||||
currentDate,
|
||||
currentDate,
|
||||
forceRefresh
|
||||
student = student,
|
||||
semester = semester,
|
||||
start = currentDate,
|
||||
end = currentDate,
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
view?.showExcuseButton(false)
|
||||
if (!it.data.isNullOrEmpty()) {
|
||||
val filteredAttendance = if (prefRepository.isShowPresent) {
|
||||
it.data
|
||||
} else {
|
||||
it.data.filter { item -> !item.presence }
|
||||
}
|
||||
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showRefresh(true)
|
||||
showProgress(false)
|
||||
showErrorView(false)
|
||||
showEmpty(filteredAttendance.isEmpty())
|
||||
showContent(filteredAttendance.isNotEmpty())
|
||||
updateData(filteredAttendance.sortedBy { item -> item.number })
|
||||
}
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading attendance result: Success")
|
||||
val filteredAttendance = if (prefRepository.isShowPresent) {
|
||||
it.data.orEmpty()
|
||||
} else {
|
||||
it.data?.filter { item -> !item.presence }.orEmpty()
|
||||
}
|
||||
|
||||
isVulcanExcusedFunctionEnabled =
|
||||
filteredAttendance.any { item -> item.excusable }
|
||||
|
||||
view?.apply {
|
||||
updateData(filteredAttendance.sortedBy { item -> item.number })
|
||||
showEmpty(filteredAttendance.isEmpty())
|
||||
showErrorView(false)
|
||||
showContent(filteredAttendance.isNotEmpty())
|
||||
val anyExcusables = filteredAttendance.any { it.isExcusableOrNotExcused }
|
||||
showExcuseButton(anyExcusables && (isParent || isVulcanExcusedFunctionEnabled))
|
||||
}
|
||||
analytics.logEvent(
|
||||
"load_data",
|
||||
"type" to "attendance",
|
||||
"items" to it.data!!.size
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading attendance result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
.logResourceStatus("load attendance")
|
||||
.onResourceLoading {
|
||||
view?.showExcuseButton(false)
|
||||
}
|
||||
.mapResourceData {
|
||||
if (prefRepository.isShowPresent) {
|
||||
it
|
||||
} else {
|
||||
it.filter { item -> !item.presence }
|
||||
}.sortedBy { item -> item.number }
|
||||
}
|
||||
.onResourceData {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showProgress(false)
|
||||
showErrorView(false)
|
||||
showEmpty(it.isEmpty())
|
||||
showContent(it.isNotEmpty())
|
||||
updateData(it)
|
||||
}
|
||||
}
|
||||
}.afterLoading {
|
||||
view?.run {
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
enableSwipe(true)
|
||||
.onResourceIntermediate { view?.showRefresh(true) }
|
||||
.onResourceSuccess {
|
||||
isVulcanExcusedFunctionEnabled = it.any { item -> item.excusable }
|
||||
val anyExcusables = it.any { it.isExcusableOrNotExcused }
|
||||
view?.showExcuseButton(anyExcusables && (isParent || isVulcanExcusedFunctionEnabled))
|
||||
|
||||
analytics.logEvent(
|
||||
"load_data",
|
||||
"type" to "attendance",
|
||||
"items" to it.size
|
||||
)
|
||||
}
|
||||
}.launch()
|
||||
.onResourceNotLoading {
|
||||
view?.run {
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
enableSwipe(true)
|
||||
}
|
||||
}
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch()
|
||||
}
|
||||
|
||||
private fun excuseAbsence(reason: String?, toExcuseList: List<Attendance>) {
|
||||
flowWithResource {
|
||||
resourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
attendanceRepository.excuseForAbsence(student, semester, toExcuseList, reason)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> view?.run {
|
||||
when (it) {
|
||||
is Resource.Loading -> view?.run {
|
||||
Timber.i("Excusing absence started")
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
showExcuseButton(false)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
is Resource.Success -> {
|
||||
Timber.i("Excusing for absence result: Success")
|
||||
analytics.logEvent("excuse_absence", "items" to attendanceToExcuseList.size)
|
||||
attendanceToExcuseList.clear()
|
||||
@ -311,9 +284,9 @@ class AttendancePresenter @Inject constructor(
|
||||
}
|
||||
loadData(forceRefresh = true)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
is Resource.Error -> {
|
||||
Timber.i("Excusing for absence result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
errorHandler.dispatch(it.error)
|
||||
loadData()
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ class AttendanceSummaryFragment :
|
||||
binding.attendanceSummarySubjectsContainer.elevation = requireContext().dpToPx(1f)
|
||||
}
|
||||
|
||||
override fun updateSubjects(data: ArrayList<String>) {
|
||||
override fun updateSubjects(data: Collection<String>) {
|
||||
with(subjectsAdapter) {
|
||||
clear()
|
||||
addAll(data)
|
||||
|
@ -1,6 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.attendance.summary
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.db.entities.AttendanceSummary
|
||||
import io.github.wulkanowy.data.db.entities.Subject
|
||||
import io.github.wulkanowy.data.repositories.AttendanceSummaryRepository
|
||||
@ -10,9 +10,6 @@ import io.github.wulkanowy.data.repositories.SubjectRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import java.time.Month
|
||||
import javax.inject.Inject
|
||||
@ -75,11 +72,9 @@ class AttendanceSummaryPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData(subjectId: Int, forceRefresh: Boolean = false) {
|
||||
Timber.i("Loading attendance summary data started")
|
||||
|
||||
currentSubjectId = subjectId
|
||||
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
|
||||
@ -89,47 +84,37 @@ class AttendanceSummaryPresenter @Inject constructor(
|
||||
subjectId = subjectId,
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
if (!it.data.isNullOrEmpty()) {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showRefresh(true)
|
||||
showProgress(false)
|
||||
showContent(true)
|
||||
showErrorView(false)
|
||||
updateDataSet(sortItems(it.data))
|
||||
}
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading attendance summary result: Success")
|
||||
view?.apply {
|
||||
showErrorView(false)
|
||||
showEmpty(it.data!!.isEmpty())
|
||||
showContent(it.data.isNotEmpty())
|
||||
updateDataSet(sortItems(it.data))
|
||||
}
|
||||
analytics.logEvent(
|
||||
"load_data",
|
||||
"type" to "attendance_summary",
|
||||
"items" to it.data!!.size,
|
||||
"item_id" to subjectId
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading attendance summary result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
.logResourceStatus("load attendance summary")
|
||||
.mapResourceData(this::sortItems)
|
||||
.onResourceData {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showProgress(false)
|
||||
showErrorView(false)
|
||||
showContent(it.isNotEmpty())
|
||||
showEmpty(it.isEmpty())
|
||||
updateDataSet(it)
|
||||
}
|
||||
}
|
||||
}.afterLoading {
|
||||
view?.run {
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
enableSwipe(true)
|
||||
.onResourceIntermediate { view?.showRefresh(true) }
|
||||
.onResourceSuccess {
|
||||
analytics.logEvent(
|
||||
"load_data",
|
||||
"type" to "attendance_summary",
|
||||
"items" to it.size,
|
||||
"item_id" to subjectId
|
||||
)
|
||||
}
|
||||
}.launch()
|
||||
.onResourceNotLoading {
|
||||
view?.run {
|
||||
showProgress(false)
|
||||
showRefresh(false)
|
||||
enableSwipe(true)
|
||||
}
|
||||
}
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch()
|
||||
}
|
||||
|
||||
private fun sortItems(items: List<AttendanceSummary>) = items.sortedByDescending { item ->
|
||||
@ -148,27 +133,20 @@ class AttendanceSummaryPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadSubjects() {
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
subjectRepository.getSubjects(student, semester)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Loading attendance summary subjects started")
|
||||
Status.SUCCESS -> {
|
||||
subjects = it.data!!
|
||||
|
||||
Timber.i("Loading attendance summary subjects result: Success")
|
||||
view?.run {
|
||||
view?.updateSubjects(ArrayList(it.data.map { subject -> subject.name }))
|
||||
showSubjects(true)
|
||||
}
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading attendance summary subjects result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
.logResourceStatus("load attendance summary subjects")
|
||||
.onResourceData {
|
||||
subjects = it
|
||||
view?.run {
|
||||
view?.updateSubjects(it.map { subject -> subject.name }.toList())
|
||||
showSubjects(true)
|
||||
}
|
||||
}
|
||||
}.launch("subjects")
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch("subjects")
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ interface AttendanceSummaryView : BaseView {
|
||||
|
||||
fun updateDataSet(data: List<AttendanceSummary>)
|
||||
|
||||
fun updateSubjects(data: ArrayList<String>)
|
||||
fun updateSubjects(data: Collection<String>)
|
||||
|
||||
fun showSubjects(show: Boolean)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.conference
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.db.entities.Conference
|
||||
import io.github.wulkanowy.data.repositories.ConferenceRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
@ -8,9 +8,6 @@ import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -64,50 +61,39 @@ class ConferencePresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData(forceRefresh: Boolean = false) {
|
||||
Timber.i("Loading conference data started")
|
||||
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
conferenceRepository.getConferences(student, semester, forceRefresh)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
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 -> {
|
||||
Timber.i("Loading conference result: Success")
|
||||
view?.run {
|
||||
updateData(it.data!!.sortedByDescending { conference -> conference.date })
|
||||
showContent(it.data.isNotEmpty())
|
||||
showEmpty(it.data.isEmpty())
|
||||
showErrorView(false)
|
||||
}
|
||||
analytics.logEvent(
|
||||
"load_data",
|
||||
"type" to "conferences",
|
||||
"items" to it.data!!.size
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading conference result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
.logResourceStatus("load conference data")
|
||||
.mapResourceData { it.sortedByDescending { conference -> conference.date } }
|
||||
.onResourceData {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showProgress(false)
|
||||
showErrorView(false)
|
||||
showContent(it.isNotEmpty())
|
||||
showEmpty(it.isEmpty())
|
||||
updateData(it)
|
||||
}
|
||||
}
|
||||
}.afterLoading {
|
||||
view?.run {
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
enableSwipe(true)
|
||||
.onResourceIntermediate { view?.showRefresh(true) }
|
||||
.onResourceSuccess {
|
||||
analytics.logEvent(
|
||||
"load_data",
|
||||
"type" to "conferences",
|
||||
"items" to it.size
|
||||
)
|
||||
}
|
||||
}.launch()
|
||||
.onResourceNotLoading {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showProgress(false)
|
||||
showRefresh(false)
|
||||
}
|
||||
}
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch()
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.dashboard
|
||||
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
@ -10,7 +9,6 @@ import io.github.wulkanowy.data.repositories.*
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.calculatePercentage
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
@ -225,27 +223,26 @@ class DashboardPresenter @Inject constructor(
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
val selectedTiles = preferencesRepository.selectedDashboardTiles
|
||||
|
||||
val flowSuccess = flowOf(Resource.Success(null))
|
||||
val luckyNumberFlow = luckyNumberRepository.getLuckyNumber(student, forceRefresh)
|
||||
.map {
|
||||
if (it.data == null) {
|
||||
it.copy(data = LuckyNumber(0, LocalDate.now(), 0))
|
||||
} else it
|
||||
.mapResourceData {
|
||||
it ?: LuckyNumber(0, LocalDate.now(), 0)
|
||||
}
|
||||
.takeIf { DashboardItem.Tile.LUCKY_NUMBER in selectedTiles } ?: flowOf(null)
|
||||
.takeIf { DashboardItem.Tile.LUCKY_NUMBER in selectedTiles } ?: flowSuccess
|
||||
|
||||
val messageFLow = messageRepository.getMessages(
|
||||
student = student,
|
||||
semester = semester,
|
||||
folder = MessageFolder.RECEIVED,
|
||||
forceRefresh = forceRefresh
|
||||
).takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowOf(null)
|
||||
).takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowSuccess
|
||||
|
||||
val attendanceFlow = attendanceSummaryRepository.getAttendanceSummary(
|
||||
student = student,
|
||||
semester = semester,
|
||||
subjectId = -1,
|
||||
forceRefresh = forceRefresh
|
||||
).takeIf { DashboardItem.Tile.ATTENDANCE in selectedTiles } ?: flowOf(null)
|
||||
).takeIf { DashboardItem.Tile.ATTENDANCE in selectedTiles } ?: flowSuccess
|
||||
|
||||
emitAll(
|
||||
combine(
|
||||
@ -253,16 +250,13 @@ class DashboardPresenter @Inject constructor(
|
||||
messageFLow,
|
||||
attendanceFlow
|
||||
) { luckyNumberResource, messageResource, attendanceResource ->
|
||||
val error =
|
||||
luckyNumberResource?.error ?: messageResource?.error ?: attendanceResource?.error
|
||||
error?.let { throw it }
|
||||
val resList = listOf(luckyNumberResource, messageResource, attendanceResource)
|
||||
resList.firstNotNullOfOrNull { it.errorOrNull }?.let { throw it }
|
||||
val isLoading = resList.any { it is Resource.Loading }
|
||||
|
||||
val luckyNumber = luckyNumberResource?.data?.luckyNumber
|
||||
val messageCount = messageResource?.data?.count { it.unread }
|
||||
val attendancePercentage = attendanceResource?.data?.calculatePercentage()
|
||||
|
||||
val isLoading =
|
||||
luckyNumberResource?.status == Status.LOADING || messageResource?.status == Status.LOADING || attendanceResource?.status == Status.LOADING
|
||||
val luckyNumber = luckyNumberResource.dataOrNull?.luckyNumber
|
||||
val messageCount = messageResource.dataOrNull?.count { it.unread }
|
||||
val attendancePercentage = attendanceResource.dataOrNull?.calculatePercentage()
|
||||
|
||||
DashboardItem.HorizontalGroup(
|
||||
isLoading = isLoading,
|
||||
@ -295,72 +289,69 @@ class DashboardPresenter @Inject constructor(
|
||||
)
|
||||
errorHandler.dispatch(it)
|
||||
}
|
||||
.launch("horizontal_group")
|
||||
.launch("horizontal_group ${if (forceRefresh) "-forceRefresh" else ""}")
|
||||
}
|
||||
|
||||
private fun loadGrades(student: Student, forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
|
||||
gradeRepository.getGrades(student, semester, forceRefresh)
|
||||
}.map { originalResource ->
|
||||
val filteredSubjectWithGrades = originalResource.data?.first
|
||||
.orEmpty()
|
||||
.filter { it.date >= LocalDate.now().minusDays(7) }
|
||||
.groupBy { it.subject }
|
||||
.mapValues { entry ->
|
||||
entry.value
|
||||
.take(5)
|
||||
.sortedByDescending { it.date }
|
||||
}
|
||||
.toList()
|
||||
.sortedByDescending { (_, grades) -> grades[0].date }
|
||||
.toMap()
|
||||
}
|
||||
.mapResourceData { (details, _) ->
|
||||
val filteredSubjectWithGrades = details
|
||||
.filter { it.date >= LocalDate.now().minusDays(7) }
|
||||
.groupBy { it.subject }
|
||||
.mapValues { entry ->
|
||||
entry.value
|
||||
.take(5)
|
||||
.sortedByDescending { it.date }
|
||||
}
|
||||
.toList()
|
||||
.sortedByDescending { (_, grades) -> grades[0].date }
|
||||
.toMap()
|
||||
|
||||
Resource(
|
||||
status = originalResource.status,
|
||||
data = filteredSubjectWithGrades.takeIf { originalResource.data != null },
|
||||
error = originalResource.error
|
||||
)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard grades data started")
|
||||
if (forceRefresh) return@onEach
|
||||
filteredSubjectWithGrades
|
||||
}
|
||||
.onEach {
|
||||
when (it) {
|
||||
is Resource.Loading -> {
|
||||
Timber.i("Loading dashboard grades data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(
|
||||
DashboardItem.Grades(
|
||||
subjectWithGrades = it.dataOrNull,
|
||||
gradeTheme = preferencesRepository.gradeColorTheme,
|
||||
isLoading = true
|
||||
), forceRefresh
|
||||
)
|
||||
|
||||
updateData(
|
||||
DashboardItem.Grades(
|
||||
subjectWithGrades = it.data,
|
||||
gradeTheme = preferencesRepository.gradeColorTheme,
|
||||
isLoading = true
|
||||
), forceRefresh
|
||||
)
|
||||
|
||||
if (!it.data.isNullOrEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.GRADES
|
||||
if (!it.dataOrNull.isNullOrEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.GRADES
|
||||
}
|
||||
}
|
||||
is Resource.Success -> {
|
||||
Timber.i("Loading dashboard grades result: Success")
|
||||
updateData(
|
||||
DashboardItem.Grades(
|
||||
subjectWithGrades = it.data,
|
||||
gradeTheme = preferencesRepository.gradeColorTheme
|
||||
),
|
||||
forceRefresh
|
||||
)
|
||||
}
|
||||
is Resource.Error -> {
|
||||
Timber.i("Loading dashboard grades result: An exception occurred")
|
||||
errorHandler.dispatch(it.error)
|
||||
updateData(DashboardItem.Grades(error = it.error), forceRefresh)
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard grades result: Success")
|
||||
updateData(
|
||||
DashboardItem.Grades(
|
||||
subjectWithGrades = it.data,
|
||||
gradeTheme = preferencesRepository.gradeColorTheme
|
||||
),
|
||||
forceRefresh
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard grades result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
updateData(DashboardItem.Grades(error = it.error), forceRefresh)
|
||||
}
|
||||
}
|
||||
}.launch("dashboard_grades")
|
||||
.launchWithUniqueRefreshJob("dashboard_grades", forceRefresh)
|
||||
}
|
||||
|
||||
private fun loadLessons(student: Student, forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
val date = LocalDate.now().nextOrSameSchoolDay
|
||||
|
||||
@ -371,40 +362,41 @@ class DashboardPresenter @Inject constructor(
|
||||
end = date.plusDays(1),
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}
|
||||
.onEach {
|
||||
when (it) {
|
||||
is Resource.Loading -> {
|
||||
Timber.i("Loading dashboard lessons data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(
|
||||
DashboardItem.Lessons(it.dataOrNull, isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard lessons data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(
|
||||
DashboardItem.Lessons(it.data, isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
|
||||
if (!it.data?.lessons.isNullOrEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.LESSONS
|
||||
if (!it.dataOrNull?.lessons.isNullOrEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.LESSONS
|
||||
}
|
||||
}
|
||||
is Resource.Success -> {
|
||||
Timber.i("Loading dashboard lessons result: Success")
|
||||
updateData(
|
||||
DashboardItem.Lessons(it.data), forceRefresh
|
||||
)
|
||||
}
|
||||
is Resource.Error -> {
|
||||
Timber.i("Loading dashboard lessons result: An exception occurred")
|
||||
errorHandler.dispatch(it.error)
|
||||
updateData(
|
||||
DashboardItem.Lessons(error = it.error), forceRefresh
|
||||
)
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard lessons result: Success")
|
||||
updateData(
|
||||
DashboardItem.Lessons(it.data), forceRefresh
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard lessons result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
updateData(
|
||||
DashboardItem.Lessons(error = it.error), forceRefresh
|
||||
)
|
||||
}
|
||||
}
|
||||
}.launch("dashboard_lessons")
|
||||
.launchWithUniqueRefreshJob("dashboard_lessons", forceRefresh)
|
||||
}
|
||||
|
||||
private fun loadHomework(student: Student, forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
val date = LocalDate.now().nextOrSameSchoolDay
|
||||
|
||||
@ -415,73 +407,79 @@ class DashboardPresenter @Inject constructor(
|
||||
end = date,
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}.map { homeworkResource ->
|
||||
val currentDate = LocalDate.now()
|
||||
}
|
||||
.mapResourceData { homework ->
|
||||
val currentDate = LocalDate.now()
|
||||
|
||||
val filteredHomework = homeworkResource.data
|
||||
?.filter { (it.date.isAfter(currentDate) || it.date == currentDate) && !it.isDone }
|
||||
?.sortedBy { it.date }
|
||||
val filteredHomework = homework.filter {
|
||||
(it.date.isAfter(currentDate) || it.date == currentDate) && !it.isDone
|
||||
}.sortedBy { it.date }
|
||||
|
||||
homeworkResource.copy(data = filteredHomework)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard homework data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(
|
||||
DashboardItem.Homework(it.data ?: emptyList(), isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
filteredHomework
|
||||
}
|
||||
.onEach {
|
||||
when (it) {
|
||||
is Resource.Loading -> {
|
||||
Timber.i("Loading dashboard homework data started")
|
||||
if (forceRefresh) return@onEach
|
||||
val data = it.dataOrNull.orEmpty()
|
||||
updateData(
|
||||
DashboardItem.Homework(data, isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
|
||||
if (!it.data.isNullOrEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.HOMEWORK
|
||||
if (data.isNotEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.HOMEWORK
|
||||
}
|
||||
}
|
||||
is Resource.Success -> {
|
||||
Timber.i("Loading dashboard homework result: Success")
|
||||
updateData(DashboardItem.Homework(it.data), forceRefresh)
|
||||
}
|
||||
is Resource.Error -> {
|
||||
Timber.i("Loading dashboard homework result: An exception occurred")
|
||||
errorHandler.dispatch(it.error)
|
||||
updateData(DashboardItem.Homework(error = it.error), forceRefresh)
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard homework result: Success")
|
||||
updateData(DashboardItem.Homework(it.data ?: emptyList()), forceRefresh)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard homework result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
updateData(DashboardItem.Homework(error = it.error), forceRefresh)
|
||||
}
|
||||
}
|
||||
}.launch("dashboard_homework")
|
||||
.launchWithUniqueRefreshJob("dashboard_homework", forceRefresh)
|
||||
}
|
||||
|
||||
private fun loadSchoolAnnouncements(student: Student, forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
schoolAnnouncementRepository.getSchoolAnnouncements(student, forceRefresh)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard announcements data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(
|
||||
DashboardItem.Announcements(it.data ?: emptyList(), isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
}
|
||||
.onEach {
|
||||
when (it) {
|
||||
is Resource.Loading -> {
|
||||
Timber.i("Loading dashboard announcements data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(
|
||||
DashboardItem.Announcements(it.dataOrNull.orEmpty(), isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
|
||||
if (!it.data.isNullOrEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.ANNOUNCEMENTS
|
||||
if (!it.dataOrNull.isNullOrEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.ANNOUNCEMENTS
|
||||
}
|
||||
}
|
||||
is Resource.Success -> {
|
||||
Timber.i("Loading dashboard announcements result: Success")
|
||||
updateData(DashboardItem.Announcements(it.data), forceRefresh)
|
||||
}
|
||||
is Resource.Error -> {
|
||||
Timber.i("Loading dashboard announcements result: An exception occurred")
|
||||
errorHandler.dispatch(it.error)
|
||||
updateData(DashboardItem.Announcements(error = it.error), forceRefresh)
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard announcements result: Success")
|
||||
updateData(DashboardItem.Announcements(it.data ?: emptyList()), forceRefresh)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard announcements result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
updateData(DashboardItem.Announcements(error = it.error), forceRefresh)
|
||||
}
|
||||
}
|
||||
}.launch("dashboard_announcements")
|
||||
.launchWithUniqueRefreshJob("dashboard_announcements", forceRefresh)
|
||||
}
|
||||
|
||||
private fun loadExams(student: Student, forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
|
||||
examRepository.getExams(
|
||||
@ -492,40 +490,37 @@ class DashboardPresenter @Inject constructor(
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}
|
||||
.map { examResource ->
|
||||
val sortedExams = examResource.data?.sortedBy { it.date }
|
||||
|
||||
examResource.copy(data = sortedExams)
|
||||
}
|
||||
.mapResourceData { exams -> exams.sortedBy { exam -> exam.date } }
|
||||
.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
when (it) {
|
||||
is Resource.Loading -> {
|
||||
Timber.i("Loading dashboard exams data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(
|
||||
DashboardItem.Exams(it.data.orEmpty(), isLoading = true),
|
||||
DashboardItem.Exams(it.dataOrNull.orEmpty(), isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
|
||||
if (!it.data.isNullOrEmpty()) {
|
||||
if (!it.dataOrNull.isNullOrEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.EXAMS
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
is Resource.Success -> {
|
||||
Timber.i("Loading dashboard exams result: Success")
|
||||
updateData(DashboardItem.Exams(it.data ?: emptyList()), forceRefresh)
|
||||
updateData(DashboardItem.Exams(it.data), forceRefresh)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
is Resource.Error -> {
|
||||
Timber.i("Loading dashboard exams result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
errorHandler.dispatch(it.error)
|
||||
updateData(DashboardItem.Exams(error = it.error), forceRefresh)
|
||||
}
|
||||
}
|
||||
}.launch("dashboard_exams")
|
||||
}
|
||||
.launchWithUniqueRefreshJob("dashboard_exams", forceRefresh)
|
||||
}
|
||||
|
||||
private fun loadConferences(student: Student, forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
|
||||
conferenceRepository.getConferences(
|
||||
@ -534,59 +529,62 @@ class DashboardPresenter @Inject constructor(
|
||||
forceRefresh = forceRefresh,
|
||||
startDate = Instant.now(),
|
||||
)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard conferences data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(
|
||||
DashboardItem.Conferences(it.data ?: emptyList(), isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
}
|
||||
.onEach {
|
||||
when (it) {
|
||||
is Resource.Loading -> {
|
||||
Timber.i("Loading dashboard conferences data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(
|
||||
DashboardItem.Conferences(it.dataOrNull.orEmpty(), isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
|
||||
if (!it.data.isNullOrEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.CONFERENCES
|
||||
if (!it.dataOrNull.isNullOrEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.CONFERENCES
|
||||
}
|
||||
}
|
||||
is Resource.Success -> {
|
||||
Timber.i("Loading dashboard conferences result: Success")
|
||||
updateData(DashboardItem.Conferences(it.data), forceRefresh)
|
||||
}
|
||||
is Resource.Error -> {
|
||||
Timber.i("Loading dashboard conferences result: An exception occurred")
|
||||
errorHandler.dispatch(it.error)
|
||||
updateData(DashboardItem.Conferences(error = it.error), forceRefresh)
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard conferences result: Success")
|
||||
updateData(DashboardItem.Conferences(it.data ?: emptyList()), forceRefresh)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard conferences result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
updateData(DashboardItem.Conferences(error = it.error), forceRefresh)
|
||||
}
|
||||
}
|
||||
}.launch("dashboard_conferences")
|
||||
.launchWithUniqueRefreshJob("dashboard_conferences", forceRefresh)
|
||||
}
|
||||
|
||||
private fun loadAdminMessage(student: Student, forceRefresh: Boolean) {
|
||||
flowWithResourceIn { adminMessageRepository.getAdminMessages(student) }
|
||||
.map {
|
||||
val isDismissed = it.data?.id in preferencesRepository.dismissedAdminMessageIds
|
||||
it.copy(data = it.data.takeUnless { isDismissed })
|
||||
flatResourceFlow { adminMessageRepository.getAdminMessages(student) }
|
||||
.filter {
|
||||
val data = it.dataOrNull ?: return@filter true
|
||||
val isDismissed = data.id in preferencesRepository.dismissedAdminMessageIds
|
||||
!isDismissed
|
||||
}
|
||||
.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
when (it) {
|
||||
is Resource.Loading -> {
|
||||
Timber.i("Loading dashboard admin message data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(DashboardItem.AdminMessages(), forceRefresh)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
is Resource.Success -> {
|
||||
Timber.i("Loading dashboard admin message result: Success")
|
||||
updateData(
|
||||
dashboardItem = DashboardItem.AdminMessages(adminMessage = it.data),
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
is Resource.Error -> {
|
||||
Timber.i("Loading dashboard admin message result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
errorHandler.dispatch(it.error)
|
||||
updateData(
|
||||
dashboardItem = DashboardItem.AdminMessages(
|
||||
adminMessage = it.data,
|
||||
adminMessage = null,
|
||||
error = it.error
|
||||
),
|
||||
forceRefresh = forceRefresh
|
||||
@ -594,7 +592,7 @@ class DashboardPresenter @Inject constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
.launch("dashboard_admin_messages")
|
||||
.launchWithUniqueRefreshJob("dashboard_admin_messages", forceRefresh)
|
||||
}
|
||||
|
||||
private fun updateData(dashboardItem: DashboardItem, forceRefresh: Boolean) {
|
||||
@ -733,4 +731,18 @@ class DashboardPresenter @Inject constructor(
|
||||
dashboardItemsPosition?.getOrDefault(tile.type, defaultPosition) ?: tile.type.ordinal
|
||||
}
|
||||
}
|
||||
|
||||
private fun Flow<Resource<*>>.launchWithUniqueRefreshJob(name: String, forceRefresh: Boolean) {
|
||||
val jobName = if (forceRefresh) "$name-forceRefresh" else name
|
||||
|
||||
if (forceRefresh) {
|
||||
onEach {
|
||||
if (it is Resource.Success) {
|
||||
cancelJobs(jobName)
|
||||
}
|
||||
}.launch(jobName)
|
||||
} else {
|
||||
launch(jobName)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
package io.github.wulkanowy.ui.modules.debug.logviewer
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.repositories.LoggerRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
@ -23,19 +23,21 @@ class LogViewerPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
fun onShareLogsSelected(): Boolean {
|
||||
flowWithResource { loggerRepository.getLogFiles() }.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.d("Loading logs files started")
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading logs files result: ${it.data!!.joinToString { file -> file.name }}")
|
||||
view?.shareLogs(it.data)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading logs files result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
resourceFlow { loggerRepository.getLogFiles() }
|
||||
.onEach {
|
||||
when (it) {
|
||||
is Resource.Loading -> Timber.d("Loading logs files started")
|
||||
is Resource.Success -> {
|
||||
Timber.i("Loading logs files result: ${it.data.joinToString { file -> file.name }}")
|
||||
view?.shareLogs(it.data)
|
||||
}
|
||||
is Resource.Error -> {
|
||||
Timber.i("Loading logs files result: An exception occurred")
|
||||
errorHandler.dispatch(it.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.launch("share")
|
||||
.launch("share")
|
||||
return true
|
||||
}
|
||||
|
||||
@ -44,18 +46,20 @@ class LogViewerPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadLogFile() {
|
||||
flowWithResource { loggerRepository.getLastLogLines() }.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.d("Loading last log file started")
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading last log file result: load ${it.data!!.size} lines")
|
||||
view?.setLines(it.data)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading last log file result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
resourceFlow { loggerRepository.getLastLogLines() }
|
||||
.onEach {
|
||||
when (it) {
|
||||
is Resource.Loading -> Timber.d("Loading last log file started")
|
||||
is Resource.Success -> {
|
||||
Timber.i("Loading last log file result: load ${it.data.size} lines")
|
||||
view?.setLines(it.data)
|
||||
}
|
||||
is Resource.Error -> {
|
||||
Timber.i("Loading last log file result: An exception occurred")
|
||||
errorHandler.dispatch(it.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.launch("file")
|
||||
.launch("file")
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ private fun generateTimetable(subject: String, room: String, roomOld: String) =
|
||||
diaryId = 0,
|
||||
date = LocalDate.now().minusDays(Random.nextLong(0, 8)),
|
||||
number = 1,
|
||||
start = Instant.now(),
|
||||
end = Instant.now().plus(Duration.ofHours(1)),
|
||||
start = Instant.now().plus(Duration.ofHours(1)),
|
||||
end = Instant.now(),
|
||||
subjectOld = "",
|
||||
group = "",
|
||||
room = room,
|
||||
|
@ -5,10 +5,13 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.databinding.DialogExamBinding
|
||||
import io.github.wulkanowy.utils.lifecycleAwareVariable
|
||||
import io.github.wulkanowy.utils.openCalendarEventAdd
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import java.time.LocalTime
|
||||
|
||||
class ExamDialog : DialogFragment() {
|
||||
|
||||
@ -46,10 +49,21 @@ class ExamDialog : DialogFragment() {
|
||||
examDialogSubjectValue.text = exam.subject
|
||||
examDialogTypeValue.text = exam.type
|
||||
examDialogTeacherValue.text = exam.teacher
|
||||
examDialogDateValue.text = exam.entryDate.toFormattedString()
|
||||
examDialogDescriptionValue.text = exam.description
|
||||
examDialogEntryDateValue.text = exam.entryDate.toFormattedString()
|
||||
examDialogDeadlineDateValue.text = exam.date.toFormattedString()
|
||||
examDialogDescriptionValue.text = exam.description.ifBlank {
|
||||
getString(R.string.all_no_data)
|
||||
}
|
||||
|
||||
examDialogClose.setOnClickListener { dismiss() }
|
||||
examDialogAddToCalendar.setOnClickListener {
|
||||
requireContext().openCalendarEventAdd(
|
||||
title = "${exam.subject} - ${exam.type}",
|
||||
description = exam.description,
|
||||
start = exam.date.atTime(LocalTime.of(8, 0)),
|
||||
end = exam.date.atTime(LocalTime.of(8, 45)),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,13 @@
|
||||
package io.github.wulkanowy.ui.modules.exam
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.data.repositories.ExamRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import io.github.wulkanowy.utils.getLastSchoolDayIfHoliday
|
||||
import io.github.wulkanowy.utils.isHolidays
|
||||
import io.github.wulkanowy.utils.monday
|
||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||
import io.github.wulkanowy.utils.sunday
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.*
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -86,61 +78,57 @@ class ExamPresenter @Inject constructor(
|
||||
flow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
emit(semesterRepository.getCurrentSemester(student))
|
||||
}.catch {
|
||||
Timber.i("Loading semester result: An exception occurred")
|
||||
}.onEach {
|
||||
baseDate = baseDate.getLastSchoolDayIfHoliday(it.schoolYear)
|
||||
currentDate = baseDate
|
||||
reloadNavigation()
|
||||
}.launch("holidays")
|
||||
}
|
||||
.catch { Timber.i("Loading semester result: An exception occurred") }
|
||||
.onEach {
|
||||
baseDate = baseDate.getLastSchoolDayIfHoliday(it.schoolYear)
|
||||
currentDate = baseDate
|
||||
reloadNavigation()
|
||||
}
|
||||
.launch("holidays")
|
||||
}
|
||||
|
||||
private fun loadData(forceRefresh: Boolean = false) {
|
||||
Timber.i("Loading exam data started")
|
||||
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
examRepository.getExams(student, semester, currentDate.monday, currentDate.sunday, forceRefresh)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
if (!it.data.isNullOrEmpty()) {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showRefresh(true)
|
||||
showProgress(false)
|
||||
showContent(true)
|
||||
updateData(createExamItems(it.data))
|
||||
}
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading exam result: Success")
|
||||
view?.apply {
|
||||
updateData(createExamItems(it.data!!))
|
||||
showEmpty(it.data.isEmpty())
|
||||
showErrorView(false)
|
||||
showContent(it.data.isNotEmpty())
|
||||
}
|
||||
analytics.logEvent(
|
||||
"load_data",
|
||||
"type" to "exam",
|
||||
"items" to it.data!!.size
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading exam result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
examRepository.getExams(
|
||||
student = student,
|
||||
semester = semester,
|
||||
start = currentDate.monday,
|
||||
end = currentDate.sunday,
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}
|
||||
.logResourceStatus("load exam data")
|
||||
.mapResourceData { createExamItems(it) }
|
||||
.onResourceData {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showProgress(false)
|
||||
showErrorView(false)
|
||||
showContent(it.isNotEmpty())
|
||||
showEmpty(it.isEmpty())
|
||||
updateData(it)
|
||||
}
|
||||
}
|
||||
}.afterLoading {
|
||||
view?.run {
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
enableSwipe(true)
|
||||
.onResourceIntermediate { view?.showRefresh(true) }
|
||||
.onResourceSuccess {
|
||||
analytics.logEvent(
|
||||
"load_data",
|
||||
"type" to "exam",
|
||||
"items" to it.size
|
||||
)
|
||||
}
|
||||
}.launch()
|
||||
.onResourceNotLoading {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showProgress(false)
|
||||
showRefresh(false)
|
||||
}
|
||||
}
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch()
|
||||
}
|
||||
|
||||
private fun showErrorViewOnError(message: String, error: Throwable) {
|
||||
@ -181,8 +169,10 @@ class ExamPresenter @Inject constructor(
|
||||
view?.apply {
|
||||
showPreButton(!currentDate.minusDays(7).isHolidays)
|
||||
showNextButton(!currentDate.plusDays(7).isHolidays)
|
||||
updateNavigationWeek("${currentDate.monday.toFormattedString("dd.MM")} - " +
|
||||
currentDate.sunday.toFormattedString("dd.MM"))
|
||||
updateNavigationWeek(
|
||||
"${currentDate.monday.toFormattedString("dd.MM")} - " +
|
||||
currentDate.sunday.toFormattedString("dd.MM")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.grade
|
||||
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
@ -10,17 +9,13 @@ import io.github.wulkanowy.data.repositories.GradeRepository
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode.ALL_YEAR
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode.BOTH_SEMESTERS
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode.ONE_SEMESTER
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode.*
|
||||
import io.github.wulkanowy.utils.calcAverage
|
||||
import io.github.wulkanowy.utils.changeModifier
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import javax.inject.Inject
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
@ -37,7 +32,7 @@ class GradeAverageProvider @Inject constructor(
|
||||
private val isOptionalArithmeticAverage get() = preferencesRepository.isOptionalArithmeticAverage
|
||||
|
||||
fun getGradesDetailsWithAverage(student: Student, semesterId: Int, forceRefresh: Boolean) =
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val semesters = semesterRepository.getSemesters(student)
|
||||
|
||||
when (preferencesRepository.gradeAverageMode) {
|
||||
@ -83,17 +78,17 @@ class GradeAverageProvider @Inject constructor(
|
||||
val firstSemesterGradeSubjects = getGradeSubjects(student, firstSemester, forceRefresh)
|
||||
|
||||
return selectedSemesterGradeSubjects.combine(firstSemesterGradeSubjects) { secondSemesterGradeSubject, firstSemesterGradeSubject ->
|
||||
if (firstSemesterGradeSubject.status == Status.ERROR) {
|
||||
if (firstSemesterGradeSubject.errorOrNull != null) {
|
||||
return@combine firstSemesterGradeSubject
|
||||
}
|
||||
|
||||
val isAnyVulcanAverageInFirstSemester =
|
||||
firstSemesterGradeSubject.data.orEmpty().any { it.isVulcanAverage }
|
||||
firstSemesterGradeSubject.dataOrNull.orEmpty().any { it.isVulcanAverage }
|
||||
val isAnyVulcanAverageInSecondSemester =
|
||||
secondSemesterGradeSubject.data.orEmpty().any { it.isVulcanAverage }
|
||||
secondSemesterGradeSubject.dataOrNull.orEmpty().any { it.isVulcanAverage }
|
||||
|
||||
val updatedData = secondSemesterGradeSubject.data?.map { secondSemesterSubject ->
|
||||
val firstSemesterSubject = firstSemesterGradeSubject.data.orEmpty()
|
||||
val updatedData = secondSemesterGradeSubject.dataOrNull?.map { secondSemesterSubject ->
|
||||
val firstSemesterSubject = firstSemesterGradeSubject.dataOrNull.orEmpty()
|
||||
.singleOrNull { it.subject == secondSemesterSubject.subject }
|
||||
|
||||
val updatedAverage = if (averageMode == ALL_YEAR) {
|
||||
@ -115,7 +110,7 @@ class GradeAverageProvider @Inject constructor(
|
||||
}
|
||||
secondSemesterSubject.copy(average = updatedAverage)
|
||||
}
|
||||
secondSemesterGradeSubject.copy(data = updatedData)
|
||||
secondSemesterGradeSubject.mapData { updatedData!! }
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,20 +139,20 @@ class GradeAverageProvider @Inject constructor(
|
||||
isGradeAverageForceCalc: Boolean,
|
||||
secondSemesterSubject: GradeSubject,
|
||||
firstSemesterSubject: GradeSubject?
|
||||
): Double {
|
||||
): Double = if (!isAnyVulcanAverage || isGradeAverageForceCalc) {
|
||||
val divider = if (secondSemesterSubject.grades.any { it.weightValue > .0 }) 2 else 1
|
||||
|
||||
return if (!isAnyVulcanAverage || isGradeAverageForceCalc) {
|
||||
val secondSemesterAverage =
|
||||
secondSemesterSubject.grades.updateModifiers(student)
|
||||
.calcAverage(isOptionalArithmeticAverage)
|
||||
val firstSemesterAverage = firstSemesterSubject?.grades?.updateModifiers(student)
|
||||
?.calcAverage(isOptionalArithmeticAverage) ?: secondSemesterAverage
|
||||
val secondSemesterAverage = secondSemesterSubject.grades.updateModifiers(student)
|
||||
.calcAverage(isOptionalArithmeticAverage)
|
||||
val firstSemesterAverage = firstSemesterSubject?.grades?.updateModifiers(student)
|
||||
?.calcAverage(isOptionalArithmeticAverage) ?: secondSemesterAverage
|
||||
|
||||
(secondSemesterAverage + firstSemesterAverage) / divider
|
||||
} else {
|
||||
(secondSemesterSubject.average + (firstSemesterSubject?.average ?: secondSemesterSubject.average)) / divider
|
||||
}
|
||||
(secondSemesterAverage + firstSemesterAverage) / divider
|
||||
} else {
|
||||
val divider = if (secondSemesterSubject.average > 0) 2 else 1
|
||||
|
||||
(secondSemesterSubject.average + (firstSemesterSubject?.average
|
||||
?: secondSemesterSubject.average)) / divider
|
||||
}
|
||||
|
||||
private fun getGradeSubjects(
|
||||
@ -168,17 +163,17 @@ class GradeAverageProvider @Inject constructor(
|
||||
val isGradeAverageForceCalc = preferencesRepository.gradeAverageForceCalc
|
||||
|
||||
return gradeRepository.getGrades(student, semester, forceRefresh = forceRefresh)
|
||||
.map { res ->
|
||||
val (details, summaries) = res.data ?: null to null
|
||||
val isAnyAverage = summaries.orEmpty().any { it.average != .0 }
|
||||
val allGrades = details.orEmpty().groupBy { it.subject }
|
||||
.mapResourceData { res ->
|
||||
val (details, summaries) = res
|
||||
val isAnyAverage = summaries.any { it.average != .0 }
|
||||
val allGrades = details.groupBy { it.subject }
|
||||
|
||||
val items = summaries?.emulateEmptySummaries(
|
||||
val items = summaries.emulateEmptySummaries(
|
||||
student = student,
|
||||
semester = semester,
|
||||
grades = allGrades.toList(),
|
||||
calcAverage = isAnyAverage
|
||||
)?.map { summary ->
|
||||
).map { summary ->
|
||||
val grades = allGrades[summary.subject].orEmpty()
|
||||
GradeSubject(
|
||||
subject = summary.subject,
|
||||
@ -192,7 +187,7 @@ class GradeAverageProvider @Inject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
Resource(res.status, items, res.error)
|
||||
items
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
package io.github.wulkanowy.ui.modules.grade
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.logResourceStatus
|
||||
import io.github.wulkanowy.data.onResourceData
|
||||
import io.github.wulkanowy.data.onResourceError
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.getCurrentOrLast
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -99,32 +99,26 @@ class GradePresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
flowWithResource {
|
||||
resourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
semesterRepository.getSemesters(student, refreshOnNoCurrent = true)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Loading grade data started")
|
||||
Status.SUCCESS -> {
|
||||
val current = it.data!!.getCurrentOrLast()
|
||||
selectedIndex = if (selectedIndex == 0) current.semesterName else selectedIndex
|
||||
schoolYear = current.schoolYear
|
||||
semesters = it.data.filter { semester -> semester.diaryId == current.diaryId }
|
||||
view?.setCurrentSemesterName(current.semesterName, schoolYear)
|
||||
|
||||
view?.run {
|
||||
Timber.i("Loading grade result: Attempt load index $currentPageIndex")
|
||||
loadChild(currentPageIndex)
|
||||
showErrorView(false)
|
||||
showSemesterSwitch(true)
|
||||
}
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading grade result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
.logResourceStatus("load grade data")
|
||||
.onResourceData {
|
||||
val current = it.getCurrentOrLast()
|
||||
selectedIndex = if (selectedIndex == 0) current.semesterName else selectedIndex
|
||||
schoolYear = current.schoolYear
|
||||
semesters = it.filter { semester -> semester.diaryId == current.diaryId }
|
||||
view?.setCurrentSemesterName(current.semesterName, schoolYear)
|
||||
view?.run {
|
||||
Timber.i("Loading grade data: Attempt load index $currentPageIndex")
|
||||
loadChild(currentPageIndex)
|
||||
showErrorView(false)
|
||||
showSemesterSwitch(true)
|
||||
}
|
||||
}
|
||||
}.launch()
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch()
|
||||
}
|
||||
|
||||
private fun showErrorViewOnError(message: String, error: Throwable) {
|
||||
|
@ -10,11 +10,8 @@ import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.data.enums.GradeColorTheme
|
||||
import io.github.wulkanowy.databinding.DialogGradeBinding
|
||||
import io.github.wulkanowy.utils.colorStringId
|
||||
import io.github.wulkanowy.utils.getBackgroundColor
|
||||
import io.github.wulkanowy.utils.getGradeColor
|
||||
import io.github.wulkanowy.utils.lifecycleAwareVariable
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.*
|
||||
|
||||
|
||||
class GradeDetailsDialog : DialogFragment() {
|
||||
|
||||
@ -80,9 +77,7 @@ class GradeDetailsDialog : DialogFragment() {
|
||||
setBackgroundResource(grade.getBackgroundColor(gradeColorTheme))
|
||||
}
|
||||
|
||||
gradeDialogTeacherValue.text = if (grade.teacher.isBlank()) {
|
||||
getString(R.string.all_no_data)
|
||||
} else grade.teacher
|
||||
gradeDialogTeacherValue.text = grade.teacher.ifBlank { getString(R.string.all_no_data) }
|
||||
|
||||
gradeDialogDescriptionValue.text = grade.run {
|
||||
when {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.grade.details
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.data.enums.GradeExpandMode
|
||||
import io.github.wulkanowy.data.enums.GradeSortingMode.ALPHABETIC
|
||||
@ -14,12 +14,8 @@ import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeSubject
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -71,7 +67,7 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
fun onMarkAsReadSelected(): Boolean {
|
||||
flowWithResource {
|
||||
resourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
val semesters = semesterRepository.getSemesters(student)
|
||||
val semester = semesters.first { item -> item.semesterId == currentSemesterId }
|
||||
@ -79,19 +75,11 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
|
||||
Timber.i("Mark as read ${unreadGrades.size} grades")
|
||||
gradeRepository.updateGrades(unreadGrades.map { it.apply { isRead = true } })
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Select mark grades as read")
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Mark as read result: Success")
|
||||
loadData(currentSemesterId, false)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Mark as read result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
}
|
||||
}.launch("mark")
|
||||
}
|
||||
.logResourceStatus("mark grades as read")
|
||||
.onResourceSuccess { loadData(currentSemesterId, false) }
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch("mark")
|
||||
return true
|
||||
}
|
||||
|
||||
@ -138,71 +126,49 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData(semesterId: Int, forceRefresh: Boolean) {
|
||||
Timber.i("Loading grade details data started")
|
||||
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
averageProvider.getGradesDetailsWithAverage(student, semesterId, forceRefresh)
|
||||
}.onEach {
|
||||
Timber.d("Loading grade details status: ${it.status}, data: ${it.data != null}")
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
val items = createGradeItems(it.data.orEmpty())
|
||||
if (items.isNotEmpty()) {
|
||||
Timber.i("Loading grade details result: load cached data")
|
||||
view?.run {
|
||||
updateNewGradesAmount(it.data.orEmpty())
|
||||
enableSwipe(true)
|
||||
showRefresh(true)
|
||||
showProgress(false)
|
||||
showEmpty(false)
|
||||
showContent(true)
|
||||
updateData(
|
||||
data = items,
|
||||
expandMode = preferencesRepository.gradeExpandMode,
|
||||
gradeColorTheme = preferencesRepository.gradeColorTheme
|
||||
)
|
||||
notifyParentDataLoaded(semesterId)
|
||||
}
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading grade details result: Success")
|
||||
updateNewGradesAmount(it.data!!)
|
||||
}
|
||||
.logResourceStatus("load grade details")
|
||||
.onResourceData {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showProgress(false)
|
||||
showErrorView(false)
|
||||
showContent(it.isNotEmpty())
|
||||
showEmpty(it.isEmpty())
|
||||
updateNewGradesAmount(it)
|
||||
updateMarkAsDoneButton()
|
||||
val items = createGradeItems(it.data)
|
||||
view?.run {
|
||||
showEmpty(items.isEmpty())
|
||||
showErrorView(false)
|
||||
showContent(items.isNotEmpty())
|
||||
updateData(
|
||||
data = items,
|
||||
expandMode = preferencesRepository.gradeExpandMode,
|
||||
gradeColorTheme = preferencesRepository.gradeColorTheme
|
||||
)
|
||||
}
|
||||
analytics.logEvent(
|
||||
"load_data",
|
||||
"type" to "grade_details",
|
||||
"items" to it.data.size
|
||||
updateData(
|
||||
data = createGradeItems(it),
|
||||
expandMode = preferencesRepository.gradeExpandMode,
|
||||
preferencesRepository.gradeColorTheme
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading grade details result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
.onResourceIntermediate { view?.showRefresh(true) }
|
||||
.onResourceSuccess {
|
||||
analytics.logEvent(
|
||||
"load_data",
|
||||
"type" to "grade_details",
|
||||
"items" to it.size
|
||||
)
|
||||
}
|
||||
.onResourceNotLoading {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
notifyParentDataLoaded(semesterId)
|
||||
}
|
||||
}
|
||||
}.afterLoading {
|
||||
view?.run {
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
enableSwipe(true)
|
||||
notifyParentDataLoaded(semesterId)
|
||||
.catch {
|
||||
errorHandler.dispatch(it)
|
||||
view?.notifyParentDataLoaded(semesterId)
|
||||
}
|
||||
}.catch {
|
||||
errorHandler.dispatch(it)
|
||||
view?.notifyParentDataLoaded(semesterId)
|
||||
}.launch()
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch()
|
||||
}
|
||||
|
||||
private fun updateNewGradesAmount(grades: List<GradeSubject>) {
|
||||
@ -267,15 +233,9 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun updateGrade(grade: Grade) {
|
||||
flowWithResource { gradeRepository.updateGrade(grade) }.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Attempt to update grade ${grade.id}")
|
||||
Status.SUCCESS -> Timber.i("Update grade result: Success")
|
||||
Status.ERROR -> {
|
||||
Timber.i("Update grade result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
}
|
||||
}.launch("update")
|
||||
resourceFlow { gradeRepository.updateGrade(grade) }
|
||||
.logResourceStatus("update grade result ${grade.id}")
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch("update")
|
||||
}
|
||||
}
|
||||
|
@ -9,12 +9,7 @@ import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.mikephil.charting.components.Legend
|
||||
import com.github.mikephil.charting.components.LegendEntry
|
||||
import com.github.mikephil.charting.data.BarData
|
||||
import com.github.mikephil.charting.data.BarDataSet
|
||||
import com.github.mikephil.charting.data.BarEntry
|
||||
import com.github.mikephil.charting.data.PieData
|
||||
import com.github.mikephil.charting.data.PieDataSet
|
||||
import com.github.mikephil.charting.data.PieEntry
|
||||
import com.github.mikephil.charting.data.*
|
||||
import com.github.mikephil.charting.formatter.ValueFormatter
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
|
||||
@ -136,20 +131,50 @@ class GradeStatisticsAdapter @Inject constructor() :
|
||||
binding: ItemGradeStatisticsPieBinding,
|
||||
partials: GradePartialStatistics
|
||||
) {
|
||||
bindPieChart(binding, partials.subject, partials.classAverage, partials.classAmounts)
|
||||
val studentAverage = partials.studentAverage.takeIf { it.isNotEmpty() }?.let {
|
||||
binding.root.context.getString(R.string.grade_statistics_student_average, it)
|
||||
}
|
||||
bindPieChart(
|
||||
binding = binding,
|
||||
subject = partials.subject,
|
||||
average = partials.classAverage,
|
||||
studentValue = studentAverage,
|
||||
amounts = partials.classAmounts
|
||||
)
|
||||
}
|
||||
|
||||
private fun bindSemesterChart(
|
||||
binding: ItemGradeStatisticsPieBinding,
|
||||
semester: GradeSemesterStatistics
|
||||
) {
|
||||
bindPieChart(binding, semester.subject, semester.average, semester.amounts)
|
||||
val studentAverage = semester.studentAverage.takeIf { it.isNotBlank() }
|
||||
val studentGrade = semester.studentGrade.takeIf { it != 0 }
|
||||
|
||||
val studentValue = when {
|
||||
studentAverage != null -> binding.root.context.getString(
|
||||
R.string.grade_statistics_student_average,
|
||||
studentAverage
|
||||
)
|
||||
studentGrade != null -> binding.root.context.getString(
|
||||
R.string.grade_statistics_student_grade,
|
||||
studentGrade.toString()
|
||||
)
|
||||
else -> null
|
||||
}
|
||||
bindPieChart(
|
||||
binding = binding,
|
||||
subject = semester.subject,
|
||||
average = semester.classAverage,
|
||||
studentValue = studentValue,
|
||||
amounts = semester.amounts
|
||||
)
|
||||
}
|
||||
|
||||
private fun bindPieChart(
|
||||
binding: ItemGradeStatisticsPieBinding,
|
||||
subject: String,
|
||||
average: String,
|
||||
studentValue: String?,
|
||||
amounts: List<Int>
|
||||
) {
|
||||
with(binding.gradeStatisticsPieTitle) {
|
||||
@ -208,13 +233,13 @@ class GradeStatisticsAdapter @Inject constructor() :
|
||||
val numberOfGradesString = amounts.fold(0) { acc, it -> acc + it }
|
||||
.let { resources.getQuantityString(R.plurals.grade_number_item, it, it) }
|
||||
val averageString =
|
||||
binding.root.context.getString(R.string.grade_statistics_average, average)
|
||||
binding.root.context.getString(R.string.grade_statistics_class_average, average)
|
||||
|
||||
minAngleForSlices = 25f
|
||||
description.isEnabled = false
|
||||
centerText =
|
||||
numberOfGradesString + ("\n\n" + averageString).takeIf { average.isNotBlank() }
|
||||
.orEmpty()
|
||||
.orEmpty() + studentValue?.let { "\n$it" }.orEmpty()
|
||||
|
||||
setHoleColor(context.getThemeAttrColor(android.R.attr.windowBackground))
|
||||
setCenterTextColor(context.getThemeAttrColor(android.R.attr.textColorPrimary))
|
||||
|
@ -1,19 +1,12 @@
|
||||
package io.github.wulkanowy.ui.modules.grade.statistics
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.*
|
||||
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.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.SubjectRepository
|
||||
import io.github.wulkanowy.data.repositories.*
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -125,33 +118,26 @@ class GradeStatisticsPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadSubjects() {
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
subjectRepository.getSubjects(student, semester)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Loading grade stats subjects started")
|
||||
Status.SUCCESS -> {
|
||||
subjects = requireNotNull(it.data)
|
||||
Timber.i("Loading grade stats subjects result: Success")
|
||||
|
||||
view?.run {
|
||||
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)
|
||||
updateSubjects(
|
||||
data = it.data.map { subject -> subject.name },
|
||||
selectedIndex = it.data.indexOfFirst { subject ->
|
||||
subject.name == currentSubjectName
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading grade stats subjects result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
.logResourceStatus("load grade stats subjects")
|
||||
.onResourceData {
|
||||
subjects = it
|
||||
view?.run {
|
||||
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)
|
||||
updateSubjects(
|
||||
data = it.map { subject -> subject.name },
|
||||
selectedIndex = it.indexOfFirst { subject ->
|
||||
subject.name == currentSubjectName
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}.launch("subjects")
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch("subjects")
|
||||
}
|
||||
|
||||
private fun loadDataByType(
|
||||
@ -168,7 +154,7 @@ class GradeStatisticsPresenter @Inject constructor(
|
||||
else -> subjectName
|
||||
}
|
||||
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
val semesters = semesterRepository.getSemesters(student)
|
||||
val semester = semesters.first { item -> item.semesterId == semesterId }
|
||||
@ -201,58 +187,43 @@ class GradeStatisticsPresenter @Inject constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
val isNoContent = it.data == null || checkIsNoContent(it.data, type)
|
||||
if (!isNoContent) {
|
||||
view?.run {
|
||||
showEmpty(isNoContent)
|
||||
showErrorView(false)
|
||||
enableSwipe(true)
|
||||
showRefresh(true)
|
||||
showProgress(false)
|
||||
updateData(
|
||||
newItems = if (isNoContent) emptyList() else it.data!!,
|
||||
newTheme = preferencesRepository.gradeColorTheme,
|
||||
showAllSubjectsOnStatisticsList = preferencesRepository.showAllSubjectsOnStatisticsList,
|
||||
)
|
||||
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)
|
||||
}
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading grade stats result: Success")
|
||||
view?.run {
|
||||
val isNoContent = checkIsNoContent(it.data!!, type)
|
||||
showEmpty(isNoContent)
|
||||
showErrorView(false)
|
||||
updateData(
|
||||
newItems = if (isNoContent) emptyList() else it.data,
|
||||
newTheme = preferencesRepository.gradeColorTheme,
|
||||
showAllSubjectsOnStatisticsList = preferencesRepository.showAllSubjectsOnStatisticsList,
|
||||
)
|
||||
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)
|
||||
}
|
||||
analytics.logEvent(
|
||||
"load_data",
|
||||
"type" to "grade_statistics",
|
||||
"items" to it.data!!.size
|
||||
}
|
||||
.logResourceStatus("load grade stats data")
|
||||
.mapResourceData {
|
||||
val isNoContent = checkIsNoContent(it, type)
|
||||
if (isNoContent) emptyList() else it
|
||||
}
|
||||
.onResourceData {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showProgress(false)
|
||||
showErrorView(false)
|
||||
showEmpty(it.isEmpty())
|
||||
updateData(
|
||||
newItems = it,
|
||||
newTheme = preferencesRepository.gradeColorTheme,
|
||||
showAllSubjectsOnStatisticsList = preferencesRepository.showAllSubjectsOnStatisticsList
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading grade stats result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
.onResourceIntermediate { view?.showRefresh(true) }
|
||||
.onResourceSuccess {
|
||||
analytics.logEvent(
|
||||
"load_data",
|
||||
"type" to "grade_statistics",
|
||||
"items" to it.size
|
||||
)
|
||||
}
|
||||
.onResourceNotLoading {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
notifyParentDataLoaded(semesterId)
|
||||
}
|
||||
}
|
||||
}.afterLoading {
|
||||
view?.run {
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
enableSwipe(true)
|
||||
notifyParentDataLoaded(semesterId)
|
||||
}
|
||||
}.launch("load")
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch("load")
|
||||
}
|
||||
|
||||
private fun checkIsNoContent(
|
||||
@ -267,7 +238,8 @@ class GradeStatisticsPresenter @Inject constructor(
|
||||
items.firstOrNull()?.partial?.classAmounts.orEmpty().sum() == 0
|
||||
}
|
||||
GradeStatisticsItem.DataType.POINTS -> {
|
||||
items.firstOrNull()?.points?.let { points -> points.student == .0 && points.others == .0 } ?: false
|
||||
items.firstOrNull()?.points?.let { points -> points.student == .0 && points.others == .0 }
|
||||
?: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.grade.summary
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
@ -8,9 +8,6 @@ import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeSubject
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -37,56 +34,40 @@ class GradeSummaryPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData(semesterId: Int, forceRefresh: Boolean) {
|
||||
Timber.i("Loading grade summary started")
|
||||
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
averageProvider.getGradesDetailsWithAverage(student, semesterId, forceRefresh)
|
||||
}.onEach {
|
||||
Timber.d("Loading grade summary status: ${it.status}, data: ${it.data != null}")
|
||||
when (it.status) {
|
||||
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)
|
||||
showEmpty(false)
|
||||
showContent(true)
|
||||
updateData(items)
|
||||
}
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading grade summary result: Success")
|
||||
val items = createGradeSummaryItems(it.data!!)
|
||||
view?.run {
|
||||
showEmpty(items.isEmpty())
|
||||
showContent(items.isNotEmpty())
|
||||
showErrorView(false)
|
||||
updateData(items)
|
||||
}
|
||||
analytics.logEvent(
|
||||
"load_data",
|
||||
"type" to "grade_summary",
|
||||
"items" to it.data.size
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading grade summary result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
.logResourceStatus("load grade summary", showData = true)
|
||||
.mapResourceData { createGradeSummaryItems(it) }
|
||||
.onResourceData {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showProgress(false)
|
||||
showErrorView(false)
|
||||
showContent(it.isNotEmpty())
|
||||
showEmpty(it.isEmpty())
|
||||
updateData(it)
|
||||
}
|
||||
}
|
||||
}.afterLoading {
|
||||
view?.run {
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
enableSwipe(true)
|
||||
notifyParentDataLoaded(semesterId)
|
||||
.onResourceIntermediate { view?.showRefresh(true) }
|
||||
.onResourceSuccess {
|
||||
analytics.logEvent(
|
||||
"load_data",
|
||||
"type" to "grade_summary",
|
||||
"items" to it.size
|
||||
)
|
||||
}
|
||||
}.launch()
|
||||
.onResourceNotLoading {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
notifyParentDataLoaded(semesterId)
|
||||
}
|
||||
}
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch()
|
||||
}
|
||||
|
||||
private fun showErrorViewOnError(message: String, error: Throwable) {
|
||||
@ -153,9 +134,9 @@ class GradeSummaryPresenter @Inject constructor(
|
||||
private fun checkEmpty(gradeSummary: GradeSubject): Boolean {
|
||||
return gradeSummary.run {
|
||||
summary.finalGrade.isBlank()
|
||||
&& summary.predictedGrade.isBlank()
|
||||
&& average == .0
|
||||
&& points.isBlank()
|
||||
&& summary.predictedGrade.isBlank()
|
||||
&& average == .0
|
||||
&& points.isBlank()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,13 @@
|
||||
package io.github.wulkanowy.ui.modules.homework
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.db.entities.Homework
|
||||
import io.github.wulkanowy.data.repositories.HomeworkRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import io.github.wulkanowy.utils.getLastSchoolDayIfHoliday
|
||||
import io.github.wulkanowy.utils.isHolidays
|
||||
import io.github.wulkanowy.utils.monday
|
||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||
import io.github.wulkanowy.utils.sunday
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.*
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -89,61 +81,59 @@ class HomeworkPresenter @Inject constructor(
|
||||
flow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
emit(semesterRepository.getCurrentSemester(student))
|
||||
}.catch {
|
||||
Timber.i("Loading semester result: An exception occurred")
|
||||
}.onEach {
|
||||
baseDate = baseDate.getLastSchoolDayIfHoliday(it.schoolYear)
|
||||
currentDate = baseDate
|
||||
reloadNavigation()
|
||||
}.launch("holidays")
|
||||
}
|
||||
.catch { Timber.i("Loading semester result: An exception occurred") }
|
||||
.onEach {
|
||||
baseDate = baseDate.getLastSchoolDayIfHoliday(it.schoolYear)
|
||||
currentDate = baseDate
|
||||
reloadNavigation()
|
||||
}
|
||||
.launch("holidays")
|
||||
}
|
||||
|
||||
private fun loadData(forceRefresh: Boolean = false) {
|
||||
Timber.i("Loading homework data started")
|
||||
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
homeworkRepository.getHomework(student, semester, currentDate, currentDate, forceRefresh)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
if (!it.data.isNullOrEmpty()) {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showRefresh(true)
|
||||
showProgress(false)
|
||||
showContent(true)
|
||||
updateData(createHomeworkItem(it.data))
|
||||
}
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading homework result: Success")
|
||||
view?.apply {
|
||||
updateData(createHomeworkItem(it.data!!))
|
||||
showEmpty(it.data.isEmpty())
|
||||
showErrorView(false)
|
||||
showContent(it.data.isNotEmpty())
|
||||
}
|
||||
analytics.logEvent(
|
||||
"load_data",
|
||||
"type" to "homework",
|
||||
"items" to it.data!!.size
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading homework result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
homeworkRepository.getHomework(
|
||||
student = student,
|
||||
semester = semester,
|
||||
start = currentDate,
|
||||
end = currentDate,
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}
|
||||
.logResourceStatus("loading homework")
|
||||
.mapResourceData { createHomeworkItem(it) }
|
||||
.onResourceData {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showProgress(false)
|
||||
showErrorView(false)
|
||||
showContent(it.isNotEmpty())
|
||||
showEmpty(it.isEmpty())
|
||||
updateData(it)
|
||||
}
|
||||
}
|
||||
}.afterLoading {
|
||||
view?.run {
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
enableSwipe(true)
|
||||
.onResourceIntermediate { view?.showRefresh(true) }
|
||||
.onResourceSuccess {
|
||||
analytics.logEvent(
|
||||
"load_data",
|
||||
"type" to "homework",
|
||||
"items" to it.size
|
||||
)
|
||||
}
|
||||
}.launch()
|
||||
.onResourceNotLoading {
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showProgress(false)
|
||||
showRefresh(false)
|
||||
}
|
||||
}
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch()
|
||||
}
|
||||
|
||||
private fun showErrorViewOnError(message: String, error: Throwable) {
|
||||
@ -159,9 +149,10 @@ class HomeworkPresenter @Inject constructor(
|
||||
|
||||
private fun createHomeworkItem(items: List<Homework>): List<HomeworkItem<*>> {
|
||||
return items.groupBy { it.date }.toSortedMap().map { (date, exams) ->
|
||||
listOf(HomeworkItem(date, HomeworkItem.ViewType.HEADER)) + exams.reversed().map { exam ->
|
||||
HomeworkItem(exam, HomeworkItem.ViewType.ITEM)
|
||||
}
|
||||
listOf(HomeworkItem(date, HomeworkItem.ViewType.HEADER)) + exams.reversed()
|
||||
.map { exam ->
|
||||
HomeworkItem(exam, HomeworkItem.ViewType.ITEM)
|
||||
}
|
||||
}.flatten()
|
||||
}
|
||||
|
||||
@ -184,8 +175,10 @@ class HomeworkPresenter @Inject constructor(
|
||||
view?.apply {
|
||||
showPreButton(!currentDate.minusDays(7).isHolidays)
|
||||
showNextButton(!currentDate.plusDays(7).isHolidays)
|
||||
updateNavigationWeek("${currentDate.monday.toFormattedString("dd.MM")} - " +
|
||||
currentDate.sunday.toFormattedString("dd.MM"))
|
||||
updateNavigationWeek(
|
||||
"${currentDate.monday.toFormattedString("dd.MM")} - " +
|
||||
currentDate.sunday.toFormattedString("dd.MM")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,16 @@
|
||||
package io.github.wulkanowy.ui.modules.homework.add
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.db.entities.Homework
|
||||
import io.github.wulkanowy.data.logResourceStatus
|
||||
import io.github.wulkanowy.data.onResourceError
|
||||
import io.github.wulkanowy.data.onResourceSuccess
|
||||
import io.github.wulkanowy.data.repositories.HomeworkRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.toLocalDate
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import java.time.LocalDate
|
||||
import javax.inject.Inject
|
||||
@ -55,7 +56,7 @@ class HomeworkAddPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun saveHomework(subject: String, teacher: String, date: LocalDate, content: String) {
|
||||
flowWithResource {
|
||||
resourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
val entryDate = LocalDate.now()
|
||||
@ -72,21 +73,15 @@ class HomeworkAddPresenter @Inject constructor(
|
||||
attachments = emptyList(),
|
||||
).apply { isAddedByUser = true }
|
||||
)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Homework insert start")
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Homework insert: Success")
|
||||
view?.run {
|
||||
showSuccessMessage()
|
||||
closeDialog()
|
||||
}
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Homework insert result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
.logResourceStatus("homework insert")
|
||||
.onResourceSuccess {
|
||||
view?.run {
|
||||
showSuccessMessage()
|
||||
closeDialog()
|
||||
}
|
||||
}
|
||||
}.launch("add_homework")
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch("add_homework")
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,16 @@
|
||||
package io.github.wulkanowy.ui.modules.homework.details
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.db.entities.Homework
|
||||
import io.github.wulkanowy.data.logResourceStatus
|
||||
import io.github.wulkanowy.data.onResourceError
|
||||
import io.github.wulkanowy.data.onResourceSuccess
|
||||
import io.github.wulkanowy.data.repositories.HomeworkRepository
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -34,38 +35,26 @@ class HomeworkDetailsPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
fun deleteHomework(homework: Homework) {
|
||||
flowWithResource { homeworkRepository.deleteHomework(homework) }.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Homework delete start")
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Homework delete: Success")
|
||||
view?.run {
|
||||
showMessage(homeworkDeleteSuccess)
|
||||
closeDialog()
|
||||
}
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Homework delete result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
resourceFlow { homeworkRepository.deleteHomework(homework) }
|
||||
.logResourceStatus("homework delete")
|
||||
.onResourceSuccess {
|
||||
view?.run {
|
||||
showMessage(homeworkDeleteSuccess)
|
||||
closeDialog()
|
||||
}
|
||||
}
|
||||
}.launch("delete")
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch("delete")
|
||||
}
|
||||
|
||||
fun toggleDone(homework: Homework) {
|
||||
flowWithResource { homeworkRepository.toggleDone(homework) }.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Homework details update start")
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Homework details update: Success")
|
||||
view?.updateMarkAsDoneLabel(homework.isDone)
|
||||
analytics.logEvent("homework_mark_as_done")
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Homework details update result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
resourceFlow { homeworkRepository.toggleDone(homework) }
|
||||
.logResourceStatus("homework details update")
|
||||
.onResourceSuccess {
|
||||
view?.updateMarkAsDoneLabel(homework.isDone)
|
||||
analytics.logEvent("homework_mark_as_done")
|
||||
}
|
||||
}.launch("toggle")
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch("toggle")
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,16 @@
|
||||
package io.github.wulkanowy.ui.modules.login.advanced
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.logResourceStatus
|
||||
import io.github.wulkanowy.data.onResourceNotLoading
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.ifNullOrBlank
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
@ -129,20 +130,20 @@ class LoginAdvancedPresenter @Inject constructor(
|
||||
fun onSignInClick() {
|
||||
if (!validateCredentials()) return
|
||||
|
||||
flowWithResource { getStudentsAppropriatesToLoginType() }.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> view?.run {
|
||||
Timber.i("Login started")
|
||||
hideSoftKeyboard()
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Login result: Success")
|
||||
analytics.logEvent(
|
||||
"registration_form",
|
||||
resourceFlow { getStudentsAppropriatesToLoginType() }
|
||||
.logResourceStatus("login")
|
||||
.onEach {
|
||||
when (it) {
|
||||
is Resource.Loading -> view?.run {
|
||||
hideSoftKeyboard()
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
}
|
||||
is Resource.Success -> {
|
||||
analytics.logEvent(
|
||||
"registration_form",
|
||||
"success" to true,
|
||||
"students" to it.data!!.size,
|
||||
"students" to it.data.size,
|
||||
"error" to "No error"
|
||||
)
|
||||
val loginData = LoginData(
|
||||
@ -154,23 +155,22 @@ class LoginAdvancedPresenter @Inject constructor(
|
||||
0 -> view?.navigateToSymbol(loginData)
|
||||
else -> view?.navigateToStudentSelect(it.data)
|
||||
}
|
||||
}
|
||||
is Resource.Error -> {
|
||||
analytics.logEvent(
|
||||
"registration_form",
|
||||
"success" to false, "students" to -1,
|
||||
"error" to it.error.message.ifNullOrBlank { "No message" }
|
||||
)
|
||||
loginErrorHandler.dispatch(it.error)
|
||||
}
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Login result: An exception occurred")
|
||||
analytics.logEvent(
|
||||
"registration_form",
|
||||
"success" to false, "students" to -1,
|
||||
"error" to it.error!!.message.ifNullOrBlank { "No message" }
|
||||
)
|
||||
loginErrorHandler.dispatch(it.error)
|
||||
}.onResourceNotLoading {
|
||||
view?.apply {
|
||||
showProgress(false)
|
||||
showContent(true)
|
||||
}
|
||||
}
|
||||
}.afterLoading {
|
||||
view?.apply {
|
||||
showProgress(false)
|
||||
showContent(true)
|
||||
}
|
||||
}.launch("login")
|
||||
}.launch("login")
|
||||
}
|
||||
|
||||
private suspend fun getStudentsAppropriatesToLoginType(): List<StudentWithSemesters> {
|
||||
|
@ -1,16 +1,13 @@
|
||||
package io.github.wulkanowy.ui.modules.login.form
|
||||
|
||||
import androidx.core.net.toUri
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.ifNullOrBlank
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import java.net.URL
|
||||
import javax.inject.Inject
|
||||
@ -75,7 +72,7 @@ class LoginFormPresenter @Inject constructor(
|
||||
|
||||
val username = view?.formUsernameValue.orEmpty().trim()
|
||||
if ("@" in username && "@vulcan" !in username) {
|
||||
val hosts = view?.getHostsValues().orEmpty().map { it.toUri().host to it }.toMap()
|
||||
val hosts = view?.getHostsValues().orEmpty().associateBy { it.toUri().host }
|
||||
val usernameHost = username.substringAfter("@")
|
||||
|
||||
hosts[usernameHost]?.let {
|
||||
@ -95,54 +92,54 @@ class LoginFormPresenter @Inject constructor(
|
||||
|
||||
if (!validateCredentials(email, password, host)) return
|
||||
|
||||
flowWithResource {
|
||||
resourceFlow {
|
||||
studentRepository.getStudentsScrapper(
|
||||
email = email,
|
||||
password = password,
|
||||
scrapperBaseUrl = host,
|
||||
symbol = symbol
|
||||
)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> view?.run {
|
||||
Timber.i("Login started")
|
||||
}
|
||||
.logResourceStatus("login")
|
||||
.onResourceLoading {
|
||||
view?.run {
|
||||
hideSoftKeyboard()
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Login result: Success")
|
||||
analytics.logEvent(
|
||||
"registration_form",
|
||||
"success" to true,
|
||||
"students" to it.data!!.size,
|
||||
"scrapperBaseUrl" to host,
|
||||
"error" to "No error"
|
||||
)
|
||||
when (it.data.size) {
|
||||
0 -> view?.navigateToSymbol(LoginData(email, password, host))
|
||||
else -> view?.navigateToStudentSelect(it.data)
|
||||
}
|
||||
}
|
||||
.onResourceSuccess {
|
||||
when (it.size) {
|
||||
0 -> view?.navigateToSymbol(LoginData(email, password, host))
|
||||
else -> view?.navigateToStudentSelect(it)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Login result: An exception occurred")
|
||||
analytics.logEvent(
|
||||
"registration_form",
|
||||
"success" to false,
|
||||
"students" to -1,
|
||||
"scrapperBaseUrl" to host,
|
||||
"error" to it.error!!.message.ifNullOrBlank { "No message" })
|
||||
loginErrorHandler.dispatch(it.error)
|
||||
lastError = it.error
|
||||
view?.showContact(true)
|
||||
analytics.logEvent(
|
||||
"registration_form",
|
||||
"success" to true,
|
||||
"students" to it.size,
|
||||
"scrapperBaseUrl" to host,
|
||||
"error" to "No error"
|
||||
)
|
||||
}
|
||||
.onResourceNotLoading {
|
||||
view?.apply {
|
||||
showProgress(false)
|
||||
showContent(true)
|
||||
}
|
||||
}
|
||||
}.afterLoading {
|
||||
view?.apply {
|
||||
showProgress(false)
|
||||
showContent(true)
|
||||
.onResourceError {
|
||||
loginErrorHandler.dispatch(it)
|
||||
lastError = it
|
||||
view?.showContact(true)
|
||||
analytics.logEvent(
|
||||
"registration_form",
|
||||
"success" to false,
|
||||
"students" to -1,
|
||||
"scrapperBaseUrl" to host,
|
||||
"error" to it.message.ifNullOrBlank { "No message" }
|
||||
)
|
||||
}
|
||||
}.launch("login")
|
||||
.launch("login")
|
||||
}
|
||||
|
||||
fun onFaqClick() {
|
||||
|
@ -1,12 +1,12 @@
|
||||
package io.github.wulkanowy.ui.modules.login.recover
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.onResourceNotLoading
|
||||
import io.github.wulkanowy.data.repositories.RecoverRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.ifNullOrBlank
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
@ -57,24 +57,28 @@ class LoginRecoverPresenter @Inject constructor(
|
||||
|
||||
if (!validateInput(username, host)) return
|
||||
|
||||
flowWithResource { recoverRepository.getReCaptchaSiteKey(host, symbol.ifBlank { "Default" }) }.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> view?.run {
|
||||
resourceFlow {
|
||||
recoverRepository.getReCaptchaSiteKey(
|
||||
host,
|
||||
symbol.ifBlank { "Default" })
|
||||
}.onEach {
|
||||
when (it) {
|
||||
is Resource.Loading -> view?.run {
|
||||
hideSoftKeyboard()
|
||||
showRecoverForm(false)
|
||||
showProgress(true)
|
||||
showErrorView(false)
|
||||
showCaptcha(false)
|
||||
}
|
||||
Status.SUCCESS -> view?.run {
|
||||
loadReCaptcha(url = it.data!!.first, siteKey = it.data.second)
|
||||
is Resource.Success -> view?.run {
|
||||
loadReCaptcha(url = it.data.first, siteKey = it.data.second)
|
||||
showProgress(false)
|
||||
showErrorView(false)
|
||||
showCaptcha(true)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
is Resource.Error -> {
|
||||
Timber.i("Obtain captcha site key result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
errorHandler.dispatch(it.error)
|
||||
}
|
||||
}
|
||||
}.launch("captcha")
|
||||
@ -101,26 +105,43 @@ class LoginRecoverPresenter @Inject constructor(
|
||||
val host = view?.recoverHostValue.orEmpty()
|
||||
val symbol = view?.formHostSymbol.ifNullOrBlank { "Default" }
|
||||
|
||||
flowWithResource { recoverRepository.sendRecoverRequest(host, symbol, username, reCaptchaResponse) }.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> view?.run {
|
||||
resourceFlow {
|
||||
recoverRepository.sendRecoverRequest(
|
||||
host,
|
||||
symbol,
|
||||
username,
|
||||
reCaptchaResponse
|
||||
)
|
||||
}.onEach {
|
||||
when (it) {
|
||||
is Resource.Loading -> view?.run {
|
||||
showProgress(true)
|
||||
showRecoverForm(false)
|
||||
showCaptcha(false)
|
||||
}
|
||||
Status.SUCCESS -> view?.run {
|
||||
is Resource.Success -> view?.run {
|
||||
showSuccessView(true)
|
||||
setSuccessTitle(it.data!!.substringBefore(". "))
|
||||
setSuccessTitle(it.data.substringBefore(". "))
|
||||
setSuccessMessage(it.data.substringAfter(". "))
|
||||
analytics.logEvent("account_recover", "register" to host, "symbol" to symbol, "success" to true)
|
||||
analytics.logEvent(
|
||||
"account_recover",
|
||||
"register" to host,
|
||||
"symbol" to symbol,
|
||||
"success" to true
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
is Resource.Error -> {
|
||||
Timber.i("Send recover request result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
analytics.logEvent("account_recover", "register" to host, "symbol" to symbol, "success" to false)
|
||||
errorHandler.dispatch(it.error)
|
||||
analytics.logEvent(
|
||||
"account_recover",
|
||||
"register" to host,
|
||||
"symbol" to symbol,
|
||||
"success" to false
|
||||
)
|
||||
}
|
||||
}
|
||||
}.afterLoading {
|
||||
}.onResourceNotLoading {
|
||||
view?.showProgress(false)
|
||||
}.launch("verified")
|
||||
}
|
||||
|
@ -1,14 +1,15 @@
|
||||
package io.github.wulkanowy.ui.modules.login.studentselect
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.logResourceStatus
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.services.sync.SyncManager
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.ifNullOrBlank
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
@ -66,16 +67,16 @@ class LoginStudentSelectPresenter @Inject constructor(
|
||||
private fun loadData(studentsWithSemesters: List<StudentWithSemesters>) {
|
||||
resetSelectedState()
|
||||
|
||||
flowWithResource { studentRepository.getSavedStudents(false) }.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.d("Login student select students load started")
|
||||
Status.SUCCESS -> view?.updateData(studentsWithSemesters.map { studentWithSemesters ->
|
||||
studentWithSemesters to it.data!!.any { item ->
|
||||
resourceFlow { studentRepository.getSavedStudents(false) }.onEach {
|
||||
when (it) {
|
||||
is Resource.Loading -> Timber.d("Login student select students load started")
|
||||
is Resource.Success -> view?.updateData(studentsWithSemesters.map { studentWithSemesters ->
|
||||
studentWithSemesters to it.data.any { item ->
|
||||
compareStudents(studentWithSemesters.student, item.student)
|
||||
}
|
||||
})
|
||||
Status.ERROR -> {
|
||||
errorHandler.dispatch(it.error!!)
|
||||
is Resource.Error -> {
|
||||
errorHandler.dispatch(it.error)
|
||||
lastError = it.error
|
||||
view?.updateData(studentsWithSemesters.map { student -> student to false })
|
||||
}
|
||||
@ -89,29 +90,27 @@ class LoginStudentSelectPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun registerStudents(studentsWithSemesters: List<StudentWithSemesters>) {
|
||||
flowWithResource { studentRepository.saveStudents(studentsWithSemesters) }
|
||||
resourceFlow { studentRepository.saveStudents(studentsWithSemesters) }
|
||||
.logResourceStatus("registration")
|
||||
.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> view?.run {
|
||||
Timber.i("Registration started")
|
||||
when (it) {
|
||||
is Resource.Loading -> view?.run {
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Registration result: Success")
|
||||
is Resource.Success -> {
|
||||
syncManager.startOneTimeSyncWorker(quiet = true)
|
||||
view?.openMainView()
|
||||
logRegisterEvent(studentsWithSemesters)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Registration result: An exception occurred ")
|
||||
is Resource.Error -> {
|
||||
view?.apply {
|
||||
showProgress(false)
|
||||
showContent(true)
|
||||
showContact(true)
|
||||
}
|
||||
lastError = it.error
|
||||
loginErrorHandler.dispatch(it.error!!)
|
||||
loginErrorHandler.dispatch(it.error)
|
||||
logRegisterEvent(studentsWithSemesters, it.error)
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
package io.github.wulkanowy.ui.modules.login.symbol
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.onResourceNotLoading
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.ifNullOrBlank
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
@ -45,7 +45,7 @@ class LoginSymbolPresenter @Inject constructor(
|
||||
return
|
||||
}
|
||||
|
||||
flowWithResource {
|
||||
resourceFlow {
|
||||
studentRepository.getStudentsScrapper(
|
||||
email = loginData.login,
|
||||
password = loginData.password,
|
||||
@ -53,15 +53,15 @@ class LoginSymbolPresenter @Inject constructor(
|
||||
symbol = symbol,
|
||||
)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> view?.run {
|
||||
when (it) {
|
||||
is Resource.Loading -> view?.run {
|
||||
Timber.i("Login with symbol started")
|
||||
hideSoftKeyboard()
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
when (it.data?.size) {
|
||||
is Resource.Success -> {
|
||||
when (it.data.size) {
|
||||
0 -> {
|
||||
Timber.i("Login with symbol result: Empty student list")
|
||||
view?.run {
|
||||
@ -77,13 +77,13 @@ class LoginSymbolPresenter @Inject constructor(
|
||||
analytics.logEvent(
|
||||
"registration_symbol",
|
||||
"success" to true,
|
||||
"students" to it.data!!.size,
|
||||
"students" to it.data.size,
|
||||
"scrapperBaseUrl" to loginData.baseUrl,
|
||||
"symbol" to symbol,
|
||||
"error" to "No error"
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
is Resource.Error -> {
|
||||
Timber.i("Login with symbol result: An exception occurred")
|
||||
analytics.logEvent(
|
||||
"registration_symbol",
|
||||
@ -91,14 +91,14 @@ class LoginSymbolPresenter @Inject constructor(
|
||||
"students" to -1,
|
||||
"scrapperBaseUrl" to loginData.baseUrl,
|
||||
"symbol" to symbol,
|
||||
"error" to it.error!!.message.ifNullOrBlank { "No message" }
|
||||
"error" to it.error.message.ifNullOrBlank { "No message" }
|
||||
)
|
||||
loginErrorHandler.dispatch(it.error)
|
||||
lastError = it.error
|
||||
view?.showContact(true)
|
||||
}
|
||||
}
|
||||
}.afterLoading {
|
||||
}.onResourceNotLoading {
|
||||
view?.apply {
|
||||
showProgress(false)
|
||||
showContent(true)
|
||||
|
@ -1,14 +1,11 @@
|
||||
package io.github.wulkanowy.ui.modules.luckynumber
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -34,47 +31,45 @@ class LuckyNumberPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData(forceRefresh: Boolean = false) {
|
||||
flowWithResourceIn {
|
||||
flatResourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
luckyNumberRepository.getLuckyNumber(student, forceRefresh)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Loading lucky number started")
|
||||
Status.SUCCESS -> {
|
||||
if (it.data != null) {
|
||||
Timber.i("Loading lucky number result: Success")
|
||||
view?.apply {
|
||||
updateData(it.data)
|
||||
showContent(true)
|
||||
showEmpty(false)
|
||||
showErrorView(false)
|
||||
}
|
||||
analytics.logEvent(
|
||||
"load_item",
|
||||
"type" to "lucky_number",
|
||||
"number" to it.data.luckyNumber
|
||||
)
|
||||
} else {
|
||||
Timber.i("Loading lucky number result: No lucky number found")
|
||||
view?.run {
|
||||
showContent(false)
|
||||
showEmpty(true)
|
||||
showErrorView(false)
|
||||
}
|
||||
}
|
||||
.logResourceStatus("load lucky number")
|
||||
.onResourceData {
|
||||
if (it != null) {
|
||||
view?.apply {
|
||||
updateData(it)
|
||||
showContent(true)
|
||||
showEmpty(false)
|
||||
showErrorView(false)
|
||||
}
|
||||
} else {
|
||||
view?.run {
|
||||
showContent(false)
|
||||
showEmpty(true)
|
||||
showErrorView(false)
|
||||
}
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading lucky number result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
.onResourceSuccess {
|
||||
if (it != null) {
|
||||
analytics.logEvent(
|
||||
"load_item",
|
||||
"type" to "lucky_number",
|
||||
"number" to it.luckyNumber
|
||||
)
|
||||
}
|
||||
}
|
||||
}.afterLoading {
|
||||
view?.run {
|
||||
hideRefresh()
|
||||
showProgress(false)
|
||||
enableSwipe(true)
|
||||
.onResourceNotLoading {
|
||||
view?.run {
|
||||
hideRefresh()
|
||||
showProgress(false)
|
||||
enableSwipe(true)
|
||||
}
|
||||
}
|
||||
}.launch()
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch()
|
||||
}
|
||||
|
||||
private fun showErrorViewOnError(message: String, error: Throwable) {
|
||||
|
@ -1,24 +1,12 @@
|
||||
package io.github.wulkanowy.ui.modules.luckynumber.history
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.getLastSchoolDayIfHoliday
|
||||
import io.github.wulkanowy.utils.isHolidays
|
||||
import io.github.wulkanowy.utils.monday
|
||||
import io.github.wulkanowy.utils.previousOrSameSchoolDay
|
||||
import io.github.wulkanowy.utils.sunday
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import io.github.wulkanowy.utils.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import timber.log.Timber
|
||||
import java.time.LocalDate
|
||||
import javax.inject.Inject
|
||||
@ -52,55 +40,51 @@ class LuckyNumberHistoryPresenter @Inject constructor(
|
||||
flow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
emit(semesterRepository.getCurrentSemester(student))
|
||||
}.catch {
|
||||
Timber.i("Loading semester result: An exception occurred")
|
||||
}.onEach {
|
||||
currentDate = currentDate.getLastSchoolDayIfHoliday(it.schoolYear)
|
||||
reloadNavigation()
|
||||
}.launch("holidays")
|
||||
}
|
||||
.catch { Timber.i("Loading semester result: An exception occurred") }
|
||||
.onEach {
|
||||
currentDate = currentDate.getLastSchoolDayIfHoliday(it.schoolYear)
|
||||
reloadNavigation()
|
||||
}
|
||||
.launch("holidays")
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
flowWithResource {
|
||||
flow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
luckyNumberRepository.getLuckyNumberHistory(student, currentDate.monday, currentDate.sunday)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Loading lucky number history started")
|
||||
Status.SUCCESS -> {
|
||||
if (!it.data?.first().isNullOrEmpty()) {
|
||||
Timber.i("Loading lucky number result: Success")
|
||||
view?.apply {
|
||||
updateData(it.data!!.first())
|
||||
showContent(true)
|
||||
showEmpty(false)
|
||||
showErrorView(false)
|
||||
showProgress(false)
|
||||
}
|
||||
analytics.logEvent(
|
||||
"load_items",
|
||||
"type" to "lucky_number_history",
|
||||
"numbers" to it.data
|
||||
)
|
||||
} else {
|
||||
Timber.i("Loading lucky number history result: No lucky numbers found")
|
||||
view?.run {
|
||||
showContent(false)
|
||||
showEmpty(true)
|
||||
showErrorView(false)
|
||||
}
|
||||
emitAll(
|
||||
luckyNumberRepository.getLuckyNumberHistory(
|
||||
student = student,
|
||||
start = currentDate.monday,
|
||||
end = currentDate.sunday
|
||||
)
|
||||
)
|
||||
}
|
||||
.onEach {
|
||||
if (!it.isNullOrEmpty()) {
|
||||
view?.apply {
|
||||
updateData(it)
|
||||
showContent(true)
|
||||
showEmpty(false)
|
||||
showErrorView(false)
|
||||
showProgress(false)
|
||||
}
|
||||
} else {
|
||||
view?.run {
|
||||
showContent(false)
|
||||
showEmpty(true)
|
||||
showErrorView(false)
|
||||
showProgress(false)
|
||||
}
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading lucky number history result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
|
||||
analytics.logEvent(
|
||||
"load_items",
|
||||
"type" to "lucky_number_history",
|
||||
)
|
||||
}
|
||||
}.afterLoading {
|
||||
view?.run {
|
||||
showProgress(false)
|
||||
}
|
||||
}.launch()
|
||||
.catch { errorHandler.dispatch(it) }
|
||||
.launchIn(presenterScope)
|
||||
}
|
||||
|
||||
private fun showErrorViewOnError(message: String, error: Throwable) {
|
||||
@ -143,8 +127,10 @@ class LuckyNumberHistoryPresenter @Inject constructor(
|
||||
view?.apply {
|
||||
showPreButton(!currentDate.minusDays(7).isHolidays)
|
||||
showNextButton(!currentDate.plusDays(7).isHolidays)
|
||||
updateNavigationWeek("${currentDate.monday.toFormattedString("dd.MM")} - " +
|
||||
currentDate.sunday.toFormattedString("dd.MM"))
|
||||
updateNavigationWeek(
|
||||
"${currentDate.monday.toFormattedString("dd.MM")} - " +
|
||||
currentDate.sunday.toFormattedString("dd.MM")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
package io.github.wulkanowy.ui.modules.luckynumberwidget
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.ui.modules.luckynumberwidget.LuckyNumberWidgetProvider.Companion.getStudentWidgetKey
|
||||
import io.github.wulkanowy.ui.modules.luckynumberwidget.LuckyNumberWidgetProvider.Companion.getThemeWidgetKey
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
@ -47,16 +47,15 @@ class LuckyNumberWidgetConfigurePresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
flowWithResource { studentRepository.getSavedStudents(false) }.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.d("Lucky number widget configure students data load")
|
||||
Status.SUCCESS -> {
|
||||
resourceFlow { studentRepository.getSavedStudents(false) }.onEach {
|
||||
when (it) {
|
||||
is Resource.Loading -> Timber.d("Lucky number widget configure students data load")
|
||||
is Resource.Success -> {
|
||||
val selectedStudentId = appWidgetId?.let { id ->
|
||||
sharedPref.getLong(getStudentWidgetKey(id), 0)
|
||||
} ?: -1
|
||||
|
||||
when {
|
||||
it.data!!.isEmpty() -> view?.openLoginView()
|
||||
it.data.isEmpty() -> view?.openLoginView()
|
||||
it.data.size == 1 -> {
|
||||
selectedStudent = it.data.single().student
|
||||
view?.showThemeDialog()
|
||||
@ -64,7 +63,7 @@ class LuckyNumberWidgetConfigurePresenter @Inject constructor(
|
||||
else -> view?.updateData(it.data, selectedStudentId)
|
||||
}
|
||||
}
|
||||
Status.ERROR -> errorHandler.dispatch(it.error!!)
|
||||
is Resource.Error -> errorHandler.dispatch(it.error)
|
||||
}
|
||||
}.launch()
|
||||
}
|
||||
|
@ -13,14 +13,17 @@ import android.view.View.VISIBLE
|
||||
import android.widget.RemoteViews
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.dataOrNull
|
||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
||||
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.toFirstResult
|
||||
import io.github.wulkanowy.ui.modules.Destination
|
||||
import io.github.wulkanowy.ui.modules.splash.SplashActivity
|
||||
import io.github.wulkanowy.utils.PendingIntentCompat
|
||||
import io.github.wulkanowy.utils.toFirstResult
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
@ -66,12 +69,16 @@ class LuckyNumberWidgetProvider : AppWidgetProvider() {
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
if (luckyNumber is Resource.Error) {
|
||||
Timber.e("Error loading lucky number for widget", luckyNumber.error)
|
||||
}
|
||||
|
||||
val remoteView =
|
||||
RemoteViews(context.packageName, getCorrectLayoutId(appWidgetId, context))
|
||||
.apply {
|
||||
setTextViewText(
|
||||
R.id.luckyNumberWidgetNumber,
|
||||
luckyNumber?.luckyNumber?.toString() ?: "#"
|
||||
luckyNumber.dataOrNull?.toString() ?: "#"
|
||||
)
|
||||
setOnClickPendingIntent(R.id.luckyNumberWidgetContainer, appIntent)
|
||||
}
|
||||
@ -167,14 +174,17 @@ class LuckyNumberWidgetProvider : AppWidgetProvider() {
|
||||
else -> null
|
||||
}
|
||||
|
||||
currentStudent?.let {
|
||||
luckyNumberRepository.getLuckyNumber(it, false).toFirstResult().data
|
||||
if (currentStudent != null) {
|
||||
luckyNumberRepository.getLuckyNumber(currentStudent, forceRefresh = false)
|
||||
.toFirstResult()
|
||||
} else {
|
||||
Resource.Success<LuckyNumber?>(null)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (e.cause !is NoCurrentStudentException) {
|
||||
Timber.e(e, "An error has occurred in lucky number provider")
|
||||
}
|
||||
null
|
||||
Resource.Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,16 +23,7 @@ import io.github.wulkanowy.databinding.ActivityMainBinding
|
||||
import io.github.wulkanowy.ui.base.BaseActivity
|
||||
import io.github.wulkanowy.ui.modules.Destination
|
||||
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import io.github.wulkanowy.utils.InAppReviewHelper
|
||||
import io.github.wulkanowy.utils.UpdateHelper
|
||||
import io.github.wulkanowy.utils.createNameInitialsDrawable
|
||||
import io.github.wulkanowy.utils.dpToPx
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.nickOrName
|
||||
import io.github.wulkanowy.utils.safelyPopFragments
|
||||
import io.github.wulkanowy.utils.setOnViewChangeListener
|
||||
import io.github.wulkanowy.utils.*
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -169,8 +160,12 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
.setIcon(R.drawable.ic_main_more)
|
||||
}
|
||||
selectedItemId = startMenuIndex
|
||||
setOnItemSelectedListener { presenter.onTabSelected(it.itemId, false) }
|
||||
setOnItemReselectedListener { presenter.onTabSelected(it.itemId, true) }
|
||||
setOnItemSelectedListener {
|
||||
this@MainActivity.presenter.onTabSelected(it.itemId, false)
|
||||
}
|
||||
setOnItemReselectedListener {
|
||||
this@MainActivity.presenter.onTabSelected(it.itemId, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,8 +173,10 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
caller: PreferenceFragmentCompat,
|
||||
pref: Preference
|
||||
): Boolean {
|
||||
val fragment =
|
||||
supportFragmentManager.fragmentFactory.instantiate(classLoader, pref.fragment)
|
||||
val fragment = supportFragmentManager.fragmentFactory.instantiate(
|
||||
classLoader,
|
||||
pref.fragment.toString()
|
||||
)
|
||||
pushView(fragment)
|
||||
return true
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
package io.github.wulkanowy.ui.modules.main
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.logResourceStatus
|
||||
import io.github.wulkanowy.data.onResourceError
|
||||
import io.github.wulkanowy.data.onResourceSuccess
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.services.sync.SyncManager
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
@ -16,8 +19,6 @@ import io.github.wulkanowy.ui.modules.message.MessageView
|
||||
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersView
|
||||
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
@ -75,20 +76,14 @@ class MainPresenter @Inject constructor(
|
||||
return
|
||||
}
|
||||
|
||||
flowWithResource { studentRepository.getSavedStudents(false) }
|
||||
.onEach { resource ->
|
||||
when (resource.status) {
|
||||
Status.LOADING -> Timber.i("Loading student avatar data started")
|
||||
Status.SUCCESS -> {
|
||||
studentsWitSemesters = resource.data
|
||||
showCurrentStudentAvatar()
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading student avatar result: An exception occurred")
|
||||
errorHandler.dispatch(resource.error!!)
|
||||
}
|
||||
}
|
||||
}.launch("avatar")
|
||||
resourceFlow { studentRepository.getSavedStudents(false) }
|
||||
.logResourceStatus("load student avatar")
|
||||
.onResourceSuccess {
|
||||
studentsWitSemesters = it
|
||||
showCurrentStudentAvatar()
|
||||
}
|
||||
.onResourceError(errorHandler::dispatch)
|
||||
.launch("avatar")
|
||||
}
|
||||
|
||||
fun onViewChange(destinationView: BaseView) {
|
||||
|
@ -4,12 +4,14 @@ import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.View.INVISIBLE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updateMargins
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
|
||||
import io.github.wulkanowy.data.enums.MessageFolder.SENT
|
||||
import io.github.wulkanowy.data.enums.MessageFolder.TRASHED
|
||||
import io.github.wulkanowy.data.enums.MessageFolder.*
|
||||
import io.github.wulkanowy.databinding.FragmentMessageBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter
|
||||
@ -78,7 +80,6 @@ class MessageFragment : BaseFragment<FragmentMessageBinding>(R.layout.fragment_m
|
||||
}
|
||||
|
||||
binding.messageTabLayout.elevation = requireContext().dpToPx(4f)
|
||||
|
||||
binding.openSendMessageButton.setOnClickListener { presenter.onSendMessageButtonClicked() }
|
||||
}
|
||||
|
||||
@ -93,12 +94,37 @@ class MessageFragment : BaseFragment<FragmentMessageBinding>(R.layout.fragment_m
|
||||
binding.messageProgress.visibility = if (show) VISIBLE else INVISIBLE
|
||||
}
|
||||
|
||||
override fun showNewMessage(show: Boolean) {
|
||||
binding.openSendMessageButton.run {
|
||||
if (show) show() else hide()
|
||||
}
|
||||
}
|
||||
|
||||
override fun showTabLayout(show: Boolean) {
|
||||
binding.messageTabLayout.isVisible = show
|
||||
|
||||
with(binding.messageViewPager) {
|
||||
isUserInputEnabled = show
|
||||
updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
updateMargins(top = if (show) requireContext().dpToPx(48f).toInt() else 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onChildFragmentShowActionMode(show: Boolean) {
|
||||
presenter.onChildViewShowActionMode(show)
|
||||
}
|
||||
|
||||
fun onChildFragmentLoaded() {
|
||||
presenter.onChildViewLoaded()
|
||||
}
|
||||
|
||||
override fun notifyChildMessageDeleted(tabId: Int) {
|
||||
(pagerAdapter.getFragmentInstance(tabId) as? MessageTabFragment)?.onParentDeleteMessage()
|
||||
fun onChildFragmentShowNewMessage(show: Boolean) {
|
||||
presenter.onChildViewShowNewMessage(show)
|
||||
}
|
||||
|
||||
fun onFragmentChanged() {
|
||||
presenter.onFragmentChanged()
|
||||
}
|
||||
|
||||
override fun notifyChildLoadData(index: Int, forceRefresh: Boolean) {
|
||||
@ -106,6 +132,13 @@ class MessageFragment : BaseFragment<FragmentMessageBinding>(R.layout.fragment_m
|
||||
?.onParentLoadData(forceRefresh)
|
||||
}
|
||||
|
||||
override fun notifyChildrenFinishActionMode() {
|
||||
repeat(3) {
|
||||
(pagerAdapter.getFragmentInstance(it) as? MessageTabFragment)
|
||||
?.onParentFinishActionMode()
|
||||
}
|
||||
}
|
||||
|
||||
override fun openSendMessage() {
|
||||
context?.let { it.startActivity(SendMessageActivity.getStartIntent(it)) }
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user