Merge branch 'release/0.20.0' into master

This commit is contained in:
Mikołaj Pich 2020-08-29 23:57:14 +02:00
commit 580ad58dd6
329 changed files with 6316 additions and 4598 deletions

View File

@ -4,7 +4,16 @@
<JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value>
<package name="kotlinx.android.synthetic" withSubpackages="true" static="false" />
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
</value>
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />

View File

@ -14,7 +14,7 @@ cache:
branches:
only:
- develop
- 0.19.0
- 0.20.0
android:
licenses:

View File

@ -1,6 +1,7 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'
apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'com.github.triplet.play'
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
@ -17,8 +18,8 @@ android {
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 17
targetSdkVersion 29
versionCode 63
versionName "0.19.0"
versionCode 64
versionName "0.20.0"
multiDexEnabled true
resValue "string", "app_name", "Wulkanowy"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@ -28,7 +29,7 @@ android {
]
javaCompileOptions {
annotationProcessorOptions {
arguments = [
arguments += [
"room.schemaLocation": "$projectDir/schemas".toString(),
"room.incremental" : "true"
]
@ -86,12 +87,14 @@ android {
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn", "-Xjvm-default=all"]
}
packagingOptions {
@ -112,11 +115,10 @@ play {
}
ext {
work_manager = "2.3.4"
work_manager = "2.4.0"
room = "2.2.5"
dagger = "2.28"
chucker = "3.2.0"
mockk = "1.9.2"
mockk = "1.10.0"
}
configurations.all {
@ -124,13 +126,17 @@ configurations.all {
}
dependencies {
implementation "io.github.wulkanowy:sdk:0.19.0"
implementation "io.github.wulkanowy:sdk:0.20.0"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "androidx.core:core-ktx:1.2.0"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
implementation "androidx.core:core-ktx:1.3.1"
implementation "androidx.activity:activity-ktx:1.1.0"
implementation "androidx.appcompat:appcompat:1.2.0-rc01"
implementation "androidx.appcompat:appcompat-resources:1.1.0"
implementation "androidx.appcompat:appcompat:1.2.0"
implementation "androidx.appcompat:appcompat-resources:1.2.0"
implementation "androidx.fragment:fragment-ktx:1.2.5"
implementation "androidx.annotation:annotation:1.1.0"
implementation "androidx.multidex:multidex:2.0.1"
@ -138,7 +144,7 @@ dependencies {
implementation "androidx.preference:preference-ktx:1.1.1"
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation "androidx.viewpager:viewpager:1.0.0"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-rc01"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "androidx.constraintlayout:constraintlayout:1.1.3"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
implementation "com.google.android.material:material:1.1.0"
@ -147,46 +153,38 @@ dependencies {
implementation "me.zhanghai.android.materialprogressbar:library:1.6.1"
implementation "androidx.work:work-runtime-ktx:$work_manager"
implementation "androidx.work:work-rxjava2:$work_manager"
implementation "androidx.work:work-gcm:$work_manager"
implementation 'com.github.PaulinaSadowska:RxWorkManagerObservers:1.0.0'
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
implementation "androidx.room:room-runtime:$room"
implementation "androidx.room:room-rxjava2:$room"
implementation "androidx.room:room-ktx:$room"
kapt "androidx.room:room-compiler:$room"
implementation "com.google.dagger:dagger-android-support:$dagger"
kapt "com.google.dagger:dagger-compiler:$dagger"
kapt "com.google.dagger:dagger-android-processor:$dagger"
implementation "com.squareup.inject:assisted-inject-annotations-dagger2:0.5.2"
kapt "com.squareup.inject:assisted-inject-processor-dagger2:0.5.2"
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
implementation 'androidx.hilt:hilt-work:1.0.0-alpha02'
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha02'
implementation "com.aurelhubert:ahbottomnavigation:2.3.4"
implementation "com.ncapdevi:frag-nav:3.3.0"
implementation "com.github.YarikSOffice:lingver:1.2.2"
implementation "com.github.pwittchen:reactivenetwork-rx2:3.0.8"
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
implementation "io.reactivex.rxjava2:rxjava:2.2.19"
implementation "com.google.code.gson:gson:2.8.6"
implementation "com.jakewharton.threetenabp:threetenabp:1.2.4"
implementation "com.jakewharton.timber:timber:4.7.1"
implementation "at.favre.lib:slf4j-timber:1.0.1"
implementation "fr.bipi.treessence:treessence:0.3.2"
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
implementation "io.coil-kt:coil:0.11.0"
implementation "io.coil-kt:coil:1.0.0-rc1"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
playImplementation 'com.google.firebase:firebase-analytics:17.4.3'
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.0.7'
playImplementation "com.google.firebase:firebase-inappmessaging-ktx:19.0.7"
playImplementation 'com.google.firebase:firebase-messaging:20.2.0'
playImplementation 'com.google.firebase:firebase-crashlytics:17.0.1'
playImplementation 'com.google.firebase:firebase-analytics:17.5.0'
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.1.0'
playImplementation "com.google.firebase:firebase-inappmessaging-ktx:19.1.1"
playImplementation 'com.google.firebase:firebase-messaging:20.2.4'
playImplementation 'com.google.firebase:firebase-crashlytics:17.1.1'
playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
@ -196,16 +194,14 @@ dependencies {
testImplementation "junit:junit:4.13"
testImplementation "io.mockk:mockk:$mockk"
testImplementation "org.threeten:threetenbp:1.4.4"
testImplementation "org.mockito:mockito-inline:3.3.3"
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.9'
androidTestImplementation "androidx.test:core:1.2.0"
androidTestImplementation "androidx.test:runner:1.2.0"
androidTestImplementation "androidx.test.ext:junit:1.1.1"
androidTestImplementation "androidx.test.ext:junit:1.1.2"
androidTestImplementation "io.mockk:mockk-android:$mockk"
androidTestImplementation "androidx.room:room-testing:$room"
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
androidTestImplementation "org.mockito:mockito-android:3.3.3"
}
apply plugin: 'com.google.gms.google-services'

View File

@ -30,13 +30,6 @@
-dontwarn javax.annotation.**
#Config for ReactiveNetwork
-dontwarn com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
-dontwarn io.reactivex.functions.Function
-dontwarn rx.internal.util.**
-dontwarn sun.misc.Unsafe
#Config for MPAndroidChart
-keep class com.github.mikephil.charting.** { *; }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
package io.github.wulkanowy.data
import io.github.wulkanowy.utils.DispatchersProvider
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
class TestDispatchersProvider : DispatchersProvider() {
override val backgroundThread: CoroutineDispatcher
get() = Dispatchers.Unconfined
}

View File

@ -4,6 +4,7 @@ import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase.CONFLICT_FAIL
import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.test.ext.junit.runners.AndroidJUnit4
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.test.assertEquals
@ -29,7 +30,7 @@ class Migration12Test : AbstractMigrationTest() {
helper.runMigrationsAndValidate(dbName, 12, true, Migration12())
val db = getMigratedRoomDatabase()
val students = db.studentDao.loadAll().blockingGet()
val students = runBlocking { db.studentDao.loadAll() }
assertEquals(2, students.size)
@ -58,7 +59,7 @@ class Migration12Test : AbstractMigrationTest() {
helper.runMigrationsAndValidate(dbName, 12, true, Migration12())
val db = getMigratedRoomDatabase()
val students = db.studentDao.loadAll().blockingGet()
val students = runBlocking { db.studentDao.loadAll() }
assertEquals(1, students.size)
@ -84,7 +85,7 @@ class Migration12Test : AbstractMigrationTest() {
helper.runMigrationsAndValidate(dbName, 12, true, Migration12())
val db = getMigratedRoomDatabase()
val students = db.studentDao.loadAll().blockingGet()
val students = runBlocking { db.studentDao.loadAll() }
assertEquals(3, students.size)

View File

@ -5,10 +5,11 @@ import android.database.sqlite.SQLiteDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import io.github.wulkanowy.data.db.Converters
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
import org.threeten.bp.LocalDate.of
import java.time.LocalDate.of
import kotlin.test.assertFalse
import kotlin.test.assertTrue
@ -26,7 +27,7 @@ class Migration13Test : AbstractMigrationTest() {
helper.runMigrationsAndValidate(dbName, 13, true, Migration13())
val db = getMigratedRoomDatabase()
val students = db.studentDao.loadAll().blockingGet()
val students = runBlocking { db.studentDao.loadAll() }
assertEquals(3, students.size)
@ -60,7 +61,7 @@ class Migration13Test : AbstractMigrationTest() {
helper.runMigrationsAndValidate(dbName, 13, true, Migration13())
val db = getMigratedRoomDatabase()
val students = db.studentDao.loadAll().blockingGet()
val students = runBlocking { db.studentDao.loadAll() }
assertEquals(2, students.size)

View File

@ -0,0 +1,124 @@
package io.github.wulkanowy.data.db.migrations
import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Test
import kotlin.random.Random
class Migration27Test : AbstractMigrationTest() {
@Test
fun userWithoutCorrespondingUnit() {
with(helper.createDatabase(dbName, 26)) {
createStudent(this, 321, 123, "Jan Student")
createUnit(this, 9999, "Unit Jan")
close()
}
helper.runMigrationsAndValidate(dbName, 27, true, Migration27())
val db = getMigratedRoomDatabase()
val students = runBlocking { db.studentDao.loadAll() }
assertEquals(1, students.size)
with(students[0]) {
assertEquals(321, id)
assertEquals(123, userLoginId)
assertEquals("Student Jan", userName)
}
}
@Test
fun userWithCorrespondingUnit() {
with(helper.createDatabase(dbName, 26)) {
createStudent(this, 1, 2, "Jan Kowalski Student")
createUnit(this, 2, "Unit Jan")
close()
}
helper.runMigrationsAndValidate(dbName, 27, true, Migration27())
val db = getMigratedRoomDatabase()
val students = runBlocking { db.studentDao.loadAll() }
assertEquals(1, students.size)
with(students[0]) {
assertEquals(1, id)
assertEquals(2, userLoginId)
assertEquals("Unit Jan", userName)
}
}
@Test
fun studentAccountAndParentAccountWithCorrespondingUnits() {
with(helper.createDatabase(dbName, 26)) {
createStudent(this, 1, 222, "Jan Student")
createStudent(this, 2, 333, "Jan Parent")
createUnit(this, 222, "Unit Jan")
createUnit(this, 333, "Unit Tomasz")
close()
}
helper.runMigrationsAndValidate(dbName, 27, true, Migration27())
val db = getMigratedRoomDatabase()
val students = runBlocking { db.studentDao.loadAll() }
assertEquals(2, students.size)
with(students[0]) {
assertEquals(1, id)
assertEquals(222, userLoginId)
assertEquals("Unit Jan", userName)
}
with(students[1]) {
assertEquals(2, id)
assertEquals(333, userLoginId)
assertEquals("Unit Tomasz", userName)
}
}
private fun createStudent(db: SupportSQLiteDatabase, id: Long, userLoginId: Int, studentName: String) {
db.insert("Students", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply {
put("id", id)
put("scrapper_base_url", "https://fakelog.cf")
put("mobile_base_url", "")
put("login_mode", "SCRAPPER")
put("login_type", "STANDARD")
put("certificate_key", "")
put("private_key", "")
put("is_parent", false)
put("email", "jan@fakelog.cf")
put("password", "******")
put("symbol", "Default")
put("school_short", "")
put("class_name", "")
put("student_id", Random.nextInt())
put("class_id", Random.nextInt())
put("school_id", "123")
put("school_name", "Wulkan first class school")
put("is_current", false)
put("registration_date", "0")
put("user_login_id", userLoginId)
put("student_name", studentName)
})
}
private fun createUnit(db: SupportSQLiteDatabase, senderId: Int, senderName: String) {
db.insert("ReportingUnits", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply {
put("student_id", Random.nextInt())
put("real_id", Random.nextInt())
put("short", "SHORT")
put("roles", "[0]")
put("sender_id", senderId)
put("sender_name", senderName)
})
}
}

View File

@ -1,7 +1,9 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import org.threeten.bp.LocalDateTime
import java.time.LocalDate.now
import java.time.LocalDateTime
fun getStudent(): Student {
return Student(
@ -11,6 +13,7 @@ fun getStudent(): Student {
scrapperBaseUrl = "fakelog.cf",
loginType = "AUTO",
isCurrent = true,
userName = "",
studentName = "",
schoolShortName = "",
schoolName = "",
@ -27,3 +30,16 @@ fun getStudent(): Student {
isParent = false
)
}
fun getSemester() = Semester(
semesterId = 1,
studentId = 1,
classId = 1,
diaryId = 2,
diaryName = "",
end = now(),
schoolYear = 2019,
semesterName = 1,
start = now(),
unitId = 1
)

View File

@ -1,19 +0,0 @@
package io.github.wulkanowy.data.repositories
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingStrategy
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.ErrorHandler
import io.reactivex.Observable
import io.reactivex.Single
class TestInternetObservingStrategy : InternetObservingStrategy {
override fun checkInternetConnectivity(host: String?, port: Int, timeoutInMs: Int, httpResponse: Int, errorHandler: ErrorHandler?): Single<Boolean> {
return Single.just(true)
}
override fun observeInternetConnectivity(initialIntervalInMs: Int, intervalInMs: Int, host: String?, port: Int, timeoutInMs: Int, httpResponse: Int, errorHandler: ErrorHandler?): Observable<Boolean> {
return Observable.just(true)
}
override fun getDefaultPingHost() = "localhost"
}

View File

@ -6,13 +6,15 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDate.now
import org.threeten.bp.LocalDate.of
import java.time.LocalDate
import java.time.LocalDate.now
import java.time.LocalDate.of
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -35,7 +37,7 @@ class AttendanceLocalTest {
@Test
fun saveAndReadTest() {
attendanceLocal.saveAttendance(listOf(
val list = listOf(
getAttendanceEntity(
of(2018, 9, 10),
SentExcuseStatus.ACCEPTED
@ -48,14 +50,11 @@ class AttendanceLocalTest {
of(2018, 9, 17),
SentExcuseStatus.ACCEPTED
)
))
val attendance = attendanceLocal
.getAttendance(Semester(1, 2, "", 1, 3, 2019, now(), now(), 1, 1),
of(2018, 9, 10),
of(2018, 9, 14)
)
.blockingGet()
runBlocking { attendanceLocal.saveAttendance(list) }
val semester = Semester(1, 2, "", 1, 3, 2019, now(), now(), 1, 1)
val attendance = runBlocking { attendanceLocal.getAttendance(semester, of(2018, 9, 10), of(2018, 9, 14)).first() }
assertEquals(2, attendance.size)
assertEquals(attendance[0].date, of(2018, 9, 10))
assertEquals(attendance[1].date, of(2018, 9, 14))

View File

@ -6,13 +6,15 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDate.now
import org.threeten.bp.LocalDate.of
import java.time.LocalDate
import java.time.LocalDate.now
import java.time.LocalDate.of
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -24,7 +26,8 @@ class CompletedLessonsLocalTest {
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
testDb = Room
.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
completedLessonsLocal = CompletedLessonsLocal(testDb.completedLessonsDao)
}
@ -36,18 +39,15 @@ class CompletedLessonsLocalTest {
@Test
fun saveAndReadTest() {
completedLessonsLocal.saveCompletedLessons(listOf(
val list = listOf(
getCompletedLesson(of(2018, 9, 10), 1),
getCompletedLesson(of(2018, 9, 14), 2),
getCompletedLesson(of(2018, 9, 17), 3)
))
val completed = completedLessonsLocal
.getCompletedLessons(Semester(1, 2, "", 1, 3, 2019, now(), now(), 1, 1),
of(2018, 9, 10),
of(2018, 9, 14)
)
.blockingGet()
runBlocking { completedLessonsLocal.saveCompletedLessons(list) }
val semester = Semester(1, 2, "", 1, 3, 2019, now(), now(), 1, 1)
val completed = runBlocking { completedLessonsLocal.getCompletedLessons(semester, of(2018, 9, 10), of(2018, 9, 14)).first() }
assertEquals(2, completed.size)
assertEquals(completed[0].date, of(2018, 9, 10))
assertEquals(completed[1].date, of(2018, 9, 14))

View File

@ -6,12 +6,14 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate.now
import org.threeten.bp.LocalDate.of
import java.time.LocalDate.now
import java.time.LocalDate.of
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -34,18 +36,15 @@ class ExamLocalTest {
@Test
fun saveAndReadTest() {
examLocal.saveExams(listOf(
val list = listOf(
Exam(1, 2, of(2018, 9, 10), now(), "", "", "", "", "", ""),
Exam(1, 2, of(2018, 9, 14), now(), "", "", "", "", "", ""),
Exam(1, 2, of(2018, 9, 17), now(), "", "", "", "", "", "")
))
val exams = examLocal
.getExams(Semester(1, 2, "", 1, 3, 2019, now(), now(), 1, 1),
of(2018, 9, 10),
of(2018, 9, 14)
)
.blockingGet()
runBlocking { examLocal.saveExams(list) }
val semester = Semester(1, 2, "", 1, 3, 2019, now(), now(), 1, 1)
val exams = runBlocking { examLocal.getExams(semester, of(2018, 9, 10), of(2018, 9, 14)).first() }
assertEquals(2, exams.size)
assertEquals(exams[0].date, of(2018, 9, 10))
assertEquals(exams[1].date, of(2018, 9, 14))

View File

@ -5,12 +5,14 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDate.now
import java.time.LocalDate
import java.time.LocalDate.now
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -22,7 +24,8 @@ class GradeLocalTest {
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
testDb = Room
.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
gradeLocal = GradeLocal(testDb.gradeDao, testDb.gradeSummaryDao)
}
@ -34,17 +37,16 @@ class GradeLocalTest {
@Test
fun saveAndReadTest() {
gradeLocal.saveGrades(listOf(
val list = listOf(
createGradeLocal(5, 3.0, LocalDate.of(2018, 9, 10), "", 1),
createGradeLocal(4, 4.0, LocalDate.of(2019, 2, 27), "", 2),
createGradeLocal(3, 5.0, LocalDate.of(2019, 2, 28), "", 2)
))
)
runBlocking { gradeLocal.saveGrades(list) }
val semester = Semester(1, 2, "", 2019, 2, 1, now(), now(), 1, 1)
val grades = gradeLocal
.getGradesDetails(semester)
.blockingGet()
val grades = runBlocking { gradeLocal.getGradesDetails(semester).first() }
assertEquals(2, grades.size)
assertEquals(grades[0].date, LocalDate.of(2019, 2, 27))

View File

@ -5,23 +5,25 @@ import androidx.room.Room
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.TestInternetObservingStrategy
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Grade
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.reactivex.Single
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate.of
import org.threeten.bp.LocalDateTime
import java.time.LocalDate.of
import java.time.LocalDateTime
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
@ -30,19 +32,12 @@ import kotlin.test.assertTrue
@RunWith(AndroidJUnit4::class)
class GradeRepositoryTest {
@MockK
private lateinit var mockSdk: Sdk
private val settings = InternetObservingSettings.builder()
.strategy(TestInternetObservingStrategy())
.build()
@MockK
private lateinit var semesterMock: Semester
@MockK
private lateinit var studentMock: Student
@MockK
private lateinit var gradeRemote: GradeRemote
private lateinit var gradeLocal: GradeLocal
@ -54,14 +49,12 @@ class GradeRepositoryTest {
MockKAnnotations.init(this)
testDb = Room.inMemoryDatabaseBuilder(getApplicationContext(), AppDatabase::class.java).build()
gradeLocal = GradeLocal(testDb.gradeDao, testDb.gradeSummaryDao)
gradeRemote = GradeRemote(mockSdk)
studentMock = getStudentMock()
every { studentMock.registrationDate } returns LocalDateTime.of(2019, 2, 27, 12, 0)
every { semesterMock.studentId } returns 1
every { semesterMock.diaryId } returns 1
every { semesterMock.schoolYear } returns 2019
every { semesterMock.semesterId } returns 1
every { mockSdk.switchDiary(any(), any()) } returns mockSdk
}
@After
@ -71,15 +64,18 @@ class GradeRepositoryTest {
@Test
fun markOlderThanRegisterDateAsRead() {
every { mockSdk.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 4.0, of(2019, 2, 25), "Ocena pojawiła się"),
createGradeApi(5, 4.0, of(2019, 2, 26), "przed zalogowanie w aplikacji"),
createGradeApi(5, 4.0, of(2019, 2, 27), "Ocena z dnia logowania"),
createGradeApi(5, 4.0, of(2019, 2, 28), "Ocena jeszcze nowsza")
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (listOf(
createGradeLocal(5, 4.0, of(2019, 2, 25), "Ocena pojawiła się"),
createGradeLocal(5, 4.0, of(2019, 2, 26), "przed zalogowanie w aplikacji"),
createGradeLocal(5, 4.0, of(2019, 2, 27), "Ocena z dnia logowania"),
createGradeLocal(5, 4.0, of(2019, 2, 28), "Ocena jeszcze nowsza")
) to emptyList())
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet().first.sortedByDescending { it.date }
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!.first.sortedByDescending { it.date }
}
assertFalse { grades[0].isRead }
assertFalse { grades[1].isRead }
@ -89,21 +85,25 @@ class GradeRepositoryTest {
@Test
fun mitigateOldGradesNotifications() {
gradeLocal.saveGrades(listOf(
val list = listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Jedna ocena"),
createGradeLocal(4, 4.0, of(2019, 2, 26), "Druga"),
createGradeLocal(3, 5.0, of(2019, 2, 27), "Trzecia")
))
)
runBlocking { gradeLocal.saveGrades(list) }
every { mockSdk.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 2.0, of(2019, 2, 25), "Ocena ma datę, jest inna, ale nie zostanie powiadomiona"),
createGradeApi(4, 3.0, of(2019, 2, 26), "starszą niż ostatnia lokalnie"),
createGradeApi(3, 4.0, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie"),
createGradeApi(2, 5.0, of(2019, 2, 28), "Ta jest już w ogóle nowa")
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (listOf(
createGradeLocal(5, 2.0, of(2019, 2, 25), "Ocena ma datę, jest inna, ale nie zostanie powiadomiona"),
createGradeLocal(4, 3.0, of(2019, 2, 26), "starszą niż ostatnia lokalnie"),
createGradeLocal(3, 4.0, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie"),
createGradeLocal(2, 5.0, of(2019, 2, 28), "Ta jest już w ogóle nowa")
) to emptyList())
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet().first.sortedByDescending { it.date }
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!.first.sortedByDescending { it.date }
}
assertFalse { grades[0].isRead }
assertFalse { grades[1].isRead }
@ -113,70 +113,109 @@ class GradeRepositoryTest {
@Test
fun subtractLocaleDuplicateGrades() {
gradeLocal.saveGrades(listOf(
val list = listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
))
)
runBlocking { gradeLocal.saveGrades(list) }
every { mockSdk.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
) to emptyList())
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet()
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!
}
assertEquals(2, grades.first.size)
}
@Test
fun subtractRemoteDuplicateGrades() {
gradeLocal.saveGrades(listOf(
val list = listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
))
)
runBlocking { gradeLocal.saveGrades(list) }
every { mockSdk.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
) to emptyList())
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet()
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!
}
assertEquals(3, grades.first.size)
}
@Test
fun emptyLocal() {
gradeLocal.saveGrades(listOf())
runBlocking { gradeLocal.saveGrades(listOf()) }
every { mockSdk.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
) to emptyList())
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet()
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!
}
assertEquals(3, grades.first.size)
}
@Test
fun emptyRemote() {
gradeLocal.saveGrades(listOf(
val list = listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
))
)
runBlocking { gradeLocal.saveGrades(list) }
every { mockSdk.getGrades(1) } returns Single.just(emptyList<Grade>() to emptyList())
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (emptyList<Grade>() to emptyList())
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet()
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!
}
assertEquals(0, grades.first.size)
}
private fun getStudentMock() = Student(
scrapperBaseUrl = "http://fakelog.cf",
email = "jan@fakelog.cf",
certificateKey = "",
classId = 0,
className = "",
isCurrent = false,
isParent = false,
loginMode = Sdk.Mode.SCRAPPER.name,
loginType = "STANDARD",
mobileBaseUrl = "",
password = "",
privateKey = "",
registrationDate = LocalDateTime.of(2019, 2, 27, 12, 0),
schoolName = "",
schoolShortName = "test",
schoolSymbol = "",
studentId = 0,
studentName = "",
symbol = "",
userLoginId = 0,
userName = ""
)
}

View File

@ -1,6 +1,6 @@
package io.github.wulkanowy.data.repositories.grade
import org.threeten.bp.LocalDate
import java.time.LocalDate
import io.github.wulkanowy.sdk.pojo.Grade as GradeRemote
import io.github.wulkanowy.data.db.entities.Grade as GradeLocal

View File

@ -7,11 +7,13 @@ import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeStatistics
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate.now
import java.time.LocalDate.now
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -35,40 +37,44 @@ class GradeStatisticsLocalTest {
@Test
fun saveAndRead_subject() {
gradeStatisticsLocal.saveGradesStatistics(listOf(
val list = listOf(
getGradeStatistics("Matematyka", 2, 1),
getGradeStatistics("Fizyka", 1, 2)
))
)
runBlocking { gradeStatisticsLocal.saveGradesStatistics(list) }
val stats = gradeStatisticsLocal.getGradesStatistics(getSemester(), false, "Matematyka").blockingGet()
val stats = runBlocking { gradeStatisticsLocal.getGradesStatistics(getSemester(), false).first() }
assertEquals(1, stats.size)
assertEquals(stats[0].subject, "Matematyka")
}
@Test
fun saveAndRead_all() {
gradeStatisticsLocal.saveGradesStatistics(listOf(
val list = listOf(
getGradeStatistics("Matematyka", 2, 1),
getGradeStatistics("Chemia", 2, 1),
getGradeStatistics("Fizyka", 1, 2)
))
)
runBlocking { gradeStatisticsLocal.saveGradesStatistics(list) }
val stats = gradeStatisticsLocal.getGradesStatistics(getSemester(), false, "Wszystkie").blockingGet()
assertEquals(3, stats.size)
assertEquals(stats[0].subject, "Wszystkie")
assertEquals(stats[1].subject, "Matematyka")
assertEquals(stats[2].subject, "Chemia")
val stats = runBlocking { gradeStatisticsLocal.getGradesStatistics(getSemester(), false).first() }
assertEquals(2, stats.size)
// assertEquals(3, stats.size)
// assertEquals(stats[0].subject, "Wszystkie") // now in main repo
assertEquals(stats[0].subject, "Matematyka")
assertEquals(stats[1].subject, "Chemia")
}
@Test
fun saveAndRead_points() {
gradeStatisticsLocal.saveGradesPointsStatistics(listOf(
val list = listOf(
getGradePointsStatistics("Matematyka", 2, 1),
getGradePointsStatistics("Chemia", 2, 1),
getGradePointsStatistics("Fizyka", 1, 2)
))
)
runBlocking { gradeStatisticsLocal.saveGradesPointsStatistics(list) }
val stats = gradeStatisticsLocal.getGradesPointsStatistics(getSemester(), "Matematyka").blockingGet()
val stats = runBlocking { gradeStatisticsLocal.getGradesPointsStatistics(getSemester()).first() }
with(stats[0]) {
assertEquals(subject, "Matematyka")
assertEquals(others, 5.0)
@ -78,18 +84,18 @@ class GradeStatisticsLocalTest {
@Test
fun saveAndRead_subjectEmpty() {
gradeStatisticsLocal.saveGradesPointsStatistics(listOf())
runBlocking { gradeStatisticsLocal.saveGradesPointsStatistics(listOf()) }
val stats = gradeStatisticsLocal.getGradesPointsStatistics(getSemester(), "Matematyka").blockingGet()
assertEquals(null, stats)
val stats = runBlocking { gradeStatisticsLocal.getGradesPointsStatistics(getSemester()).first() }
assertEquals(emptyList(), stats)
}
@Test
fun saveAndRead_allEmpty() {
gradeStatisticsLocal.saveGradesPointsStatistics(listOf())
runBlocking { gradeStatisticsLocal.saveGradesPointsStatistics(listOf()) }
val stats = gradeStatisticsLocal.getGradesPointsStatistics(getSemester(), "Wszystkie").blockingGet()
assertEquals(null, stats)
val stats = runBlocking { gradeStatisticsLocal.getGradesPointsStatistics(getSemester()).first() }
assertEquals(emptyList(), stats)
}
private fun getSemester(): Semester {

View File

@ -6,12 +6,14 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Student
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDateTime.now
import java.time.LocalDate
import java.time.LocalDateTime.now
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -23,7 +25,8 @@ class LuckyNumberLocalTest {
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
testDb = Room
.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
luckyNumberLocal = LuckyNumberLocal(testDb.luckyNumberDao)
}
@ -35,14 +38,14 @@ class LuckyNumberLocalTest {
@Test
fun saveAndReadTest() {
luckyNumberLocal.saveLuckyNumber(LuckyNumber(1, LocalDate.of(2019, 1, 20), 14))
val number = LuckyNumber(1, LocalDate.of(2019, 1, 20), 14)
runBlocking { luckyNumberLocal.saveLuckyNumber(number) }
val luckyNumber = luckyNumberLocal.getLuckyNumber(Student("", "", "", "", "", "", false, "", "", "", 1, 1, "", "", "", "", "", 1, false, now()),
LocalDate.of(2019, 1, 20)
).blockingGet()
val student = Student("", "", "", "", "", "", false, "", "", "", 1, 1, "", "", "", "", "", "", 1, false, now())
val luckyNumber = runBlocking { luckyNumberLocal.getLuckyNumber(student, LocalDate.of(2019, 1, 20)).first() }
assertEquals(1, luckyNumber.studentId)
assertEquals(LocalDate.of(2019, 1, 20), luckyNumber.date)
assertEquals(14, luckyNumber.luckyNumber)
assertEquals(1, luckyNumber?.studentId)
assertEquals(LocalDate.of(2019, 1, 20), luckyNumber?.date)
assertEquals(14, luckyNumber?.luckyNumber)
}
}

View File

@ -7,11 +7,12 @@ import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.Student
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDateTime
import java.time.LocalDateTime
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -35,17 +36,21 @@ class RecipientLocalTest {
@Test
fun saveAndReadTest() {
recipientLocal.saveRecipients(listOf(
val list = listOf(
Recipient(1, "2rPracownik", "Kowalski Jan", "Kowalski Jan [KJ] - Pracownik (Fake123456)", 3, 4, 2, "hash"),
Recipient(1, "3rPracownik", "Kowalska Karolina", "Kowalska Karolina [KK] - Pracownik (Fake123456)", 4, 4, 2, "hash"),
Recipient(1, "4rPracownik", "Krupa Stanisław", "Krupa Stanisław [KS] - Uczeń (Fake123456)", 5, 4, 1, "hash")
))
)
runBlocking { recipientLocal.saveRecipients(list) }
val recipients = recipientLocal.getRecipients(
Student("fakelog.cf", "AUTO", "", "", "", "", false, "", "", "", 1, 0, "", "", "", "", "", 1, true, LocalDateTime.now()),
2,
ReportingUnit(1, 4, "", 0, "", emptyList())
).blockingGet()
val student = Student("fakelog.cf", "AUTO", "", "", "", "", false, "", "", "", 1, 0, "", "", "", "", "", "", 1, true, LocalDateTime.now())
val recipients = runBlocking {
recipientLocal.getRecipients(
student = student,
role = 2,
unit = ReportingUnit(1, 4, "", 0, "", emptyList())
)
}
assertEquals(2, recipients.size)
assertEquals(1, recipients[0].studentId)

View File

@ -4,8 +4,10 @@ import android.content.Context
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.TestDispatchersProvider
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.repositories.getStudent
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
@ -26,7 +28,7 @@ class StudentLocalTest {
val context = ApplicationProvider.getApplicationContext<Context>()
testDb = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java)
.build()
studentLocal = StudentLocal(testDb.studentDao, context)
studentLocal = StudentLocal(testDb.studentDao, TestDispatchersProvider(), context)
}
@After
@ -36,9 +38,9 @@ class StudentLocalTest {
@Test
fun saveAndReadTest() {
studentLocal.saveStudents(listOf(student)).blockingGet()
runBlocking { studentLocal.saveStudents(listOf(student)) }
val student = studentLocal.getCurrentStudent(true).blockingGet()
assertEquals("23", student.schoolSymbol)
val student = runBlocking { studentLocal.getCurrentStudent(true) }
assertEquals("23", student?.schoolSymbol)
}
}

View File

@ -1,7 +1,7 @@
package io.github.wulkanowy.data.repositories.timetable
import org.threeten.bp.LocalDateTime
import org.threeten.bp.LocalDateTime.now
import java.time.LocalDateTime
import java.time.LocalDateTime.now
import io.github.wulkanowy.data.db.entities.Timetable as TimetableLocal
import io.github.wulkanowy.sdk.pojo.Timetable as TimetableRemote

View File

@ -5,12 +5,14 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDateTime.of
import java.time.LocalDate
import java.time.LocalDateTime.of
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -34,17 +36,21 @@ class TimetableLocalTest {
@Test
fun saveAndReadTest() {
timetableDb.saveTimetable(listOf(
val list = listOf(
createTimetableLocal(of(2018, 9, 10, 0, 0, 0), 1),
createTimetableLocal(of(2018, 9, 14, 0, 0, 0), 1),
createTimetableLocal(of(2018, 9, 17, 0, 0, 0), 1)
))
)
runBlocking { timetableDb.saveTimetable(list) }
val exams = timetableDb.getTimetable(
Semester(1, 2, "", 1, 1, 2019, LocalDate.now(), LocalDate.now(), 1, 1),
LocalDate.of(2018, 9, 10),
LocalDate.of(2018, 9, 14)
).blockingGet()
val semester = Semester(1, 2, "", 1, 1, 2019, LocalDate.now(), LocalDate.now(), 1, 1)
val exams = runBlocking {
timetableDb.getTimetable(
semester = semester,
startDate = LocalDate.of(2018, 9, 10),
endDate = LocalDate.of(2018, 9, 14)
).first()
}
assertEquals(2, exams.size)
assertEquals(exams[0].date, LocalDate.of(2018, 9, 10))

View File

@ -5,74 +5,48 @@ import androidx.room.Room
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.TestInternetObservingStrategy
import io.github.wulkanowy.data.repositories.getSemester
import io.github.wulkanowy.data.repositories.getStudent
import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
import io.github.wulkanowy.sdk.Sdk
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.coEvery
import io.mockk.impl.annotations.MockK
import io.mockk.mockk
import io.reactivex.Single
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDateTime.of
import java.time.LocalDate
import java.time.LocalDateTime.of
import kotlin.test.assertEquals
@SdkSuppress(minSdkVersion = P)
@RunWith(AndroidJUnit4::class)
class TimetableRepositoryTest {
@MockK
private lateinit var mockSdk: Sdk
private val settings = InternetObservingSettings.builder()
.strategy(TestInternetObservingStrategy())
.build()
@MockK
private lateinit var studentMock: Student
private val student = getStudent()
@MockK
private lateinit var semesterMock: Semester
@MockK
@MockK(relaxed = true)
private lateinit var timetableNotificationSchedulerHelper: TimetableNotificationSchedulerHelper
@MockK
private lateinit var timetableRemote: TimetableRemote
private lateinit var timetableLocal: TimetableLocal
private lateinit var testDb: AppDatabase
private val student = getStudent()
private val semester = getSemester()
@Before
fun initApi() {
MockKAnnotations.init(this)
testDb = Room.inMemoryDatabaseBuilder(getApplicationContext(), AppDatabase::class.java).build()
timetableLocal = TimetableLocal(testDb.timetableDao)
timetableRemote = TimetableRemote(mockSdk)
every { timetableNotificationSchedulerHelper.scheduleNotifications(any(), any()) } returns mockk()
every { timetableNotificationSchedulerHelper.cancelScheduled(any(), any()) } returns mockk()
every { studentMock.studentId } returns 1
every { studentMock.studentName } returns "Jan Kowalski"
every { semesterMock.studentId } returns 1
every { semesterMock.diaryId } returns 2
every { semesterMock.schoolYear } returns 2019
every { semesterMock.semesterId } returns 1
every { mockSdk.switchDiary(any(), any()) } returns mockSdk
}
@After
@ -82,23 +56,31 @@ class TimetableRepositoryTest {
@Test
fun copyRoomToCompletedFromPrevious() {
runBlocking {
timetableLocal.saveTimetable(listOf(
createTimetableLocal(of(2019, 3, 5, 8, 0), 1, "123", "Przyroda"),
createTimetableLocal(of(2019, 3, 5, 8, 50), 2, "321", "Religia"),
createTimetableLocal(of(2019, 3, 5, 9, 40), 3, "213", "W-F"),
createTimetableLocal(of(2019, 3, 5, 10, 30),3, "213", "W-F", "Jan Kowalski")
createTimetableLocal(of(2019, 3, 5, 10, 30), 3, "213", "W-F", "Jan Kowalski")
))
}
every { mockSdk.getTimetable(any(), any()) } returns Single.just(listOf(
createTimetableRemote(of(2019, 3, 5, 8, 0), 1, "", "Przyroda"),
createTimetableRemote(of(2019, 3, 5, 8, 50), 2, "", "Religia"),
createTimetableRemote(of(2019, 3, 5, 9, 40), 3, "", "W-F"),
createTimetableRemote(of(2019, 3, 5, 10, 30), 4, "", "W-F")
))
coEvery { timetableRemote.getTimetable(student, semester, any(), any()) } returns listOf(
createTimetableLocal(of(2019, 3, 5, 8, 0), 1, "", "Przyroda"),
createTimetableLocal(of(2019, 3, 5, 8, 50), 2, "", "Religia"),
createTimetableLocal(of(2019, 3, 5, 9, 40), 3, "", "W-F"),
createTimetableLocal(of(2019, 3, 5, 10, 30), 4, "", "W-F")
)
val lessons = TimetableRepository(settings, timetableLocal, timetableRemote, timetableNotificationSchedulerHelper)
.getTimetable(student, semesterMock, LocalDate.of(2019, 3, 5), LocalDate.of(2019, 3, 5), true)
.blockingGet()
val lessons = runBlocking {
TimetableRepository(timetableLocal, timetableRemote, timetableNotificationSchedulerHelper).getTimetable(
student = student,
semester = semester,
start = LocalDate.of(2019, 3, 5),
end = LocalDate.of(2019, 3, 5),
forceRefresh = true
).filter { it.status == Status.SUCCESS }.first().data.orEmpty()
}
assertEquals(4, lessons.size)
assertEquals("123", lessons[0].room)
@ -108,7 +90,7 @@ class TimetableRepositoryTest {
@Test
fun copyTeacherToCompletedFromPrevious() {
timetableLocal.saveTimetable(listOf(
val list = listOf(
createTimetableLocal(of(2019, 12, 23, 8, 0), 1, "123", "Matematyka", "Paweł Poniedziałkowski", false),
createTimetableLocal(of(2019, 12, 23, 8, 50), 2, "124", "Matematyka", "Paweł Poniedziałkowski", false),
createTimetableLocal(of(2019, 12, 23, 9, 40), 3, "125", "Język polski", "Joanna Wtorkowska", true),
@ -123,28 +105,35 @@ class TimetableRepositoryTest {
createTimetableLocal(of(2019, 12, 25, 8, 50), 2, "124", "Matematyka", "", false),
createTimetableLocal(of(2019, 12, 25, 9, 40), 3, "125", "Matematyka", "", true),
createTimetableLocal(of(2019, 12, 25, 10, 40), 4, "126", "Matematyka", "", true)
))
)
runBlocking { timetableLocal.saveTimetable(list) }
every { mockSdk.getTimetable(any(), any()) } returns Single.just(listOf(
createTimetableRemote(of(2019, 12, 23, 8, 0), 1, "123", "Matematyka", "Paweł Poniedziałkowski", false),
createTimetableRemote(of(2019, 12, 23, 8, 50), 2, "124", "Matematyka", "Jakub Wtorkowski", true),
createTimetableRemote(of(2019, 12, 23, 9, 40), 3, "125", "Język polski", "Joanna Poniedziałkowska", false),
createTimetableRemote(of(2019, 12, 23, 10, 40), 4, "126", "Język polski", "Joanna Wtorkowska", true),
coEvery { timetableRemote.getTimetable(student, semester, any(), any()) } returns listOf(
createTimetableLocal(of(2019, 12, 23, 8, 0), 1, "123", "Matematyka", "Paweł Poniedziałkowski", false),
createTimetableLocal(of(2019, 12, 23, 8, 50), 2, "124", "Matematyka", "Jakub Wtorkowski", true),
createTimetableLocal(of(2019, 12, 23, 9, 40), 3, "125", "Język polski", "Joanna Poniedziałkowska", false),
createTimetableLocal(of(2019, 12, 23, 10, 40), 4, "126", "Język polski", "Joanna Wtorkowska", true),
createTimetableRemote(of(2019, 12, 24, 8, 0), 1, "123", "Język polski", "", false),
createTimetableRemote(of(2019, 12, 24, 8, 50), 2, "124", "Język polski", "", true),
createTimetableRemote(of(2019, 12, 24, 9, 40), 3, "125", "Język polski", "", false),
createTimetableRemote(of(2019, 12, 24, 10, 40), 4, "126", "Język polski", "", true),
createTimetableLocal(of(2019, 12, 24, 8, 0), 1, "123", "Język polski", "", false),
createTimetableLocal(of(2019, 12, 24, 8, 50), 2, "124", "Język polski", "", true),
createTimetableLocal(of(2019, 12, 24, 9, 40), 3, "125", "Język polski", "", false),
createTimetableLocal(of(2019, 12, 24, 10, 40), 4, "126", "Język polski", "", true),
createTimetableRemote(of(2019, 12, 25, 8, 0), 1, "123", "Matematyka", "Paweł Środowski", false),
createTimetableRemote(of(2019, 12, 25, 8, 50), 2, "124", "Matematyka", "Paweł Czwartkowski", true),
createTimetableRemote(of(2019, 12, 25, 9, 40), 3, "125", "Matematyka", "Paweł Środowski", false),
createTimetableRemote(of(2019, 12, 25, 10, 40), 4, "126", "Matematyka", "Paweł Czwartkowski", true)
))
createTimetableLocal(of(2019, 12, 25, 8, 0), 1, "123", "Matematyka", "Paweł Środowski", false),
createTimetableLocal(of(2019, 12, 25, 8, 50), 2, "124", "Matematyka", "Paweł Czwartkowski", true),
createTimetableLocal(of(2019, 12, 25, 9, 40), 3, "125", "Matematyka", "Paweł Środowski", false),
createTimetableLocal(of(2019, 12, 25, 10, 40), 4, "126", "Matematyka", "Paweł Czwartkowski", true)
)
val lessons = TimetableRepository(settings, timetableLocal, timetableRemote, timetableNotificationSchedulerHelper)
.getTimetable(student, semesterMock, LocalDate.of(2019, 12, 23), LocalDate.of(2019, 12, 25), true)
.blockingGet()
val lessons = runBlocking {
TimetableRepository(timetableLocal, timetableRemote, timetableNotificationSchedulerHelper).getTimetable(
student = student,
semester = semester,
start = LocalDate.of(2019, 12, 23),
end = LocalDate.of(2019, 12, 25),
forceRefresh = true
).filter { it.status == Status.SUCCESS }.first().data.orEmpty()
}
assertEquals(12, lessons.size)

View File

@ -18,8 +18,7 @@
android:supportsRtl="false"
android:theme="@style/WulkanowyTheme"
android:usesCleartextTraffic="true"
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute"
tools:replace="android:supportsRtl,android:allowBackup">
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
<activity
android:name=".ui.modules.splash.SplashActivity"
android:screenOrientation="portrait"

View File

@ -1,34 +1,30 @@
package io.github.wulkanowy
import android.app.Application
import android.content.Context
import android.util.Log.DEBUG
import android.util.Log.INFO
import android.util.Log.VERBOSE
import androidx.hilt.work.HiltWorkerFactory
import androidx.multidex.MultiDex
import androidx.work.Configuration
import com.jakewharton.threetenabp.AndroidThreeTen
import com.yariksoffice.lingver.Lingver
import dagger.android.AndroidInjector
import dagger.android.support.DaggerApplication
import dagger.hilt.android.HiltAndroidApp
import fr.bipi.tressence.file.FileLoggerTree
import io.github.wulkanowy.di.DaggerAppComponent
import io.github.wulkanowy.services.sync.SyncWorkerFactory
import io.github.wulkanowy.ui.base.ThemeManager
import io.github.wulkanowy.utils.ActivityLifecycleLogger
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.CrashlyticsExceptionTree
import io.github.wulkanowy.utils.CrashlyticsTree
import io.github.wulkanowy.utils.DebugLogTree
import io.reactivex.exceptions.UndeliverableException
import io.reactivex.plugins.RxJavaPlugins
import timber.log.Timber
import java.io.IOException
import javax.inject.Inject
class WulkanowyApp : DaggerApplication(), Configuration.Provider {
@HiltAndroidApp
class WulkanowyApp : Application(), Configuration.Provider {
@Inject
lateinit var workerFactory: SyncWorkerFactory
lateinit var workerFactory: HiltWorkerFactory
@Inject
lateinit var themeManager: ThemeManager
@ -43,8 +39,6 @@ class WulkanowyApp : DaggerApplication(), Configuration.Provider {
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
RxJavaPlugins.setErrorHandler(::onError)
Lingver.init(this)
themeManager.applyDefaultTheme()
@ -68,18 +62,6 @@ class WulkanowyApp : DaggerApplication(), Configuration.Provider {
registerActivityLifecycleCallbacks(ActivityLifecycleLogger())
}
private fun onError(error: Throwable) {
//RxJava's too deep stack traces may cause SOE on older android devices
val cause = error.cause
if (error is UndeliverableException && cause is IOException || cause is InterruptedException || cause is StackOverflowError) {
Timber.e(cause, "An undeliverable error occurred")
} else throw error
}
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return DaggerAppComponent.factory().create(this)
}
override fun getWorkManagerConfiguration() = Configuration.Builder()
.setWorkerFactory(workerFactory)
.setMinimumLoggingLevel(if (appInfo.isDebug) VERBOSE else INFO)

View File

@ -8,10 +8,11 @@ import androidx.preference.PreferenceManager
import com.chuckerteam.chucker.api.ChuckerCollector
import com.chuckerteam.chucker.api.ChuckerInterceptor
import com.chuckerteam.chucker.api.RetentionManager
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.WalledGardenInternetObservingStrategy
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ApplicationComponent
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
@ -20,19 +21,12 @@ import timber.log.Timber
import javax.inject.Singleton
@Module
@InstallIn(ApplicationComponent::class)
internal class RepositoryModule {
@Singleton
@Provides
fun provideInternetObservingSettings(): InternetObservingSettings {
return InternetObservingSettings.builder()
.strategy(WalledGardenInternetObservingStrategy())
.build()
}
@Singleton
@Provides
fun provideSdk(chuckerCollector: ChuckerCollector, context: Context): Sdk {
fun provideSdk(chuckerCollector: ChuckerCollector, @ApplicationContext context: Context): Sdk {
return Sdk().apply {
androidVersion = android.os.Build.VERSION.RELEASE
buildTag = android.os.Build.MODEL
@ -45,7 +39,7 @@ internal class RepositoryModule {
@Singleton
@Provides
fun provideChuckerCollector(context: Context, prefRepository: PreferencesRepository): ChuckerCollector {
fun provideChuckerCollector(@ApplicationContext context: Context, prefRepository: PreferencesRepository): ChuckerCollector {
return ChuckerCollector(
context = context,
showNotification = prefRepository.isDebugNotificationEnable,
@ -55,19 +49,19 @@ internal class RepositoryModule {
@Singleton
@Provides
fun provideDatabase(context: Context, sharedPrefProvider: SharedPrefProvider) = AppDatabase.newInstance(context, sharedPrefProvider)
fun provideDatabase(@ApplicationContext context: Context, sharedPrefProvider: SharedPrefProvider) = AppDatabase.newInstance(context, sharedPrefProvider)
@Singleton
@Provides
fun provideResources(context: Context): Resources = context.resources
fun provideResources(@ApplicationContext context: Context): Resources = context.resources
@Singleton
@Provides
fun provideAssets(context: Context): AssetManager = context.assets
fun provideAssets(@ApplicationContext context: Context): AssetManager = context.assets
@Singleton
@Provides
fun provideSharedPref(context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
@Singleton
@Provides

View File

@ -0,0 +1,23 @@
package io.github.wulkanowy.data
data class Resource<out 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)
}
fun <T> error(error: Throwable?, data: T? = null): Resource<T> {
return Resource(Status.ERROR, data, error)
}
fun <T> loading(data: T? = null): Resource<T> {
return Resource(Status.LOADING, data, null)
}
}
}
enum class Status {
LOADING,
SUCCESS,
ERROR
}

View File

@ -69,6 +69,7 @@ import io.github.wulkanowy.data.db.migrations.Migration23
import io.github.wulkanowy.data.db.migrations.Migration24
import io.github.wulkanowy.data.db.migrations.Migration25
import io.github.wulkanowy.data.db.migrations.Migration26
import io.github.wulkanowy.data.db.migrations.Migration27
import io.github.wulkanowy.data.db.migrations.Migration3
import io.github.wulkanowy.data.db.migrations.Migration4
import io.github.wulkanowy.data.db.migrations.Migration5
@ -111,7 +112,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() {
companion object {
const val VERSION_SCHEMA = 26
const val VERSION_SCHEMA = 27
fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> {
return arrayOf(
@ -139,7 +140,8 @@ abstract class AppDatabase : RoomDatabase() {
Migration23(),
Migration24(),
Migration25(),
Migration26()
Migration26(),
Migration27(),
)
}

View File

@ -3,19 +3,18 @@ package io.github.wulkanowy.data.db
import androidx.room.TypeConverter
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import org.threeten.bp.DateTimeUtils
import org.threeten.bp.Instant
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDateTime
import org.threeten.bp.Month
import org.threeten.bp.ZoneOffset
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.Month
import java.time.ZoneOffset
import java.util.Date
class Converters {
@TypeConverter
fun timestampToDate(value: Long?): LocalDate? = value?.run {
DateTimeUtils.toInstant(Date(value)).atZone(ZoneOffset.UTC).toLocalDate()
Date(value).toInstant().atZone(ZoneOffset.UTC).toLocalDate()
}
@TypeConverter

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Attendance
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Singleton
@Singleton
@ -12,5 +12,5 @@ import javax.inject.Singleton
interface AttendanceDao : BaseDao<Attendance> {
@Query("SELECT * FROM Attendance WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<Attendance>>
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<Attendance>>
}

View File

@ -3,11 +3,11 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
@Dao
interface AttendanceSummaryDao : BaseDao<AttendanceSummary> {
@Query("SELECT * FROM AttendanceSummary WHERE diary_id = :diaryId AND student_id = :studentId AND subject_id = :subjectId")
fun loadAll(diaryId: Int, studentId: Int, subjectId: Int): Maybe<List<AttendanceSummary>>
fun loadAll(diaryId: Int, studentId: Int, subjectId: Int): Flow<List<AttendanceSummary>>
}

View File

@ -7,11 +7,11 @@ import androidx.room.Update
interface BaseDao<T> {
@Insert
fun insertAll(items: List<T>): List<Long>
suspend fun insertAll(items: List<T>): List<Long>
@Update
fun updateAll(items: List<T>)
suspend fun updateAll(items: List<T>)
@Delete
fun deleteAll(items: List<T>)
suspend fun deleteAll(items: List<T>)
}

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Singleton
@Singleton
@ -12,5 +12,5 @@ import javax.inject.Singleton
interface CompletedLessonsDao : BaseDao<CompletedLesson> {
@Query("SELECT * FROM CompletedLesson WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<CompletedLesson>>
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<CompletedLesson>>
}

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Exam
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Singleton
@Singleton
@ -12,5 +12,5 @@ import javax.inject.Singleton
interface ExamDao : BaseDao<Exam> {
@Query("SELECT * FROM Exams WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<Exam>>
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<Exam>>
}

View File

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Grade
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@ -11,6 +11,5 @@ import javax.inject.Singleton
interface GradeDao : BaseDao<Grade> {
@Query("SELECT * FROM Grades WHERE semester_id = :semesterId AND student_id = :studentId")
fun loadAll(semesterId: Int, studentId: Int): Maybe<List<Grade>>
fun loadAll(semesterId: Int, studentId: Int): Flow<List<Grade>>
}

View File

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@ -11,8 +11,8 @@ import javax.inject.Singleton
interface GradePointsStatisticsDao : BaseDao<GradePointsStatistics> {
@Query("SELECT * FROM GradesPointsStatistics WHERE student_id = :studentId AND semester_id = :semesterId AND subject = :subjectName")
fun loadSubject(semesterId: Int, studentId: Int, subjectName: String): Maybe<List<GradePointsStatistics>>
fun loadSubject(semesterId: Int, studentId: Int, subjectName: String): Flow<List<GradePointsStatistics>>
@Query("SELECT * FROM GradesPointsStatistics WHERE student_id = :studentId AND semester_id = :semesterId")
fun loadAll(semesterId: Int, studentId: Int): Maybe<List<GradePointsStatistics>>
fun loadAll(semesterId: Int, studentId: Int): Flow<List<GradePointsStatistics>>
}

View File

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.GradeStatistics
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@ -11,8 +11,8 @@ import javax.inject.Singleton
interface GradeStatisticsDao : BaseDao<GradeStatistics> {
@Query("SELECT * FROM GradesStatistics WHERE student_id = :studentId AND semester_id = :semesterId AND subject = :subjectName AND is_semester = :isSemester")
fun loadSubject(semesterId: Int, studentId: Int, subjectName: String, isSemester: Boolean): Maybe<List<GradeStatistics>>
fun loadSubject(semesterId: Int, studentId: Int, subjectName: String, isSemester: Boolean): Flow<List<GradeStatistics>>
@Query("SELECT * FROM GradesStatistics WHERE student_id = :studentId AND semester_id = :semesterId AND is_semester = :isSemester")
fun loadAll(semesterId: Int, studentId: Int, isSemester: Boolean): Maybe<List<GradeStatistics>>
fun loadAll(semesterId: Int, studentId: Int, isSemester: Boolean): Flow<List<GradeStatistics>>
}

View File

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.GradeSummary
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@ -11,5 +11,5 @@ import javax.inject.Singleton
interface GradeSummaryDao : BaseDao<GradeSummary> {
@Query("SELECT * FROM GradesSummary WHERE student_id = :studentId AND semester_id = :semesterId")
fun loadAll(semesterId: Int, studentId: Int): Maybe<List<GradeSummary>>
fun loadAll(semesterId: Int, studentId: Int): Flow<List<GradeSummary>>
}

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Homework
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Singleton
@Singleton
@ -12,5 +12,5 @@ import javax.inject.Singleton
interface HomeworkDao : BaseDao<Homework> {
@Query("SELECT * FROM Homework WHERE semester_id = :semesterId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(semesterId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<Homework>>
fun loadAll(semesterId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<Homework>>
}

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Singleton
@Singleton
@ -12,5 +12,5 @@ import javax.inject.Singleton
interface LuckyNumberDao : BaseDao<LuckyNumber> {
@Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date = :date")
fun load(studentId: Int, date: LocalDate): Maybe<LuckyNumber>
fun load(studentId: Int, date: LocalDate): Flow<LuckyNumber>
}

View File

@ -9,5 +9,5 @@ import io.github.wulkanowy.data.db.entities.MessageAttachment
interface MessageAttachmentDao : BaseDao<MessageAttachment> {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAttachments(items: List<MessageAttachment>): List<Long>
suspend fun insertAttachments(items: List<MessageAttachment>): List<Long>
}

View File

@ -5,19 +5,15 @@ import androidx.room.Query
import androidx.room.Transaction
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
import io.reactivex.Maybe
import io.reactivex.Single
import kotlinx.coroutines.flow.Flow
@Dao
interface MessagesDao : BaseDao<Message> {
@Transaction
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND message_id = :messageId")
fun loadMessageWithAttachment(studentId: Int, messageId: Int): Single<MessageWithAttachment>
fun loadMessageWithAttachment(studentId: Int, messageId: Int): Flow<MessageWithAttachment>
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder AND removed = 0 ORDER BY date DESC")
fun loadAll(studentId: Int, folder: Int): Maybe<List<Message>>
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND removed = 1 ORDER BY date DESC")
fun loadDeleted(studentId: Int): Maybe<List<Message>>
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder ORDER BY date DESC")
fun loadAll(studentId: Int, folder: Int): Flow<List<Message>>
}

View File

@ -3,11 +3,11 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.MobileDevice
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
@Dao
interface MobileDeviceDao : BaseDao<MobileDevice> {
@Query("SELECT * FROM MobileDevices WHERE student_id = :studentId ORDER BY date DESC")
fun loadAll(studentId: Int): Maybe<List<MobileDevice>>
fun loadAll(studentId: Int): Flow<List<MobileDevice>>
}

View File

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Note
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@ -11,5 +11,5 @@ import javax.inject.Singleton
interface NoteDao : BaseDao<Note> {
@Query("SELECT * FROM Notes WHERE student_id = :studentId")
fun loadAll(studentId: Int): Maybe<List<Note>>
fun loadAll(studentId: Int): Flow<List<Note>>
}

View File

@ -3,7 +3,6 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Recipient
import io.reactivex.Maybe
import javax.inject.Singleton
@Singleton
@ -11,5 +10,5 @@ import javax.inject.Singleton
interface RecipientDao : BaseDao<Recipient> {
@Query("SELECT * FROM Recipients WHERE student_id = :studentId AND role = :role AND unit_id = :unitId")
fun load(studentId: Int, role: Int, unitId: Int): Maybe<List<Recipient>>
suspend fun load(studentId: Int, role: Int, unitId: Int): List<Recipient>
}

View File

@ -3,7 +3,6 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.reactivex.Maybe
import javax.inject.Singleton
@Singleton
@ -11,8 +10,8 @@ import javax.inject.Singleton
interface ReportingUnitDao : BaseDao<ReportingUnit> {
@Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId")
fun load(studentId: Int): Maybe<List<ReportingUnit>>
suspend fun load(studentId: Int): List<ReportingUnit>
@Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId AND real_id = :unitId")
fun loadOne(studentId: Int, unitId: Int): Maybe<ReportingUnit>
suspend fun loadOne(studentId: Int, unitId: Int): ReportingUnit?
}

View File

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.School
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@ -11,5 +11,5 @@ import javax.inject.Singleton
interface SchoolDao : BaseDao<School> {
@Query("SELECT * FROM School WHERE student_id = :studentId AND class_id = :classId")
fun load(studentId: Int, classId: Int): Maybe<School>
fun load(studentId: Int, classId: Int): Flow<School?>
}

View File

@ -1,15 +1,19 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe
import javax.inject.Singleton
@Singleton
@Dao
interface SemesterDao : BaseDao<Semester> {
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insertSemesters(items: List<Semester>): List<Long>
@Query("SELECT * FROM Semesters WHERE student_id = :studentId AND class_id = :classId")
fun loadAll(studentId: Int, classId: Int): Maybe<List<Semester>>
suspend fun loadAll(studentId: Int, classId: Int): List<Semester>
}

View File

@ -5,8 +5,9 @@ import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy.ABORT
import androidx.room.Query
import androidx.room.Transaction
import io.github.wulkanowy.data.db.entities.Student
import io.reactivex.Maybe
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import javax.inject.Singleton
@Singleton
@ -14,23 +15,27 @@ import javax.inject.Singleton
interface StudentDao {
@Insert(onConflict = ABORT)
fun insertAll(student: List<Student>): List<Long>
suspend fun insertAll(student: List<Student>): List<Long>
@Delete
fun delete(student: Student)
suspend fun delete(student: Student)
@Query("SELECT * FROM Students WHERE is_current = 1")
fun loadCurrent(): Maybe<Student>
suspend fun loadCurrent(): Student?
@Query("SELECT * FROM Students WHERE id = :id")
fun loadById(id: Int): Maybe<Student>
suspend fun loadById(id: Int): Student?
@Query("SELECT * FROM Students")
fun loadAll(): Maybe<List<Student>>
suspend fun loadAll(): List<Student>
@Transaction
@Query("SELECT * FROM Students")
suspend fun loadStudentsWithSemesters(): List<StudentWithSemesters>
@Query("UPDATE Students SET is_current = 1 WHERE id = :id")
fun updateCurrent(id: Long)
suspend fun updateCurrent(id: Long)
@Query("UPDATE Students SET is_current = 0")
fun resetCurrent()
suspend fun resetCurrent()
}

View File

@ -3,11 +3,11 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Subject
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
@Dao
interface SubjectDao : BaseDao<Subject> {
@Query("SELECT * FROM Subjects WHERE diary_id = :diaryId AND student_id = :studentId")
fun loadAll(diaryId: Int, studentId: Int): Maybe<List<Subject>>
fun loadAll(diaryId: Int, studentId: Int): Flow<List<Subject>>
}

View File

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Teacher
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@ -11,5 +11,5 @@ import javax.inject.Singleton
interface TeacherDao : BaseDao<Teacher> {
@Query("SELECT * FROM Teachers WHERE student_id = :studentId AND class_id = :classId")
fun loadAll(studentId: Int, classId: Int): Maybe<List<Teacher>>
fun loadAll(studentId: Int, classId: Int): Flow<List<Teacher>>
}

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Timetable
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Singleton
@Singleton
@ -12,5 +12,5 @@ import javax.inject.Singleton
interface TimetableDao : BaseDao<Timetable> {
@Query("SELECT * FROM Timetable WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<Timetable>>
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<Timetable>>
}

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "Attendance")
data class Attendance(

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.Month
import java.io.Serializable
import java.time.Month
@Entity(tableName = "AttendanceSummary")
data class AttendanceSummary(

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "CompletedLesson")
data class CompletedLesson(

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "Exams")
data class Exam(

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "Grades")
data class Grade(

View File

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDateTime
import java.time.LocalDateTime
@Entity(tableName = "GradesSummary")
data class GradeSummary(

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "Homework")
data class Homework(

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "LuckyNumbers")
data class LuckyNumber (

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDateTime
import java.io.Serializable
import java.time.LocalDateTime
@Entity(tableName = "Messages")
data class Message(
@ -29,8 +29,6 @@ data class Message(
val subject: String,
var content: String,
val date: LocalDateTime,
@ColumnInfo(name = "folder_id")
@ -55,4 +53,6 @@ data class Message(
@ColumnInfo(name = "is_notified")
var isNotified: Boolean = true
var content: String = ""
}

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDateTime
import java.io.Serializable
import java.time.LocalDateTime
@Entity(tableName = "MobileDevices")
data class MobileDevice(

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "Notes")
data class Note(

View File

@ -4,7 +4,8 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "Semesters", indices = [Index(value = ["student_id", "diary_id", "semester_id"], unique = true)])
data class Semester(
@ -36,7 +37,7 @@ data class Semester(
@ColumnInfo(name = "unit_id")
val unitId: Int
) {
): Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0

View File

@ -4,8 +4,8 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDateTime
import java.io.Serializable
import java.time.LocalDateTime
@Entity(tableName = "Students", indices = [Index(value = ["email", "symbol", "student_id", "school_id", "class_id"], unique = true)])
data class Student(
@ -43,6 +43,9 @@ data class Student(
@ColumnInfo(name = "user_login_id")
val userLoginId: Int,
@ColumnInfo(name = "user_name")
val userName: String,
@ColumnInfo(name = "student_name")
val studentName: String,

View File

@ -0,0 +1,13 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.Embedded
import androidx.room.Relation
import java.io.Serializable
data class StudentWithSemesters(
@Embedded
val student: Student,
@Relation(parentColumn = "student_id", entityColumn = "student_id")
val semesters: List<Semester>
) : Serializable

View File

@ -3,9 +3,9 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDateTime
import java.io.Serializable
import java.time.LocalDate
import java.time.LocalDateTime
@Entity(tableName = "Timetable")
data class Timetable(

View File

@ -0,0 +1,45 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration27 : Migration(26, 27) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN user_name TEXT NOT NULL DEFAULT \"\"")
val students = getStudentsIdsAndNames(database)
val units = getReportingUnits(database)
students.forEach { (id, userLoginId, studentName) ->
val userNameFromUnits = units.singleOrNull { (senderId, _) -> senderId == userLoginId }?.second
val normalizedStudentName = studentName.split(" ").asReversed().joinToString(" ")
val userName = userNameFromUnits ?: normalizedStudentName
database.execSQL("UPDATE Students SET user_name = '$userName' WHERE id = '$id'")
}
}
private fun getStudentsIdsAndNames(database: SupportSQLiteDatabase): MutableList<Triple<Long, Int, String>> {
val students = mutableListOf<Triple<Long, Int, String>>()
val studentsCursor = database.query("SELECT id, user_login_id, student_name FROM Students")
if (studentsCursor.moveToFirst()) {
do {
students.add(Triple(studentsCursor.getLong(0), studentsCursor.getInt(1), studentsCursor.getString(2)))
} while (studentsCursor.moveToNext())
}
return students
}
private fun getReportingUnits(database: SupportSQLiteDatabase): MutableList<Pair<Int, String>> {
val units = mutableListOf<Pair<Int, String>>()
val unitsCursor = database.query("SELECT sender_id, sender_name FROM ReportingUnits")
if (unitsCursor.moveToFirst()) {
do {
units.add(unitsCursor.getInt(0) to unitsCursor.getString(1))
} while (unitsCursor.moveToNext())
}
return units
}
}

View File

@ -2,8 +2,8 @@ package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import org.threeten.bp.LocalDateTime.now
import org.threeten.bp.ZoneOffset
import java.time.LocalDateTime.now
import java.time.ZoneOffset
class Migration5 : Migration(4, 5) {

View File

@ -0,0 +1,19 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.sdk.pojo.Semester as SdkSemester
fun List<SdkSemester>.mapToEntities(studentId: Int) = map {
Semester(
studentId = studentId,
diaryId = it.diaryId,
diaryName = it.diaryName,
schoolYear = it.schoolYear,
semesterId = it.semesterId,
semesterName = it.semesterNumber,
start = it.start,
end = it.end,
classId = it.classId,
unitId = it.unitId
)
}

View File

@ -0,0 +1,35 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import java.time.LocalDateTime
import io.github.wulkanowy.sdk.pojo.Student as SdkStudent
fun List<SdkStudent>.mapToEntities(password: String = "") = map {
StudentWithSemesters(
student = Student(
email = it.email,
password = password,
isParent = it.isParent,
symbol = it.symbol,
studentId = it.studentId,
userLoginId = it.userLoginId,
userName = it.userName,
studentName = it.studentName + " " + it.studentSurname,
schoolSymbol = it.schoolSymbol,
schoolShortName = it.schoolShortName,
schoolName = it.schoolName,
className = it.className,
classId = it.classId,
scrapperBaseUrl = it.scrapperBaseUrl,
loginType = it.loginType.name,
isCurrent = false,
registrationDate = LocalDateTime.now(),
mobileBaseUrl = it.mobileBaseUrl,
privateKey = it.privateKey,
certificateKey = it.certificateKey,
loginMode = it.loginMode.name
),
semesters = it.semesters.mapToEntities(it.studentId)
)
}

View File

@ -3,18 +3,21 @@ package io.github.wulkanowy.data.repositories.appcreator
import android.content.res.AssetManager
import com.google.gson.Gson
import io.github.wulkanowy.data.pojos.Contributor
import io.reactivex.Single
import io.github.wulkanowy.utils.DispatchersProvider
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AppCreatorRepository @Inject constructor(private val assets: AssetManager) {
fun getAppCreators(): Single<List<Contributor>> {
return Single.fromCallable {
class AppCreatorRepository @Inject constructor(
private val assets: AssetManager,
private val dispatchers: DispatchersProvider
) {
suspend fun getAppCreators() = withContext(dispatchers.backgroundThread) {
Gson().fromJson(
assets.open("contributors.json").bufferedReader().use { it.readText() },
Array<Contributor>::class.java
).toList()
}
}
}

View File

@ -3,23 +3,23 @@ package io.github.wulkanowy.data.repositories.attendance
import io.github.wulkanowy.data.db.dao.AttendanceDao
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AttendanceLocal @Inject constructor(private val attendanceDb: AttendanceDao) {
fun saveAttendance(attendance: List<Attendance>) {
suspend fun saveAttendance(attendance: List<Attendance>) {
attendanceDb.insertAll(attendance)
}
fun deleteAttendance(attendance: List<Attendance>) {
suspend fun deleteAttendance(attendance: List<Attendance>) {
attendanceDb.deleteAll(attendance)
}
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Attendance>> {
return attendanceDb.loadAll(semester.diaryId, semester.studentId, startDate, endDate).filter { it.isNotEmpty() }
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate): Flow<List<Attendance>> {
return attendanceDb.loadAll(semester.diaryId, semester.studentId, startDate, endDate)
}
}

View File

@ -6,21 +6,19 @@ import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Absent
import io.github.wulkanowy.utils.init
import io.reactivex.Single
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDateTime
import org.threeten.bp.LocalTime
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AttendanceRemote @Inject constructor(private val sdk: Sdk) {
fun getAttendance(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Attendance>> {
suspend fun getAttendance(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): List<Attendance> {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getAttendance(startDate, endDate, semester.semesterId)
.map { attendance ->
attendance.map {
.map {
Attendance(
studentId = semester.studentId,
diaryId = semester.diaryId,
@ -40,9 +38,8 @@ class AttendanceRemote @Inject constructor(private val sdk: Sdk) {
)
}
}
}
fun excuseAbsence(student: Student, semester: Semester, absenceList: List<Attendance>, reason: String?): Single<Boolean> {
suspend fun excuseAbsence(student: Student, semester: Semester, absenceList: List<Attendance>, reason: String?): Boolean {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).excuseForAbsence(absenceList.map { attendance ->
Absent(
date = LocalDateTime.of(attendance.date, LocalTime.of(0, 0)),

View File

@ -1,45 +1,34 @@
package io.github.wulkanowy.data.repositories.attendance
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
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.utils.sunday
import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Single
import org.threeten.bp.LocalDate
import java.net.UnknownHostException
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AttendanceRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: AttendanceLocal,
private val remote: AttendanceRemote
) {
fun getAttendance(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean): Single<List<Attendance>> {
return local.getAttendance(semester, start.monday, end.sunday).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
if (it) remote.getAttendance(student, semester, start.monday, end.sunday)
else Single.error(UnknownHostException())
}.flatMap { newAttendance ->
local.getAttendance(semester, start.monday, end.sunday)
.toSingle(emptyList())
.doOnSuccess { oldAttendance ->
local.deleteAttendance(oldAttendance.uniqueSubtract(newAttendance))
local.saveAttendance(newAttendance.uniqueSubtract(oldAttendance))
}
}.flatMap {
local.getAttendance(semester, start.monday, end.sunday)
.toSingle(emptyList())
}).map { list -> list.filter { it.date in start..end } }
}
fun getAttendance(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh },
query = { local.getAttendance(semester, start.monday, end.sunday) },
fetch = { remote.getAttendance(student, semester, start.monday, end.sunday) },
saveFetchResult = { old, new ->
local.deleteAttendance(old uniqueSubtract new)
local.saveAttendance(new uniqueSubtract old)
},
filterResult = { it.filter { item -> item.date in start..end } }
)
fun excuseForAbsence(student: Student, semester: Semester, attendanceList: List<Attendance>, reason: String? = null): Single<Boolean> {
return remote.excuseAbsence(student, semester, attendanceList, reason)
suspend fun excuseForAbsence(student: Student, semester: Semester, attendanceList: List<Attendance>, reason: String? = null) {
remote.excuseAbsence(student, semester, attendanceList, reason)
}
}

View File

@ -3,22 +3,22 @@ package io.github.wulkanowy.data.repositories.attendancesummary
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AttendanceSummaryLocal @Inject constructor(private val attendanceDb: AttendanceSummaryDao) {
fun saveAttendanceSummary(attendance: List<AttendanceSummary>) {
suspend fun saveAttendanceSummary(attendance: List<AttendanceSummary>) {
attendanceDb.insertAll(attendance)
}
fun deleteAttendanceSummary(attendance: List<AttendanceSummary>) {
suspend fun deleteAttendanceSummary(attendance: List<AttendanceSummary>) {
attendanceDb.deleteAll(attendance)
}
fun getAttendanceSummary(semester: Semester, subjectId: Int): Maybe<List<AttendanceSummary>> {
return attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId).filter { it.isNotEmpty() }
fun getAttendanceSummary(semester: Semester, subjectId: Int): Flow<List<AttendanceSummary>> {
return attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId)
}
}

View File

@ -5,18 +5,16 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AttendanceSummaryRemote @Inject constructor(private val sdk: Sdk) {
fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int): Single<List<AttendanceSummary>> {
suspend fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int): List<AttendanceSummary> {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getAttendanceSummary(subjectId)
.map { attendance ->
attendance.map {
.map {
AttendanceSummary(
studentId = semester.studentId,
diaryId = semester.diaryId,
@ -32,5 +30,4 @@ class AttendanceSummaryRemote @Inject constructor(private val sdk: Sdk) {
)
}
}
}
}

View File

@ -1,35 +1,25 @@
package io.github.wulkanowy.data.repositories.attendancesummary
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Single
import java.net.UnknownHostException
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AttendanceSummaryRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: AttendanceSummaryLocal,
private val remote: AttendanceSummaryRemote
) {
fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int, forceRefresh: Boolean = false): Single<List<AttendanceSummary>> {
return local.getAttendanceSummary(semester, subjectId).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getAttendanceSummary(student, semester, subjectId)
else Single.error(UnknownHostException())
}.flatMap { new ->
local.getAttendanceSummary(semester, subjectId).toSingle(emptyList())
.doOnSuccess { old ->
local.deleteAttendanceSummary(old.uniqueSubtract(new))
local.saveAttendanceSummary(new.uniqueSubtract(old))
}
}.flatMap { local.getAttendanceSummary(semester, subjectId).toSingle(emptyList()) })
fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh },
query = { local.getAttendanceSummary(semester, subjectId) },
fetch = { remote.getAttendanceSummary(student, semester, subjectId) },
saveFetchResult = { old, new ->
local.deleteAttendanceSummary(old uniqueSubtract new)
local.saveAttendanceSummary(new uniqueSubtract old)
}
)
}

View File

@ -3,23 +3,23 @@ package io.github.wulkanowy.data.repositories.completedlessons
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class CompletedLessonsLocal @Inject constructor(private val completedLessonsDb: CompletedLessonsDao) {
fun saveCompletedLessons(completedLessons: List<CompletedLesson>) {
suspend fun saveCompletedLessons(completedLessons: List<CompletedLesson>) {
completedLessonsDb.insertAll(completedLessons)
}
fun deleteCompleteLessons(completedLessons: List<CompletedLesson>) {
suspend fun deleteCompleteLessons(completedLessons: List<CompletedLesson>) {
completedLessonsDb.deleteAll(completedLessons)
}
fun getCompletedLessons(semester: Semester, start: LocalDate, end: LocalDate): Maybe<List<CompletedLesson>> {
return completedLessonsDb.loadAll(semester.diaryId, semester.studentId, start, end).filter { it.isNotEmpty() }
fun getCompletedLessons(semester: Semester, start: LocalDate, end: LocalDate): Flow<List<CompletedLesson>> {
return completedLessonsDb.loadAll(semester.diaryId, semester.studentId, start, end)
}
}

View File

@ -5,19 +5,17 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single
import org.threeten.bp.LocalDate
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class CompletedLessonsRemote @Inject constructor(private val sdk: Sdk) {
fun getCompletedLessons(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<CompletedLesson>> {
suspend fun getCompletedLessons(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): List<CompletedLesson> {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getCompletedLessons(startDate, endDate)
.map { lessons ->
lessons.map {
.map {
it.absence
CompletedLesson(
studentId = semester.studentId,
@ -34,5 +32,4 @@ class CompletedLessonsRemote @Inject constructor(private val sdk: Sdk) {
)
}
}
}
}

View File

@ -1,42 +1,29 @@
package io.github.wulkanowy.data.repositories.completedlessons
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Single
import org.threeten.bp.LocalDate
import java.net.UnknownHostException
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class CompletedLessonsRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: CompletedLessonsLocal,
private val remote: CompletedLessonsRemote
) {
fun getCompletedLessons(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single<List<CompletedLesson>> {
return local.getCompletedLessons(semester, start.monday, end.sunday).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getCompletedLessons(student, semester, start.monday, end.sunday)
else Single.error(UnknownHostException())
}.flatMap { new ->
local.getCompletedLessons(semester, start.monday, end.sunday)
.toSingle(emptyList())
.doOnSuccess { old ->
local.deleteCompleteLessons(old.uniqueSubtract(new))
local.saveCompletedLessons(new.uniqueSubtract(old))
}
}.flatMap {
local.getCompletedLessons(semester, start.monday, end.sunday)
.toSingle(emptyList())
}).map { list -> list.filter { it.date in start..end } }
}
fun getCompletedLessons(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh },
query = { local.getCompletedLessons(semester, start.monday, end.sunday) },
fetch = { remote.getCompletedLessons(student, semester, start.monday, end.sunday) },
saveFetchResult = { old, new ->
local.deleteCompleteLessons(old uniqueSubtract new)
local.saveCompletedLessons(new uniqueSubtract old)
},
filterResult = { it.filter { item -> item.date in start..end } }
)
}

View File

@ -3,24 +3,23 @@ package io.github.wulkanowy.data.repositories.exam
import io.github.wulkanowy.data.db.dao.ExamDao
import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ExamLocal @Inject constructor(private val examDb: ExamDao) {
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Exam>> {
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate): Flow<List<Exam>> {
return examDb.loadAll(semester.diaryId, semester.studentId, startDate, endDate)
.filter { it.isNotEmpty() }
}
fun saveExams(exams: List<Exam>) {
suspend fun saveExams(exams: List<Exam>) {
examDb.insertAll(exams)
}
fun deleteExams(exams: List<Exam>) {
suspend fun deleteExams(exams: List<Exam>) {
examDb.deleteAll(exams)
}
}

View File

@ -5,19 +5,17 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single
import org.threeten.bp.LocalDate
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ExamRemote @Inject constructor(private val sdk: Sdk) {
fun getExams(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Exam>> {
suspend fun getExams(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): List<Exam> {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getExams(startDate, endDate, semester.semesterId)
.map { exams ->
exams.map {
.map {
Exam(
studentId = semester.studentId,
diaryId = semester.diaryId,
@ -32,5 +30,4 @@ class ExamRemote @Inject constructor(private val sdk: Sdk) {
)
}
}
}
}

View File

@ -1,42 +1,29 @@
package io.github.wulkanowy.data.repositories.exam
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
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.utils.sunday
import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Single
import org.threeten.bp.LocalDate
import java.net.UnknownHostException
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ExamRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: ExamLocal,
private val remote: ExamRemote
) {
fun getExams(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single<List<Exam>> {
return local.getExams(semester, start.monday, end.sunday).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getExams(student, semester, start.monday, end.sunday)
else Single.error(UnknownHostException())
}.flatMap { new ->
local.getExams(semester, start.monday, end.sunday)
.toSingle(emptyList())
.doOnSuccess { old ->
local.deleteExams(old.uniqueSubtract(new))
local.saveExams(new.uniqueSubtract(old))
}
}.flatMap {
local.getExams(semester, start.monday, end.sunday)
.toSingle(emptyList())
}).map { list -> list.filter { it.date in start..end } }
}
fun getExams(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh },
query = { local.getExams(semester, start.monday, end.sunday) },
fetch = { remote.getExams(student, semester, start.monday, end.sunday) },
saveFetchResult = { old, new ->
local.deleteExams(old uniqueSubtract new)
local.saveExams(new uniqueSubtract old)
},
filterResult = { it.filter { item -> item.date in start..end } }
)
}

View File

@ -5,7 +5,7 @@ import io.github.wulkanowy.data.db.dao.GradeSummaryDao
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
import javax.inject.Singleton
@ -15,35 +15,35 @@ class GradeLocal @Inject constructor(
private val gradeSummaryDb: GradeSummaryDao
) {
fun saveGrades(grades: List<Grade>) {
suspend fun saveGrades(grades: List<Grade>) {
gradeDb.insertAll(grades)
}
fun deleteGrades(grades: List<Grade>) {
suspend fun deleteGrades(grades: List<Grade>) {
gradeDb.deleteAll(grades)
}
fun updateGrades(grades: List<Grade>) {
suspend fun updateGrades(grades: List<Grade>) {
gradeDb.updateAll(grades)
}
fun updateGradesSummary(gradesSummary: List<GradeSummary>) {
suspend fun updateGradesSummary(gradesSummary: List<GradeSummary>) {
gradeSummaryDb.updateAll(gradesSummary)
}
fun getGradesDetails(semester: Semester): Maybe<List<Grade>> {
return gradeDb.loadAll(semester.semesterId, semester.studentId).filter { it.isNotEmpty() }
fun getGradesDetails(semester: Semester): Flow<List<Grade>> {
return gradeDb.loadAll(semester.semesterId, semester.studentId)
}
fun saveGradesSummary(gradesSummary: List<GradeSummary>) {
suspend fun saveGradesSummary(gradesSummary: List<GradeSummary>) {
gradeSummaryDb.insertAll(gradesSummary)
}
fun deleteGradesSummary(gradesSummary: List<GradeSummary>) {
suspend fun deleteGradesSummary(gradesSummary: List<GradeSummary>) {
gradeSummaryDb.deleteAll(gradesSummary)
}
fun getGradesSummary(semester: Semester): Maybe<List<GradeSummary>> {
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).filter { it.isNotEmpty() }
fun getGradesSummary(semester: Semester): Flow<List<GradeSummary>> {
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)
}
}

View File

@ -6,18 +6,19 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class GradeRemote @Inject constructor(private val sdk: Sdk) {
fun getGrades(student: Student, semester: Semester): Single<Pair<List<Grade>, List<GradeSummary>>> {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
suspend fun getGrades(student: Student, semester: Semester): Pair<List<Grade>, List<GradeSummary>> {
val (details, summary) = sdk
.init(student)
.switchDiary(semester.diaryId, semester.schoolYear)
.getGrades(semester.semesterId)
.map { (details, summary) ->
details.map {
return details.map {
Grade(
studentId = semester.studentId,
semesterId = semester.semesterId,
@ -49,5 +50,4 @@ class GradeRemote @Inject constructor(private val sdk: Sdk) {
)
}
}
}
}

View File

@ -1,52 +1,49 @@
package io.github.wulkanowy.data.repositories.grade
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.Grade
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.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Completable
import io.reactivex.Single
import org.threeten.bp.LocalDateTime
import java.net.UnknownHostException
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import java.time.LocalDateTime
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class GradeRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: GradeLocal,
private val remote: GradeRemote
) {
fun getGrades(student: Student, semester: Semester, forceRefresh: Boolean = false, notify: Boolean = false): Single<Pair<List<Grade>, List<GradeSummary>>> {
return local.getGradesDetails(semester).flatMap { details ->
local.getGradesSummary(semester).map { summary -> details to summary }
}.filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
if (it) remote.getGrades(student, semester)
else Single.error(UnknownHostException())
}.flatMap { (newDetails, newSummary) ->
local.getGradesDetails(semester).toSingle(emptyList())
.doOnSuccess { old ->
val notifyBreakDate = old.maxBy { it.date }?.date ?: student.registrationDate.toLocalDate()
local.deleteGrades(old.uniqueSubtract(newDetails))
local.saveGrades(newDetails.uniqueSubtract(old)
.onEach {
fun getGrades(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
shouldFetch = { (details, summaries) -> details.isEmpty() || summaries.isEmpty() || forceRefresh },
query = { local.getGradesDetails(semester).combine(local.getGradesSummary(semester)) { details, summaries -> details to summaries } },
fetch = { remote.getGrades(student, semester) },
saveFetchResult = { old, new ->
refreshGradeDetails(student, old.first, new.first, notify)
refreshGradeSummaries(old.second, new.second, notify)
}
)
private suspend fun refreshGradeDetails(student: Student, oldGrades: List<Grade>, newDetails: List<Grade>, notify: Boolean) {
val notifyBreakDate = oldGrades.maxByOrNull { it.date }?.date ?: student.registrationDate.toLocalDate()
local.deleteGrades(oldGrades uniqueSubtract newDetails)
local.saveGrades((newDetails uniqueSubtract oldGrades).onEach {
if (it.date >= notifyBreakDate) it.apply {
isRead = false
if (notify) isNotified = false
}
})
}.flatMap {
local.getGradesSummary(semester).toSingle(emptyList())
.doOnSuccess { old ->
local.deleteGradesSummary(old.uniqueSubtract(newSummary))
local.saveGradesSummary(newSummary.uniqueSubtract(old)
.onEach { summary ->
val oldSummary = old.find { oldSummary -> oldSummary.subject == summary.subject }
}
private suspend fun refreshGradeSummaries(oldSummaries: List<GradeSummary>, newSummary: List<GradeSummary>, notify: Boolean) {
local.deleteGradesSummary(oldSummaries uniqueSubtract newSummary)
local.saveGradesSummary((newSummary uniqueSubtract oldSummaries).onEach { summary ->
val oldSummary = oldSummaries.find { oldSummary -> oldSummary.subject == summary.subject }
summary.isPredictedGradeNotified = when {
summary.predictedGrade.isEmpty() -> true
notify && oldSummary?.predictedGrade != summary.predictedGrade -> false
@ -70,41 +67,32 @@ class GradeRepository @Inject constructor(
}
})
}
}
}.flatMap {
local.getGradesDetails(semester).toSingle(emptyList()).flatMap { details ->
local.getGradesSummary(semester).toSingle(emptyList()).map { summary ->
details to summary
}
}
})
fun getUnreadGrades(semester: Semester): Flow<List<Grade>> {
return local.getGradesDetails(semester).map { it.filter { grade -> !grade.isRead } }
}
fun getUnreadGrades(semester: Semester): Single<List<Grade>> {
return local.getGradesDetails(semester).map { it.filter { grade -> !grade.isRead } }.toSingle(emptyList())
fun getNotNotifiedGrades(semester: Semester): Flow<List<Grade>> {
return local.getGradesDetails(semester).map { it.filter { grade -> !grade.isNotified } }
}
fun getNotNotifiedGrades(semester: Semester): Single<List<Grade>> {
return local.getGradesDetails(semester).map { it.filter { grade -> !grade.isNotified } }.toSingle(emptyList())
fun getNotNotifiedPredictedGrades(semester: Semester): Flow<List<GradeSummary>> {
return local.getGradesSummary(semester).map { it.filter { gradeSummary -> !gradeSummary.isPredictedGradeNotified } }
}
fun getNotNotifiedPredictedGrades(semester: Semester): Single<List<GradeSummary>> {
return local.getGradesSummary(semester).map { it.filter { gradeSummary -> !gradeSummary.isPredictedGradeNotified } }.toSingle(emptyList())
fun getNotNotifiedFinalGrades(semester: Semester): Flow<List<GradeSummary>> {
return local.getGradesSummary(semester).map { it.filter { gradeSummary -> !gradeSummary.isFinalGradeNotified } }
}
fun getNotNotifiedFinalGrades(semester: Semester): Single<List<GradeSummary>> {
return local.getGradesSummary(semester).map { it.filter { gradeSummary -> !gradeSummary.isFinalGradeNotified } }.toSingle(emptyList())
suspend fun updateGrade(grade: Grade) {
return local.updateGrades(listOf(grade))
}
fun updateGrade(grade: Grade): Completable {
return Completable.fromCallable { local.updateGrades(listOf(grade)) }
suspend fun updateGrades(grades: List<Grade>) {
return local.updateGrades(grades)
}
fun updateGrades(grades: List<Grade>): Completable {
return Completable.fromCallable { local.updateGrades(grades) }
}
fun updateGradesSummary(gradesSummary: List<GradeSummary>): Completable {
return Completable.fromCallable { local.updateGradesSummary(gradesSummary) }
suspend fun updateGradesSummary(gradesSummary: List<GradeSummary>) {
return local.updateGradesSummary(gradesSummary)
}
}

View File

@ -5,7 +5,7 @@ import io.github.wulkanowy.data.db.dao.GradeStatisticsDao
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeStatistics
import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
import javax.inject.Singleton
@ -15,46 +15,27 @@ class GradeStatisticsLocal @Inject constructor(
private val gradePointsStatisticsDb: GradePointsStatisticsDao
) {
fun getGradesStatistics(semester: Semester, isSemester: Boolean): Maybe<List<GradeStatistics>> {
return gradeStatisticsDb.loadAll(semester.semesterId, semester.studentId, isSemester).filter { it.isNotEmpty() }
fun getGradesStatistics(semester: Semester, isSemester: Boolean): Flow<List<GradeStatistics>> {
return gradeStatisticsDb.loadAll(semester.semesterId, semester.studentId, isSemester)
}
fun getGradesPointsStatistics(semester: Semester): Maybe<List<GradePointsStatistics>> {
return gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId).filter { it.isNotEmpty() }
fun getGradesPointsStatistics(semester: Semester): Flow<List<GradePointsStatistics>> {
return gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId)
}
fun getGradesStatistics(semester: Semester, isSemester: Boolean, subjectName: String): Maybe<List<GradeStatistics>> {
return when (subjectName) {
"Wszystkie" -> gradeStatisticsDb.loadAll(semester.semesterId, semester.studentId, isSemester).map { list ->
list.groupBy { it.grade }.map {
GradeStatistics(semester.studentId, semester.semesterId, subjectName, it.key,
it.value.fold(0) { acc, e -> acc + e.amount }, false)
} + list
}
else -> gradeStatisticsDb.loadSubject(semester.semesterId, semester.studentId, subjectName, isSemester)
}.filter { it.isNotEmpty() }
}
fun getGradesPointsStatistics(semester: Semester, subjectName: String): Maybe<List<GradePointsStatistics>> {
return when (subjectName) {
"Wszystkie" -> gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId)
else -> gradePointsStatisticsDb.loadSubject(semester.semesterId, semester.studentId, subjectName)
}.filter { it.isNotEmpty() }
}
fun saveGradesStatistics(gradesStatistics: List<GradeStatistics>) {
suspend fun saveGradesStatistics(gradesStatistics: List<GradeStatistics>) {
gradeStatisticsDb.insertAll(gradesStatistics)
}
fun saveGradesPointsStatistics(gradePointsStatistics: List<GradePointsStatistics>) {
suspend fun saveGradesPointsStatistics(gradePointsStatistics: List<GradePointsStatistics>) {
gradePointsStatisticsDb.insertAll(gradePointsStatistics)
}
fun deleteGradesStatistics(gradesStatistics: List<GradeStatistics>) {
suspend fun deleteGradesStatistics(gradesStatistics: List<GradeStatistics>) {
gradeStatisticsDb.deleteAll(gradesStatistics)
}
fun deleteGradesPointsStatistics(gradesPointsStatistics: List<GradePointsStatistics>) {
suspend fun deleteGradesPointsStatistics(gradesPointsStatistics: List<GradePointsStatistics>) {
gradePointsStatisticsDb.deleteAll(gradesPointsStatistics)
}
}

View File

@ -6,19 +6,17 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class GradeStatisticsRemote @Inject constructor(private val sdk: Sdk) {
fun getGradeStatistics(student: Student, semester: Semester, isSemester: Boolean): Single<List<GradeStatistics>> {
suspend fun getGradeStatistics(student: Student, semester: Semester, isSemester: Boolean): List<GradeStatistics> {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).let {
if (isSemester) it.getGradesAnnualStatistics(semester.semesterId)
else it.getGradesPartialStatistics(semester.semesterId)
}.map { gradeStatistics ->
gradeStatistics.map {
}.map {
GradeStatistics(
semesterId = semester.semesterId,
studentId = semester.studentId,
@ -29,13 +27,11 @@ class GradeStatisticsRemote @Inject constructor(private val sdk: Sdk) {
)
}
}
}
fun getGradePointsStatistics(student: Student, semester: Semester): Single<List<GradePointsStatistics>> {
suspend fun getGradePointsStatistics(student: Student, semester: Semester): List<GradePointsStatistics> {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getGradesPointsStatistics(semester.semesterId)
.map { gradePointsStatistics ->
gradePointsStatistics.map {
.map {
GradePointsStatistics(
semesterId = semester.semesterId,
studentId = semester.studentId,
@ -45,5 +41,4 @@ class GradeStatisticsRemote @Inject constructor(private val sdk: Sdk) {
)
}
}
}
}

View File

@ -1,58 +1,58 @@
package io.github.wulkanowy.data.repositories.gradestatistics
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeStatistics
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
import io.github.wulkanowy.ui.modules.grade.statistics.ViewType
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Single
import java.net.UnknownHostException
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class GradeStatisticsRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: GradeStatisticsLocal,
private val remote: GradeStatisticsRemote
) {
fun getGradesStatistics(student: Student, semester: Semester, subjectName: String, isSemester: Boolean, forceRefresh: Boolean = false): Single<List<GradeStatisticsItem>> {
return local.getGradesStatistics(semester, isSemester, subjectName).map { it.mapToStatisticItems() }.filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getGradeStatistics(student, semester, isSemester)
else Single.error(UnknownHostException())
}.flatMap { new ->
local.getGradesStatistics(semester, isSemester).toSingle(emptyList())
.doOnSuccess { old ->
local.deleteGradesStatistics(old.uniqueSubtract(new))
local.saveGradesStatistics(new.uniqueSubtract(old))
}
}.flatMap { local.getGradesStatistics(semester, isSemester, subjectName).map { it.mapToStatisticItems() }.toSingle(emptyList()) })
fun getGradesStatistics(student: Student, semester: Semester, subjectName: String, isSemester: Boolean, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh },
query = { local.getGradesStatistics(semester, isSemester) },
fetch = { remote.getGradeStatistics(student, semester, isSemester) },
saveFetchResult = { old, new ->
local.deleteGradesStatistics(old uniqueSubtract new)
local.saveGradesStatistics(new uniqueSubtract old)
},
mapResult = { items ->
when (subjectName) {
"Wszystkie" -> items.groupBy { it.grade }.map {
GradeStatistics(semester.studentId, semester.semesterId, subjectName, it.key,
it.value.fold(0) { acc, e -> acc + e.amount }, false)
} + items
else -> items.filter { it.subject == subjectName }
}.mapToStatisticItems()
}
)
fun getGradesPointsStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean): Single<List<GradeStatisticsItem>> {
return local.getGradesPointsStatistics(semester, subjectName).map { it.mapToStatisticsItem() }.filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getGradePointsStatistics(student, semester)
else Single.error(UnknownHostException())
}.flatMap { new ->
local.getGradesPointsStatistics(semester).toSingle(emptyList())
.doOnSuccess { old ->
local.deleteGradesPointsStatistics(old.uniqueSubtract(new))
local.saveGradesPointsStatistics(new.uniqueSubtract(old))
}
}.flatMap { local.getGradesPointsStatistics(semester, subjectName).map { it.mapToStatisticsItem() }.toSingle(emptyList()) })
fun getGradesPointsStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh },
query = { local.getGradesPointsStatistics(semester) },
fetch = { remote.getGradePointsStatistics(student, semester) },
saveFetchResult = { old, new ->
local.deleteGradesPointsStatistics(old uniqueSubtract new)
local.saveGradesPointsStatistics(new uniqueSubtract old)
},
mapResult = { items ->
when (subjectName) {
"Wszystkie" -> items
else -> items.filter { it.subject == subjectName }
}.mapToStatisticsItem()
}
)
private fun List<GradeStatistics>.mapToStatisticItems(): List<GradeStatisticsItem> {
return groupBy { it.subject }.map {
private fun List<GradeStatistics>.mapToStatisticItems() = groupBy { it.subject }.map {
GradeStatisticsItem(
type = ViewType.PARTIAL,
partial = it.value
@ -61,15 +61,12 @@ class GradeStatisticsRepository @Inject constructor(
points = null
)
}
}
private fun List<GradePointsStatistics>.mapToStatisticsItem(): List<GradeStatisticsItem> {
return map {
private fun List<GradePointsStatistics>.mapToStatisticsItem() = map {
GradeStatisticsItem(
type = ViewType.POINTS,
partial = emptyList(),
points = it
)
}
}
}

View File

@ -3,28 +3,27 @@ package io.github.wulkanowy.data.repositories.homework
import io.github.wulkanowy.data.db.dao.HomeworkDao
import io.github.wulkanowy.data.db.entities.Homework
import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class HomeworkLocal @Inject constructor(private val homeworkDb: HomeworkDao) {
fun saveHomework(homework: List<Homework>) {
suspend fun saveHomework(homework: List<Homework>) {
homeworkDb.insertAll(homework)
}
fun deleteHomework(homework: List<Homework>) {
suspend fun deleteHomework(homework: List<Homework>) {
homeworkDb.deleteAll(homework)
}
fun updateHomework(homework: List<Homework>) {
suspend fun updateHomework(homework: List<Homework>) {
homeworkDb.updateAll(homework)
}
fun getHomework(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Homework>> {
fun getHomework(semester: Semester, startDate: LocalDate, endDate: LocalDate): Flow<List<Homework>> {
return homeworkDb.loadAll(semester.semesterId, semester.studentId, startDate, endDate)
.filter { it.isNotEmpty() }
}
}

View File

@ -5,19 +5,17 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single
import org.threeten.bp.LocalDate
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class HomeworkRemote @Inject constructor(private val sdk: Sdk) {
fun getHomework(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Homework>> {
suspend fun getHomework(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): List<Homework> {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getHomework(startDate, endDate)
.map { homework ->
homework.map {
.map {
Homework(
semesterId = semester.semesterId,
studentId = semester.studentId,
@ -31,5 +29,4 @@ class HomeworkRemote @Inject constructor(private val sdk: Sdk) {
)
}
}
}
}

View File

@ -1,49 +1,35 @@
package io.github.wulkanowy.data.repositories.homework
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
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.utils.sunday
import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Completable
import io.reactivex.Single
import org.threeten.bp.LocalDate
import java.net.UnknownHostException
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class HomeworkRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: HomeworkLocal,
private val remote: HomeworkRemote
) {
fun getHomework(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single<List<Homework>> {
return Single.fromCallable { start.monday to end.sunday }.flatMap { (monday, friday) ->
local.getHomework(semester, monday, friday).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getHomework(student, semester, monday, friday)
else Single.error(UnknownHostException())
}.flatMap { new ->
local.getHomework(semester, monday, friday).toSingle(emptyList())
.doOnSuccess { old ->
local.deleteHomework(old.uniqueSubtract(new))
local.saveHomework(new.uniqueSubtract(old))
}
}.flatMap { local.getHomework(semester, monday, friday).toSingle(emptyList()) })
}
fun getHomework(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh },
query = { local.getHomework(semester, start.monday, end.sunday) },
fetch = { remote.getHomework(student, semester, start.monday, end.sunday) },
saveFetchResult = { old, new ->
local.deleteHomework(old uniqueSubtract new)
local.saveHomework(new uniqueSubtract old)
}
)
fun toggleDone(homework: Homework): Completable {
return Completable.fromCallable {
suspend fun toggleDone(homework: Homework) {
local.updateHomework(listOf(homework.apply {
isDone = !isDone
}))
}
}
}

View File

@ -1,29 +1,28 @@
package io.github.wulkanowy.data.repositories.logger
import android.content.Context
import io.reactivex.Single
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.utils.DispatchersProvider
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileNotFoundException
import javax.inject.Inject
class LoggerRepository @Inject constructor(private val context: Context) {
class LoggerRepository @Inject constructor(
@ApplicationContext private val context: Context,
private val dispatchers: DispatchersProvider
) {
fun getLastLogLines(): Single<List<String>> {
return getLastModified()
.map { it.readText() }
.map { it.split("\n") }
}
suspend fun getLastLogLines() = getLastModified().readText().split("\n")
fun getLogFiles(): Single<List<File>> {
return Single.fromCallable {
suspend fun getLogFiles() = withContext(dispatchers.backgroundThread) {
File(context.filesDir.absolutePath).listFiles(File::isFile)?.filter {
it.name.endsWith(".log")
}
}
}!!
}
private fun getLastModified(): Single<File> {
return Single.fromCallable {
private suspend fun getLastModified(): File {
return withContext(dispatchers.backgroundThread) {
var lastModifiedTime = Long.MIN_VALUE
var chosenFile: File? = null
File(context.filesDir.absolutePath).listFiles(File::isFile)?.forEach { file ->
@ -33,7 +32,7 @@ class LoggerRepository @Inject constructor(private val context: Context) {
}
}
if (chosenFile == null) throw FileNotFoundException("Log file not found")
chosenFile
chosenFile!!
}
}
}

View File

@ -3,27 +3,27 @@ package io.github.wulkanowy.data.repositories.luckynumber
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.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class LuckyNumberLocal @Inject constructor(private val luckyNumberDb: LuckyNumberDao) {
fun saveLuckyNumber(luckyNumber: LuckyNumber) {
luckyNumberDb.insertAll(listOf(luckyNumber))
suspend fun saveLuckyNumber(luckyNumber: LuckyNumber?) {
luckyNumberDb.insertAll(listOfNotNull(luckyNumber))
}
fun updateLuckyNumber(luckyNumber: LuckyNumber) {
luckyNumberDb.updateAll(listOf(luckyNumber))
suspend fun updateLuckyNumber(luckyNumber: LuckyNumber?) {
luckyNumberDb.updateAll(listOfNotNull(luckyNumber))
}
fun deleteLuckyNumber(luckyNumber: LuckyNumber) {
luckyNumberDb.deleteAll(listOf(luckyNumber))
suspend fun deleteLuckyNumber(luckyNumber: LuckyNumber?) {
luckyNumberDb.deleteAll(listOfNotNull(luckyNumber))
}
fun getLuckyNumber(student: Student, date: LocalDate): Maybe<LuckyNumber> {
fun getLuckyNumber(student: Student, date: LocalDate): Flow<LuckyNumber?> {
return luckyNumberDb.load(student.studentId, date)
}
}

View File

@ -4,16 +4,15 @@ import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class LuckyNumberRemote @Inject constructor(private val sdk: Sdk) {
fun getLuckyNumber(student: Student): Maybe<LuckyNumber> {
return sdk.init(student).getLuckyNumber(student.schoolShortName).map {
suspend fun getLuckyNumber(student: Student): LuckyNumber? {
return sdk.init(student).getLuckyNumber(student.schoolShortName)?.let {
LuckyNumber(
studentId = student.studentId,
date = LocalDate.now(),

View File

@ -1,54 +1,38 @@
package io.github.wulkanowy.data.repositories.luckynumber
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Student
import io.reactivex.Completable
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import java.net.UnknownHostException
import io.github.wulkanowy.utils.networkBoundResource
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate.now
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class LuckyNumberRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: LuckyNumberLocal,
private val remote: LuckyNumberRemote
) {
fun getLuckyNumber(student: Student, forceRefresh: Boolean = false, notify: Boolean = false): Maybe<LuckyNumber> {
return local.getLuckyNumber(student, LocalDate.now()).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMapMaybe {
if (it) remote.getLuckyNumber(student)
else Maybe.error(UnknownHostException())
}.flatMap { new ->
local.getLuckyNumber(student, LocalDate.now())
.doOnSuccess { old ->
fun getLuckyNumber(student: Student, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
shouldFetch = { it == null || forceRefresh },
query = { local.getLuckyNumber(student, now()) },
fetch = { remote.getLuckyNumber(student) },
saveFetchResult = { old, new ->
if (new != old) {
local.deleteLuckyNumber(old)
local.saveLuckyNumber(new.apply {
old?.let { local.deleteLuckyNumber(it) }
local.saveLuckyNumber(new?.apply {
if (notify) isNotified = false
})
}
}
.doOnComplete {
local.saveLuckyNumber(new.apply {
if (notify) isNotified = false
})
}
}.flatMap({ local.getLuckyNumber(student, LocalDate.now()) }, { Maybe.error(it) },
{ local.getLuckyNumber(student, LocalDate.now()) })
)
fun getNotNotifiedLuckyNumber(student: Student): Flow<LuckyNumber?> {
return local.getLuckyNumber(student, now())
}
fun getNotNotifiedLuckyNumber(student: Student): Maybe<LuckyNumber> {
return local.getLuckyNumber(student, LocalDate.now()).filter { !it.isNotified }
}
fun updateLuckyNumber(luckyNumber: LuckyNumber): Completable {
return Completable.fromCallable { local.updateLuckyNumber(luckyNumber) }
suspend fun updateLuckyNumber(luckyNumber: LuckyNumber?) {
local.updateLuckyNumber(luckyNumber)
}
}

View File

@ -7,8 +7,7 @@ import io.github.wulkanowy.data.db.entities.MessageAttachment
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.message.MessageFolder.TRASHED
import io.reactivex.Maybe
import io.reactivex.Single
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
import javax.inject.Singleton
@ -18,30 +17,27 @@ class MessageLocal @Inject constructor(
private val messageAttachmentDao: MessageAttachmentDao
) {
fun saveMessages(messages: List<Message>) {
suspend fun saveMessages(messages: List<Message>) {
messagesDb.insertAll(messages)
}
fun updateMessages(messages: List<Message>) {
suspend fun updateMessages(messages: List<Message>) {
messagesDb.updateAll(messages)
}
fun deleteMessages(messages: List<Message>) {
suspend fun deleteMessages(messages: List<Message>) {
messagesDb.deleteAll(messages)
}
fun getMessageWithAttachment(student: Student, message: Message): Single<MessageWithAttachment> {
fun getMessageWithAttachment(student: Student, message: Message): Flow<MessageWithAttachment> {
return messagesDb.loadMessageWithAttachment(student.id.toInt(), message.messageId)
}
fun saveMessageAttachments(attachments: List<MessageAttachment>) {
suspend fun saveMessageAttachments(attachments: List<MessageAttachment>) {
messageAttachmentDao.insertAttachments(attachments)
}
fun getMessages(student: Student, folder: MessageFolder): Maybe<List<Message>> {
return when (folder) {
TRASHED -> messagesDb.loadDeleted(student.id.toInt())
else -> messagesDb.loadAll(student.id.toInt(), folder.id)
}.filter { it.isNotEmpty() }
fun getMessages(student: Student, folder: MessageFolder): Flow<List<Message>> {
return messagesDb.loadAll(student.id.toInt(), folder.id)
}
}

View File

@ -9,8 +9,7 @@ import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Folder
import io.github.wulkanowy.sdk.pojo.SentMessage
import io.github.wulkanowy.utils.init
import io.reactivex.Single
import org.threeten.bp.LocalDateTime.now
import java.time.LocalDateTime.now
import javax.inject.Inject
import javax.inject.Singleton
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
@ -18,32 +17,31 @@ import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
@Singleton
class MessageRemote @Inject constructor(private val sdk: Sdk) {
fun getMessages(student: Student, semester: Semester, folder: MessageFolder): Single<List<Message>> {
return sdk.init(student).getMessages(Folder.valueOf(folder.name), semester.start.atStartOfDay(), semester.end.atStartOfDay()).map { messages ->
messages.map {
suspend fun getMessages(student: Student, semester: Semester, folder: MessageFolder): List<Message> {
return sdk.init(student).getMessages(Folder.valueOf(folder.name), now().minusMonths(3), now()).map {
Message(
studentId = student.id.toInt(),
realId = it.id ?: 0,
messageId = it.messageId ?: 0,
sender = it.sender.orEmpty(),
senderId = it.senderId ?: 0,
recipient = it.recipient.orEmpty(),
sender = it.sender?.name.orEmpty(),
senderId = it.sender?.loginId ?: 0,
recipient = it.recipients.singleOrNull()?.name ?: "Wielu adresatów",
subject = it.subject.trim(),
date = it.date ?: now(),
content = it.content.orEmpty(),
folderId = it.folderId,
unread = it.unread ?: false,
unreadBy = it.unreadBy ?: 0,
readBy = it.readBy ?: 0,
removed = it.removed,
hasAttachments = it.hasAttachments
)
).apply {
content = it.content.orEmpty()
}
}
}
fun getMessagesContentDetails(student: Student, message: Message, markAsRead: Boolean = false): Single<Pair<String, List<MessageAttachment>>> {
return sdk.init(student).getMessageDetails(message.messageId, message.folderId, markAsRead, message.realId).map { details ->
suspend fun getMessagesContentDetails(student: Student, message: Message, markAsRead: Boolean = false): Pair<String, List<MessageAttachment>> {
return sdk.init(student).getMessageDetails(message.messageId, message.folderId, markAsRead, message.realId).let { details ->
details.content to details.attachments.map {
MessageAttachment(
realId = it.id,
@ -56,7 +54,7 @@ class MessageRemote @Inject constructor(private val sdk: Sdk) {
}
}
fun sendMessage(student: Student, subject: String, content: String, recipients: List<Recipient>): Single<SentMessage> {
suspend fun sendMessage(student: Student, subject: String, content: String, recipients: List<Recipient>): SentMessage {
return sdk.init(student).sendMessage(
subject = subject,
content = content,
@ -74,7 +72,7 @@ class MessageRemote @Inject constructor(private val sdk: Sdk) {
)
}
fun deleteMessage(student: Student, message: Message): Single<Boolean> {
return sdk.init(student).deleteMessages(listOf(message.messageId to message.folderId))
suspend fun deleteMessage(student: Student, message: Message): Boolean {
return sdk.init(student).deleteMessages(listOf(message.messageId), message.folderId)
}
}

Some files were not shown because too many files have changed in this diff Show More