Compare commits
105 Commits
Author | SHA1 | Date | |
---|---|---|---|
31902a7667 | |||
4c1c4f8a43 | |||
7850412ba9 | |||
4f0ff5f49c | |||
131ba7dbb1 | |||
b95b529015 | |||
29226dd93e | |||
115da64167 | |||
6cd1877af7 | |||
78a90591fd | |||
45265d025d | |||
9bf5c2dc40 | |||
ee4bdd2a9a | |||
0b75635ad5 | |||
f7b5b9c413 | |||
52d66ac30b | |||
6ac5c6a0b4 | |||
45fc76a9a5 | |||
6d1fa0cf05 | |||
8eb0c0351b | |||
ec80f939f1 | |||
70fc51a0b5 | |||
bd700a88bf | |||
98f2f0e74f | |||
4a3b746d48 | |||
a1f864b35e | |||
17ac3cfd52 | |||
c6c2b1c6a3 | |||
5fba3d5775 | |||
6fe62edd63 | |||
87af3da1ad | |||
155f0cc347 | |||
2de1ad5334 | |||
763543a16e | |||
acabe90c9f | |||
f79da9003a | |||
fc9e558cd6 | |||
68140bd544 | |||
2c4c2d1f49 | |||
4894086d9d | |||
1d29ef5fe3 | |||
7fa333cff2 | |||
c1ffc2ae72 | |||
9c0e2dc533 | |||
9b18e3669d | |||
366ebc781d | |||
4bd0459155 | |||
b19084cb57 | |||
69be7ca412 | |||
07307b9709 | |||
ee4a5e56a9 | |||
c8f8ec77a9 | |||
be46a43427 | |||
183e379223 | |||
2350fc2ddf | |||
152f966a66 | |||
85ee7fad1d | |||
3ac085573f | |||
64a19d9627 | |||
76af623c94 | |||
11c285be01 | |||
a0528496eb | |||
299345b864 | |||
0a18fefb1f | |||
a26f0ec8c8 | |||
232d8d38bd | |||
4833e1e130 | |||
bb30cf2ce3 | |||
c9b35bed7e | |||
999672fcc3 | |||
6a0ce3a58d | |||
3612326628 | |||
bf61dd1bad | |||
18c1153e12 | |||
651be69ad2 | |||
394e3bb79c | |||
502a98b70a | |||
da357775ff | |||
c0adeaadfd | |||
358c87528a | |||
0cb4866f40 | |||
6ec13c896d | |||
a0587a8bce | |||
184c9413f8 | |||
6440820dc5 | |||
d9322b0df4 | |||
b9a19b60e4 | |||
6f697eff47 | |||
d9c8bb399b | |||
2137b6c225 | |||
0320079d02 | |||
95a833ea85 | |||
a85a4fe7a0 | |||
f94b8c9be8 | |||
5dfe9cdd4f | |||
9a83b43d57 | |||
7d21babd38 | |||
f763a42323 | |||
478596c4e6 | |||
37842a3603 | |||
1775e2fe62 | |||
68b26d5e2b | |||
6304395050 | |||
fa3c357665 | |||
83282aeab6 |
@ -1,3 +1,3 @@
|
||||
component_depth: 8
|
||||
component_depth: 10
|
||||
languages:
|
||||
- kotlin
|
||||
|
11
.travis.yml
11
.travis.yml
@ -14,7 +14,7 @@ cache:
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- 0.16.0
|
||||
- 0.18.0
|
||||
|
||||
android:
|
||||
licenses:
|
||||
@ -48,20 +48,15 @@ before_script:
|
||||
script:
|
||||
- ./gradlew dependencies --stacktrace --daemon
|
||||
- fossa --no-ansi || true
|
||||
#- ./gradlew lintPlayRelease -x fabricGenerateResourcesPlayRelease --stacktrace --daemon
|
||||
- ./gradlew -Pcoverage testPlayDebugUnitTest -x fabricGenerateResourcesPlay --stacktrace --daemon
|
||||
- ./gradlew -Pcoverage testPlayDebugUnitTest --stacktrace --daemon
|
||||
- ./gradlew -Pcoverage createFdroidDebugCoverageReport --stacktrace --daemon
|
||||
- ./gradlew -Pcoverage jacocoTestReport --stacktrace --daemon
|
||||
- if [ -z ${SONAR_HOST+x} ]; then echo "sonar scan skipped"; else
|
||||
git fetch --unshallow;
|
||||
./gradlew sonarqube -x test -x lint -x fabricGenerateResourcesPlayRelease -x fabricGenerateResourcesFdroidRelease -Dsonar.host.url=$SONAR_HOST -Dsonar.organization=$SONAR_ORG -Dsonar.login=$SONAR_KEY -Dsonar.branch.name=${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} --stacktrace --daemon;
|
||||
fi
|
||||
- |
|
||||
if [ $TRAVIS_TAG ]; then
|
||||
gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/google-services.json.gpg;
|
||||
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/key.p12.gpg;
|
||||
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg;
|
||||
./gradlew publishPlayRelease -PenableCrashlytics --stacktrace;
|
||||
./gradlew publishPlayRelease -PenableFirebase --stacktrace;
|
||||
fi
|
||||
|
||||
after_success:
|
||||
|
@ -1,9 +1,9 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'io.fabric'
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
apply plugin: 'com.github.triplet.play'
|
||||
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
|
||||
apply from: 'jacoco.gradle'
|
||||
apply from: 'sonarqube.gradle'
|
||||
apply from: 'hooks.gradle'
|
||||
@ -17,14 +17,13 @@ android {
|
||||
testApplicationId "io.github.tests.wulkanowy"
|
||||
minSdkVersion 17
|
||||
targetSdkVersion 29
|
||||
versionCode 53
|
||||
versionName "0.16.0"
|
||||
versionCode 59
|
||||
versionName "0.18.0"
|
||||
multiDexEnabled true
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
manifestPlaceholders = [
|
||||
fabric_api_key : System.getenv("FABRIC_API_KEY") ?: "null",
|
||||
crashlytics_enabled: project.hasProperty("enableCrashlytics")
|
||||
firebase_enabled: project.hasProperty("enableFirebase")
|
||||
]
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
@ -51,18 +50,16 @@ android {
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
buildConfigField "boolean", "CRASHLYTICS_ENABLED", "true"
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
debug {
|
||||
buildConfigField "boolean", "CRASHLYTICS_ENABLED", project.hasProperty("enableCrashlytics") ? "true" : "false"
|
||||
applicationIdSuffix ".dev"
|
||||
versionNameSuffix "-dev"
|
||||
testCoverageEnabled = project.hasProperty('coverage')
|
||||
ext.enableCrashlytics = project.hasProperty("enableCrashlytics")
|
||||
ext.enableCrashlytics = project.hasProperty("enableFirebase")
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,11 +71,14 @@ android {
|
||||
}
|
||||
|
||||
fdroid {
|
||||
buildConfigField "boolean", "CRASHLYTICS_ENABLED", "false"
|
||||
dimension "platform"
|
||||
}
|
||||
}
|
||||
|
||||
viewBinding {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
disable 'HardwareIds'
|
||||
}
|
||||
@ -96,10 +96,10 @@ android {
|
||||
exclude 'META-INF/library_release.kotlin_module'
|
||||
exclude 'META-INF/library-core_release.kotlin_module'
|
||||
}
|
||||
}
|
||||
|
||||
androidExtensions {
|
||||
experimental = true
|
||||
aboutLibraries {
|
||||
configPath = "app/src/main/res/raw"
|
||||
}
|
||||
}
|
||||
|
||||
play {
|
||||
@ -110,10 +110,10 @@ play {
|
||||
}
|
||||
|
||||
ext {
|
||||
work_manager = "2.3.2"
|
||||
room = "2.2.4"
|
||||
dagger = "2.26"
|
||||
chucker = "2.0.4"
|
||||
work_manager = "2.3.4"
|
||||
room = "2.2.5"
|
||||
dagger = "2.27"
|
||||
chucker = "3.2.0"
|
||||
mockk = "1.9.2"
|
||||
}
|
||||
|
||||
@ -122,21 +122,21 @@ configurations.all {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "io.github.wulkanowy:sdk:0.16.0"
|
||||
implementation "io.github.wulkanowy:sdk:0.18.0"
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "androidx.core:core-ktx:1.2.0"
|
||||
implementation "androidx.activity:activity-ktx:1.1.0"
|
||||
implementation "androidx.appcompat:appcompat:1.1.0"
|
||||
implementation "androidx.appcompat:appcompat:1.2.0-rc01"
|
||||
implementation "androidx.appcompat:appcompat-resources:1.1.0"
|
||||
implementation "androidx.fragment:fragment-ktx:1.2.2"
|
||||
implementation "androidx.fragment:fragment-ktx:1.2.4"
|
||||
implementation "androidx.annotation:annotation:1.1.0"
|
||||
implementation "androidx.multidex:multidex:2.0.1"
|
||||
|
||||
implementation "androidx.preference:preference-ktx:1.1.0"
|
||||
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-alpha03"
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-rc01"
|
||||
implementation "androidx.constraintlayout:constraintlayout:1.1.3"
|
||||
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
|
||||
implementation "com.google.android.material:material:1.1.0"
|
||||
@ -148,6 +148,8 @@ dependencies {
|
||||
implementation "androidx.work:work-rxjava2:$work_manager"
|
||||
implementation "androidx.work:work-gcm:$work_manager"
|
||||
|
||||
implementation 'com.github.PaulinaSadowska:RxWorkManagerObservers:1.0.0'
|
||||
|
||||
implementation "androidx.room:room-runtime:$room"
|
||||
implementation "androidx.room:room-rxjava2:$room"
|
||||
implementation "androidx.room:room-ktx:$room"
|
||||
@ -159,38 +161,40 @@ dependencies {
|
||||
implementation "com.squareup.inject:assisted-inject-annotations-dagger2:0.5.2"
|
||||
kapt "com.squareup.inject:assisted-inject-processor-dagger2:0.5.2"
|
||||
|
||||
implementation "eu.davidea:flexible-adapter:5.1.0"
|
||||
implementation "eu.davidea:flexible-adapter-ui:1.0.0"
|
||||
implementation "com.aurelhubert:ahbottomnavigation:2.3.4"
|
||||
implementation "com.ncapdevi:frag-nav:3.3.0"
|
||||
implementation "com.github.YarikSOffice:lingver:1.1.0"
|
||||
implementation "com.github.YarikSOffice:lingver:1.2.2"
|
||||
|
||||
implementation "com.github.pwittchen:reactivenetwork-rx2:3.0.6"
|
||||
implementation "com.github.pwittchen:reactivenetwork-rx2:3.0.8"
|
||||
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
|
||||
implementation "io.reactivex.rxjava2:rxjava:2.2.18"
|
||||
implementation "io.reactivex.rxjava2:rxjava:2.2.19"
|
||||
|
||||
implementation "com.google.code.gson:gson:2.8.6"
|
||||
implementation "com.jakewharton.threetenabp:threetenabp:1.2.2"
|
||||
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:7.1.0"
|
||||
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
||||
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
|
||||
implementation "io.coil-kt:coil:0.11.0"
|
||||
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
|
||||
|
||||
implementation("io.coil-kt:coil:0.9.5")
|
||||
playImplementation 'com.google.firebase:firebase-analytics:17.4.1'
|
||||
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.0.6'
|
||||
playImplementation "com.google.firebase:firebase-inappmessaging-ktx:19.0.6"
|
||||
playImplementation 'com.google.firebase:firebase-messaging:20.1.7'
|
||||
playImplementation 'com.google.firebase:firebase-crashlytics:17.0.0'
|
||||
playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
|
||||
|
||||
playImplementation "com.google.firebase:firebase-core:17.2.3"
|
||||
playImplementation "com.crashlytics.sdk.android:crashlytics:2.10.1"
|
||||
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
||||
|
||||
releaseImplementation "fr.o80.chucker:library-no-op:$chucker"
|
||||
|
||||
debugImplementation "fr.o80.chucker:library:$chucker"
|
||||
debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker"
|
||||
debugImplementation "com.amitshekhar.android:debug-db:1.0.6"
|
||||
|
||||
testImplementation "junit:junit:4.13"
|
||||
testImplementation "io.mockk:mockk:$mockk"
|
||||
testImplementation "org.threeten:threetenbp:1.4.1"
|
||||
testImplementation "org.mockito:mockito-inline:3.3.1"
|
||||
testImplementation "org.threeten:threetenbp:1.4.4"
|
||||
testImplementation "org.mockito:mockito-inline:3.3.3"
|
||||
|
||||
androidTestImplementation "androidx.test:core:1.2.0"
|
||||
androidTestImplementation "androidx.test:runner:1.2.0"
|
||||
@ -198,7 +202,7 @@ dependencies {
|
||||
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.1"
|
||||
androidTestImplementation "org.mockito:mockito-android:3.3.3"
|
||||
}
|
||||
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
|
7
app/proguard-rules.pro
vendored
7
app/proguard-rules.pro
vendored
@ -43,3 +43,10 @@
|
||||
|
||||
#Config for Material Components
|
||||
-keep class com.google.android.material.tabs.** { *; }
|
||||
|
||||
|
||||
#Config for About Libraries
|
||||
-keep class .R
|
||||
-keep class **.R$* {
|
||||
<fields>;
|
||||
}
|
||||
|
1682
app/schemas/io.github.wulkanowy.data.db.AppDatabase/23.json
Normal file
1682
app/schemas/io.github.wulkanowy.data.db.AppDatabase/23.json
Normal file
File diff suppressed because it is too large
Load Diff
1732
app/schemas/io.github.wulkanowy.data.db.AppDatabase/24.json
Normal file
1732
app/schemas/io.github.wulkanowy.data.db.AppDatabase/24.json
Normal file
File diff suppressed because it is too large
Load Diff
1744
app/schemas/io.github.wulkanowy.data.db.AppDatabase/25.json
Normal file
1744
app/schemas/io.github.wulkanowy.data.db.AppDatabase/25.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,29 @@
|
||||
package io.github.wulkanowy.data.repositories
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import org.threeten.bp.LocalDateTime
|
||||
|
||||
fun getStudent(): Student {
|
||||
return Student(
|
||||
email = "test",
|
||||
password = "test123",
|
||||
schoolSymbol = "23",
|
||||
scrapperBaseUrl = "fakelog.cf",
|
||||
loginType = "AUTO",
|
||||
isCurrent = true,
|
||||
studentName = "",
|
||||
schoolShortName = "",
|
||||
schoolName = "",
|
||||
studentId = 0,
|
||||
classId = 1,
|
||||
symbol = "",
|
||||
registrationDate = LocalDateTime.now(),
|
||||
className = "",
|
||||
loginMode = "API",
|
||||
certificateKey = "",
|
||||
privateKey = "",
|
||||
mobileBaseUrl = "",
|
||||
userLoginId = 0,
|
||||
isParent = false
|
||||
)
|
||||
}
|
@ -24,7 +24,7 @@ class GradeLocalTest {
|
||||
fun createDb() {
|
||||
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
|
||||
.build()
|
||||
gradeLocal = GradeLocal(testDb.gradeDao)
|
||||
gradeLocal = GradeLocal(testDb.gradeDao, testDb.gradeSummaryDao)
|
||||
}
|
||||
|
||||
@After
|
||||
@ -43,7 +43,7 @@ class GradeLocalTest {
|
||||
val semester = Semester(1, 2, "", 2019, 2, 1, now(), now(), 1, 1)
|
||||
|
||||
val grades = gradeLocal
|
||||
.getGrades(semester)
|
||||
.getGradesDetails(semester)
|
||||
.blockingGet()
|
||||
|
||||
assertEquals(2, grades.size)
|
||||
|
@ -11,6 +11,7 @@ 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.every
|
||||
import io.mockk.impl.annotations.MockK
|
||||
@ -52,7 +53,7 @@ class GradeRepositoryTest {
|
||||
fun initApi() {
|
||||
MockKAnnotations.init(this)
|
||||
testDb = Room.inMemoryDatabaseBuilder(getApplicationContext(), AppDatabase::class.java).build()
|
||||
gradeLocal = GradeLocal(testDb.gradeDao)
|
||||
gradeLocal = GradeLocal(testDb.gradeDao, testDb.gradeSummaryDao)
|
||||
gradeRemote = GradeRemote(mockSdk)
|
||||
|
||||
every { studentMock.registrationDate } returns LocalDateTime.of(2019, 2, 27, 12, 0)
|
||||
@ -75,10 +76,10 @@ class GradeRepositoryTest {
|
||||
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")
|
||||
))
|
||||
) to emptyList())
|
||||
|
||||
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
|
||||
.getGrades(studentMock, semesterMock, true).blockingGet().sortedByDescending { it.date }
|
||||
.getGrades(studentMock, semesterMock, true).blockingGet().first.sortedByDescending { it.date }
|
||||
|
||||
assertFalse { grades[0].isRead }
|
||||
assertFalse { grades[1].isRead }
|
||||
@ -99,10 +100,10 @@ class GradeRepositoryTest {
|
||||
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")
|
||||
))
|
||||
) to emptyList())
|
||||
|
||||
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
|
||||
.getGrades(studentMock, semesterMock, true).blockingGet().sortedByDescending { it.date }
|
||||
.getGrades(studentMock, semesterMock, true).blockingGet().first.sortedByDescending { it.date }
|
||||
|
||||
assertFalse { grades[0].isRead }
|
||||
assertFalse { grades[1].isRead }
|
||||
@ -121,12 +122,12 @@ class GradeRepositoryTest {
|
||||
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")
|
||||
))
|
||||
) to emptyList())
|
||||
|
||||
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
|
||||
.getGrades(studentMock, semesterMock, true).blockingGet()
|
||||
|
||||
assertEquals(2, grades.size)
|
||||
assertEquals(2, grades.first.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -140,12 +141,12 @@ class GradeRepositoryTest {
|
||||
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")
|
||||
))
|
||||
) to emptyList())
|
||||
|
||||
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
|
||||
.getGrades(studentMock, semesterMock, true).blockingGet()
|
||||
|
||||
assertEquals(3, grades.size)
|
||||
assertEquals(3, grades.first.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -156,12 +157,12 @@ class GradeRepositoryTest {
|
||||
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")
|
||||
))
|
||||
) to emptyList())
|
||||
|
||||
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
|
||||
.getGrades(studentMock, semesterMock, true).blockingGet()
|
||||
|
||||
assertEquals(3, grades.size)
|
||||
assertEquals(3, grades.first.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -171,11 +172,11 @@ class GradeRepositoryTest {
|
||||
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
|
||||
))
|
||||
|
||||
every { mockSdk.getGrades(1) } returns Single.just(listOf())
|
||||
every { mockSdk.getGrades(1) } returns Single.just(emptyList<Grade>() to emptyList())
|
||||
|
||||
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
|
||||
.getGrades(studentMock, semesterMock, true).blockingGet()
|
||||
|
||||
assertEquals(0, grades.size)
|
||||
assertEquals(0, grades.first.size)
|
||||
}
|
||||
}
|
||||
|
@ -5,13 +5,11 @@ import androidx.room.Room
|
||||
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.SharedPrefProvider
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.getStudent
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.threeten.bp.LocalDateTime.now
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@ -21,14 +19,13 @@ class StudentLocalTest {
|
||||
|
||||
private lateinit var testDb: AppDatabase
|
||||
|
||||
private lateinit var sharedProvider: SharedPrefProvider
|
||||
private val student = getStudent()
|
||||
|
||||
@Before
|
||||
fun createDb() {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
testDb = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java)
|
||||
.build()
|
||||
sharedProvider = SharedPrefProvider(context.getSharedPreferences("TEST", Context.MODE_PRIVATE))
|
||||
studentLocal = StudentLocal(testDb.studentDao, context)
|
||||
}
|
||||
|
||||
@ -39,8 +36,7 @@ class StudentLocalTest {
|
||||
|
||||
@Test
|
||||
fun saveAndReadTest() {
|
||||
studentLocal.saveStudents(listOf(Student(email = "test", password = "test123", schoolSymbol = "23", scrapperBaseUrl = "fakelog.cf", loginType = "AUTO", isCurrent = true, studentName = "", schoolShortName = "", schoolName = "", studentId = 0, classId = 1, symbol = "", registrationDate = now(), className = "", loginMode = "API", certificateKey = "", privateKey = "", mobileBaseUrl = "", userLoginId = 0, isParent = false)))
|
||||
.blockingGet()
|
||||
studentLocal.saveStudents(listOf(student)).blockingGet()
|
||||
|
||||
val student = studentLocal.getCurrentStudent(true).blockingGet()
|
||||
assertEquals("23", student.schoolSymbol)
|
||||
|
@ -8,11 +8,15 @@ import androidx.test.filters.SdkSuppress
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||
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.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.impl.annotations.MockK
|
||||
import io.mockk.mockk
|
||||
import io.reactivex.Single
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
@ -33,9 +37,17 @@ class TimetableRepositoryTest {
|
||||
.strategy(TestInternetObservingStrategy())
|
||||
.build()
|
||||
|
||||
@MockK
|
||||
private lateinit var studentMock: Student
|
||||
|
||||
private val student = getStudent()
|
||||
|
||||
@MockK
|
||||
private lateinit var semesterMock: Semester
|
||||
|
||||
@MockK
|
||||
private lateinit var timetableNotificationSchedulerHelper: TimetableNotificationSchedulerHelper
|
||||
|
||||
private lateinit var timetableRemote: TimetableRemote
|
||||
|
||||
private lateinit var timetableLocal: TimetableLocal
|
||||
@ -49,10 +61,17 @@ class TimetableRepositoryTest {
|
||||
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
|
||||
}
|
||||
|
||||
@ -77,8 +96,8 @@ class TimetableRepositoryTest {
|
||||
createTimetableRemote(of(2019, 3, 5, 10, 30), 4, "", "W-F")
|
||||
))
|
||||
|
||||
val lessons = TimetableRepository(settings, timetableLocal, timetableRemote)
|
||||
.getTimetable(semesterMock, LocalDate.of(2019, 3, 5), LocalDate.of(2019, 3, 5), true)
|
||||
val lessons = TimetableRepository(settings, timetableLocal, timetableRemote, timetableNotificationSchedulerHelper)
|
||||
.getTimetable(student, semesterMock, LocalDate.of(2019, 3, 5), LocalDate.of(2019, 3, 5), true)
|
||||
.blockingGet()
|
||||
|
||||
assertEquals(4, lessons.size)
|
||||
@ -123,8 +142,8 @@ class TimetableRepositoryTest {
|
||||
createTimetableRemote(of(2019, 12, 25, 10, 40), 4, "126", "Matematyka", "Paweł Czwartkowski", true)
|
||||
))
|
||||
|
||||
val lessons = TimetableRepository(settings, timetableLocal, timetableRemote)
|
||||
.getTimetable(semesterMock, LocalDate.of(2019, 12, 23), LocalDate.of(2019, 12, 25), true)
|
||||
val lessons = TimetableRepository(settings, timetableLocal, timetableRemote, timetableNotificationSchedulerHelper)
|
||||
.getTimetable(student, semesterMock, LocalDate.of(2019, 12, 23), LocalDate.of(2019, 12, 25), true)
|
||||
.blockingGet()
|
||||
|
||||
assertEquals(12, lessons.size)
|
||||
|
4
app/src/debug/res/values/preferences_defaults.xml
Normal file
4
app/src/debug/res/values/preferences_defaults.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||
|
||||
<bool name="pref_default_notification_debug">true</bool>
|
||||
</resources>
|
@ -18,11 +18,13 @@
|
||||
android:supportsRtl="false"
|
||||
android:theme="@style/WulkanowyTheme"
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
|
||||
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute"
|
||||
tools:replace="android:supportsRtl,android:allowBackup">
|
||||
<activity
|
||||
android:name=".ui.modules.splash.SplashActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/WulkanowyTheme.SplashScreen">
|
||||
android:theme="@style/WulkanowyTheme.SplashScreen"
|
||||
tools:ignore="LockedOrientationActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
@ -38,7 +40,8 @@
|
||||
android:name=".ui.modules.main.MainActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/main_title"
|
||||
android:theme="@style/WulkanowyTheme.NoActionBar" />
|
||||
android:theme="@style/WulkanowyTheme.NoActionBar"
|
||||
android:windowSoftInputMode="adjustPan" />
|
||||
<activity
|
||||
android:name=".ui.modules.message.send.SendMessageActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
@ -90,6 +93,8 @@
|
||||
android:resource="@xml/provider_widget_lucky_number" />
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".services.alarm.TimetableNotificationReceiver" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.work.impl.WorkManagerInitializer"
|
||||
android:authorities="${applicationId}.workmanager-init"
|
||||
@ -106,11 +111,40 @@
|
||||
android:resource="@xml/provider_paths" />
|
||||
</provider>
|
||||
|
||||
<!-- workaround for https://github.com/firebase/firebase-android-sdk/issues/473 enabled:false -->
|
||||
<!-- https://firebase.googleblog.com/2017/03/take-control-of-your-firebase-init-on.html -->
|
||||
<provider
|
||||
android:name="com.google.firebase.provider.FirebaseInitProvider"
|
||||
android:authorities="${applicationId}.firebaseinitprovider"
|
||||
android:enabled="${firebase_enabled}"
|
||||
android:exported="false" />
|
||||
|
||||
<meta-data
|
||||
android:name="io.fabric.ApiKey"
|
||||
android:value="${fabric_api_key}" />
|
||||
android:name="firebase_analytics_collection_enabled"
|
||||
android:value="${firebase_enabled}" />
|
||||
|
||||
<meta-data
|
||||
android:name="google_analytics_adid_collection_enabled"
|
||||
android:value="${firebase_enabled}" />
|
||||
|
||||
<meta-data
|
||||
android:name="firebase_crashlytics_collection_enabled"
|
||||
android:value="${crashlytics_enabled}" />
|
||||
android:value="${firebase_enabled}" />
|
||||
|
||||
<meta-data
|
||||
android:name="firebase_messaging_auto_init_enabled"
|
||||
android:value="${firebase_enabled}" />
|
||||
|
||||
<meta-data
|
||||
android:name="firebase_inapp_messaging_auto_data_collection_enabled"
|
||||
android:value="${firebase_enabled}" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||
android:resource="@drawable/ic_stat_push" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_channel_id"
|
||||
android:value="push_channel" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
@ -10,8 +10,6 @@ import com.jakewharton.threetenabp.AndroidThreeTen
|
||||
import com.yariksoffice.lingver.Lingver
|
||||
import dagger.android.AndroidInjector
|
||||
import dagger.android.support.DaggerApplication
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.utils.Log
|
||||
import fr.bipi.tressence.file.FileLoggerTree
|
||||
import io.github.wulkanowy.di.DaggerAppComponent
|
||||
import io.github.wulkanowy.services.sync.SyncWorkerFactory
|
||||
@ -21,7 +19,6 @@ 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.github.wulkanowy.utils.initCrashlytics
|
||||
import io.reactivex.exceptions.UndeliverableException
|
||||
import io.reactivex.plugins.RxJavaPlugins
|
||||
import timber.log.Timber
|
||||
@ -52,12 +49,10 @@ class WulkanowyApp : DaggerApplication(), Configuration.Provider {
|
||||
themeManager.applyDefaultTheme()
|
||||
|
||||
initLogging()
|
||||
initCrashlytics(this, appInfo)
|
||||
}
|
||||
|
||||
private fun initLogging() {
|
||||
if (appInfo.isDebug) {
|
||||
FlexibleAdapter.enableLogs(Log.Level.DEBUG)
|
||||
Timber.plant(DebugLogTree())
|
||||
Timber.plant(FileLoggerTree.Builder()
|
||||
.withFileName("wulkanowy.%g.log")
|
||||
|
@ -1,15 +1,17 @@
|
||||
package io.github.wulkanowy.data
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.AssetManager
|
||||
import android.content.res.Resources
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.WalledGardenInternetObservingStrategy
|
||||
import com.readystatesoftware.chuck.api.ChuckCollector
|
||||
import com.readystatesoftware.chuck.api.ChuckInterceptor
|
||||
import com.readystatesoftware.chuck.api.RetentionManager
|
||||
import com.chuckerteam.chucker.api.ChuckerCollector
|
||||
import com.chuckerteam.chucker.api.ChuckerInterceptor
|
||||
import com.chuckerteam.chucker.api.RetentionManager
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.github.wulkanowy.data.db.AppDatabase
|
||||
@ -32,23 +34,25 @@ internal class RepositoryModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideSdk(chuckCollector: ChuckCollector, context: Context): Sdk {
|
||||
fun provideSdk(chuckerCollector: ChuckerCollector, context: Context): Sdk {
|
||||
return Sdk().apply {
|
||||
androidVersion = android.os.Build.VERSION.RELEASE
|
||||
buildTag = android.os.Build.MODEL
|
||||
setSimpleHttpLogger { Timber.d(it) }
|
||||
|
||||
// for debug only
|
||||
addInterceptor(ChuckInterceptor(context, chuckCollector).maxContentLength(250000L), true)
|
||||
addInterceptor(ChuckerInterceptor(context, chuckerCollector), true)
|
||||
}
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideChuckCollector(context: Context, prefRepository: PreferencesRepository): ChuckCollector {
|
||||
return ChuckCollector(context)
|
||||
.showNotification(prefRepository.isDebugNotificationEnable)
|
||||
.retentionManager(RetentionManager(context, ChuckCollector.Period.ONE_HOUR))
|
||||
fun provideChuckerCollector(context: Context, prefRepository: PreferencesRepository): ChuckerCollector {
|
||||
return ChuckerCollector(
|
||||
context = context,
|
||||
showNotification = prefRepository.isDebugNotificationEnable,
|
||||
retentionPeriod = RetentionManager.Period.ONE_HOUR
|
||||
)
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@ -95,6 +99,10 @@ internal class RepositoryModule {
|
||||
@Provides
|
||||
fun provideMessagesDao(database: AppDatabase) = database.messagesDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideMessageAttachmentsDao(database: AppDatabase) = database.messageAttachmentDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideExamDao(database: AppDatabase) = database.examsDao
|
||||
|
@ -1,30 +0,0 @@
|
||||
package io.github.wulkanowy.data
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import javax.inject.Inject
|
||||
|
||||
class SdkHelper @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun init(student: Student) {
|
||||
sdk.apply {
|
||||
email = student.email
|
||||
password = student.password
|
||||
symbol = student.symbol
|
||||
schoolSymbol = student.schoolSymbol
|
||||
studentId = student.studentId
|
||||
classId = student.classId
|
||||
|
||||
if (Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
|
||||
scrapperBaseUrl = student.scrapperBaseUrl
|
||||
loginType = Sdk.ScrapperLoginType.valueOf(student.loginType)
|
||||
}
|
||||
loginId = student.userLoginId
|
||||
|
||||
mode = Sdk.Mode.valueOf(student.loginMode)
|
||||
mobileBaseUrl = student.mobileBaseUrl
|
||||
certKey = student.certificateKey
|
||||
privateKey = student.privateKey
|
||||
}
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ import io.github.wulkanowy.data.db.dao.GradeStatisticsDao
|
||||
import io.github.wulkanowy.data.db.dao.GradeSummaryDao
|
||||
import io.github.wulkanowy.data.db.dao.HomeworkDao
|
||||
import io.github.wulkanowy.data.db.dao.LuckyNumberDao
|
||||
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||
import io.github.wulkanowy.data.db.dao.MobileDeviceDao
|
||||
import io.github.wulkanowy.data.db.dao.NoteDao
|
||||
@ -39,6 +40,7 @@ import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
import io.github.wulkanowy.data.db.entities.Homework
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
||||
import io.github.wulkanowy.data.db.entities.MobileDevice
|
||||
import io.github.wulkanowy.data.db.entities.Note
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
@ -63,6 +65,9 @@ import io.github.wulkanowy.data.db.migrations.Migration2
|
||||
import io.github.wulkanowy.data.db.migrations.Migration20
|
||||
import io.github.wulkanowy.data.db.migrations.Migration21
|
||||
import io.github.wulkanowy.data.db.migrations.Migration22
|
||||
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.Migration3
|
||||
import io.github.wulkanowy.data.db.migrations.Migration4
|
||||
import io.github.wulkanowy.data.db.migrations.Migration5
|
||||
@ -86,6 +91,7 @@ import javax.inject.Singleton
|
||||
GradeStatistics::class,
|
||||
GradePointsStatistics::class,
|
||||
Message::class,
|
||||
MessageAttachment::class,
|
||||
Note::class,
|
||||
Homework::class,
|
||||
Subject::class,
|
||||
@ -104,7 +110,7 @@ import javax.inject.Singleton
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
companion object {
|
||||
const val VERSION_SCHEMA = 22
|
||||
const val VERSION_SCHEMA = 25
|
||||
|
||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> {
|
||||
return arrayOf(
|
||||
@ -128,7 +134,10 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
Migration19(sharedPrefProvider),
|
||||
Migration20(),
|
||||
Migration21(),
|
||||
Migration22()
|
||||
Migration22(),
|
||||
Migration23(),
|
||||
Migration24(),
|
||||
Migration25()
|
||||
)
|
||||
}
|
||||
|
||||
@ -164,6 +173,8 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
abstract val messagesDao: MessagesDao
|
||||
|
||||
abstract val messageAttachmentDao: MessageAttachmentDao
|
||||
|
||||
abstract val noteDao: NoteDao
|
||||
|
||||
abstract val homeworkDao: HomeworkDao
|
||||
|
@ -48,4 +48,14 @@ class Converters {
|
||||
fun gsonToIntList(value: String): List<Int> {
|
||||
return Gson().fromJson(value, object : TypeToken<List<Int>>() {}.type)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun stringPairListToGson(list: List<Pair<String, String>>): String {
|
||||
return Gson().toJson(list)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun gsonToStringPairList(value: String): List<Pair<String, String>> {
|
||||
return Gson().fromJson(value, object : TypeToken<List<Pair<String, String>>>() {}.type)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package io.github.wulkanowy.data.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
||||
|
||||
@Dao
|
||||
interface MessageAttachmentDao : BaseDao<MessageAttachment> {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insertAttachments(items: List<MessageAttachment>): List<Long>
|
||||
}
|
@ -2,19 +2,22 @@ package io.github.wulkanowy.data.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
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
|
||||
|
||||
@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>
|
||||
|
||||
@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 id = :id")
|
||||
fun load(id: Long): Single<Message>
|
||||
|
||||
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND removed = 1 ORDER BY date DESC")
|
||||
fun loadDeleted(studentId: Int): Maybe<List<Message>>
|
||||
}
|
||||
|
@ -22,6 +22,9 @@ interface StudentDao {
|
||||
@Query("SELECT * FROM Students WHERE is_current = 1")
|
||||
fun loadCurrent(): Maybe<Student>
|
||||
|
||||
@Query("SELECT * FROM Students WHERE id = :id")
|
||||
fun loadById(id: Int): Maybe<Student>
|
||||
|
||||
@Query("SELECT * FROM Students")
|
||||
fun loadAll(): Maybe<List<Student>>
|
||||
|
||||
|
@ -27,10 +27,14 @@ data class Homework(
|
||||
val teacher: String,
|
||||
|
||||
@ColumnInfo(name = "teacher_symbol")
|
||||
val teacherSymbol: String
|
||||
val teacherSymbol: String,
|
||||
|
||||
val attachments: List<Pair<String, String>>
|
||||
) : Serializable {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
|
||||
@ColumnInfo(name = "is_done")
|
||||
var isDone: Boolean = false
|
||||
}
|
||||
|
@ -44,7 +44,10 @@ data class Message(
|
||||
@ColumnInfo(name = "read_by")
|
||||
val readBy: Int,
|
||||
|
||||
val removed: Boolean
|
||||
val removed: Boolean,
|
||||
|
||||
@ColumnInfo(name = "has_attachments")
|
||||
val hasAttachments: Boolean
|
||||
) : Serializable {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
|
@ -0,0 +1,26 @@
|
||||
package io.github.wulkanowy.data.db.entities
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import java.io.Serializable
|
||||
|
||||
@Entity(tableName = "MessageAttachments")
|
||||
data class MessageAttachment(
|
||||
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "real_id")
|
||||
val realId: Int,
|
||||
|
||||
@ColumnInfo(name = "message_id")
|
||||
val messageId: Int,
|
||||
|
||||
@ColumnInfo(name = "one_drive_id")
|
||||
val oneDriveId: String,
|
||||
|
||||
@ColumnInfo(name = "url")
|
||||
val url: String,
|
||||
|
||||
@ColumnInfo(name = "filename")
|
||||
val filename: String
|
||||
) : Serializable
|
@ -0,0 +1,12 @@
|
||||
package io.github.wulkanowy.data.db.entities
|
||||
|
||||
import androidx.room.Embedded
|
||||
import androidx.room.Relation
|
||||
|
||||
data class MessageWithAttachment(
|
||||
@Embedded
|
||||
val message: Message,
|
||||
|
||||
@Relation(parentColumn = "message_id", entityColumn = "message_id")
|
||||
val attachments: List<MessageAttachment>
|
||||
)
|
@ -16,8 +16,19 @@ data class Note(
|
||||
|
||||
val teacher: String,
|
||||
|
||||
@ColumnInfo(name = "teacher_symbol")
|
||||
val teacherSymbol: String,
|
||||
|
||||
val category: String,
|
||||
|
||||
@ColumnInfo(name = "category_type")
|
||||
val categoryType: Int,
|
||||
|
||||
@ColumnInfo(name = "is_points_show")
|
||||
val isPointsShow: Boolean,
|
||||
|
||||
val points: Int,
|
||||
|
||||
val content: String
|
||||
) : Serializable {
|
||||
|
||||
|
@ -0,0 +1,14 @@
|
||||
package io.github.wulkanowy.data.db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
class Migration23 : Migration(22, 23) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE Notes ADD COLUMN teacher_symbol TEXT NOT NULL DEFAULT ''")
|
||||
database.execSQL("ALTER TABLE Notes ADD COLUMN category_type INTEGER NOT NULL DEFAULT 0")
|
||||
database.execSQL("ALTER TABLE Notes ADD COLUMN is_points_show INTEGER NOT NULL DEFAULT 0")
|
||||
database.execSQL("ALTER TABLE Notes ADD COLUMN points INTEGER NOT NULL DEFAULT 0")
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package io.github.wulkanowy.data.db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
class Migration24 : Migration(23, 24) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE Messages ADD COLUMN has_attachments INTEGER NOT NULL DEFAULT 0")
|
||||
database.execSQL("""
|
||||
CREATE TABLE IF NOT EXISTS MessageAttachments (
|
||||
real_id INTEGER NOT NULL,
|
||||
message_id INTEGER NOT NULL,
|
||||
one_drive_id TEXT NOT NULL,
|
||||
url TEXT NOT NULL,
|
||||
filename TEXT NOT NULL,
|
||||
PRIMARY KEY(real_id)
|
||||
)
|
||||
""")
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package io.github.wulkanowy.data.db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
class Migration25 : Migration(24, 25) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE Homework ADD COLUMN is_done INTEGER NOT NULL DEFAULT 0")
|
||||
database.execSQL("ALTER TABLE Homework ADD COLUMN attachments TEXT NOT NULL DEFAULT \"[]\"")
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
package io.github.wulkanowy.data.pojos
|
||||
|
||||
class AppCreator(val displayName: String, val githubUsername: String)
|
@ -0,0 +1,3 @@
|
||||
package io.github.wulkanowy.data.pojos
|
||||
|
||||
class Contributor(val displayName: String, val githubUsername: String)
|
@ -2,18 +2,18 @@ package io.github.wulkanowy.data.repositories.appcreator
|
||||
|
||||
import android.content.res.AssetManager
|
||||
import com.google.gson.Gson
|
||||
import io.github.wulkanowy.data.pojos.AppCreator
|
||||
import io.github.wulkanowy.data.pojos.Contributor
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class AppCreatorRepository @Inject constructor(private val assets: AssetManager) {
|
||||
fun getAppCreators(): Single<List<AppCreator>> {
|
||||
return Single.fromCallable<List<AppCreator>> {
|
||||
fun getAppCreators(): Single<List<Contributor>> {
|
||||
return Single.fromCallable<List<Contributor>> {
|
||||
Gson().fromJson(
|
||||
assets.open("contributors.json").bufferedReader().use { it.readText() },
|
||||
Array<AppCreator>::class.java
|
||||
Array<Contributor>::class.java
|
||||
).toList()
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,10 @@ package io.github.wulkanowy.data.repositories.attendance
|
||||
|
||||
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.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
|
||||
@ -14,8 +16,9 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
class AttendanceRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Attendance>> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getAttendance(startDate, endDate, semester.semesterId)
|
||||
fun getAttendance(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Attendance>> {
|
||||
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getAttendance(startDate, endDate, semester.semesterId)
|
||||
.map { attendance ->
|
||||
attendance.map {
|
||||
Attendance(
|
||||
@ -39,8 +42,8 @@ class AttendanceRemote @Inject constructor(private val sdk: Sdk) {
|
||||
}
|
||||
}
|
||||
|
||||
fun excuseAbsence(semester: Semester, absenceList: List<Attendance>, reason: String?): Single<Boolean> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).excuseForAbsence(absenceList.map { attendance ->
|
||||
fun excuseAbsence(student: Student, semester: Semester, absenceList: List<Attendance>, reason: String?): Single<Boolean> {
|
||||
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).excuseForAbsence(absenceList.map { attendance ->
|
||||
Absent(
|
||||
date = LocalDateTime.of(attendance.date, LocalTime.of(0, 0)),
|
||||
timeId = attendance.timeId
|
||||
|
@ -4,6 +4,7 @@ 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.friday
|
||||
import io.github.wulkanowy.utils.monday
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
@ -20,29 +21,25 @@ class AttendanceRepository @Inject constructor(
|
||||
private val remote: AttendanceRemote
|
||||
) {
|
||||
|
||||
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean)
|
||||
: Single<List<Attendance>> {
|
||||
return Single.fromCallable { startDate.monday to endDate.friday }
|
||||
.flatMap { dates ->
|
||||
local.getAttendance(semester, dates.first, dates.second).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
|
||||
if (it) remote.getAttendance(semester, dates.first, dates.second)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { newAttendance ->
|
||||
local.getAttendance(semester, dates.first, dates.second)
|
||||
.toSingle(emptyList())
|
||||
.doOnSuccess { oldAttendance ->
|
||||
local.deleteAttendance(oldAttendance.uniqueSubtract(newAttendance))
|
||||
local.saveAttendance(newAttendance.uniqueSubtract(oldAttendance))
|
||||
}
|
||||
}.flatMap {
|
||||
local.getAttendance(semester, dates.first, dates.second)
|
||||
.toSingle(emptyList())
|
||||
}).map { list -> list.filter { it.date in startDate..endDate } }
|
||||
}
|
||||
fun getAttendance(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean): Single<List<Attendance>> {
|
||||
return local.getAttendance(semester, start.monday, end.friday).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
|
||||
if (it) remote.getAttendance(student, semester, start.monday, end.friday)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { newAttendance ->
|
||||
local.getAttendance(semester, start.monday, end.friday)
|
||||
.toSingle(emptyList())
|
||||
.doOnSuccess { oldAttendance ->
|
||||
local.deleteAttendance(oldAttendance.uniqueSubtract(newAttendance))
|
||||
local.saveAttendance(newAttendance.uniqueSubtract(oldAttendance))
|
||||
}
|
||||
}.flatMap {
|
||||
local.getAttendance(semester, start.monday, end.friday)
|
||||
.toSingle(emptyList())
|
||||
}).map { list -> list.filter { it.date in start..end } }
|
||||
}
|
||||
|
||||
fun excuseForAbsence(semester: Semester, attendanceList: List<Attendance>, reason: String? = null): Single<Boolean> {
|
||||
return remote.excuseAbsence(semester, attendanceList, reason)
|
||||
fun excuseForAbsence(student: Student, semester: Semester, attendanceList: List<Attendance>, reason: String? = null): Single<Boolean> {
|
||||
return remote.excuseAbsence(student, semester, attendanceList, reason)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.attendancesummary
|
||||
|
||||
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.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -10,8 +12,9 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
class AttendanceSummaryRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getAttendanceSummary(semester: Semester, subjectId: Int): Single<List<AttendanceSummary>> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getAttendanceSummary(subjectId)
|
||||
fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int): Single<List<AttendanceSummary>> {
|
||||
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getAttendanceSummary(subjectId)
|
||||
.map { attendance ->
|
||||
attendance.map {
|
||||
AttendanceSummary(
|
||||
|
@ -4,6 +4,7 @@ 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.uniqueSubtract
|
||||
import io.reactivex.Single
|
||||
import java.net.UnknownHostException
|
||||
@ -17,11 +18,11 @@ class AttendanceSummaryRepository @Inject constructor(
|
||||
private val remote: AttendanceSummaryRemote
|
||||
) {
|
||||
|
||||
fun getAttendanceSummary(semester: Semester, subjectId: Int, forceRefresh: Boolean = false): Single<List<AttendanceSummary>> {
|
||||
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(semester, subjectId)
|
||||
if (it) remote.getAttendanceSummary(student, semester, subjectId)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getAttendanceSummary(semester, subjectId).toSingle(emptyList())
|
||||
|
@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.completedlessons
|
||||
|
||||
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.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.reactivex.Single
|
||||
import org.threeten.bp.LocalDate
|
||||
import javax.inject.Inject
|
||||
@ -11,8 +13,9 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
class CompletedLessonsRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getCompletedLessons(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<CompletedLesson>> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getCompletedLessons(startDate, endDate)
|
||||
fun getCompletedLessons(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<CompletedLesson>> {
|
||||
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getCompletedLessons(startDate, endDate)
|
||||
.map { lessons ->
|
||||
lessons.map {
|
||||
it.absence
|
||||
|
@ -4,6 +4,7 @@ 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.friday
|
||||
import io.github.wulkanowy.utils.monday
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
@ -20,25 +21,22 @@ class CompletedLessonsRepository @Inject constructor(
|
||||
private val remote: CompletedLessonsRemote
|
||||
) {
|
||||
|
||||
fun getCompletedLessons(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false): Single<List<CompletedLesson>> {
|
||||
return Single.fromCallable { startDate.monday to endDate.friday }
|
||||
.flatMap { dates ->
|
||||
local.getCompletedLessons(semester, dates.first, dates.second).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getCompletedLessons(semester, dates.first, dates.second)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getCompletedLessons(semester, dates.first, dates.second)
|
||||
.toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteCompleteLessons(old.uniqueSubtract(new))
|
||||
local.saveCompletedLessons(new.uniqueSubtract(old))
|
||||
}
|
||||
}.flatMap {
|
||||
local.getCompletedLessons(semester, dates.first, dates.second)
|
||||
.toSingle(emptyList())
|
||||
}).map { list -> list.filter { it.date in startDate..endDate } }
|
||||
}
|
||||
fun getCompletedLessons(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single<List<CompletedLesson>> {
|
||||
return local.getCompletedLessons(semester, start.monday, end.friday).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getCompletedLessons(student, semester, start.monday, end.friday)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getCompletedLessons(semester, start.monday, end.friday)
|
||||
.toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteCompleteLessons(old.uniqueSubtract(new))
|
||||
local.saveCompletedLessons(new.uniqueSubtract(old))
|
||||
}
|
||||
}.flatMap {
|
||||
local.getCompletedLessons(semester, start.monday, end.friday)
|
||||
.toSingle(emptyList())
|
||||
}).map { list -> list.filter { it.date in start..end } }
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.exam
|
||||
|
||||
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.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.reactivex.Single
|
||||
import org.threeten.bp.LocalDate
|
||||
import javax.inject.Inject
|
||||
@ -11,8 +13,9 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
class ExamRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Exam>> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getExams(startDate, endDate, semester.semesterId)
|
||||
fun getExams(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Exam>> {
|
||||
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getExams(startDate, endDate, semester.semesterId)
|
||||
.map { exams ->
|
||||
exams.map {
|
||||
Exam(
|
||||
|
@ -4,6 +4,7 @@ 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.friday
|
||||
import io.github.wulkanowy.utils.monday
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
@ -20,25 +21,22 @@ class ExamRepository @Inject constructor(
|
||||
private val remote: ExamRemote
|
||||
) {
|
||||
|
||||
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false): Single<List<Exam>> {
|
||||
return Single.fromCallable { startDate.monday to endDate.friday }
|
||||
.flatMap { dates ->
|
||||
local.getExams(semester, dates.first, dates.second).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getExams(semester, dates.first, dates.second)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getExams(semester, dates.first, dates.second)
|
||||
.toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteExams(old.uniqueSubtract(new))
|
||||
local.saveExams(new.uniqueSubtract(old))
|
||||
}
|
||||
}.flatMap {
|
||||
local.getExams(semester, dates.first, dates.second)
|
||||
.toSingle(emptyList())
|
||||
}).map { list -> list.filter { it.date in startDate..endDate } }
|
||||
}
|
||||
fun getExams(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single<List<Exam>> {
|
||||
return local.getExams(semester, start.monday, end.friday).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getExams(student, semester, start.monday, end.friday)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getExams(semester, start.monday, end.friday)
|
||||
.toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteExams(old.uniqueSubtract(new))
|
||||
local.saveExams(new.uniqueSubtract(old))
|
||||
}
|
||||
}.flatMap {
|
||||
local.getExams(semester, start.monday, end.friday)
|
||||
.toSingle(emptyList())
|
||||
}).map { list -> list.filter { it.date in start..end } }
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,19 @@
|
||||
package io.github.wulkanowy.data.repositories.grade
|
||||
|
||||
import io.github.wulkanowy.data.db.dao.GradeDao
|
||||
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 javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class GradeLocal @Inject constructor(private val gradeDb: GradeDao) {
|
||||
class GradeLocal @Inject constructor(
|
||||
private val gradeDb: GradeDao,
|
||||
private val gradeSummaryDb: GradeSummaryDao
|
||||
) {
|
||||
|
||||
fun saveGrades(grades: List<Grade>) {
|
||||
gradeDb.insertAll(grades)
|
||||
@ -22,7 +27,19 @@ class GradeLocal @Inject constructor(private val gradeDb: GradeDao) {
|
||||
gradeDb.updateAll(grades)
|
||||
}
|
||||
|
||||
fun getGrades(semester: Semester): Maybe<List<Grade>> {
|
||||
fun getGradesDetails(semester: Semester): Maybe<List<Grade>> {
|
||||
return gradeDb.loadAll(semester.semesterId, semester.studentId).filter { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
fun saveGradesSummary(gradesSummary: List<GradeSummary>) {
|
||||
gradeSummaryDb.insertAll(gradesSummary)
|
||||
}
|
||||
|
||||
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() }
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
package io.github.wulkanowy.data.repositories.grade
|
||||
|
||||
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.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -10,10 +13,11 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
class GradeRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getGrades(semester: Semester): Single<List<Grade>> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getGrades(semester.semesterId)
|
||||
.map { grades ->
|
||||
grades.map {
|
||||
fun getGrades(student: Student, semester: Semester): Single<Pair<List<Grade>, List<GradeSummary>>> {
|
||||
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getGrades(semester.semesterId)
|
||||
.map { (details, summary) ->
|
||||
details.map {
|
||||
Grade(
|
||||
studentId = semester.studentId,
|
||||
semesterId = semester.semesterId,
|
||||
@ -30,6 +34,19 @@ class GradeRemote @Inject constructor(private val sdk: Sdk) {
|
||||
date = it.date,
|
||||
teacher = it.teacher
|
||||
)
|
||||
} to summary.map {
|
||||
GradeSummary(
|
||||
semesterId = semester.semesterId,
|
||||
studentId = semester.studentId,
|
||||
position = 0,
|
||||
subject = it.name,
|
||||
predictedGrade = it.predicted,
|
||||
finalGrade = it.final,
|
||||
pointsSum = it.pointsSum,
|
||||
proposedPoints = it.proposedPoints,
|
||||
finalPoints = it.finalPoints,
|
||||
average = it.average
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ 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.uniqueSubtract
|
||||
@ -19,34 +20,47 @@ class GradeRepository @Inject constructor(
|
||||
private val remote: GradeRemote
|
||||
) {
|
||||
|
||||
fun getGrades(student: Student, semester: Semester, forceRefresh: Boolean = false, notify: Boolean = false): Single<List<Grade>> {
|
||||
return local.getGrades(semester).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getGrades(semester)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getGrades(semester).toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
val notifyBreakDate = old.maxBy { it.date }?.date ?: student.registrationDate.toLocalDate()
|
||||
local.deleteGrades(old.uniqueSubtract(new))
|
||||
local.saveGrades(new.uniqueSubtract(old)
|
||||
.onEach {
|
||||
if (it.date >= notifyBreakDate) it.apply {
|
||||
isRead = false
|
||||
if (notify) isNotified = false
|
||||
}
|
||||
})
|
||||
}
|
||||
}.flatMap { local.getGrades(semester).toSingle(emptyList()) })
|
||||
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 {
|
||||
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))
|
||||
}
|
||||
}
|
||||
}.flatMap {
|
||||
local.getGradesDetails(semester).toSingle(emptyList()).flatMap { details ->
|
||||
local.getGradesSummary(semester).toSingle(emptyList()).map { summary ->
|
||||
details to summary
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun getUnreadGrades(semester: Semester): Single<List<Grade>> {
|
||||
return local.getGrades(semester).map { it.filter { grade -> !grade.isRead } }.toSingle(emptyList())
|
||||
return local.getGradesDetails(semester).map { it.filter { grade -> !grade.isRead } }.toSingle(emptyList())
|
||||
}
|
||||
|
||||
fun getNotNotifiedGrades(semester: Semester): Single<List<Grade>> {
|
||||
return local.getGrades(semester).map { it.filter { grade -> !grade.isNotified } }.toSingle(emptyList())
|
||||
return local.getGradesDetails(semester).map { it.filter { grade -> !grade.isNotified } }.toSingle(emptyList())
|
||||
}
|
||||
|
||||
fun updateGrade(grade: Grade): Completable {
|
||||
|
@ -1,24 +0,0 @@
|
||||
package io.github.wulkanowy.data.repositories.gradessummary
|
||||
|
||||
import io.github.wulkanowy.data.db.dao.GradeSummaryDao
|
||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class GradeSummaryLocal @Inject constructor(private val gradeSummaryDb: GradeSummaryDao) {
|
||||
|
||||
fun saveGradesSummary(gradesSummary: List<GradeSummary>) {
|
||||
gradeSummaryDb.insertAll(gradesSummary)
|
||||
}
|
||||
|
||||
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() }
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package io.github.wulkanowy.data.repositories.gradessummary
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class GradeSummaryRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getGradeSummary(semester: Semester): Single<List<GradeSummary>> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getGradesSummary(semester.semesterId)
|
||||
.map { gradesSummary ->
|
||||
gradesSummary.map {
|
||||
GradeSummary(
|
||||
semesterId = semester.semesterId,
|
||||
studentId = semester.studentId,
|
||||
position = 0,
|
||||
subject = it.name,
|
||||
predictedGrade = it.predicted,
|
||||
finalGrade = it.final,
|
||||
pointsSum = it.pointsSum,
|
||||
proposedPoints = it.proposedPoints,
|
||||
finalPoints = it.finalPoints,
|
||||
average = it.average
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
package io.github.wulkanowy.data.repositories.gradessummary
|
||||
|
||||
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.GradeSummary
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import io.reactivex.Single
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class GradeSummaryRepository @Inject constructor(
|
||||
private val settings: InternetObservingSettings,
|
||||
private val local: GradeSummaryLocal,
|
||||
private val remote: GradeSummaryRemote
|
||||
) {
|
||||
|
||||
fun getGradesSummary(semester: Semester, forceRefresh: Boolean = false): Single<List<GradeSummary>> {
|
||||
return local.getGradesSummary(semester).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getGradeSummary(semester)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getGradesSummary(semester).toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteGradesSummary(old.uniqueSubtract(new))
|
||||
local.saveGradesSummary(new.uniqueSubtract(old))
|
||||
}
|
||||
}.flatMap { local.getGradesSummary(semester).toSingle(emptyList()) })
|
||||
}
|
||||
}
|
@ -3,7 +3,9 @@ package io.github.wulkanowy.data.repositories.gradestatistics
|
||||
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.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -11,8 +13,8 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
class GradeStatisticsRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getGradeStatistics(semester: Semester, isSemester: Boolean): Single<List<GradeStatistics>> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).let {
|
||||
fun getGradeStatistics(student: Student, semester: Semester, isSemester: Boolean): Single<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 ->
|
||||
@ -29,8 +31,9 @@ class GradeStatisticsRemote @Inject constructor(private val sdk: Sdk) {
|
||||
}
|
||||
}
|
||||
|
||||
fun getGradePointsStatistics(semester: Semester): Single<List<GradePointsStatistics>> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getGradesPointsStatistics(semester.semesterId)
|
||||
fun getGradePointsStatistics(student: Student, semester: Semester): Single<List<GradePointsStatistics>> {
|
||||
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getGradesPointsStatistics(semester.semesterId)
|
||||
.map { gradePointsStatistics ->
|
||||
gradePointsStatistics.map {
|
||||
GradePointsStatistics(
|
||||
|
@ -5,6 +5,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.Inter
|
||||
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.uniqueSubtract
|
||||
@ -20,11 +21,11 @@ class GradeStatisticsRepository @Inject constructor(
|
||||
private val remote: GradeStatisticsRemote
|
||||
) {
|
||||
|
||||
fun getGradesStatistics(semester: Semester, subjectName: String, isSemester: Boolean, forceRefresh: Boolean = false): Single<List<GradeStatisticsItem>> {
|
||||
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(semester, isSemester)
|
||||
if (it) remote.getGradeStatistics(student, semester, isSemester)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getGradesStatistics(semester, isSemester).toSingle(emptyList())
|
||||
@ -35,11 +36,11 @@ class GradeStatisticsRepository @Inject constructor(
|
||||
}.flatMap { local.getGradesStatistics(semester, isSemester, subjectName).map { it.mapToStatisticItems() }.toSingle(emptyList()) })
|
||||
}
|
||||
|
||||
fun getGradesPointsStatistics(semester: Semester, subjectName: String, forceRefresh: Boolean): Single<List<GradeStatisticsItem>> {
|
||||
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(semester)
|
||||
if (it) remote.getGradePointsStatistics(student, semester)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getGradesPointsStatistics(semester).toSingle(emptyList())
|
||||
|
@ -19,6 +19,10 @@ class HomeworkLocal @Inject constructor(private val homeworkDb: HomeworkDao) {
|
||||
homeworkDb.deleteAll(homework)
|
||||
}
|
||||
|
||||
fun updateHomework(homework: List<Homework>) {
|
||||
homeworkDb.updateAll(homework)
|
||||
}
|
||||
|
||||
fun getHomework(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Homework>> {
|
||||
return homeworkDb.loadAll(semester.semesterId, semester.studentId, startDate, endDate)
|
||||
.filter { it.isNotEmpty() }
|
||||
|
@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.homework
|
||||
|
||||
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.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.reactivex.Single
|
||||
import org.threeten.bp.LocalDate
|
||||
import javax.inject.Inject
|
||||
@ -11,8 +13,9 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
class HomeworkRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getHomework(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Homework>> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getHomework(startDate, endDate)
|
||||
fun getHomework(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Homework>> {
|
||||
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getHomework(startDate, endDate)
|
||||
.map { homework ->
|
||||
homework.map {
|
||||
Homework(
|
||||
@ -23,7 +26,8 @@ class HomeworkRemote @Inject constructor(private val sdk: Sdk) {
|
||||
subject = it.subject,
|
||||
content = it.content,
|
||||
teacher = it.teacher,
|
||||
teacherSymbol = it.teacherSymbol
|
||||
teacherSymbol = it.teacherSymbol,
|
||||
attachments = it.attachments.map { attachment -> attachment.url to attachment.name }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,11 @@ 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.friday
|
||||
import io.github.wulkanowy.utils.monday
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
import org.threeten.bp.LocalDate
|
||||
import java.net.UnknownHostException
|
||||
@ -20,12 +22,12 @@ class HomeworkRepository @Inject constructor(
|
||||
private val remote: HomeworkRemote
|
||||
) {
|
||||
|
||||
fun getHomework(semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single<List<Homework>> {
|
||||
fun getHomework(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single<List<Homework>> {
|
||||
return Single.fromCallable { start.monday to end.friday }.flatMap { (monday, friday) ->
|
||||
local.getHomework(semester, monday, friday).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getHomework(semester, monday, friday)
|
||||
if (it) remote.getHomework(student, semester, monday, friday)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getHomework(semester, monday, friday).toSingle(emptyList())
|
||||
@ -36,4 +38,12 @@ class HomeworkRepository @Inject constructor(
|
||||
}.flatMap { local.getHomework(semester, monday, friday).toSingle(emptyList()) })
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleDone(homework: Homework): Completable {
|
||||
return Completable.fromCallable {
|
||||
local.updateHomework(listOf(homework.apply {
|
||||
isDone = !isDone
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.luckynumber
|
||||
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 javax.inject.Inject
|
||||
@ -12,7 +13,7 @@ import javax.inject.Singleton
|
||||
class LuckyNumberRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getLuckyNumber(student: Student): Maybe<LuckyNumber> {
|
||||
return sdk.getLuckyNumber(student.schoolShortName).map {
|
||||
return sdk.init(student).getLuckyNumber(student.schoolShortName).map {
|
||||
LuckyNumber(
|
||||
studentId = student.studentId,
|
||||
date = LocalDate.now(),
|
||||
|
@ -1,7 +1,10 @@
|
||||
package io.github.wulkanowy.data.repositories.message
|
||||
|
||||
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.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
|
||||
@ -10,7 +13,10 @@ import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class MessageLocal @Inject constructor(private val messagesDb: MessagesDao) {
|
||||
class MessageLocal @Inject constructor(
|
||||
private val messagesDb: MessagesDao,
|
||||
private val messageAttachmentDao: MessageAttachmentDao
|
||||
) {
|
||||
|
||||
fun saveMessages(messages: List<Message>) {
|
||||
messagesDb.insertAll(messages)
|
||||
@ -24,8 +30,12 @@ class MessageLocal @Inject constructor(private val messagesDb: MessagesDao) {
|
||||
messagesDb.deleteAll(messages)
|
||||
}
|
||||
|
||||
fun getMessage(id: Long): Single<Message> {
|
||||
return messagesDb.load(id)
|
||||
fun getMessageWithAttachment(student: Student, message: Message): Single<MessageWithAttachment> {
|
||||
return messagesDb.loadMessageWithAttachment(student.id.toInt(), message.messageId)
|
||||
}
|
||||
|
||||
fun saveMessageAttachments(attachments: List<MessageAttachment>) {
|
||||
messageAttachmentDao.insertAttachments(attachments)
|
||||
}
|
||||
|
||||
fun getMessages(student: Student, folder: MessageFolder): Maybe<List<Message>> {
|
||||
|
@ -1,12 +1,14 @@
|
||||
package io.github.wulkanowy.data.repositories.message
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.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 javax.inject.Inject
|
||||
@ -17,7 +19,7 @@ import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
|
||||
class MessageRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getMessages(student: Student, semester: Semester, folder: MessageFolder): Single<List<Message>> {
|
||||
return sdk.getMessages(Folder.valueOf(folder.name), semester.start.atStartOfDay(), semester.end.atStartOfDay()).map { messages ->
|
||||
return sdk.init(student).getMessages(Folder.valueOf(folder.name), semester.start.atStartOfDay(), semester.end.atStartOfDay()).map { messages ->
|
||||
messages.map {
|
||||
Message(
|
||||
studentId = student.id.toInt(),
|
||||
@ -33,18 +35,29 @@ class MessageRemote @Inject constructor(private val sdk: Sdk) {
|
||||
unread = it.unread ?: false,
|
||||
unreadBy = it.unreadBy ?: 0,
|
||||
readBy = it.readBy ?: 0,
|
||||
removed = it.removed
|
||||
removed = it.removed,
|
||||
hasAttachments = it.hasAttachments
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getMessagesContent(message: Message, markAsRead: Boolean = false): Single<String> {
|
||||
return sdk.getMessageContent(message.messageId, message.folderId, markAsRead, message.realId)
|
||||
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 ->
|
||||
details.content to details.attachments.map {
|
||||
MessageAttachment(
|
||||
realId = it.id,
|
||||
messageId = it.messageId,
|
||||
oneDriveId = it.oneDriveId,
|
||||
url = it.url,
|
||||
filename = it.filename
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun sendMessage(subject: String, content: String, recipients: List<Recipient>): Single<SentMessage> {
|
||||
return sdk.sendMessage(
|
||||
fun sendMessage(student: Student, subject: String, content: String, recipients: List<Recipient>): Single<SentMessage> {
|
||||
return sdk.init(student).sendMessage(
|
||||
subject = subject,
|
||||
content = content,
|
||||
recipients = recipients.map {
|
||||
@ -61,7 +74,7 @@ class MessageRemote @Inject constructor(private val sdk: Sdk) {
|
||||
)
|
||||
}
|
||||
|
||||
fun deleteMessage(message: Message): Single<Boolean> {
|
||||
return sdk.deleteMessages(listOf(Pair(message.realId, message.folderId)))
|
||||
fun deleteMessage(student: Student, message: Message): Single<Boolean> {
|
||||
return sdk.init(student).deleteMessages(listOf(Pair(message.realId, message.folderId)))
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ package io.github.wulkanowy.data.repositories.message
|
||||
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||
import io.github.wulkanowy.data.SdkHelper
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
@ -11,7 +11,6 @@ import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED
|
||||
import io.github.wulkanowy.sdk.pojo.SentMessage
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
import timber.log.Timber
|
||||
import java.net.UnknownHostException
|
||||
@ -22,59 +21,53 @@ import javax.inject.Singleton
|
||||
class MessageRepository @Inject constructor(
|
||||
private val settings: InternetObservingSettings,
|
||||
private val local: MessageLocal,
|
||||
private val remote: MessageRemote,
|
||||
private val sdkHelper: SdkHelper
|
||||
private val remote: MessageRemote
|
||||
) {
|
||||
|
||||
fun getMessages(student: Student, semester: Semester, folder: MessageFolder, forceRefresh: Boolean = false, notify: Boolean = false): Single<List<Message>> {
|
||||
return Single.just(sdkHelper.init(student))
|
||||
.flatMap { _ ->
|
||||
local.getMessages(student, folder).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getMessages(student, semester, folder)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getMessages(student, folder).toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteMessages(old.uniqueSubtract(new))
|
||||
local.saveMessages(new.uniqueSubtract(old)
|
||||
.onEach {
|
||||
it.isNotified = !notify
|
||||
})
|
||||
}
|
||||
}.flatMap { local.getMessages(student, folder).toSingle(emptyList()) }
|
||||
)
|
||||
}
|
||||
return local.getMessages(student, folder).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getMessages(student, semester, folder)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getMessages(student, folder).toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteMessages(old.uniqueSubtract(new))
|
||||
local.saveMessages(new.uniqueSubtract(old)
|
||||
.onEach {
|
||||
it.isNotified = !notify
|
||||
})
|
||||
}
|
||||
}.flatMap { local.getMessages(student, folder).toSingle(emptyList()) }
|
||||
)
|
||||
}
|
||||
|
||||
fun getMessage(student: Student, messageDbId: Long, markAsRead: Boolean = false): Single<Message> {
|
||||
return Single.just(sdkHelper.init(student))
|
||||
.flatMap { _ ->
|
||||
local.getMessage(messageDbId)
|
||||
.filter {
|
||||
it.content.isNotEmpty().also { status ->
|
||||
Timber.d("Message content in db empty: ${!status}")
|
||||
}
|
||||
}
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) local.getMessage(messageDbId)
|
||||
else Single.error(UnknownHostException())
|
||||
}
|
||||
.flatMap { dbMessage ->
|
||||
remote.getMessagesContent(dbMessage, markAsRead).doOnSuccess {
|
||||
local.updateMessages(listOf(dbMessage.copy(unread = !markAsRead).apply {
|
||||
id = dbMessage.id
|
||||
content = content.ifBlank { it }
|
||||
}))
|
||||
Timber.d("Message $messageDbId with blank content: ${dbMessage.content.isBlank()}, marked as read")
|
||||
}
|
||||
}.flatMap {
|
||||
local.getMessage(messageDbId)
|
||||
}
|
||||
)
|
||||
fun getMessage(student: Student, message: Message, markAsRead: Boolean = false): Single<MessageWithAttachment> {
|
||||
return local.getMessageWithAttachment(student, message)
|
||||
.filter {
|
||||
it.message.content.isNotEmpty().also { status ->
|
||||
Timber.d("Message content in db empty: ${!status}")
|
||||
} && !it.message.unread
|
||||
}
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) local.getMessageWithAttachment(student, message)
|
||||
else Single.error(UnknownHostException())
|
||||
}
|
||||
.flatMap { dbMessage ->
|
||||
remote.getMessagesContentDetails(student, dbMessage.message, markAsRead).doOnSuccess { (downloadedMessage, attachments) ->
|
||||
local.updateMessages(listOf(dbMessage.message.copy(unread = !markAsRead).apply {
|
||||
id = dbMessage.message.id
|
||||
content = content.ifBlank { downloadedMessage }
|
||||
}))
|
||||
local.saveMessageAttachments(attachments)
|
||||
Timber.d("Message ${message.messageId} with blank content: ${dbMessage.message.content.isBlank()}, marked as read")
|
||||
}
|
||||
}.flatMap {
|
||||
local.getMessageWithAttachment(student, message)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun getNotNotifiedMessages(student: Student): Single<List<Message>> {
|
||||
@ -83,29 +76,24 @@ class MessageRepository @Inject constructor(
|
||||
.toSingle(emptyList())
|
||||
}
|
||||
|
||||
fun updateMessage(message: Message): Completable {
|
||||
return Completable.fromCallable { local.updateMessages(listOf(message)) }
|
||||
}
|
||||
|
||||
fun updateMessages(messages: List<Message>): Completable {
|
||||
return Completable.fromCallable { local.updateMessages(messages) }
|
||||
}
|
||||
|
||||
fun sendMessage(subject: String, content: String, recipients: List<Recipient>): Single<SentMessage> {
|
||||
fun sendMessage(student: Student, subject: String, content: String, recipients: List<Recipient>): Single<SentMessage> {
|
||||
return ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.sendMessage(subject, content, recipients)
|
||||
if (it) remote.sendMessage(student, subject, content, recipients)
|
||||
else Single.error(UnknownHostException())
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteMessage(message: Message): Maybe<Boolean> {
|
||||
fun deleteMessage(student: Student, message: Message): Single<Boolean> {
|
||||
return ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.deleteMessage(message)
|
||||
if (it) remote.deleteMessage(student, message)
|
||||
else Single.error(UnknownHostException())
|
||||
}
|
||||
.filter { it }
|
||||
.doOnSuccess {
|
||||
if (!message.removed) local.updateMessages(listOf(message.copy(removed = true).apply {
|
||||
id = message.id
|
||||
|
@ -2,8 +2,10 @@ package io.github.wulkanowy.data.repositories.mobiledevice
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.MobileDevice
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.pojos.MobileDeviceToken
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -11,13 +13,14 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
class MobileDeviceRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getDevices(semester: Semester): Single<List<MobileDevice>> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getRegisteredDevices()
|
||||
fun getDevices(student: Student, semester: Semester): Single<List<MobileDevice>> {
|
||||
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getRegisteredDevices()
|
||||
.map { devices ->
|
||||
devices.map {
|
||||
MobileDevice(
|
||||
studentId = semester.studentId,
|
||||
date = it.date,
|
||||
date = it.createDate,
|
||||
deviceId = it.id,
|
||||
name = it.name
|
||||
)
|
||||
@ -25,12 +28,14 @@ class MobileDeviceRemote @Inject constructor(private val sdk: Sdk) {
|
||||
}
|
||||
}
|
||||
|
||||
fun unregisterDevice(semester: Semester, device: MobileDevice): Single<Boolean> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).unregisterDevice(device.deviceId)
|
||||
fun unregisterDevice(student: Student, semester: Semester, device: MobileDevice): Single<Boolean> {
|
||||
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.unregisterDevice(device.deviceId)
|
||||
}
|
||||
|
||||
fun getToken(semester: Semester): Single<MobileDeviceToken> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getToken()
|
||||
fun getToken(student: Student, semester: Semester): Single<MobileDeviceToken> {
|
||||
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getToken()
|
||||
.map {
|
||||
MobileDeviceToken(
|
||||
token = it.token,
|
||||
|
@ -4,6 +4,7 @@ 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.MobileDevice
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.pojos.MobileDeviceToken
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import io.reactivex.Single
|
||||
@ -18,11 +19,11 @@ class MobileDeviceRepository @Inject constructor(
|
||||
private val remote: MobileDeviceRemote
|
||||
) {
|
||||
|
||||
fun getDevices(semester: Semester, forceRefresh: Boolean = false): Single<List<MobileDevice>> {
|
||||
fun getDevices(student: Student, semester: Semester, forceRefresh: Boolean = false): Single<List<MobileDevice>> {
|
||||
return local.getDevices(semester).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getDevices(semester)
|
||||
if (it) remote.getDevices(student, semester)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getDevices(semester).toSingle(emptyList())
|
||||
@ -34,18 +35,18 @@ class MobileDeviceRepository @Inject constructor(
|
||||
).flatMap { local.getDevices(semester).toSingle(emptyList()) }
|
||||
}
|
||||
|
||||
fun unregisterDevice(semester: Semester, device: MobileDevice): Single<Boolean> {
|
||||
fun unregisterDevice(student: Student, semester: Semester, device: MobileDevice): Single<Boolean> {
|
||||
return ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.unregisterDevice(semester, device)
|
||||
if (it) remote.unregisterDevice(student, semester, device)
|
||||
else Single.error(UnknownHostException())
|
||||
}
|
||||
}
|
||||
|
||||
fun getToken(semester: Semester): Single<MobileDeviceToken> {
|
||||
fun getToken(student: Student, semester: Semester): Single<MobileDeviceToken> {
|
||||
return ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getToken(semester)
|
||||
if (it) remote.getToken(student, semester)
|
||||
else Single.error(UnknownHostException())
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.note
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Note
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -10,15 +12,20 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
class NoteRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getNotes(semester: Semester): Single<List<Note>> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getNotes(semester.semesterId)
|
||||
fun getNotes(student: Student, semester: Semester): Single<List<Note>> {
|
||||
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getNotes(semester.semesterId)
|
||||
.map { notes ->
|
||||
notes.map {
|
||||
Note(
|
||||
studentId = semester.studentId,
|
||||
date = it.date,
|
||||
teacher = it.teacher,
|
||||
teacherSymbol = it.teacherSymbol,
|
||||
category = it.category,
|
||||
categoryType = it.categoryType.id,
|
||||
isPointsShow = it.showPoints,
|
||||
points = it.points,
|
||||
content = it.content
|
||||
)
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ class NoteRepository @Inject constructor(
|
||||
return local.getNotes(student).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getNotes(semester)
|
||||
if (it) remote.getNotes(student, semester)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getNotes(student).toSingle(emptyList())
|
||||
|
@ -26,6 +26,9 @@ class PreferencesRepository @Inject constructor(
|
||||
val isGradeExpandable: Boolean
|
||||
get() = !getBoolean(R.string.pref_key_expand_grade, R.bool.pref_default_expand_grade)
|
||||
|
||||
val showAllSubjectsOnStatisticsList: Boolean
|
||||
get() = getBoolean(R.string.pref_key_grade_statistics_list, R.bool.pref_default_grade_statistics_list)
|
||||
|
||||
val appThemeKey = context.getString(R.string.pref_key_app_theme)
|
||||
val appTheme: String
|
||||
get() = getString(appThemeKey, R.string.pref_default_app_theme)
|
||||
@ -52,6 +55,10 @@ class PreferencesRepository @Inject constructor(
|
||||
val isNotificationsEnable: Boolean
|
||||
get() = getBoolean(R.string.pref_key_notifications_enable, R.bool.pref_default_notifications_enable)
|
||||
|
||||
val isUpcomingLessonsNotificationsEnableKey = context.getString(R.string.pref_key_notifications_upcoming_lessons_enable)
|
||||
val isUpcomingLessonsNotificationsEnable: Boolean
|
||||
get() = getBoolean(isUpcomingLessonsNotificationsEnableKey, R.bool.pref_default_notification_upcoming_lessons_enable)
|
||||
|
||||
val isDebugNotificationEnableKey = context.getString(R.string.pref_key_notification_debug)
|
||||
val isDebugNotificationEnable: Boolean
|
||||
get() = getBoolean(isDebugNotificationEnableKey, R.bool.pref_default_notification_debug)
|
||||
@ -68,6 +75,9 @@ class PreferencesRepository @Inject constructor(
|
||||
val showWholeClassPlan: String
|
||||
get() = getString(R.string.pref_key_timetable_show_whole_class, R.string.pref_default_timetable_show_whole_class)
|
||||
|
||||
val showTimetableTimers: Boolean
|
||||
get() = getBoolean(R.string.pref_key_timetable_show_timers, R.bool.pref_default_timetable_show_timers)
|
||||
|
||||
private fun getString(id: Int, default: Int) = getString(context.getString(id), default)
|
||||
|
||||
private fun getString(id: String, default: Int) = sharedPref.getString(id, context.getString(default)) ?: context.getString(default)
|
||||
|
@ -3,7 +3,9 @@ package io.github.wulkanowy.data.repositories.recipient
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
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 io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -12,15 +14,15 @@ import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
|
||||
@Singleton
|
||||
class RecipientRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getRecipients(role: Int, unit: ReportingUnit): Single<List<Recipient>> {
|
||||
return sdk.getRecipients(unit.realId, role)
|
||||
fun getRecipients(student: Student, role: Int, unit: ReportingUnit): Single<List<Recipient>> {
|
||||
return sdk.init(student).getRecipients(unit.realId, role)
|
||||
.map { recipients ->
|
||||
recipients.map { it.toRecipient() }
|
||||
}
|
||||
}
|
||||
|
||||
fun getMessageRecipients(message: Message): Single<List<Recipient>> {
|
||||
return sdk.getMessageRecipients(message.messageId, message.senderId)
|
||||
fun getMessageRecipients(student: Student, message: Message): Single<List<Recipient>> {
|
||||
return sdk.init(student).getMessageRecipients(message.messageId, message.senderId)
|
||||
.map { recipients ->
|
||||
recipients.map { it.toRecipient() }
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package io.github.wulkanowy.data.repositories.recipient
|
||||
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||
import io.github.wulkanowy.data.SdkHelper
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||
@ -17,36 +16,31 @@ import javax.inject.Singleton
|
||||
class RecipientRepository @Inject constructor(
|
||||
private val settings: InternetObservingSettings,
|
||||
private val local: RecipientLocal,
|
||||
private val remote: RecipientRemote,
|
||||
private val sdkHelper: SdkHelper
|
||||
private val remote: RecipientRemote
|
||||
) {
|
||||
|
||||
fun getRecipients(student: Student, role: Int, unit: ReportingUnit, forceRefresh: Boolean = false): Single<List<Recipient>> {
|
||||
return Single.just(sdkHelper.init(student))
|
||||
.flatMap { _ ->
|
||||
local.getRecipients(student, role, unit).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getRecipients(role, unit)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getRecipients(student, role, unit).toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteRecipients(old.uniqueSubtract(new))
|
||||
local.saveRecipients(new.uniqueSubtract(old))
|
||||
}
|
||||
}.flatMap {
|
||||
local.getRecipients(student, role, unit).toSingle(emptyList())
|
||||
return local.getRecipients(student, role, unit).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getRecipients(student, role, unit)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getRecipients(student, role, unit).toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteRecipients(old.uniqueSubtract(new))
|
||||
local.saveRecipients(new.uniqueSubtract(old))
|
||||
}
|
||||
)
|
||||
}
|
||||
}.flatMap {
|
||||
local.getRecipients(student, role, unit).toSingle(emptyList())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun getMessageRecipients(student: Student, message: Message): Single<List<Recipient>> {
|
||||
return Single.just(sdkHelper.init(student))
|
||||
.flatMap { ReactiveNetwork.checkInternetConnectivity(settings) }
|
||||
return ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getMessageRecipients(message)
|
||||
if (it) remote.getMessageRecipients(student, message)
|
||||
else Single.error(UnknownHostException())
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package io.github.wulkanowy.data.repositories.reportingunit
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||
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
|
||||
@ -9,8 +11,8 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
class ReportingUnitRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getReportingUnits(): Single<List<ReportingUnit>> {
|
||||
return sdk.getReportingUnits().map {
|
||||
fun getReportingUnits(student: Student): Single<List<ReportingUnit>> {
|
||||
return sdk.init(student).getReportingUnits().map {
|
||||
it.map { unit ->
|
||||
ReportingUnit(
|
||||
studentId = sdk.studentId,
|
||||
|
@ -2,7 +2,6 @@ package io.github.wulkanowy.data.repositories.reportingunit
|
||||
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||
import io.github.wulkanowy.data.SdkHelper
|
||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
@ -16,41 +15,34 @@ import javax.inject.Singleton
|
||||
class ReportingUnitRepository @Inject constructor(
|
||||
private val settings: InternetObservingSettings,
|
||||
private val local: ReportingUnitLocal,
|
||||
private val remote: ReportingUnitRemote,
|
||||
private val sdkHelper: SdkHelper
|
||||
private val remote: ReportingUnitRemote
|
||||
) {
|
||||
|
||||
fun getReportingUnits(student: Student, forceRefresh: Boolean = false): Single<List<ReportingUnit>> {
|
||||
return Single.just(sdkHelper.init(student))
|
||||
.flatMap { _ ->
|
||||
local.getReportingUnits(student).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getReportingUnits()
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getReportingUnits(student).toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteReportingUnits(old.uniqueSubtract(new))
|
||||
local.saveReportingUnits(new.uniqueSubtract(old))
|
||||
}
|
||||
}.flatMap { local.getReportingUnits(student).toSingle(emptyList()) }
|
||||
)
|
||||
}
|
||||
return local.getReportingUnits(student).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getReportingUnits(student)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getReportingUnits(student).toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteReportingUnits(old.uniqueSubtract(new))
|
||||
local.saveReportingUnits(new.uniqueSubtract(old))
|
||||
}
|
||||
}.flatMap { local.getReportingUnits(student).toSingle(emptyList()) }
|
||||
)
|
||||
}
|
||||
|
||||
fun getReportingUnit(student: Student, unitId: Int): Maybe<ReportingUnit> {
|
||||
return Maybe.just(sdkHelper.init(student))
|
||||
.flatMap { _ ->
|
||||
local.getReportingUnit(student, unitId)
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) getReportingUnits(student, true)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMapMaybe {
|
||||
local.getReportingUnit(student, unitId)
|
||||
}
|
||||
)
|
||||
}
|
||||
return local.getReportingUnit(student, unitId)
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) getReportingUnits(student, true)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMapMaybe {
|
||||
local.getReportingUnit(student, unitId)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -2,14 +2,17 @@ package io.github.wulkanowy.data.repositories.school
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.School
|
||||
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
|
||||
|
||||
class SchoolRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getSchoolInfo(semester: Semester): Single<School> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getSchool()
|
||||
fun getSchoolInfo(student: Student, semester: Semester): Single<School> {
|
||||
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getSchool()
|
||||
.map {
|
||||
School(
|
||||
studentId = semester.studentId,
|
||||
|
@ -4,6 +4,7 @@ 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.School
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
import java.net.UnknownHostException
|
||||
@ -17,11 +18,11 @@ class SchoolRepository @Inject constructor(
|
||||
private val remote: SchoolRemote
|
||||
) {
|
||||
|
||||
fun getSchoolInfo(semester: Semester, forceRefresh: Boolean = false): Maybe<School> {
|
||||
fun getSchoolInfo(student: Student, semester: Semester, forceRefresh: Boolean = false): Maybe<School> {
|
||||
return local.getSchool(semester).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getSchoolInfo(semester)
|
||||
if (it) remote.getSchoolInfo(student, semester)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMapMaybe { new ->
|
||||
local.getSchool(semester)
|
||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.semester
|
||||
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
|
||||
@ -11,7 +12,7 @@ import javax.inject.Singleton
|
||||
class SemesterRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getSemesters(student: Student): Single<List<Semester>> {
|
||||
return sdk.getSemesters().map { semesters ->
|
||||
return sdk.init(student).getSemesters().map { semesters ->
|
||||
semesters.map {
|
||||
Semester(
|
||||
studentId = student.studentId,
|
||||
|
@ -2,13 +2,12 @@ package io.github.wulkanowy.data.repositories.semester
|
||||
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||
import io.github.wulkanowy.data.SdkHelper
|
||||
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.getCurrentOrLast
|
||||
import io.github.wulkanowy.utils.isCurrent
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
@ -18,31 +17,28 @@ import javax.inject.Singleton
|
||||
class SemesterRepository @Inject constructor(
|
||||
private val remote: SemesterRemote,
|
||||
private val local: SemesterLocal,
|
||||
private val settings: InternetObservingSettings,
|
||||
private val sdkHelper: SdkHelper
|
||||
private val settings: InternetObservingSettings
|
||||
) {
|
||||
|
||||
fun getSemesters(student: Student, forceRefresh: Boolean = false, refreshOnNoCurrent: Boolean = false): Single<List<Semester>> {
|
||||
return Maybe.just(sdkHelper.init(student))
|
||||
.flatMap {
|
||||
local.getSemesters(student).filter { !forceRefresh }.filter {
|
||||
if (refreshOnNoCurrent) {
|
||||
it.any { semester -> semester.isCurrent }
|
||||
} else true
|
||||
}
|
||||
return local.getSemesters(student).filter { !forceRefresh }.filter { semesters ->
|
||||
when {
|
||||
Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API -> semesters.firstOrNull { it.isCurrent }?.diaryId != 0
|
||||
refreshOnNoCurrent -> semesters.any { semester -> semester.isCurrent }
|
||||
else -> true
|
||||
}
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getSemesters(student)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
if (new.isEmpty()) throw IllegalArgumentException("Empty semester list!")
|
||||
}.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getSemesters(student)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
if (new.isEmpty()) throw IllegalArgumentException("Empty semester list!")
|
||||
|
||||
local.getSemesters(student).toSingle(emptyList()).doOnSuccess { old ->
|
||||
local.deleteSemesters(old.uniqueSubtract(new))
|
||||
local.saveSemesters(new.uniqueSubtract(old))
|
||||
}
|
||||
}.flatMap { local.getSemesters(student).toSingle(emptyList()) })
|
||||
local.getSemesters(student).toSingle(emptyList()).doOnSuccess { old ->
|
||||
local.deleteSemesters(old.uniqueSubtract(new))
|
||||
local.saveSemesters(new.uniqueSubtract(old))
|
||||
}
|
||||
}.flatMap { local.getSemesters(student).toSingle(emptyList()) })
|
||||
}
|
||||
|
||||
fun getCurrentSemester(student: Student, forceRefresh: Boolean = false): Single<Semester> {
|
||||
|
@ -29,10 +29,18 @@ class StudentLocal @Inject constructor(
|
||||
|
||||
fun getStudents(decryptPass: Boolean): Maybe<List<Student>> {
|
||||
return studentDb.loadAll()
|
||||
.map { list -> list.map { it.apply { if (decryptPass) password = decrypt(password) } } }
|
||||
.map { list -> list.map { it.apply { if (decryptPass && Sdk.Mode.valueOf(loginMode) != Sdk.Mode.API) password = decrypt(password) } } }
|
||||
.filter { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
fun getStudentById(id: Int): Maybe<Student> {
|
||||
return studentDb.loadById(id).map {
|
||||
it.apply {
|
||||
if (Sdk.Mode.valueOf(loginMode) != Sdk.Mode.API) password = decrypt(password)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getCurrentStudent(decryptPass: Boolean): Maybe<Student> {
|
||||
return studentDb.loadCurrent().map {
|
||||
it.apply {
|
||||
|
@ -47,6 +47,12 @@ class StudentRepository @Inject constructor(
|
||||
return local.getStudents(decryptPass).toSingle(emptyList())
|
||||
}
|
||||
|
||||
fun getStudentById(id: Int): Single<Student> {
|
||||
return local.getStudentById(id)
|
||||
.switchIfEmpty(Maybe.error(NoCurrentStudentException()))
|
||||
.toSingle()
|
||||
}
|
||||
|
||||
fun getCurrentStudent(decryptPass: Boolean = true): Single<Student> {
|
||||
return local.getCurrentStudent(decryptPass)
|
||||
.switchIfEmpty(Maybe.error(NoCurrentStudentException()))
|
||||
|
@ -12,7 +12,7 @@ class SubjectLocal @Inject constructor(private val subjectDao: SubjectDao) {
|
||||
|
||||
fun getSubjects(semester: Semester): Maybe<List<Subject>> {
|
||||
return subjectDao.loadAll(semester.diaryId, semester.studentId)
|
||||
.filter { !it.isEmpty() }
|
||||
.filter { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
fun saveSubjects(subjects: List<Subject>) {
|
||||
|
@ -1,8 +1,10 @@
|
||||
package io.github.wulkanowy.data.repositories.subject
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.Subject
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -10,8 +12,9 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
class SubjectRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getSubjects(semester: Semester): Single<List<Subject>> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getSubjects()
|
||||
fun getSubjects(student: Student, semester: Semester): Single<List<Subject>> {
|
||||
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getSubjects()
|
||||
.map { subjects ->
|
||||
subjects.map {
|
||||
Subject(
|
||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.subject
|
||||
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.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.Subject
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import io.reactivex.Single
|
||||
@ -17,11 +18,11 @@ class SubjectRepository @Inject constructor(
|
||||
private val remote: SubjectRemote
|
||||
) {
|
||||
|
||||
fun getSubjects(semester: Semester, forceRefresh: Boolean = false): Single<List<Subject>> {
|
||||
fun getSubjects(student: Student, semester: Semester, forceRefresh: Boolean = false): Single<List<Subject>> {
|
||||
return local.getSubjects(semester).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getSubjects(semester)
|
||||
if (it) remote.getSubjects(student, semester)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getSubjects(semester)
|
||||
|
@ -1,8 +1,10 @@
|
||||
package io.github.wulkanowy.data.repositories.teacher
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.Teacher
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -10,8 +12,9 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
class TeacherRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getTeachers(semester: Semester): Single<List<Teacher>> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getTeachers(semester.semesterId)
|
||||
fun getTeachers(student: Student, semester: Semester): Single<List<Teacher>> {
|
||||
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getTeachers(semester.semesterId)
|
||||
.map { teachers ->
|
||||
teachers.map {
|
||||
Teacher(
|
||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.teacher
|
||||
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.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.Teacher
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import io.reactivex.Single
|
||||
@ -17,11 +18,11 @@ class TeacherRepository @Inject constructor(
|
||||
private val remote: TeacherRemote
|
||||
) {
|
||||
|
||||
fun getTeachers(semester: Semester, forceRefresh: Boolean = false): Single<List<Teacher>> {
|
||||
fun getTeachers(student: Student, semester: Semester, forceRefresh: Boolean = false): Single<List<Teacher>> {
|
||||
return local.getTeachers(semester).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getTeachers(semester)
|
||||
if (it) remote.getTeachers(student, semester)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getTeachers(semester).toSingle(emptyList())
|
||||
|
@ -1,8 +1,10 @@
|
||||
package io.github.wulkanowy.data.repositories.timetable
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.reactivex.Single
|
||||
import org.threeten.bp.LocalDate
|
||||
import javax.inject.Inject
|
||||
@ -11,8 +13,9 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
class TimetableRemote @Inject constructor(private val sdk: Sdk) {
|
||||
|
||||
fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Timetable>> {
|
||||
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getTimetable(startDate, endDate)
|
||||
fun getTimetable(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Timetable>> {
|
||||
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getTimetable(startDate, endDate)
|
||||
.map { lessons ->
|
||||
lessons.map {
|
||||
Timetable(
|
||||
|
@ -3,7 +3,9 @@ package io.github.wulkanowy.data.repositories.timetable
|
||||
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.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
|
||||
import io.github.wulkanowy.utils.friday
|
||||
import io.github.wulkanowy.utils.monday
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
@ -17,21 +19,22 @@ import javax.inject.Singleton
|
||||
class TimetableRepository @Inject constructor(
|
||||
private val settings: InternetObservingSettings,
|
||||
private val local: TimetableLocal,
|
||||
private val remote: TimetableRemote
|
||||
private val remote: TimetableRemote,
|
||||
private val schedulerHelper: TimetableNotificationSchedulerHelper
|
||||
) {
|
||||
|
||||
fun getTimetable(semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single<List<Timetable>> {
|
||||
fun getTimetable(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single<List<Timetable>> {
|
||||
return Single.fromCallable { start.monday to end.friday }.flatMap { (monday, friday) ->
|
||||
local.getTimetable(semester, monday, friday).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
|
||||
if (it) remote.getTimetable(semester, monday, friday)
|
||||
if (it) remote.getTimetable(student, semester, monday, friday)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getTimetable(semester, monday, friday)
|
||||
.toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteTimetable(old.uniqueSubtract(new))
|
||||
local.saveTimetable(new.uniqueSubtract(old).map { item ->
|
||||
local.deleteTimetable(old.uniqueSubtract(new).also { schedulerHelper.cancelScheduled(it) })
|
||||
local.saveTimetable(new.uniqueSubtract(old).also { schedulerHelper.scheduleNotifications(it, student) }.map { item ->
|
||||
item.also { new ->
|
||||
old.singleOrNull { new.start == it.start }?.let { old ->
|
||||
return@map new.copy(
|
||||
@ -44,7 +47,7 @@ class TimetableRepository @Inject constructor(
|
||||
}
|
||||
}.flatMap {
|
||||
local.getTimetable(semester, monday, friday).toSingle(emptyList())
|
||||
}).map { list -> list.filter { it.date in start..end } }
|
||||
}).map { list -> list.filter { it.date in start..end }.also { schedulerHelper.scheduleNotifications(it, student) } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,6 @@ import android.content.Context
|
||||
import com.yariksoffice.lingver.Lingver
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.WulkanowyApp
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
@ -23,9 +21,6 @@ internal class AppModule {
|
||||
@Provides
|
||||
fun provideSchedulersProvider() = SchedulersProvider()
|
||||
|
||||
@Provides
|
||||
fun provideFlexibleAdapter() = FlexibleAdapter<AbstractFlexibleItem<*>>(null, null, true)
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideAppWidgetManager(context: Context): AppWidgetManager = AppWidgetManager.getInstance(context)
|
||||
|
@ -3,6 +3,8 @@ package io.github.wulkanowy.di
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import io.github.wulkanowy.di.scopes.PerActivity
|
||||
import io.github.wulkanowy.ui.base.ErrorDialog
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver
|
||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||
import io.github.wulkanowy.ui.modules.login.LoginModule
|
||||
import io.github.wulkanowy.ui.modules.luckynumberwidget.LuckyNumberWidgetConfigureActivity
|
||||
@ -18,6 +20,9 @@ import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider
|
||||
@Module
|
||||
internal abstract class BindingModule {
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindErrorDialog(): ErrorDialog
|
||||
|
||||
@PerActivity
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindSplashActivity(): SplashActivity
|
||||
@ -44,4 +49,7 @@ internal abstract class BindingModule {
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindLuckyNumberWidgetProvider(): LuckyNumberWidgetProvider
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindTimetableNotificationReceiver(): TimetableNotificationReceiver
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package io.github.wulkanowy.services
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.work.WorkManager
|
||||
import com.squareup.inject.assisted.dagger2.AssistedModule
|
||||
import dagger.Binds
|
||||
@ -15,12 +17,13 @@ import io.github.wulkanowy.services.sync.channels.LuckyNumberChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewGradesChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewMessagesChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewNotesChannel
|
||||
import io.github.wulkanowy.services.sync.channels.UpcomingLessonsChannel
|
||||
import io.github.wulkanowy.services.sync.channels.PushChannel
|
||||
import io.github.wulkanowy.services.sync.works.AttendanceSummaryWork
|
||||
import io.github.wulkanowy.services.sync.works.AttendanceWork
|
||||
import io.github.wulkanowy.services.sync.works.CompletedLessonWork
|
||||
import io.github.wulkanowy.services.sync.works.ExamWork
|
||||
import io.github.wulkanowy.services.sync.works.GradeStatisticsWork
|
||||
import io.github.wulkanowy.services.sync.works.GradeSummaryWork
|
||||
import io.github.wulkanowy.services.sync.works.GradeWork
|
||||
import io.github.wulkanowy.services.sync.works.HomeworkWork
|
||||
import io.github.wulkanowy.services.sync.works.LuckyNumberWork
|
||||
@ -46,6 +49,10 @@ abstract class ServicesModule {
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideNotificationManager(context: Context) = NotificationManagerCompat.from(context)
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideAlarmManager(context: Context): AlarmManager = context.getSystemService()!!
|
||||
}
|
||||
|
||||
@ContributesAndroidInjector
|
||||
@ -63,10 +70,6 @@ abstract class ServicesModule {
|
||||
@IntoSet
|
||||
abstract fun provideAttendanceWork(work: AttendanceWork): Work
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun provideGradeSummaryWork(work: GradeSummaryWork): Work
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun provideExamWork(work: ExamWork): Work
|
||||
@ -126,4 +129,12 @@ abstract class ServicesModule {
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun provideNewNotesChannel(channel: NewNotesChannel): Channel
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun providePushChannel(channel: PushChannel): Channel
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun provideUpcomingLessonsChannel(channel: UpcomingLessonsChannel): Channel
|
||||
}
|
||||
|
@ -0,0 +1,117 @@
|
||||
package io.github.wulkanowy.services.alarm
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.PendingIntent
|
||||
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Build.VERSION_CODES.N
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import dagger.android.AndroidInjection
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.services.sync.channels.UpcomingLessonsChannel.Companion.CHANNEL_ID
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import io.github.wulkanowy.utils.getCompatColor
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class TimetableNotificationReceiver : BroadcastReceiver() {
|
||||
|
||||
@Inject
|
||||
lateinit var studentRepository: StudentRepository
|
||||
|
||||
@Inject
|
||||
lateinit var schedulers: SchedulersProvider
|
||||
|
||||
companion object {
|
||||
const val NOTIFICATION_TYPE_CURRENT = 1
|
||||
const val NOTIFICATION_TYPE_UPCOMING = 2
|
||||
const val NOTIFICATION_TYPE_LAST_LESSON_CANCELLATION = 3
|
||||
|
||||
const val NOTIFICATION_ID = "id"
|
||||
|
||||
const val STUDENT_NAME = "student_name"
|
||||
const val STUDENT_ID = "student_id"
|
||||
const val LESSON_TYPE = "type"
|
||||
const val LESSON_TITLE = "title"
|
||||
const val LESSON_ROOM = "room"
|
||||
const val LESSON_NEXT_TITLE = "next_title"
|
||||
const val LESSON_NEXT_ROOM = "next_room"
|
||||
const val LESSON_START = "start_timestamp"
|
||||
const val LESSON_END = "end_timestamp"
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
Timber.d("Receiving intent... ${intent.toUri(0)}")
|
||||
AndroidInjection.inject(this, context)
|
||||
|
||||
studentRepository.getCurrentStudent(false)
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
.subscribe({
|
||||
val studentId = intent.getIntExtra(STUDENT_ID, 0)
|
||||
if (it.studentId == studentId) prepareNotification(context, intent)
|
||||
else Timber.d("Notification studentId($studentId) differs from current(${it.studentId})")
|
||||
}, { Timber.e(it) })
|
||||
}
|
||||
|
||||
private fun prepareNotification(context: Context, intent: Intent) {
|
||||
val type = intent.getIntExtra(LESSON_TYPE, 0)
|
||||
val notificationId = intent.getIntExtra(NOTIFICATION_ID, MainView.Section.TIMETABLE.id)
|
||||
|
||||
if (type == NOTIFICATION_TYPE_LAST_LESSON_CANCELLATION) {
|
||||
return NotificationManagerCompat.from(context).cancel(notificationId)
|
||||
}
|
||||
|
||||
val studentId = intent.getIntExtra(STUDENT_ID, 0)
|
||||
val studentName = intent.getStringExtra(STUDENT_NAME)
|
||||
|
||||
val subject = intent.getStringExtra(LESSON_TITLE)
|
||||
val room = intent.getStringExtra(LESSON_ROOM)
|
||||
|
||||
val start = intent.getLongExtra(LESSON_START, 0)
|
||||
val end = intent.getLongExtra(LESSON_END, 0)
|
||||
|
||||
val nextSubject = intent.getStringExtra(LESSON_NEXT_TITLE)
|
||||
val nextRoom = intent.getStringExtra(LESSON_NEXT_ROOM)
|
||||
|
||||
Timber.d("TimetableNotification receive: type: $type, subject: $subject, start: ${start.toLocalDateTime()}, student: $studentId")
|
||||
|
||||
showNotification(context, notificationId, studentName,
|
||||
if (type == NOTIFICATION_TYPE_CURRENT) end else start, end - start,
|
||||
context.getString(if (type == NOTIFICATION_TYPE_CURRENT) R.string.timetable_now else R.string.timetable_next, "($room) $subject".removePrefix("()")),
|
||||
nextSubject?.let { context.getString(R.string.timetable_later, "($nextRoom) $nextSubject".removePrefix("()")) }
|
||||
)
|
||||
}
|
||||
|
||||
private fun showNotification(context: Context, notificationId: Int, studentName: String?, countDown: Long, timeout: Long, title: String, next: String?) {
|
||||
NotificationManagerCompat.from(context).notify(notificationId, NotificationCompat.Builder(context, CHANNEL_ID)
|
||||
.setContentTitle(title)
|
||||
.setContentText(next)
|
||||
.setAutoCancel(false)
|
||||
.setOngoing(true)
|
||||
.setWhen(countDown)
|
||||
.apply {
|
||||
if (Build.VERSION.SDK_INT >= N) setUsesChronometer(true)
|
||||
}
|
||||
.setTimeoutAfter(timeout)
|
||||
.setSmallIcon(R.drawable.ic_stat_timetable)
|
||||
.setColor(context.getCompatColor(R.color.colorPrimary))
|
||||
.setStyle(NotificationCompat.InboxStyle().also {
|
||||
it.setSummaryText(studentName)
|
||||
it.addLine(next)
|
||||
})
|
||||
.setContentIntent(PendingIntent.getActivity(context, MainView.Section.TIMETABLE.id,
|
||||
MainActivity.getStartIntent(context, MainView.Section.TIMETABLE, true), FLAG_UPDATE_CURRENT))
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
package io.github.wulkanowy.services.alarm
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.AlarmManager.RTC_WAKEUP
|
||||
import android.app.PendingIntent
|
||||
import android.app.PendingIntent.FLAG_CANCEL_CURRENT
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.core.app.AlarmManagerCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companion.LESSON_END
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companion.LESSON_NEXT_ROOM
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companion.LESSON_NEXT_TITLE
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companion.LESSON_ROOM
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companion.LESSON_START
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companion.LESSON_TITLE
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companion.LESSON_TYPE
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companion.NOTIFICATION_ID
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companion.NOTIFICATION_TYPE_CURRENT
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companion.NOTIFICATION_TYPE_LAST_LESSON_CANCELLATION
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companion.NOTIFICATION_TYPE_UPCOMING
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companion.STUDENT_ID
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companion.STUDENT_NAME
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import org.threeten.bp.LocalDateTime
|
||||
import org.threeten.bp.LocalDateTime.now
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class TimetableNotificationSchedulerHelper @Inject constructor(
|
||||
private val context: Context,
|
||||
private val alarmManager: AlarmManager,
|
||||
private val preferencesRepository: PreferencesRepository
|
||||
) {
|
||||
|
||||
private fun getRequestCode(time: LocalDateTime, studentId: Int) = (time.toTimestamp() * studentId).toInt()
|
||||
|
||||
private fun getUpcomingLessonTime(index: Int, day: List<Timetable>, lesson: Timetable): LocalDateTime {
|
||||
return day.getOrNull(index - 1)?.end ?: lesson.start.minusMinutes(30)
|
||||
}
|
||||
|
||||
fun cancelScheduled(lessons: List<Timetable>, studentId: Int = 1) {
|
||||
lessons.sortedBy { it.start }.forEachIndexed { index, lesson ->
|
||||
val upcomingTime = getUpcomingLessonTime(index, lessons, lesson)
|
||||
cancelScheduledTo(upcomingTime..lesson.start, getRequestCode(upcomingTime, studentId))
|
||||
cancelScheduledTo(lesson.start..lesson.end, getRequestCode(lesson.start, studentId))
|
||||
|
||||
Timber.d("TimetableNotification canceled: type 1 & 2, subject: ${lesson.subject}, start: ${lesson.start}, student: $studentId")
|
||||
}
|
||||
}
|
||||
|
||||
private fun cancelScheduledTo(range: ClosedRange<LocalDateTime>, requestCode: Int) {
|
||||
if (now() in range) cancelNotification()
|
||||
alarmManager.cancel(PendingIntent.getBroadcast(context, requestCode, Intent(), FLAG_CANCEL_CURRENT))
|
||||
}
|
||||
|
||||
fun cancelNotification() = NotificationManagerCompat.from(context).cancel(MainView.Section.TIMETABLE.id)
|
||||
|
||||
fun scheduleNotifications(lessons: List<Timetable>, student: Student) {
|
||||
if (!preferencesRepository.isUpcomingLessonsNotificationsEnable) return cancelScheduled(lessons, student.studentId)
|
||||
|
||||
lessons.groupBy { it.date }
|
||||
.map { it.value.sortedBy { lesson -> lesson.start } }
|
||||
.map { it.filter { lesson -> !lesson.canceled && lesson.isStudentPlan } }
|
||||
.map { day ->
|
||||
day.forEachIndexed { index, lesson ->
|
||||
val intent = createIntent(student, lesson, day.getOrNull(index + 1))
|
||||
|
||||
if (lesson.start > now()) {
|
||||
scheduleBroadcast(intent, student.studentId, NOTIFICATION_TYPE_UPCOMING, getUpcomingLessonTime(index, day, lesson))
|
||||
}
|
||||
|
||||
if (lesson.end > now()) {
|
||||
scheduleBroadcast(intent, student.studentId, NOTIFICATION_TYPE_CURRENT, lesson.start)
|
||||
if (day.lastIndex == index) {
|
||||
scheduleBroadcast(intent, student.studentId, NOTIFICATION_TYPE_LAST_LESSON_CANCELLATION, lesson.end)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createIntent(student: Student, lesson: Timetable, nextLesson: Timetable?): Intent {
|
||||
return Intent(context, TimetableNotificationReceiver::class.java).apply {
|
||||
putExtra(STUDENT_ID, student.studentId)
|
||||
putExtra(STUDENT_NAME, student.studentName)
|
||||
putExtra(LESSON_ROOM, lesson.room)
|
||||
putExtra(LESSON_START, lesson.start.toTimestamp())
|
||||
putExtra(LESSON_END, lesson.end.toTimestamp())
|
||||
putExtra(LESSON_TITLE, lesson.subject)
|
||||
putExtra(LESSON_NEXT_TITLE, nextLesson?.subject)
|
||||
putExtra(LESSON_NEXT_ROOM, nextLesson?.room)
|
||||
}
|
||||
}
|
||||
|
||||
private fun scheduleBroadcast(intent: Intent, studentId: Int, notificationType: Int, time: LocalDateTime) {
|
||||
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, RTC_WAKEUP, time.toTimestamp(),
|
||||
PendingIntent.getBroadcast(context, getRequestCode(time, studentId), intent.also {
|
||||
it.putExtra(NOTIFICATION_ID, MainView.Section.TIMETABLE.id)
|
||||
it.putExtra(LESSON_TYPE, notificationType)
|
||||
}, FLAG_CANCEL_CURRENT)
|
||||
)
|
||||
Timber.d("TimetableNotification scheduled: type: $notificationType, subject: ${intent.getStringExtra(LESSON_TITLE)}, start: $time, student: $studentId")
|
||||
}
|
||||
}
|
@ -5,18 +5,24 @@ import android.os.Build.VERSION_CODES.O
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.work.BackoffPolicy.EXPONENTIAL
|
||||
import androidx.work.Constraints
|
||||
import androidx.work.Data
|
||||
import androidx.work.ExistingPeriodicWorkPolicy.KEEP
|
||||
import androidx.work.ExistingPeriodicWorkPolicy.REPLACE
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.NetworkType.CONNECTED
|
||||
import androidx.work.NetworkType.UNMETERED
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import com.paulinasadowska.rxworkmanagerobservers.extensions.getWorkInfoByIdObservable
|
||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||
import io.github.wulkanowy.data.db.SharedPrefProvider.Companion.APP_VERSION_CODE_KEY
|
||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||
import io.github.wulkanowy.services.sync.channels.Channel
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import io.github.wulkanowy.utils.isHolidays
|
||||
import io.reactivex.Observable
|
||||
import org.threeten.bp.LocalDate.now
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.TimeUnit.MINUTES
|
||||
@ -36,19 +42,19 @@ class SyncManager @Inject constructor(
|
||||
init {
|
||||
if (now().isHolidays) stopSyncWorker()
|
||||
|
||||
if (SDK_INT > O) {
|
||||
if (SDK_INT >= O) {
|
||||
channels.forEach { it.create() }
|
||||
notificationManager.deleteNotificationChannel("new_entries_channel")
|
||||
}
|
||||
|
||||
if (sharedPrefProvider.getLong(APP_VERSION_CODE_KEY, -1L) != appInfo.versionCode.toLong()) {
|
||||
startSyncWorker(true)
|
||||
startPeriodicSyncWorker(true)
|
||||
sharedPrefProvider.putLong(APP_VERSION_CODE_KEY, appInfo.versionCode.toLong(), true)
|
||||
}
|
||||
Timber.i("SyncManager was initialized")
|
||||
}
|
||||
|
||||
fun startSyncWorker(restart: Boolean = false) {
|
||||
fun startPeriodicSyncWorker(restart: Boolean = false) {
|
||||
if (preferencesRepository.isServiceEnabled && !now().isHolidays) {
|
||||
workManager.enqueueUniquePeriodicWork(SyncWorker::class.java.simpleName, if (restart) REPLACE else KEEP,
|
||||
PeriodicWorkRequestBuilder<SyncWorker>(preferencesRepository.servicesInterval, MINUTES)
|
||||
@ -61,6 +67,19 @@ class SyncManager @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun startOneTimeSyncWorker(): Observable<WorkInfo> {
|
||||
val work = OneTimeWorkRequestBuilder<SyncWorker>()
|
||||
.setInputData(
|
||||
Data.Builder()
|
||||
.putBoolean("one_time", true)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
|
||||
workManager.enqueueUniqueWork("${SyncWorker::class.java.simpleName}_one_time", ExistingWorkPolicy.REPLACE, work)
|
||||
return workManager.getWorkInfoByIdObservable(work.id)
|
||||
}
|
||||
|
||||
fun stopSyncWorker() {
|
||||
workManager.cancelUniqueWork(SyncWorker::class.java.simpleName)
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationCompat.BigTextStyle
|
||||
import androidx.core.app.NotificationCompat.PRIORITY_DEFAULT
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.work.Data
|
||||
import androidx.work.ListenableWorker
|
||||
import androidx.work.RxWorker
|
||||
import androidx.work.WorkerParameters
|
||||
@ -15,6 +16,7 @@ import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.sdk.exception.FeatureDisabledException
|
||||
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
|
||||
import io.github.wulkanowy.services.sync.channels.DebugChannel
|
||||
import io.github.wulkanowy.services.sync.works.Work
|
||||
import io.github.wulkanowy.utils.getCompatColor
|
||||
@ -43,6 +45,10 @@ class SyncWorker @AssistedInject constructor(
|
||||
.flatMapCompletable { semester ->
|
||||
Completable.mergeDelayError(works.map { work ->
|
||||
work.create(student, semester)
|
||||
.onErrorResumeNext {
|
||||
if (it is FeatureDisabledException || it is FeatureNotAvailableException) Completable.complete()
|
||||
else Completable.error(it)
|
||||
}
|
||||
.doOnSubscribe { Timber.i("${work::class.java.simpleName} is starting") }
|
||||
.doOnError { Timber.i("${work::class.java.simpleName} result: An exception occurred") }
|
||||
.doOnComplete { Timber.i("${work::class.java.simpleName} result: Success") }
|
||||
@ -52,8 +58,15 @@ class SyncWorker @AssistedInject constructor(
|
||||
.toSingleDefault(Result.success())
|
||||
.onErrorReturn {
|
||||
Timber.e(it, "There was an error during synchronization")
|
||||
if (it is FeatureDisabledException) Result.success()
|
||||
else Result.retry()
|
||||
when {
|
||||
inputData.getBoolean("one_time", false) -> {
|
||||
Result.failure(Data.Builder()
|
||||
.putString("error", it.toString())
|
||||
.build()
|
||||
)
|
||||
}
|
||||
else -> Result.retry()
|
||||
}
|
||||
}
|
||||
.doOnSuccess {
|
||||
if (preferencesRepository.isDebugNotificationEnable) notify(it)
|
||||
@ -64,7 +77,7 @@ class SyncWorker @AssistedInject constructor(
|
||||
private fun notify(result: Result) {
|
||||
notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(applicationContext, DebugChannel.CHANNEL_ID)
|
||||
.setContentTitle("Debug notification")
|
||||
.setSmallIcon(R.drawable.ic_more_settings)
|
||||
.setSmallIcon(R.drawable.ic_stat_push)
|
||||
.setAutoCancel(true)
|
||||
.setColor(applicationContext.getCompatColor(R.color.colorPrimary))
|
||||
.setStyle(BigTextStyle().bigText("${SyncWorker::class.java.simpleName} result: $result"))
|
||||
|
@ -0,0 +1,32 @@
|
||||
package io.github.wulkanowy.services.sync.channels
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import io.github.wulkanowy.R
|
||||
import javax.inject.Inject
|
||||
|
||||
@TargetApi(26)
|
||||
class PushChannel @Inject constructor(
|
||||
private val notificationManager: NotificationManagerCompat,
|
||||
private val context: Context
|
||||
) : Channel {
|
||||
|
||||
companion object {
|
||||
const val CHANNEL_ID = "push_channel"
|
||||
}
|
||||
|
||||
override fun create() {
|
||||
notificationManager.createNotificationChannel(
|
||||
NotificationChannel(CHANNEL_ID, context.getString(R.string.channel_push), NotificationManager.IMPORTANCE_HIGH)
|
||||
.apply {
|
||||
enableLights(true)
|
||||
enableVibration(true)
|
||||
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package io.github.wulkanowy.services.sync.channels
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Notification.VISIBILITY_PUBLIC
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager.IMPORTANCE_DEFAULT
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import io.github.wulkanowy.R
|
||||
import javax.inject.Inject
|
||||
|
||||
@TargetApi(26)
|
||||
class UpcomingLessonsChannel @Inject constructor(
|
||||
private val notificationManager: NotificationManagerCompat,
|
||||
private val context: Context
|
||||
) : Channel {
|
||||
|
||||
companion object {
|
||||
const val CHANNEL_ID = "lesson_channel"
|
||||
}
|
||||
|
||||
override fun create() {
|
||||
notificationManager.createNotificationChannel(
|
||||
NotificationChannel(CHANNEL_ID, context.getString(R.string.channel_upcoming_lessons), IMPORTANCE_DEFAULT).apply {
|
||||
lockscreenVisibility = VISIBILITY_PUBLIC
|
||||
setShowBadge(false)
|
||||
enableVibration(false)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ class AttendanceSummaryWork @Inject constructor(
|
||||
) : Work {
|
||||
|
||||
override fun create(student: Student, semester: Semester): Completable {
|
||||
return attendanceSummaryRepository.getAttendanceSummary(semester, -1, true).ignoreElement()
|
||||
return attendanceSummaryRepository.getAttendanceSummary(student, semester, -1, true).ignoreElement()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ import javax.inject.Inject
|
||||
class AttendanceWork @Inject constructor(private val attendanceRepository: AttendanceRepository) : Work {
|
||||
|
||||
override fun create(student: Student, semester: Semester): Completable {
|
||||
return attendanceRepository.getAttendance(semester, now().monday, now().friday, true)
|
||||
return attendanceRepository.getAttendance(student, semester, now().monday, now().friday, true)
|
||||
.ignoreElement()
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ class CompletedLessonWork @Inject constructor(
|
||||
) : Work {
|
||||
|
||||
override fun create(student: Student, semester: Semester): Completable {
|
||||
return completedLessonsRepository.getCompletedLessons(semester, now().monday, now().friday, true)
|
||||
return completedLessonsRepository.getCompletedLessons(student, semester, now().monday, now().friday, true)
|
||||
.ignoreElement()
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,6 @@ import javax.inject.Inject
|
||||
class ExamWork @Inject constructor(private val examRepository: ExamRepository) : Work {
|
||||
|
||||
override fun create(student: Student, semester: Semester): Completable {
|
||||
return examRepository.getExams(semester, now().monday, now().friday, true).ignoreElement()
|
||||
return examRepository.getExams(student, semester, now().monday, now().friday, true).ignoreElement()
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import javax.inject.Inject
|
||||
class GradeStatisticsWork @Inject constructor(private val gradeStatisticsRepository: GradeStatisticsRepository) : Work {
|
||||
|
||||
override fun create(student: Student, semester: Semester): Completable {
|
||||
return gradeStatisticsRepository.getGradesStatistics(semester, "Wszystkie", false, true)
|
||||
return gradeStatisticsRepository.getGradesStatistics(student, semester, "Wszystkie", false, true)
|
||||
.ignoreElement()
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +0,0 @@
|
||||
package io.github.wulkanowy.services.sync.works
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.gradessummary.GradeSummaryRepository
|
||||
import io.reactivex.Completable
|
||||
import javax.inject.Inject
|
||||
|
||||
class GradeSummaryWork @Inject constructor(private val gradeSummaryRepository: GradeSummaryRepository) : Work {
|
||||
|
||||
override fun create(student: Student, semester: Semester): Completable {
|
||||
return gradeSummaryRepository.getGradesSummary(semester, true).ignoreElement()
|
||||
}
|
||||
}
|
@ -58,4 +58,3 @@ class GradeWork @Inject constructor(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,6 @@ import javax.inject.Inject
|
||||
class HomeworkWork @Inject constructor(private val homeworkRepository: HomeworkRepository) : Work {
|
||||
|
||||
override fun create(student: Student, semester: Semester): Completable {
|
||||
return homeworkRepository.getHomework(semester, now().monday, now().friday, true).ignoreElement()
|
||||
return homeworkRepository.getHomework(student, semester, now().monday, now().friday, true).ignoreElement()
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,6 @@ import javax.inject.Inject
|
||||
class TeacherWork @Inject constructor(private val teacherRepository: TeacherRepository) : Work {
|
||||
|
||||
override fun create(student: Student, semester: Semester): Completable {
|
||||
return teacherRepository.getTeachers(semester, true).ignoreElement()
|
||||
return teacherRepository.getTeachers(student, semester, true).ignoreElement()
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import javax.inject.Inject
|
||||
class TimetableWork @Inject constructor(private val timetableRepository: TimetableRepository) : Work {
|
||||
|
||||
override fun create(student: Student, semester: Semester): Completable {
|
||||
return timetableRepository.getTimetable(semester, now().monday, now().friday, true)
|
||||
return timetableRepository.getTimetable(student, semester, now().monday, now().friday, true)
|
||||
.ignoreElement()
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.android.material.snackbar.Snackbar.LENGTH_LONG
|
||||
import dagger.android.AndroidInjection
|
||||
@ -20,10 +21,13 @@ import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||
import io.github.wulkanowy.utils.FragmentLifecycleLogger
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.lifecycleAwareVariable
|
||||
import javax.inject.Inject
|
||||
|
||||
abstract class BaseActivity<T : BasePresenter<out BaseView>> : AppCompatActivity(), BaseView,
|
||||
HasAndroidInjector {
|
||||
abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
|
||||
AppCompatActivity(), BaseView, HasAndroidInjector {
|
||||
|
||||
protected var binding: VB by lifecycleAwareVariable()
|
||||
|
||||
@Inject
|
||||
lateinit var androidInjector: DispatchingAndroidInjector<Any>
|
||||
|
@ -1,9 +1,13 @@
|
||||
package io.github.wulkanowy.ui.base
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import dagger.android.support.DaggerAppCompatDialogFragment
|
||||
import io.github.wulkanowy.utils.lifecycleAwareVariable
|
||||
|
||||
abstract class BaseDialogFragment : DaggerAppCompatDialogFragment(), BaseView {
|
||||
abstract class BaseDialogFragment<VB : ViewBinding> : DaggerAppCompatDialogFragment(), BaseView {
|
||||
|
||||
protected var binding: VB by lifecycleAwareVariable()
|
||||
|
||||
override fun showError(text: String, error: Throwable) {
|
||||
showMessage(text)
|
||||
@ -14,11 +18,11 @@ abstract class BaseDialogFragment : DaggerAppCompatDialogFragment(), BaseView {
|
||||
}
|
||||
|
||||
override fun showExpiredDialog() {
|
||||
(activity as? BaseActivity<*>)?.showExpiredDialog()
|
||||
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
|
||||
}
|
||||
|
||||
override fun openClearLoginView() {
|
||||
(activity as? BaseActivity<*>)?.openClearLoginView()
|
||||
(activity as? BaseActivity<*, *>)?.openClearLoginView()
|
||||
}
|
||||
|
||||
override fun showErrorDetailsDialog(error: Throwable) {
|
||||
|
@ -0,0 +1,58 @@
|
||||
package io.github.wulkanowy.ui.base
|
||||
|
||||
import android.util.DisplayMetrics
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.LinearSmoothScroller
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
abstract class BaseExpandableAdapter<T : RecyclerView.ViewHolder> : RecyclerView.Adapter<T>() {
|
||||
|
||||
companion object {
|
||||
private const val MILLISECONDS_PER_INCH = 100f
|
||||
private const val AUTO_SCROLL_DELAY = 150L
|
||||
}
|
||||
|
||||
private var recyclerView: RecyclerView? = null
|
||||
|
||||
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
|
||||
super.onAttachedToRecyclerView(recyclerView)
|
||||
this.recyclerView = recyclerView
|
||||
}
|
||||
|
||||
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
|
||||
super.onDetachedFromRecyclerView(recyclerView)
|
||||
this.recyclerView = null
|
||||
}
|
||||
|
||||
// original: https://github.com/davideas/FlexibleAdapter/blob/5.1.0/flexible-adapter/src/main/java/eu/davidea/flexibleadapter/FlexibleAdapter.java#L4984-L5011
|
||||
protected fun scrollToHeaderWithSubItems(position: Int, subItemsCount: Int) {
|
||||
val layoutManager = recyclerView!!.layoutManager as LinearLayoutManager
|
||||
val firstVisibleItem = layoutManager.findFirstCompletelyVisibleItemPosition()
|
||||
val lastVisibleItem = layoutManager.findLastCompletelyVisibleItemPosition()
|
||||
val itemsToShow = position + subItemsCount - lastVisibleItem
|
||||
if (itemsToShow > 0) {
|
||||
val scrollMax: Int = position - firstVisibleItem
|
||||
val scrollMin = max(0, position + subItemsCount - lastVisibleItem)
|
||||
val scrollBy = min(scrollMax, scrollMin)
|
||||
val scrollTo = firstVisibleItem + scrollBy
|
||||
scrollToPosition(scrollTo)
|
||||
} else if (position < firstVisibleItem) {
|
||||
scrollToPosition(position)
|
||||
}
|
||||
}
|
||||
|
||||
private fun scrollToPosition(position: Int) {
|
||||
recyclerView?.run {
|
||||
postDelayed({
|
||||
layoutManager?.startSmoothScroll(object : LinearSmoothScroller(context) {
|
||||
override fun getVerticalSnapPreference() = SNAP_TO_START
|
||||
override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics) = MILLISECONDS_PER_INCH / displayMetrics.densityDpi
|
||||
}.apply {
|
||||
targetPosition = position
|
||||
})
|
||||
}, AUTO_SCROLL_DELAY)
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user