diff --git a/.circleci/config.yml b/.circleci/config.yml
index 1ae402f5..d4e59be1 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -159,7 +159,7 @@ jobs:
openssl aes-256-cbc -d -in ./app/upload-key-encrypted.jks -k $ENCRYPT_KEY >> ./app/upload-key.jks
- run:
name: Publish release
- command: ./gradlew publishRelease --no-daemon --stacktrace --console=plain -PenableCrashlytics -PdisablePreDex
+ command: ./gradlew publish --no-daemon --stacktrace --console=plain -PenableCrashlytics -PdisablePreDex
workflows:
version: 2
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index eb4efba7..a8407c84 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -19,7 +19,7 @@
-
+
diff --git a/.travis.yml b/.travis.yml
index a430c90e..56c64858 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,6 +11,11 @@ cache:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
+#branches:
+# only:
+# - master
+# - 0.7.x
+
android:
licenses:
- android-sdk-preview-license-.+
@@ -41,7 +46,7 @@ before_script:
- "curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | sudo bash"
script:
- - ./gradlew build -x test -x lint -x fabricGenerateResourcesRelease -x packageRelease --stacktrace --daemon
+ - ./gradlew dependencies --stacktrace --daemon
- fossa --no-ansi || true
- ./gradlew lint -x fabricGenerateResourcesRelease --stacktrace --daemon
- ./gradlew test -x fabricGenerateResourcesRelease --stacktrace --daemon
@@ -56,7 +61,7 @@ script:
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 publishRelease -PenableCrashlytics --stacktrace;
+ ./gradlew publish -PenableCrashlytics --stacktrace;
fi
after_success:
diff --git a/README.md b/README.md
index ccbf14ca..97a4172c 100644
--- a/README.md
+++ b/README.md
@@ -6,12 +6,12 @@
[](https://codecov.io/gh/wulkanowy/wulkanowy)
[](https://bettercodehub.com/)
[](https://sonarcloud.io/dashboard?id=io.github.wulkanowy%3Aapp)
-[](https://app.fossa.io/projects/custom%2B5644%2Fgit%40github.com%3Awulkanowy%2Fwulkanowy.git?ref=badge_shield)
+[](https://app.fossa.com/projects/custom%2B5644%2Fgithub.com%2Fwulkanowy%2Fwulkanowy?ref=badge_shield)
[](https://discord.gg/vccAQBr)
[Pobierz wersję beta z Google Play](https://play.google.com/store/apps/details?id=io.github.wulkanowy&utm_source=vcs)
-[Pobierz wersję DEV](https://bitrise-redirector.herokuapp.com/v0.1/apps/daeff1893f3c8128/builds/master/artifacts/0)
+[Pobierz wersję DEV](https://bitrise-redirector.herokuapp.com/v0.1/apps/f841f20d8f8b1dc8/builds/master/artifacts/0)
[(Więcej wersji DEV)](https://wulkanowy.github.io/dev.html)
Androidowy klient dziennika VULCAN UONET+.
@@ -19,4 +19,4 @@ Androidowy klient dziennika VULCAN UONET+.
## License
-[](https://app.fossa.io/projects/custom%2B5644%2Fgit%40github.com%3Awulkanowy%2Fwulkanowy.git?ref=badge_large)
+[](https://app.fossa.com/projects/custom%2B5644%2Fgithub.com%2Fwulkanowy%2Fwulkanowy?ref=badge_large)
diff --git a/app/build.gradle b/app/build.gradle
index 6382469d..4b471bdc 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,25 +11,20 @@ android {
compileSdkVersion 28
buildToolsVersion '28.0.3'
- playAccountConfigs {
- defaultAccountConfig {
- serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL")
- pk12File = file('key.p12')
- }
- }
-
defaultConfig {
applicationId "io.github.wulkanowy"
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 15
targetSdkVersion 28
- versionCode 19
- versionName "0.6.0"
+ versionCode 27
+ versionName "0.7.1"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
- playAccountConfig = playAccountConfigs.defaultAccountConfig
- manifestPlaceholders = [crashlytics_enabled: project.hasProperty("enableCrashlytics")]
+ manifestPlaceholders = [
+ fabric_api_key: System.getenv("FABRIC_API_KEY") ?: "null",
+ crashlytics_enabled: project.hasProperty("enableCrashlytics")
+ ]
}
signingConfigs {
@@ -45,7 +40,6 @@ android {
release {
buildConfigField "boolean", "CRASHLYTICS_ENABLED", "true"
minifyEnabled true
- useProguard false
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
@@ -63,6 +57,11 @@ android {
lintOptions {
disable 'HardwareIds'
}
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
}
androidExtensions {
@@ -70,66 +69,74 @@ androidExtensions {
}
play {
+ serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") ?: "jan@fakelog.cf"
+ serviceAccountCredentials = file('key.p12')
+ defaultToAppBundles = true
track = 'alpha'
- uploadImages = true
-}
-
-configurations.all {
- resolutionStrategy.force "com.squareup.okhttp3:okhttp-urlconnection:3.11.0"
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
- implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
- implementation('io.github.wulkanowy:api:0.6.0') { exclude module: "threetenbp" }
+ implementation('io.github.wulkanowy:api:0.7.1') { exclude module: "threetenbp" }
implementation "androidx.legacy:legacy-support-v4:1.0.0"
implementation "androidx.appcompat:appcompat:1.0.2"
implementation "androidx.cardview:cardview:1.0.0"
implementation "com.google.android.material:material:1.0.0"
- implementation 'androidx.multidex:multidex:2.0.0'
+ implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+ implementation 'androidx.multidex:multidex:2.0.1'
implementation 'com.takisoft.preferencex:preferencex:1.0.0'
- implementation "com.mikepenz:aboutlibraries:6.2.0"
- implementation "com.firebase:firebase-jobdispatcher:0.8.5"
- implementation "com.google.dagger:dagger-android-support:2.19"
- kapt "com.google.dagger:dagger-compiler:2.19"
- kapt "com.google.dagger:dagger-android-processor:2.19"
+ implementation "android.arch.work:work-rxjava2:1.0.0"
+ implementation "android.arch.work:work-runtime:1.0.0"
- implementation "androidx.room:room-runtime:2.1.0-alpha03"
- implementation "androidx.room:room-rxjava2:2.1.0-alpha03"
- kapt "androidx.room:room-compiler:2.1.0-alpha03"
+ implementation 'com.squareup.inject:assisted-inject-annotations-dagger2:0.3.3'
+ kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.3.3'
+
+ implementation "com.google.dagger:dagger-android-support:2.21"
+ kapt "com.google.dagger:dagger-compiler:2.21"
+ kapt "com.google.dagger:dagger-android-processor:2.21"
+
+ implementation "androidx.room:room-runtime:2.1.0-alpha05"
+ implementation "androidx.room:room-rxjava2:2.1.0-alpha05"
+ kapt "androidx.room:room-compiler:2.1.0-alpha05"
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.1.0'
- implementation "com.aurelhubert:ahbottomnavigation:2.2.0"
- implementation 'com.ncapdevi:frag-nav:3.0.0'
+ implementation 'com.github.wulkanowy:MaterialChipsInput:b72fd0ee6f'
+ implementation 'com.github.PhilJay:MPAndroidChart:971640b29d'
- implementation 'com.github.pwittchen:reactivenetwork-rx2:3.0.1'
- implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
- implementation "io.reactivex.rxjava2:rxjava:2.2.4"
-
- implementation "com.jakewharton.threetenabp:threetenabp:1.1.0"
+ implementation 'com.github.pwittchen:reactivenetwork-rx2:3.0.2'
+ implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
+ implementation "io.reactivex.rxjava2:rxjava:2.2.7"
+ implementation "com.jakewharton.threetenabp:threetenabp:1.2.0"
implementation "com.jakewharton.timber:timber:4.7.1"
implementation "at.favre.lib:slf4j-timber:1.0.1"
+ implementation "com.mikepenz:aboutlibraries:6.2.3"
- implementation 'com.google.firebase:firebase-core:16.0.6'
- implementation 'com.crashlytics.sdk.android:crashlytics:2.9.7'
+ implementation 'com.google.firebase:firebase-core:16.0.8'
+ implementation 'com.crashlytics.sdk.android:crashlytics:2.9.9'
- debugImplementation "com.amitshekhar.android:debug-db:1.0.4"
+ releaseImplementation 'fr.o80.chucker:library-no-op:2.0.4'
+
+ debugImplementation 'fr.o80.chucker:library:2.0.4'
+ debugImplementation "com.amitshekhar.android:debug-db:1.0.6"
testImplementation "junit:junit:4.12"
- testImplementation "io.mockk:mockk:1.8.13.kotlin13"
- testImplementation "org.mockito:mockito-inline:2.23.4"
+ testImplementation "io.mockk:mockk:1.9.1"
+ testImplementation "org.mockito:mockito-inline:2.25.0"
testImplementation 'org.threeten:threetenbp:1.3.8'
+ androidTestImplementation "io.mockk:mockk-android:1.9.1"
androidTestImplementation 'androidx.test:core:1.1.0'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
- androidTestImplementation 'org.mockito:mockito-android:2.23.4'
+ androidTestImplementation 'org.mockito:mockito-android:2.25.0'
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
}
diff --git a/app/jacoco.gradle b/app/jacoco.gradle
index 4f94ef19..f2b01b48 100644
--- a/app/jacoco.gradle
+++ b/app/jacoco.gradle
@@ -1,7 +1,7 @@
apply plugin: "jacoco"
jacoco {
- toolVersion "0.8.2"
+ toolVersion "0.8.3"
reportsDir = file("$buildDir/reports")
}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index cebd3d94..15b62838 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -5,6 +5,7 @@
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
+-dontobfuscate
-allowaccessmodification
-repackageclasses ''
-verbose
@@ -13,7 +14,6 @@
#Config for anallitycs
-keepattributes *Annotation*
-keepattributes SourceFile,LineNumberTable
--renamesourcefileattribute SourceFile
-keep class com.crashlytics.** {*;}
-keep public class * extends java.lang.Exception
-dontwarn com.crashlytics.**
@@ -32,5 +32,8 @@
-dontwarn rx.internal.util.**
-dontwarn sun.misc.Unsafe
+#Config for MPAndroidChart
+-keep class com.github.mikephil.charting.** { *; }
+
#Config for API
-keep class io.github.wulkanowy.api.** {*;}
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/TestInternetObservingStrategy.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/TestInternetObservingStrategy.kt
new file mode 100644
index 00000000..7dc93c4a
--- /dev/null
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/TestInternetObservingStrategy.kt
@@ -0,0 +1,19 @@
+package io.github.wulkanowy.data.repositories
+
+import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingStrategy
+import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.ErrorHandler
+import io.reactivex.Observable
+import io.reactivex.Single
+
+class TestInternetObservingStrategy : InternetObservingStrategy {
+
+ override fun checkInternetConnectivity(host: String?, port: Int, timeoutInMs: Int, httpResponse: Int, errorHandler: ErrorHandler?): Single {
+ return Single.just(true)
+ }
+
+ override fun observeInternetConnectivity(initialIntervalInMs: Int, intervalInMs: Int, host: String?, port: Int, timeoutInMs: Int, httpResponse: Int, errorHandler: ErrorHandler?): Observable {
+ return Observable.just(true)
+ }
+
+ override fun getDefaultPingHost() = "localhost"
+}
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/AttendanceLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/attendance/AttendanceLocalTest.kt
similarity index 85%
rename from app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/AttendanceLocalTest.kt
rename to app/src/androidTest/java/io/github/wulkanowy/data/repositories/attendance/AttendanceLocalTest.kt
index 8cbd13cd..ee65cf84 100644
--- a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/AttendanceLocalTest.kt
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/attendance/AttendanceLocalTest.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.local
+package io.github.wulkanowy.data.repositories.attendance
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
@@ -34,13 +34,13 @@ class AttendanceLocalTest {
@Test
fun saveAndReadTest() {
attendanceLocal.saveAttendance(listOf(
- Attendance(1, 2, LocalDate.of(2018, 9, 10), 0, "", ""),
- Attendance(1, 2, LocalDate.of(2018, 9, 14), 0, "", ""),
- Attendance(1, 2, LocalDate.of(2018, 9, 17), 0, "", "")
+ Attendance(1, 2, LocalDate.of(2018, 9, 10), 0, "", "", false, false, false, false, false, false),
+ Attendance(1, 2, LocalDate.of(2018, 9, 14), 0, "", "", false, false, false, false, false, false),
+ Attendance(1, 2, LocalDate.of(2018, 9, 17), 0, "", "", false, false, false, false, false, false)
))
val attendance = attendanceLocal
- .getAttendance(Semester(1, 1, 2, "", 3, 1),
+ .getAttendance(Semester(1, 2, "", 1, 3, true, 1, 1),
LocalDate.of(2018, 9, 10),
LocalDate.of(2018, 9, 14)
)
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsLocalTest.kt
new file mode 100644
index 00000000..014f0b8b
--- /dev/null
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsLocalTest.kt
@@ -0,0 +1,57 @@
+package io.github.wulkanowy.data.repositories.completedlessons
+
+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.entities.CompletedLesson
+import io.github.wulkanowy.data.db.entities.Semester
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.threeten.bp.LocalDate
+import kotlin.test.assertEquals
+
+@RunWith(AndroidJUnit4::class)
+class CompletedLessonsLocalTest {
+
+ private lateinit var completedLessonsLocal: CompletedLessonsLocal
+
+ private lateinit var testDb: AppDatabase
+
+ @Before
+ fun createDb() {
+ testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
+ .build()
+ completedLessonsLocal = CompletedLessonsLocal(testDb.completedLessonsDao)
+ }
+
+ @After
+ fun closeDb() {
+ testDb.close()
+ }
+
+ @Test
+ fun saveAndReadTest() {
+ completedLessonsLocal.saveCompletedLessons(listOf(
+ getCompletedLesson(LocalDate.of(2018, 9, 10), 1),
+ getCompletedLesson(LocalDate.of(2018, 9, 14), 2),
+ getCompletedLesson(LocalDate.of(2018, 9, 17), 3)
+ ))
+
+ val completed = completedLessonsLocal
+ .getCompletedLessons(Semester(1, 2, "", 1, 3, true, 1, 1),
+ LocalDate.of(2018, 9, 10),
+ LocalDate.of(2018, 9, 14)
+ )
+ .blockingGet()
+ assertEquals(2, completed.size)
+ assertEquals(completed[0].date, LocalDate.of(2018, 9, 10))
+ assertEquals(completed[1].date, LocalDate.of(2018, 9, 14))
+ }
+
+ private fun getCompletedLesson(date: LocalDate, number: Int): CompletedLesson {
+ return CompletedLesson(1, 2, date, number, "", "", "", "", "", "", "")
+ }
+}
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/ExamLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/exam/ExamLocalTest.kt
similarity index 93%
rename from app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/ExamLocalTest.kt
rename to app/src/androidTest/java/io/github/wulkanowy/data/repositories/exam/ExamLocalTest.kt
index c60348e3..dc66fa42 100644
--- a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/ExamLocalTest.kt
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/exam/ExamLocalTest.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.local
+package io.github.wulkanowy.data.repositories.exam
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
@@ -40,7 +40,7 @@ class ExamLocalTest {
))
val exams = examLocal
- .getExams(Semester(1, 1, 2, "", 3, 1),
+ .getExams(Semester(1, 2, "", 1, 3, true, 1, 1),
LocalDate.of(2018, 9, 10),
LocalDate.of(2018, 9, 14)
)
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/GradeLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/GradeLocalTest.kt
new file mode 100644
index 00000000..36238f1b
--- /dev/null
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/GradeLocalTest.kt
@@ -0,0 +1,50 @@
+package io.github.wulkanowy.data.repositories.grade
+
+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.entities.Semester
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.threeten.bp.LocalDate
+import kotlin.test.assertEquals
+
+@RunWith(AndroidJUnit4::class)
+class GradeLocalTest {
+
+ private lateinit var gradeLocal: GradeLocal
+
+ private lateinit var testDb: AppDatabase
+
+ @Before
+ fun createDb() {
+ testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
+ .build()
+ gradeLocal = GradeLocal(testDb.gradeDao)
+ }
+
+ @After
+ fun closeDb() {
+ testDb.close()
+ }
+
+ @Test
+ fun saveAndReadTest() {
+ gradeLocal.saveGrades(listOf(
+ createGradeLocal(5, 3.0, LocalDate.of(2018, 9, 10), "", 1),
+ createGradeLocal(4, 4.0, LocalDate.of(2019, 2, 27), "", 2),
+ createGradeLocal(3, 5.0, LocalDate.of(2019, 2, 28), "", 2)
+ ))
+
+ val grades = gradeLocal
+ .getGrades(Semester(1, 2, "", 2, 3, true, 1, 1))
+ .blockingGet()
+
+ assertEquals(2, grades.size)
+ assertEquals(grades[0].date, LocalDate.of(2019, 2, 27))
+ assertEquals(grades[1].date, LocalDate.of(2019, 2, 28))
+ }
+}
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/GradeRepositoryTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/GradeRepositoryTest.kt
new file mode 100644
index 00000000..17e788fc
--- /dev/null
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/GradeRepositoryTest.kt
@@ -0,0 +1,112 @@
+package io.github.wulkanowy.data.repositories.grade
+
+import android.os.Build.VERSION_CODES.P
+import androidx.room.Room
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
+import io.github.wulkanowy.api.Api
+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.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.impl.annotations.SpyK
+import io.reactivex.Single
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.threeten.bp.LocalDate.of
+import org.threeten.bp.LocalDateTime
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+import io.github.wulkanowy.api.grades.Grade as GradeApi
+
+@SdkSuppress(minSdkVersion = P)
+@RunWith(AndroidJUnit4::class)
+class GradeRepositoryTest {
+
+ @SpyK
+ private var mockApi = Api()
+
+ private val settings = InternetObservingSettings.builder()
+ .strategy(TestInternetObservingStrategy())
+ .build()
+
+ @MockK
+ private lateinit var semesterMock: Semester
+
+ @MockK
+ private lateinit var studentMock: Student
+
+ private lateinit var gradeRemote: GradeRemote
+
+ private lateinit var gradeLocal: GradeLocal
+
+ private lateinit var testDb: AppDatabase
+
+ @Before
+ fun initApi() {
+ MockKAnnotations.init(this)
+ testDb = Room.inMemoryDatabaseBuilder(getApplicationContext(), AppDatabase::class.java).build()
+ gradeLocal = GradeLocal(testDb.gradeDao)
+ gradeRemote = GradeRemote(mockApi)
+
+ every { mockApi.diaryId } returns 1
+ every { studentMock.registrationDate } returns LocalDateTime.of(2019, 2, 27, 12, 0)
+ every { semesterMock.studentId } returns 1
+ every { semesterMock.semesterId } returns 1
+ every { semesterMock.diaryId } returns 1
+ }
+
+ @After
+ fun closeDb() {
+ testDb.close()
+ }
+
+ @Test
+ fun markOlderThanRegisterDateAsRead() {
+ every { mockApi.getGrades(1) } returns Single.just(listOf(
+ createGradeApi(5, 4.0, of(2019, 2, 25), "Ocena pojawiła się"),
+ createGradeApi(5, 4.0, of(2019, 2, 26), "przed zalogowanie w aplikacji"),
+ createGradeApi(5, 4.0, of(2019, 2, 27), "Ocena z dnia logowania"),
+ createGradeApi(5, 4.0, of(2019, 2, 28), "Ocena jeszcze nowsza")
+ ))
+
+ val grades = GradeRepository(settings, gradeLocal, gradeRemote)
+ .getGrades(studentMock, semesterMock, true).blockingGet().sortedByDescending { it.date }
+
+ assertFalse { grades[0].isRead }
+ assertFalse { grades[1].isRead }
+ assertTrue { grades[2].isRead }
+ assertTrue { grades[3].isRead }
+ }
+
+ @Test
+ fun mitigateOldGradesNotifications() {
+ gradeLocal.saveGrades(listOf(
+ createGradeLocal(5, 3.0, of(2019, 2, 25), "Jedna ocena"),
+ createGradeLocal(4, 4.0, of(2019, 2, 26), "Druga"),
+ createGradeLocal(3, 5.0, of(2019, 2, 27), "Trzecia")
+ ))
+
+ every { mockApi.getGrades(1) } returns Single.just(listOf(
+ createGradeApi(5, 2.0, of(2019, 2, 25), "Ocena ma datę, jest inna, ale nie zostanie powiadomiona"),
+ createGradeApi(4, 3.0, of(2019, 2, 26), "starszą niż ostatnia lokalnie"),
+ createGradeApi(3, 4.0, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie"),
+ createGradeApi(2, 5.0, of(2019, 2, 28), "Ta jest już w ogóle nowa")
+ ))
+
+ val grades = GradeRepository(settings, gradeLocal, gradeRemote)
+ .getGrades(studentMock, semesterMock, true).blockingGet().sortedByDescending { it.date }
+
+ assertFalse { grades[0].isRead }
+ assertFalse { grades[1].isRead }
+ assertTrue { grades[2].isRead }
+ assertTrue { grades[3].isRead }
+ }
+}
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/TestGradeEntityCreator.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/TestGradeEntityCreator.kt
new file mode 100644
index 00000000..e0fd05a8
--- /dev/null
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/TestGradeEntityCreator.kt
@@ -0,0 +1,34 @@
+package io.github.wulkanowy.data.repositories.grade
+
+import io.github.wulkanowy.api.toDate
+import org.threeten.bp.LocalDate
+import io.github.wulkanowy.api.grades.Grade as GradeRemote
+import io.github.wulkanowy.data.db.entities.Grade as GradeLocal
+
+fun createGradeLocal(value: Int, weight: Double, date: LocalDate, desc: String, semesterId: Int = 1): GradeLocal {
+ return GradeLocal(
+ semesterId = semesterId,
+ studentId = 1,
+ modifier = .0,
+ teacher = "",
+ subject = "",
+ date = date,
+ color = "",
+ comment = "",
+ description = desc,
+ entry = "",
+ gradeSymbol = "",
+ value = value,
+ weight = "",
+ weightValue = weight
+ )
+}
+
+fun createGradeApi(value: Int, weight: Double, date: LocalDate, desc: String): GradeRemote {
+ return GradeRemote().apply {
+ this.value = value
+ this.weightValue = weight
+ this.date = date.toDate()
+ this.description = desc
+ }
+}
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsLocalTest.kt
new file mode 100644
index 00000000..5c0590e7
--- /dev/null
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsLocalTest.kt
@@ -0,0 +1,68 @@
+package io.github.wulkanowy.data.repositories.gradestatistics
+
+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.entities.GradeStatistics
+import io.github.wulkanowy.data.db.entities.Semester
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertEquals
+
+@RunWith(AndroidJUnit4::class)
+class GradeStatisticsLocalTest {
+
+ private lateinit var gradeStatisticsLocal: GradeStatisticsLocal
+
+ private lateinit var testDb: AppDatabase
+
+ @Before
+ fun createDb() {
+ testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
+ .build()
+ gradeStatisticsLocal = GradeStatisticsLocal(testDb.gradeStatistics)
+ }
+
+ @After
+ fun closeDb() {
+ testDb.close()
+ }
+
+ @Test
+ fun saveAndRead_subject() {
+ gradeStatisticsLocal.saveGradesStatistics(listOf(
+ getGradeStatistics("Matematyka", 2, 1),
+ getGradeStatistics("Fizyka", 1, 2)
+ ))
+
+ val stats = gradeStatisticsLocal.getGradesStatistics(
+ Semester(2, 2, "", 1, 2, true, 1, 1), false,
+ "Matematyka"
+ ).blockingGet()
+ assertEquals(1, stats.size)
+ assertEquals(stats[0].subject, "Matematyka")
+ }
+
+ @Test
+ fun saveAndRead_all() {
+ gradeStatisticsLocal.saveGradesStatistics(listOf(
+ getGradeStatistics("Matematyka", 2, 1),
+ getGradeStatistics("Chemia", 2, 1),
+ getGradeStatistics("Fizyka", 1, 2)
+ ))
+
+ val stats = gradeStatisticsLocal.getGradesStatistics(
+ Semester(2, 2, "", 1, 2, true, 1, 1), false,
+ "Wszystkie"
+ ).blockingGet()
+ assertEquals(1, stats.size)
+ assertEquals(stats[0].subject, "Wszystkie")
+ }
+
+ private fun getGradeStatistics(subject: String, studentId: Int, semesterId: Int): GradeStatistics {
+ return GradeStatistics(studentId, semesterId, subject, 5, 5, false)
+ }
+}
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberLocalTest.kt
new file mode 100644
index 00000000..a656ac05
--- /dev/null
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberLocalTest.kt
@@ -0,0 +1,47 @@
+package io.github.wulkanowy.data.repositories.luckynumber
+
+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.entities.LuckyNumber
+import io.github.wulkanowy.data.db.entities.Semester
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.threeten.bp.LocalDate
+import kotlin.test.assertEquals
+
+@RunWith(AndroidJUnit4::class)
+class LuckyNumberLocalTest {
+
+ private lateinit var luckyNumberLocal: LuckyNumberLocal
+
+ private lateinit var testDb: AppDatabase
+
+ @Before
+ fun createDb() {
+ testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
+ .build()
+ luckyNumberLocal = LuckyNumberLocal(testDb.luckyNumberDao)
+ }
+
+ @After
+ fun closeDb() {
+ testDb.close()
+ }
+
+ @Test
+ fun saveAndReadTest() {
+ luckyNumberLocal.saveLuckyNumber(LuckyNumber(1, LocalDate.of(2019, 1, 20), 14))
+
+ val luckyNumber = luckyNumberLocal.getLuckyNumber(Semester(1, 1, "", 1, 3, true, 1, 1),
+ LocalDate.of(2019, 1, 20)
+ ).blockingGet()
+
+ assertEquals(1, luckyNumber.studentId)
+ assertEquals(LocalDate.of(2019, 1, 20), luckyNumber.date)
+ assertEquals(14, luckyNumber.luckyNumber)
+ }
+}
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/recipient/RecipientLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/recipient/RecipientLocalTest.kt
new file mode 100644
index 00000000..1f6562a2
--- /dev/null
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/recipient/RecipientLocalTest.kt
@@ -0,0 +1,60 @@
+package io.github.wulkanowy.data.repositories.recipient
+
+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.entities.Recipient
+import io.github.wulkanowy.data.db.entities.ReportingUnit
+import io.github.wulkanowy.data.db.entities.Student
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.threeten.bp.LocalDateTime
+import kotlin.test.assertEquals
+
+@RunWith(AndroidJUnit4::class)
+class RecipientLocalTest {
+
+ private lateinit var recipientLocal: RecipientLocal
+
+ private lateinit var testDb: AppDatabase
+
+ @Before
+ fun createDb() {
+ testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
+ .build()
+ recipientLocal = RecipientLocal(testDb.recipientDao)
+ }
+
+ @After
+ fun closeDb() {
+ testDb.close()
+ }
+
+ @Test
+ fun saveAndReadTest() {
+ recipientLocal.saveRecipients(listOf(
+ Recipient(1, "2rPracownik", "Kowalski Jan", "Kowalski Jan [KJ] - Pracownik (Fake123456)", 3, 4, 2, "hash"),
+ Recipient(1, "3rPracownik", "Kowalska Karolina", "Kowalska Karolina [KK] - Pracownik (Fake123456)", 4, 4, 2, "hash"),
+ Recipient(1, "4rPracownik", "Krupa Stanisław", "Krupa Stanisław [KS] - Uczeń (Fake123456)", 5, 4, 1, "hash")
+ ))
+
+ val recipients = recipientLocal.getRecipients(
+ Student("fakelog.cf", "AUTO", "", "", "", 1, "", "", "", true, LocalDateTime.now()),
+ 2,
+ ReportingUnit(1, 4, "", 0, "", emptyList())
+ ).blockingGet()
+
+ assertEquals(2, recipients.size)
+ assertEquals(1, recipients[0].studentId)
+ assertEquals("3rPracownik", recipients[1].realId)
+ assertEquals("Kowalski Jan", recipients[0].name)
+ assertEquals("Kowalska Karolina [KK] - Pracownik (Fake123456)", recipients[1].realName)
+ assertEquals(3, recipients[0].loginId)
+ assertEquals(4, recipients[1].unitId)
+ assertEquals(2, recipients[0].role)
+ assertEquals("hash", recipients[1].hash)
+ }
+}
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/StudentLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/student/StudentLocalTest.kt
similarity index 82%
rename from app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/StudentLocalTest.kt
rename to app/src/androidTest/java/io/github/wulkanowy/data/repositories/student/StudentLocalTest.kt
index 732dc5bc..c31bc806 100644
--- a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/StudentLocalTest.kt
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/student/StudentLocalTest.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.local
+package io.github.wulkanowy.data.repositories.student
import android.content.Context
import androidx.room.Room
@@ -11,6 +11,7 @@ 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)
@@ -28,7 +29,7 @@ class StudentLocalTest {
testDb = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java)
.build()
sharedHelper = SharedPrefHelper(context.getSharedPreferences("TEST", Context.MODE_PRIVATE))
- studentLocal = StudentLocal(testDb.studentDao, sharedHelper, context)
+ studentLocal = StudentLocal(testDb.studentDao, context)
}
@After
@@ -38,9 +39,8 @@ class StudentLocalTest {
@Test
fun saveAndReadTest() {
- studentLocal.saveStudent(Student(email = "test", password = "test123", schoolSymbol = "23", endpoint = "fakelog.cf", loginType = "AUTO", isCurrent = true))
+ studentLocal.saveStudent(Student(email = "test", password = "test123", schoolSymbol = "23", endpoint = "fakelog.cf", loginType = "AUTO", isCurrent = true, studentName = "", schoolName = "", studentId = 0, symbol = "", registrationDate = now()))
.blockingGet()
- assert(studentLocal.isStudentSaved)
val student = studentLocal.getCurrentStudent(true).blockingGet()
assertEquals("23", student.schoolSymbol)
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TestTimetableEntityCreator.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TestTimetableEntityCreator.kt
new file mode 100644
index 00000000..438e95f4
--- /dev/null
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TestTimetableEntityCreator.kt
@@ -0,0 +1,45 @@
+package io.github.wulkanowy.data.repositories.timetable
+
+import io.github.wulkanowy.api.toDate
+import io.github.wulkanowy.utils.toDate
+import org.threeten.bp.LocalDateTime
+import org.threeten.bp.LocalDateTime.now
+import io.github.wulkanowy.api.timetable.Timetable as TimetableRemote
+import io.github.wulkanowy.data.db.entities.Timetable as TimetableLocal
+
+fun createTimetableLocal(number: Int, start: LocalDateTime, room: String = "", subject: String = ""): TimetableLocal {
+ return TimetableLocal(
+ studentId = 1,
+ diaryId = 2,
+ number = number,
+ start = start,
+ end = now(),
+ date = start.toLocalDate(),
+ subject = subject,
+ subjectOld = "",
+ group = "",
+ room = room,
+ roomOld = "",
+ teacher = "",
+ teacherOld = "",
+ info = "",
+ changes = false,
+ canceled = false
+ )
+}
+
+fun createTimetableRemote(number: Int, start: LocalDateTime, room: String, subject: String = ""): TimetableRemote {
+ return TimetableRemote(
+ number = number,
+ start = start.toDate(),
+ end = start.plusMinutes(45).toDate(),
+ date = start.toLocalDate().toDate(),
+ subject = subject,
+ group = "",
+ room = room,
+ teacher = "",
+ info = "",
+ changes = false,
+ canceled = false
+ )
+}
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/TimetableLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TimetableLocalTest.kt
similarity index 58%
rename from app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/TimetableLocalTest.kt
rename to app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TimetableLocalTest.kt
index df0a7994..0ecbcf92 100644
--- a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/TimetableLocalTest.kt
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TimetableLocalTest.kt
@@ -1,17 +1,16 @@
-package io.github.wulkanowy.data.repositories.local
+package io.github.wulkanowy.data.repositories.timetable
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.entities.Semester
-import io.github.wulkanowy.data.db.entities.Timetable
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
-import org.threeten.bp.LocalDateTime
+import org.threeten.bp.LocalDateTime.of
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@@ -23,7 +22,8 @@ class TimetableLocalTest {
@Before
fun createDb() {
- testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java).build()
+ testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
+ .build()
timetableDb = TimetableLocal(testDb.timetableDao)
}
@@ -35,19 +35,17 @@ class TimetableLocalTest {
@Test
fun saveAndReadTest() {
timetableDb.saveTimetable(listOf(
- Timetable(1, 2, 1, LocalDateTime.now(), LocalDateTime.now(),
- LocalDate.of(2018, 9, 10), "", "", "", "", ""),
- Timetable(1, 2, 1, LocalDateTime.now(), LocalDateTime.now(),
- LocalDate.of(2018, 9, 14), "", "", "", "", ""),
- Timetable(1, 2, 1, LocalDateTime.now(), LocalDateTime.now(),
- LocalDate.of(2018, 9, 17), "", "", "", "", "")
+ createTimetableLocal(1, of(2018, 9, 10, 0, 0, 0)),
+ createTimetableLocal(1, of(2018, 9, 14, 0, 0, 0)),
+ createTimetableLocal(1, of(2018, 9, 17, 0, 0, 0))
))
val exams = timetableDb.getTimetable(
- Semester(0, 1, 2, "3", 1, 1),
- LocalDate.of(2018, 9, 10),
- LocalDate.of(2018, 9, 14)
+ Semester(1, 2, "", 1, 1, true, 1, 1),
+ LocalDate.of(2018, 9, 10),
+ LocalDate.of(2018, 9, 14)
).blockingGet()
+
assertEquals(2, exams.size)
assertEquals(exams[0].date, LocalDate.of(2018, 9, 10))
assertEquals(exams[1].date, LocalDate.of(2018, 9, 14))
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TimetableRepositoryTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TimetableRepositoryTest.kt
new file mode 100644
index 00000000..1c080263
--- /dev/null
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TimetableRepositoryTest.kt
@@ -0,0 +1,85 @@
+package io.github.wulkanowy.data.repositories.timetable
+
+import android.os.Build.VERSION_CODES.P
+import androidx.room.Room
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
+import io.github.wulkanowy.api.Api
+import io.github.wulkanowy.data.db.AppDatabase
+import io.github.wulkanowy.data.db.entities.Semester
+import io.github.wulkanowy.data.repositories.TestInternetObservingStrategy
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.impl.annotations.SpyK
+import io.reactivex.Single
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.threeten.bp.LocalDate
+import org.threeten.bp.LocalDateTime.of
+import kotlin.test.assertEquals
+
+@SdkSuppress(minSdkVersion = P)
+@RunWith(AndroidJUnit4::class)
+class TimetableRepositoryTest {
+
+ @SpyK
+ private var mockApi = Api()
+
+ private val settings = InternetObservingSettings.builder()
+ .strategy(TestInternetObservingStrategy())
+ .build()
+
+ @MockK
+ private lateinit var semesterMock: Semester
+
+ private lateinit var timetableRemote: TimetableRemote
+
+ private lateinit var timetableLocal: TimetableLocal
+
+ private lateinit var testDb: AppDatabase
+
+ @Before
+ fun initApi() {
+ MockKAnnotations.init(this)
+ testDb = Room.inMemoryDatabaseBuilder(getApplicationContext(), AppDatabase::class.java).build()
+ timetableLocal = TimetableLocal(testDb.timetableDao)
+ timetableRemote = TimetableRemote(mockApi)
+
+ every { semesterMock.studentId } returns 1
+ every { semesterMock.diaryId } returns 2
+ }
+
+ @After
+ fun closeDb() {
+ testDb.close()
+ }
+
+ @Test
+ fun copyDetailsToCompletedFromPrevious() {
+ timetableLocal.saveTimetable(listOf(
+ createTimetableLocal(1, of(2019, 3, 5, 8, 0), "123", "Przyroda"),
+ createTimetableLocal(1, of(2019, 3, 5, 8, 50), "321", "Religia"),
+ createTimetableLocal(1, of(2019, 3, 5, 9, 40), "213", "W-F")
+ ))
+
+ every { mockApi.getTimetable(any(), any()) } returns Single.just(listOf(
+ createTimetableRemote(1, of(2019, 3, 5, 8, 0), "", "Przyroda"),
+ createTimetableRemote(1, of(2019, 3, 5, 8, 50), "", "Religia"),
+ createTimetableRemote(1, of(2019, 3, 5, 9, 40), "", "W-F")
+ ))
+
+ val lessons = TimetableRepository(settings, timetableLocal, timetableRemote)
+ .getTimetable(semesterMock, LocalDate.of(2019, 3, 5), LocalDate.of(2019, 3, 5), true)
+ .blockingGet()
+
+ assertEquals(3, lessons.size)
+ assertEquals("123", lessons[0].room)
+ assertEquals("321", lessons[1].room)
+ assertEquals("213", lessons[2].room)
+ }
+}
diff --git a/app/src/debug/res/drawable/ic_launcher_foreground.xml b/app/src/debug/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 00000000..6be79909
--- /dev/null
+++ b/app/src/debug/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 00000000..7353dbd1
--- /dev/null
+++ b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 00000000..7353dbd1
--- /dev/null
+++ b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/debug/res/mipmap-hdpi/ic_launcher.png b/app/src/debug/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..5b688d7c
Binary files /dev/null and b/app/src/debug/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/debug/res/mipmap-hdpi/ic_launcher_round.png b/app/src/debug/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 00000000..81e723ec
Binary files /dev/null and b/app/src/debug/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/debug/res/mipmap-mdpi/ic_launcher.png b/app/src/debug/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..48b13240
Binary files /dev/null and b/app/src/debug/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/debug/res/mipmap-mdpi/ic_launcher_round.png b/app/src/debug/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 00000000..394b5707
Binary files /dev/null and b/app/src/debug/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/debug/res/mipmap-xhdpi/ic_launcher.png b/app/src/debug/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..ff8bfa3e
Binary files /dev/null and b/app/src/debug/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..365b4d66
Binary files /dev/null and b/app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png b/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..96be1ed4
Binary files /dev/null and b/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..463c089b
Binary files /dev/null and b/app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..57c7416f
Binary files /dev/null and b/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..53d6f5bb
Binary files /dev/null and b/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/debug/res/values/ic_launcher_background.xml b/app/src/debug/res/values/ic_launcher_background.xml
new file mode 100644
index 00000000..9646c0b4
--- /dev/null
+++ b/app/src/debug/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+
+
+ #D32F2F
+
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 643fd292..352b6d2b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -4,6 +4,8 @@
package="io.github.wulkanowy"
android:installLocation="internalOnly">
+
+
@@ -18,14 +20,13 @@
android:supportsRtl="false"
android:theme="@style/WulkanowyTheme"
android:usesCleartextTraffic="true"
- tools:ignore="GoogleAppIndexingWarning">
+ tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
-
@@ -39,14 +40,12 @@
android:configChanges="orientation|screenSize"
android:label="@string/main_title"
android:theme="@style/WulkanowyTheme.NoActionBar" />
+
-
-
-
-
-
@@ -62,6 +61,15 @@
android:resource="@xml/provider_widget_timetable" />
+
+
+
diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png
deleted file mode 100644
index de216d36..00000000
Binary files a/app/src/main/ic_launcher-web.png and /dev/null differ
diff --git a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt
index 628d6ce6..68fc7c64 100644
--- a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt
+++ b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt
@@ -3,6 +3,8 @@ package io.github.wulkanowy
import android.content.Context
import androidx.appcompat.app.AppCompatDelegate
import androidx.multidex.MultiDex
+import androidx.work.Configuration
+import androidx.work.WorkManager
import com.crashlytics.android.Crashlytics
import com.crashlytics.android.core.CrashlyticsCore
import com.jakewharton.threetenabp.AndroidThreeTen
@@ -12,8 +14,9 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.utils.Log
import io.fabric.sdk.android.Fabric
import io.github.wulkanowy.BuildConfig.DEBUG
-import io.github.wulkanowy.data.repositories.PreferencesRepository
+import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.di.DaggerAppComponent
+import io.github.wulkanowy.services.sync.SyncWorkerFactory
import io.github.wulkanowy.utils.CrashlyticsTree
import io.github.wulkanowy.utils.DebugLogTree
import timber.log.Timber
@@ -24,6 +27,9 @@ class WulkanowyApp : DaggerApplication() {
@Inject
lateinit var prefRepository: PreferencesRepository
+ @Inject
+ lateinit var workerFactory: SyncWorkerFactory
+
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
MultiDex.install(this)
@@ -35,6 +41,7 @@ class WulkanowyApp : DaggerApplication() {
initializeFabric()
if (DEBUG) enableDebugLog()
AppCompatDelegate.setDefaultNightMode(prefRepository.currentTheme)
+ WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(workerFactory).build())
}
private fun enableDebugLog() {
diff --git a/app/src/main/java/io/github/wulkanowy/data/ApiHelper.kt b/app/src/main/java/io/github/wulkanowy/data/ApiHelper.kt
index 5b7b1072..5ef40ce8 100644
--- a/app/src/main/java/io/github/wulkanowy/data/ApiHelper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/ApiHelper.kt
@@ -14,14 +14,20 @@ class ApiHelper @Inject constructor(private val api: Api) {
symbol = student.symbol
schoolSymbol = student.schoolSymbol
studentId = student.studentId
- useNewStudent = false
host = URL(student.endpoint).run { host + ":$port".removeSuffix(":-1") }
ssl = student.endpoint.startsWith("https")
loginType = Api.LoginType.valueOf(student.loginType)
+ useNewStudent = true
}
}
fun initApi(email: String, password: String, symbol: String, endpoint: String) {
- initApi(Student(email = email, password = password, symbol = symbol, endpoint = endpoint, loginType = "AUTO"))
+ api.apply {
+ this.email = email
+ this.password = password
+ this.symbol = symbol
+ host = URL(endpoint).run { host + ":$port".removeSuffix(":-1") }
+ ssl = endpoint.startsWith("https")
+ }
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt
index 3c58ea4b..c832368a 100644
--- a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt
@@ -5,11 +5,15 @@ import android.content.SharedPreferences
import android.content.res.Resources
import androidx.preference.PreferenceManager
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
-import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.SocketInternetObservingStrategy
+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 dagger.Module
import dagger.Provides
import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.AppDatabase
+import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import okhttp3.logging.HttpLoggingInterceptor
import okhttp3.logging.HttpLoggingInterceptor.Level.BASIC
import okhttp3.logging.HttpLoggingInterceptor.Level.NONE
@@ -23,22 +27,32 @@ internal class RepositoryModule {
@Provides
fun provideInternetObservingSettings(): InternetObservingSettings {
return InternetObservingSettings.builder()
- .strategy(SocketInternetObservingStrategy())
- .host("www.google.com")
+ .strategy(WalledGardenInternetObservingStrategy())
.build()
}
@Singleton
@Provides
- fun provideApi(): Api {
+ fun provideApi(chuckCollector: ChuckCollector, context: Context): Api {
return Api().apply {
logLevel = NONE
androidVersion = android.os.Build.VERSION.RELEASE
buildTag = android.os.Build.MODEL
setInterceptor(HttpLoggingInterceptor(HttpLoggingInterceptor.Logger { Timber.d(it) }).setLevel(BASIC))
+
+ // for debug only
+ setInterceptor(ChuckInterceptor(context, chuckCollector).maxContentLength(250000L), true, 0)
}
}
+ @Singleton
+ @Provides
+ fun provideChuckCollector(context: Context, prefRepository: PreferencesRepository): ChuckCollector {
+ return ChuckCollector(context)
+ .showNotification(prefRepository.isDebugNotificationEnable)
+ .retentionManager(RetentionManager(context, ChuckCollector.Period.ONE_HOUR))
+ }
+
@Singleton
@Provides
fun provideDatabase(context: Context) = AppDatabase.newInstance(context)
@@ -67,6 +81,10 @@ internal class RepositoryModule {
@Provides
fun provideGradeSummaryDao(database: AppDatabase) = database.gradeSummaryDao
+ @Singleton
+ @Provides
+ fun provideGradeStatisticsDao(database: AppDatabase) = database.gradeStatistics
+
@Singleton
@Provides
fun provideMessagesDao(database: AppDatabase) = database.messagesDao
@@ -98,4 +116,20 @@ internal class RepositoryModule {
@Singleton
@Provides
fun provideSubjectDao(database: AppDatabase) = database.subjectDao
+
+ @Singleton
+ @Provides
+ fun provideLuckyNumberDao(database: AppDatabase) = database.luckyNumberDao
+
+ @Singleton
+ @Provides
+ fun provideCompletedLessonsDao(database: AppDatabase) = database.completedLessonsDao
+
+ @Singleton
+ @Provides
+ fun provideReportingUnitDao(database: AppDatabase) = database.reportingUnitDao
+
+ @Singleton
+ @Provides
+ fun provideRecipientDao(database: AppDatabase) = database.recipientDao
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
index 30c957b4..4fefd9c9 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
@@ -8,28 +8,48 @@ import androidx.room.RoomDatabase.JournalMode.TRUNCATE
import androidx.room.TypeConverters
import io.github.wulkanowy.data.db.dao.AttendanceDao
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
+import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
import io.github.wulkanowy.data.db.dao.ExamDao
import io.github.wulkanowy.data.db.dao.GradeDao
+import io.github.wulkanowy.data.db.dao.GradeStatisticsDao
import io.github.wulkanowy.data.db.dao.GradeSummaryDao
-import io.github.wulkanowy.data.db.dao.MessagesDao
import io.github.wulkanowy.data.db.dao.HomeworkDao
+import io.github.wulkanowy.data.db.dao.LuckyNumberDao
+import io.github.wulkanowy.data.db.dao.MessagesDao
import io.github.wulkanowy.data.db.dao.NoteDao
+import io.github.wulkanowy.data.db.dao.RecipientDao
+import io.github.wulkanowy.data.db.dao.ReportingUnitDao
import io.github.wulkanowy.data.db.dao.SemesterDao
import io.github.wulkanowy.data.db.dao.StudentDao
import io.github.wulkanowy.data.db.dao.SubjectDao
import io.github.wulkanowy.data.db.dao.TimetableDao
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.AttendanceSummary
+import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Grade
+import io.github.wulkanowy.data.db.entities.GradeStatistics
import io.github.wulkanowy.data.db.entities.GradeSummary
-import io.github.wulkanowy.data.db.entities.Message
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.Note
+import io.github.wulkanowy.data.db.entities.Recipient
+import io.github.wulkanowy.data.db.entities.ReportingUnit
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.data.db.entities.Timetable
+import io.github.wulkanowy.data.db.migrations.Migration10
+import io.github.wulkanowy.data.db.migrations.Migration11
+import io.github.wulkanowy.data.db.migrations.Migration2
+import io.github.wulkanowy.data.db.migrations.Migration3
+import io.github.wulkanowy.data.db.migrations.Migration4
+import io.github.wulkanowy.data.db.migrations.Migration5
+import io.github.wulkanowy.data.db.migrations.Migration6
+import io.github.wulkanowy.data.db.migrations.Migration7
+import io.github.wulkanowy.data.db.migrations.Migration8
+import io.github.wulkanowy.data.db.migrations.Migration9
import javax.inject.Singleton
@Singleton
@@ -43,21 +63,42 @@ import javax.inject.Singleton
AttendanceSummary::class,
Grade::class,
GradeSummary::class,
+ GradeStatistics::class,
Message::class,
Note::class,
Homework::class,
- Subject::class
+ Subject::class,
+ LuckyNumber::class,
+ CompletedLesson::class,
+ ReportingUnit::class,
+ Recipient::class
],
- version = 1,
+ version = AppDatabase.VERSION_SCHEMA,
exportSchema = false
)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
companion object {
+ const val VERSION_SCHEMA = 11
+
fun newInstance(context: Context): AppDatabase {
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
.setJournalMode(TRUNCATE)
+ .fallbackToDestructiveMigrationFrom(VERSION_SCHEMA + 1)
+ .fallbackToDestructiveMigrationOnDowngrade()
+ .addMigrations(
+ Migration2(),
+ Migration3(),
+ Migration4(),
+ Migration5(),
+ Migration6(),
+ Migration7(),
+ Migration8(),
+ Migration9(),
+ Migration10(),
+ Migration11()
+ )
.build()
}
}
@@ -78,6 +119,8 @@ abstract class AppDatabase : RoomDatabase() {
abstract val gradeSummaryDao: GradeSummaryDao
+ abstract val gradeStatistics: GradeStatisticsDao
+
abstract val messagesDao: MessagesDao
abstract val noteDao: NoteDao
@@ -85,4 +128,12 @@ abstract class AppDatabase : RoomDatabase() {
abstract val homeworkDao: HomeworkDao
abstract val subjectDao: SubjectDao
+
+ abstract val luckyNumberDao: LuckyNumberDao
+
+ abstract val completedLessonsDao: CompletedLessonsDao
+
+ abstract val reportingUnitDao: ReportingUnitDao
+
+ abstract val recipientDao: RecipientDao
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/Converters.kt b/app/src/main/java/io/github/wulkanowy/data/db/Converters.kt
index a550df89..73a04d23 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/Converters.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/Converters.kt
@@ -1,6 +1,8 @@
package io.github.wulkanowy.data.db
import androidx.room.TypeConverter
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
import org.threeten.bp.DateTimeUtils
import org.threeten.bp.Instant
import org.threeten.bp.LocalDate
@@ -36,4 +38,14 @@ class Converters {
@TypeConverter
fun intToMonth(value: Int?) = value?.let { Month.of(it) }
+
+ @TypeConverter
+ fun intListToGson(list: List): String {
+ return Gson().toJson(list)
+ }
+
+ @TypeConverter
+ fun gsonToIntList(value: String): List {
+ return Gson().fromJson(value, object : TypeToken>() {}.type)
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/SharedPrefHelper.kt b/app/src/main/java/io/github/wulkanowy/data/db/SharedPrefHelper.kt
index 656b39d4..b3b6f5e3 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/SharedPrefHelper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/SharedPrefHelper.kt
@@ -19,14 +19,6 @@ class SharedPrefHelper @Inject constructor(private val sharedPref: SharedPrefere
return sharedPref.getLong(key, defaultValue)
}
- fun putBoolean(key: String, value: Boolean) {
- sharedPref.edit().putBoolean(key, value).apply()
- }
-
- fun getBoolean(key: String, defaultValue: Boolean): Boolean {
- return sharedPref.getBoolean(key, defaultValue)
- }
-
fun delete(key: String) {
sharedPref.edit().remove(key).apply()
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/CompletedLessonsDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/CompletedLessonsDao.kt
new file mode 100644
index 00000000..6816ceaa
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/CompletedLessonsDao.kt
@@ -0,0 +1,24 @@
+package io.github.wulkanowy.data.db.dao
+
+import androidx.room.Dao
+import androidx.room.Delete
+import androidx.room.Insert
+import androidx.room.Query
+import io.github.wulkanowy.data.db.entities.CompletedLesson
+import io.reactivex.Maybe
+import org.threeten.bp.LocalDate
+import javax.inject.Singleton
+
+@Singleton
+@Dao
+interface CompletedLessonsDao {
+
+ @Insert
+ fun insertAll(exams: List)
+
+ @Delete
+ fun deleteAll(exams: List)
+
+ @Query("SELECT * FROM CompletedLesson WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
+ fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe>
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/GradeDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/GradeDao.kt
index 629f201d..0bd210b0 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/GradeDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/GradeDao.kt
@@ -16,9 +16,6 @@ interface GradeDao {
@Insert
fun insertAll(grades: List)
- @Update
- fun update(grade: Grade)
-
@Update
fun updateAll(grade: List)
@@ -28,6 +25,4 @@ interface GradeDao {
@Query("SELECT * FROM Grades WHERE semester_id = :semesterId AND student_id = :studentId")
fun loadAll(semesterId: Int, studentId: Int): Maybe>
- @Query("SELECT * FROM Grades WHERE is_read = 0 AND semester_id = :semesterId AND student_id = :studentId")
- fun loadAllNew(semesterId: Int, studentId: Int): Maybe>
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/GradeStatisticsDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/GradeStatisticsDao.kt
new file mode 100644
index 00000000..338c369f
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/GradeStatisticsDao.kt
@@ -0,0 +1,26 @@
+package io.github.wulkanowy.data.db.dao
+
+import androidx.room.Dao
+import androidx.room.Delete
+import androidx.room.Insert
+import androidx.room.Query
+import io.github.wulkanowy.data.db.entities.GradeStatistics
+import io.reactivex.Maybe
+import javax.inject.Singleton
+
+@Singleton
+@Dao
+interface GradeStatisticsDao {
+
+ @Insert
+ fun insertAll(gradesStatistics: List)
+
+ @Delete
+ fun deleteAll(gradesStatistics: List)
+
+ @Query("SELECT * FROM GradesStatistics WHERE student_id = :studentId AND semester_id = :semesterId AND subject = :subjectName AND is_semester = :isSemester")
+ fun loadSubject(semesterId: Int, studentId: Int, subjectName: String, isSemester: Boolean): Maybe>
+
+ @Query("SELECT * FROM GradesStatistics WHERE student_id = :studentId AND semester_id = :semesterId AND is_semester = :isSemester")
+ fun loadAll(semesterId: Int, studentId: Int, isSemester: Boolean): Maybe>
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/GradeSummaryDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/GradeSummaryDao.kt
index 3530118c..3f2e87bd 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/GradeSummaryDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/GradeSummaryDao.kt
@@ -18,6 +18,6 @@ interface GradeSummaryDao {
@Delete
fun deleteAll(gradesSummary: List)
- @Query("SELECT * FROM grades_summary WHERE student_id = :studentId AND semester_id = :semesterId")
+ @Query("SELECT * FROM GradesSummary WHERE student_id = :studentId AND semester_id = :semesterId")
fun loadAll(semesterId: Int, studentId: Int): Maybe>
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/HomeworkDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/HomeworkDao.kt
index 4127460f..253bdb11 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/HomeworkDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/HomeworkDao.kt
@@ -19,6 +19,6 @@ interface HomeworkDao {
@Delete
fun deleteAll(homework: List)
- @Query("SELECT * FROM Homework WHERE semester_id = :semesterId AND student_id = :studentId AND date = :date")
- fun loadAll(semesterId: Int, studentId: Int, date: LocalDate): Maybe>
+ @Query("SELECT * FROM Homework WHERE semester_id = :semesterId AND student_id = :studentId AND date >= :from AND date <= :end")
+ fun loadAll(semesterId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe>
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/LuckyNumberDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/LuckyNumberDao.kt
new file mode 100644
index 00000000..afd7905c
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/LuckyNumberDao.kt
@@ -0,0 +1,29 @@
+package io.github.wulkanowy.data.db.dao
+
+import androidx.room.Dao
+import androidx.room.Delete
+import androidx.room.Insert
+import androidx.room.Query
+import androidx.room.Update
+import io.github.wulkanowy.data.db.entities.LuckyNumber
+import io.reactivex.Maybe
+import org.threeten.bp.LocalDate
+import javax.inject.Singleton
+
+@Singleton
+@Dao
+interface LuckyNumberDao {
+
+ @Insert
+ fun insert(luckyNumber: LuckyNumber)
+
+ @Update
+ fun update(luckyNumber: LuckyNumber)
+
+ @Delete
+ fun delete(luckyNumber: LuckyNumber)
+
+ @Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date = :date")
+ fun load(studentId: Int, date: LocalDate): Maybe
+
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt
index 5018b690..3ef5d690 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt
@@ -12,26 +12,20 @@ import io.reactivex.Maybe
interface MessagesDao {
@Insert
- fun insertAll(messages: List): List
+ fun insertAll(messages: List)
@Delete
fun deleteAll(messages: List)
- @Update
- fun update(message: Message)
-
@Update
fun updateAll(messages: List)
- @Query("SELECT * FROM Messages WHERE student_id = :studentId AND real_id = :id")
- fun loadOne(studentId: Int, id: Int): Maybe
+ @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>
- @Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder ORDER BY date DESC")
- fun load(studentId: Int, folder: Int): Maybe>
+ @Query("SELECT * FROM Messages WHERE student_id = :studentId AND real_id = :id")
+ fun load(studentId: Int, id: Int): Maybe
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND removed = 1 ORDER BY date DESC")
fun loadDeleted(studentId: Int): Maybe>
-
- @Query("SELECT * FROM Messages WHERE unread = 1 AND student_id = :studentId")
- fun loadNewMessages(studentId: Int): Maybe>
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/NoteDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/NoteDao.kt
index 2c182860..867e06a2 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/NoteDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/NoteDao.kt
@@ -16,18 +16,13 @@ interface NoteDao {
@Insert
fun insertAll(notes: List)
- @Update
- fun update(note: Note)
-
@Update
fun updateAll(notes: List)
@Delete
fun deleteAll(notes: List)
- @Query("SELECT * FROM Notes WHERE semester_id = :semesterId AND student_id = :studentId")
- fun loadAll(semesterId: Int, studentId: Int): Maybe>
+ @Query("SELECT * FROM Notes WHERE student_id = :studentId")
+ fun loadAll(studentId: Int): Maybe>
- @Query("SELECT * FROM Notes WHERE is_read = 0 AND semester_id = :semesterId AND student_id = :studentId")
- fun loadNew(semesterId: Int, studentId: Int): Maybe>
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/RecipientDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/RecipientDao.kt
new file mode 100644
index 00000000..7c5fd6ca
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/RecipientDao.kt
@@ -0,0 +1,23 @@
+package io.github.wulkanowy.data.db.dao
+
+import androidx.room.Dao
+import androidx.room.Delete
+import androidx.room.Insert
+import androidx.room.Query
+import io.github.wulkanowy.data.db.entities.Recipient
+import io.reactivex.Maybe
+import javax.inject.Singleton
+
+@Singleton
+@Dao
+interface RecipientDao {
+
+ @Insert
+ fun insertAll(messages: List)
+
+ @Delete
+ fun deleteAll(messages: List)
+
+ @Query("SELECT * FROM Recipients WHERE student_id = :studentId AND role = :role AND unit_id = :unitId")
+ fun load(studentId: Int, role: Int, unitId: Int): Maybe>
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/ReportingUnitDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/ReportingUnitDao.kt
new file mode 100644
index 00000000..1898390a
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/ReportingUnitDao.kt
@@ -0,0 +1,26 @@
+package io.github.wulkanowy.data.db.dao
+
+import androidx.room.Dao
+import androidx.room.Delete
+import androidx.room.Insert
+import androidx.room.Query
+import io.github.wulkanowy.data.db.entities.ReportingUnit
+import io.reactivex.Maybe
+import javax.inject.Singleton
+
+@Singleton
+@Dao
+interface ReportingUnitDao {
+
+ @Insert
+ fun insertAll(reportingUnits: List)
+
+ @Delete
+ fun deleteAll(reportingUnits: List)
+
+ @Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId")
+ fun load(studentId: Int): Maybe>
+
+ @Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId AND real_id = :unitId")
+ fun loadOne(studentId: Int, unitId: Int): Maybe
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt
index 76e29539..c0c054c8 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt
@@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
-import androidx.room.OnConflictStrategy.FAIL
+import androidx.room.OnConflictStrategy.ABORT
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Student
import io.reactivex.Maybe
@@ -13,7 +13,7 @@ import javax.inject.Singleton
@Dao
interface StudentDao {
- @Insert(onConflict = FAIL)
+ @Insert(onConflict = ABORT)
fun insert(student: Student): Long
@Delete
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Attendance.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Attendance.kt
index 7588201b..3c58971a 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Attendance.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Attendance.kt
@@ -10,30 +10,30 @@ import java.io.Serializable
data class Attendance(
@ColumnInfo(name = "student_id")
- var studentId: Int,
+ val studentId: Int,
@ColumnInfo(name = "diary_id")
- var diaryId: Int,
+ val diaryId: Int,
- var date: LocalDate,
+ val date: LocalDate,
- var number: Int,
+ val number: Int,
- var subject: String,
+ val subject: String,
- var name: String,
+ val name: String,
- var presence: Boolean = false,
+ val presence: Boolean,
- var absence: Boolean = false,
+ val absence: Boolean,
- var exemption: Boolean = false,
+ val exemption: Boolean,
- var lateness: Boolean = false,
+ val lateness: Boolean,
- var excused: Boolean = false,
+ val excused: Boolean,
- var deleted: Boolean = false
+ val deleted: Boolean
) : Serializable {
@PrimaryKey(autoGenerate = true)
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/AttendanceSummary.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/AttendanceSummary.kt
index de2de98f..d2e1f174 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/AttendanceSummary.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/AttendanceSummary.kt
@@ -10,13 +10,13 @@ import java.io.Serializable
data class AttendanceSummary(
@ColumnInfo(name = "student_id")
- var studentId: Int,
+ val studentId: Int,
@ColumnInfo(name = "diary_id")
- var diaryId: Int,
+ val diaryId: Int,
@ColumnInfo(name = "subject_id")
- var subjectId: Int = 0,
+ val subjectId: Int,
val month: Month,
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/CompletedLesson.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/CompletedLesson.kt
new file mode 100644
index 00000000..775f3f55
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/CompletedLesson.kt
@@ -0,0 +1,40 @@
+package io.github.wulkanowy.data.db.entities
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import org.threeten.bp.LocalDate
+import java.io.Serializable
+
+@Entity(tableName = "CompletedLesson")
+data class CompletedLesson(
+
+ @ColumnInfo(name = "student_id")
+ val studentId: Int,
+
+ @ColumnInfo(name = "diary_id")
+ val diaryId: Int,
+
+ val date: LocalDate,
+
+ val number: Int,
+
+ val subject: String,
+
+ val topic: String,
+
+ val teacher: String,
+
+ @ColumnInfo(name = "teacher_symbol")
+ val teacherSymbol: String,
+
+ val substitution: String,
+
+ val absence: String,
+
+ val resources: String
+) : Serializable {
+
+ @PrimaryKey(autoGenerate = true)
+ var id: Long = 0
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Exam.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Exam.kt
index daa886d5..9ae795e7 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Exam.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Exam.kt
@@ -9,29 +9,29 @@ import java.io.Serializable
@Entity(tableName = "Exams")
data class Exam(
- @ColumnInfo(name = "student_id")
- var studentId: Int,
+ @ColumnInfo(name = "student_id")
+ val studentId: Int,
- @ColumnInfo(name = "diary_id")
- var diaryId: Int,
+ @ColumnInfo(name = "diary_id")
+ val diaryId: Int,
- var date: LocalDate,
+ val date: LocalDate,
- @ColumnInfo(name = "entry_date")
- var entryDate: LocalDate = LocalDate.now(),
+ @ColumnInfo(name = "entry_date")
+ val entryDate: LocalDate,
- var subject: String,
+ val subject: String,
- var group: String,
+ val group: String,
- var type: String,
+ val type: String,
- var description: String,
+ val description: String,
- var teacher: String,
+ val teacher: String,
- @ColumnInfo(name = "teacher_symbol")
- var teacherSymbol: String
+ @ColumnInfo(name = "teacher_symbol")
+ val teacherSymbol: String
) : Serializable {
@PrimaryKey(autoGenerate = true)
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Grade.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Grade.kt
index d665f9d2..1221a7aa 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Grade.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Grade.kt
@@ -10,35 +10,35 @@ import java.io.Serializable
data class Grade(
@ColumnInfo(name = "semester_id")
- var semesterId: Int,
+ val semesterId: Int,
@ColumnInfo(name = "student_id")
- var studentId: Int,
+ val studentId: Int,
- var subject: String,
+ val subject: String,
- var entry: String,
+ val entry: String,
- var value: Int,
+ val value: Int,
- var modifier: Double,
+ val modifier: Double,
- var comment: String,
+ val comment: String,
- var color: String,
+ val color: String,
@ColumnInfo(name = "grade_symbol")
- var gradeSymbol: String,
+ val gradeSymbol: String,
- var description: String,
+ val description: String,
- var weight: String,
+ val weight: String,
- var weightValue: Int,
+ val weightValue: Double,
- var date: LocalDate,
+ val date: LocalDate,
- var teacher: String
+ val teacher: String
) : Serializable {
@PrimaryKey(autoGenerate = true)
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/GradeStatistics.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/GradeStatistics.kt
new file mode 100644
index 00000000..8ad8b8b8
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/GradeStatistics.kt
@@ -0,0 +1,27 @@
+package io.github.wulkanowy.data.db.entities
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+@Entity(tableName = "GradesStatistics")
+data class GradeStatistics(
+
+ @ColumnInfo(name = "student_id")
+ val studentId: Int,
+
+ @ColumnInfo(name = "semester_id")
+ val semesterId: Int,
+
+ val subject: String,
+
+ val grade: Int,
+
+ val amount: Int,
+
+ @ColumnInfo(name = "is_semester")
+ val semester: Boolean
+) {
+ @PrimaryKey(autoGenerate = true)
+ var id: Long = 0
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/GradeSummary.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/GradeSummary.kt
index 74d709bb..e6ac4926 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/GradeSummary.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/GradeSummary.kt
@@ -4,22 +4,21 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
-@Entity(tableName = "Grades_Summary")
+@Entity(tableName = "GradesSummary")
data class GradeSummary(
- @ColumnInfo(name = "semester_id")
- var semesterId: Int,
+ @ColumnInfo(name = "semester_id")
+ val semesterId: Int,
- @ColumnInfo(name = "student_id")
- var studentId: Int,
+ @ColumnInfo(name = "student_id")
+ val studentId: Int,
- var subject: String,
+ val subject: String,
- var predictedGrade: String,
+ val predictedGrade: String,
- var finalGrade: String
+ val finalGrade: String
) {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
-
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Homework.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Homework.kt
index 705d1d63..a22df096 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Homework.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Homework.kt
@@ -10,24 +10,24 @@ import java.io.Serializable
data class Homework(
@ColumnInfo(name = "semester_id")
- var semesterId: Int,
+ val semesterId: Int,
@ColumnInfo(name = "student_id")
- var studentId: Int,
+ val studentId: Int,
- var date: LocalDate,
+ val date: LocalDate,
@ColumnInfo(name = "entry_date")
- var entryDate: LocalDate,
+ val entryDate: LocalDate,
- var subject: String,
+ val subject: String,
- var content: String,
+ val content: String,
- var teacher: String,
+ val teacher: String,
@ColumnInfo(name = "teacher_symbol")
- var teacherSymbol: String
+ val teacherSymbol: String
) : Serializable {
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/LuckyNumber.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/LuckyNumber.kt
new file mode 100644
index 00000000..5b9130f5
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/LuckyNumber.kt
@@ -0,0 +1,27 @@
+package io.github.wulkanowy.data.db.entities
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import org.threeten.bp.LocalDate
+import java.io.Serializable
+
+@Entity(tableName = "LuckyNumbers")
+data class LuckyNumber (
+
+ @ColumnInfo(name = "student_id")
+ val studentId: Int,
+
+ val date: LocalDate,
+
+ @ColumnInfo(name = "lucky_number")
+ val luckyNumber: Int
+
+) : Serializable {
+
+ @PrimaryKey(autoGenerate = true)
+ var id: Long = 0
+
+ @ColumnInfo(name = "is_notified")
+ var isNotified: Boolean = true
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt
index 320e9322..48b4fd02 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt
@@ -10,40 +10,39 @@ import java.io.Serializable
data class Message(
@ColumnInfo(name = "student_id")
- var studentId: Int? = null,
+ val studentId: Int,
@ColumnInfo(name = "real_id")
- val realId: Int? = null,
+ val realId: Int,
@ColumnInfo(name = "message_id")
- val messageId: Int? = null,
+ val messageId: Int,
@ColumnInfo(name = "sender_name")
- val sender: String? = null,
+ val sender: String,
@ColumnInfo(name = "sender_id")
- val senderId: Int? = null,
-
- @ColumnInfo(name = "recipient_id")
- val recipientId: Int? = null,
+ val senderId: Int,
@ColumnInfo(name = "recipient_name")
- val recipient: String? = "",
+ val recipient: String,
- val subject: String = "",
+ val subject: String,
- val date: LocalDateTime? = null,
+ val date: LocalDateTime,
@ColumnInfo(name = "folder_id")
- val folderId: Int = 0,
+ val folderId: Int,
- var unread: Boolean? = false,
+ var unread: Boolean,
- val unreadBy: Int? = 0,
+ @ColumnInfo(name = "unread_by")
+ val unreadBy: Int,
- val readBy: Int? = 0,
+ @ColumnInfo(name = "read_by")
+ val readBy: Int,
- val removed: Boolean = false
+ val removed: Boolean
) : Serializable {
@PrimaryKey(autoGenerate = true)
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Note.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Note.kt
index 1f61f087..5f3a92ab 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Note.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Note.kt
@@ -9,26 +9,23 @@ import java.io.Serializable
@Entity(tableName = "Notes")
data class Note(
- @ColumnInfo(name = "semester_id")
- var semesterId: Int,
-
@ColumnInfo(name = "student_id")
- var studentId: Int,
+ val studentId: Int,
- var date: LocalDate,
+ val date: LocalDate,
- var teacher: String,
+ val teacher: String,
- var category: String,
+ val category: String,
- var content: String
+ val content: String
) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
@ColumnInfo(name = "is_read")
- var isRead: Boolean = false
+ var isRead: Boolean = true
@ColumnInfo(name = "is_notified")
var isNotified: Boolean = true
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Recipient.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Recipient.kt
new file mode 100644
index 00000000..3021da72
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Recipient.kt
@@ -0,0 +1,38 @@
+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 = "Recipients")
+data class Recipient(
+
+ @ColumnInfo(name = "student_id")
+ val studentId: Int,
+
+ @ColumnInfo(name = "real_id")
+ val realId: String,
+
+ val name: String,
+
+ @ColumnInfo(name = "real_name")
+ val realName: String,
+
+ @ColumnInfo(name = "login_id")
+ val loginId: Int,
+
+ @ColumnInfo(name = "unit_id")
+ val unitId: Int,
+
+ val role: Int,
+
+ val hash: String
+
+) : Serializable {
+
+ @PrimaryKey(autoGenerate = true)
+ var id: Long = 0
+
+ override fun toString() = name
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/ReportingUnit.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/ReportingUnit.kt
new file mode 100644
index 00000000..601d8aac
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/ReportingUnit.kt
@@ -0,0 +1,32 @@
+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 = "ReportingUnits")
+data class ReportingUnit(
+
+ @ColumnInfo(name = "student_id")
+ val studentId: Int,
+
+ @ColumnInfo(name = "real_id")
+ val realId: Int,
+
+ @ColumnInfo(name = "short")
+ val shortName: String,
+
+ @ColumnInfo(name = "sender_id")
+ val senderId: Int,
+
+ @ColumnInfo(name = "sender_name")
+ val senderName: String,
+
+ val roles: List
+
+) : Serializable {
+
+ @PrimaryKey(autoGenerate = true)
+ var id: Long = 0
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Semester.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Semester.kt
index 509a692e..0f44fa2d 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Semester.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Semester.kt
@@ -8,24 +8,31 @@ import androidx.room.PrimaryKey
@Entity(tableName = "Semesters", indices = [Index(value = ["student_id", "diary_id", "semester_id"], unique = true)])
data class Semester(
- @PrimaryKey(autoGenerate = true)
- var id: Long = 0,
-
@ColumnInfo(name = "student_id")
- var studentId: Int,
+ val studentId: Int,
@ColumnInfo(name = "diary_id")
- var diaryId: Int,
+ val diaryId: Int,
@ColumnInfo(name = "diary_name")
- var diaryName: String,
+ val diaryName: String,
@ColumnInfo(name = "semester_id")
- var semesterId: Int,
+ val semesterId: Int,
@ColumnInfo(name = "semester_name")
- var semesterName: Int,
+ val semesterName: Int,
@ColumnInfo(name = "is_current")
- var isCurrent: Boolean = false
-)
+ val isCurrent: Boolean,
+
+ @ColumnInfo(name = "class_id")
+ val classId: Int,
+
+ @ColumnInfo(name = "unit_id")
+ val unitId: Int
+) {
+
+ @PrimaryKey(autoGenerate = true)
+ var id: Long = 0
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Student.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Student.kt
index 1fe4cf8d..261b35fb 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Student.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Student.kt
@@ -4,35 +4,41 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
+import org.threeten.bp.LocalDateTime
+import java.io.Serializable
@Entity(tableName = "Students", indices = [Index(value = ["email", "symbol", "student_id", "school_id"], unique = true)])
data class Student(
- @PrimaryKey(autoGenerate = true)
- var id: Long = 0,
+ val endpoint: String,
- var endpoint: String,
+ val loginType: String,
- var loginType: String,
-
- var email: String,
+ val email: String,
var password: String,
- var symbol: String = "",
+ val symbol: String,
@ColumnInfo(name = "student_id")
- var studentId: Int = 0,
+ val studentId: Int,
@ColumnInfo(name = "student_name")
- var studentName: String = "",
+ val studentName: String,
@ColumnInfo(name = "school_id")
- var schoolSymbol: String = "",
+ val schoolSymbol: String,
@ColumnInfo(name = "school_name")
- var schoolName: String = "",
+ val schoolName: String,
@ColumnInfo(name = "is_current")
- var isCurrent: Boolean = false
-)
+ val isCurrent: Boolean,
+
+ @ColumnInfo(name = "registration_date")
+ val registrationDate: LocalDateTime
+) : Serializable {
+
+ @PrimaryKey(autoGenerate = true)
+ var id: Long = 0
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Subject.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Subject.kt
index 45306be3..dbaa6f4e 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Subject.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Subject.kt
@@ -9,15 +9,15 @@ import java.io.Serializable
data class Subject(
@ColumnInfo(name = "student_id")
- var studentId: Int,
+ val studentId: Int,
@ColumnInfo(name = "diary_id")
- var diaryId: Int,
+ val diaryId: Int,
@ColumnInfo(name = "real_id")
- var realId: Int,
+ val realId: Int,
- var name: String
+ val name: String
) : Serializable {
@PrimaryKey(autoGenerate = true)
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Timetable.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Timetable.kt
index 2aa1eafa..9bc3d214 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Timetable.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Timetable.kt
@@ -10,33 +10,39 @@ import java.io.Serializable
@Entity(tableName = "Timetable")
data class Timetable(
- @ColumnInfo(name = "student_id")
- var studentId: Int,
+ @ColumnInfo(name = "student_id")
+ val studentId: Int,
- @ColumnInfo(name = "diary_id")
- var diaryId: Int,
+ @ColumnInfo(name = "diary_id")
+ val diaryId: Int,
- val number: Int = 0,
+ val number: Int,
- val start: LocalDateTime = LocalDateTime.now(),
+ val start: LocalDateTime,
- val end: LocalDateTime = LocalDateTime.now(),
+ val end: LocalDateTime,
- val date: LocalDate,
+ val date: LocalDate,
- val subject: String,
+ val subject: String,
- val group: String,
+ val subjectOld: String,
- val room: String,
+ val group: String,
- val teacher: String,
+ val room: String,
- val info: String,
+ val roomOld: String,
- val changes: Boolean = false,
+ val teacher: String,
- val canceled: Boolean = false
+ val teacherOld: String,
+
+ val info: String,
+
+ val changes: Boolean,
+
+ val canceled: Boolean
) : Serializable {
@PrimaryKey(autoGenerate = true)
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration10.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration10.kt
new file mode 100644
index 00000000..c26a02d1
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration10.kt
@@ -0,0 +1,11 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class Migration10 : Migration(9, 10) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("ALTER TABLE Grades_Summary RENAME TO GradesSummary")
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration11.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration11.kt
new file mode 100644
index 00000000..cb437c0e
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration11.kt
@@ -0,0 +1,34 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class Migration11 : Migration(10, 11) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("""
+ CREATE TABLE IF NOT EXISTS Grades_temp (
+ id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ is_read INTEGER NOT NULL,
+ is_notified INTEGER NOT NULL,
+ semester_id INTEGER NOT NULL,
+ student_id INTEGER NOT NULL,
+ subject TEXT NOT NULL,
+ entry TEXT NOT NULL,
+ value INTEGER NOT NULL,
+ modifier REAL NOT NULL,
+ comment TEXT NOT NULL,
+ color TEXT NOT NULL,
+ grade_symbol TEXT NOT NULL,
+ description TEXT NOT NULL,
+ weight TEXT NOT NULL,
+ weightValue REAL NOT NULL,
+ date INTEGER NOT NULL,
+ teacher TEXT NOT NULL
+ )
+ """)
+ database.execSQL("INSERT INTO Grades_temp SELECT * FROM Grades")
+ database.execSQL("DROP TABLE Grades")
+ database.execSQL("ALTER TABLE Grades_temp RENAME TO Grades")
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration2.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration2.kt
new file mode 100644
index 00000000..c5a30991
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration2.kt
@@ -0,0 +1,18 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class Migration2 : Migration(1, 2) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("""
+ CREATE TABLE IF NOT EXISTS LuckyNumbers (
+ id INTEGER PRIMARY KEY NOT NULL,
+ is_notified INTEGER NOT NULL,
+ student_id INTEGER NOT NULL,
+ date INTEGER NOT NULL,
+ lucky_number INTEGER NOT NULL)
+ """)
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration3.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration3.kt
new file mode 100644
index 00000000..d9699c0f
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration3.kt
@@ -0,0 +1,25 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class Migration3 : Migration(2, 3) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("""
+ CREATE TABLE IF NOT EXISTS CompletedLesson (
+ id INTEGER PRIMARY KEY NOT NULL,
+ student_id INTEGER NOT NULL,
+ diary_id INTEGER NOT NULL,
+ date INTEGER NOT NULL,
+ number INTEGER NOT NULL,
+ subject TEXT NOT NULL,
+ topic TEXT NOT NULL,
+ teacher TEXT NOT NULL,
+ teacher_symbol TEXT NOT NULL,
+ substitution TEXT NOT NULL,
+ absence TEXT NOT NULL,
+ resources TEXT NOT NULL)
+ """)
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration4.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration4.kt
new file mode 100644
index 00000000..0ae89bdd
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration4.kt
@@ -0,0 +1,31 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class Migration4 : Migration(3, 4) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("DROP TABLE IF EXISTS Messages")
+ database.execSQL("""
+ CREATE TABLE IF NOT EXISTS Messages (
+ id INTEGER PRIMARY KEY NOT NULL,
+ is_notified INTEGER NOT NULL,
+ content TEXT,
+ student_id INTEGER NOT NULL,
+ real_id INTEGER NOT NULL,
+ message_id INTEGER NOT NULL,
+ sender_name TEXT NOT NULL,
+ sender_id INTEGER NOT NULL,
+ recipient_id INTEGER NOT NULL,
+ recipient_name TEXT NOT NULL,
+ subject TEXT NOT NULL,
+ date INTEGER NOT NULL,
+ folder_id INTEGER NOT NULL,
+ unread INTEGER NOT NULL,
+ unreadBy INTEGER NOT NULL,
+ readBy INTEGER NOT NULL,
+ removed INTEGER NOT NULL)
+ """)
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration5.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration5.kt
new file mode 100644
index 00000000..fe0dec48
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration5.kt
@@ -0,0 +1,26 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+import org.threeten.bp.LocalDateTime.now
+import org.threeten.bp.ZoneOffset
+
+class Migration5 : Migration(4, 5) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("ALTER TABLE Students ADD COLUMN registration_date INTEGER DEFAULT 0 NOT NULL")
+ database.execSQL("UPDATE Students SET registration_date = '${now().atZone(ZoneOffset.UTC).toInstant().toEpochMilli()}'")
+ database.execSQL("DROP TABLE IF EXISTS Notes")
+ database.execSQL("""
+ CREATE TABLE IF NOT EXISTS Notes (
+ id INTEGER PRIMARY KEY NOT NULL,
+ is_read INTEGER NOT NULL,
+ is_notified INTEGER NOT NULL,
+ student_id INTEGER NOT NULL,
+ date INTEGER NOT NULL,
+ teacher TEXT NOT NULL,
+ category TEXT NOT NULL,
+ content TEXT NOT NULL)
+ """)
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration6.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration6.kt
new file mode 100644
index 00000000..fa943618
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration6.kt
@@ -0,0 +1,37 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class Migration6 : Migration(5, 6) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("""
+ CREATE TABLE IF NOT EXISTS ReportingUnits (
+ id INTEGER PRIMARY KEY NOT NULL,
+ student_id INTEGER NOT NULL,
+ real_id INTEGER NOT NULL,
+ short TEXT NOT NULL,
+ sender_id INTEGER NOT NULL,
+ sender_name TEXT NOT NULL,
+ roles TEXT NOT NULL)
+ """)
+
+ database.execSQL("""
+ CREATE TABLE IF NOT EXISTS Recipients (
+ id INTEGER PRIMARY KEY NOT NULL,
+ student_id INTEGER NOT NULL,
+ real_id TEXT NOT NULL,
+ name TEXT NOT NULL,
+ real_name TEXT NOT NULL,
+ login_id INTEGER NOT NULL,
+ unit_id INTEGER NOT NULL,
+ role INTEGER NOT NULL,
+ hash TEXT NOT NULL)
+ """)
+
+ database.execSQL("DELETE FROM Semesters WHERE 1")
+ database.execSQL("ALTER TABLE Semesters ADD COLUMN class_id INTEGER DEFAULT 0 NOT NULL")
+ database.execSQL("ALTER TABLE Semesters ADD COLUMN unit_id INTEGER DEFAULT 0 NOT NULL")
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration7.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration7.kt
new file mode 100644
index 00000000..120716c8
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration7.kt
@@ -0,0 +1,20 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class Migration7 : Migration(6, 7) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("""
+ CREATE TABLE IF NOT EXISTS GradesStatistics (
+ id INTEGER PRIMARY KEY NOT NULL,
+ student_id INTEGER NOT NULL,
+ semester_id INTEGER NOT NULL,
+ subject TEXT NOT NULL,
+ grade INTEGER NOT NULL,
+ amount INTEGER NOT NULL,
+ is_semester INTEGER NOT NULL)
+ """)
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration8.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration8.kt
new file mode 100644
index 00000000..7009ee12
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration8.kt
@@ -0,0 +1,13 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class Migration8 : Migration(7, 8) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("ALTER TABLE Timetable ADD COLUMN subjectOld TEXT DEFAULT \"\" NOT NULL")
+ database.execSQL("ALTER TABLE Timetable ADD COLUMN roomOld TEXT DEFAULT \"\" NOT NULL")
+ database.execSQL("ALTER TABLE Timetable ADD COLUMN teacherOld TEXT DEFAULT \"\" NOT NULL")
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration9.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration9.kt
new file mode 100644
index 00000000..d79a5706
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration9.kt
@@ -0,0 +1,30 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class Migration9 : Migration(8, 9) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("DROP TABLE IF EXISTS Messages")
+ database.execSQL("""
+ CREATE TABLE IF NOT EXISTS Messages (
+ id INTEGER PRIMARY KEY NOT NULL,
+ student_id INTEGER NOT NULL,
+ real_id INTEGER NOT NULL,
+ message_id INTEGER NOT NULL,
+ sender_name TEXT NOT NULL,
+ sender_id INTEGER NOT NULL,
+ recipient_name TEXT NOT NULL,
+ subject TEXT NOT NULL,
+ date INTEGER NOT NULL,
+ folder_id INTEGER NOT NULL,
+ unread INTEGER NOT NULL,
+ unread_by INTEGER NOT NULL,
+ read_by INTEGER NOT NULL,
+ removed INTEGER NOT NULL,
+ is_notified INTEGER NOT NULL,
+ content TEXT)
+ """)
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/HomeworkRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/HomeworkRepository.kt
deleted file mode 100644
index a2a477b5..00000000
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/HomeworkRepository.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package io.github.wulkanowy.data.repositories
-
-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.repositories.local.HomeworkLocal
-import io.github.wulkanowy.data.repositories.remote.HomeworkRemote
-import io.reactivex.Single
-import org.threeten.bp.LocalDate
-import java.net.UnknownHostException
-import javax.inject.Inject
-import javax.inject.Singleton
-
-@Singleton
-class HomeworkRepository @Inject constructor(
- private val settings: InternetObservingSettings,
- private val local: HomeworkLocal,
- private val remote: HomeworkRemote
-) {
-
- fun getHomework(semester: Semester, date: LocalDate, forceRefresh: Boolean = false): Single> {
- return local.getHomework(semester, date).filter { !forceRefresh }
- .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
- .flatMap {
- if (it) remote.getHomework(semester, date)
- else Single.error(UnknownHostException())
- }.flatMap { newGrades ->
- local.getHomework(semester, date).toSingle(emptyList())
- .doOnSuccess { oldGrades ->
- local.deleteHomework(oldGrades - newGrades)
- local.saveHomework(newGrades - oldGrades)
- }
- }.flatMap { local.getHomework(semester, date).toSingle(emptyList()) })
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/MessagesRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/MessagesRepository.kt
deleted file mode 100644
index 06a0f6f9..00000000
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/MessagesRepository.kt
+++ /dev/null
@@ -1,79 +0,0 @@
-package io.github.wulkanowy.data.repositories
-
-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.Message
-import io.github.wulkanowy.data.db.entities.Student
-import io.github.wulkanowy.data.repositories.local.MessagesLocal
-import io.github.wulkanowy.data.repositories.remote.MessagesRemote
-import io.reactivex.Completable
-import io.reactivex.Single
-import java.net.UnknownHostException
-import javax.inject.Inject
-import javax.inject.Singleton
-
-@Singleton
-class MessagesRepository @Inject constructor(
- private val settings: InternetObservingSettings,
- private val local: MessagesLocal,
- private val remote: MessagesRemote
-) {
-
- enum class MessageFolder(val id: Int = 1) {
- RECEIVED(1),
- SENT(2),
- TRASHED(3)
- }
-
- fun getMessages(studentId: Int, folder: MessageFolder, forceRefresh: Boolean = false, notify: Boolean = false): Single> {
- return local.getMessages(studentId, folder).filter { !forceRefresh }
- .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
- .flatMap {
- if (it) remote.getMessages(studentId, folder)
- else Single.error(UnknownHostException())
- }.flatMap { new ->
- local.getMessages(studentId, folder).toSingle(emptyList())
- .doOnSuccess { old ->
- local.deleteMessages(old - new)
- local.saveMessages((new - old)
- .onEach {
- it.isNotified = !notify
- })
- }
- }.flatMap { local.getMessages(studentId, folder).toSingle(emptyList()) }
- )
- }
-
- fun getMessage(studentId: Int, messageId: Int, markAsRead: Boolean = false): Single {
- return local.getMessage(studentId, messageId)
- .filter { !it.content.isNullOrEmpty() }
- .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
- .flatMap {
- if (it) local.getMessage(studentId, messageId).toSingle()
- else Single.error(UnknownHostException())
- }
- .flatMap { dbMessage ->
- remote.getMessagesContent(dbMessage, markAsRead).doOnSuccess {
- local.updateMessage(dbMessage.copy(unread = false).apply {
- id = dbMessage.id
- content = it
- })
- }
- }.flatMap {
- local.getMessage(studentId, messageId).toSingle()
- }
- )
- }
-
- fun getNewMessages(student: Student): Single> {
- return local.getNewMessages(student).toSingle(emptyList())
- }
-
- fun updateMessage(message: Message): Completable {
- return Completable.fromCallable { local.updateMessage(message) }
- }
-
- fun updateMessages(messages: List): Completable {
- return Completable.fromCallable { local.updateMessages(messages) }
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/TimetableRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/TimetableRepository.kt
deleted file mode 100644
index 6cc6a043..00000000
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/TimetableRepository.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-package io.github.wulkanowy.data.repositories
-
-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.Timetable
-import io.github.wulkanowy.data.repositories.local.TimetableLocal
-import io.github.wulkanowy.data.repositories.remote.TimetableRemote
-import io.github.wulkanowy.utils.friday
-import io.github.wulkanowy.utils.monday
-import io.reactivex.Single
-import org.threeten.bp.LocalDate
-import java.net.UnknownHostException
-import javax.inject.Inject
-import javax.inject.Singleton
-
-@Singleton
-class TimetableRepository @Inject constructor(
- private val settings: InternetObservingSettings,
- private val local: TimetableLocal,
- private val remote: TimetableRemote
-) {
-
- fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false)
- : Single> {
- return Single.fromCallable { startDate.monday to endDate.friday }
- .flatMap { dates ->
- local.getTimetable(semester, dates.first, dates.second).filter { !forceRefresh }
- .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
- .flatMap {
- if (it) remote.getTimetable(semester, dates.first, dates.second)
- else Single.error(UnknownHostException())
- }.flatMap { newTimetable ->
- local.getTimetable(semester, dates.first, dates.second)
- .toSingle(emptyList())
- .doOnSuccess { oldTimetable ->
- local.deleteTimetable(oldTimetable - newTimetable)
- local.saveTimetable(newTimetable - oldTimetable)
- }
- }.flatMap {
- local.getTimetable(semester, dates.first, dates.second)
- .toSingle(emptyList())
- }).map { list -> list.filter { it.date in startDate..endDate } }
- }
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/AttendanceLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceLocal.kt
similarity index 82%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/local/AttendanceLocal.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceLocal.kt
index 9a318dba..0f587376 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/local/AttendanceLocal.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceLocal.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.local
+package io.github.wulkanowy.data.repositories.attendance
import io.github.wulkanowy.data.db.dao.AttendanceDao
import io.github.wulkanowy.data.db.entities.Attendance
@@ -6,14 +6,11 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import javax.inject.Inject
+import javax.inject.Singleton
+@Singleton
class AttendanceLocal @Inject constructor(private val attendanceDb: AttendanceDao) {
- fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe> {
- return attendanceDb.loadAll(semester.diaryId, semester.studentId, startDate, endDate)
- .filter { !it.isEmpty() }
- }
-
fun saveAttendance(attendance: List) {
attendanceDb.insertAll(attendance)
}
@@ -21,4 +18,8 @@ class AttendanceLocal @Inject constructor(private val attendanceDb: AttendanceDa
fun deleteAttendance(attendance: List) {
attendanceDb.deleteAll(attendance)
}
+
+ fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe> {
+ return attendanceDb.loadAll(semester.diaryId, semester.studentId, startDate, endDate).filter { it.isNotEmpty() }
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/AttendanceRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemote.kt
similarity index 95%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/remote/AttendanceRemote.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemote.kt
index 79047606..b3544c3f 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/AttendanceRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemote.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.remote
+package io.github.wulkanowy.data.repositories.attendance
import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Attendance
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRepository.kt
similarity index 91%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceRepository.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRepository.kt
index eb7230ae..f6eb07da 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRepository.kt
@@ -1,11 +1,9 @@
-package io.github.wulkanowy.data.repositories
+package io.github.wulkanowy.data.repositories.attendance
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.Semester
-import io.github.wulkanowy.data.repositories.local.AttendanceLocal
-import io.github.wulkanowy.data.repositories.remote.AttendanceRemote
import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.utils.monday
import io.reactivex.Single
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/AttendanceSummaryLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryLocal.kt
similarity index 82%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/local/AttendanceSummaryLocal.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryLocal.kt
index 2bb9f122..2e9a1006 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/local/AttendanceSummaryLocal.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryLocal.kt
@@ -1,17 +1,15 @@
-package io.github.wulkanowy.data.repositories.local
+package io.github.wulkanowy.data.repositories.attendancesummary
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe
import javax.inject.Inject
+import javax.inject.Singleton
+@Singleton
class AttendanceSummaryLocal @Inject constructor(private val attendanceDb: AttendanceSummaryDao) {
- fun getAttendanceSummary(semester: Semester, subjectId: Int): Maybe> {
- return attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId).filter { !it.isEmpty() }
- }
-
fun saveAttendanceSummary(attendance: List) {
attendanceDb.insertAll(attendance)
}
@@ -19,4 +17,8 @@ class AttendanceSummaryLocal @Inject constructor(private val attendanceDb: Atten
fun deleteAttendanceSummary(attendance: List) {
attendanceDb.deleteAll(attendance)
}
+
+ fun getAttendanceSummary(semester: Semester, subjectId: Int): Maybe> {
+ return attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId).filter { it.isNotEmpty() }
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/AttendanceSummaryRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRemote.kt
similarity index 95%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/remote/AttendanceSummaryRemote.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRemote.kt
index 079eb4b8..d38dd3a4 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/AttendanceSummaryRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRemote.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.remote
+package io.github.wulkanowy.data.repositories.attendancesummary
import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.AttendanceSummary
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceSummaryRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRepository.kt
similarity index 88%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceSummaryRepository.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRepository.kt
index 8e21b12c..90d39aab 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceSummaryRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRepository.kt
@@ -1,11 +1,9 @@
-package io.github.wulkanowy.data.repositories
+package io.github.wulkanowy.data.repositories.attendancesummary
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.Semester
-import io.github.wulkanowy.data.repositories.local.AttendanceSummaryLocal
-import io.github.wulkanowy.data.repositories.remote.AttendanceSummaryRemote
import io.reactivex.Single
import java.net.UnknownHostException
import javax.inject.Inject
@@ -18,7 +16,7 @@ class AttendanceSummaryRepository @Inject constructor(
private val remote: AttendanceSummaryRemote
) {
- fun getAttendanceSummary(semester: Semester, subjectId: Int, forceRefresh: Boolean = false): Single>? {
+ fun getAttendanceSummary(semester: Semester, subjectId: Int, forceRefresh: Boolean = false): Single> {
return local.getAttendanceSummary(semester, subjectId).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsLocal.kt
new file mode 100644
index 00000000..9b275908
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsLocal.kt
@@ -0,0 +1,25 @@
+package io.github.wulkanowy.data.repositories.completedlessons
+
+import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
+import io.github.wulkanowy.data.db.entities.CompletedLesson
+import io.github.wulkanowy.data.db.entities.Semester
+import io.reactivex.Maybe
+import org.threeten.bp.LocalDate
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class CompletedLessonsLocal @Inject constructor(private val completedLessonsDb: CompletedLessonsDao) {
+
+ fun saveCompletedLessons(completedLessons: List) {
+ completedLessonsDb.insertAll(completedLessons)
+ }
+
+ fun deleteCompleteLessons(completedLessons: List) {
+ completedLessonsDb.deleteAll(completedLessons)
+ }
+
+ fun getCompletedLessons(semester: Semester, start: LocalDate, end: LocalDate): Maybe> {
+ return completedLessonsDb.loadAll(semester.diaryId, semester.studentId, start, end).filter { it.isNotEmpty() }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRemote.kt
new file mode 100644
index 00000000..58dd5a9d
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRemote.kt
@@ -0,0 +1,37 @@
+package io.github.wulkanowy.data.repositories.completedlessons
+
+import io.github.wulkanowy.api.Api
+import io.github.wulkanowy.api.toLocalDate
+import io.github.wulkanowy.data.db.entities.CompletedLesson
+import io.github.wulkanowy.data.db.entities.Semester
+import io.reactivex.Single
+import org.threeten.bp.LocalDate
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class CompletedLessonsRemote @Inject constructor(private val api: Api) {
+
+ fun getCompletedLessons(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> {
+ return Single.just(api.apply { diaryId = semester.diaryId })
+ .flatMap { it.getCompletedLessons(startDate, endDate) }
+ .map { lessons ->
+ lessons.map {
+ it.absence
+ CompletedLesson(
+ studentId = semester.studentId,
+ diaryId = semester.diaryId,
+ date = it.date.toLocalDate(),
+ number = it.number,
+ subject = it.subject,
+ topic = it.topic,
+ teacher = it.teacher,
+ teacherSymbol = it.teacherSymbol,
+ substitution = it.substitution,
+ absence = it.absence,
+ resources = it.resources
+ )
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRepository.kt
new file mode 100644
index 00000000..5b594107
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRepository.kt
@@ -0,0 +1,43 @@
+package io.github.wulkanowy.data.repositories.completedlessons
+
+import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
+import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
+import io.github.wulkanowy.data.db.entities.CompletedLesson
+import io.github.wulkanowy.data.db.entities.Semester
+import io.github.wulkanowy.utils.friday
+import io.github.wulkanowy.utils.monday
+import io.reactivex.Single
+import org.threeten.bp.LocalDate
+import java.net.UnknownHostException
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class CompletedLessonsRepository @Inject constructor(
+ private val settings: InternetObservingSettings,
+ private val local: CompletedLessonsLocal,
+ private val remote: CompletedLessonsRemote
+) {
+
+ fun getCompletedLessons(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false): Single> {
+ 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 - new)
+ local.saveCompletedLessons(new - old)
+ }
+ }.flatMap {
+ local.getCompletedLessons(semester, dates.first, dates.second)
+ .toSingle(emptyList())
+ }).map { list -> list.filter { it.date in startDate..endDate } }
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/ExamLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamLocal.kt
similarity index 88%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/local/ExamLocal.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamLocal.kt
index 3e32a635..0f484d32 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/local/ExamLocal.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamLocal.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.local
+package io.github.wulkanowy.data.repositories.exam
import io.github.wulkanowy.data.db.dao.ExamDao
import io.github.wulkanowy.data.db.entities.Exam
@@ -6,7 +6,9 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import javax.inject.Inject
+import javax.inject.Singleton
+@Singleton
class ExamLocal @Inject constructor(private val examDb: ExamDao) {
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe> {
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/ExamRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRemote.kt
similarity index 92%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/remote/ExamRemote.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRemote.kt
index 3937b768..f6d653a6 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/ExamRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRemote.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.remote
+package io.github.wulkanowy.data.repositories.exam
import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Exam
@@ -7,7 +7,9 @@ import io.github.wulkanowy.utils.toLocalDate
import io.reactivex.Single
import org.threeten.bp.LocalDate
import javax.inject.Inject
+import javax.inject.Singleton
+@Singleton
class ExamRemote @Inject constructor(private val api: Api) {
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> {
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/ExamRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRepository.kt
similarity index 92%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/ExamRepository.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRepository.kt
index cb78df53..a0cb5ba1 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/ExamRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRepository.kt
@@ -1,11 +1,9 @@
-package io.github.wulkanowy.data.repositories
+package io.github.wulkanowy.data.repositories.exam
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Semester
-import io.github.wulkanowy.data.repositories.local.ExamLocal
-import io.github.wulkanowy.data.repositories.remote.ExamRemote
import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.utils.monday
import io.reactivex.Single
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/GradeLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeLocal.kt
similarity index 55%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/local/GradeLocal.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeLocal.kt
index d6d46340..4983a474 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/local/GradeLocal.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeLocal.kt
@@ -1,9 +1,8 @@
-package io.github.wulkanowy.data.repositories.local
+package io.github.wulkanowy.data.repositories.grade
import io.github.wulkanowy.data.db.dao.GradeDao
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.Semester
-import io.reactivex.Completable
import io.reactivex.Maybe
import javax.inject.Inject
import javax.inject.Singleton
@@ -11,27 +10,19 @@ import javax.inject.Singleton
@Singleton
class GradeLocal @Inject constructor(private val gradeDb: GradeDao) {
- fun getGrades(semester: Semester): Maybe> {
- return gradeDb.loadAll(semester.semesterId, semester.studentId).filter { !it.isEmpty() }
- }
-
- fun getNewGrades(semester: Semester): Maybe> {
- return gradeDb.loadAllNew(semester.semesterId, semester.studentId)
- }
-
fun saveGrades(grades: List) {
gradeDb.insertAll(grades)
}
- fun updateGrade(grade: Grade): Completable {
- return Completable.fromCallable { gradeDb.update(grade) }
- }
-
- fun updateGrades(grades: List): Completable {
- return Completable.fromCallable { gradeDb.updateAll(grades) }
- }
-
fun deleteGrades(grades: List) {
gradeDb.deleteAll(grades)
}
+
+ fun updateGrades(grades: List) {
+ gradeDb.updateAll(grades)
+ }
+
+ fun getGrades(semester: Semester): Maybe> {
+ return gradeDb.loadAll(semester.semesterId, semester.studentId).filter { it.isNotEmpty() }
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/GradeRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRemote.kt
similarity index 87%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/remote/GradeRemote.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRemote.kt
index df3bf4d2..570ab7a7 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/GradeRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRemote.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.remote
+package io.github.wulkanowy.data.repositories.grade
import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Grade
@@ -25,8 +25,8 @@ class GradeRemote @Inject constructor(private val api: Api) {
modifier = it.modifier,
comment = it.comment,
color = it.color,
- gradeSymbol = it.symbol ?: "",
- description = it.description,
+ gradeSymbol = it.symbol.orEmpty(),
+ description = it.description.orEmpty(),
weight = it.weight,
weightValue = it.weightValue,
date = it.date.toLocalDate(),
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/GradeRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRepository.kt
similarity index 56%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/GradeRepository.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRepository.kt
index 42266955..3dd456bf 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/GradeRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRepository.kt
@@ -1,11 +1,10 @@
-package io.github.wulkanowy.data.repositories
+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.Semester
-import io.github.wulkanowy.data.repositories.local.GradeLocal
-import io.github.wulkanowy.data.repositories.remote.GradeRemote
+import io.github.wulkanowy.data.db.entities.Student
import io.reactivex.Completable
import io.reactivex.Single
import java.net.UnknownHostException
@@ -19,7 +18,7 @@ class GradeRepository @Inject constructor(
private val remote: GradeRemote
) {
- fun getGrades(semester: Semester, forceRefresh: Boolean = false, notify: Boolean = false): Single> {
+ fun getGrades(student: Student, semester: Semester, forceRefresh: Boolean = false, notify: Boolean = false): Single> {
return local.getGrades(semester).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
@@ -28,25 +27,33 @@ class GradeRepository @Inject constructor(
}.flatMap { newGrades ->
local.getGrades(semester).toSingle(emptyList())
.doOnSuccess { oldGrades ->
+ val notifyBreakDate = oldGrades.maxBy { it.date }?.date
+ ?: student.registrationDate.toLocalDate()
local.deleteGrades(oldGrades - newGrades)
local.saveGrades((newGrades - oldGrades)
.onEach {
- if (oldGrades.isNotEmpty()) it.isRead = false
- if (notify) it.isNotified = false
+ if (it.date >= notifyBreakDate) it.apply {
+ isRead = false
+ if (notify) isNotified = false
+ }
})
}
}.flatMap { local.getGrades(semester).toSingle(emptyList()) })
}
- fun getNewGrades(semester: Semester): Single> {
- return local.getNewGrades(semester).toSingle(emptyList())
+ fun getUnreadGrades(semester: Semester): Single> {
+ return local.getGrades(semester).map { it.filter { grade -> !grade.isRead } }.toSingle(emptyList())
+ }
+
+ fun getNotNotifiedGrades(semester: Semester): Single> {
+ return local.getGrades(semester).map { it.filter { grade -> !grade.isNotified } }.toSingle(emptyList())
}
fun updateGrade(grade: Grade): Completable {
- return local.updateGrade(grade)
+ return Completable.fromCallable { local.updateGrades(listOf(grade)) }
}
fun updateGrades(grades: List): Completable {
- return local.updateGrades(grades)
+ return Completable.fromCallable { local.updateGrades(grades) }
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/GradeSummaryLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryLocal.kt
similarity index 87%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/local/GradeSummaryLocal.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryLocal.kt
index 6a72416d..e74641d3 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/local/GradeSummaryLocal.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryLocal.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.local
+package io.github.wulkanowy.data.repositories.gradessummary
import io.github.wulkanowy.data.db.dao.GradeSummaryDao
import io.github.wulkanowy.data.db.entities.GradeSummary
@@ -10,11 +10,6 @@ import javax.inject.Singleton
@Singleton
class GradeSummaryLocal @Inject constructor(private val gradeSummaryDb: GradeSummaryDao) {
- fun getGradesSummary(semester: Semester): Maybe> {
- return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)
- .filter { !it.isEmpty() }
- }
-
fun saveGradesSummary(gradesSummary: List) {
gradeSummaryDb.insertAll(gradesSummary)
}
@@ -22,4 +17,8 @@ class GradeSummaryLocal @Inject constructor(private val gradeSummaryDb: GradeSum
fun deleteGradesSummary(gradesSummary: List) {
gradeSummaryDb.deleteAll(gradesSummary)
}
+
+ fun getGradesSummary(semester: Semester): Maybe> {
+ return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).filter { it.isNotEmpty() }
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/GradeSummaryRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt
similarity index 94%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/remote/GradeSummaryRemote.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt
index af45ca73..d395decf 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/GradeSummaryRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.remote
+package io.github.wulkanowy.data.repositories.gradessummary
import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.GradeSummary
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/GradeSummaryRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRepository.kt
similarity index 88%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/GradeSummaryRepository.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRepository.kt
index a59a2cd5..b19e07f0 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/GradeSummaryRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRepository.kt
@@ -1,11 +1,9 @@
-package io.github.wulkanowy.data.repositories
+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.data.repositories.local.GradeSummaryLocal
-import io.github.wulkanowy.data.repositories.remote.GradeSummaryRemote
import io.reactivex.Single
import java.net.UnknownHostException
import javax.inject.Inject
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsLocal.kt
new file mode 100644
index 00000000..581ac2f8
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsLocal.kt
@@ -0,0 +1,34 @@
+package io.github.wulkanowy.data.repositories.gradestatistics
+
+import io.github.wulkanowy.data.db.dao.GradeStatisticsDao
+import io.github.wulkanowy.data.db.entities.GradeStatistics
+import io.github.wulkanowy.data.db.entities.Semester
+import io.reactivex.Maybe
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class GradeStatisticsLocal @Inject constructor(private val gradeStatisticsDb: GradeStatisticsDao) {
+
+ fun getGradesStatistics(semester: Semester, isSemester: Boolean): Maybe> {
+ return gradeStatisticsDb.loadAll(semester.semesterId, semester.studentId, isSemester)
+ .filter { !it.isEmpty() }
+ }
+
+ fun getGradesStatistics(semester: Semester, isSemester: Boolean, subjectName: String): Maybe> {
+ return (if ("Wszystkie" == subjectName) gradeStatisticsDb.loadAll(semester.semesterId, semester.studentId, isSemester).map { list ->
+ list.groupBy { it.grade }.map {
+ GradeStatistics(semester.studentId, semester.semesterId, subjectName, it.key, it.value.fold(0) { acc, e -> acc + e.amount }, false)
+ }
+ }
+ else gradeStatisticsDb.loadSubject(semester.semesterId, semester.studentId, subjectName, isSemester)).filter { !it.isEmpty() }
+ }
+
+ fun saveGradesStatistics(gradesStatistics: List) {
+ gradeStatisticsDb.insertAll(gradesStatistics)
+ }
+
+ fun deleteGradesStatistics(gradesStatistics: List) {
+ gradeStatisticsDb.deleteAll(gradesStatistics)
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRemote.kt
new file mode 100644
index 00000000..fa3b951f
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRemote.kt
@@ -0,0 +1,29 @@
+package io.github.wulkanowy.data.repositories.gradestatistics
+
+import io.github.wulkanowy.api.Api
+import io.github.wulkanowy.data.db.entities.GradeStatistics
+import io.github.wulkanowy.data.db.entities.Semester
+import io.reactivex.Single
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class GradeStatisticsRemote @Inject constructor(private val api: Api) {
+
+ fun getGradeStatistics(semester: Semester, isSemester: Boolean): Single> {
+ return Single.just(api.apply { diaryId = semester.diaryId })
+ .flatMap { it.getGradesStatistics(semester.semesterId, isSemester) }
+ .map { gradeStatistics ->
+ gradeStatistics.map {
+ GradeStatistics(
+ semesterId = semester.semesterId,
+ studentId = semester.studentId,
+ subject = it.subject,
+ grade = it.gradeValue,
+ amount = it.amount ?: 0,
+ semester = isSemester
+ )
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRepository.kt
new file mode 100644
index 00000000..870bd1e9
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRepository.kt
@@ -0,0 +1,33 @@
+package io.github.wulkanowy.data.repositories.gradestatistics
+
+import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
+import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
+import io.github.wulkanowy.data.db.entities.GradeStatistics
+import io.github.wulkanowy.data.db.entities.Semester
+import io.reactivex.Single
+import java.net.UnknownHostException
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class GradeStatisticsRepository @Inject constructor(
+ private val settings: InternetObservingSettings,
+ private val local: GradeStatisticsLocal,
+ private val remote: GradeStatisticsRemote
+) {
+
+ fun getGradesStatistics(semester: Semester, subjectName: String, isSemester: Boolean, forceRefresh: Boolean = false): Single> {
+ return local.getGradesStatistics(semester, isSemester, subjectName).filter { !forceRefresh }
+ .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
+ .flatMap {
+ if (it) remote.getGradeStatistics(semester, isSemester)
+ else Single.error(UnknownHostException())
+ }.flatMap { newGradesStats ->
+ local.getGradesStatistics(semester, isSemester).toSingle(emptyList())
+ .doOnSuccess { oldGradesStats ->
+ local.deleteGradesStatistics(oldGradesStats - newGradesStats)
+ local.saveGradesStatistics(newGradesStats - oldGradesStats)
+ }
+ }.flatMap { local.getGradesStatistics(semester, isSemester, subjectName).toSingle(emptyList()) })
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/HomeworkLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkLocal.kt
similarity index 73%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/local/HomeworkLocal.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkLocal.kt
index ea18d814..671ecafd 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/local/HomeworkLocal.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkLocal.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.local
+package io.github.wulkanowy.data.repositories.homework
import io.github.wulkanowy.data.db.dao.HomeworkDao
import io.github.wulkanowy.data.db.entities.Homework
@@ -11,10 +11,6 @@ import javax.inject.Singleton
@Singleton
class HomeworkLocal @Inject constructor(private val homeworkDb: HomeworkDao) {
- fun getHomework(semester: Semester, date: LocalDate): Maybe> {
- return homeworkDb.loadAll(semester.semesterId, semester.studentId, date).filter { !it.isEmpty() }
- }
-
fun saveHomework(homework: List) {
homeworkDb.insertAll(homework)
}
@@ -22,4 +18,9 @@ class HomeworkLocal @Inject constructor(private val homeworkDb: HomeworkDao) {
fun deleteHomework(homework: List) {
homeworkDb.deleteAll(homework)
}
+
+ fun getHomework(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe> {
+ return homeworkDb.loadAll(semester.semesterId, semester.studentId, startDate, endDate)
+ .filter { it.isNotEmpty() }
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/HomeworkRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRemote.kt
similarity index 82%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/remote/HomeworkRemote.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRemote.kt
index 0fdc0251..681b6646 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/HomeworkRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRemote.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.remote
+package io.github.wulkanowy.data.repositories.homework
import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Homework
@@ -12,9 +12,9 @@ import javax.inject.Singleton
@Singleton
class HomeworkRemote @Inject constructor(private val api: Api) {
- fun getHomework(semester: Semester, date: LocalDate): Single> {
+ fun getHomework(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> {
return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { it.getHomework(date, date) }
+ .flatMap { it.getHomework(startDate, endDate) }
.map { homework ->
homework.map {
Homework(
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRepository.kt
new file mode 100644
index 00000000..0447c86f
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRepository.kt
@@ -0,0 +1,38 @@
+package io.github.wulkanowy.data.repositories.homework
+
+import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
+import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
+import io.github.wulkanowy.data.db.entities.Homework
+import io.github.wulkanowy.data.db.entities.Semester
+import io.github.wulkanowy.utils.friday
+import io.github.wulkanowy.utils.monday
+import io.reactivex.Single
+import org.threeten.bp.LocalDate
+import java.net.UnknownHostException
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class HomeworkRepository @Inject constructor(
+ private val settings: InternetObservingSettings,
+ private val local: HomeworkLocal,
+ private val remote: HomeworkRemote
+) {
+
+ fun getHomework(semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single> {
+ 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)
+ else Single.error(UnknownHostException())
+ }.flatMap { newGrades ->
+ local.getHomework(semester, monday, friday).toSingle(emptyList())
+ .doOnSuccess { oldGrades ->
+ local.deleteHomework(oldGrades - newGrades)
+ local.saveHomework(newGrades - oldGrades)
+ }
+ }.flatMap { local.getHomework(semester, monday, friday).toSingle(emptyList()) })
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/MessagesLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/local/MessagesLocal.kt
deleted file mode 100644
index 531cd8b0..00000000
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/local/MessagesLocal.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package io.github.wulkanowy.data.repositories.local
-
-import io.github.wulkanowy.data.db.dao.MessagesDao
-import io.github.wulkanowy.data.db.entities.Message
-import io.github.wulkanowy.data.db.entities.Student
-import io.github.wulkanowy.data.repositories.MessagesRepository
-import io.reactivex.Maybe
-import javax.inject.Inject
-import javax.inject.Singleton
-
-@Singleton
-class MessagesLocal @Inject constructor(private val messagesDb: MessagesDao) {
-
- fun getMessage(studentId: Int, id: Int): Maybe {
- return messagesDb.loadOne(studentId, id)
- }
-
- fun getMessages(studentId: Int, folder: MessagesRepository.MessageFolder): Maybe> {
- return when (folder) {
- MessagesRepository.MessageFolder.TRASHED -> messagesDb.loadDeleted(studentId)
- else -> messagesDb.load(studentId, folder.id)
- }.filter { !it.isEmpty() }
- }
-
- fun getNewMessages(student: Student): Maybe> {
- return messagesDb.loadNewMessages(student.studentId)
- }
-
- fun saveMessages(messages: List): List {
- return messagesDb.insertAll(messages)
- }
-
- fun updateMessage(message: Message) {
- return messagesDb.update(message)
- }
-
- fun updateMessages(messages: List) {
- return messagesDb.updateAll(messages)
- }
-
- fun deleteMessages(messages: List) {
- messagesDb.deleteAll(messages)
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/NoteLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/local/NoteLocal.kt
deleted file mode 100644
index 543eab9b..00000000
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/local/NoteLocal.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-package io.github.wulkanowy.data.repositories.local
-
-import io.github.wulkanowy.data.db.dao.NoteDao
-import io.github.wulkanowy.data.db.entities.Note
-import io.github.wulkanowy.data.db.entities.Semester
-import io.reactivex.Completable
-import io.reactivex.Maybe
-import javax.inject.Inject
-import javax.inject.Singleton
-
-@Singleton
-class NoteLocal @Inject constructor(private val noteDb: NoteDao) {
-
- fun getNotes(semester: Semester): Maybe> {
- return noteDb.loadAll(semester.semesterId, semester.studentId).filter { !it.isEmpty() }
- }
-
- fun getNewNotes(semester: Semester): Maybe> {
- return noteDb.loadNew(semester.semesterId, semester.studentId)
- }
-
- fun saveNotes(notes: List) {
- noteDb.insertAll(notes)
- }
-
- fun updateNote(note: Note): Completable {
- return Completable.fromCallable { noteDb.update(note) }
- }
-
- fun updateNotes(notes: List): Completable {
- return Completable.fromCallable { noteDb.updateAll(notes) }
- }
-
- fun deleteNotes(notes: List) {
- noteDb.deleteAll(notes)
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberLocal.kt
new file mode 100644
index 00000000..115c8965
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberLocal.kt
@@ -0,0 +1,29 @@
+package io.github.wulkanowy.data.repositories.luckynumber
+
+import io.github.wulkanowy.data.db.dao.LuckyNumberDao
+import io.github.wulkanowy.data.db.entities.LuckyNumber
+import io.github.wulkanowy.data.db.entities.Semester
+import io.reactivex.Maybe
+import org.threeten.bp.LocalDate
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class LuckyNumberLocal @Inject constructor(private val luckyNumberDb: LuckyNumberDao) {
+
+ fun saveLuckyNumber(luckyNumber: LuckyNumber) {
+ luckyNumberDb.insert(luckyNumber)
+ }
+
+ fun updateLuckyNumber(luckyNumber: LuckyNumber) {
+ luckyNumberDb.update(luckyNumber)
+ }
+
+ fun deleteLuckyNumber(luckyNumber: LuckyNumber) {
+ luckyNumberDb.delete(luckyNumber)
+ }
+
+ fun getLuckyNumber(semester: Semester, date: LocalDate): Maybe {
+ return luckyNumberDb.load(semester.studentId, date)
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRemote.kt
new file mode 100644
index 00000000..1b0f12b3
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRemote.kt
@@ -0,0 +1,26 @@
+package io.github.wulkanowy.data.repositories.luckynumber
+
+import io.github.wulkanowy.api.Api
+import io.github.wulkanowy.data.db.entities.LuckyNumber
+import io.github.wulkanowy.data.db.entities.Semester
+import io.reactivex.Maybe
+import io.reactivex.Single
+import org.threeten.bp.LocalDate
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class LuckyNumberRemote @Inject constructor(private val api: Api) {
+
+ fun getLuckyNumber(semester: Semester): Maybe {
+ return Single.just(api.apply { diaryId = semester.diaryId })
+ .flatMapMaybe { it.getLuckyNumber() }
+ .map {
+ LuckyNumber(
+ studentId = semester.studentId,
+ date = LocalDate.now(),
+ luckyNumber = it
+ )
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRepository.kt
new file mode 100644
index 00000000..4036521f
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRepository.kt
@@ -0,0 +1,54 @@
+package io.github.wulkanowy.data.repositories.luckynumber
+
+import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
+import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
+import io.github.wulkanowy.data.db.entities.LuckyNumber
+import io.github.wulkanowy.data.db.entities.Semester
+import io.reactivex.Completable
+import io.reactivex.Maybe
+import org.threeten.bp.LocalDate
+import java.net.UnknownHostException
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class LuckyNumberRepository @Inject constructor(
+ private val settings: InternetObservingSettings,
+ private val local: LuckyNumberLocal,
+ private val remote: LuckyNumberRemote
+) {
+
+ fun getLuckyNumber(semester: Semester, forceRefresh: Boolean = false, notify: Boolean = false): Maybe {
+ return local.getLuckyNumber(semester, LocalDate.now()).filter { !forceRefresh }
+ .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
+ .flatMapMaybe {
+ if (it) remote.getLuckyNumber(semester)
+ else Maybe.error(UnknownHostException())
+ }.flatMap { new ->
+ local.getLuckyNumber(semester, LocalDate.now())
+ .doOnSuccess { old ->
+ if (new != old) {
+ local.deleteLuckyNumber(old)
+ local.saveLuckyNumber(new.apply {
+ if (notify) isNotified = false
+ })
+ }
+ }
+ .doOnComplete {
+ local.saveLuckyNumber(new.apply {
+ if (notify) isNotified = false
+ })
+ }
+ }.flatMap({ local.getLuckyNumber(semester, LocalDate.now()) }, { Maybe.error(it) },
+ { local.getLuckyNumber(semester, LocalDate.now()) })
+ )
+ }
+
+ fun getNotNotifiedLuckyNumber(semester: Semester): Maybe {
+ return local.getLuckyNumber(semester, LocalDate.now()).filter { !it.isNotified }
+ }
+
+ fun updateLuckyNumber(luckyNumber: LuckyNumber): Completable {
+ return Completable.fromCallable { local.updateLuckyNumber(luckyNumber) }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageFolder.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageFolder.kt
new file mode 100644
index 00000000..06f5a1e0
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageFolder.kt
@@ -0,0 +1,7 @@
+package io.github.wulkanowy.data.repositories.message
+
+enum class MessageFolder(val id: Int = 1) {
+ RECEIVED(1),
+ SENT(2),
+ TRASHED(3)
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageLocal.kt
new file mode 100644
index 00000000..e9ab7297
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageLocal.kt
@@ -0,0 +1,36 @@
+package io.github.wulkanowy.data.repositories.message
+
+import io.github.wulkanowy.data.db.dao.MessagesDao
+import io.github.wulkanowy.data.db.entities.Message
+import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.data.repositories.message.MessageFolder.TRASHED
+import io.reactivex.Maybe
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class MessageLocal @Inject constructor(private val messagesDb: MessagesDao) {
+
+ fun saveMessages(messages: List) {
+ messagesDb.insertAll(messages)
+ }
+
+ fun updateMessages(messages: List) {
+ messagesDb.updateAll(messages)
+ }
+
+ fun deleteMessages(messages: List) {
+ messagesDb.deleteAll(messages)
+ }
+
+ fun getMessage(student: Student, id: Int): Maybe {
+ return messagesDb.load(student.studentId, id)
+ }
+
+ fun getMessages(student: Student, folder: MessageFolder): Maybe> {
+ return when (folder) {
+ TRASHED -> messagesDb.loadDeleted(student.studentId)
+ else -> messagesDb.loadAll(student.studentId, folder.id)
+ }.filter { it.isNotEmpty() }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRemote.kt
new file mode 100644
index 00000000..3fb01d30
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRemote.kt
@@ -0,0 +1,61 @@
+package io.github.wulkanowy.data.repositories.message
+
+import io.github.wulkanowy.api.Api
+import io.github.wulkanowy.api.messages.Folder
+import io.github.wulkanowy.api.messages.SentMessage
+import io.github.wulkanowy.data.db.entities.Message
+import io.github.wulkanowy.data.db.entities.Recipient
+import io.github.wulkanowy.utils.toLocalDateTime
+import io.reactivex.Single
+import org.threeten.bp.LocalDateTime.now
+import javax.inject.Inject
+import javax.inject.Singleton
+import io.github.wulkanowy.api.messages.Message as ApiMessage
+import io.github.wulkanowy.api.messages.Recipient as ApiRecipient
+
+@Singleton
+class MessageRemote @Inject constructor(private val api: Api) {
+
+ fun getMessages(studentId: Int, folder: MessageFolder): Single> {
+ return api.getMessages(Folder.valueOf(folder.name)).map { messages ->
+ messages.map {
+ Message(
+ studentId = studentId,
+ realId = it.id ?: 0,
+ messageId = it.messageId ?: 0,
+ sender = it.sender.orEmpty(),
+ senderId = it.senderId ?: 0,
+ recipient = it.recipient.orEmpty(),
+ subject = it.subject.trim(),
+ date = it.date?.toLocalDateTime() ?: now(),
+ folderId = it.folderId,
+ unread = it.unread ?: false,
+ unreadBy = it.unreadBy ?: 0,
+ readBy = it.readBy ?: 0,
+ removed = it.removed
+ )
+ }
+ }
+ }
+
+ fun getMessagesContent(message: Message, markAsRead: Boolean = false): Single {
+ return api.getMessageContent(message.messageId, message.folderId, markAsRead, message.realId)
+ }
+
+ fun sendMessage(subject: String, content: String, recipients: List): Single {
+ return api.sendMessage(
+ subject = subject,
+ content = content,
+ recipients = recipients.map {
+ ApiRecipient(
+ id = it.realId,
+ name = it.realName,
+ loginId = it.loginId,
+ reportingUnitId = it.unitId,
+ role = it.role,
+ hash = it.hash
+ )
+ }
+ )
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRepository.kt
new file mode 100644
index 00000000..d319689e
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRepository.kt
@@ -0,0 +1,92 @@
+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.api.messages.SentMessage
+import io.github.wulkanowy.data.ApiHelper
+import io.github.wulkanowy.data.db.entities.Message
+import io.github.wulkanowy.data.db.entities.Recipient
+import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED
+import io.reactivex.Completable
+import io.reactivex.Single
+import java.net.UnknownHostException
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class MessageRepository @Inject constructor(
+ private val settings: InternetObservingSettings,
+ private val local: MessageLocal,
+ private val remote: MessageRemote,
+ private val apiHelper: ApiHelper
+) {
+
+ fun getMessages(student: Student, folder: MessageFolder, forceRefresh: Boolean = false, notify: Boolean = false): Single> {
+ return Single.just(apiHelper.initApi(student))
+ .flatMap { _ ->
+ local.getMessages(student, folder).filter { !forceRefresh }
+ .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
+ .flatMap {
+ if (it) remote.getMessages(student.studentId, folder)
+ else Single.error(UnknownHostException())
+ }.flatMap { new ->
+ local.getMessages(student, folder).toSingle(emptyList())
+ .doOnSuccess { old ->
+ local.deleteMessages(old - new)
+ local.saveMessages((new - old)
+ .onEach {
+ it.isNotified = !notify
+ })
+ }
+ }.flatMap { local.getMessages(student, folder).toSingle(emptyList()) }
+ )
+ }
+ }
+
+ fun getMessage(student: Student, messageId: Int, markAsRead: Boolean = false): Single {
+ return Single.just(apiHelper.initApi(student))
+ .flatMap { _ ->
+ local.getMessage(student, messageId)
+ .filter { !it.content.isNullOrEmpty() }
+ .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
+ .flatMap {
+ if (it) local.getMessage(student, messageId).toSingle()
+ else Single.error(UnknownHostException())
+ }
+ .flatMap { dbMessage ->
+ remote.getMessagesContent(dbMessage, markAsRead).doOnSuccess {
+ local.updateMessages(listOf(dbMessage.copy(unread = false).apply {
+ id = dbMessage.id
+ content = it
+ }))
+ }
+ }.flatMap {
+ local.getMessage(student, messageId).toSingle()
+ }
+ )
+ }
+ }
+
+ fun getNotNotifiedMessages(student: Student): Single> {
+ return local.getMessages(student, RECEIVED)
+ .map { it.filter { message -> !message.isNotified && message.unread } }
+ .toSingle(emptyList())
+ }
+
+ fun updateMessage(message: Message): Completable {
+ return Completable.fromCallable { local.updateMessages(listOf(message)) }
+ }
+
+ fun updateMessages(messages: List): Completable {
+ return Completable.fromCallable { local.updateMessages(messages) }
+ }
+
+ fun sendMessage(subject: String, content: String, recipients: List): Single {
+ return ReactiveNetwork.checkInternetConnectivity(settings)
+ .flatMap {
+ if (it) remote.sendMessage(subject, content, recipients)
+ else Single.error(UnknownHostException())
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteLocal.kt
new file mode 100644
index 00000000..784e61f0
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteLocal.kt
@@ -0,0 +1,28 @@
+package io.github.wulkanowy.data.repositories.note
+
+import io.github.wulkanowy.data.db.dao.NoteDao
+import io.github.wulkanowy.data.db.entities.Note
+import io.github.wulkanowy.data.db.entities.Student
+import io.reactivex.Maybe
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class NoteLocal @Inject constructor(private val noteDb: NoteDao) {
+
+ fun saveNotes(notes: List) {
+ noteDb.insertAll(notes)
+ }
+
+ fun updateNotes(notes: List) {
+ noteDb.updateAll(notes)
+ }
+
+ fun deleteNotes(notes: List) {
+ noteDb.deleteAll(notes)
+ }
+
+ fun getNotes(student: Student): Maybe> {
+ return noteDb.loadAll(student.studentId).filter { it.isNotEmpty() }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/NoteRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRemote.kt
similarity index 89%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/remote/NoteRemote.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRemote.kt
index 31f28e11..aebc6230 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/NoteRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRemote.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.remote
+package io.github.wulkanowy.data.repositories.note
import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Note
@@ -17,7 +17,6 @@ class NoteRemote @Inject constructor(private val api: Api) {
.map { notes ->
notes.map {
Note(
- semesterId = semester.semesterId,
studentId = semester.studentId,
date = it.date.toLocalDate(),
teacher = it.teacher,
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/NoteRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRepository.kt
similarity index 54%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/NoteRepository.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRepository.kt
index 2836894f..d74bc7ea 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/NoteRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRepository.kt
@@ -1,11 +1,10 @@
-package io.github.wulkanowy.data.repositories
+package io.github.wulkanowy.data.repositories.note
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.Note
import io.github.wulkanowy.data.db.entities.Semester
-import io.github.wulkanowy.data.repositories.local.NoteLocal
-import io.github.wulkanowy.data.repositories.remote.NoteRemote
+import io.github.wulkanowy.data.db.entities.Student
import io.reactivex.Completable
import io.reactivex.Single
import java.net.UnknownHostException
@@ -19,34 +18,36 @@ class NoteRepository @Inject constructor(
private val remote: NoteRemote
) {
- fun getNotes(semester: Semester, forceRefresh: Boolean = false, notify: Boolean = false): Single> {
- return local.getNotes(semester).filter { !forceRefresh }
+ fun getNotes(student: Student, semester: Semester, forceRefresh: Boolean = false, notify: Boolean = false): Single> {
+ return local.getNotes(student).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getNotes(semester)
else Single.error(UnknownHostException())
}.flatMap { new ->
- local.getNotes(semester).toSingle(emptyList())
+ local.getNotes(student).toSingle(emptyList())
.doOnSuccess { old ->
local.deleteNotes(old - new)
local.saveNotes((new - old)
.onEach {
- if (notify) it.isNotified = false
+ if (it.date >= student.registrationDate.toLocalDate()) it.apply {
+ isRead = false
+ if (notify) isNotified = false
+ }
})
}
- }.flatMap { local.getNotes(semester).toSingle(emptyList()) }
- )
+ }.flatMap { local.getNotes(student).toSingle(emptyList()) })
}
- fun getNewNotes(semester: Semester): Single> {
- return local.getNewNotes(semester).toSingle(emptyList())
+ fun getNotNotifiedNotes(student: Student): Single> {
+ return local.getNotes(student).map { it.filter { note -> !note.isNotified } }.toSingle(emptyList())
}
fun updateNote(note: Note): Completable {
- return local.updateNote(note)
+ return Completable.fromCallable { local.updateNotes(listOf(note)) }
}
fun updateNotes(notes: List): Completable {
- return local.updateNotes(notes)
+ return Completable.fromCallable { local.updateNotes(notes) }
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/preferences/PreferencesRepository.kt
similarity index 64%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/preferences/PreferencesRepository.kt
index 205baa3a..d51fc495 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/preferences/PreferencesRepository.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories
+package io.github.wulkanowy.data.repositories.preferences
import android.content.Context
import android.content.SharedPreferences
@@ -12,7 +12,7 @@ class PreferencesRepository @Inject constructor(
val context: Context
) {
val startMenuIndex: Int
- get() = sharedPref.getString(context.getString(R.string.pref_key_start_menu), "0")?.toInt() ?: 0
+ get() = sharedPref.getString(context.getString(R.string.pref_key_start_menu), "0")?.toIntOrNull() ?: 0
val isShowPresent: Boolean
get() = sharedPref.getBoolean(context.getString(R.string.pref_key_attendance_present), true)
@@ -22,21 +22,18 @@ class PreferencesRepository @Inject constructor(
val currentThemeKey: String = context.getString(R.string.pref_key_theme)
val currentTheme: Int
- get() = sharedPref.getString(currentThemeKey, "1")?.toInt() ?: 1
+ get() = sharedPref.getString(currentThemeKey, "1")?.toIntOrNull() ?: 1
- val gradePlusModifier: Double
- get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_plus), "0.0")?.toDouble() ?: 0.0
+ val gradeColorTheme: String
+ get() = sharedPref.getString(context.getString(R.string.pref_key_grade_color_scheme), "vulcan") ?: "vulcan"
- val gradeMinusModifier: Double
- get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_minus), "0.0")?.toDouble() ?: 0.0
-
- val serviceEnablesKey: String = context.getString(R.string.pref_key_services_enable)
+ val serviceEnableKey: String = context.getString(R.string.pref_key_services_enable)
val isServiceEnabled: Boolean
- get() = sharedPref.getBoolean(serviceEnablesKey, true)
+ get() = sharedPref.getBoolean(serviceEnableKey, true)
val servicesIntervalKey: String = context.getString(R.string.pref_key_services_interval)
- val servicesInterval: Int
- get() = sharedPref.getString(servicesIntervalKey, "60")?.toInt() ?: 60
+ val servicesInterval: Long
+ get() = sharedPref.getString(servicesIntervalKey, "60")?.toLongOrNull() ?: 60
val servicesOnlyWifiKey: String = context.getString(R.string.pref_key_services_wifi_only)
val isServicesOnlyWifi: Boolean
@@ -44,4 +41,18 @@ class PreferencesRepository @Inject constructor(
val isNotificationsEnable: Boolean
get() = sharedPref.getBoolean(context.getString(R.string.pref_key_notifications_enable), true)
+
+ val isDebugNotificationEnableKey: String = context.getString(R.string.pref_key_notification_debug)
+ val isDebugNotificationEnable: Boolean
+ get() = sharedPref.getBoolean(isDebugNotificationEnableKey, false)
+
+ val gradePlusModifier: Double
+ get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_plus), "0.0")?.toDouble() ?: 0.0
+
+ val gradeMinusModifier: Double
+ get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_minus), "0.0")?.toDouble()
+ ?: 0.0
+
+ val fillMessageContent: Boolean
+ get() = sharedPref.getBoolean(context.getString(R.string.pref_key_fill_message_content), true)
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientLocal.kt
new file mode 100644
index 00000000..6b8328ec
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientLocal.kt
@@ -0,0 +1,25 @@
+package io.github.wulkanowy.data.repositories.recipient
+
+import io.github.wulkanowy.data.db.dao.RecipientDao
+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.reactivex.Maybe
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class RecipientLocal @Inject constructor(private val recipientDb: RecipientDao) {
+
+ fun getRecipients(student: Student, role: Int, unit: ReportingUnit): Maybe> {
+ return recipientDb.load(student.studentId, role, unit.realId).filter { !it.isEmpty() }
+ }
+
+ fun saveRecipients(recipients: List) {
+ return recipientDb.insertAll(recipients)
+ }
+
+ fun deleteRecipients(recipients: List) {
+ recipientDb.deleteAll(recipients)
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientRemote.kt
new file mode 100644
index 00000000..b726edda
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientRemote.kt
@@ -0,0 +1,41 @@
+package io.github.wulkanowy.data.repositories.recipient
+
+import io.github.wulkanowy.api.Api
+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.reactivex.Single
+import javax.inject.Inject
+import javax.inject.Singleton
+import io.github.wulkanowy.api.messages.Recipient as ApiRecipient
+
+@Singleton
+class RecipientRemote @Inject constructor(private val api: Api) {
+
+ fun getRecipients(role: Int, unit: ReportingUnit): Single> {
+ return api.getRecipients(unit.realId, role)
+ .map { recipients ->
+ recipients.map { it.toRecipient() }
+ }
+ }
+
+ fun getMessageRecipients(message: Message): Single> {
+ return api.getMessageRecipients(message.messageId, message.senderId)
+ .map { recipients ->
+ recipients.map { it.toRecipient() }
+ }
+ }
+
+ private fun ApiRecipient.toRecipient(): Recipient {
+ return Recipient(
+ studentId = api.studentId,
+ realId = id,
+ realName = name,
+ name = shortName,
+ hash = hash,
+ loginId = loginId,
+ role = role,
+ unitId = reportingUnitId ?: 0
+ )
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientRepository.kt
new file mode 100644
index 00000000..0b02721f
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientRepository.kt
@@ -0,0 +1,52 @@
+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.ApiHelper
+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.reactivex.Single
+import java.net.UnknownHostException
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class RecipientRepository @Inject constructor(
+ private val settings: InternetObservingSettings,
+ private val local: RecipientLocal,
+ private val remote: RecipientRemote,
+ private val apiHelper: ApiHelper
+) {
+
+ fun getRecipients(student: Student, role: Int, unit: ReportingUnit, forceRefresh: Boolean = false): Single> {
+ return Single.just(apiHelper.initApi(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 - new)
+ local.saveRecipients(new - old)
+ }
+ }.flatMap {
+ local.getRecipients(student, role, unit).toSingle(emptyList())
+ }
+ )
+ }
+ }
+
+ fun getMessageRecipients(student: Student, message: Message): Single> {
+ return Single.just(apiHelper.initApi(student))
+ .flatMap { ReactiveNetwork.checkInternetConnectivity(settings) }
+ .flatMap {
+ if (it) remote.getMessageRecipients(message)
+ else Single.error(UnknownHostException())
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/MessagesRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/remote/MessagesRemote.kt
deleted file mode 100644
index bc0f3400..00000000
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/MessagesRemote.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-package io.github.wulkanowy.data.repositories.remote
-
-import io.github.wulkanowy.api.Api
-import io.github.wulkanowy.api.messages.Folder
-import io.github.wulkanowy.data.db.entities.Message
-import io.github.wulkanowy.data.repositories.MessagesRepository
-import io.github.wulkanowy.utils.toLocalDateTime
-import io.reactivex.Single
-import javax.inject.Inject
-import io.github.wulkanowy.api.messages.Message as ApiMessage
-
-class MessagesRemote @Inject constructor(private val api: Api) {
-
- fun getMessages(studentId: Int, folder: MessagesRepository.MessageFolder): Single> {
- return api.getMessages(Folder.valueOf(folder.name)).map { messages ->
- messages.map {
- Message(
- studentId = studentId,
- realId = it.id,
- messageId = it.messageId,
- sender = it.sender,
- senderId = it.senderId,
- recipient = it.recipient,
- recipientId = it.recipientId,
- subject = it.subject.trim(),
- date = it.date?.toLocalDateTime(),
- folderId = it.folderId,
- unread = it.unread,
- unreadBy = it.unreadBy,
- readBy = it.readBy,
- removed = it.removed
- )
- }
- }
- }
-
- fun getMessagesContent(message: Message, markAsRead: Boolean = false): Single {
- return api.getMessageContent(message.messageId ?: 0, message.folderId, markAsRead, message.realId ?: 0)
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/StudentRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/remote/StudentRemote.kt
deleted file mode 100644
index 6c6e26a9..00000000
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/StudentRemote.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package io.github.wulkanowy.data.repositories.remote
-
-import io.github.wulkanowy.api.Api
-import io.github.wulkanowy.data.db.entities.Student
-import io.reactivex.Single
-import javax.inject.Inject
-import javax.inject.Singleton
-
-@Singleton
-class StudentRemote @Inject constructor(private val api: Api) {
-
- fun getStudents(email: String, password: String, endpoint: String): Single> {
- return api.getPupils().map { students ->
- students.map { pupil ->
- Student(
- email = email,
- password = password,
- symbol = pupil.symbol,
- studentId = pupil.studentId,
- studentName = pupil.studentName,
- schoolSymbol = pupil.schoolSymbol,
- schoolName = pupil.description,
- endpoint = endpoint,
- loginType = pupil.loginType.name
- )
- }
- }
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitLocal.kt
new file mode 100644
index 00000000..b4281cbf
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitLocal.kt
@@ -0,0 +1,28 @@
+package io.github.wulkanowy.data.repositories.reportingunit
+
+import io.github.wulkanowy.data.db.dao.ReportingUnitDao
+import io.github.wulkanowy.data.db.entities.ReportingUnit
+import io.github.wulkanowy.data.db.entities.Student
+import io.reactivex.Maybe
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class ReportingUnitLocal @Inject constructor(private val reportingUnitDb: ReportingUnitDao) {
+
+ fun getReportingUnits(student: Student): Maybe> {
+ return reportingUnitDb.load(student.studentId).filter { !it.isEmpty() }
+ }
+
+ fun getReportingUnit(student: Student, unitId: Int): Maybe {
+ return reportingUnitDb.loadOne(student.studentId, unitId)
+ }
+
+ fun saveReportingUnits(reportingUnits: List) {
+ return reportingUnitDb.insertAll(reportingUnits)
+ }
+
+ fun deleteReportingUnits(reportingUnits: List) {
+ reportingUnitDb.deleteAll(reportingUnits)
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitRemote.kt
new file mode 100644
index 00000000..feb4b013
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitRemote.kt
@@ -0,0 +1,26 @@
+package io.github.wulkanowy.data.repositories.reportingunit
+
+import io.github.wulkanowy.api.Api
+import io.github.wulkanowy.data.db.entities.ReportingUnit
+import io.reactivex.Single
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class ReportingUnitRemote @Inject constructor(private val api: Api) {
+
+ fun getReportingUnits(): Single> {
+ return api.getReportingUnits().map {
+ it.map { unit ->
+ ReportingUnit(
+ studentId = api.studentId,
+ realId = unit.id,
+ roles = unit.roles,
+ senderId = unit.senderId,
+ senderName = unit.senderName,
+ shortName = unit.short
+ )
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitRepository.kt
new file mode 100644
index 00000000..9184b4bb
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitRepository.kt
@@ -0,0 +1,55 @@
+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.ApiHelper
+import io.github.wulkanowy.data.db.entities.ReportingUnit
+import io.github.wulkanowy.data.db.entities.Student
+import io.reactivex.Maybe
+import io.reactivex.Single
+import java.net.UnknownHostException
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class ReportingUnitRepository @Inject constructor(
+ private val settings: InternetObservingSettings,
+ private val local: ReportingUnitLocal,
+ private val remote: ReportingUnitRemote,
+ private val apiHelper: ApiHelper
+) {
+
+ fun getReportingUnits(student: Student, forceRefresh: Boolean = false): Single> {
+ return Single.just(apiHelper.initApi(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 - new)
+ local.saveReportingUnits(new - old)
+ }
+ }.flatMap { local.getReportingUnits(student).toSingle(emptyList()) }
+ )
+ }
+ }
+
+ fun getReportingUnit(student: Student, unitId: Int): Maybe {
+ return Maybe.just(apiHelper.initApi(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)
+ }
+ )
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/SemesterLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterLocal.kt
similarity index 93%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/local/SemesterLocal.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterLocal.kt
index 77000478..5be82d7f 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/local/SemesterLocal.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterLocal.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.local
+package io.github.wulkanowy.data.repositories.semester
import io.github.wulkanowy.data.db.dao.SemesterDao
import io.github.wulkanowy.data.db.entities.Semester
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/SemesterRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRemote.kt
similarity index 80%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/remote/SemesterRemote.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRemote.kt
index 1cf10501..b25c8881 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/SemesterRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRemote.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.remote
+package io.github.wulkanowy.data.repositories.semester
import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Semester
@@ -19,7 +19,9 @@ class SemesterRemote @Inject constructor(private val api: Api) {
diaryName = semester.diaryName,
semesterId = semester.semesterId,
semesterName = semester.semesterNumber,
- isCurrent = semester.current
+ isCurrent = semester.current,
+ classId = semester.classId,
+ unitId = semester.unitId
)
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/SemesterRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRepository.kt
similarity index 90%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/SemesterRepository.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRepository.kt
index b7902106..975868a2 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/SemesterRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRepository.kt
@@ -1,12 +1,10 @@
-package io.github.wulkanowy.data.repositories
+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.ApiHelper
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
-import io.github.wulkanowy.data.repositories.local.SemesterLocal
-import io.github.wulkanowy.data.repositories.remote.SemesterRemote
import io.reactivex.Maybe
import io.reactivex.Single
import java.net.UnknownHostException
@@ -39,4 +37,3 @@ class SemesterRepository @Inject constructor(
return getSemesters(student, forceRefresh).map { item -> item.single { it.isCurrent } }
}
}
-
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/StudentLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentLocal.kt
similarity index 68%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/local/StudentLocal.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentLocal.kt
index 0e4e9cbd..e05e7223 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/local/StudentLocal.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentLocal.kt
@@ -1,7 +1,6 @@
-package io.github.wulkanowy.data.repositories.local
+package io.github.wulkanowy.data.repositories.student
import android.content.Context
-import io.github.wulkanowy.data.db.SharedPrefHelper
import io.github.wulkanowy.data.db.dao.StudentDao
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.security.decrypt
@@ -15,25 +14,17 @@ import javax.inject.Singleton
@Singleton
class StudentLocal @Inject constructor(
private val studentDb: StudentDao,
- private val sharedPref: SharedPrefHelper,
private val context: Context
) {
- companion object {
- const val STUDENT_SAVED_KEY: String = "is_student_saved"
- }
-
- val isStudentSaved
- get() = sharedPref.getBoolean(STUDENT_SAVED_KEY, false)
-
fun saveStudent(student: Student): Single {
return Single.fromCallable { studentDb.insert(student.copy(password = encrypt(student.password, context))) }
- .doOnSuccess { sharedPref.putBoolean(STUDENT_SAVED_KEY, true) }
}
fun getStudents(decryptPass: Boolean): Maybe> {
return studentDb.loadAll()
.map { list -> list.map { it.apply { if (decryptPass) password = decrypt(password) } } }
+ .filter { !it.isEmpty() }
}
fun getCurrentStudent(decryptPass: Boolean): Maybe {
@@ -46,13 +37,10 @@ class StudentLocal @Inject constructor(
resetCurrent()
updateCurrent(student.studentId)
}
- }.doOnComplete { sharedPref.putBoolean(STUDENT_SAVED_KEY, true) }
+ }
}
fun logoutStudent(student: Student): Completable {
- return Completable.fromCallable {
- studentDb.delete(student)
- if (student.isCurrent) sharedPref.putBoolean(STUDENT_SAVED_KEY, false)
- }
+ return Completable.fromCallable { studentDb.delete(student) }
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRemote.kt
new file mode 100644
index 00000000..7a504cca
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRemote.kt
@@ -0,0 +1,32 @@
+package io.github.wulkanowy.data.repositories.student
+
+import io.github.wulkanowy.api.Api
+import io.github.wulkanowy.data.db.entities.Student
+import io.reactivex.Single
+import org.threeten.bp.LocalDateTime.now
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class StudentRemote @Inject constructor(private val api: Api) {
+
+ fun getStudents(email: String, password: String, endpoint: String): Single> {
+ return api.getStudents().map { students ->
+ students.map { student ->
+ Student(
+ email = email,
+ password = password,
+ symbol = student.symbol,
+ studentId = student.studentId,
+ studentName = student.studentName,
+ schoolSymbol = student.schoolSymbol,
+ schoolName = student.schoolName,
+ endpoint = endpoint,
+ loginType = student.loginType.name,
+ isCurrent = false,
+ registrationDate = now()
+ )
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRepository.kt
similarity index 68%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRepository.kt
index 97210da0..7ddff0aa 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRepository.kt
@@ -1,12 +1,11 @@
-package io.github.wulkanowy.data.repositories
+package io.github.wulkanowy.data.repositories.student
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.ApiHelper
import io.github.wulkanowy.data.db.entities.Student
-import io.github.wulkanowy.data.repositories.local.StudentLocal
-import io.github.wulkanowy.data.repositories.remote.StudentRemote
import io.reactivex.Completable
+import io.reactivex.Maybe
import io.reactivex.Single
import java.net.UnknownHostException
import javax.inject.Inject
@@ -20,20 +19,15 @@ class StudentRepository @Inject constructor(
private val apiHelper: ApiHelper
) {
- val isStudentSaved
- get() = local.isStudentSaved
+ fun isStudentSaved(): Single = local.getStudents(false).isEmpty.map { !it }
- lateinit var cachedStudents: Single>
- private set
-
- fun getStudents(email: String, password: String, symbol: String, endpoint: String): Single> {
- cachedStudents = ReactiveNetwork.checkInternetConnectivity(settings)
+ fun getStudents(email: String, password: String, endpoint: String, symbol: String = ""): Single> {
+ return ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
apiHelper.initApi(email, password, symbol, endpoint)
if (it) remote.getStudents(email, password, endpoint)
else Single.error(UnknownHostException("No internet connection"))
- }.doOnSuccess { cachedStudents = Single.just(it) }
- return cachedStudents
+ }
}
fun getSavedStudents(decryptPass: Boolean = true): Single> {
@@ -41,7 +35,9 @@ class StudentRepository @Inject constructor(
}
fun getCurrentStudent(decryptPass: Boolean = true): Single {
- return local.getCurrentStudent(decryptPass).toSingle()
+ return local.getCurrentStudent(decryptPass)
+ .switchIfEmpty(Maybe.error(NoSuchElementException("No current student")))
+ .toSingle()
}
fun saveStudent(student: Student): Single {
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/SubjectLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectLocal.kt
similarity index 92%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/local/SubjectLocal.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectLocal.kt
index 7ca7c1b0..63e33401 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/local/SubjectLocal.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectLocal.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.local
+package io.github.wulkanowy.data.repositories.subject
import io.github.wulkanowy.data.db.dao.SubjectDao
import io.github.wulkanowy.data.db.entities.Semester
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/SubjectRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRemote.kt
similarity index 93%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/remote/SubjectRemote.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRemote.kt
index ae565d48..88fbb196 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/SubjectRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRemote.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.remote
+package io.github.wulkanowy.data.repositories.subject
import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Semester
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/SubjectRepostory.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRepository.kt
similarity index 86%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/SubjectRepostory.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRepository.kt
index e3e8a2a7..6167251b 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/SubjectRepostory.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRepository.kt
@@ -1,18 +1,16 @@
-package io.github.wulkanowy.data.repositories
+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.Subject
-import io.github.wulkanowy.data.repositories.local.SubjectLocal
-import io.github.wulkanowy.data.repositories.remote.SubjectRemote
import io.reactivex.Single
import java.net.UnknownHostException
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class SubjectRepostory @Inject constructor(
+class SubjectRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: SubjectLocal,
private val remote: SubjectRemote
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/TimetableLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableLocal.kt
similarity index 82%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/local/TimetableLocal.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableLocal.kt
index 63cc7c94..e074ce2a 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/local/TimetableLocal.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableLocal.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.local
+package io.github.wulkanowy.data.repositories.timetable
import io.github.wulkanowy.data.db.dao.TimetableDao
import io.github.wulkanowy.data.db.entities.Semester
@@ -6,14 +6,11 @@ import io.github.wulkanowy.data.db.entities.Timetable
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import javax.inject.Inject
+import javax.inject.Singleton
+@Singleton
class TimetableLocal @Inject constructor(private val timetableDb: TimetableDao) {
- fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe> {
- return timetableDb.loadAll(semester.diaryId, semester.studentId, startDate, endDate)
- .filter { !it.isEmpty() }
- }
-
fun saveTimetable(timetables: List) {
timetableDb.insertAll(timetables)
}
@@ -21,4 +18,8 @@ class TimetableLocal @Inject constructor(private val timetableDb: TimetableDao)
fun deleteTimetable(timetables: List) {
timetableDb.deleteAll(timetables)
}
+
+ fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe> {
+ return timetableDb.loadAll(semester.diaryId, semester.studentId, startDate, endDate).filter { it.isNotEmpty() }
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/TimetableRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemote.kt
similarity index 85%
rename from app/src/main/java/io/github/wulkanowy/data/repositories/remote/TimetableRemote.kt
rename to app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemote.kt
index aa8949fd..77742e7b 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/TimetableRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemote.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.data.repositories.remote
+package io.github.wulkanowy.data.repositories.timetable
import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Semester
@@ -8,7 +8,9 @@ import io.github.wulkanowy.utils.toLocalDateTime
import io.reactivex.Single
import org.threeten.bp.LocalDate
import javax.inject.Inject
+import javax.inject.Singleton
+@Singleton
class TimetableRemote @Inject constructor(private val api: Api) {
fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> {
@@ -24,9 +26,12 @@ class TimetableRemote @Inject constructor(private val api: Api) {
end = it.end.toLocalDateTime(),
date = it.date.toLocalDate(),
subject = it.subject,
+ subjectOld = it.subjectOld,
group = it.group,
room = it.room,
+ roomOld = it.roomOld,
teacher = it.teacher,
+ teacherOld = it.teacherOld,
info = it.info,
changes = it.changes,
canceled = it.canceled
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRepository.kt
new file mode 100644
index 00000000..460d55fd
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRepository.kt
@@ -0,0 +1,49 @@
+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.Timetable
+import io.github.wulkanowy.utils.friday
+import io.github.wulkanowy.utils.monday
+import io.reactivex.Single
+import org.threeten.bp.LocalDate
+import java.net.UnknownHostException
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class TimetableRepository @Inject constructor(
+ private val settings: InternetObservingSettings,
+ private val local: TimetableLocal,
+ private val remote: TimetableRemote
+) {
+
+ fun getTimetable(semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single> {
+ 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)
+ else Single.error(UnknownHostException())
+ }.flatMap { newTimetable ->
+ local.getTimetable(semester, monday, friday)
+ .toSingle(emptyList())
+ .doOnSuccess { oldTimetable ->
+ local.deleteTimetable(oldTimetable - newTimetable)
+ local.saveTimetable((newTimetable - oldTimetable).map { item ->
+ item.apply {
+ oldTimetable.singleOrNull { this.start == it.start }?.let {
+ return@map copy(
+ room = if (room.isEmpty()) it.room else room,
+ teacher = if (teacher.isEmpty()) it.teacher else teacher
+ )
+ }
+ }
+ })
+ }
+ }.flatMap {
+ local.getTimetable(semester, monday, friday).toSingle(emptyList())
+ }).map { list -> list.filter { it.date in start..end } }
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/di/AppComponent.kt b/app/src/main/java/io/github/wulkanowy/di/AppComponent.kt
index 21c193e5..9e8b24ab 100644
--- a/app/src/main/java/io/github/wulkanowy/di/AppComponent.kt
+++ b/app/src/main/java/io/github/wulkanowy/di/AppComponent.kt
@@ -5,6 +5,7 @@ import dagger.android.AndroidInjector
import dagger.android.support.AndroidSupportInjectionModule
import io.github.wulkanowy.WulkanowyApp
import io.github.wulkanowy.data.RepositoryModule
+import io.github.wulkanowy.services.ServicesModule
import javax.inject.Singleton
@Singleton
@@ -12,6 +13,7 @@ import javax.inject.Singleton
AndroidSupportInjectionModule::class,
AppModule::class,
RepositoryModule::class,
+ ServicesModule::class,
BuilderModule::class])
interface AppComponent : AndroidInjector {
diff --git a/app/src/main/java/io/github/wulkanowy/di/AppModule.kt b/app/src/main/java/io/github/wulkanowy/di/AppModule.kt
index fc2e9297..eb3b18f9 100644
--- a/app/src/main/java/io/github/wulkanowy/di/AppModule.kt
+++ b/app/src/main/java/io/github/wulkanowy/di/AppModule.kt
@@ -1,16 +1,17 @@
package io.github.wulkanowy.di
+import android.appwidget.AppWidgetManager
import android.content.Context
-import com.firebase.jobdispatcher.FirebaseJobDispatcher
-import com.firebase.jobdispatcher.GooglePlayDriver
import com.google.firebase.analytics.FirebaseAnalytics
import dagger.Module
import dagger.Provides
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
+import io.github.wulkanowy.BuildConfig.DEBUG
import io.github.wulkanowy.WulkanowyApp
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.github.wulkanowy.utils.SchedulersProvider
+import javax.inject.Named
import javax.inject.Singleton
@Module
@@ -29,9 +30,14 @@ internal class AppModule {
@Singleton
@Provides
- fun provideJobDispatcher(context: Context) = FirebaseJobDispatcher(GooglePlayDriver(context))
+ fun provideFirebaseAnalyticsHelper(context: Context) = FirebaseAnalyticsHelper(FirebaseAnalytics.getInstance(context))
@Singleton
@Provides
- fun provideFirebaseAnalyticsHelper(context: Context) = FirebaseAnalyticsHelper(FirebaseAnalytics.getInstance(context))
+ fun provideAppWidgetManager(context: Context) = AppWidgetManager.getInstance(context)
+
+ @Singleton
+ @Named("isDebug")
+ @Provides
+ fun provideIsDebug() = DEBUG
}
diff --git a/app/src/main/java/io/github/wulkanowy/di/BuilderModule.kt b/app/src/main/java/io/github/wulkanowy/di/BuilderModule.kt
index 9f4ecb80..2616acc3 100644
--- a/app/src/main/java/io/github/wulkanowy/di/BuilderModule.kt
+++ b/app/src/main/java/io/github/wulkanowy/di/BuilderModule.kt
@@ -3,12 +3,12 @@ package io.github.wulkanowy.di
import dagger.Module
import dagger.android.ContributesAndroidInjector
import io.github.wulkanowy.di.scopes.PerActivity
-import io.github.wulkanowy.services.job.SyncWorker
import io.github.wulkanowy.services.widgets.TimetableWidgetService
import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.ui.modules.login.LoginModule
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainModule
+import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
import io.github.wulkanowy.ui.modules.splash.SplashActivity
import io.github.wulkanowy.ui.widgets.timetable.TimetableWidgetProvider
@@ -16,7 +16,7 @@ import io.github.wulkanowy.ui.widgets.timetable.TimetableWidgetProvider
internal abstract class BuilderModule {
@PerActivity
- @ContributesAndroidInjector()
+ @ContributesAndroidInjector
abstract fun bindSplashActivity(): SplashActivity
@PerActivity
@@ -27,12 +27,12 @@ internal abstract class BuilderModule {
@ContributesAndroidInjector(modules = [MainModule::class])
abstract fun bindMainActivity(): MainActivity
+ @ContributesAndroidInjector
+ abstract fun bindMessageSendActivity(): SendMessageActivity
+
@ContributesAndroidInjector
abstract fun bindTimetableWidgetService(): TimetableWidgetService
@ContributesAndroidInjector
abstract fun bindTimetableWidgetProvider(): TimetableWidgetProvider
-
- @ContributesAndroidInjector
- abstract fun bindSyncJob(): SyncWorker
}
diff --git a/app/src/main/java/io/github/wulkanowy/services/ServicesModule.kt b/app/src/main/java/io/github/wulkanowy/services/ServicesModule.kt
new file mode 100644
index 00000000..70cbf84c
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/ServicesModule.kt
@@ -0,0 +1,102 @@
+package io.github.wulkanowy.services
+
+import android.app.NotificationManager
+import android.content.Context
+import android.content.Context.NOTIFICATION_SERVICE
+import androidx.core.app.NotificationManagerCompat
+import androidx.work.WorkManager
+import com.squareup.inject.assisted.dagger2.AssistedModule
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.multibindings.IntoSet
+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
+import io.github.wulkanowy.services.sync.works.MessageWork
+import io.github.wulkanowy.services.sync.works.NoteWork
+import io.github.wulkanowy.services.sync.works.RecipientWork
+import io.github.wulkanowy.services.sync.works.TimetableWork
+import io.github.wulkanowy.services.sync.works.Work
+import javax.inject.Singleton
+
+@AssistedModule
+@Module(includes = [AssistedInject_ServicesModule::class])
+abstract class ServicesModule {
+
+ @Module
+ companion object {
+
+ @JvmStatic
+ @Provides
+ fun provideWorkManager() = WorkManager.getInstance()
+
+ @JvmStatic
+ @Singleton
+ @Provides
+ fun provideNotificationManagerCompat(context: Context) = NotificationManagerCompat.from(context)
+
+ @JvmStatic
+ @Singleton
+ @Provides
+ fun provideNotificationManager(context: Context) = context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
+ }
+
+ @Binds
+ @IntoSet
+ abstract fun provideGradeWork(work: GradeWork): Work
+
+ @Binds
+ @IntoSet
+ abstract fun provideNoteWork(work: NoteWork): Work
+
+ @Binds
+ @IntoSet
+ abstract fun provideAttendanceWork(work: AttendanceWork): Work
+
+ @Binds
+ @IntoSet
+ abstract fun provideGradeSummaryWork(work: GradeSummaryWork): Work
+
+ @Binds
+ @IntoSet
+ abstract fun provideExamWork(work: ExamWork): Work
+
+ @Binds
+ @IntoSet
+ abstract fun provideAttendanceSummaryWork(work: AttendanceSummaryWork): Work
+
+ @Binds
+ @IntoSet
+ abstract fun provideTimetableWork(work: TimetableWork): Work
+
+ @Binds
+ @IntoSet
+ abstract fun provideLuckyNumberWork(work: LuckyNumberWork): Work
+
+ @Binds
+ @IntoSet
+ abstract fun provideCompletedLessonWork(work: CompletedLessonWork): Work
+
+ @Binds
+ @IntoSet
+ abstract fun provideHomeworkWork(work: HomeworkWork): Work
+
+ @Binds
+ @IntoSet
+ abstract fun provideMessageWork(work: MessageWork): Work
+
+ @Binds
+ @IntoSet
+ abstract fun provideRecipientWork(work: RecipientWork): Work
+
+ @Binds
+ @IntoSet
+ abstract fun provideGradeStatistics(work: GradeStatisticsWork): Work
+}
diff --git a/app/src/main/java/io/github/wulkanowy/services/job/ServiceHelper.kt b/app/src/main/java/io/github/wulkanowy/services/job/ServiceHelper.kt
deleted file mode 100644
index d81b4b6d..00000000
--- a/app/src/main/java/io/github/wulkanowy/services/job/ServiceHelper.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-package io.github.wulkanowy.services.job
-
-import com.firebase.jobdispatcher.Constraint.ON_ANY_NETWORK
-import com.firebase.jobdispatcher.Constraint.ON_UNMETERED_NETWORK
-import com.firebase.jobdispatcher.FirebaseJobDispatcher
-import com.firebase.jobdispatcher.Lifetime.FOREVER
-import com.firebase.jobdispatcher.RetryStrategy.DEFAULT_EXPONENTIAL
-import com.firebase.jobdispatcher.Trigger.executionWindow
-import io.github.wulkanowy.data.repositories.PreferencesRepository
-import io.github.wulkanowy.utils.isHolidays
-import org.threeten.bp.LocalDate
-import timber.log.Timber
-import javax.inject.Inject
-import javax.inject.Singleton
-
-@Singleton
-class ServiceHelper @Inject constructor(
- private val prefRepository: PreferencesRepository,
- private val dispatcher: FirebaseJobDispatcher
-) {
-
- fun reloadFullSyncService() {
- startFullSyncService(true)
- }
-
- fun startFullSyncService(replaceCurrent: Boolean = false) {
- if (LocalDate.now().isHolidays || !prefRepository.isServiceEnabled) {
- Timber.d("Services disabled or it's holidays")
- return
- }
-
- dispatcher.mustSchedule(
- dispatcher.newJobBuilder()
- .setLifetime(FOREVER)
- .setRecurring(true)
- .setService(SyncWorker::class.java)
- .setTag(SyncWorker.WORK_TAG)
- .setTrigger(
- executionWindow(
- prefRepository.servicesInterval * 60,
- (prefRepository.servicesInterval + 10) * 60
- )
- )
- .setConstraints(if (prefRepository.isServicesOnlyWifi) ON_UNMETERED_NETWORK else ON_ANY_NETWORK)
- .setReplaceCurrent(replaceCurrent)
- .setRetryStrategy(DEFAULT_EXPONENTIAL)
- .build()
- )
-
- Timber.d("Services started")
- }
-
- fun stopFullSyncService() {
- dispatcher.cancel(SyncWorker.WORK_TAG)
- Timber.d("Services stopped")
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt b/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt
deleted file mode 100644
index 65fb3abc..00000000
--- a/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt
+++ /dev/null
@@ -1,174 +0,0 @@
-package io.github.wulkanowy.services.job
-
-import com.firebase.jobdispatcher.JobParameters
-import com.firebase.jobdispatcher.SimpleJobService
-import dagger.android.AndroidInjection
-import io.github.wulkanowy.data.repositories.AttendanceRepository
-import io.github.wulkanowy.data.repositories.ExamRepository
-import io.github.wulkanowy.data.repositories.GradeRepository
-import io.github.wulkanowy.data.repositories.GradeSummaryRepository
-import io.github.wulkanowy.data.repositories.HomeworkRepository
-import io.github.wulkanowy.data.repositories.MessagesRepository
-import io.github.wulkanowy.data.repositories.MessagesRepository.MessageFolder.RECEIVED
-import io.github.wulkanowy.data.repositories.NoteRepository
-import io.github.wulkanowy.data.repositories.PreferencesRepository
-import io.github.wulkanowy.data.repositories.SemesterRepository
-import io.github.wulkanowy.data.repositories.StudentRepository
-import io.github.wulkanowy.data.repositories.TimetableRepository
-import io.github.wulkanowy.services.notification.GradeNotification
-import io.github.wulkanowy.services.notification.MessageNotification
-import io.github.wulkanowy.services.notification.NoteNotification
-import io.github.wulkanowy.utils.friday
-import io.github.wulkanowy.utils.isHolidays
-import io.github.wulkanowy.utils.monday
-import io.reactivex.Single
-import io.reactivex.disposables.CompositeDisposable
-import org.threeten.bp.LocalDate
-import timber.log.Timber
-import javax.inject.Inject
-
-class SyncWorker : SimpleJobService() {
-
- @Inject
- lateinit var student: StudentRepository
-
- @Inject
- lateinit var semester: SemesterRepository
-
- @Inject
- lateinit var gradesDetails: GradeRepository
-
- @Inject
- lateinit var gradesSummary: GradeSummaryRepository
-
- @Inject
- lateinit var attendance: AttendanceRepository
-
- @Inject
- lateinit var exam: ExamRepository
-
- @Inject
- lateinit var timetable: TimetableRepository
-
- @Inject
- lateinit var message: MessagesRepository
-
- @Inject
- lateinit var note: NoteRepository
-
- @Inject
- lateinit var homework: HomeworkRepository
-
- @Inject
- lateinit var prefRepository: PreferencesRepository
-
- private val disposable = CompositeDisposable()
-
- companion object {
- const val WORK_TAG = "FULL_SYNC"
- }
-
- override fun onCreate() {
- super.onCreate()
- AndroidInjection.inject(this)
- }
-
- override fun onRunJob(job: JobParameters?): Int {
- Timber.d("Synchronization started")
-
- val start = LocalDate.now().monday
- val end = LocalDate.now().friday
-
- if (start.isHolidays) return RESULT_FAIL_NORETRY
-
- var error: Throwable? = null
-
- disposable.add(student.getCurrentStudent()
- .flatMap { semester.getCurrentSemester(it, true) }
- .flatMapPublisher {
- Single.merge(
- listOf(
- gradesDetails.getGrades(it, true, true),
- gradesSummary.getGradesSummary(it, true),
- attendance.getAttendance(it, start, end, true),
- exam.getExams(it, start, end, true),
- timetable.getTimetable(it, start, end, true),
- message.getMessages(it.studentId, RECEIVED, true, true),
- note.getNotes(it, true, true),
- homework.getHomework(it, LocalDate.now(), true),
- homework.getHomework(it, LocalDate.now().plusDays(1), true)
- )
- )
- }
- .subscribe({}, { error = it }))
-
- return if (null === error) {
- if (prefRepository.isNotificationsEnable) sendNotifications()
- Timber.d("Synchronization successful")
- RESULT_SUCCESS
- } else {
- Timber.e(error, "Synchronization failed")
- RESULT_FAIL_RETRY
- }
- }
-
- private fun sendNotifications() {
- sendGradeNotifications()
- sendMessageNotification()
- sendNoteNotification()
- }
-
- private fun sendGradeNotifications() {
- disposable.add(student.getCurrentStudent()
- .flatMap { semester.getCurrentSemester(it) }
- .flatMap { gradesDetails.getNewGrades(it) }
- .map { it.filter { grade -> !grade.isNotified } }
- .doOnSuccess {
- if (it.isNotEmpty()) {
- Timber.d("Found ${it.size} unread grades")
- GradeNotification(applicationContext).sendNotification(it)
- }
- }
- .map { it.map { grade -> grade.apply { isNotified = true } } }
- .flatMapCompletable { gradesDetails.updateGrades(it) }
- .subscribe({}, { Timber.e(it, "Grade notifications sending failed") }))
- }
-
- private fun sendMessageNotification() {
- disposable.add(student.getCurrentStudent()
- .flatMap { message.getNewMessages(it) }
- .map { it.filter { message -> !message.isNotified } }
- .doOnSuccess{
- if (it.isNotEmpty()) {
- Timber.d("Found ${it.size} unread messages")
- MessageNotification(applicationContext).sendNotification(it)
- }
- }
- .map { it.map { message -> message.apply { isNotified = true } } }
- .flatMapCompletable { message.updateMessages(it) }
- .subscribe({}, { Timber.e(it, "Message notifications sending failed") })
- )
- }
-
- private fun sendNoteNotification() {
- disposable.add(student.getCurrentStudent()
- .flatMap { semester.getCurrentSemester(it) }
- .flatMap { note.getNewNotes(it) }
- .map { it.filter { note -> !note.isNotified } }
- .doOnSuccess {
- if (it.isNotEmpty()) {
- Timber.d("Found ${it.size} unread notes")
- NoteNotification(applicationContext).sendNotification(it)
- }
- }
- .map { it.map { note -> note.apply { isNotified = true } } }
- .flatMapCompletable { note.updateNotes(it) }
- .subscribe({}, { Timber.e("Notifications sending failed") })
- )
- }
-
- override fun onDestroy() {
- super.onDestroy()
- disposable.clear()
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/services/notification/BaseNotification.kt b/app/src/main/java/io/github/wulkanowy/services/notification/BaseNotification.kt
deleted file mode 100644
index 945d0b15..00000000
--- a/app/src/main/java/io/github/wulkanowy/services/notification/BaseNotification.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package io.github.wulkanowy.services.notification
-
-import android.app.Notification
-import android.app.NotificationManager
-import android.content.Context
-import android.content.Context.NOTIFICATION_SERVICE
-import android.os.Build.VERSION.SDK_INT
-import android.os.Build.VERSION_CODES.O
-import androidx.core.app.NotificationCompat
-import timber.log.Timber
-import kotlin.random.Random
-
-abstract class BaseNotification(protected val context: Context) {
-
- protected val notificationManager: NotificationManager by lazy {
- context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
- }
-
- fun notify(notification: Notification) {
- notificationManager.notify(Random.nextInt(1000), notification)
- }
-
- fun notificationBuilder(channelId: String): NotificationCompat.Builder {
- if (SDK_INT >= O) createChannel(channelId)
- return NotificationCompat.Builder(context, channelId)
- }
-
- fun cancelAll() {
- notificationManager.cancelAll()
- Timber.d("Notifications canceled")
- }
-
- abstract fun createChannel(channelId: String)
-}
diff --git a/app/src/main/java/io/github/wulkanowy/services/notification/GradeNotification.kt b/app/src/main/java/io/github/wulkanowy/services/notification/GradeNotification.kt
deleted file mode 100644
index df57ec28..00000000
--- a/app/src/main/java/io/github/wulkanowy/services/notification/GradeNotification.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-package io.github.wulkanowy.services.notification
-
-import android.annotation.TargetApi
-import android.app.Notification.VISIBILITY_PUBLIC
-import android.app.NotificationChannel
-import android.app.NotificationManager.IMPORTANCE_HIGH
-import android.app.PendingIntent
-import android.app.PendingIntent.FLAG_UPDATE_CURRENT
-import android.content.Context
-import androidx.core.app.NotificationCompat
-import androidx.core.content.ContextCompat
-import io.github.wulkanowy.R
-import io.github.wulkanowy.data.db.entities.Grade
-import io.github.wulkanowy.ui.modules.main.MainActivity
-import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
-import timber.log.Timber
-
-class GradeNotification(context: Context) : BaseNotification(context) {
-
- private val channelId = "Grade_Notify"
-
- @TargetApi(26)
- override fun createChannel(channelId: String) {
- notificationManager.createNotificationChannel(NotificationChannel(
- channelId, context.getString(R.string.notify_grade_channel), IMPORTANCE_HIGH
- ).apply {
- enableLights(true)
- enableVibration(true)
- lockscreenVisibility = VISIBILITY_PUBLIC
- })
- }
-
- fun sendNotification(items: List) {
- notify(notificationBuilder(channelId)
- .setContentTitle(context.resources.getQuantityString(R.plurals.grade_new_items, items.size, items.size))
- .setContentText(context.resources.getQuantityString(R.plurals.notify_grade_new_items, items.size, items.size))
- .setSmallIcon(R.drawable.ic_stat_notify_grade)
- .setAutoCancel(true)
- .setDefaults(NotificationCompat.DEFAULT_ALL)
- .setPriority(NotificationCompat.PRIORITY_HIGH)
- .setColor(ContextCompat.getColor(context, R.color.colorPrimary))
- .setContentIntent(
- PendingIntent.getActivity(context, 0,
- MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 0),
- FLAG_UPDATE_CURRENT
- )
- )
- .setStyle(NotificationCompat.InboxStyle().run {
- setSummaryText(context.resources.getQuantityString(R.plurals.grade_number_item, items.size, items.size))
- items.forEach {
- addLine("${it.subject}: ${it.entry}")
- }
- this
- })
- .build()
- )
-
- Timber.d("Notification sent")
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/services/notification/MessageNotification.kt b/app/src/main/java/io/github/wulkanowy/services/notification/MessageNotification.kt
deleted file mode 100644
index 8733cada..00000000
--- a/app/src/main/java/io/github/wulkanowy/services/notification/MessageNotification.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package io.github.wulkanowy.services.notification
-
-import android.annotation.TargetApi
-import android.app.Notification
-import android.app.NotificationChannel
-import android.app.NotificationManager
-import android.app.PendingIntent
-import android.content.Context
-import androidx.core.app.NotificationCompat
-import androidx.core.content.ContextCompat
-import io.github.wulkanowy.R
-import io.github.wulkanowy.data.db.entities.Message
-import io.github.wulkanowy.ui.modules.main.MainActivity
-import timber.log.Timber
-
-class MessageNotification(context: Context) : BaseNotification(context) {
-
- private val channelId = "Message_Notify"
-
- @TargetApi(26)
- override fun createChannel(channelId: String) {
- notificationManager.createNotificationChannel(NotificationChannel(
- channelId, context.getString(R.string.notify_message_channel), NotificationManager.IMPORTANCE_HIGH
- ).apply {
- enableLights(true)
- enableVibration(true)
- lockscreenVisibility = Notification.VISIBILITY_PUBLIC
- })
- }
-
- fun sendNotification(items: List) {
- notify(notificationBuilder(channelId)
- .setContentTitle(context.resources.getQuantityString(R.plurals.message_new_items, items.size, items.size))
- .setContentText(context.resources.getQuantityString(R.plurals.notify_message_new_items, items.size, items.size))
- .setSmallIcon(R.drawable.ic_stat_notify_message)
- .setAutoCancel(true)
- .setDefaults(NotificationCompat.DEFAULT_ALL)
- .setPriority(NotificationCompat.PRIORITY_HIGH)
- .setColor(ContextCompat.getColor(context, R.color.colorPrimary))
- .setContentIntent(
- PendingIntent.getActivity(context, 0,
- MainActivity.getStartIntent(context).putExtra(MainActivity.EXTRA_START_MENU_INDEX, 4),
- PendingIntent.FLAG_UPDATE_CURRENT
- )
- )
- .setStyle(NotificationCompat.InboxStyle().run {
- setSummaryText(context.resources.getQuantityString(R.plurals.message_number_item, items.size, items.size))
- items.forEach {
- addLine("${it.sender}: ${it.subject}")
- }
- this
- })
- .build()
- )
-
- Timber.d("Notification sent")
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/services/notification/NoteNotification.kt b/app/src/main/java/io/github/wulkanowy/services/notification/NoteNotification.kt
deleted file mode 100644
index 33c2fdc7..00000000
--- a/app/src/main/java/io/github/wulkanowy/services/notification/NoteNotification.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package io.github.wulkanowy.services.notification
-
-import android.annotation.TargetApi
-import android.app.Notification
-import android.app.NotificationChannel
-import android.app.NotificationManager
-import android.app.PendingIntent
-import android.content.Context
-import androidx.core.app.NotificationCompat
-import androidx.core.content.ContextCompat
-import io.github.wulkanowy.R
-import io.github.wulkanowy.data.db.entities.Note
-import io.github.wulkanowy.ui.modules.main.MainActivity
-import timber.log.Timber
-
-class NoteNotification(context: Context) : BaseNotification(context) {
-
- private val channelId = "Note_Notify"
-
- @TargetApi(26)
- override fun createChannel(channelId: String) {
- notificationManager.createNotificationChannel(NotificationChannel(
- channelId, context.getString(R.string.notify_note_channel), NotificationManager.IMPORTANCE_HIGH
- ).apply {
- enableLights(true)
- enableVibration(true)
- lockscreenVisibility = Notification.VISIBILITY_PUBLIC
- })
- }
-
- fun sendNotification(items: List) {
- notify(notificationBuilder(channelId)
- .setContentTitle(context.resources.getQuantityString(R.plurals.note_new_items, items.size, items.size))
- .setContentText(context.resources.getQuantityString(R.plurals.notify_note_new_items, items.size, items.size))
- .setSmallIcon(R.drawable.ic_stat_notify_note)
- .setAutoCancel(true)
- .setDefaults(NotificationCompat.DEFAULT_ALL)
- .setPriority(NotificationCompat.PRIORITY_HIGH)
- .setColor(ContextCompat.getColor(context, R.color.colorPrimary))
- .setContentIntent(
- PendingIntent.getActivity(context, 0,
- MainActivity.getStartIntent(context).putExtra(MainActivity.EXTRA_START_MENU_INDEX, 4),
- PendingIntent.FLAG_UPDATE_CURRENT
- )
- )
- .setStyle(NotificationCompat.InboxStyle().run {
- setSummaryText(context.resources.getQuantityString(R.plurals.note_number_item, items.size, items.size))
- items.forEach {
- addLine("${it.teacher}: ${it.category}")
- }
- this
- })
- .build()
- )
-
- Timber.d("Notification sent")
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/SyncManager.kt b/app/src/main/java/io/github/wulkanowy/services/sync/SyncManager.kt
new file mode 100644
index 00000000..7a9a9956
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/SyncManager.kt
@@ -0,0 +1,55 @@
+package io.github.wulkanowy.services.sync
+
+import android.os.Build.VERSION.SDK_INT
+import android.os.Build.VERSION_CODES.O
+import androidx.work.BackoffPolicy.EXPONENTIAL
+import androidx.work.Constraints
+import androidx.work.ExistingPeriodicWorkPolicy.KEEP
+import androidx.work.ExistingPeriodicWorkPolicy.REPLACE
+import androidx.work.NetworkType.METERED
+import androidx.work.NetworkType.UNMETERED
+import androidx.work.PeriodicWorkRequest
+import androidx.work.WorkManager
+import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
+import io.github.wulkanowy.services.sync.channels.DebugChannel
+import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
+import io.github.wulkanowy.utils.isHolidays
+import org.threeten.bp.LocalDate.now
+import timber.log.Timber
+import java.util.concurrent.TimeUnit.MINUTES
+import javax.inject.Inject
+import javax.inject.Named
+import javax.inject.Singleton
+
+@Singleton
+class SyncManager @Inject constructor(
+ private val workManager: WorkManager,
+ private val preferencesRepository: PreferencesRepository,
+ newEntriesChannel: NewEntriesChannel,
+ debugChannel: DebugChannel,
+ @Named("isDebug") isDebug: Boolean
+) {
+
+ init {
+ if (SDK_INT >= O) newEntriesChannel.create()
+ if (SDK_INT >= O && isDebug) debugChannel.create()
+ if (now().isHolidays) stopSyncWorker()
+ Timber.i("SyncManager was initialized")
+ }
+
+ fun startSyncWorker(restart: Boolean = false) {
+ if (preferencesRepository.isServiceEnabled && !now().isHolidays) {
+ workManager.enqueueUniquePeriodicWork(SyncWorker::class.java.simpleName, if (restart) REPLACE else KEEP,
+ PeriodicWorkRequest.Builder(SyncWorker::class.java, preferencesRepository.servicesInterval, MINUTES)
+ .setBackoffCriteria(EXPONENTIAL, 30, MINUTES)
+ .setConstraints(Constraints.Builder()
+ .setRequiredNetworkType(if (preferencesRepository.isServicesOnlyWifi) METERED else UNMETERED)
+ .build())
+ .build())
+ }
+ }
+
+ fun stopSyncWorker() {
+ workManager.cancelUniqueWork(SyncWorker::class.java.simpleName)
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/SyncWorker.kt b/app/src/main/java/io/github/wulkanowy/services/sync/SyncWorker.kt
new file mode 100644
index 00000000..ec753b7e
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/SyncWorker.kt
@@ -0,0 +1,68 @@
+package io.github.wulkanowy.services.sync
+
+import android.content.Context
+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.ListenableWorker
+import androidx.work.RxWorker
+import androidx.work.WorkerParameters
+import com.squareup.inject.assisted.Assisted
+import com.squareup.inject.assisted.AssistedInject
+import io.github.wulkanowy.R
+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.services.sync.channels.DebugChannel
+import io.github.wulkanowy.services.sync.works.Work
+import io.github.wulkanowy.utils.getCompatColor
+import io.reactivex.Completable
+import io.reactivex.Single
+import timber.log.Timber
+import kotlin.random.Random
+
+class SyncWorker @AssistedInject constructor(
+ @Assisted appContext: Context,
+ @Assisted workerParameters: WorkerParameters,
+ private val studentRepository: StudentRepository,
+ private val semesterRepository: SemesterRepository,
+ private val works: Set<@JvmSuppressWildcards Work>,
+ private val preferencesRepository: PreferencesRepository,
+ private val notificationManager: NotificationManagerCompat
+) : RxWorker(appContext, workerParameters) {
+
+ override fun createWork(): Single {
+ return studentRepository.getCurrentStudent()
+ .flatMapCompletable { student ->
+ semesterRepository.getCurrentSemester(student, true)
+ .flatMapCompletable { semester ->
+ Completable.mergeDelayError(works.map { it.create(student, semester) })
+ }
+ }
+ .toSingleDefault(Result.success())
+ .onErrorReturn {
+ Timber.e(it, "There was an error during synchronization")
+ Result.retry()
+ }
+ .doOnSuccess { if (preferencesRepository.isDebugNotificationEnable) notify(it) }
+ }
+
+ 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_24dp)
+ .setAutoCancel(true)
+ .setColor(applicationContext.getCompatColor(R.color.colorPrimary))
+ .setStyle(BigTextStyle().bigText("${SyncWorker::class.java.simpleName} result: $result"))
+ .setPriority(PRIORITY_DEFAULT)
+ .build())
+ }
+
+ @AssistedInject.Factory
+ interface Factory {
+
+ fun create(appContext: Context, workerParameters: WorkerParameters): ListenableWorker
+ }
+}
+
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/SyncWorkerFactory.kt b/app/src/main/java/io/github/wulkanowy/services/sync/SyncWorkerFactory.kt
new file mode 100644
index 00000000..aadfc27f
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/SyncWorkerFactory.kt
@@ -0,0 +1,20 @@
+package io.github.wulkanowy.services.sync
+
+import android.content.Context
+import androidx.work.ListenableWorker
+import androidx.work.WorkerFactory
+import androidx.work.WorkerParameters
+import timber.log.Timber
+import javax.inject.Inject
+
+class SyncWorkerFactory @Inject constructor(private val syncWorkerFactory: SyncWorker.Factory) : WorkerFactory() {
+
+ override fun createWorker(appContext: Context, workerClassName: String, workerParameters: WorkerParameters): ListenableWorker? {
+ return if (workerClassName == SyncWorker::class.java.name) {
+ syncWorkerFactory.create(appContext, workerParameters)
+ } else {
+ Timber.e(IllegalArgumentException("Unknown worker class name: $workerClassName"))
+ null
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/channels/DebugChannel.kt b/app/src/main/java/io/github/wulkanowy/services/sync/channels/DebugChannel.kt
new file mode 100644
index 00000000..02fff569
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/channels/DebugChannel.kt
@@ -0,0 +1,28 @@
+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
+import android.app.NotificationManager.IMPORTANCE_DEFAULT
+import android.content.Context
+import io.github.wulkanowy.R
+import javax.inject.Inject
+
+@TargetApi(26)
+class DebugChannel @Inject constructor(
+ private val notificationManager: NotificationManager,
+ private val context: Context
+) {
+
+ companion object {
+ const val CHANNEL_ID = "debug_channel"
+ }
+
+ fun create() {
+ notificationManager.createNotificationChannel(
+ NotificationChannel(CHANNEL_ID, context.getString(R.string.channel_debug), IMPORTANCE_DEFAULT).apply {
+ lockscreenVisibility = VISIBILITY_PUBLIC
+ })
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/channels/NewEntriesChannel.kt b/app/src/main/java/io/github/wulkanowy/services/sync/channels/NewEntriesChannel.kt
new file mode 100644
index 00000000..8e24a2a6
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/channels/NewEntriesChannel.kt
@@ -0,0 +1,30 @@
+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
+import android.app.NotificationManager.IMPORTANCE_HIGH
+import android.content.Context
+import io.github.wulkanowy.R
+import javax.inject.Inject
+
+@TargetApi(26)
+class NewEntriesChannel @Inject constructor(
+ private val notificationManager: NotificationManager,
+ private val context: Context
+) {
+
+ companion object {
+ const val CHANNEL_ID = "new_entries_channel"
+ }
+
+ fun create() {
+ notificationManager.createNotificationChannel(
+ NotificationChannel(CHANNEL_ID, context.getString(R.string.channel_new_entries), IMPORTANCE_HIGH).apply {
+ enableLights(true)
+ enableVibration(true)
+ lockscreenVisibility = VISIBILITY_PUBLIC
+ })
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceSummaryWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceSummaryWork.kt
new file mode 100644
index 00000000..01978c5b
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceSummaryWork.kt
@@ -0,0 +1,17 @@
+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.attendancesummary.AttendanceSummaryRepository
+import io.reactivex.Completable
+import javax.inject.Inject
+
+class AttendanceSummaryWork @Inject constructor(
+ private val attendanceSummaryRepository: AttendanceSummaryRepository
+) : Work {
+
+ override fun create(student: Student, semester: Semester): Completable {
+ return attendanceSummaryRepository.getAttendanceSummary(semester, -1, true).ignoreElement()
+ }
+}
+
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceWork.kt
new file mode 100644
index 00000000..e4b55b0e
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceWork.kt
@@ -0,0 +1,18 @@
+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.attendance.AttendanceRepository
+import io.github.wulkanowy.utils.friday
+import io.github.wulkanowy.utils.monday
+import io.reactivex.Completable
+import org.threeten.bp.LocalDate.now
+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)
+ .ignoreElement()
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/CompletedLessonWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/CompletedLessonWork.kt
new file mode 100644
index 00000000..29642ad6
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/CompletedLessonWork.kt
@@ -0,0 +1,21 @@
+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.completedlessons.CompletedLessonsRepository
+import io.github.wulkanowy.utils.friday
+import io.github.wulkanowy.utils.monday
+import io.reactivex.Completable
+import org.threeten.bp.LocalDate.now
+import javax.inject.Inject
+
+class CompletedLessonWork @Inject constructor(
+ private val completedLessonsRepository: CompletedLessonsRepository
+) : Work {
+
+ override fun create(student: Student, semester: Semester): Completable {
+ return completedLessonsRepository.getCompletedLessons(semester, now().monday, now().friday, true)
+ .ignoreElement()
+ }
+}
+
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/ExamWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/ExamWork.kt
new file mode 100644
index 00000000..8744fcc7
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/ExamWork.kt
@@ -0,0 +1,17 @@
+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.exam.ExamRepository
+import io.github.wulkanowy.utils.friday
+import io.github.wulkanowy.utils.monday
+import io.reactivex.Completable
+import org.threeten.bp.LocalDate.now
+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()
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeStatisticsWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeStatisticsWork.kt
new file mode 100644
index 00000000..1de39a95
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeStatisticsWork.kt
@@ -0,0 +1,16 @@
+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.gradestatistics.GradeStatisticsRepository
+import io.reactivex.Completable
+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)
+ .ignoreElement()
+ }
+}
+
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeSummaryWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeSummaryWork.kt
new file mode 100644
index 00000000..6de0bc5b
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeSummaryWork.kt
@@ -0,0 +1,14 @@
+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()
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeWork.kt
new file mode 100644
index 00000000..66316934
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeWork.kt
@@ -0,0 +1,61 @@
+package io.github.wulkanowy.services.sync.works
+
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_UPDATE_CURRENT
+import android.content.Context
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationCompat.DEFAULT_ALL
+import androidx.core.app.NotificationCompat.PRIORITY_HIGH
+import androidx.core.app.NotificationManagerCompat
+import io.github.wulkanowy.R
+import io.github.wulkanowy.data.db.entities.Grade
+import io.github.wulkanowy.data.db.entities.Semester
+import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.data.repositories.grade.GradeRepository
+import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
+import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
+import io.github.wulkanowy.ui.modules.main.MainActivity
+import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
+import io.github.wulkanowy.utils.getCompatColor
+import io.reactivex.Completable
+import javax.inject.Inject
+import kotlin.random.Random
+
+class GradeWork @Inject constructor(
+ private val context: Context,
+ private val notificationManager: NotificationManagerCompat,
+ private val gradeRepository: GradeRepository,
+ private val preferencesRepository: PreferencesRepository
+) : Work {
+
+ override fun create(student: Student, semester: Semester): Completable {
+ return gradeRepository.getGrades(student, semester, true, preferencesRepository.isNotificationsEnable)
+ .flatMap { gradeRepository.getNotNotifiedGrades(semester) }
+ .flatMapCompletable {
+ if (it.isNotEmpty()) notify(it)
+ gradeRepository.updateGrades(it.onEach { grade -> grade.isNotified = true })
+ }
+ }
+
+ private fun notify(grades: List) {
+ notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(context, NewEntriesChannel.CHANNEL_ID)
+ .setContentTitle(context.resources.getQuantityString(R.plurals.grade_new_items, grades.size, grades.size))
+ .setContentText(context.resources.getQuantityString(R.plurals.grade_notify_new_items, grades.size, grades.size))
+ .setSmallIcon(R.drawable.ic_stat_notify_grade)
+ .setAutoCancel(true)
+ .setPriority(PRIORITY_HIGH)
+ .setDefaults(DEFAULT_ALL)
+ .setColor(context.getCompatColor(R.color.colorPrimary))
+ .setContentIntent(
+ PendingIntent.getActivity(context, 0,
+ MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 0), FLAG_UPDATE_CURRENT))
+ .setStyle(NotificationCompat.InboxStyle().run {
+ setSummaryText(context.resources.getQuantityString(R.plurals.grade_number_item, grades.size, grades.size))
+ grades.forEach { addLine("${it.subject}: ${it.entry}") }
+ this
+ })
+ .build()
+ )
+ }
+}
+
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/HomeworkWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/HomeworkWork.kt
new file mode 100644
index 00000000..32b356c6
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/HomeworkWork.kt
@@ -0,0 +1,17 @@
+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.homework.HomeworkRepository
+import io.github.wulkanowy.utils.friday
+import io.github.wulkanowy.utils.monday
+import io.reactivex.Completable
+import org.threeten.bp.LocalDate.now
+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()
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/LuckyNumberWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/LuckyNumberWork.kt
new file mode 100644
index 00000000..ca7aaac6
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/LuckyNumberWork.kt
@@ -0,0 +1,55 @@
+package io.github.wulkanowy.services.sync.works
+
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_UPDATE_CURRENT
+import android.content.Context
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationCompat.DEFAULT_ALL
+import androidx.core.app.NotificationCompat.PRIORITY_HIGH
+import androidx.core.app.NotificationManagerCompat
+import io.github.wulkanowy.R
+import io.github.wulkanowy.data.db.entities.LuckyNumber
+import io.github.wulkanowy.data.db.entities.Semester
+import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.data.repositories.luckynumber.LuckyNumberRepository
+import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
+import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
+import io.github.wulkanowy.ui.modules.main.MainActivity
+import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
+import io.github.wulkanowy.utils.getCompatColor
+import io.reactivex.Completable
+import javax.inject.Inject
+import kotlin.random.Random
+
+class LuckyNumberWork @Inject constructor(
+ private val context: Context,
+ private val notificationManager: NotificationManagerCompat,
+ private val luckyNumberRepository: LuckyNumberRepository,
+ private val preferencesRepository: PreferencesRepository
+) : Work {
+
+ override fun create(student: Student, semester: Semester): Completable {
+ return luckyNumberRepository.getLuckyNumber(semester, true, preferencesRepository.isNotificationsEnable)
+ .flatMap { luckyNumberRepository.getNotNotifiedLuckyNumber(semester) }
+ .flatMapCompletable {
+ notify(it)
+ luckyNumberRepository.updateLuckyNumber(it.apply { isNotified = true })
+ }
+ }
+
+ private fun notify(luckyNumber: LuckyNumber) {
+ notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(context, NewEntriesChannel.CHANNEL_ID)
+ .setContentTitle(context.getString(R.string.lucky_number_notify_new_item_title))
+ .setContentText(context.getString(R.string.lucky_number_notify_new_item, luckyNumber.luckyNumber))
+ .setSmallIcon(R.drawable.ic_stat_notify_lucky_number)
+ .setAutoCancel(true)
+ .setDefaults(DEFAULT_ALL)
+ .setPriority(PRIORITY_HIGH)
+ .setColor(context.getCompatColor(R.color.colorPrimary))
+ .setContentIntent(
+ PendingIntent.getActivity(context, 0,
+ MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 4), FLAG_UPDATE_CURRENT)
+ )
+ .build())
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/MessageWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/MessageWork.kt
new file mode 100644
index 00000000..7ab2c8d4
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/MessageWork.kt
@@ -0,0 +1,61 @@
+package io.github.wulkanowy.services.sync.works
+
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_UPDATE_CURRENT
+import android.content.Context
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationCompat.DEFAULT_ALL
+import androidx.core.app.NotificationCompat.PRIORITY_HIGH
+import androidx.core.app.NotificationManagerCompat
+import io.github.wulkanowy.R
+import io.github.wulkanowy.data.db.entities.Message
+import io.github.wulkanowy.data.db.entities.Semester
+import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED
+import io.github.wulkanowy.data.repositories.message.MessageRepository
+import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
+import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
+import io.github.wulkanowy.ui.modules.main.MainActivity
+import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
+import io.github.wulkanowy.utils.getCompatColor
+import io.reactivex.Completable
+import javax.inject.Inject
+import kotlin.random.Random
+
+class MessageWork @Inject constructor(
+ private val context: Context,
+ private val notificationManager: NotificationManagerCompat,
+ private val messageRepository: MessageRepository,
+ private val preferencesRepository: PreferencesRepository
+) : Work {
+
+ override fun create(student: Student, semester: Semester): Completable {
+ return messageRepository.getMessages(student, RECEIVED, true, preferencesRepository.isNotificationsEnable)
+ .flatMap { messageRepository.getNotNotifiedMessages(student) }
+ .flatMapCompletable {
+ if (it.isNotEmpty()) notify(it)
+ messageRepository.updateMessages(it.onEach { message -> message.isNotified = true })
+ }
+ }
+
+ private fun notify(messages: List) {
+ notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(context, NewEntriesChannel.CHANNEL_ID)
+ .setContentTitle(context.resources.getQuantityString(R.plurals.message_new_items, messages.size, messages.size))
+ .setContentText(context.resources.getQuantityString(R.plurals.message_notify_new_items, messages.size, messages.size))
+ .setSmallIcon(R.drawable.ic_stat_notify_message)
+ .setAutoCancel(true)
+ .setDefaults(DEFAULT_ALL)
+ .setPriority(PRIORITY_HIGH)
+ .setColor(context.getCompatColor(R.color.colorPrimary))
+ .setContentIntent(
+ PendingIntent.getActivity(context, 0,
+ MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 4), FLAG_UPDATE_CURRENT)
+ )
+ .setStyle(NotificationCompat.InboxStyle().run {
+ setSummaryText(context.resources.getQuantityString(R.plurals.message_number_item, messages.size, messages.size))
+ messages.forEach { addLine("${it.sender}: ${it.subject}") }
+ this
+ })
+ .build())
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/NoteWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/NoteWork.kt
new file mode 100644
index 00000000..d0e8fe21
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/NoteWork.kt
@@ -0,0 +1,61 @@
+package io.github.wulkanowy.services.sync.works
+
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_UPDATE_CURRENT
+import android.content.Context
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationCompat.DEFAULT_ALL
+import androidx.core.app.NotificationCompat.PRIORITY_HIGH
+import androidx.core.app.NotificationManagerCompat
+import io.github.wulkanowy.R
+import io.github.wulkanowy.data.db.entities.Note
+import io.github.wulkanowy.data.db.entities.Semester
+import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.data.repositories.note.NoteRepository
+import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
+import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
+import io.github.wulkanowy.ui.modules.main.MainActivity
+import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
+import io.github.wulkanowy.utils.getCompatColor
+import io.reactivex.Completable
+import javax.inject.Inject
+import kotlin.random.Random
+
+class NoteWork @Inject constructor(
+ private val context: Context,
+ private val notificationManager: NotificationManagerCompat,
+ private val noteRepository: NoteRepository,
+ private val preferencesRepository: PreferencesRepository
+) : Work {
+
+ override fun create(student: Student, semester: Semester): Completable {
+ return noteRepository.getNotes(student, semester, true, preferencesRepository.isNotificationsEnable)
+ .flatMap { noteRepository.getNotNotifiedNotes(student) }
+ .flatMapCompletable {
+ if (it.isNotEmpty()) notify(it)
+ noteRepository.updateNotes(it.onEach { note -> note.isNotified = true })
+ }
+ }
+
+ private fun notify(notes: List) {
+ notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(context, NewEntriesChannel.CHANNEL_ID)
+ .setContentTitle(context.resources.getQuantityString(R.plurals.note_new_items, notes.size, notes.size))
+ .setContentText(context.resources.getQuantityString(R.plurals.note_notify_new_items, notes.size, notes.size))
+ .setSmallIcon(R.drawable.ic_stat_notify_note)
+ .setAutoCancel(true)
+ .setDefaults(DEFAULT_ALL)
+ .setPriority(PRIORITY_HIGH)
+ .setColor(context.getCompatColor(R.color.colorPrimary))
+ .setContentIntent(
+ PendingIntent.getActivity(context, 0,
+ MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 4), FLAG_UPDATE_CURRENT)
+ )
+ .setStyle(NotificationCompat.InboxStyle().run {
+ setSummaryText(context.resources.getQuantityString(R.plurals.note_number_item, notes.size, notes.size))
+ notes.forEach { addLine("${it.teacher}: ${it.category}") }
+ this
+ })
+ .build())
+ }
+}
+
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/RecipientWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/RecipientWork.kt
new file mode 100644
index 00000000..af8de434
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/RecipientWork.kt
@@ -0,0 +1,24 @@
+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.recipient.RecipientRepository
+import io.github.wulkanowy.data.repositories.reportingunit.ReportingUnitRepository
+import io.reactivex.Completable
+import javax.inject.Inject
+
+class RecipientWork @Inject constructor(
+ private val reportingUnitRepository: ReportingUnitRepository,
+ private val recipientRepository: RecipientRepository
+) : Work {
+
+ override fun create(student: Student, semester: Semester): Completable {
+ return reportingUnitRepository.getReportingUnits(student)
+ .flatMapCompletable { units ->
+ Completable.mergeDelayError(units.map {
+ recipientRepository.getRecipients(student, 2, it).ignoreElement()
+ })
+ }
+ }
+}
+
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/TimetableWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/TimetableWork.kt
new file mode 100644
index 00000000..743ae0e8
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/TimetableWork.kt
@@ -0,0 +1,18 @@
+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.timetable.TimetableRepository
+import io.github.wulkanowy.utils.friday
+import io.github.wulkanowy.utils.monday
+import io.reactivex.Completable
+import org.threeten.bp.LocalDate.now
+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)
+ .ignoreElement()
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/Work.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/Work.kt
new file mode 100644
index 00000000..1601a103
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/Work.kt
@@ -0,0 +1,11 @@
+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.reactivex.Completable
+
+interface Work {
+
+ fun create(student: Student, semester: Semester): Completable
+}
+
diff --git a/app/src/main/java/io/github/wulkanowy/services/widgets/TimetableWidgetService.kt b/app/src/main/java/io/github/wulkanowy/services/widgets/TimetableWidgetService.kt
index d1e275b7..0432ee14 100644
--- a/app/src/main/java/io/github/wulkanowy/services/widgets/TimetableWidgetService.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/widgets/TimetableWidgetService.kt
@@ -4,10 +4,11 @@ import android.content.Intent
import android.widget.RemoteViewsService
import dagger.android.AndroidInjection
import io.github.wulkanowy.data.db.SharedPrefHelper
-import io.github.wulkanowy.data.repositories.SemesterRepository
-import io.github.wulkanowy.data.repositories.StudentRepository
-import io.github.wulkanowy.data.repositories.TimetableRepository
+import io.github.wulkanowy.data.repositories.semester.SemesterRepository
+import io.github.wulkanowy.data.repositories.student.StudentRepository
+import io.github.wulkanowy.data.repositories.timetable.TimetableRepository
import io.github.wulkanowy.ui.widgets.timetable.TimetableWidgetFactory
+import io.github.wulkanowy.utils.SchedulersProvider
import javax.inject.Inject
class TimetableWidgetService : RemoteViewsService() {
@@ -24,8 +25,11 @@ class TimetableWidgetService : RemoteViewsService() {
@Inject
lateinit var sharedPref: SharedPrefHelper
+ @Inject
+ lateinit var schedulers: SchedulersProvider
+
override fun onGetViewFactory(intent: Intent?): RemoteViewsFactory {
AndroidInjection.inject(this)
- return TimetableWidgetFactory(timetableRepo, studentRepo, semesterRepo, sharedPref, applicationContext, intent)
+ return TimetableWidgetFactory(timetableRepo, studentRepo, semesterRepo, sharedPref, schedulers, applicationContext, intent)
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt
index 667b46ff..6e863c51 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt
@@ -13,7 +13,7 @@ abstract class BaseFragment : DaggerFragment(), BaseView {
if (messageContainer == null) (activity as? BaseActivity)?.showError(text, error)
else messageContainer?.also {
Snackbar.make(it, text, Snackbar.LENGTH_LONG).setAction(R.string.all_details) {
- ErrorDialog.newInstance(error).show(fragmentManager, error.toString())
+ ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
}.show()
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragmentPagerAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragmentPagerAdapter.kt
new file mode 100644
index 00000000..fcf7e980
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragmentPagerAdapter.kt
@@ -0,0 +1,31 @@
+package io.github.wulkanowy.ui.base
+
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentManager
+import androidx.fragment.app.FragmentPagerAdapter
+
+class BaseFragmentPagerAdapter(private val fragmentManager: FragmentManager) : FragmentPagerAdapter(fragmentManager) {
+
+ private val pages = mutableMapOf()
+
+ var containerId = 0
+
+ fun getFragmentInstance(position: Int): Fragment? {
+ if (containerId == 0) throw IllegalArgumentException("Container id is 0")
+ return fragmentManager.findFragmentByTag("android:switcher:$containerId:$position")
+ }
+
+ fun addFragments(fragments: List) {
+ fragments.forEach { pages[it] = null }
+ }
+
+ fun addFragmentsWithTitle(pages: Map) {
+ this.pages.putAll(pages)
+ }
+
+ override fun getItem(position: Int) = pages.keys.elementAt(position)
+
+ override fun getCount() = pages.size
+
+ override fun getPageTitle(position: Int) = pages.values.elementAt(position)
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BasePagerAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BasePagerAdapter.kt
deleted file mode 100644
index 000efdcd..00000000
--- a/app/src/main/java/io/github/wulkanowy/ui/base/BasePagerAdapter.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package io.github.wulkanowy.ui.base
-
-import android.view.ViewGroup
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentManager
-import androidx.fragment.app.FragmentStatePagerAdapter
-
-class BasePagerAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAdapter(fragmentManager) {
-
- val fragments = mutableMapOf()
-
- val registeredFragments = mutableMapOf()
-
- override fun getItem(position: Int) = fragments.values.elementAt(position)
-
- override fun getCount() = fragments.size
-
- override fun getPageTitle(position: Int): CharSequence? {
- return fragments.keys.elementAtOrNull(position)
- }
-
- override fun instantiateItem(container: ViewGroup, position: Int): Any {
- return super.instantiateItem(container, position).also {
- registeredFragments[position] = it as Fragment
- }
- }
-
- override fun destroyItem(container: ViewGroup, position: Int, fragment: Any) {
- registeredFragments.remove(position)
- super.destroyItem(container, position, fragment)
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/ErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/ui/base/ErrorHandler.kt
index e0e32e2c..83cbf0ef 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/base/ErrorHandler.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/base/ErrorHandler.kt
@@ -1,7 +1,9 @@
package io.github.wulkanowy.ui.base
import android.content.res.Resources
+import com.readystatesoftware.chuck.api.ChuckCollector
import io.github.wulkanowy.R
+import io.github.wulkanowy.api.interceptor.FeatureDisabledException
import io.github.wulkanowy.api.interceptor.ServiceUnavailableException
import io.github.wulkanowy.api.login.NotLoggedInException
import timber.log.Timber
@@ -9,11 +11,12 @@ import java.net.SocketTimeoutException
import java.net.UnknownHostException
import javax.inject.Inject
-open class ErrorHandler @Inject constructor(protected val resources: Resources) {
+open class ErrorHandler @Inject constructor(protected val resources: Resources, private val chuckCollector: ChuckCollector) {
var showErrorMessage: (String, Throwable) -> Unit = { _, _ -> }
fun dispatch(error: Throwable) {
+ chuckCollector.onError(error.javaClass.simpleName, error)
Timber.e(error, "An exception occurred while the Wulkanowy was running")
proceed(error)
}
@@ -24,6 +27,7 @@ open class ErrorHandler @Inject constructor(protected val resources: Resources)
is SocketTimeoutException -> resources.getString(R.string.error_timeout)
is NotLoggedInException -> resources.getString(R.string.error_login_failed)
is ServiceUnavailableException -> resources.getString(R.string.error_service_unavailable)
+ is FeatureDisabledException -> resources.getString(R.string.error_feature_disabled)
else -> resources.getString(R.string.error_unknown)
}), error)
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/session/SessionErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/ui/base/session/SessionErrorHandler.kt
index 89654732..1d81e932 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/base/session/SessionErrorHandler.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/base/session/SessionErrorHandler.kt
@@ -1,11 +1,15 @@
package io.github.wulkanowy.ui.base.session
import android.content.res.Resources
+import com.readystatesoftware.chuck.api.ChuckCollector
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.security.ScramblerException
import javax.inject.Inject
-class SessionErrorHandler @Inject constructor(resources: Resources) : ErrorHandler(resources) {
+open class SessionErrorHandler @Inject constructor(
+ resources: Resources,
+ chuckCollector: ChuckCollector
+) : ErrorHandler(resources, chuckCollector) {
var onDecryptionFail: () -> Unit = {}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt
index ddc4e11f..1002f914 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt
@@ -1,12 +1,14 @@
package io.github.wulkanowy.ui.modules.about
import android.content.Intent
+import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.mikepenz.aboutlibraries.LibsBuilder
import com.mikepenz.aboutlibraries.LibsFragmentCompat
+import io.github.wulkanowy.BuildConfig
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.main.MainView
@@ -36,12 +38,12 @@ class AboutFragment : BaseFragment(), AboutView, MainView.TitledView {
.withAboutVersionShown(true)
.withAboutIconShown(true)
.withLicenseShown(true)
- .withAboutSpecial1(getString(R.string.about_source_code))
- .withAboutSpecial2(getString(R.string.about_feedback))
+ .withAboutSpecial1(getString(R.string.about_discord_invite))
+ .withAboutSpecial2(getString(R.string.about_homepage))
+ .withAboutSpecial3(getString(R.string.about_feedback))
.withFields(R.string::class.java.fields)
.withCheckCachedDetection(false)
- .withExcludedLibraries("fastadapter", "AndroidIconics", "gson",
- "Jsoup", "Retrofit", "okio", "OkHttp")
+ .withExcludedLibraries("fastadapter", "AndroidIconics", "gson", "Jsoup", "Retrofit", "okio", "OkHttp")
.withOnExtraListener { presenter.onExtraSelect(it) })
}.let {
fragmentCompat.onCreateView(inflater.context, inflater, container, savedInstanceState, it)
@@ -53,12 +55,33 @@ class AboutFragment : BaseFragment(), AboutView, MainView.TitledView {
fragmentCompat.onViewCreated(view, savedInstanceState)
}
- override fun openSourceWebView() {
- startActivity(Intent.parseUri("https://github.com/wulkanowy/wulkanowy", 0))
+ override fun openDiscordInviteView() {
+ startActivity(Intent.parseUri("https://discord.gg/vccAQBr", 0))
}
- override fun openIssuesWebView() {
- startActivity(Intent.parseUri("https://github.com/wulkanowy/wulkanowy/issues", 0))
+ override fun openHomepageWebView() {
+ startActivity(Intent.parseUri("https://wulkanowy.github.io/", 0))
+ }
+
+ override fun openEmailClientView() {
+ val intent = Intent(Intent.ACTION_SENDTO).apply {
+ data = Uri.parse("mailto:")
+ putExtra(Intent.EXTRA_EMAIL, Array(1) { "wulkanowyinc@gmail.com" })
+ putExtra(Intent.EXTRA_SUBJECT, "Zgłoszenie błędu")
+ putExtra(Intent.EXTRA_TEXT,"Tu umieść treść zgłoszenia\n\n" + "-".repeat(40) + "\n" + """
+ Build: ${BuildConfig.VERSION_CODE}
+ SDK: ${android.os.Build.VERSION.SDK_INT}
+ Device: ${android.os.Build.MANUFACTURER} ${android.os.Build.MODEL}
+ """.trimIndent())
+ }
+
+ context?.let {
+ if (intent.resolveActivity(it.packageManager) != null) {
+ startActivity(Intent.createChooser(intent, getString(R.string.about_feedback)))
+ } else {
+ startActivity(Intent.parseUri("https://github.com/wulkanowy/wulkanowy/issues", 0))
+ }
+ }
}
override fun onDestroyView() {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutPresenter.kt
index 9a512f70..116dbef3 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutPresenter.kt
@@ -15,21 +15,28 @@ class AboutPresenter @Inject constructor(
private val analytics: FirebaseAnalyticsHelper
) : BasePresenter(errorHandler) {
+ override fun onAttachView(view: AboutView) {
+ super.onAttachView(view)
+ Timber.i("About view is attached")
+ }
+
fun onExtraSelect(type: Libs.SpecialButton?) {
view?.run {
when (type) {
SPECIAL1 -> {
- Timber.i("Opening github page")
- analytics.logEvent("open_page", mapOf("name" to "github"))
- openSourceWebView()
+ Timber.i("Opening discord invide page")
+ analytics.logEvent("open_page", "name" to "discord")
+ openDiscordInviteView()
}
SPECIAL2 -> {
- Timber.i("Opening issues page")
- analytics.logEvent("open_page", mapOf("name" to "issues"))
- openIssuesWebView()
+ Timber.i("Opening home page")
+ analytics.logEvent("open_page", "name" to "home")
+ openHomepageWebView()
}
SPECIAL3 -> {
- //empty for now
+ Timber.i("Opening email client")
+ analytics.logEvent("open_page", "name" to "email")
+ openEmailClientView()
}
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutView.kt
index a3ae2ada..5b206ad8 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutView.kt
@@ -4,7 +4,9 @@ import io.github.wulkanowy.ui.base.BaseView
interface AboutView : BaseView {
- fun openSourceWebView()
+ fun openDiscordInviteView()
- fun openIssuesWebView()
+ fun openEmailClientView()
+
+ fun openHomepageWebView()
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt
index e1459fe7..0fc6cc45 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt
@@ -1,34 +1,41 @@
package io.github.wulkanowy.ui.modules.account
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
-import io.github.wulkanowy.data.repositories.StudentRepository
+import io.github.wulkanowy.data.repositories.student.StudentRepository
+import io.github.wulkanowy.services.sync.SyncManager
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.SchedulersProvider
import io.reactivex.Single
+import timber.log.Timber
import javax.inject.Inject
class AccountPresenter @Inject constructor(
private val errorHandler: ErrorHandler,
private val studentRepository: StudentRepository,
+ private val syncManager: SyncManager,
private val schedulers: SchedulersProvider
) : BasePresenter(errorHandler) {
override fun onAttachView(view: AccountView) {
super.onAttachView(view)
+ Timber.i("Account dialog is attached")
view.initView()
loadData()
}
fun onAddSelected() {
+ Timber.i("Select add account")
view?.openLoginView()
}
fun onRemoveSelected() {
+ Timber.i("Select remove account")
view?.showConfirmDialog()
}
fun onLogoutConfirm() {
+ Timber.i("Attempt to logout current user ")
disposable.add(studentRepository.getCurrentStudent()
.flatMapCompletable { studentRepository.logoutStudent(it) }
.andThen(studentRepository.getSavedStudents(false))
@@ -41,31 +48,55 @@ class AccountPresenter @Inject constructor(
.doFinally { view?.dismissView() }
.subscribe({
view?.apply {
- if (it.isEmpty()) openClearLoginView()
- else recreateView()
+ if (it.isEmpty()) {
+ Timber.i("Logout result: Open login view")
+ syncManager.stopSyncWorker()
+ openClearLoginView()
+ } else {
+ Timber.i("Logout result: Switch to another student")
+ recreateView()
+ }
}
- }, { errorHandler.dispatch(it) }))
+ }, {
+ Timber.i("Logout result: An exception occurred")
+ errorHandler.dispatch(it)
+ }))
}
fun onItemSelected(item: AbstractFlexibleItem<*>) {
if (item is AccountItem) {
+ Timber.i("Select student item ${item.student.id}")
if (item.student.isCurrent) {
view?.dismissView()
} else {
+ Timber.i("Attempt to change a student")
disposable.add(studentRepository.switchStudent(item.student)
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
- .subscribe({ view?.recreateView() }, { errorHandler.dispatch(it) }))
+ .subscribe({
+ Timber.i("Change a student result: Success")
+ view?.recreateView()
+ }, {
+ Timber.i("Change a student result: An exception occurred")
+ errorHandler.dispatch(it)
+ }))
}
}
}
private fun loadData() {
+ Timber.i("Loading account data started")
disposable.add(studentRepository.getSavedStudents(false)
.map { it.map { item -> AccountItem(item) } }
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
- .subscribe({ view?.updateData(it) }, { errorHandler.dispatch(it) }))
+ .subscribe({
+ Timber.i("Loading account result: Success")
+ view?.updateData(it)
+ }, {
+ Timber.i("Loading account result: An exception occurred")
+ errorHandler.dispatch(it)
+ }))
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt
index 3b60d8cb..f0cab7f1 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt
@@ -8,6 +8,7 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import eu.davidea.flexibleadapter.FlexibleAdapter
+import eu.davidea.flexibleadapter.common.FlexibleItemDecoration
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.R
@@ -66,6 +67,10 @@ class AttendanceFragment : BaseSessionFragment(), AttendanceView, MainView.MainC
attendanceRecycler.run {
layoutManager = SmoothScrollLinearLayoutManager(context)
adapter = attendanceAdapter
+ addItemDecoration(FlexibleItemDecoration(context)
+ .withDefaultDivider()
+ .withDrawDividerOnLastItem(false)
+ )
}
attendanceSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
attendancePreviousButton.setOnClickListener { presenter.onPreviousDay() }
@@ -113,6 +118,10 @@ class AttendanceFragment : BaseSessionFragment(), AttendanceView, MainView.MainC
attendanceProgress.visibility = if (show) View.VISIBLE else View.GONE
}
+ override fun enableSwipe(enable: Boolean) {
+ attendanceSwipe.isEnabled = enable
+ }
+
override fun showContent(show: Boolean) {
attendanceRecycler.visibility = if (show) View.VISIBLE else View.GONE
}
@@ -130,7 +139,7 @@ class AttendanceFragment : BaseSessionFragment(), AttendanceView, MainView.MainC
}
override fun showAttendanceDialog(lesson: Attendance) {
- AttendanceDialog.newInstance(lesson).show(fragmentManager, lesson.toString())
+ (activity as? MainActivity)?.showDialogFragment(AttendanceDialog.newInstance(lesson))
}
override fun openSummaryView() {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt
index 9be87b44..988681b1 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt
@@ -2,10 +2,10 @@ package io.github.wulkanowy.ui.modules.attendance
import com.google.firebase.analytics.FirebaseAnalytics.Param.START_DATE
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
-import io.github.wulkanowy.data.repositories.AttendanceRepository
-import io.github.wulkanowy.data.repositories.PreferencesRepository
-import io.github.wulkanowy.data.repositories.SemesterRepository
-import io.github.wulkanowy.data.repositories.StudentRepository
+import io.github.wulkanowy.data.repositories.attendance.AttendanceRepository
+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.ui.base.session.BaseSessionPresenter
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
@@ -18,6 +18,7 @@ import io.github.wulkanowy.utils.toFormattedString
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDate.now
import org.threeten.bp.LocalDate.ofEpochDay
+import timber.log.Timber
import java.util.concurrent.TimeUnit.MILLISECONDS
import javax.inject.Inject
@@ -36,6 +37,7 @@ class AttendancePresenter @Inject constructor(
fun onAttachView(view: AttendanceView, date: Long?) {
super.onAttachView(view)
+ Timber.i("Attendance view is attached")
view.initView()
loadData(ofEpochDay(date ?: now().previousOrSameSchoolDay.toEpochDay()))
reloadView()
@@ -52,10 +54,12 @@ class AttendancePresenter @Inject constructor(
}
fun onSwipeRefresh() {
+ Timber.i("Force refreshing the attendance")
loadData(currentDate, true)
}
fun onViewReselected() {
+ Timber.i("Attendance view is reselected")
view?.also { view ->
if (view.currentStackSize == 1) {
now().previousOrSameSchoolDay.also {
@@ -69,7 +73,10 @@ class AttendancePresenter @Inject constructor(
}
fun onAttendanceItemSelected(item: AbstractFlexibleItem<*>?) {
- if (item is AttendanceItem) view?.showAttendanceDialog(item.attendance)
+ if (item is AttendanceItem) {
+ Timber.i("Select attendance item ${item.attendance.id}")
+ view?.showAttendanceDialog(item.attendance)
+ }
}
fun onSummarySwitchSelected(): Boolean {
@@ -78,6 +85,7 @@ class AttendancePresenter @Inject constructor(
}
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) {
+ Timber.i("Loading attendance data started")
currentDate = date
disposable.apply {
clear()
@@ -97,16 +105,19 @@ class AttendancePresenter @Inject constructor(
view?.run {
hideRefresh()
showProgress(false)
+ enableSwipe(true)
}
}
.subscribe({
+ Timber.i("Loading attendance result: Success")
view?.apply {
updateData(it)
showEmpty(it.isEmpty())
showContent(it.isNotEmpty())
}
- analytics.logEvent("load_attendance", mapOf("items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd")))
+ analytics.logEvent("load_attendance", "items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd"))
}) {
+ Timber.i("Loading attendance result: An exception occurred")
view?.run { showEmpty(isViewEmpty) }
errorHandler.dispatch(it)
}
@@ -115,8 +126,10 @@ class AttendancePresenter @Inject constructor(
}
private fun reloadView() {
+ Timber.i("Reload attendance view with the date ${currentDate.toFormattedString()}")
view?.apply {
showProgress(true)
+ enableSwipe(false)
showContent(false)
showEmpty(false)
clearData()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceView.kt
index f839e89a..ef3b874b 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceView.kt
@@ -25,6 +25,8 @@ interface AttendanceView : BaseSessionView {
fun showProgress(show: Boolean)
+ fun enableSwipe(enable: Boolean)
+
fun showContent(show: Boolean)
fun showPreButton(show: Boolean)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryFragment.kt
index 1a3fc16f..b8d2c952 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryFragment.kt
@@ -4,6 +4,7 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
+import android.view.View.INVISIBLE
import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.ArrayAdapter
@@ -96,12 +97,16 @@ class AttendanceSummaryFragment : BaseSessionFragment(), AttendanceSummaryView,
attendanceSummaryProgress.visibility = if (show) VISIBLE else GONE
}
+ override fun enableSwipe(enable: Boolean) {
+ attendanceSummarySwipe.isEnabled = enable
+ }
+
override fun showContent(show: Boolean) {
attendanceSummaryRecycler.visibility = if (show) VISIBLE else GONE
}
override fun showSubjects(show: Boolean) {
- attendanceSummarySubjects.visibility = if (show) VISIBLE else VISIBLE
+ attendanceSummarySubjectsContainer.visibility = if (show) VISIBLE else INVISIBLE
}
override fun hideRefresh() {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryPresenter.kt
index 5086e80c..8b17f743 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryPresenter.kt
@@ -2,16 +2,17 @@ package io.github.wulkanowy.ui.modules.attendance.summary
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.Subject
-import io.github.wulkanowy.data.repositories.AttendanceSummaryRepository
-import io.github.wulkanowy.data.repositories.SemesterRepository
-import io.github.wulkanowy.data.repositories.StudentRepository
-import io.github.wulkanowy.data.repositories.SubjectRepostory
+import io.github.wulkanowy.data.repositories.attendancesummary.AttendanceSummaryRepository
+import io.github.wulkanowy.data.repositories.semester.SemesterRepository
+import io.github.wulkanowy.data.repositories.student.StudentRepository
+import io.github.wulkanowy.data.repositories.subject.SubjectRepository
import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.github.wulkanowy.utils.SchedulersProvider
import io.github.wulkanowy.utils.calculatePercentage
import io.github.wulkanowy.utils.getFormattedName
+import timber.log.Timber
import java.lang.String.format
import java.util.Locale.FRANCE
import java.util.concurrent.TimeUnit.MILLISECONDS
@@ -20,7 +21,7 @@ import javax.inject.Inject
class AttendanceSummaryPresenter @Inject constructor(
private val errorHandler: SessionErrorHandler,
private val attendanceSummaryRepository: AttendanceSummaryRepository,
- private val subjectRepository: SubjectRepostory,
+ private val subjectRepository: SubjectRepository,
private val studentRepository: StudentRepository,
private val semesterRepository: SemesterRepository,
private val schedulers: SchedulersProvider,
@@ -34,25 +35,32 @@ class AttendanceSummaryPresenter @Inject constructor(
fun onAttachView(view: AttendanceSummaryView, subjectId: Int?) {
super.onAttachView(view)
+ Timber.i("Attendance summary view is attached with subject id ${subjectId ?: -1}")
view.initView()
loadData(subjectId ?: -1)
loadSubjects()
}
fun onSwipeRefresh() {
+ Timber.i("Force refreshing the attendance summary")
loadData(currentSubjectId, true)
}
fun onSubjectSelected(name: String) {
+ Timber.i("Select attendance summary subject $name")
view?.run {
showContent(false)
showProgress(true)
+ enableSwipe(false)
clearView()
}
- loadData(subjects.singleOrNull { it.name == name }?.realId ?: -1)
+ (subjects.singleOrNull { it.name == name }?.realId ?: -1).let {
+ if (it != currentSubjectId) loadData(it)
+ }
}
private fun loadData(subjectId: Int, forceRefresh: Boolean = false) {
+ Timber.i("Loading attendance summary data started")
currentSubjectId = subjectId
disposable.apply {
clear()
@@ -67,16 +75,19 @@ class AttendanceSummaryPresenter @Inject constructor(
view?.run {
hideRefresh()
showProgress(false)
+ enableSwipe(true)
}
}
.subscribe({
+ Timber.i("Loading attendance summary result: Success")
view?.apply {
showEmpty(it.first.isEmpty())
showContent(it.first.isNotEmpty())
updateDataSet(it.first, it.second)
}
- analytics.logEvent("load_attendance_summary", mapOf("items" to it.first.size, "force_refresh" to forceRefresh, "item_id" to subjectId))
+ analytics.logEvent("load_attendance_summary", "items" to it.first.size, "force_refresh" to forceRefresh, "item_id" to subjectId)
}) {
+ Timber.i("Loading attendance summary result: An exception occurred")
view?.run { showEmpty(isViewEmpty) }
errorHandler.dispatch(it)
}
@@ -85,6 +96,7 @@ class AttendanceSummaryPresenter @Inject constructor(
}
private fun loadSubjects() {
+ Timber.i("Loading attendance summary subjects started")
disposable.add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getCurrentSemester(it) }
.flatMap { subjectRepository.getSubjects(it) }
@@ -93,11 +105,15 @@ class AttendanceSummaryPresenter @Inject constructor(
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
.subscribe({
+ Timber.i("Loading attendance summary subjects result: Success")
view?.run {
view?.updateSubjects(it)
showSubjects(true)
}
- }, { errorHandler.dispatch(it) })
+ }, {
+ Timber.i("Loading attendance summary subjects result: An exception occurred")
+ errorHandler.dispatch(it)
+ })
)
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryView.kt
index af62a2de..e4c36db7 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryView.kt
@@ -14,6 +14,8 @@ interface AttendanceSummaryView : BaseSessionView {
fun showProgress(show: Boolean)
+ fun enableSwipe(enable: Boolean)
+
fun showEmpty(show: Boolean)
fun updateDataSet(data: List, header: AttendanceSummaryScrollableHeader)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt
index d39688d4..97e97727 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt
@@ -8,11 +8,13 @@ import android.view.View.INVISIBLE
import android.view.View.VISIBLE
import android.view.ViewGroup
import eu.davidea.flexibleadapter.FlexibleAdapter
+import eu.davidea.flexibleadapter.common.FlexibleItemDecoration
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.ui.base.session.BaseSessionFragment
+import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.utils.setOnItemClickListener
import kotlinx.android.synthetic.main.fragment_exam.*
@@ -55,6 +57,10 @@ class ExamFragment : BaseSessionFragment(), ExamView, MainView.MainChildView, Ma
examRecycler.run {
layoutManager = SmoothScrollLinearLayoutManager(context)
adapter = examAdapter
+ addItemDecoration(FlexibleItemDecoration(context)
+ .withDefaultDivider(R.layout.item_exam)
+ .withDrawDividerOnLastItem(false)
+ )
}
examSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
examPreviousButton.setOnClickListener { presenter.onPreviousWeek() }
@@ -93,6 +99,10 @@ class ExamFragment : BaseSessionFragment(), ExamView, MainView.MainChildView, Ma
examProgress.visibility = if (show) VISIBLE else GONE
}
+ override fun enableSwipe(enable: Boolean) {
+ examSwipe.isEnabled = enable
+ }
+
override fun showContent(show: Boolean) {
examRecycler.visibility = if (show) VISIBLE else GONE
}
@@ -106,7 +116,7 @@ class ExamFragment : BaseSessionFragment(), ExamView, MainView.MainChildView, Ma
}
override fun showExamDialog(exam: Exam) {
- ExamDialog.newInstance(exam).show(fragmentManager, exam.toString())
+ (activity as? MainActivity)?.showDialogFragment(ExamDialog.newInstance(exam))
}
override fun onSaveInstanceState(outState: Bundle) {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamPresenter.kt
index 88a0eaa5..4b6ef298 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamPresenter.kt
@@ -3,9 +3,9 @@ package io.github.wulkanowy.ui.modules.exam
import com.google.firebase.analytics.FirebaseAnalytics.Param.START_DATE
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.data.db.entities.Exam
-import io.github.wulkanowy.data.repositories.ExamRepository
-import io.github.wulkanowy.data.repositories.SemesterRepository
-import io.github.wulkanowy.data.repositories.StudentRepository
+import io.github.wulkanowy.data.repositories.exam.ExamRepository
+import io.github.wulkanowy.data.repositories.semester.SemesterRepository
+import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
@@ -18,6 +18,7 @@ import io.github.wulkanowy.utils.toFormattedString
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDate.now
import org.threeten.bp.LocalDate.ofEpochDay
+import timber.log.Timber
import java.util.concurrent.TimeUnit.MILLISECONDS
import javax.inject.Inject
@@ -35,6 +36,7 @@ class ExamPresenter @Inject constructor(
fun onAttachView(view: ExamView, date: Long?) {
super.onAttachView(view)
+ Timber.i("Exam view is attached")
view.initView()
loadData(ofEpochDay(date ?: now().nextOrSameSchoolDay.toEpochDay()))
reloadView()
@@ -51,14 +53,19 @@ class ExamPresenter @Inject constructor(
}
fun onSwipeRefresh() {
+ Timber.i("Force refreshing the exam")
loadData(currentDate, true)
}
fun onExamItemSelected(item: AbstractFlexibleItem<*>?) {
- if (item is ExamItem) view?.showExamDialog(item.exam)
+ if (item is ExamItem) {
+ Timber.i("Select exam item ${item.exam.id}")
+ view?.showExamDialog(item.exam)
+ }
}
fun onViewReselected() {
+ Timber.i("Exam view is reselected")
now().nextOrSameSchoolDay.also {
if (currentDate != it) {
loadData(it)
@@ -68,6 +75,7 @@ class ExamPresenter @Inject constructor(
}
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) {
+ Timber.i("Loading exam data started")
currentDate = date
disposable.apply {
clear()
@@ -84,16 +92,19 @@ class ExamPresenter @Inject constructor(
view?.run {
hideRefresh()
showProgress(false)
+ enableSwipe(true)
}
}
.subscribe({
+ Timber.i("Loading exam result: Success")
view?.apply {
updateData(it)
showEmpty(it.isEmpty())
showContent(it.isNotEmpty())
}
- analytics.logEvent("load_exam", mapOf("items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd")))
+ analytics.logEvent("load_exam", "items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd"))
}) {
+ Timber.i("Loading exam result: An exception occurred")
view?.run { showEmpty(isViewEmpty) }
errorHandler.dispatch(it)
})
@@ -109,8 +120,10 @@ class ExamPresenter @Inject constructor(
}
private fun reloadView() {
+ Timber.i("Reload exam view with the date ${currentDate.toFormattedString()}")
view?.apply {
showProgress(true)
+ enableSwipe(false)
showContent(false)
showEmpty(false)
clearData()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamView.kt
index b6a926f3..2ced3f2d 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamView.kt
@@ -23,6 +23,8 @@ interface ExamView : BaseSessionView {
fun showProgress(show: Boolean)
+ fun enableSwipe(enable: Boolean)
+
fun showContent(show: Boolean)
fun showNextButton(show: Boolean)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/CustomTabLayout.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/CustomTabLayout.kt
new file mode 100644
index 00000000..e6f01497
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/CustomTabLayout.kt
@@ -0,0 +1,34 @@
+package io.github.wulkanowy.ui.modules.grade
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.ViewGroup
+import com.google.android.material.tabs.TabLayout
+
+/**
+ * @see Tabs don't fit to screen with tabmode=scrollable, Even with a Custom Tab Layout
+ */
+class CustomTabLayout : TabLayout {
+
+ constructor(context: Context) : super(context)
+
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
+
+ constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ setMeasuredDimension(widthMeasureSpec, heightMeasureSpec)
+ val tabLayout = getChildAt(0) as ViewGroup
+ val childCount = tabLayout.childCount
+
+ if (childCount == 0) return
+
+ val tabMinWidth = context.resources.displayMetrics.widthPixels / childCount
+
+ for (i in 0 until childCount) {
+ tabLayout.getChildAt(i).minimumWidth = tabMinWidth
+ }
+
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt
index a4d948a9..20d3fad7 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt
@@ -11,9 +11,10 @@ import android.view.View.VISIBLE
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import io.github.wulkanowy.R
-import io.github.wulkanowy.ui.base.BasePagerAdapter
+import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter
import io.github.wulkanowy.ui.base.session.BaseSessionFragment
import io.github.wulkanowy.ui.modules.grade.details.GradeDetailsFragment
+import io.github.wulkanowy.ui.modules.grade.statistics.GradeStatisticsFragment
import io.github.wulkanowy.ui.modules.grade.summary.GradeSummaryFragment
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.utils.setOnSelectPageListener
@@ -26,7 +27,9 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView,
lateinit var presenter: GradePresenter
@Inject
- lateinit var pagerAdapter: BasePagerAdapter
+ lateinit var pagerAdapter: BaseFragmentPagerAdapter
+
+ private var semesterSwitchMenu: MenuItem? = null
companion object {
private const val SAVED_SEMESTER_KEY = "CURRENT_SEMESTER"
@@ -56,18 +59,27 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView,
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
inflater?.inflate(R.menu.action_menu_grade, menu)
+ semesterSwitchMenu = menu?.findItem(R.id.gradeMenuSemester)
+ presenter.onCreateMenu()
}
override fun initView() {
- pagerAdapter.fragments.putAll(mapOf(
- getString(R.string.all_details) to GradeDetailsFragment.newInstance(),
- getString(R.string.grade_menu_summary) to GradeSummaryFragment.newInstance()
- ))
+ pagerAdapter.apply {
+ containerId = gradeViewPager.id
+ addFragmentsWithTitle(mapOf(
+ GradeDetailsFragment.newInstance() to getString(R.string.all_details),
+ GradeSummaryFragment.newInstance() to getString(R.string.grade_menu_summary),
+ GradeStatisticsFragment.newInstance() to getString(R.string.grade_menu_statistics)
+ ))
+ }
+
gradeViewPager.run {
adapter = pagerAdapter
+ offscreenPageLimit = 3
setOnSelectPageListener { presenter.onPageSelected(it) }
}
gradeTabLayout.setupWithViewPager(gradeViewPager)
+ gradeSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
@@ -88,8 +100,20 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView,
gradeProgress.visibility = if (show) VISIBLE else INVISIBLE
}
- override fun showEmpty() {
- gradeEmpty.visibility = VISIBLE
+ override fun showEmpty(show: Boolean) {
+ gradeEmpty.visibility = if (show) VISIBLE else INVISIBLE
+ }
+
+ override fun showRefresh(show: Boolean) {
+ gradeSwipe.isRefreshing = show
+ }
+
+ override fun showSemesterSwitch(show: Boolean) {
+ semesterSwitchMenu?.isVisible = show
+ }
+
+ override fun enableSwipe(enable: Boolean) {
+ gradeSwipe.isEnabled = enable
}
override fun showSemesterDialog(selectedIndex: Int) {
@@ -117,15 +141,15 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView,
}
override fun notifyChildLoadData(index: Int, semesterId: Int, forceRefresh: Boolean) {
- (childFragmentManager.fragments[index] as GradeView.GradeChildView).onParentLoadData(semesterId, forceRefresh)
+ (pagerAdapter.getFragmentInstance(index) as? GradeView.GradeChildView)?.onParentLoadData(semesterId, forceRefresh)
}
override fun notifyChildParentReselected(index: Int) {
- (pagerAdapter.registeredFragments[index] as? GradeView.GradeChildView)?.onParentReselected()
+ (pagerAdapter.getFragmentInstance(index) as? GradeView.GradeChildView)?.onParentReselected()
}
override fun notifyChildSemesterChange(index: Int) {
- (pagerAdapter.registeredFragments[index] as? GradeView.GradeChildView)?.onParentChangeSemester()
+ (pagerAdapter.getFragmentInstance(index) as? GradeView.GradeChildView)?.onParentChangeSemester()
}
override fun onSaveInstanceState(outState: Bundle) {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeModule.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeModule.kt
index c47ddc57..46a923d9 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeModule.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeModule.kt
@@ -5,8 +5,9 @@ import dagger.Provides
import dagger.android.ContributesAndroidInjector
import io.github.wulkanowy.di.scopes.PerChildFragment
import io.github.wulkanowy.di.scopes.PerFragment
-import io.github.wulkanowy.ui.base.BasePagerAdapter
+import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter
import io.github.wulkanowy.ui.modules.grade.details.GradeDetailsFragment
+import io.github.wulkanowy.ui.modules.grade.statistics.GradeStatisticsFragment
import io.github.wulkanowy.ui.modules.grade.summary.GradeSummaryFragment
@Module
@@ -18,7 +19,7 @@ abstract class GradeModule {
@JvmStatic
@PerFragment
@Provides
- fun provideGradePagerAdapter(fragment: GradeFragment) = BasePagerAdapter(fragment.childFragmentManager)
+ fun provideGradeAdapter(fragment: GradeFragment) = BaseFragmentPagerAdapter(fragment.childFragmentManager)
}
@PerChildFragment
@@ -28,4 +29,8 @@ abstract class GradeModule {
@PerChildFragment
@ContributesAndroidInjector
abstract fun binGradeSummaryFragment(): GradeSummaryFragment
+
+ @PerChildFragment
+ @ContributesAndroidInjector
+ abstract fun binGradeStatisticsFragment(): GradeStatisticsFragment
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt
index d2dd8031..98eb2a9f 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt
@@ -1,13 +1,14 @@
package io.github.wulkanowy.ui.modules.grade
import io.github.wulkanowy.data.db.entities.Semester
-import io.github.wulkanowy.data.repositories.SemesterRepository
-import io.github.wulkanowy.data.repositories.StudentRepository
+import io.github.wulkanowy.data.repositories.semester.SemesterRepository
+import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.github.wulkanowy.utils.SchedulersProvider
import io.reactivex.Completable
+import timber.log.Timber
import java.util.concurrent.TimeUnit.MILLISECONDS
import javax.inject.Inject
@@ -28,15 +29,24 @@ class GradePresenter @Inject constructor(
fun onAttachView(view: GradeView, savedIndex: Int?) {
super.onAttachView(view)
+ Timber.i("Grade view is attached")
disposable.add(Completable.timer(150, MILLISECONDS, schedulers.mainThread)
.subscribe {
selectedIndex = savedIndex ?: 0
- view.initView()
+ view.run {
+ initView()
+ enableSwipe(false)
+ }
loadData()
})
}
+ fun onCreateMenu() {
+ if (semesters.isEmpty()) view?.showSemesterSwitch(false)
+ }
+
fun onViewReselected() {
+ Timber.i("Grade view is reselected")
view?.run { notifyChildParentReselected(currentPageIndex) }
}
@@ -47,13 +57,14 @@ class GradePresenter @Inject constructor(
fun onSemesterSelected(index: Int) {
if (selectedIndex != index - 1) {
+ Timber.i("Change semester in grade view to ${index + 1}")
selectedIndex = index + 1
loadedSemesterId.clear()
view?.let {
notifyChildrenSemesterChange()
loadChild(it.currentPageIndex)
}
- analytics.logEvent("changed_semester", mapOf("number" to index + 1))
+ analytics.logEvent("changed_semester", "number" to index + 1)
}
}
@@ -65,6 +76,7 @@ class GradePresenter @Inject constructor(
view?.apply {
showContent(true)
showProgress(false)
+ showEmpty(false)
loadedSemesterId[currentPageIndex] = semesterId
}
}
@@ -73,7 +85,12 @@ class GradePresenter @Inject constructor(
loadChild(index)
}
+ fun onSwipeRefresh() {
+ loadData()
+ }
+
private fun loadData() {
+ Timber.i("Loading grade data started")
disposable.add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getSemesters(it) }
.doOnSuccess {
@@ -84,11 +101,21 @@ class GradePresenter @Inject constructor(
}
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
- .subscribe({ view?.run { loadChild(currentPageIndex) } }) {
+ .doFinally { view?.showRefresh(false) }
+ .subscribe({
+ view?.run {
+ Timber.i("Loading grade result: Attempt load index $currentPageIndex")
+ loadChild(currentPageIndex)
+ enableSwipe(false)
+ showSemesterSwitch(true)
+ }
+ }) {
+ Timber.i("Loading grade result: An exception occurred")
errorHandler.dispatch(it)
view?.run {
showProgress(false)
- showEmpty()
+ showEmpty(true)
+ enableSwipe(true)
}
})
}
@@ -96,12 +123,13 @@ class GradePresenter @Inject constructor(
private fun loadChild(index: Int, forceRefresh: Boolean = false) {
semesters.first { it.semesterName == selectedIndex }.semesterId.also {
if (forceRefresh || loadedSemesterId[index] != it) {
+ Timber.i("Load grade child view index: $index")
view?.notifyChildLoadData(index, it, forceRefresh)
}
}
}
private fun notifyChildrenSemesterChange() {
- for (i in 0..1) view?.notifyChildSemesterChange(i)
+ for (i in 0..2) view?.notifyChildSemesterChange(i)
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeView.kt
index 3f1a197c..9fdd46b1 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeView.kt
@@ -12,10 +12,16 @@ interface GradeView : BaseSessionView {
fun showProgress(show: Boolean)
- fun showEmpty()
+ fun showEmpty(show: Boolean)
+
+ fun showRefresh(show: Boolean)
+
+ fun showSemesterSwitch(show: Boolean)
fun showSemesterDialog(selectedIndex: Int)
+ fun enableSwipe(enable: Boolean)
+
fun notifyChildLoadData(index: Int, semesterId: Int, forceRefresh: Boolean)
fun notifyChildParentReselected(index: Int)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsDialog.kt
index 19b462b1..0abeaeea 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsDialog.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsDialog.kt
@@ -9,21 +9,26 @@ import androidx.fragment.app.DialogFragment
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.utils.colorStringId
+import io.github.wulkanowy.utils.getBackgroundColor
import io.github.wulkanowy.utils.toFormattedString
-import io.github.wulkanowy.utils.valueColor
import kotlinx.android.synthetic.main.dialog_grade.*
-
class GradeDetailsDialog : DialogFragment() {
private lateinit var grade: Grade
+ private lateinit var colorScheme: String
+
companion object {
private const val ARGUMENT_KEY = "Item"
+ private const val COLOR_SCHEME_KEY = "Scheme"
- fun newInstance(grade: Grade): GradeDetailsDialog {
+ fun newInstance(grade: Grade, colorScheme: String): GradeDetailsDialog {
return GradeDetailsDialog().apply {
- arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, grade) }
+ arguments = Bundle().apply {
+ putSerializable(ARGUMENT_KEY, grade)
+ putString(COLOR_SCHEME_KEY, colorScheme)
+ }
}
}
}
@@ -33,6 +38,7 @@ class GradeDetailsDialog : DialogFragment() {
setStyle(STYLE_NO_TITLE, 0)
arguments?.run {
grade = getSerializable(ARGUMENT_KEY) as Grade
+ colorScheme = getString(COLOR_SCHEME_KEY) ?: "default"
}
}
@@ -57,7 +63,7 @@ class GradeDetailsDialog : DialogFragment() {
gradeDialogValue.run {
text = grade.entry
- setBackgroundResource(grade.valueColor)
+ setBackgroundResource(grade.getBackgroundColor(colorScheme))
}
gradeDialogTeacherValue.text = if (grade.teacher.isBlank()) {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt
index a9ee9ce2..205cde77 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt
@@ -20,6 +20,7 @@ import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.ui.base.session.BaseSessionFragment
import io.github.wulkanowy.ui.modules.grade.GradeFragment
import io.github.wulkanowy.ui.modules.grade.GradeView
+import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.utils.setOnItemClickListener
import kotlinx.android.synthetic.main.fragment_grade_details.*
import javax.inject.Inject
@@ -45,6 +46,9 @@ class GradeDetailsFragment : BaseSessionFragment(), GradeDetailsView, GradeView.
override val weightString: String
get() = getString(R.string.grade_weight)
+ override val noDescriptionString: String
+ get() = getString(R.string.all_no_description)
+
override val isViewEmpty
get() = gradeDetailsAdapter.isEmpty
@@ -77,6 +81,9 @@ class GradeDetailsFragment : BaseSessionFragment(), GradeDetailsView, GradeView.
gradeDetailsRecycler.run {
layoutManager = SmoothScrollLinearLayoutManager(context)
adapter = gradeDetailsAdapter
+ addItemDecoration(GradeDetailsHeaderItemDecoration(context)
+ .withDefaultDivider(R.layout.header_grade_details)
+ )
}
gradeDetailsSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
}
@@ -103,7 +110,7 @@ class GradeDetailsFragment : BaseSessionFragment(), GradeDetailsView, GradeView.
}
override fun scrollToStart() {
- gradeDetailsAdapter.smoothScrollToPosition(0)
+ gradeDetailsRecycler.scrollToPosition(0)
}
override fun getHeaderOfItem(item: AbstractFlexibleItem<*>): IExpandable<*, out IFlexible<*>>? {
@@ -118,6 +125,10 @@ class GradeDetailsFragment : BaseSessionFragment(), GradeDetailsView, GradeView.
gradeDetailsProgress.visibility = if (show) VISIBLE else GONE
}
+ override fun enableSwipe(enable: Boolean) {
+ gradeDetailsSwipe.isEnabled = enable
+ }
+
override fun showContent(show: Boolean) {
gradeDetailsRecycler.visibility = if (show) VISIBLE else INVISIBLE
}
@@ -130,8 +141,8 @@ class GradeDetailsFragment : BaseSessionFragment(), GradeDetailsView, GradeView.
gradeDetailsSwipe.isRefreshing = show
}
- override fun showGradeDialog(grade: Grade) {
- GradeDetailsDialog.newInstance(grade).show(fragmentManager, grade.toString())
+ override fun showGradeDialog(grade: Grade, colorScheme: String) {
+ (activity as? MainActivity)?.showDialogFragment(GradeDetailsDialog.newInstance(grade, colorScheme))
}
override fun onParentLoadData(semesterId: Int, forceRefresh: Boolean) {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsHeader.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsHeader.kt
index 5dec00a9..e5f6e824 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsHeader.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsHeader.kt
@@ -38,6 +38,7 @@ class GradeDetailsHeader(
gradeHeaderAverage.text = average
gradeHeaderNumber.text = number
gradeHeaderNote.visibility = if (newGrades > 0) VISIBLE else GONE
+ gradeHeaderContainer.isEnabled = isExpandable
isViewExpandable = isExpandable
}
@@ -52,6 +53,7 @@ class GradeDetailsHeader(
if (subject != other.subject) return false
if (number != other.number) return false
if (average != other.average) return false
+ if (isExpandable != other.isExpandable) return false
return true
}
@@ -60,6 +62,7 @@ class GradeDetailsHeader(
var result = subject.hashCode()
result = 31 * result + number.hashCode()
result = 31 * result + average.hashCode()
+ result = 31 * result + isExpandable.hashCode()
return result
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsHeaderItemDecoration.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsHeaderItemDecoration.kt
new file mode 100644
index 00000000..39a911e6
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsHeaderItemDecoration.kt
@@ -0,0 +1,38 @@
+package io.github.wulkanowy.ui.modules.grade.details
+
+import android.content.Context
+import android.graphics.Canvas
+import androidx.recyclerview.widget.RecyclerView
+import eu.davidea.flexibleadapter.common.FlexibleItemDecoration
+
+class GradeDetailsHeaderItemDecoration(context: Context) : FlexibleItemDecoration(context) {
+
+ override fun drawVertical(canvas: Canvas, parent: RecyclerView) {
+ canvas.save()
+ val left: Int
+ val right: Int
+ if (parent.clipToPadding) {
+ left = parent.paddingLeft
+ right = parent.width - parent.paddingRight
+ canvas.clipRect(left, parent.paddingTop, right,
+ parent.height - parent.paddingBottom)
+ } else {
+ left = 0
+ right = parent.width
+ }
+
+ val itemCount = parent.childCount
+ for (i in 1 until itemCount) {
+ val child = parent.getChildAt(i)
+ val viewHolder = parent.getChildViewHolder(child)
+ if (shouldDrawDivider(viewHolder)) {
+ parent.getDecoratedBoundsWithMargins(child, mBounds)
+ val bottom = mBounds.top + Math.round(child.translationY)
+ val top = bottom - mDivider.intrinsicHeight
+ mDivider.setBounds(left, top, right, bottom)
+ mDivider.draw(canvas)
+ }
+ }
+ canvas.restore()
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsItem.kt
index 18c2656d..de1d88f7 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsItem.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsItem.kt
@@ -14,8 +14,12 @@ import io.github.wulkanowy.utils.toFormattedString
import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.item_grade_details.*
-class GradeDetailsItem(val grade: Grade, private val weightString: String, private val valueColor: Int)
- : AbstractFlexibleItem() {
+class GradeDetailsItem(
+ val grade: Grade,
+ private val valueBgColor: Int,
+ private val weightString: String,
+ private val noDescriptionString: String
+) : AbstractFlexibleItem() {
override fun getLayoutRes() = R.layout.item_grade_details
@@ -24,14 +28,20 @@ class GradeDetailsItem(val grade: Grade, private val weightString: String, priva
}
@SuppressLint("SetTextI18n")
- override fun bindViewHolder(adapter: FlexibleAdapter>, holder: ViewHolder,
- position: Int, payloads: MutableList?) {
+ override fun bindViewHolder(
+ adapter: FlexibleAdapter>, holder: ViewHolder,
+ position: Int, payloads: MutableList?
+ ) {
holder.run {
gradeItemValue.run {
text = grade.entry
- setBackgroundResource(valueColor)
+ setBackgroundResource(valueBgColor)
+ }
+ gradeItemDescription.text = when {
+ grade.description.isNotBlank() -> grade.description
+ grade.gradeSymbol.isNotBlank() -> grade.gradeSymbol
+ else -> noDescriptionString
}
- gradeItemDescription.text = if (grade.description.isNotBlank()) grade.description else grade.gradeSymbol
gradeItemDate.text = grade.date.toFormattedString()
gradeItemWeight.text = "$weightString: ${grade.weight}"
gradeItemNote.visibility = if (!grade.isRead) VISIBLE else GONE
@@ -45,22 +55,23 @@ class GradeDetailsItem(val grade: Grade, private val weightString: String, priva
other as GradeDetailsItem
if (grade != other.grade) return false
+ if (grade.id != other.grade.id) return false
if (weightString != other.weightString) return false
- if (valueColor != other.valueColor) return false
+ if (valueBgColor != other.valueBgColor) return false
return true
}
override fun hashCode(): Int {
var result = grade.hashCode()
+ result = 31 * result + grade.id.toInt()
result = 31 * result + weightString.hashCode()
- result = 31 * result + valueColor
+ result = 31 * result + valueBgColor
return result
}
-
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter),
- LayoutContainer {
+ LayoutContainer {
override val containerView: View
get() = contentView
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt
index b80a7108..1be0b36f 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt
@@ -2,17 +2,17 @@ package io.github.wulkanowy.ui.modules.grade.details
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.data.db.entities.Grade
-import io.github.wulkanowy.data.repositories.GradeRepository
-import io.github.wulkanowy.data.repositories.PreferencesRepository
-import io.github.wulkanowy.data.repositories.SemesterRepository
-import io.github.wulkanowy.data.repositories.StudentRepository
+import io.github.wulkanowy.data.repositories.grade.GradeRepository
+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.ui.base.session.BaseSessionPresenter
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.github.wulkanowy.utils.SchedulersProvider
import io.github.wulkanowy.utils.calcAverage
import io.github.wulkanowy.utils.changeModifier
-import io.github.wulkanowy.utils.valueColor
+import io.github.wulkanowy.utils.getBackgroundColor
import timber.log.Timber
import javax.inject.Inject
@@ -40,8 +40,9 @@ class GradeDetailsPresenter @Inject constructor(
fun onGradeItemSelected(item: AbstractFlexibleItem<*>?) {
if (item is GradeDetailsItem) {
+ Timber.i("Select grade item ${item.grade.id}")
view?.apply {
- showGradeDialog(item.grade)
+ showGradeDialog(item.grade, preferencesRepository.gradeColorTheme)
if (!item.grade.isRead) {
item.grade.isRead = true
updateItem(item)
@@ -58,18 +59,29 @@ class GradeDetailsPresenter @Inject constructor(
}
fun onMarkAsReadSelected(): Boolean {
+ Timber.i("Select mark grades as read")
disposable.add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getSemesters(it) }
- .flatMap { gradeRepository.getNewGrades(it.first { item -> item.semesterId == currentSemesterId }) }
+ .flatMap { gradeRepository.getUnreadGrades(it.first { item -> item.semesterId == currentSemesterId }) }
.map { it.map { grade -> grade.apply { isRead = true } } }
- .flatMapCompletable { gradeRepository.updateGrades(it) }
+ .flatMapCompletable {
+ Timber.i("Mark as read ${it.size} grades")
+ gradeRepository.updateGrades(it)
+ }
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
- .subscribe({ loadData(currentSemesterId, false) }, { errorHandler.dispatch(it) }))
+ .subscribe({
+ Timber.i("Mark as read result: Success")
+ loadData(currentSemesterId, false)
+ }, {
+ Timber.i("Mark as read result: An exception occurred")
+ errorHandler.dispatch(it)
+ }))
return true
}
fun onSwipeRefresh() {
+ Timber.i("Force refreshing the grade details")
view?.notifyParentRefresh()
}
@@ -85,6 +97,7 @@ class GradeDetailsPresenter @Inject constructor(
fun onParentViewChangeSemester() {
view?.run {
showProgress(true)
+ enableSwipe(false)
showRefresh(false)
showContent(false)
showEmpty(false)
@@ -94,9 +107,11 @@ class GradeDetailsPresenter @Inject constructor(
}
private fun loadData(semesterId: Int, forceRefresh: Boolean) {
+ Timber.i("Loading grade details data started")
disposable.add(studentRepository.getCurrentStudent()
- .flatMap { semesterRepository.getSemesters(it) }
- .flatMap { gradeRepository.getGrades(it.first { item -> item.semesterId == semesterId }, forceRefresh) }
+ .flatMap { semesterRepository.getSemesters(it).map { semester -> semester to it } }
+ .flatMap { gradeRepository.getGrades(it.second, it.first.first { item -> item.semesterId == semesterId }, forceRefresh) }
+ .map { it.sortedByDescending { grade -> grade.date } }
.map { it.map { item -> item.changeModifier(preferencesRepository.gradePlusModifier, preferencesRepository.gradeMinusModifier) } }
.map { createGradeItems(it.groupBy { grade -> grade.subject }.toSortedMap()) }
.subscribeOn(schedulers.backgroundThread)
@@ -105,17 +120,20 @@ class GradeDetailsPresenter @Inject constructor(
view?.run {
showRefresh(false)
showProgress(false)
+ enableSwipe(true)
notifyParentDataLoaded(semesterId)
}
}
.subscribe({
+ Timber.i("Loading grade details result: Success")
view?.run {
showEmpty(it.isEmpty())
showContent(it.isNotEmpty())
updateData(it)
}
- analytics.logEvent("load_grade_details", mapOf("items" to it.size, "force_refresh" to forceRefresh))
+ analytics.logEvent("load_grade_details", "items" to it.size, "force_refresh" to forceRefresh)
}) {
+ Timber.i("Loading grade details result: An exception occurred")
view?.run { showEmpty(isViewEmpty) }
errorHandler.dispatch(it)
})
@@ -134,8 +152,9 @@ class GradeDetailsPresenter @Inject constructor(
subItems = it.value.map { item ->
GradeDetailsItem(
grade = item,
+ valueBgColor = item.getBackgroundColor(preferencesRepository.gradeColorTheme),
weightString = view?.weightString.orEmpty(),
- valueColor = item.valueColor
+ noDescriptionString = view?.noDescriptionString.orEmpty()
)
}
}
@@ -151,10 +170,14 @@ class GradeDetailsPresenter @Inject constructor(
}
private fun updateGrade(grade: Grade) {
+ Timber.i("Attempt to update grade ${grade.id}")
disposable.add(gradeRepository.updateGrade(grade)
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
- .subscribe({}) { error -> errorHandler.dispatch(error) })
- Timber.d("Grade ${grade.id} updated")
+ .subscribe({ Timber.i("Update grade result: Success") })
+ { error ->
+ Timber.i("Update grade result: An exception occurred")
+ errorHandler.dispatch(error)
+ })
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsView.kt
index 24254260..1fb98216 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsView.kt
@@ -16,6 +16,8 @@ interface GradeDetailsView : BaseSessionView {
val weightString: String
+ val noDescriptionString: String
+
fun initView()
fun updateData(data: List)
@@ -28,7 +30,7 @@ interface GradeDetailsView : BaseSessionView {
fun collapseAllItems()
- fun showGradeDialog(grade: Grade)
+ fun showGradeDialog(grade: Grade, colorScheme: String)
fun showContent(show: Boolean)
@@ -36,6 +38,8 @@ interface GradeDetailsView : BaseSessionView {
fun showProgress(show: Boolean)
+ fun enableSwipe(enable: Boolean)
+
fun showRefresh(show: Boolean)
fun notifyParentDataLoaded(semesterId: Int)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsFragment.kt
new file mode 100644
index 00000000..f27a13c8
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsFragment.kt
@@ -0,0 +1,214 @@
+package io.github.wulkanowy.ui.modules.grade.statistics
+
+import android.graphics.Color.WHITE
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ArrayAdapter
+import android.widget.TextView
+import androidx.core.content.ContextCompat
+import com.github.mikephil.charting.components.Legend
+import com.github.mikephil.charting.components.LegendEntry
+import com.github.mikephil.charting.data.PieData
+import com.github.mikephil.charting.data.PieDataSet
+import com.github.mikephil.charting.data.PieEntry
+import com.github.mikephil.charting.formatter.ValueFormatter
+import io.github.wulkanowy.R
+import io.github.wulkanowy.data.db.entities.GradeStatistics
+import io.github.wulkanowy.ui.base.session.BaseSessionFragment
+import io.github.wulkanowy.ui.modules.grade.GradeFragment
+import io.github.wulkanowy.ui.modules.grade.GradeView
+import io.github.wulkanowy.utils.getThemeAttrColor
+import io.github.wulkanowy.utils.setOnItemSelectedListener
+import kotlinx.android.synthetic.main.fragment_grade_statistics.*
+import javax.inject.Inject
+
+class GradeStatisticsFragment : BaseSessionFragment(), GradeStatisticsView, GradeView.GradeChildView {
+
+ @Inject
+ lateinit var presenter: GradeStatisticsPresenter
+
+ private lateinit var subjectsAdapter: ArrayAdapter
+
+ companion object {
+ private const val SAVED_CHART_TYPE = "CURRENT_TYPE"
+
+ fun newInstance() = GradeStatisticsFragment()
+ }
+
+ override val isViewEmpty
+ get() = gradeStatisticsChart.isEmpty
+
+ private lateinit var gradeColors: List>
+
+ private val vulcanGradeColors = listOf(
+ 6 to R.color.grade_vulcan_six,
+ 5 to R.color.grade_vulcan_five,
+ 4 to R.color.grade_vulcan_four,
+ 3 to R.color.grade_vulcan_three,
+ 2 to R.color.grade_vulcan_two,
+ 1 to R.color.grade_vulcan_one
+ )
+
+ private val materialGradeColors = listOf(
+ 6 to R.color.grade_material_six,
+ 5 to R.color.grade_material_five,
+ 4 to R.color.grade_material_four,
+ 3 to R.color.grade_material_three,
+ 2 to R.color.grade_material_two,
+ 1 to R.color.grade_material_one
+ )
+
+ private val gradeLabels = listOf(
+ "6, 6-", "5, 5-, 5+", "4, 4-, 4+", "3, 3-, 3+", "2, 2-, 2+", "1, 1+"
+ )
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ return inflater.inflate(R.layout.fragment_grade_statistics, container, false)
+ }
+
+ override fun onActivityCreated(savedInstanceState: Bundle?) {
+ super.onActivityCreated(savedInstanceState)
+ messageContainer = gradeStatisticsChart
+ presenter.onAttachView(this, savedInstanceState?.getBoolean(SAVED_CHART_TYPE))
+ }
+
+ override fun initView() {
+ gradeStatisticsChart.run {
+ description.isEnabled = false
+ setHoleColor(context.getThemeAttrColor(android.R.attr.windowBackground))
+ setCenterTextColor(context.getThemeAttrColor(android.R.attr.textColorPrimary))
+ animateXY(1000, 1000)
+ minAngleForSlices = 25f
+ legend.apply {
+ textColor = context.getThemeAttrColor(android.R.attr.textColorPrimary)
+ }
+ }
+
+ context?.let {
+ subjectsAdapter = ArrayAdapter(it, android.R.layout.simple_spinner_item, ArrayList())
+ subjectsAdapter.setDropDownViewResource(R.layout.item_attendance_summary_subject)
+ }
+
+ gradeStatisticsSubjects.run {
+ adapter = subjectsAdapter
+ setOnItemSelectedListener { presenter.onSubjectSelected((it as TextView).text.toString()) }
+ }
+
+ gradeStatisticsSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
+ }
+
+ override fun updateSubjects(data: ArrayList) {
+ subjectsAdapter.run {
+ clear()
+ addAll(data)
+ notifyDataSetChanged()
+ }
+ }
+
+ override fun updateData(items: List, theme: String) {
+ gradeColors = when (theme) {
+ "vulcan" -> vulcanGradeColors
+ else -> materialGradeColors
+ }
+
+ gradeStatisticsChart.run {
+ data = PieData(PieDataSet(items.map {
+ PieEntry(it.amount.toFloat(), it.grade.toString())
+ }, "Legenda").apply {
+ valueTextSize = 12f
+ sliceSpace = 1f
+ valueTextColor = WHITE
+ setColors(items.map {
+ gradeColors.single { color -> color.first == it.grade }.second
+ }.toIntArray(), context)
+ }).apply {
+ setTouchEnabled(false)
+ setValueFormatter(object : ValueFormatter() {
+ override fun getPieLabel(value: Float, pieEntry: PieEntry): String {
+ return resources.getQuantityString(R.plurals.grade_number_item, value.toInt(), value.toInt())
+ }
+ })
+ centerText = items.fold(0) { acc, it -> acc + it.amount }
+ .let { resources.getQuantityString(R.plurals.grade_number_item, it, it) }
+ }
+ legend.apply {
+ setCustom(gradeLabels.mapIndexed { i, it ->
+ LegendEntry().apply {
+ label = it
+ formColor = ContextCompat.getColor(context, gradeColors[i].second)
+ form = Legend.LegendForm.SQUARE
+ }
+ })
+ }
+ invalidate()
+ }
+ }
+
+ override fun showSubjects(show: Boolean) {
+ gradeStatisticsSubjectsContainer.visibility = if (show) View.VISIBLE else View.INVISIBLE
+ gradeStatisticsTypeSwitch.visibility = if (show) View.VISIBLE else View.INVISIBLE
+ }
+
+ override fun clearView() {
+ gradeStatisticsChart.clear()
+ }
+
+ override fun showContent(show: Boolean) {
+ gradeStatisticsChart.visibility = if (show) View.VISIBLE else View.GONE
+ }
+
+ override fun showEmpty(show: Boolean) {
+ gradeStatisticsEmpty.visibility = if (show) View.VISIBLE else View.INVISIBLE
+ }
+
+ override fun showProgress(show: Boolean) {
+ gradeStatisticsProgress.visibility = if (show) View.VISIBLE else View.GONE
+ }
+
+ override fun enableSwipe(enable: Boolean) {
+ gradeStatisticsSwipe.isEnabled = enable
+ }
+
+ override fun showRefresh(show: Boolean) {
+ gradeStatisticsSwipe.isRefreshing = show
+ }
+
+ override fun onParentLoadData(semesterId: Int, forceRefresh: Boolean) {
+ presenter.onParentViewLoadData(semesterId, forceRefresh)
+ }
+
+ override fun onParentReselected() {
+ //
+ }
+
+ override fun onParentChangeSemester() {
+ presenter.onParentViewChangeSemester()
+ }
+
+ override fun notifyParentDataLoaded(semesterId: Int) {
+ (parentFragment as? GradeFragment)?.onChildFragmentLoaded(semesterId)
+ }
+
+ override fun notifyParentRefresh() {
+ (parentFragment as? GradeFragment)?.onChildRefresh()
+ }
+
+ override fun onResume() {
+ super.onResume()
+ gradeStatisticsTypeSwitch.setOnCheckedChangeListener { _, checkedId ->
+ presenter.onTypeChange(checkedId == R.id.gradeStatisticsTypeSemester)
+ }
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ outState.putBoolean(GradeStatisticsFragment.SAVED_CHART_TYPE, presenter.currentIsSemester)
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ presenter.onDetachView()
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsPresenter.kt
new file mode 100644
index 00000000..5111420d
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsPresenter.kt
@@ -0,0 +1,147 @@
+package io.github.wulkanowy.ui.modules.grade.statistics
+
+import io.github.wulkanowy.data.db.entities.Subject
+import io.github.wulkanowy.data.repositories.gradestatistics.GradeStatisticsRepository
+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.data.repositories.subject.SubjectRepository
+import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
+import io.github.wulkanowy.ui.base.session.SessionErrorHandler
+import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
+import io.github.wulkanowy.utils.SchedulersProvider
+import timber.log.Timber
+import javax.inject.Inject
+
+class GradeStatisticsPresenter @Inject constructor(
+ private val errorHandler: SessionErrorHandler,
+ private val gradeStatisticsRepository: GradeStatisticsRepository,
+ private val subjectRepository: SubjectRepository,
+ private val studentRepository: StudentRepository,
+ private val semesterRepository: SemesterRepository,
+ private val preferencesRepository: PreferencesRepository,
+ private val schedulers: SchedulersProvider,
+ private val analytics: FirebaseAnalyticsHelper
+) : BaseSessionPresenter(errorHandler) {
+
+ private var subjects = emptyList()
+
+ private var currentSemesterId = 0
+
+ private var currentSubjectName: String = "Wszystkie"
+
+ var currentIsSemester = false
+ private set
+
+ fun onAttachView(view: GradeStatisticsView, isSemester: Boolean?) {
+ super.onAttachView(view)
+ currentIsSemester = isSemester ?: false
+ view.initView()
+ }
+
+ fun onParentViewLoadData(semesterId: Int, forceRefresh: Boolean) {
+ currentSemesterId = semesterId
+ loadSubjects()
+ loadData(semesterId, currentSubjectName, currentIsSemester, forceRefresh)
+ }
+
+ fun onParentViewChangeSemester() {
+ view?.run {
+ showProgress(true)
+ enableSwipe(false)
+ showRefresh(false)
+ showContent(false)
+ showEmpty(false)
+ clearView()
+ }
+ disposable.clear()
+ }
+
+ fun onSwipeRefresh() {
+ Timber.i("Force refreshing the grade stats")
+ view?.notifyParentRefresh()
+ }
+
+ fun onSubjectSelected(name: String) {
+ Timber.i("Select attendance stats subject $name")
+ view?.run {
+ showContent(false)
+ showProgress(true)
+ enableSwipe(false)
+ showEmpty(false)
+ clearView()
+ }
+ (subjects.singleOrNull { it.name == name }?.name).let {
+ if (it != currentSubjectName) loadData(currentSemesterId, name, currentIsSemester)
+ }
+ }
+
+ fun onTypeChange(isSemester: Boolean) {
+ Timber.i("Select attendance stats semester: $isSemester")
+ disposable.clear()
+ view?.run {
+ showContent(false)
+ showProgress(true)
+ enableSwipe(false)
+ showEmpty(false)
+ clearView()
+ }
+ loadData(currentSemesterId, currentSubjectName, isSemester)
+ }
+
+ private fun loadSubjects() {
+ Timber.i("Loading grade stats subjects started")
+ disposable.add(studentRepository.getCurrentStudent()
+ .flatMap { semesterRepository.getCurrentSemester(it) }
+ .flatMap { subjectRepository.getSubjects(it) }
+ .doOnSuccess { subjects = it }
+ .map { ArrayList(it.map { subject -> subject.name }) }
+ .subscribeOn(schedulers.backgroundThread)
+ .observeOn(schedulers.mainThread)
+ .subscribe({
+ Timber.i("Loading grade stats subjects result: Success")
+ view?.run {
+ updateSubjects(it)
+ showSubjects(true)
+ }
+ }, {
+ Timber.e("Loading grade stats subjects result: An exception occurred")
+ errorHandler.dispatch(it)
+ })
+ )
+ }
+
+ private fun loadData(semesterId: Int, subjectName: String, isSemester: Boolean, forceRefresh: Boolean = false) {
+ Timber.i("Loading grade stats data started")
+ currentSubjectName = subjectName
+ currentIsSemester = isSemester
+ disposable.add(studentRepository.getCurrentStudent()
+ .flatMap { semesterRepository.getSemesters(it) }
+ .flatMap { gradeStatisticsRepository.getGradesStatistics(it.first { item -> item.semesterId == semesterId }, subjectName, isSemester, forceRefresh) }
+ .map { list -> list.sortedByDescending { it.grade } }
+ .map { list -> list.filter { it.amount != 0 } }
+ .subscribeOn(schedulers.backgroundThread)
+ .observeOn(schedulers.mainThread)
+ .doFinally {
+ view?.run {
+ showRefresh(false)
+ showProgress(false)
+ enableSwipe(true)
+ notifyParentDataLoaded(semesterId)
+ }
+ }
+ .subscribe({
+ Timber.i("Loading grade stats result: Success")
+ view?.run {
+ showEmpty(it.isEmpty())
+ showContent(it.isNotEmpty())
+ updateData(it, preferencesRepository.gradeColorTheme)
+ }
+ analytics.logEvent("load_grade_statistics", "items" to it.size, "force_refresh" to forceRefresh)
+ }) {
+ Timber.e("Loading grade stats result: An exception occurred")
+ view?.run { showEmpty(isViewEmpty) }
+ errorHandler.dispatch(it)
+ })
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsView.kt
new file mode 100644
index 00000000..dbdde459
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsView.kt
@@ -0,0 +1,33 @@
+package io.github.wulkanowy.ui.modules.grade.statistics
+
+import io.github.wulkanowy.data.db.entities.GradeStatistics
+import io.github.wulkanowy.ui.base.session.BaseSessionView
+
+interface GradeStatisticsView : BaseSessionView {
+
+ val isViewEmpty: Boolean
+
+ fun initView()
+
+ fun updateSubjects(data: ArrayList)
+
+ fun updateData(items: List, theme: String)
+
+ fun showSubjects(show: Boolean)
+
+ fun notifyParentDataLoaded(semesterId: Int)
+
+ fun notifyParentRefresh()
+
+ fun clearView()
+
+ fun showContent(show: Boolean)
+
+ fun showEmpty(show: Boolean)
+
+ fun showProgress(show: Boolean)
+
+ fun enableSwipe(enable: Boolean)
+
+ fun showRefresh(show: Boolean)
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt
index 13833b74..f174f96c 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt
@@ -71,7 +71,7 @@ class GradeSummaryFragment : BaseSessionFragment(), GradeSummaryView, GradeView.
}
override fun resetView() {
- gradeSummaryAdapter.smoothScrollToPosition(0)
+ gradeSummaryRecycler.scrollToPosition(0)
}
override fun showContent(show: Boolean) {
@@ -86,6 +86,10 @@ class GradeSummaryFragment : BaseSessionFragment(), GradeSummaryView, GradeView.
gradeSummaryProgress.visibility = if (show) VISIBLE else GONE
}
+ override fun enableSwipe(enable: Boolean) {
+ gradeSummarySwipe.isEnabled = enable
+ }
+
override fun showRefresh(show: Boolean) {
gradeSummarySwipe.isRefreshing = show
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryHeader.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryHeader.kt
deleted file mode 100644
index fba3fde6..00000000
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryHeader.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-package io.github.wulkanowy.ui.modules.grade.summary
-
-import android.view.View
-import eu.davidea.flexibleadapter.FlexibleAdapter
-import eu.davidea.flexibleadapter.items.AbstractHeaderItem
-import eu.davidea.flexibleadapter.items.IFlexible
-import eu.davidea.viewholders.FlexibleViewHolder
-import io.github.wulkanowy.R
-import kotlinx.android.extensions.LayoutContainer
-import kotlinx.android.synthetic.main.header_grade_summary.*
-
-class GradeSummaryHeader(private val name: String, private val average: String) : AbstractHeaderItem() {
-
- override fun getLayoutRes() = R.layout.header_grade_summary
-
- override fun createViewHolder(view: View?, adapter: FlexibleAdapter>?): ViewHolder {
- return ViewHolder(view, adapter)
- }
-
- override fun bindViewHolder(adapter: FlexibleAdapter>?, holder: ViewHolder?,
- position: Int, payloads: MutableList?) {
- holder?.run {
- gradeSummaryHeaderName.text = name
- gradeSummaryHeaderAverage.text = average
- }
- }
-
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- if (javaClass != other?.javaClass) return false
-
- other as GradeSummaryHeader
-
- if (name != other.name) return false
- if (average != other.average) return false
-
- return true
- }
-
- override fun hashCode(): Int {
- var result = name.hashCode()
- result = 31 * result + average.hashCode()
- return result
- }
-
- class ViewHolder(view: View?, adapter: FlexibleAdapter>?) :
- FlexibleViewHolder(view, adapter), LayoutContainer {
-
- override val containerView: View?
- get() = contentView
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryItem.kt
index 54302fa6..0daf0665 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryItem.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryItem.kt
@@ -2,16 +2,19 @@ package io.github.wulkanowy.ui.modules.grade.summary
import android.view.View
import eu.davidea.flexibleadapter.FlexibleAdapter
-import eu.davidea.flexibleadapter.items.AbstractSectionableItem
+import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import eu.davidea.flexibleadapter.items.IFlexible
import eu.davidea.viewholders.FlexibleViewHolder
import io.github.wulkanowy.R
-import io.github.wulkanowy.data.db.entities.GradeSummary
import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.item_grade_summary.*
-class GradeSummaryItem(header: GradeSummaryHeader, private val grade: String, private val title: String) :
- AbstractSectionableItem(header) {
+class GradeSummaryItem(
+ private val title: String,
+ private val average: String,
+ private val predictedGrade: String,
+ private val finalGrade: String
+) : AbstractFlexibleItem() {
override fun getLayoutRes() = R.layout.item_grade_summary
@@ -24,8 +27,10 @@ class GradeSummaryItem(header: GradeSummaryHeader, private val grade: String, pr
position: Int, payloads: MutableList?
) {
holder?.run {
- gradeSummaryItemGrade.text = grade
gradeSummaryItemTitle.text = title
+ gradeSummaryItemAverage.text = average
+ gradeSummaryItemPredicted.text = predictedGrade
+ gradeSummaryItemFinal.text = finalGrade
}
}
@@ -35,17 +40,19 @@ class GradeSummaryItem(header: GradeSummaryHeader, private val grade: String, pr
other as GradeSummaryItem
- if (grade != other.grade) return false
+ if (average != other.average) return false
if (title != other.title) return false
- if (header != other.header) return false
+ if (predictedGrade != other.predictedGrade) return false
+ if (finalGrade != other.finalGrade) return false
return true
}
override fun hashCode(): Int {
- var result = header.hashCode()
- result = 31 * result + grade.hashCode()
- result = 31 * result + title.hashCode()
+ var result = title.hashCode()
+ result = 31 * result + average.hashCode()
+ result = 31 * result + predictedGrade.hashCode()
+ result = 31 * result + finalGrade.hashCode()
return result
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt
index a67ad894..5dbf7513 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt
@@ -1,17 +1,18 @@
package io.github.wulkanowy.ui.modules.grade.summary
import io.github.wulkanowy.data.db.entities.GradeSummary
-import io.github.wulkanowy.data.repositories.GradeRepository
-import io.github.wulkanowy.data.repositories.GradeSummaryRepository
-import io.github.wulkanowy.data.repositories.PreferencesRepository
-import io.github.wulkanowy.data.repositories.SemesterRepository
-import io.github.wulkanowy.data.repositories.StudentRepository
+import io.github.wulkanowy.data.repositories.grade.GradeRepository
+import io.github.wulkanowy.data.repositories.gradessummary.GradeSummaryRepository
+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.ui.base.session.BaseSessionPresenter
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.github.wulkanowy.utils.SchedulersProvider
import io.github.wulkanowy.utils.calcAverage
import io.github.wulkanowy.utils.changeModifier
+import timber.log.Timber
import java.lang.String.format
import java.util.Locale.FRANCE
import javax.inject.Inject
@@ -33,13 +34,14 @@ class GradeSummaryPresenter @Inject constructor(
}
fun onParentViewLoadData(semesterId: Int, forceRefresh: Boolean) {
+ Timber.i("Loading grade summary data started")
disposable.add(studentRepository.getCurrentStudent()
- .flatMap { semesterRepository.getSemesters(it) }
- .map { semester -> semester.first { it.semesterId == semesterId } }
+ .flatMap { semesterRepository.getSemesters(it).map { semester -> semester to it } }
+ .map { pair -> pair.first.first { it.semesterId == semesterId } to pair.second }
.flatMap {
- gradeSummaryRepository.getGradesSummary(it, forceRefresh)
+ gradeSummaryRepository.getGradesSummary(it.first, forceRefresh)
.flatMap { gradesSummary ->
- gradeRepository.getGrades(it, forceRefresh)
+ gradeRepository.getGrades(it.second, it.first, forceRefresh)
.map { grades ->
grades.map { item -> item.changeModifier(preferencesRepository.gradePlusModifier, preferencesRepository.gradeMinusModifier) }
.groupBy { grade -> grade.subject }
@@ -61,22 +63,26 @@ class GradeSummaryPresenter @Inject constructor(
view?.run {
showRefresh(false)
showProgress(false)
+ enableSwipe(true)
notifyParentDataLoaded(semesterId)
}
}.subscribe({
+ Timber.i("Loading grade summary result: Success")
view?.run {
showEmpty(it.first.isEmpty())
showContent(it.first.isNotEmpty())
updateData(it.first, it.second)
}
- analytics.logEvent("load_grade_summary", mapOf("items" to it.first.size, "force_refresh" to forceRefresh))
+ analytics.logEvent("load_grade_summary", "items" to it.first.size, "force_refresh" to forceRefresh)
}) {
+ Timber.i("Loading grade summary result: An exception occurred")
view?.run { showEmpty(isViewEmpty) }
errorHandler.dispatch(it)
})
}
fun onSwipeRefresh() {
+ Timber.i("Force refreshing the grade summary")
view?.notifyParentRefresh()
}
@@ -89,6 +95,7 @@ class GradeSummaryPresenter @Inject constructor(
fun onParentViewChangeSemester() {
view?.run {
showProgress(true)
+ enableSwipe(false)
showRefresh(false)
showContent(false)
showEmpty(false)
@@ -99,23 +106,14 @@ class GradeSummaryPresenter @Inject constructor(
private fun createGradeSummaryItems(gradesSummary: List, averages: Map)
: List {
- return gradesSummary.filter { !checkEmpty(it, averages) }
- .flatMap { gradeSummary ->
- GradeSummaryHeader(
- name = gradeSummary.subject,
- average = formatAverage(averages.getOrElse(gradeSummary.subject) { 0.0 }, "")
- ).let {
- listOf(GradeSummaryItem(
- header = it,
- title = view?.predictedString.orEmpty(),
- grade = gradeSummary.predictedGrade
- ), GradeSummaryItem(
- header = it,
- title = view?.finalString.orEmpty(),
- grade = gradeSummary.finalGrade
- ))
- }
- }
+ return gradesSummary.filter { !checkEmpty(it, averages) }.map { it ->
+ GradeSummaryItem(
+ title = it.subject,
+ average = formatAverage(averages.getOrElse(it.subject) { 0.0 }, ""),
+ predictedGrade = it.predictedGrade,
+ finalGrade = it.finalGrade
+ )
+ }
}
private fun checkEmpty(gradeSummary: GradeSummary, averages: Map): Boolean {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryView.kt
index 2602ec99..5f7c7b16 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryView.kt
@@ -20,6 +20,8 @@ interface GradeSummaryView : BaseSessionView {
fun showProgress(show: Boolean)
+ fun enableSwipe(enable: Boolean)
+
fun showRefresh(show: Boolean)
fun showContent(show: Boolean)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt
index 135098fb..7325e3ec 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt
@@ -5,11 +5,13 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import eu.davidea.flexibleadapter.FlexibleAdapter
+import eu.davidea.flexibleadapter.common.FlexibleItemDecoration
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Homework
import io.github.wulkanowy.ui.base.session.BaseSessionFragment
+import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.utils.setOnItemClickListener
import kotlinx.android.synthetic.main.fragment_homework.*
@@ -50,6 +52,10 @@ class HomeworkFragment : BaseSessionFragment(), HomeworkView, MainView.TitledVie
homeworkRecycler.run {
layoutManager = SmoothScrollLinearLayoutManager(context)
adapter = homeworkAdapter
+ addItemDecoration(FlexibleItemDecoration(context)
+ .withDefaultDivider()
+ .withDrawDividerOnLastItem(false)
+ )
}
homeworkSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
homeworkPreviousButton.setOnClickListener { presenter.onPreviousDay() }
@@ -64,7 +70,7 @@ class HomeworkFragment : BaseSessionFragment(), HomeworkView, MainView.TitledVie
homeworkAdapter.clear()
}
- override fun updateNavigationDay(date: String) {
+ override fun updateNavigationWeek(date: String) {
homeworkNavDate.text = date
}
@@ -82,6 +88,10 @@ class HomeworkFragment : BaseSessionFragment(), HomeworkView, MainView.TitledVie
homeworkProgress.visibility = if (show) View.VISIBLE else View.GONE
}
+ override fun enableSwipe(enable: Boolean) {
+ homeworkSwipe.isEnabled = enable
+ }
+
override fun showContent(show: Boolean) {
homeworkRecycler.visibility = if (show) View.VISIBLE else View.GONE
}
@@ -95,7 +105,7 @@ class HomeworkFragment : BaseSessionFragment(), HomeworkView, MainView.TitledVie
}
override fun showTimetableDialog(homework: Homework) {
- HomeworkDialog.newInstance(homework).show(fragmentManager, homework.toString())
+ (activity as? MainActivity)?.showDialogFragment(HomeworkDialog.newInstance(homework))
}
override fun onSaveInstanceState(outState: Bundle) {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkHeader.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkHeader.kt
new file mode 100644
index 00000000..49023788
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkHeader.kt
@@ -0,0 +1,54 @@
+package io.github.wulkanowy.ui.modules.homework
+
+import android.view.View
+import eu.davidea.flexibleadapter.FlexibleAdapter
+import eu.davidea.flexibleadapter.items.AbstractHeaderItem
+import eu.davidea.flexibleadapter.items.IFlexible
+import eu.davidea.viewholders.ExpandableViewHolder
+import io.github.wulkanowy.R
+import io.github.wulkanowy.utils.toFormattedString
+import io.github.wulkanowy.utils.weekDayName
+import kotlinx.android.extensions.LayoutContainer
+import kotlinx.android.synthetic.main.header_homework.*
+import org.threeten.bp.LocalDate
+
+class HomeworkHeader(private val date: LocalDate) : AbstractHeaderItem() {
+
+ override fun getLayoutRes() = R.layout.header_homework
+
+ override fun createViewHolder(view: View?, adapter: FlexibleAdapter>?): ViewHolder {
+ return ViewHolder(view, adapter)
+ }
+
+ override fun bindViewHolder(
+ adapter: FlexibleAdapter>?, holder: HomeworkHeader.ViewHolder,
+ position: Int, payloads: MutableList?
+ ) {
+ holder.run {
+ homeworkHeaderDay.text = date.weekDayName.capitalize()
+ homeworkHeaderDate.text = date.toFormattedString()
+ }
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as HomeworkHeader
+
+ if (date != other.date) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ return date.hashCode()
+ }
+
+ class ViewHolder(view: View?, adapter: FlexibleAdapter>?) : ExpandableViewHolder(view, adapter),
+ LayoutContainer {
+
+ override val containerView: View
+ get() = contentView
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkItem.kt
index 97ff188c..a2b8cc0a 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkItem.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkItem.kt
@@ -1,9 +1,8 @@
package io.github.wulkanowy.ui.modules.homework
-import android.annotation.SuppressLint
import android.view.View
import eu.davidea.flexibleadapter.FlexibleAdapter
-import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
+import eu.davidea.flexibleadapter.items.AbstractSectionableItem
import eu.davidea.flexibleadapter.items.IFlexible
import eu.davidea.viewholders.FlexibleViewHolder
import io.github.wulkanowy.R
@@ -11,15 +10,16 @@ import io.github.wulkanowy.data.db.entities.Homework
import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.item_homework.*
-class HomeworkItem(val homework: Homework) : AbstractFlexibleItem() {
+class HomeworkItem(
+ header: HomeworkHeader, val homework: Homework
+) : AbstractSectionableItem(header) {
- override fun getLayoutRes(): Int = R.layout.item_homework
+ override fun getLayoutRes() = R.layout.item_homework
override fun createViewHolder(view: View, adapter: FlexibleAdapter>): ViewHolder {
return ViewHolder(view, adapter)
}
- @SuppressLint("SetTextI18n")
override fun bindViewHolder(
adapter: FlexibleAdapter>, holder: ViewHolder,
position: Int, payloads: MutableList?
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt
index e4d42745..739d4494 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt
@@ -2,19 +2,21 @@ package io.github.wulkanowy.ui.modules.homework
import com.google.firebase.analytics.FirebaseAnalytics.Param.START_DATE
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
-import io.github.wulkanowy.data.repositories.HomeworkRepository
-import io.github.wulkanowy.data.repositories.SemesterRepository
-import io.github.wulkanowy.data.repositories.StudentRepository
+import io.github.wulkanowy.data.db.entities.Homework
+import io.github.wulkanowy.data.repositories.homework.HomeworkRepository
+import io.github.wulkanowy.data.repositories.semester.SemesterRepository
+import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.github.wulkanowy.utils.SchedulersProvider
+import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.utils.isHolidays
+import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.nextOrSameSchoolDay
-import io.github.wulkanowy.utils.nextSchoolDay
-import io.github.wulkanowy.utils.previousSchoolDay
import io.github.wulkanowy.utils.toFormattedString
import org.threeten.bp.LocalDate
+import timber.log.Timber
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@@ -32,69 +34,90 @@ class HomeworkPresenter @Inject constructor(
fun onAttachView(view: HomeworkView, date: Long?) {
super.onAttachView(view)
+ Timber.i("Homework view is attached")
view.initView()
loadData(LocalDate.ofEpochDay(date ?: LocalDate.now().nextOrSameSchoolDay.toEpochDay()))
reloadView()
}
fun onPreviousDay() {
- loadData(currentDate.previousSchoolDay)
+ loadData(currentDate.minusDays(7))
reloadView()
}
fun onNextDay() {
- loadData(currentDate.nextSchoolDay)
+ loadData(currentDate.plusDays(7))
reloadView()
}
fun onSwipeRefresh() {
+ Timber.i("Force refreshing the homework")
loadData(currentDate, true)
}
fun onHomeworkItemSelected(item: AbstractFlexibleItem<*>?) {
- if (item is HomeworkItem) view?.showTimetableDialog(item.homework)
+ if (item is HomeworkItem) {
+ Timber.i("Select homework item ${item.homework.id}")
+ view?.showTimetableDialog(item.homework)
+ }
}
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) {
+ Timber.i("Loading homework data started")
currentDate = date
disposable.apply {
clear()
add(studentRepository.getCurrentStudent()
.delay(200, TimeUnit.MILLISECONDS)
.flatMap { semesterRepository.getCurrentSemester(it) }
- .flatMap { homeworkRepository.getHomework(it, currentDate, forceRefresh) }
- .map { items -> items.map { HomeworkItem(it) } }
+ .flatMap { homeworkRepository.getHomework(it, currentDate, currentDate, forceRefresh) }
+ .map { it.groupBy { homework -> homework.date }.toSortedMap() }
+ .map { createHomeworkItem(it) }
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
.doFinally {
view?.run {
hideRefresh()
showProgress(false)
+ enableSwipe(true)
}
}
.subscribe({
+ Timber.i("Loading homework result: Success")
view?.apply {
updateData(it)
showEmpty(it.isEmpty())
showContent(it.isNotEmpty())
}
- analytics.logEvent("load_homework", mapOf("items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd")))
+ analytics.logEvent("load_homework", "items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd"))
}) {
+ Timber.i("Loading homework result: An exception occurred")
view?.run { showEmpty(isViewEmpty()) }
errorHandler.dispatch(it)
})
}
}
+ private fun createHomeworkItem(items: Map>): List {
+ return items.flatMap {
+ HomeworkHeader(it.key).let { header ->
+ it.value.reversed().map { item -> HomeworkItem(header, item) }
+ }
+ }
+ }
+
private fun reloadView() {
+ Timber.i("Reload homework view with the date ${currentDate.toFormattedString()}")
view?.apply {
showProgress(true)
+ enableSwipe(false)
showContent(false)
showEmpty(false)
clearData()
- showNextButton(!currentDate.plusDays(1).isHolidays)
- showPreButton(!currentDate.minusDays(1).isHolidays)
- updateNavigationDay(currentDate.toFormattedString("EEEE \n dd.MM.YYYY").capitalize())
+ showNextButton(!currentDate.plusDays(7).isHolidays)
+ showPreButton(!currentDate.minusDays(7).isHolidays)
+ updateNavigationWeek("${currentDate.monday.toFormattedString("dd.MM")} - " +
+ currentDate.friday.toFormattedString("dd.MM"))
}
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkView.kt
index 521020e6..546d0526 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkView.kt
@@ -11,7 +11,7 @@ interface HomeworkView : BaseSessionView {
fun clearData()
- fun updateNavigationDay(date: String)
+ fun updateNavigationWeek(date: String)
fun isViewEmpty(): Boolean
@@ -21,6 +21,8 @@ interface HomeworkView : BaseSessionView {
fun showProgress(show: Boolean)
+ fun enableSwipe(enable: Boolean)
+
fun showContent(show: Boolean)
fun showPreButton(show: Boolean)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt
index c9c1aeb4..da054bb5 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt
@@ -4,10 +4,12 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import io.github.wulkanowy.R
+import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.ui.base.BaseActivity
-import io.github.wulkanowy.ui.base.BasePagerAdapter
+import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter
import io.github.wulkanowy.ui.modules.login.form.LoginFormFragment
-import io.github.wulkanowy.ui.modules.login.options.LoginOptionsFragment
+import io.github.wulkanowy.ui.modules.login.studentselect.LoginStudentSelectFragment
+import io.github.wulkanowy.ui.modules.login.symbol.LoginSymbolFragment
import io.github.wulkanowy.utils.setOnSelectPageListener
import kotlinx.android.synthetic.main.activity_login.*
import javax.inject.Inject
@@ -18,7 +20,7 @@ class LoginActivity : BaseActivity(), LoginView {
lateinit var presenter: LoginPresenter
@Inject
- lateinit var loginAdapter: BasePagerAdapter
+ lateinit var loginAdapter: BaseFragmentPagerAdapter
companion object {
fun getStartIntent(context: Context) = Intent(context, LoginActivity::class.java)
@@ -36,14 +38,19 @@ class LoginActivity : BaseActivity(), LoginView {
}
override fun initAdapter() {
- loginAdapter.fragments.putAll(mapOf(
- "1" to LoginFormFragment.newInstance(),
- "2" to LoginOptionsFragment.newInstance()
- ))
+ loginAdapter.apply {
+ containerId = loginViewpager.id
+ addFragments(listOf(
+ LoginFormFragment.newInstance(),
+ LoginSymbolFragment.newInstance(),
+ LoginStudentSelectFragment.newInstance()
+ ))
+ }
loginViewpager.run {
+ offscreenPageLimit = 2
adapter = loginAdapter
- setOnSelectPageListener { presenter.onPageSelected(it) }
+ setOnSelectPageListener { presenter.onViewSelected(it) }
}
}
@@ -51,22 +58,30 @@ class LoginActivity : BaseActivity(), LoginView {
loginViewpager.setCurrentItem(index, false)
}
- override fun notifyOptionsViewLoadData() {
- (supportFragmentManager.fragments[1] as? LoginOptionsFragment)?.onParentLoadData()
- }
-
- fun onChildFragmentSwitchOptions() {
- presenter.onChildViewSwitchOptions()
- }
-
- override fun hideActionBar() {
- supportActionBar?.hide()
+ override fun showActionBar(show: Boolean) {
+ supportActionBar?.apply { if (show) show() else hide() }
}
override fun onBackPressed() {
presenter.onBackPressed { super.onBackPressed() }
}
+ override fun notifyInitSymbolFragment(loginData: Triple) {
+ (loginAdapter.getFragmentInstance(1) as? LoginSymbolFragment)?.onParentInitSymbolFragment(loginData)
+ }
+
+ override fun notifyInitStudentSelectFragment(students: List) {
+ (loginAdapter.getFragmentInstance(2) as? LoginStudentSelectFragment)?.onParentInitStudentSelectFragment(students)
+ }
+
+ fun onFormFragmentAccountLogged(students: List, loginData: Triple) {
+ presenter.onFormViewAccountLogged(students, loginData)
+ }
+
+ fun onSymbolFragmentAccountLogged(students: List) {
+ presenter.onSymbolViewAccountLogged(students)
+ }
+
public override fun onDestroy() {
presenter.onDetachView()
super.onDestroy()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginErrorHandler.kt
index 40f1d711..a70ff2d6 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginErrorHandler.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginErrorHandler.kt
@@ -2,12 +2,16 @@ package io.github.wulkanowy.ui.modules.login
import android.content.res.Resources
import android.database.sqlite.SQLiteConstraintException
+import com.readystatesoftware.chuck.api.ChuckCollector
import io.github.wulkanowy.R
import io.github.wulkanowy.api.login.BadCredentialsException
import io.github.wulkanowy.ui.base.ErrorHandler
import javax.inject.Inject
-class LoginErrorHandler @Inject constructor(resources: Resources) : ErrorHandler(resources) {
+class LoginErrorHandler @Inject constructor(
+ resources: Resources,
+ chuckCollector: ChuckCollector
+) : ErrorHandler(resources, chuckCollector) {
var onBadCredentials: () -> Unit = {}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginModule.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginModule.kt
index 3cdf8367..7c3e7bac 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginModule.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginModule.kt
@@ -5,9 +5,10 @@ import dagger.Provides
import dagger.android.ContributesAndroidInjector
import io.github.wulkanowy.di.scopes.PerActivity
import io.github.wulkanowy.di.scopes.PerFragment
-import io.github.wulkanowy.ui.base.BasePagerAdapter
+import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter
import io.github.wulkanowy.ui.modules.login.form.LoginFormFragment
-import io.github.wulkanowy.ui.modules.login.options.LoginOptionsFragment
+import io.github.wulkanowy.ui.modules.login.studentselect.LoginStudentSelectFragment
+import io.github.wulkanowy.ui.modules.login.symbol.LoginSymbolFragment
@Module
internal abstract class LoginModule {
@@ -18,14 +19,18 @@ internal abstract class LoginModule {
@JvmStatic
@PerActivity
@Provides
- fun provideLoginAdapter(activity: LoginActivity) = BasePagerAdapter(activity.supportFragmentManager)
+ fun provideLoginAdapter(activity: LoginActivity) = BaseFragmentPagerAdapter(activity.supportFragmentManager)
}
@PerFragment
- @ContributesAndroidInjector()
+ @ContributesAndroidInjector
abstract fun bindLoginFormFragment(): LoginFormFragment
@PerFragment
- @ContributesAndroidInjector()
- abstract fun bindLoginOptionsFragment(): LoginOptionsFragment
+ @ContributesAndroidInjector
+ abstract fun bindLoginSymbolFragment(): LoginSymbolFragment
+
+ @PerFragment
+ @ContributesAndroidInjector
+ abstract fun bindLoginSelectStudentFragment(): LoginStudentSelectFragment
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginPresenter.kt
index 0687e2f2..fb025bee 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginPresenter.kt
@@ -1,7 +1,9 @@
package io.github.wulkanowy.ui.modules.login
+import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
+import timber.log.Timber
import javax.inject.Inject
class LoginPresenter @Inject constructor(errorHandler: ErrorHandler) : BasePresenter(errorHandler) {
@@ -10,24 +12,49 @@ class LoginPresenter @Inject constructor(errorHandler: ErrorHandler) : BasePrese
super.onAttachView(view)
view.run {
initAdapter()
- hideActionBar()
+ showActionBar(false)
+ }
+ Timber.i("Login view is attached")
+ }
+
+ fun onFormViewAccountLogged(students: List, loginData: Triple) {
+ view?.apply {
+ if (students.isEmpty()) {
+ Timber.i("Switch to symbol form")
+ notifyInitSymbolFragment(loginData)
+ switchView(1)
+ } else {
+ Timber.i("Switch to student select")
+ notifyInitStudentSelectFragment(students)
+ switchView(2)
+ }
}
}
- fun onPageSelected(index: Int) {
- if (index == 1) view?.notifyOptionsViewLoadData()
+ fun onSymbolViewAccountLogged(students: List) {
+ view?.apply {
+ Timber.i("Switch to student select")
+ notifyInitStudentSelectFragment(students)
+ switchView(2)
+ }
}
- fun onChildViewSwitchOptions() {
- view?.switchView(1)
+ fun onViewSelected(index: Int) {
+ view?.apply {
+ when (index) {
+ 0, 1 -> showActionBar(false)
+ 2 -> showActionBar(true)
+ }
+ }
}
fun onBackPressed(default: () -> Unit) {
- view?.run {
- if (currentViewIndex == 1) {
- switchView(0)
- hideActionBar()
- } else default()
+ Timber.i("Back pressed in login view")
+ view?.apply {
+ when (currentViewIndex) {
+ 1, 2 -> switchView(0)
+ else -> default()
+ }
}
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginView.kt
index 52cb9180..58d356bb 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginView.kt
@@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.login
+import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.ui.base.BaseView
interface LoginView : BaseView {
@@ -8,9 +9,11 @@ interface LoginView : BaseView {
fun initAdapter()
- fun hideActionBar()
-
fun switchView(index: Int)
- fun notifyOptionsViewLoadData()
+ fun showActionBar(show: Boolean)
+
+ fun notifyInitSymbolFragment(loginData: Triple)
+
+ fun notifyInitStudentSelectFragment(students: List)
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt
index 7985ef6e..54fd0704 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt
@@ -10,12 +10,14 @@ import android.view.ViewGroup
import android.view.inputmethod.EditorInfo.IME_ACTION_DONE
import android.view.inputmethod.EditorInfo.IME_NULL
import android.widget.ArrayAdapter
-import io.github.wulkanowy.BuildConfig.DEBUG
import io.github.wulkanowy.BuildConfig.VERSION_NAME
import io.github.wulkanowy.R
+import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.utils.hideSoftInput
+import io.github.wulkanowy.utils.setOnItemSelectedListener
+import io.github.wulkanowy.utils.setOnTextChangedListener
import io.github.wulkanowy.utils.showSoftInput
import kotlinx.android.synthetic.main.fragment_login_form.*
import javax.inject.Inject
@@ -29,7 +31,14 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
fun newInstance() = LoginFormFragment()
}
- override val isDebug = DEBUG
+ override val formNameValue: String
+ get() = loginFormName.text.toString()
+
+ override val formPassValue: String
+ get() = loginFormPass.text.toString()
+
+ override val formHostValue: String?
+ get() = resources.getStringArray(R.array.endpoints_values)[loginFormHost.selectedItemPosition]
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_login_form, container, false)
@@ -41,93 +50,60 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
}
override fun initView() {
- loginSignButton.setOnClickListener {
- presenter.attemptLogin(
- loginNicknameEdit.text.toString(),
- loginPassEdit.text.toString(),
- loginSymbolEdit.text.toString(),
- resources.getStringArray(R.array.endpoints_values)[loginHostEdit.selectedItemPosition]
- )
+ loginFormName.setOnTextChangedListener { presenter.onNameTextChanged() }
+ loginFormPass.setOnTextChangedListener { presenter.onPassTextChanged() }
+ loginFormHost.setOnItemSelectedListener { presenter.onHostSelected() }
+ loginFormSignIn.setOnClickListener { presenter.attemptLogin() }
+
+ loginFormPass.setOnEditorActionListener { _, id, _ ->
+ if (id == IME_ACTION_DONE || id == IME_NULL) loginFormSignIn.callOnClick() else false
}
- loginPassEdit.setOnEditorActionListener { _, id, _ -> onEditAction(id) }
-
- loginHostEdit.apply {
- adapter = ArrayAdapter.createFromResource(context, R.array.endpoints_keys, android.R.layout.simple_spinner_item)
+ context?.let {
+ loginFormHost.adapter = ArrayAdapter.createFromResource(it, R.array.endpoints_keys, android.R.layout.simple_spinner_item)
.apply { setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) }
}
-
- loginSymbolEdit.run {
- setAdapter(ArrayAdapter(context, android.R.layout.simple_list_item_1, resources.getStringArray(R.array.symbols_values)))
- setOnEditorActionListener { _, id, _ -> onEditAction(id) }
- }
}
- override fun showSymbolInput() {
- loginHeader.text = getString(R.string.login_header_symbol)
- loginMainForm.visibility = GONE
- loginSymbolInput.visibility = VISIBLE
- loginSymbolEdit.requestFocus()
- showSoftKeyboard()
+ override fun setDefaultCredentials(name: String, pass: String) {
+ loginFormName.setText(name)
+ loginFormPass.setText(pass)
}
- @SuppressLint("SetTextI18n")
- override fun showVersion() {
- loginVersion.apply {
- visibility = VISIBLE
- text = "${getString(R.string.app_name)} $VERSION_NAME"
- }
- }
-
- override fun switchOptionsView() {
- (activity as? LoginActivity)?.onChildFragmentSwitchOptions()
- }
-
- override fun setErrorNicknameRequired() {
- loginNicknameEdit.run {
+ override fun setErrorNameRequired() {
+ loginFormNameLayout.run {
requestFocus()
error = getString(R.string.login_field_required)
}
}
override fun setErrorPassRequired(focus: Boolean) {
- loginPassEdit.run {
+ loginFormPassLayout.run {
if (focus) requestFocus()
error = getString(R.string.login_field_required)
}
}
override fun setErrorPassInvalid(focus: Boolean) {
- loginPassEdit.run {
+ loginFormPassLayout.run {
if (focus) requestFocus()
error = getString(R.string.login_invalid_password)
}
}
- override fun setErrorSymbolRequire() {
- loginSymbolEdit.run {
- requestFocus()
- error = getString(R.string.login_field_required)
- }
- }
-
override fun setErrorPassIncorrect() {
- loginPassEdit.run {
+ loginFormPassLayout.run {
requestFocus()
error = getString(R.string.login_incorrect_password)
}
}
- override fun setErrorSymbolIncorrect() {
- loginSymbolEdit.run {
- requestFocus()
- error = getString(R.string.login_incorrect_symbol)
- }
+ override fun clearNameError() {
+ loginFormNameLayout.error = null
}
- override fun resetViewErrors() {
- loginNicknameEdit.error = null
- loginPassEdit.error = null
+ override fun clearPassError() {
+ loginFormPassLayout.error = null
}
override fun showSoftKeyboard() {
@@ -139,20 +115,29 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
}
override fun showProgress(show: Boolean) {
- loginFormProgressContainer.visibility = if (show) VISIBLE else GONE
+ loginFormProgress.visibility = if (show) VISIBLE else GONE
}
override fun showContent(show: Boolean) {
loginFormContainer.visibility = if (show) VISIBLE else GONE
}
- private fun onEditAction(actionId: Int): Boolean {
- return when (actionId) {
- IME_ACTION_DONE, IME_NULL -> loginSignButton.callOnClick()
- else -> false
+ @SuppressLint("SetTextI18n")
+ override fun showVersion() {
+ loginFormVersion.apply {
+ visibility = VISIBLE
+ text = "${getString(R.string.app_name)} $VERSION_NAME"
}
}
+ override fun notifyParentAccountLogged(students: List) {
+ (activity as? LoginActivity)?.onFormFragmentAccountLogged(students, Triple(
+ loginFormName.text.toString(),
+ loginFormPass.text.toString(),
+ resources.getStringArray(R.array.endpoints_values)[loginFormHost.selectedItemPosition]
+ ))
+ }
+
override fun onDestroyView() {
super.onDestroyView()
presenter.onDetachView()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt
index 58ce34a7..a0717649 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt
@@ -1,25 +1,23 @@
package io.github.wulkanowy.ui.modules.login.form
-import com.google.firebase.analytics.FirebaseAnalytics.Event.SIGN_UP
-import com.google.firebase.analytics.FirebaseAnalytics.Param.GROUP_ID
import com.google.firebase.analytics.FirebaseAnalytics.Param.SUCCESS
-import io.github.wulkanowy.data.repositories.StudentRepository
+import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.github.wulkanowy.utils.SchedulersProvider
import timber.log.Timber
import javax.inject.Inject
+import javax.inject.Named
class LoginFormPresenter @Inject constructor(
private val schedulers: SchedulersProvider,
private val errorHandler: LoginErrorHandler,
private val studentRepository: StudentRepository,
- private val analytics: FirebaseAnalyticsHelper
+ private val analytics: FirebaseAnalyticsHelper,
+ @param:Named("isDebug") private val isDebug: Boolean
) : BasePresenter(errorHandler) {
- private var wasEmpty = false
-
override fun onAttachView(view: LoginFormView) {
super.onAttachView(view)
view.run {
@@ -33,10 +31,30 @@ class LoginFormPresenter @Inject constructor(
}
}
- fun attemptLogin(email: String, password: String, symbol: String, endpoint: String) {
- if (!validateCredentials(email, password, symbol)) return
+ fun onHostSelected() {
+ view?.apply {
+ clearPassError()
+ clearNameError()
+ if (formHostValue?.contains("fakelog") == true) setDefaultCredentials("jan@fakelog.cf", "jan123")
+ }
+ }
- disposable.add(studentRepository.getStudents(email, password, symbol, endpoint)
+ fun onPassTextChanged() {
+ view?.clearPassError()
+ }
+
+ fun onNameTextChanged() {
+ view?.clearNameError()
+ }
+
+ fun attemptLogin() {
+ val email = view?.formNameValue.orEmpty()
+ val password = view?.formPassValue.orEmpty()
+ val endpoint = view?.formHostValue.orEmpty()
+
+ if (!validateCredentials(email, password)) return
+
+ disposable.add(studentRepository.getStudents(email, password, endpoint)
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
.doOnSubscribe {
@@ -45,6 +63,7 @@ class LoginFormPresenter @Inject constructor(
showProgress(true)
showContent(false)
}
+ Timber.i("Login started")
}
.doFinally {
view?.apply {
@@ -53,29 +72,21 @@ class LoginFormPresenter @Inject constructor(
}
}
.subscribe({
- view?.run {
- if (it.isEmpty() && !wasEmpty) {
- showSymbolInput()
- wasEmpty = true
- } else if (it.isEmpty() && wasEmpty) {
- showSymbolInput()
- setErrorSymbolIncorrect()
- analytics.logEvent(SIGN_UP, mapOf(SUCCESS to false, "students" to it.size, "endpoint" to endpoint, GROUP_ID to symbol.ifEmpty { "nil" }))
- } else {
- switchOptionsView()
- }
- }
+ Timber.i("Login result: Success")
+ analytics.logEvent("registration_form", SUCCESS to true, "students" to it.size, "endpoint" to endpoint, "error" to "No error")
+ view?.notifyParentAccountLogged(it)
}, {
- analytics.logEvent(SIGN_UP, mapOf(SUCCESS to true, "endpoint" to endpoint, GROUP_ID to symbol.ifEmpty { "nil" }))
+ Timber.i("Login result: An exception occurred")
+ analytics.logEvent("registration_form", SUCCESS to false, "students" to -1, "endpoint" to endpoint, "error" to it.localizedMessage)
errorHandler.dispatch(it)
}))
}
- private fun validateCredentials(login: String, password: String, symbol: String): Boolean {
+ private fun validateCredentials(login: String, password: String): Boolean {
var isCorrect = true
if (login.isEmpty()) {
- view?.setErrorNicknameRequired()
+ view?.setErrorNameRequired()
isCorrect = false
}
@@ -84,11 +95,6 @@ class LoginFormPresenter @Inject constructor(
isCorrect = false
}
- if (symbol.isEmpty() && wasEmpty) {
- view?.setErrorSymbolRequire()
- isCorrect = false
- }
-
if (password.length < 6 && password.isNotEmpty()) {
view?.setErrorPassInvalid(focus = isCorrect)
isCorrect = false
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt
index 4d540226..69672780 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt
@@ -1,30 +1,31 @@
package io.github.wulkanowy.ui.modules.login.form
+import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.ui.base.BaseView
interface LoginFormView : BaseView {
- val isDebug: Boolean
-
fun initView()
- fun switchOptionsView()
+ val formNameValue: String
- fun setErrorNicknameRequired()
+ val formPassValue: String
+
+ val formHostValue: String?
+
+ fun setDefaultCredentials(name: String, pass: String)
+
+ fun setErrorNameRequired()
fun setErrorPassRequired(focus: Boolean)
- fun setErrorSymbolRequire()
-
fun setErrorPassInvalid(focus: Boolean)
fun setErrorPassIncorrect()
- fun setErrorSymbolIncorrect()
+ fun clearNameError()
- fun resetViewErrors()
-
- fun showVersion()
+ fun clearPassError()
fun showSoftKeyboard()
@@ -34,5 +35,7 @@ interface LoginFormView : BaseView {
fun showContent(show: Boolean)
- fun showSymbolInput()
+ fun showVersion()
+
+ fun notifyParentAccountLogged(students: List)
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/options/LoginOptionsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt
similarity index 62%
rename from app/src/main/java/io/github/wulkanowy/ui/modules/login/options/LoginOptionsFragment.kt
rename to app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt
index 3e306b19..2bcb6b4e 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/options/LoginOptionsFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.ui.modules.login.options
+package io.github.wulkanowy.ui.modules.login.studentselect
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
@@ -13,47 +13,47 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.R
+import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.utils.setOnItemClickListener
-import kotlinx.android.synthetic.main.fragment_login_options.*
+import kotlinx.android.synthetic.main.fragment_login_student_select.*
+import java.io.Serializable
import javax.inject.Inject
-class LoginOptionsFragment : BaseFragment(), LoginOptionsView {
+class LoginStudentSelectFragment : BaseFragment(), LoginStudentSelectView {
@Inject
- lateinit var presenter: LoginOptionsPresenter
+ lateinit var presenter: LoginStudentSelectPresenter
@Inject
lateinit var loginAdapter: FlexibleAdapter>
companion object {
- fun newInstance() = LoginOptionsFragment()
+ const val SAVED_STUDENTS = "STUDENTS"
+
+ fun newInstance() = LoginStudentSelectFragment()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- return inflater.inflate(R.layout.fragment_login_options, container, false)
+ return inflater.inflate(R.layout.fragment_login_student_select, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
- presenter.onAttachView(this)
+ presenter.onAttachView(this, savedInstanceState?.getSerializable(SAVED_STUDENTS))
}
override fun initView() {
loginAdapter.apply { setOnItemClickListener { presenter.onItemSelected(it) } }
- loginOptionsRecycler.apply {
+ loginStudentSelectRecycler.apply {
adapter = loginAdapter
layoutManager = SmoothScrollLinearLayoutManager(context)
}
}
- fun onParentLoadData() {
- presenter.onParentViewLoadData()
- }
-
- override fun updateData(data: List) {
+ override fun updateData(data: List) {
loginAdapter.updateDataSet(data, true)
}
@@ -65,17 +65,26 @@ class LoginOptionsFragment : BaseFragment(), LoginOptionsView {
}
override fun showProgress(show: Boolean) {
- loginOptionsProgressContainer.visibility = if (show) VISIBLE else GONE
+ loginStudentSelectProgress.visibility = if (show) VISIBLE else GONE
}
override fun showContent(show: Boolean) {
- loginOptionsRecycler.visibility = if (show) VISIBLE else GONE
+ loginStudentSelectRecycler.visibility = if (show) VISIBLE else GONE
}
override fun showActionBar(show: Boolean) {
(activity as? AppCompatActivity)?.supportActionBar?.run { if (show) show() else hide() }
}
+ fun onParentInitStudentSelectFragment(students: List) {
+ presenter.onParentInitStudentSelectView(students)
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ outState.putSerializable(SAVED_STUDENTS, presenter.students as Serializable)
+ }
+
override fun onDestroyView() {
presenter.onDetachView()
super.onDestroyView()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/options/LoginOptionsItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectItem.kt
similarity index 80%
rename from app/src/main/java/io/github/wulkanowy/ui/modules/login/options/LoginOptionsItem.kt
rename to app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectItem.kt
index 2d4de475..c206a499 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/options/LoginOptionsItem.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectItem.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.ui.modules.login.options
+package io.github.wulkanowy.ui.modules.login.studentselect
import android.view.View
import eu.davidea.flexibleadapter.FlexibleAdapter
@@ -8,11 +8,11 @@ import eu.davidea.viewholders.FlexibleViewHolder
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Student
import kotlinx.android.extensions.LayoutContainer
-import kotlinx.android.synthetic.main.item_login_options.view.*
+import kotlinx.android.synthetic.main.item_login_student_select.view.*
-class LoginOptionsItem(val student: Student) : AbstractFlexibleItem() {
+class LoginStudentSelectItem(val student: Student) : AbstractFlexibleItem() {
- override fun getLayoutRes(): Int = R.layout.item_login_options
+ override fun getLayoutRes(): Int = R.layout.item_login_student_select
override fun createViewHolder(view: View?, adapter: FlexibleAdapter>?): ItemViewHolder {
return ItemViewHolder(view, adapter)
@@ -27,7 +27,7 @@ class LoginOptionsItem(val student: Student) : AbstractFlexibleItem(errorHandler) {
+) : BasePresenter