diff --git a/.travis.yml b/.travis.yml
index 8bda02d61..fa81da66b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,7 +14,7 @@ cache:
branches:
only:
- develop
- - 0.12.0
+ - 0.14.2
android:
licenses:
diff --git a/README.en.md b/README.en.md
index 29da5586e..7444cccae 100644
--- a/README.en.md
+++ b/README.en.md
@@ -7,11 +7,11 @@
[](https://f-droid.org/packages/io.github.wulkanowy/)
[](https://github.com/wulkanowy/wulkanowy/releases)
-Unofficial android VULCAN UONET+ register client for student and parent
+Unofficial android VULCAN UONET+ register client for both students and their parents
## Features
-* logging in using the email and password
+* logging in using the email and password OR using token and pin
* functions from the register website:
* grades
* grade statistics
@@ -24,7 +24,7 @@ Unofficial android VULCAN UONET+ register client for student and parent
* homework
* notes
* lucky number
-* calculation of the average
+* calculation of the average independently of school's preferences
* notifications, e.g. about a new grade
* dark and black (AMOLED) theme
* offline mode
@@ -32,21 +32,21 @@ Unofficial android VULCAN UONET+ register client for student and parent
## Download
-You can download the current beta from the Google Play or Fdroid store
+You can download the current beta version from the Google Play or the F-Droid store
[
](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
[
](https://f-droid.org/packages/io.github.wulkanowy/)
-You can also download a [development version](https://wulkanowy.github.io/#download) that includes new features prepared for the next release
+You can also download a [development version](https://wulkanowy.github.io/#download) that includes new features being prepared for the next release
## Built With
-* [Wulkanowy API](https://github.com/wulkanowy/api)
+* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
* [RxJava 2](https://github.com/ReactiveX/RxJava)
* [Dagger 2](https://github.com/google/dagger)
* [Room](https://developer.android.com/topic/libraries/architecture/room)
diff --git a/README.md b/README.md
index 59b74b3eb..61b13444a 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@ Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
## Funkcje
-* logowanie za pomocą e-maila i hasła
+* logowanie za pomocą e-maila i hasła LUB tokena i pinu
* funkcje ze strony internetowej dziennika:
* oceny
* statystyki ocen
@@ -24,7 +24,7 @@ Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
* zadania domowe
* uwagi
* szczęśliwy numerek
-* obliczanie średniej
+* obliczanie średniej niezależnie od preferencji szkoły
* powiadomienia np. o nowej ocenie
* ciemny i czarny (AMOLED) motyw
* tryb offilne
@@ -32,13 +32,13 @@ Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
## Pobierz
-Aktualną wersję beta możesz pobrać ze sklepu Google Play lub Fdroid
+Aktualną wersję beta możesz pobrać ze sklepu Google Play lub F-Droid
[
](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
[
](https://f-droid.org/packages/io.github.wulkanowy/)
@@ -47,7 +47,7 @@ Możesz także pobrać [wersję rozwojową](https://wulkanowy.github.io/#downloa
## Zbudowana za pomocą
-* [Wulkanowy API](https://github.com/wulkanowy/api)
+* [Wulkanowy SDK](https://github.com/wulkanowy/SDK)
* [RxJava 2](https://github.com/ReactiveX/RxJava)
* [Dagger 2](https://github.com/google/dagger)
* [Room](https://developer.android.com/topic/libraries/architecture/room)
@@ -59,4 +59,4 @@ Wnieś swój wkład w projekt, tworząc PR lub wysyłając issue na GitHub.
## Licencja
-Ten projekt jest licencjonowany w ramach Apache License 2.0 - szczegóły w pliku [LICENSE](LICENSE)
\ No newline at end of file
+Ten projekt udostępniany jest na licencji Apache License 2.0 - szczegóły w pliku [LICENSE](LICENSE)
diff --git a/app/build.gradle b/app/build.gradle
index 090a643da..24a470ae0 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -17,8 +17,8 @@ android {
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 16
targetSdkVersion 29
- versionCode 47
- versionName "0.12.0"
+ versionCode 51
+ versionName "0.14.2"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
@@ -110,37 +110,36 @@ play {
}
ext {
- work_manager = "2.3.0-alpha03"
- room = "2.2.1"
- dagger = "2.25.2"
+ work_manager = "2.3.0-rc01"
+ room = "2.2.3"
+ dagger = "2.25.4"
chucker = "2.0.4"
mockk = "1.9.2"
}
configurations.all {
resolutionStrategy.force "androidx.constraintlayout:constraintlayout:1.1.3"
- resolutionStrategy.force "com.google.android.material:material:1.1.0-alpha07"
}
dependencies {
- implementation "io.github.wulkanowy:api:0.12.0"
+ implementation "io.github.wulkanowy:sdk:0.14.2"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
- implementation "androidx.core:core-ktx:1.2.0-beta01"
- implementation "androidx.activity:activity-ktx:1.1.0-rc01"
+ implementation "androidx.core:core-ktx:1.2.0-rc01"
+ implementation "androidx.activity:activity-ktx:1.1.0-rc03"
implementation "androidx.appcompat:appcompat:1.1.0"
implementation "androidx.appcompat:appcompat-resources:1.1.0"
- implementation "androidx.fragment:fragment-ktx:1.2.0-rc01"
+ implementation "androidx.fragment:fragment-ktx:1.2.0-rc05"
implementation "androidx.annotation:annotation:1.1.0"
implementation "androidx.multidex:multidex:2.0.1"
implementation "androidx.preference:preference-ktx:1.1.0"
- implementation "androidx.recyclerview:recyclerview:1.1.0-rc01"
+ implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation "androidx.viewpager:viewpager:1.0.0"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha03"
implementation "androidx.constraintlayout:constraintlayout:1.1.3"
- implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0-rc01"
- implementation "com.google.android.material:material:1.1.0-alpha07"
+ implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
+ implementation "com.google.android.material:material:1.1.0-rc01"
implementation "com.github.wulkanowy:material-chips-input:2.0.1"
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
implementation "me.zhanghai.android.materialprogressbar:library:1.6.1"
@@ -157,24 +156,25 @@ dependencies {
implementation "com.google.dagger:dagger-android-support:$dagger"
kapt "com.google.dagger:dagger-compiler:$dagger"
kapt "com.google.dagger:dagger-android-processor:$dagger"
- implementation "com.squareup.inject:assisted-inject-annotations-dagger2:0.5.0"
- kapt "com.squareup.inject:assisted-inject-processor-dagger2:0.5.0"
+ implementation "com.squareup.inject:assisted-inject-annotations-dagger2:0.5.2"
+ kapt "com.squareup.inject:assisted-inject-processor-dagger2:0.5.2"
implementation "eu.davidea:flexible-adapter:5.1.0"
implementation "eu.davidea:flexible-adapter-ui:1.0.0"
implementation "com.aurelhubert:ahbottomnavigation:2.3.4"
implementation "com.ncapdevi:frag-nav:3.3.0"
+ implementation "com.github.YarikSOffice:lingver:1.1.0"
implementation "com.github.pwittchen:reactivenetwork-rx2:3.0.6"
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
- implementation "io.reactivex.rxjava2:rxjava:2.2.13"
+ implementation "io.reactivex.rxjava2:rxjava:2.2.16"
implementation "com.google.code.gson:gson:2.8.6"
implementation "com.jakewharton.threetenabp:threetenabp:1.2.1"
implementation "com.jakewharton.timber:timber:4.7.1"
implementation "at.favre.lib:slf4j-timber:1.0.1"
- implementation "com.squareup.okhttp3:logging-interceptor:3.12.6"
- implementation "com.mikepenz:aboutlibraries:7.0.4"
+ implementation "com.mikepenz:aboutlibraries-core:7.1.0"
+ implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
playImplementation "com.google.firebase:firebase-core:17.2.1"
playImplementation "com.crashlytics.sdk.android:crashlytics:2.10.1"
@@ -184,10 +184,10 @@ dependencies {
debugImplementation "fr.o80.chucker:library:$chucker"
debugImplementation "com.amitshekhar.android:debug-db:1.0.6"
- testImplementation "junit:junit:4.12"
+ testImplementation "junit:junit:4.13"
testImplementation "io.mockk:mockk:$mockk"
testImplementation "org.threeten:threetenbp:1.4.0"
- testImplementation "org.mockito:mockito-inline:3.1.0"
+ testImplementation "org.mockito:mockito-inline:3.2.4"
androidTestImplementation "androidx.test:core:1.2.0"
androidTestImplementation "androidx.test:runner:1.2.0"
@@ -195,7 +195,7 @@ dependencies {
androidTestImplementation "io.mockk:mockk-android:$mockk"
androidTestImplementation "androidx.room:room-testing:$room"
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
- androidTestImplementation "org.mockito:mockito-android:3.1.0"
+ androidTestImplementation "org.mockito:mockito-android:3.2.4"
}
apply plugin: 'com.google.gms.google-services'
diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/19.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/19.json
new file mode 100644
index 000000000..1e4593bb3
--- /dev/null
+++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/19.json
@@ -0,0 +1,1628 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 19,
+ "identityHash": "294f40cebf8314f9776208827240e65f",
+ "entities": [
+ {
+ "tableName": "Students",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `scrapper_base_url` TEXT NOT NULL, `mobile_base_url` TEXT NOT NULL, `login_type` TEXT NOT NULL, `login_mode` TEXT NOT NULL, `certificate_key` TEXT NOT NULL, `private_key` TEXT NOT NULL, `is_parent` INTEGER NOT NULL, `email` TEXT NOT NULL, `password` TEXT NOT NULL, `symbol` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `user_login_id` INTEGER NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_name` TEXT NOT NULL, `class_name` TEXT NOT NULL, `class_id` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `registration_date` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "scrapperBaseUrl",
+ "columnName": "scrapper_base_url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mobileBaseUrl",
+ "columnName": "mobile_base_url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginType",
+ "columnName": "login_type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginMode",
+ "columnName": "login_mode",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "certificateKey",
+ "columnName": "certificate_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "privateKey",
+ "columnName": "private_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isParent",
+ "columnName": "is_parent",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "password",
+ "columnName": "password",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "symbol",
+ "columnName": "symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentName",
+ "columnName": "student_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolSymbol",
+ "columnName": "school_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolName",
+ "columnName": "school_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "className",
+ "columnName": "class_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isCurrent",
+ "columnName": "is_current",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registrationDate",
+ "columnName": "registration_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_Students_email_symbol_student_id_school_id_class_id",
+ "unique": true,
+ "columnNames": [
+ "email",
+ "symbol",
+ "student_id",
+ "school_id",
+ "class_id"
+ ],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Students_email_symbol_student_id_school_id_class_id` ON `${TABLE_NAME}` (`email`, `symbol`, `student_id`, `school_id`, `class_id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Semesters",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryName",
+ "columnName": "diary_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolYear",
+ "columnName": "school_year",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterName",
+ "columnName": "semester_name",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isCurrent",
+ "columnName": "is_current",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unitId",
+ "columnName": "unit_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_Semesters_student_id_diary_id_semester_id",
+ "unique": true,
+ "columnNames": [
+ "student_id",
+ "diary_id",
+ "semester_id"
+ ],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_semester_id` ON `${TABLE_NAME}` (`student_id`, `diary_id`, `semester_id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Exams",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `group` TEXT NOT NULL, `type` TEXT NOT NULL, `description` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entryDate",
+ "columnName": "entry_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "group",
+ "columnName": "group",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Timetable",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `number` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `subjectOld` TEXT NOT NULL, `group` TEXT NOT NULL, `room` TEXT NOT NULL, `roomOld` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacherOld` TEXT NOT NULL, `info` TEXT NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectOld",
+ "columnName": "subjectOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "group",
+ "columnName": "group",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "room",
+ "columnName": "room",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "roomOld",
+ "columnName": "roomOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherOld",
+ "columnName": "teacherOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "info",
+ "columnName": "info",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "changes",
+ "columnName": "changes",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "canceled",
+ "columnName": "canceled",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Attendance",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `excused` INTEGER NOT NULL, `deleted` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presence",
+ "columnName": "presence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "exemption",
+ "columnName": "exemption",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lateness",
+ "columnName": "lateness",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excused",
+ "columnName": "excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deleted",
+ "columnName": "deleted",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AttendanceSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `subject_id` INTEGER NOT NULL, `month` INTEGER NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `absence_excused` INTEGER NOT NULL, `absence_for_school_reasons` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `lateness_excused` INTEGER NOT NULL, `exemption` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subject_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "month",
+ "columnName": "month",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presence",
+ "columnName": "presence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absenceExcused",
+ "columnName": "absence_excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absenceForSchoolReasons",
+ "columnName": "absence_for_school_reasons",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lateness",
+ "columnName": "lateness",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "latenessExcused",
+ "columnName": "lateness_excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "exemption",
+ "columnName": "exemption",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Grades",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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` REAL 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)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isRead",
+ "columnName": "is_read",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entry",
+ "columnName": "entry",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "modifier",
+ "columnName": "modifier",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "color",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gradeSymbol",
+ "columnName": "grade_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weightValue",
+ "columnName": "weightValue",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `position` INTEGER NOT NULL, `subject` TEXT NOT NULL, `predicted_grade` TEXT NOT NULL, `final_grade` TEXT NOT NULL, `proposed_points` TEXT NOT NULL, `final_points` TEXT NOT NULL, `points_sum` TEXT NOT NULL, `average` REAL NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "position",
+ "columnName": "position",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "predictedGrade",
+ "columnName": "predicted_grade",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalGrade",
+ "columnName": "final_grade",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "proposedPoints",
+ "columnName": "proposed_points",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalPoints",
+ "columnName": "final_points",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pointsSum",
+ "columnName": "points_sum",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "average",
+ "columnName": "average",
+ "affinity": "REAL",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT 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)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "grade",
+ "columnName": "grade",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "amount",
+ "columnName": "amount",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semester",
+ "columnName": "is_semester",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesPointsStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `others` REAL NOT NULL, `student` REAL NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "others",
+ "columnName": "others",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "student",
+ "columnName": "student",
+ "affinity": "REAL",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Messages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER 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, `content` 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)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageId",
+ "columnName": "message_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "sender",
+ "columnName": "sender_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "senderId",
+ "columnName": "sender_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "recipient",
+ "columnName": "recipient_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unread",
+ "columnName": "unread",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unreadBy",
+ "columnName": "unread_by",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "readBy",
+ "columnName": "read_by",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "removed",
+ "columnName": "removed",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT 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)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isRead",
+ "columnName": "is_read",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Homework",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entryDate",
+ "columnName": "entry_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Subjects",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "LuckyNumbers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "luckyNumber",
+ "columnName": "lucky_number",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "CompletedLesson",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT 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)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "topic",
+ "columnName": "topic",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "substitution",
+ "columnName": "substitution",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "resources",
+ "columnName": "resources",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "ReportingUnits",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT 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)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "shortName",
+ "columnName": "short",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "senderId",
+ "columnName": "sender_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "senderName",
+ "columnName": "sender_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "roles",
+ "columnName": "roles",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Recipients",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT 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)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realName",
+ "columnName": "real_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginId",
+ "columnName": "login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unitId",
+ "columnName": "unit_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "role",
+ "columnName": "role",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hash",
+ "columnName": "hash",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MobileDevices",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deviceId",
+ "columnName": "device_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Teachers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "shortName",
+ "columnName": "short_name",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "School",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT NOT NULL, `contact` TEXT NOT NULL, `headmaster` TEXT NOT NULL, `pedagogue` TEXT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "contact",
+ "columnName": "contact",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "headmaster",
+ "columnName": "headmaster",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pedagogue",
+ "columnName": "pedagogue",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '294f40cebf8314f9776208827240e65f')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/db/migrations/AbstractMigrationTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/db/migrations/AbstractMigrationTest.kt
index 74cac078c..611161e58 100644
--- a/app/src/androidTest/java/io/github/wulkanowy/data/db/migrations/AbstractMigrationTest.kt
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/db/migrations/AbstractMigrationTest.kt
@@ -1,11 +1,13 @@
package io.github.wulkanowy.data.db.migrations
+import androidx.preference.PreferenceManager
import androidx.room.Room
import androidx.room.testing.MigrationTestHelper
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
import androidx.test.core.app.ApplicationProvider
import androidx.test.platform.app.InstrumentationRegistry
import io.github.wulkanowy.data.db.AppDatabase
+import io.github.wulkanowy.data.db.SharedPrefProvider
import org.junit.Rule
abstract class AbstractMigrationTest {
@@ -22,7 +24,9 @@ abstract class AbstractMigrationTest {
fun getMigratedRoomDatabase(): AppDatabase {
val database = Room.databaseBuilder(ApplicationProvider.getApplicationContext(),
AppDatabase::class.java, dbName)
- .addMigrations(*AppDatabase.getMigrations())
+ .addMigrations(*AppDatabase.getMigrations(SharedPrefProvider(PreferenceManager
+ .getDefaultSharedPreferences(ApplicationProvider.getApplicationContext())))
+ )
.build()
// close the database and release any stream resources when the test finishes
helper.closeWhenFinished(database)
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
index a0acb5a76..711e29118 100644
--- 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
@@ -6,15 +6,18 @@ 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.SdkHelper
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.TestInternetObservingStrategy
+import io.github.wulkanowy.sdk.Sdk
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
+import io.mockk.just
+import io.mockk.runs
import io.reactivex.Single
import org.junit.After
import org.junit.Before
@@ -25,14 +28,13 @@ import org.threeten.bp.LocalDateTime
import kotlin.test.assertEquals
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()
+ @MockK
+ private lateinit var mockSdk: Sdk
private val settings = InternetObservingSettings.builder()
.strategy(TestInternetObservingStrategy())
@@ -55,13 +57,14 @@ class GradeRepositoryTest {
MockKAnnotations.init(this)
testDb = Room.inMemoryDatabaseBuilder(getApplicationContext(), AppDatabase::class.java).build()
gradeLocal = GradeLocal(testDb.gradeDao)
- gradeRemote = GradeRemote(mockApi)
+ gradeRemote = GradeRemote(mockSdk)
- 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
+ every { semesterMock.schoolYear } returns 2019
+ every { semesterMock.semesterId } returns 1
+ every { mockSdk.switchDiary(any(), any()) } returns mockSdk
}
@After
@@ -71,7 +74,7 @@ class GradeRepositoryTest {
@Test
fun markOlderThanRegisterDateAsRead() {
- every { mockApi.getGrades(1) } returns Single.just(listOf(
+ every { mockSdk.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 4.0, of(2019, 2, 25), "Ocena pojawiła się"),
createGradeApi(5, 4.0, of(2019, 2, 26), "przed zalogowanie w aplikacji"),
createGradeApi(5, 4.0, of(2019, 2, 27), "Ocena z dnia logowania"),
@@ -95,7 +98,7 @@ class GradeRepositoryTest {
createGradeLocal(3, 5.0, of(2019, 2, 27), "Trzecia")
))
- every { mockApi.getGrades(1) } returns Single.just(listOf(
+ every { mockSdk.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 2.0, of(2019, 2, 25), "Ocena ma datę, jest inna, ale nie zostanie powiadomiona"),
createGradeApi(4, 3.0, of(2019, 2, 26), "starszą niż ostatnia lokalnie"),
createGradeApi(3, 4.0, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie"),
@@ -119,7 +122,7 @@ class GradeRepositoryTest {
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
))
- every { mockApi.getGrades(1) } returns Single.just(listOf(
+ every { mockSdk.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
))
@@ -137,7 +140,7 @@ class GradeRepositoryTest {
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
))
- every { mockApi.getGrades(1) } returns Single.just(listOf(
+ every { mockSdk.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
@@ -153,7 +156,7 @@ class GradeRepositoryTest {
fun emptyLocal() {
gradeLocal.saveGrades(listOf())
- every { mockApi.getGrades(1) } returns Single.just(listOf(
+ every { mockSdk.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
@@ -172,7 +175,7 @@ class GradeRepositoryTest {
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
))
- every { mockApi.getGrades(1) } returns Single.just(listOf())
+ every { mockSdk.getGrades(1) } returns Single.just(listOf())
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet()
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
index e0fd05a82..9146934bf 100644
--- 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
@@ -1,8 +1,7 @@
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.sdk.pojo.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 {
@@ -18,17 +17,25 @@ fun createGradeLocal(value: Int, weight: Double, date: LocalDate, desc: String,
description = desc,
entry = "",
gradeSymbol = "",
- value = value,
+ value = value.toDouble(),
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
- }
+ return GradeRemote(
+ subject = "",
+ color = "",
+ comment = "",
+ date = date,
+ description = desc,
+ entry = "",
+ modifier = .0,
+ symbol = "",
+ teacher = "",
+ value = value.toDouble(),
+ weight = weight.toString(),
+ weightValue = weight
+ )
}
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
index 6edaccdb4..a394927bd 100644
--- 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
@@ -42,7 +42,7 @@ class RecipientLocalTest {
))
val recipients = recipientLocal.getRecipients(
- Student("fakelog.cf", "AUTO", "", "", "", 1, "", "", "", "", 1, true, LocalDateTime.now()),
+ Student("fakelog.cf", "AUTO", "", "", "", "", false, "", "", "", 1, 0, "", "", "", "", 1, true, LocalDateTime.now()),
2,
ReportingUnit(1, 4, "", 0, "", emptyList())
).blockingGet()
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/student/StudentLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/student/StudentLocalTest.kt
index ee4c652f4..6ae404b2b 100644
--- a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/student/StudentLocalTest.kt
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/student/StudentLocalTest.kt
@@ -39,7 +39,7 @@ class StudentLocalTest {
@Test
fun saveAndReadTest() {
- studentLocal.saveStudents(listOf(Student(email = "test", password = "test123", schoolSymbol = "23", endpoint = "fakelog.cf", loginType = "AUTO", isCurrent = true, studentName = "", schoolName = "", studentId = 0, classId = 1, symbol = "", registrationDate = now(), className = "")))
+ studentLocal.saveStudents(listOf(Student(email = "test", password = "test123", schoolSymbol = "23", scrapperBaseUrl = "fakelog.cf", loginType = "AUTO", isCurrent = true, studentName = "", schoolName = "", studentId = 0, classId = 1, symbol = "", registrationDate = now(), className = "", loginMode = "API", certificateKey = "", privateKey = "", mobileBaseUrl = "", userLoginId = 0, isParent = false)))
.blockingGet()
val student = studentLocal.getCurrentStudent(true).blockingGet()
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
index c38ffd99f..e2ce2255c 100644
--- 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
@@ -1,13 +1,11 @@
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.sdk.pojo.Timetable as TimetableRemote
import io.github.wulkanowy.data.db.entities.Timetable as TimetableLocal
-fun createTimetableLocal(number: Int, start: LocalDateTime, room: String = "", subject: String = "", teacher: String = "", changes: Boolean = false): TimetableLocal {
+fun createTimetableLocal(start: LocalDateTime, number: Int, room: String = "", subject: String = "", teacher: String = "", changes: Boolean = false): TimetableLocal {
return TimetableLocal(
studentId = 1,
diaryId = 2,
@@ -28,18 +26,22 @@ fun createTimetableLocal(number: Int, start: LocalDateTime, room: String = "", s
)
}
-fun createTimetableRemote(number: Int, start: LocalDateTime, room: String, subject: String = "", teacher: String = "", changes: Boolean = false): TimetableRemote {
+fun createTimetableRemote(start: LocalDateTime, number: Int = 1, room: String = "", subject: String = "", teacher: String = "", changes: Boolean = false): TimetableRemote {
return TimetableRemote(
number = number,
- start = start.toDate(),
- end = start.plusMinutes(45).toDate(),
- date = start.toLocalDate().toDate(),
+ start = start,
+ end = start.plusMinutes(45),
+ date = start.toLocalDate(),
subject = subject,
group = "",
room = room,
teacher = teacher,
info = "",
changes = changes,
- canceled = false
+ canceled = false,
+ roomOld = "",
+ subjectOld = "",
+ teacherOld = "",
+ studentPlan = true
)
}
diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TimetableLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TimetableLocalTest.kt
index fe25e4e96..6406d7435 100644
--- a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TimetableLocalTest.kt
+++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TimetableLocalTest.kt
@@ -35,9 +35,9 @@ class TimetableLocalTest {
@Test
fun saveAndReadTest() {
timetableDb.saveTimetable(listOf(
- 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))
+ createTimetableLocal(of(2018, 9, 10, 0, 0, 0), 1),
+ createTimetableLocal(of(2018, 9, 14, 0, 0, 0), 1),
+ createTimetableLocal(of(2018, 9, 17, 0, 0, 0), 1)
))
val exams = timetableDb.getTimetable(
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
index 02ab605ed..565425d43 100644
--- 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
@@ -6,14 +6,13 @@ 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.github.wulkanowy.sdk.Sdk
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
@@ -27,8 +26,8 @@ import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class TimetableRepositoryTest {
- @SpyK
- private var mockApi = Api()
+ @MockK
+ private lateinit var mockSdk: Sdk
private val settings = InternetObservingSettings.builder()
.strategy(TestInternetObservingStrategy())
@@ -48,10 +47,13 @@ class TimetableRepositoryTest {
MockKAnnotations.init(this)
testDb = Room.inMemoryDatabaseBuilder(getApplicationContext(), AppDatabase::class.java).build()
timetableLocal = TimetableLocal(testDb.timetableDao)
- timetableRemote = TimetableRemote(mockApi)
+ timetableRemote = TimetableRemote(mockSdk)
every { semesterMock.studentId } returns 1
every { semesterMock.diaryId } returns 2
+ every { semesterMock.schoolYear } returns 2019
+ every { semesterMock.semesterId } returns 1
+ every { mockSdk.switchDiary(any(), any()) } returns mockSdk
}
@After
@@ -62,17 +64,17 @@ class TimetableRepositoryTest {
@Test
fun copyRoomToCompletedFromPrevious() {
timetableLocal.saveTimetable(listOf(
- createTimetableLocal(1, of(2019, 3, 5, 8, 0), "123", "Przyroda"),
- createTimetableLocal(2, of(2019, 3, 5, 8, 50), "321", "Religia"),
- createTimetableLocal(3, of(2019, 3, 5, 9, 40), "213", "W-F"),
- createTimetableLocal(4, of(2019, 3, 5, 10, 30), "213", "W-F", "Jan Kowalski")
+ createTimetableLocal(of(2019, 3, 5, 8, 0), 1, "123", "Przyroda"),
+ createTimetableLocal(of(2019, 3, 5, 8, 50), 2, "321", "Religia"),
+ createTimetableLocal(of(2019, 3, 5, 9, 40), 3, "213", "W-F"),
+ createTimetableLocal(of(2019, 3, 5, 10, 30),3, "213", "W-F", "Jan Kowalski")
))
- every { mockApi.getTimetable(any(), any()) } returns Single.just(listOf(
- createTimetableRemote(1, of(2019, 3, 5, 8, 0), "", "Przyroda"),
- createTimetableRemote(2, of(2019, 3, 5, 8, 50), "", "Religia"),
- createTimetableRemote(3, of(2019, 3, 5, 9, 40), "", "W-F"),
- createTimetableRemote(4, of(2019, 3, 5, 10, 30), "", "W-F")
+ every { mockSdk.getTimetable(any(), any()) } returns Single.just(listOf(
+ createTimetableRemote(of(2019, 3, 5, 8, 0), 1, "", "Przyroda"),
+ createTimetableRemote(of(2019, 3, 5, 8, 50), 2, "", "Religia"),
+ createTimetableRemote(of(2019, 3, 5, 9, 40), 3, "", "W-F"),
+ createTimetableRemote(of(2019, 3, 5, 10, 30), 4, "", "W-F")
))
val lessons = TimetableRepository(settings, timetableLocal, timetableRemote)
@@ -88,27 +90,58 @@ class TimetableRepositoryTest {
@Test
fun copyTeacherToCompletedFromPrevious() {
timetableLocal.saveTimetable(listOf(
- createTimetableLocal(1, of(2019, 3, 5, 8, 0), "123", "Przyroda", "Jan Garnkiewicz", false),
- createTimetableLocal(2, of(2019, 3, 5, 8, 50), "321", "Religia", "Paweł Jumper", false),
- createTimetableLocal(3, of(2019, 3, 5, 9, 40), "213", "W-F", "", true),
- createTimetableLocal(4, of(2019, 3, 5, 10, 30), "213", "W-F", "", false)
+ createTimetableLocal(of(2019, 12, 23, 8, 0), 1, "123", "Matematyka", "Paweł Poniedziałkowski", false),
+ createTimetableLocal(of(2019, 12, 23, 8, 50), 2, "124", "Matematyka", "Paweł Poniedziałkowski", false),
+ createTimetableLocal(of(2019, 12, 23, 9, 40), 3, "125", "Język polski", "Joanna Wtorkowska", true),
+ createTimetableLocal(of(2019, 12, 23, 10, 40), 4, "126", "Język polski", "Joanna Wtorkowska", true),
+
+ createTimetableLocal(of(2019, 12, 24, 8, 0), 1, "123", "Język polski", "Joanna Wtorkowska", false),
+ createTimetableLocal(of(2019, 12, 24, 8, 50), 2, "124", "Język polski", "Joanna Wtorkowska", false),
+ createTimetableLocal(of(2019, 12, 24, 9, 40), 3, "125", "Język polski", "Joanna Środowska", true),
+ createTimetableLocal(of(2019, 12, 24, 10, 40), 4, "126", "Język polski", "Joanna Środowska", true),
+
+ createTimetableLocal(of(2019, 12, 25, 8, 0), 1, "123", "Matematyka", "", false),
+ createTimetableLocal(of(2019, 12, 25, 8, 50), 2, "124", "Matematyka", "", false),
+ createTimetableLocal(of(2019, 12, 25, 9, 40), 3, "125", "Matematyka", "", true),
+ createTimetableLocal(of(2019, 12, 25, 10, 40), 4, "126", "Matematyka", "", true)
))
- every { mockApi.getTimetable(any(), any()) } returns Single.just(listOf(
- createTimetableRemote(1, of(2019, 3, 5, 8, 0), "", "Przyroda", "", true), // should override local
- createTimetableRemote(2, of(2019, 3, 5, 8, 50), "", "Religia", "", false),
- createTimetableRemote(3, of(2019, 3, 5, 9, 40), "", "W-F", "Jan Garnkiewicz", false),
- createTimetableRemote(4, of(2019, 3, 5, 10, 30), "", "W-F", "Paweł Jumper", false)
+ every { mockSdk.getTimetable(any(), any()) } returns Single.just(listOf(
+ createTimetableRemote(of(2019, 12, 23, 8, 0), 1, "123", "Matematyka", "Paweł Poniedziałkowski", false),
+ createTimetableRemote(of(2019, 12, 23, 8, 50), 2, "124", "Matematyka", "Jakub Wtorkowski", true),
+ createTimetableRemote(of(2019, 12, 23, 9, 40), 3, "125", "Język polski", "Joanna Poniedziałkowska", false),
+ createTimetableRemote(of(2019, 12, 23, 10, 40), 4, "126", "Język polski", "Joanna Wtorkowska", true),
+
+ createTimetableRemote(of(2019, 12, 24, 8, 0), 1, "123", "Język polski", "", false),
+ createTimetableRemote(of(2019, 12, 24, 8, 50), 2, "124", "Język polski", "", true),
+ createTimetableRemote(of(2019, 12, 24, 9, 40), 3, "125", "Język polski", "", false),
+ createTimetableRemote(of(2019, 12, 24, 10, 40), 4, "126", "Język polski", "", true),
+
+ createTimetableRemote(of(2019, 12, 25, 8, 0), 1, "123", "Matematyka", "Paweł Środowski", false),
+ createTimetableRemote(of(2019, 12, 25, 8, 50), 2, "124", "Matematyka", "Paweł Czwartkowski", true),
+ createTimetableRemote(of(2019, 12, 25, 9, 40), 3, "125", "Matematyka", "Paweł Środowski", false),
+ createTimetableRemote(of(2019, 12, 25, 10, 40), 4, "126", "Matematyka", "Paweł Czwartkowski", true)
))
val lessons = TimetableRepository(settings, timetableLocal, timetableRemote)
- .getTimetable(semesterMock, LocalDate.of(2019, 3, 5), LocalDate.of(2019, 3, 5), true)
+ .getTimetable(semesterMock, LocalDate.of(2019, 12, 23), LocalDate.of(2019, 12, 25), true)
.blockingGet()
- assertEquals(4, lessons.size)
- assertEquals("", lessons[0].teacher)
- assertEquals("Paweł Jumper", lessons[1].teacher)
- assertEquals("Jan Garnkiewicz", lessons[2].teacher)
- assertEquals("Paweł Jumper", lessons[3].teacher)
+ assertEquals(12, lessons.size)
+
+ assertEquals("Paweł Poniedziałkowski", lessons[0].teacher)
+ assertEquals("Jakub Wtorkowski", lessons[1].teacher)
+ assertEquals("Joanna Poniedziałkowska", lessons[2].teacher)
+ assertEquals("Joanna Wtorkowska", lessons[3].teacher)
+
+ assertEquals("Joanna Wtorkowska", lessons[4].teacher)
+ assertEquals("", lessons[5].teacher)
+ assertEquals("", lessons[6].teacher)
+ assertEquals("", lessons[7].teacher)
+
+ assertEquals("Paweł Środowski", lessons[8].teacher)
+ assertEquals("Paweł Czwartkowski", lessons[9].teacher)
+ assertEquals("Paweł Środowski", lessons[10].teacher)
+ assertEquals("Paweł Czwartkowski", lessons[11].teacher)
}
}
diff --git a/app/src/debug/res/values-pl/strings.xml b/app/src/debug/res/values-pl/strings.xml
deleted file mode 100644
index c90641ddb..000000000
--- a/app/src/debug/res/values-pl/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- Wulkanowy DEV
-
diff --git a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt
index 72969059b..90b3581c8 100644
--- a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt
+++ b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt
@@ -6,6 +6,7 @@ import android.util.Log.VERBOSE
import androidx.multidex.MultiDex
import androidx.work.Configuration
import com.jakewharton.threetenabp.AndroidThreeTen
+import com.yariksoffice.lingver.Lingver
import dagger.android.AndroidInjector
import dagger.android.support.DaggerApplication
import eu.davidea.flexibleadapter.FlexibleAdapter
@@ -44,6 +45,7 @@ class WulkanowyApp : DaggerApplication(), Configuration.Provider {
super.onCreate()
AndroidThreeTen.init(this)
RxJavaPlugins.setErrorHandler(::onError)
+ Lingver.init(this)
themeManager.applyDefaultTheme()
initLogging()
diff --git a/app/src/main/java/io/github/wulkanowy/data/ApiHelper.kt b/app/src/main/java/io/github/wulkanowy/data/ApiHelper.kt
deleted file mode 100644
index b6eee316b..000000000
--- a/app/src/main/java/io/github/wulkanowy/data/ApiHelper.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-package io.github.wulkanowy.data
-
-import io.github.wulkanowy.api.Api
-import io.github.wulkanowy.data.db.entities.Student
-import java.net.URL
-import javax.inject.Inject
-
-class ApiHelper @Inject constructor(private val api: Api) {
-
- fun initApi(student: Student) {
- api.apply {
- email = student.email
- password = student.password
- symbol = student.symbol
- schoolSymbol = student.schoolSymbol
- studentId = student.studentId
- classId = student.classId
- 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) {
- api.apply {
- this.email = email
- this.password = password
- this.symbol = symbol
- host = URL(endpoint).run { host + ":$port".removeSuffix(":-1") }
- ssl = endpoint.startsWith("https")
- useNewStudent = true
- }
- }
-}
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 9c89d507c..1bc4eb616 100644
--- a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt
@@ -11,12 +11,10 @@ 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.db.SharedPrefProvider
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
-import okhttp3.logging.HttpLoggingInterceptor
-import okhttp3.logging.HttpLoggingInterceptor.Level.BASIC
-import okhttp3.logging.HttpLoggingInterceptor.Level.NONE
+import io.github.wulkanowy.sdk.Sdk
import timber.log.Timber
import javax.inject.Singleton
@@ -33,15 +31,14 @@ internal class RepositoryModule {
@Singleton
@Provides
- fun provideApi(chuckCollector: ChuckCollector, context: Context): Api {
- return Api().apply {
- logLevel = NONE
+ fun provideSdk(chuckCollector: ChuckCollector, context: Context): Sdk {
+ return Sdk().apply {
androidVersion = android.os.Build.VERSION.RELEASE
buildTag = android.os.Build.MODEL
- setInterceptor(HttpLoggingInterceptor(HttpLoggingInterceptor.Logger { Timber.d(it) }).setLevel(BASIC))
+ setSimpleHttpLogger { Timber.d(it) }
// for debug only
- setInterceptor(ChuckInterceptor(context, chuckCollector).maxContentLength(250000L), true, 0)
+ addInterceptor(ChuckInterceptor(context, chuckCollector).maxContentLength(250000L), true)
}
}
@@ -55,7 +52,7 @@ internal class RepositoryModule {
@Singleton
@Provides
- fun provideDatabase(context: Context) = AppDatabase.newInstance(context)
+ fun provideDatabase(context: Context, sharedPrefProvider: SharedPrefProvider) = AppDatabase.newInstance(context, sharedPrefProvider)
@Singleton
@Provides
diff --git a/app/src/main/java/io/github/wulkanowy/data/SdkHelper.kt b/app/src/main/java/io/github/wulkanowy/data/SdkHelper.kt
new file mode 100644
index 000000000..901712594
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/SdkHelper.kt
@@ -0,0 +1,30 @@
+package io.github.wulkanowy.data
+
+import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.sdk.Sdk
+import javax.inject.Inject
+
+class SdkHelper @Inject constructor(private val sdk: Sdk) {
+
+ fun init(student: Student) {
+ sdk.apply {
+ email = student.email
+ password = student.password
+ symbol = student.symbol
+ schoolSymbol = student.schoolSymbol
+ studentId = student.studentId
+ classId = student.classId
+
+ if (Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
+ scrapperBaseUrl = student.scrapperBaseUrl
+ loginType = Sdk.ScrapperLoginType.valueOf(student.loginType)
+ }
+ loginId = student.userLoginId
+
+ mode = Sdk.Mode.valueOf(student.loginMode)
+ mobileBaseUrl = student.mobileBaseUrl
+ certKey = student.certificateKey
+ privateKey = student.privateKey
+ }
+ }
+}
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 b1896c755..9ee1b263d 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
@@ -58,6 +58,7 @@ import io.github.wulkanowy.data.db.migrations.Migration15
import io.github.wulkanowy.data.db.migrations.Migration16
import io.github.wulkanowy.data.db.migrations.Migration17
import io.github.wulkanowy.data.db.migrations.Migration18
+import io.github.wulkanowy.data.db.migrations.Migration19
import io.github.wulkanowy.data.db.migrations.Migration2
import io.github.wulkanowy.data.db.migrations.Migration3
import io.github.wulkanowy.data.db.migrations.Migration4
@@ -100,9 +101,9 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() {
companion object {
- const val VERSION_SCHEMA = 18
+ const val VERSION_SCHEMA = 19
- fun getMigrations(): Array {
+ fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array {
return arrayOf(
Migration2(),
Migration3(),
@@ -120,16 +121,17 @@ abstract class AppDatabase : RoomDatabase() {
Migration15(),
Migration16(),
Migration17(),
- Migration18()
+ Migration18(),
+ Migration19(sharedPrefProvider)
)
}
- fun newInstance(context: Context): AppDatabase {
+ fun newInstance(context: Context, sharedPrefProvider: SharedPrefProvider): AppDatabase {
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
.setJournalMode(TRUNCATE)
.fallbackToDestructiveMigrationFrom(VERSION_SCHEMA + 1)
.fallbackToDestructiveMigrationOnDowngrade()
- .addMigrations(*getMigrations())
+ .addMigrations(*getMigrations(sharedPrefProvider))
.build()
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/SharedPrefProvider.kt b/app/src/main/java/io/github/wulkanowy/data/db/SharedPrefProvider.kt
index a6d0a067e..4a4aaf74f 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/SharedPrefProvider.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/SharedPrefProvider.kt
@@ -8,12 +8,22 @@ import javax.inject.Singleton
@Singleton
class SharedPrefProvider @Inject constructor(private val sharedPref: SharedPreferences) {
+ companion object {
+ const val APP_VERSION_CODE_KEY = "app_version_code"
+ }
+
fun putLong(key: String, value: Long, sync: Boolean = false) {
sharedPref.edit(sync) { putLong(key, value) }
}
fun getLong(key: String, defaultValue: Long) = sharedPref.getLong(key, defaultValue)
+ fun getString(key: String, defaultValue: String): String = sharedPref.getString(key, defaultValue) ?: defaultValue
+
+ fun putString(key: String, value: String, sync: Boolean = false) {
+ sharedPref.edit(sync) { putString(key, value) }
+ }
+
fun delete(key: String) {
sharedPref.edit().remove(key).apply()
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/AttendanceDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/AttendanceDao.kt
index d3c4f146f..3eb57473d 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/AttendanceDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/AttendanceDao.kt
@@ -1,8 +1,6 @@
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.Attendance
import io.reactivex.Maybe
@@ -11,13 +9,7 @@ import javax.inject.Singleton
@Singleton
@Dao
-interface AttendanceDao {
-
- @Insert
- fun insertAll(exams: List): List
-
- @Delete
- fun deleteAll(exams: List)
+interface AttendanceDao : BaseDao {
@Query("SELECT * FROM Attendance WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe>
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/AttendanceSummaryDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/AttendanceSummaryDao.kt
index a7413de56..fd58533f1 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/AttendanceSummaryDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/AttendanceSummaryDao.kt
@@ -1,20 +1,12 @@
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.AttendanceSummary
import io.reactivex.Maybe
@Dao
-interface AttendanceSummaryDao {
-
- @Insert
- fun insertAll(exams: List): List
-
- @Delete
- fun deleteAll(exams: List)
+interface AttendanceSummaryDao : BaseDao {
@Query("SELECT * FROM AttendanceSummary WHERE diary_id = :diaryId AND student_id = :studentId AND subject_id = :subjectId")
fun loadAll(diaryId: Int, studentId: Int, subjectId: Int): Maybe>
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/BaseDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/BaseDao.kt
new file mode 100644
index 000000000..32dbadb86
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/BaseDao.kt
@@ -0,0 +1,17 @@
+package io.github.wulkanowy.data.db.dao
+
+import androidx.room.Delete
+import androidx.room.Insert
+import androidx.room.Update
+
+interface BaseDao {
+
+ @Insert
+ fun insertAll(items: List): List
+
+ @Update
+ fun updateAll(items: List)
+
+ @Delete
+ fun deleteAll(items: List)
+}
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
index 6816ceaaf..e13e569b6 100644
--- 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
@@ -1,8 +1,6 @@
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
@@ -11,13 +9,7 @@ import javax.inject.Singleton
@Singleton
@Dao
-interface CompletedLessonsDao {
-
- @Insert
- fun insertAll(exams: List)
-
- @Delete
- fun deleteAll(exams: List)
+interface CompletedLessonsDao : BaseDao {
@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/ExamDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/ExamDao.kt
index 06cd56135..ca6b32dfc 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/ExamDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/ExamDao.kt
@@ -1,8 +1,6 @@
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.Exam
import io.reactivex.Maybe
@@ -11,13 +9,7 @@ import javax.inject.Singleton
@Singleton
@Dao
-interface ExamDao {
-
- @Insert
- fun insertAll(exams: List): List
-
- @Delete
- fun deleteAll(exams: List)
+interface ExamDao : BaseDao {
@Query("SELECT * FROM Exams WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe>
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 0bd210b02..c74d1937f 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
@@ -1,26 +1,14 @@
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.Grade
import io.reactivex.Maybe
import javax.inject.Singleton
@Singleton
@Dao
-interface GradeDao {
-
- @Insert
- fun insertAll(grades: List)
-
- @Update
- fun updateAll(grade: List)
-
- @Delete
- fun deleteAll(grades: List)
+interface GradeDao : BaseDao {
@Query("SELECT * FROM Grades WHERE semester_id = :semesterId AND student_id = :studentId")
fun loadAll(semesterId: Int, studentId: Int): Maybe>
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/GradePointsStatisticsDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/GradePointsStatisticsDao.kt
index 99a1269bd..376092865 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/GradePointsStatisticsDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/GradePointsStatisticsDao.kt
@@ -1,8 +1,6 @@
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.GradePointsStatistics
import io.reactivex.Maybe
@@ -10,13 +8,7 @@ import javax.inject.Singleton
@Singleton
@Dao
-interface GradePointsStatisticsDao {
-
- @Insert
- fun insertAll(gradesStatistics: List)
-
- @Delete
- fun deleteAll(gradesStatistics: List)
+interface GradePointsStatisticsDao : BaseDao {
@Query("SELECT * FROM GradesPointsStatistics WHERE student_id = :studentId AND semester_id = :semesterId AND subject = :subjectName")
fun loadSubject(semesterId: Int, studentId: Int, subjectName: String): 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
index 338c369fa..6faa35d0b 100644
--- 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
@@ -1,8 +1,6 @@
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
@@ -10,13 +8,7 @@ import javax.inject.Singleton
@Singleton
@Dao
-interface GradeStatisticsDao {
-
- @Insert
- fun insertAll(gradesStatistics: List)
-
- @Delete
- fun deleteAll(gradesStatistics: List)
+interface GradeStatisticsDao : BaseDao {
@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>
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 3f2e87bd0..1165ef07f 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
@@ -1,8 +1,6 @@
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.GradeSummary
import io.reactivex.Maybe
@@ -10,13 +8,7 @@ import javax.inject.Singleton
@Singleton
@Dao
-interface GradeSummaryDao {
-
- @Insert
- fun insertAll(gradesSummary: List)
-
- @Delete
- fun deleteAll(gradesSummary: List)
+interface GradeSummaryDao : BaseDao {
@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 253bdb11f..1947a0dfe 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
@@ -1,8 +1,6 @@
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.Homework
import io.reactivex.Maybe
@@ -11,13 +9,7 @@ import javax.inject.Singleton
@Singleton
@Dao
-interface HomeworkDao {
-
- @Insert
- fun insertAll(homework: List)
-
- @Delete
- fun deleteAll(homework: List)
+interface HomeworkDao : BaseDao {
@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
index afd7905c0..f16c28d9e 100644
--- 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
@@ -1,10 +1,7 @@
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
@@ -12,18 +9,8 @@ import javax.inject.Singleton
@Singleton
@Dao
-interface LuckyNumberDao {
-
- @Insert
- fun insert(luckyNumber: LuckyNumber)
-
- @Update
- fun update(luckyNumber: LuckyNumber)
-
- @Delete
- fun delete(luckyNumber: LuckyNumber)
+interface LuckyNumberDao : BaseDao {
@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 4f72c6c91..6d14ad016 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
@@ -1,24 +1,12 @@
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.Message
import io.reactivex.Maybe
@Dao
-interface MessagesDao {
-
- @Insert
- fun insertAll(messages: List)
-
- @Delete
- fun deleteAll(messages: List)
-
- @Update
- fun updateAll(messages: List)
+interface MessagesDao : BaseDao {
@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>
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/MobileDeviceDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/MobileDeviceDao.kt
index d6b97f6ad..b05b2d9cc 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/MobileDeviceDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/MobileDeviceDao.kt
@@ -1,20 +1,12 @@
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.MobileDevice
import io.reactivex.Maybe
@Dao
-interface MobileDeviceDao {
-
- @Insert
- fun insertAll(devices: List)
-
- @Delete
- fun deleteAll(devices: List)
+interface MobileDeviceDao : BaseDao {
@Query("SELECT * FROM MobileDevices WHERE student_id = :studentId ORDER BY date DESC")
fun loadAll(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 867e06a25..ea2fc6eb2 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
@@ -1,28 +1,15 @@
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.Note
import io.reactivex.Maybe
import javax.inject.Singleton
@Singleton
@Dao
-interface NoteDao {
-
- @Insert
- fun insertAll(notes: List)
-
- @Update
- fun updateAll(notes: List)
-
- @Delete
- fun deleteAll(notes: List)
+interface NoteDao : BaseDao {
@Query("SELECT * FROM Notes WHERE student_id = :studentId")
fun loadAll(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
index 7c5fd6ca6..afb941b1a 100644
--- 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
@@ -1,8 +1,6 @@
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
@@ -10,13 +8,7 @@ import javax.inject.Singleton
@Singleton
@Dao
-interface RecipientDao {
-
- @Insert
- fun insertAll(messages: List)
-
- @Delete
- fun deleteAll(messages: List)
+interface RecipientDao : BaseDao {
@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
index 1898390a9..6ddfd4941 100644
--- 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
@@ -1,8 +1,6 @@
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
@@ -10,13 +8,7 @@ import javax.inject.Singleton
@Singleton
@Dao
-interface ReportingUnitDao {
-
- @Insert
- fun insertAll(reportingUnits: List)
-
- @Delete
- fun deleteAll(reportingUnits: List)
+interface ReportingUnitDao : BaseDao {
@Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId")
fun load(studentId: Int): Maybe>
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/SchoolDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/SchoolDao.kt
index c2b2e0bcb..e9bd67557 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/SchoolDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/SchoolDao.kt
@@ -1,8 +1,6 @@
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.School
import io.reactivex.Maybe
@@ -10,13 +8,7 @@ import javax.inject.Singleton
@Singleton
@Dao
-interface SchoolDao {
-
- @Insert
- fun insert(school: School)
-
- @Delete
- fun delete(school: School)
+interface SchoolDao : BaseDao {
@Query("SELECT * FROM School WHERE student_id = :studentId AND class_id = :classId")
fun load(studentId: Int, classId: Int): Maybe
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/SemesterDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/SemesterDao.kt
index 01841fb67..654b80f38 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/SemesterDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/SemesterDao.kt
@@ -1,8 +1,6 @@
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.Semester
import io.reactivex.Maybe
@@ -10,13 +8,7 @@ import javax.inject.Singleton
@Singleton
@Dao
-interface SemesterDao {
-
- @Insert
- fun insertAll(semester: List)
-
- @Delete
- fun deleteAll(semester: List)
+interface SemesterDao : BaseDao {
@Query("SELECT * FROM Semesters WHERE student_id = :studentId AND class_id = :classId")
fun loadAll(studentId: Int, classId: Int): Maybe>
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/SubjectDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/SubjectDao.kt
index 725a371ab..525a7129a 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/SubjectDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/SubjectDao.kt
@@ -1,20 +1,12 @@
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.Subject
import io.reactivex.Maybe
@Dao
-interface SubjectDao {
-
- @Insert
- fun insertAll(subjects: List): List
-
- @Delete
- fun deleteAll(subjects: List)
+interface SubjectDao : BaseDao {
@Query("SELECT * FROM Subjects WHERE diary_id = :diaryId AND student_id = :studentId")
fun loadAll(diaryId: Int, studentId: Int): Maybe>
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/TeacherDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/TeacherDao.kt
index e7794248a..5ea237a84 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/TeacherDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/TeacherDao.kt
@@ -1,8 +1,6 @@
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.Teacher
import io.reactivex.Maybe
@@ -10,13 +8,7 @@ import javax.inject.Singleton
@Singleton
@Dao
-interface TeacherDao {
-
- @Insert
- fun insertAll(teachers: List)
-
- @Delete
- fun deleteAll(teachers: List)
+interface TeacherDao : BaseDao {
@Query("SELECT * FROM Teachers WHERE student_id = :studentId AND class_id = :classId")
fun loadAll(studentId: Int, classId: Int): Maybe>
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/TimetableDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/TimetableDao.kt
index abe213618..6b62cc82a 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/TimetableDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/TimetableDao.kt
@@ -1,8 +1,6 @@
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.Timetable
import io.reactivex.Maybe
@@ -11,13 +9,7 @@ import javax.inject.Singleton
@Singleton
@Dao
-interface TimetableDao {
-
- @Insert
- fun insertAll(exams: List): List
-
- @Delete
- fun deleteAll(exams: List)
+interface TimetableDao : BaseDao {
@Query("SELECT * FROM Timetable WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe>
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 1221a7aab..3f69c61b1 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
@@ -19,7 +19,7 @@ data class Grade(
val entry: String,
- val value: Int,
+ val value: Double,
val modifier: Double,
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 48b4fd022..93e254c3b 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
@@ -29,6 +29,8 @@ data class Message(
val subject: String,
+ var content: String,
+
val date: LocalDateTime,
@ColumnInfo(name = "folder_id")
@@ -50,6 +52,4 @@ data class Message(
@ColumnInfo(name = "is_notified")
var isNotified: Boolean = true
-
- var content: String? = null
}
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 13c5ee084..fe0283f87 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
@@ -10,10 +10,27 @@ import java.io.Serializable
@Entity(tableName = "Students", indices = [Index(value = ["email", "symbol", "student_id", "school_id", "class_id"], unique = true)])
data class Student(
- val endpoint: String,
+ @ColumnInfo(name = "scrapper_base_url")
+ val scrapperBaseUrl: String,
+ @ColumnInfo(name = "mobile_base_url")
+ val mobileBaseUrl: String,
+
+ @ColumnInfo(name = "login_type")
val loginType: String,
+ @ColumnInfo(name = "login_mode")
+ val loginMode: String,
+
+ @ColumnInfo(name = "certificate_key")
+ val certificateKey: String,
+
+ @ColumnInfo(name = "private_key")
+ val privateKey: String,
+
+ @ColumnInfo(name = "is_parent")
+ val isParent: Boolean,
+
val email: String,
var password: String,
@@ -23,6 +40,9 @@ data class Student(
@ColumnInfo(name = "student_id")
val studentId: Int,
+ @ColumnInfo(name = "user_login_id")
+ val userLoginId: Int,
+
@ColumnInfo(name = "student_name")
val studentName: String,
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration19.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration19.kt
new file mode 100644
index 000000000..d38f1245a
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration19.kt
@@ -0,0 +1,119 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+import io.github.wulkanowy.data.db.SharedPrefProvider
+
+class Migration19(private val sharedPrefProvider: SharedPrefProvider) : Migration(18, 19) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ migrateMessages(database)
+ migrateGrades(database)
+ migrateStudents(database)
+ migrateSharedPreferences()
+ }
+
+ private fun migrateMessages(database: SupportSQLiteDatabase) {
+ database.execSQL("DROP TABLE Messages")
+ database.execSQL("""
+ CREATE TABLE IF NOT EXISTS Messages (
+ id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ is_notified INTEGER 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,
+ content 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
+ )
+ """)
+ }
+
+ private fun migrateGrades(database: SupportSQLiteDatabase) {
+ database.execSQL("DROP TABLE Grades")
+ database.execSQL("""
+ CREATE TABLE IF NOT EXISTS Grades (
+ 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 REAL 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
+ )
+ """)
+ }
+
+ private fun migrateStudents(database: SupportSQLiteDatabase) {
+ database.execSQL("""
+ CREATE TABLE IF NOT EXISTS Students_tmp (
+ id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ scrapper_base_url TEXT NOT NULL,
+ mobile_base_url TEXT NOT NULL,
+ is_parent INTEGER NOT NULL,
+ login_type TEXT NOT NULL,
+ login_mode TEXT NOT NULL,
+ certificate_key TEXT NOT NULL,
+ private_key TEXT NOT NULL,
+ email TEXT NOT NULL,
+ password TEXT NOT NULL,
+ symbol TEXT NOT NULL,
+ student_id INTEGER NOT NULL,
+ user_login_id INTEGER NOT NULL,
+ student_name TEXT NOT NULL,
+ school_id TEXT NOT NULL,
+ school_name TEXT NOT NULL,
+ class_name TEXT NOT NULL,
+ class_id INTEGER NOT NULL,
+ is_current INTEGER NOT NULL,
+ registration_date INTEGER NOT NULL
+ )
+ """)
+
+ database.execSQL("ALTER TABLE Students ADD COLUMN scrapperBaseUrl TEXT NOT NULL DEFAULT \"\";")
+ database.execSQL("ALTER TABLE Students ADD COLUMN apiBaseUrl TEXT NOT NULL DEFAULT \"\";")
+ database.execSQL("ALTER TABLE Students ADD COLUMN is_parent INT NOT NULL DEFAULT 0;")
+ database.execSQL("ALTER TABLE Students ADD COLUMN loginMode TEXT NOT NULL DEFAULT \"\";")
+ database.execSQL("ALTER TABLE Students ADD COLUMN certificateKey TEXT NOT NULL DEFAULT \"\";")
+ database.execSQL("ALTER TABLE Students ADD COLUMN privateKey TEXT NOT NULL DEFAULT \"\";")
+ database.execSQL("ALTER TABLE Students ADD COLUMN user_login_id INTEGER NOT NULL DEFAULT 0;")
+
+ database.execSQL("""
+ INSERT INTO Students_tmp(
+ id, scrapper_base_url, mobile_base_url, is_parent, login_type, login_mode, certificate_key, private_key, email, password, symbol, student_id, user_login_id, student_name, school_id, school_name, school_id, school_name, class_name, class_id, is_current, registration_date)
+ SELECT
+ id, endpoint, apiBaseUrl, is_parent, loginType, "SCRAPPER", certificateKey, privateKey, email, password, symbol, student_id, user_login_id, student_name, school_id, school_name, school_id, school_name, class_name, class_id, is_current, registration_date
+ FROM Students
+ """)
+ database.execSQL("DROP TABLE Students")
+ database.execSQL("ALTER TABLE Students_tmp RENAME TO Students")
+ database.execSQL("CREATE UNIQUE INDEX index_Students_email_symbol_student_id_school_id_class_id ON Students (email, symbol, student_id, school_id, class_id)")
+ }
+
+ private fun migrateSharedPreferences() {
+ if (sharedPrefProvider.getString("grade_modifier_plus", "0.0") == "0.0") {
+ sharedPrefProvider.putString("grade_modifier_plus", "0.33")
+ }
+ if (sharedPrefProvider.getString("grade_modifier_minus", "0.0") == "0.0") {
+ sharedPrefProvider.putString("grade_modifier_minus", "0.33")
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemote.kt
index b3544c3f5..cd7702c10 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemote.kt
@@ -1,25 +1,24 @@
package io.github.wulkanowy.data.repositories.attendance
-import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.Semester
-import io.github.wulkanowy.utils.toLocalDate
+import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import org.threeten.bp.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class AttendanceRemote @Inject constructor(private val api: Api) {
+class AttendanceRemote @Inject constructor(private val sdk: Sdk) {
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { it.getAttendance(startDate, endDate) }.map { attendance ->
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).getAttendance(startDate, endDate, semester.semesterId)
+ .map { attendance ->
attendance.map {
Attendance(
studentId = semester.studentId,
diaryId = semester.diaryId,
- date = it.date.toLocalDate(),
+ date = it.date,
number = it.number,
subject = it.subject,
name = it.name,
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRemote.kt
index d38dd3a4b..c167427f7 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRemote.kt
@@ -1,18 +1,18 @@
package io.github.wulkanowy.data.repositories.attendancesummary
-import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.Semester
+import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class AttendanceSummaryRemote @Inject constructor(private val api: Api) {
+class AttendanceSummaryRemote @Inject constructor(private val sdk: Sdk) {
fun getAttendanceSummary(semester: Semester, subjectId: Int): Single> {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { api.getAttendanceSummary(subjectId) }.map { attendance ->
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).getAttendanceSummary(subjectId)
+ .map { attendance ->
attendance.map {
AttendanceSummary(
studentId = semester.studentId,
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
index 58dd5a9d1..ca680f209 100644
--- 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
@@ -1,27 +1,25 @@
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.github.wulkanowy.sdk.Sdk
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) {
+class CompletedLessonsRemote @Inject constructor(private val sdk: Sdk) {
fun getCompletedLessons(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { it.getCompletedLessons(startDate, endDate) }
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).getCompletedLessons(startDate, endDate)
.map { lessons ->
lessons.map {
it.absence
CompletedLesson(
studentId = semester.studentId,
diaryId = semester.diaryId,
- date = it.date.toLocalDate(),
+ date = it.date,
number = it.number,
subject = it.subject,
topic = it.topic,
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRemote.kt
index f6d653a61..ea7ec9441 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRemote.kt
@@ -1,26 +1,25 @@
package io.github.wulkanowy.data.repositories.exam
-import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Semester
-import io.github.wulkanowy.utils.toLocalDate
+import io.github.wulkanowy.sdk.Sdk
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) {
+class ExamRemote @Inject constructor(private val sdk: Sdk) {
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { it.getExams(startDate, endDate) }.map { exams ->
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).getExams(startDate, endDate, semester.semesterId)
+ .map { exams ->
exams.map {
Exam(
studentId = semester.studentId,
diaryId = semester.diaryId,
- date = it.date.toLocalDate(),
- entryDate = it.entryDate.toLocalDate(),
+ date = it.date,
+ entryDate = it.entryDate,
subject = it.subject,
group = it.group,
type = it.type,
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRemote.kt
index 570ab7a77..d07ac6d1c 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRemote.kt
@@ -1,35 +1,33 @@
package io.github.wulkanowy.data.repositories.grade
-import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.Semester
-import io.github.wulkanowy.utils.toLocalDate
+import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class GradeRemote @Inject constructor(private val api: Api) {
+class GradeRemote @Inject constructor(private val sdk: Sdk) {
fun getGrades(semester: Semester): Single> {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { it.getGrades(semester.semesterId) }
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).getGrades(semester.semesterId)
.map { grades ->
grades.map {
Grade(
- semesterId = semester.semesterId,
studentId = semester.studentId,
+ semesterId = semester.semesterId,
subject = it.subject,
entry = it.entry,
value = it.value,
modifier = it.modifier,
comment = it.comment,
color = it.color,
- gradeSymbol = it.symbol.orEmpty(),
- description = it.description.orEmpty(),
+ gradeSymbol = it.symbol,
+ description = it.description,
weight = it.weight,
weightValue = it.weightValue,
- date = it.date.toLocalDate(),
+ date = it.date,
teacher = it.teacher
)
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt
index 3335cfb02..2681fe058 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt
@@ -1,24 +1,23 @@
package io.github.wulkanowy.data.repositories.gradessummary
-import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.db.entities.Semester
+import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class GradeSummaryRemote @Inject constructor(private val api: Api) {
+class GradeSummaryRemote @Inject constructor(private val sdk: Sdk) {
fun getGradeSummary(semester: Semester): Single> {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { it.getGradesSummary(semester.semesterId) }
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).getGradesSummary(semester.semesterId)
.map { gradesSummary ->
gradesSummary.map {
GradeSummary(
semesterId = semester.semesterId,
studentId = semester.studentId,
- position = it.order,
+ position = 0,
subject = it.name,
predictedGrade = it.predicted,
finalGrade = it.final,
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
index 74c1f7357..f10f30369 100644
--- 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
@@ -1,39 +1,36 @@
package io.github.wulkanowy.data.repositories.gradestatistics
-import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeStatistics
import io.github.wulkanowy.data.db.entities.Semester
+import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class GradeStatisticsRemote @Inject constructor(private val api: Api) {
+class GradeStatisticsRemote @Inject constructor(private val sdk: Sdk) {
fun getGradeStatistics(semester: Semester, isSemester: Boolean): Single> {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap {
- if (isSemester) it.getGradesAnnualStatistics(semester.semesterId)
- else it.getGradesPartialStatistics(semester.semesterId)
- }
- .map { gradeStatistics ->
- gradeStatistics.map {
- GradeStatistics(
- semesterId = semester.semesterId,
- studentId = semester.studentId,
- subject = it.subject,
- grade = it.gradeValue,
- amount = it.amount ?: 0,
- semester = isSemester
- )
- }
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).let {
+ if (isSemester) it.getGradesAnnualStatistics(semester.semesterId)
+ else it.getGradesPartialStatistics(semester.semesterId)
+ }.map { gradeStatistics ->
+ gradeStatistics.map {
+ GradeStatistics(
+ semesterId = semester.semesterId,
+ studentId = semester.studentId,
+ subject = it.subject,
+ grade = it.gradeValue,
+ amount = it.amount,
+ semester = isSemester
+ )
}
+ }
}
fun getGradePointsStatistics(semester: Semester): Single> {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { it.getGradesPointsStatistics(semester.semesterId) }
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).getGradesPointsStatistics(semester.semesterId)
.map { gradePointsStatistics ->
gradePointsStatistics.map {
GradePointsStatistics(
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRemote.kt
index 681b66469..189499dbe 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRemote.kt
@@ -1,27 +1,25 @@
package io.github.wulkanowy.data.repositories.homework
-import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Homework
import io.github.wulkanowy.data.db.entities.Semester
-import io.github.wulkanowy.utils.toLocalDate
+import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import org.threeten.bp.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class HomeworkRemote @Inject constructor(private val api: Api) {
+class HomeworkRemote @Inject constructor(private val sdk: Sdk) {
fun getHomework(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { it.getHomework(startDate, endDate) }
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).getHomework(startDate, endDate)
.map { homework ->
homework.map {
Homework(
semesterId = semester.semesterId,
studentId = semester.studentId,
- date = it.date.toLocalDate(),
- entryDate = it.entryDate.toLocalDate(),
+ date = it.date,
+ entryDate = it.entryDate,
subject = it.subject,
content = it.content,
teacher = it.teacher,
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
index 115c89652..b461ca22a 100644
--- 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
@@ -12,15 +12,15 @@ import javax.inject.Singleton
class LuckyNumberLocal @Inject constructor(private val luckyNumberDb: LuckyNumberDao) {
fun saveLuckyNumber(luckyNumber: LuckyNumber) {
- luckyNumberDb.insert(luckyNumber)
+ luckyNumberDb.insertAll(listOf(luckyNumber))
}
fun updateLuckyNumber(luckyNumber: LuckyNumber) {
- luckyNumberDb.update(luckyNumber)
+ luckyNumberDb.updateAll(listOf(luckyNumber))
}
fun deleteLuckyNumber(luckyNumber: LuckyNumber) {
- luckyNumberDb.delete(luckyNumber)
+ luckyNumberDb.deleteAll(listOf(luckyNumber))
}
fun getLuckyNumber(semester: Semester, date: LocalDate): Maybe {
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
index 1b0f12b3e..75454143f 100644
--- 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
@@ -1,20 +1,18 @@
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.github.wulkanowy.sdk.Sdk
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) {
+class LuckyNumberRemote @Inject constructor(private val sdk: Sdk) {
fun getLuckyNumber(semester: Semester): Maybe {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMapMaybe { it.getLuckyNumber() }
+ return sdk.getLuckyNumber()
.map {
LuckyNumber(
studentId = semester.studentId,
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
index b2bff1e77..d27eb904d 100644
--- 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
@@ -1,24 +1,23 @@
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.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
-import io.github.wulkanowy.utils.toLocalDateTime
+import io.github.wulkanowy.sdk.Sdk
+import io.github.wulkanowy.sdk.pojo.Folder
+import io.github.wulkanowy.sdk.pojo.SentMessage
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
+import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
@Singleton
-class MessageRemote @Inject constructor(private val api: Api) {
+class MessageRemote @Inject constructor(private val sdk: Sdk) {
- fun getMessages(student: Student, folder: MessageFolder): Single> {
- return api.getMessages(Folder.valueOf(folder.name)).map { messages ->
+ fun getMessages(student: Student, semester: Semester, folder: MessageFolder): Single> {
+ return sdk.getMessages(Folder.valueOf(folder.name), semester.start.atStartOfDay(), semester.end.atStartOfDay()).map { messages ->
messages.map {
Message(
studentId = student.id.toInt(),
@@ -28,7 +27,8 @@ class MessageRemote @Inject constructor(private val api: Api) {
senderId = it.senderId ?: 0,
recipient = it.recipient.orEmpty(),
subject = it.subject.trim(),
- date = it.date?.toLocalDateTime() ?: now(),
+ date = it.date ?: now(),
+ content = it.content.orEmpty(),
folderId = it.folderId,
unread = it.unread ?: false,
unreadBy = it.unreadBy ?: 0,
@@ -40,27 +40,28 @@ class MessageRemote @Inject constructor(private val api: Api) {
}
fun getMessagesContent(message: Message, markAsRead: Boolean = false): Single {
- return api.getMessageContent(message.messageId, message.folderId, markAsRead, message.realId)
+ return sdk.getMessageContent(message.messageId, message.folderId, markAsRead, message.realId)
}
fun sendMessage(subject: String, content: String, recipients: List): Single {
- return api.sendMessage(
+ return sdk.sendMessage(
subject = subject,
content = content,
recipients = recipients.map {
- ApiRecipient(
+ SdkRecipient(
id = it.realId,
name = it.realName,
loginId = it.loginId,
reportingUnitId = it.unitId,
role = it.role,
- hash = it.hash
+ hash = it.hash,
+ shortName = it.name
)
}
)
}
fun deleteMessage(message: Message): Single {
- return api.deleteMessages(listOf(Pair(message.realId, message.folderId)))
+ return sdk.deleteMessages(listOf(Pair(message.realId, message.folderId)))
}
}
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
index c10cd5181..0dfdd72fe 100644
--- 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
@@ -2,12 +2,13 @@ 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.SdkHelper
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.Recipient
+import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED
+import io.github.wulkanowy.sdk.pojo.SentMessage
import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Completable
import io.reactivex.Maybe
@@ -21,16 +22,16 @@ class MessageRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: MessageLocal,
private val remote: MessageRemote,
- private val apiHelper: ApiHelper
+ private val sdkHelper: SdkHelper
) {
- fun getMessages(student: Student, folder: MessageFolder, forceRefresh: Boolean = false, notify: Boolean = false): Single> {
- return Single.just(apiHelper.initApi(student))
+ fun getMessages(student: Student, semester: Semester, folder: MessageFolder, forceRefresh: Boolean = false, notify: Boolean = false): Single> {
+ return Single.just(sdkHelper.init(student))
.flatMap { _ ->
local.getMessages(student, folder).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
- if (it) remote.getMessages(student, folder)
+ if (it) remote.getMessages(student, semester, folder)
else Single.error(UnknownHostException())
}.flatMap { new ->
local.getMessages(student, folder).toSingle(emptyList())
@@ -47,10 +48,10 @@ class MessageRepository @Inject constructor(
}
fun getMessage(student: Student, messageDbId: Long, markAsRead: Boolean = false): Single {
- return Single.just(apiHelper.initApi(student))
+ return Single.just(sdkHelper.init(student))
.flatMap { _ ->
local.getMessage(messageDbId)
- .filter { !it.content.isNullOrEmpty() }
+ .filter { it.content.isNotEmpty() }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) local.getMessage(messageDbId).toSingle()
@@ -60,7 +61,7 @@ class MessageRepository @Inject constructor(
remote.getMessagesContent(dbMessage, markAsRead).doOnSuccess {
local.updateMessages(listOf(dbMessage.copy(unread = false).apply {
id = dbMessage.id
- content = it
+ content = content.ifBlank { it }
}))
}
}.flatMap {
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceLocal.kt
index 8f0efa5b6..473ffa7fe 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceLocal.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceLocal.kt
@@ -3,7 +3,6 @@ package io.github.wulkanowy.data.repositories.mobiledevice
import io.github.wulkanowy.data.db.dao.MobileDeviceDao
import io.github.wulkanowy.data.db.entities.MobileDevice
import io.github.wulkanowy.data.db.entities.Semester
-import io.github.wulkanowy.data.db.entities.Student
import io.reactivex.Maybe
import javax.inject.Inject
import javax.inject.Singleton
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRemote.kt
index 86fdce97a..c43c3f21e 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRemote.kt
@@ -1,25 +1,23 @@
package io.github.wulkanowy.data.repositories.mobiledevice
-import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.MobileDevice
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.pojos.MobileDeviceToken
-import io.github.wulkanowy.utils.toLocalDateTime
+import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class MobileDeviceRemote @Inject constructor(private val api: Api) {
+class MobileDeviceRemote @Inject constructor(private val sdk: Sdk) {
fun getDevices(semester: Semester): Single> {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { api.getRegisteredDevices() }
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).getRegisteredDevices()
.map { devices ->
devices.map {
MobileDevice(
studentId = semester.studentId,
- date = it.date.toLocalDateTime(),
+ date = it.date,
deviceId = it.id,
name = it.name
)
@@ -28,13 +26,11 @@ class MobileDeviceRemote @Inject constructor(private val api: Api) {
}
fun unregisterDevice(semester: Semester, device: MobileDevice): Single {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { api.unregisterDevice(device.deviceId) }
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).unregisterDevice(device.deviceId)
}
fun getToken(semester: Semester): Single {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { api.getToken() }
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).getToken()
.map {
MobileDeviceToken(
token = it.token,
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRemote.kt
index aebc6230e..503575b69 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRemote.kt
@@ -1,24 +1,22 @@
package io.github.wulkanowy.data.repositories.note
-import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Note
import io.github.wulkanowy.data.db.entities.Semester
-import io.github.wulkanowy.utils.toLocalDate
+import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class NoteRemote @Inject constructor(private val api: Api) {
+class NoteRemote @Inject constructor(private val sdk: Sdk) {
fun getNotes(semester: Semester): Single> {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { it.getNotes() }
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).getNotes(semester.semesterId)
.map { notes ->
notes.map {
Note(
studentId = semester.studentId,
- date = it.date.toLocalDate(),
+ date = it.date,
teacher = it.teacher,
category = it.category,
content = it.content
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/preferences/PreferencesRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/preferences/PreferencesRepository.kt
index e1caf9202..07a3654ac 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/preferences/PreferencesRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/preferences/PreferencesRepository.kt
@@ -33,6 +33,10 @@ class PreferencesRepository @Inject constructor(
val gradeColorTheme: String
get() = getString(R.string.pref_key_grade_color_scheme, R.string.pref_default_grade_color_scheme)
+ val appLanguageKey = context.getString(R.string.pref_key_app_language)
+ val appLanguage
+ get() = getString(appLanguageKey, R.string.pref_default_app_language)
+
val serviceEnableKey = context.getString(R.string.pref_key_services_enable)
val isServiceEnabled: Boolean
get() = getBoolean(serviceEnableKey, R.bool.pref_default_services_enable)
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
index 6b8328ec2..9b1d4ac2f 100644
--- 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
@@ -15,7 +15,7 @@ class RecipientLocal @Inject constructor(private val recipientDb: RecipientDao)
return recipientDb.load(student.studentId, role, unit.realId).filter { !it.isEmpty() }
}
- fun saveRecipients(recipients: List) {
+ fun saveRecipients(recipients: List): List {
return recipientDb.insertAll(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
index b726edda9..f070ea765 100644
--- 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
@@ -1,34 +1,34 @@
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.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
-import io.github.wulkanowy.api.messages.Recipient as ApiRecipient
+import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
@Singleton
-class RecipientRemote @Inject constructor(private val api: Api) {
+class RecipientRemote @Inject constructor(private val sdk: Sdk) {
fun getRecipients(role: Int, unit: ReportingUnit): Single> {
- return api.getRecipients(unit.realId, role)
+ return sdk.getRecipients(unit.realId, role)
.map { recipients ->
recipients.map { it.toRecipient() }
}
}
fun getMessageRecipients(message: Message): Single> {
- return api.getMessageRecipients(message.messageId, message.senderId)
+ return sdk.getMessageRecipients(message.messageId, message.senderId)
.map { recipients ->
recipients.map { it.toRecipient() }
}
}
- private fun ApiRecipient.toRecipient(): Recipient {
+ private fun SdkRecipient.toRecipient(): Recipient {
return Recipient(
- studentId = api.studentId,
+ studentId = sdk.studentId,
realId = id,
realName = name,
name = shortName,
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
index cde75ea8b..d29369b94 100644
--- 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
@@ -2,7 +2,7 @@ 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.SdkHelper
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.ReportingUnit
@@ -18,11 +18,11 @@ class RecipientRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: RecipientLocal,
private val remote: RecipientRemote,
- private val apiHelper: ApiHelper
+ private val sdkHelper: SdkHelper
) {
fun getRecipients(student: Student, role: Int, unit: ReportingUnit, forceRefresh: Boolean = false): Single> {
- return Single.just(apiHelper.initApi(student))
+ return Single.just(sdkHelper.init(student))
.flatMap { _ ->
local.getRecipients(student, role, unit).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
@@ -43,7 +43,7 @@ class RecipientRepository @Inject constructor(
}
fun getMessageRecipients(student: Student, message: Message): Single> {
- return Single.just(apiHelper.initApi(student))
+ return Single.just(sdkHelper.init(student))
.flatMap { ReactiveNetwork.checkInternetConnectivity(settings) }
.flatMap {
if (it) remote.getMessageRecipients(message)
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
index b4281cbfd..6f9eec3fc 100644
--- 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
@@ -18,7 +18,7 @@ class ReportingUnitLocal @Inject constructor(private val reportingUnitDb: Report
return reportingUnitDb.loadOne(student.studentId, unitId)
}
- fun saveReportingUnits(reportingUnits: List) {
+ fun saveReportingUnits(reportingUnits: List): List {
return reportingUnitDb.insertAll(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
index feb4b0134..5dbabc545 100644
--- 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
@@ -1,19 +1,19 @@
package io.github.wulkanowy.data.repositories.reportingunit
-import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.ReportingUnit
+import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class ReportingUnitRemote @Inject constructor(private val api: Api) {
+class ReportingUnitRemote @Inject constructor(private val sdk: Sdk) {
fun getReportingUnits(): Single> {
- return api.getReportingUnits().map {
+ return sdk.getReportingUnits().map {
it.map { unit ->
ReportingUnit(
- studentId = api.studentId,
+ studentId = sdk.studentId,
realId = unit.id,
roles = unit.roles,
senderId = unit.senderId,
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
index 6758898e2..4c8370e68 100644
--- 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
@@ -2,7 +2,7 @@ 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.SdkHelper
import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.uniqueSubtract
@@ -17,11 +17,11 @@ class ReportingUnitRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: ReportingUnitLocal,
private val remote: ReportingUnitRemote,
- private val apiHelper: ApiHelper
+ private val sdkHelper: SdkHelper
) {
fun getReportingUnits(student: Student, forceRefresh: Boolean = false): Single> {
- return Single.just(apiHelper.initApi(student))
+ return Single.just(sdkHelper.init(student))
.flatMap { _ ->
local.getReportingUnits(student).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
@@ -40,7 +40,7 @@ class ReportingUnitRepository @Inject constructor(
}
fun getReportingUnit(student: Student, unitId: Int): Maybe {
- return Maybe.just(apiHelper.initApi(student))
+ return Maybe.just(sdkHelper.init(student))
.flatMap { _ ->
local.getReportingUnit(student, unitId)
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/school/SchoolLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/school/SchoolLocal.kt
index 1692e39b4..d87272875 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/school/SchoolLocal.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/school/SchoolLocal.kt
@@ -9,11 +9,11 @@ import javax.inject.Inject
class SchoolLocal @Inject constructor(private val schoolDb: SchoolDao) {
fun saveSchool(school: School) {
- schoolDb.insert(school)
+ schoolDb.insertAll(listOf(school))
}
fun deleteSchool(school: School) {
- schoolDb.delete(school)
+ schoolDb.deleteAll(listOf(school))
}
fun getSchool(semester: Semester): Maybe {
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/school/SchoolRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/school/SchoolRemote.kt
index 86e05f0f4..4d5c92a9e 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/school/SchoolRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/school/SchoolRemote.kt
@@ -1,16 +1,15 @@
package io.github.wulkanowy.data.repositories.school
-import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.School
import io.github.wulkanowy.data.db.entities.Semester
+import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import javax.inject.Inject
-class SchoolRemote @Inject constructor(private val api: Api) {
+class SchoolRemote @Inject constructor(private val sdk: Sdk) {
fun getSchoolInfo(semester: Semester): Single {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { it.getSchool() }
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).getSchool()
.map {
School(
studentId = semester.studentId,
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRemote.kt
index c199c16c0..55d13a765 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRemote.kt
@@ -1,35 +1,32 @@
package io.github.wulkanowy.data.repositories.semester
-import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class SemesterRemote @Inject constructor(private val api: Api) {
+class SemesterRemote @Inject constructor(private val sdk: Sdk) {
fun getSemesters(student: Student): Single> {
- return api.getSemesters().map { semesters ->
- semesters.map { semester ->
+ return sdk.getSemesters().map { semesters ->
+ semesters.map {
Semester(
studentId = student.studentId,
- diaryId = semester.diaryId,
- diaryName = semester.diaryName,
- schoolYear = semester.schoolYear,
- semesterId = semester.semesterId,
- semesterName = semester.semesterNumber,
- isCurrent = semester.current,
- start = semester.start,
- end = semester.end,
- classId = semester.classId,
- unitId = semester.unitId
+ diaryId = it.diaryId,
+ diaryName = it.diaryName,
+ schoolYear = it.schoolYear,
+ semesterId = it.semesterId,
+ semesterName = it.semesterNumber,
+ isCurrent = it.current,
+ start = it.start,
+ end = it.end,
+ classId = it.classId,
+ unitId = it.unitId
)
}
-
}
}
}
-
-
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRepository.kt
index 593014032..95fddc1b3 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRepository.kt
@@ -2,7 +2,7 @@ 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.SdkHelper
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.uniqueSubtract
@@ -18,11 +18,11 @@ class SemesterRepository @Inject constructor(
private val remote: SemesterRemote,
private val local: SemesterLocal,
private val settings: InternetObservingSettings,
- private val apiHelper: ApiHelper
+ private val sdkHelper: SdkHelper
) {
fun getSemesters(student: Student, forceRefresh: Boolean = false): Single> {
- return Maybe.just(apiHelper.initApi(student))
+ return Maybe.just(sdkHelper.init(student))
.flatMap { local.getSemesters(student).filter { !forceRefresh } }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentLocal.kt
index e6d744213..a3576ca22 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentLocal.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentLocal.kt
@@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.student
import android.content.Context
import io.github.wulkanowy.data.db.dao.StudentDao
import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.security.decrypt
import io.github.wulkanowy.utils.security.encrypt
import io.reactivex.Completable
@@ -18,17 +19,26 @@ class StudentLocal @Inject constructor(
) {
fun saveStudents(students: List): Single> {
- return Single.fromCallable { studentDb.insertAll(students.map { it.copy(password = encrypt(it.password, context)) }) }
+ return Single.fromCallable {
+ studentDb.insertAll(students.map {
+ if (Sdk.Mode.valueOf(it.loginMode) != Sdk.Mode.API) it.copy(password = encrypt(it.password, context))
+ else it
+ })
+ }
}
fun getStudents(decryptPass: Boolean): Maybe> {
return studentDb.loadAll()
.map { list -> list.map { it.apply { if (decryptPass) password = decrypt(password) } } }
- .filter { !it.isEmpty() }
+ .filter { it.isNotEmpty() }
}
fun getCurrentStudent(decryptPass: Boolean): Maybe {
- return studentDb.loadCurrent().map { it.apply { if (decryptPass) password = decrypt(password) } }
+ return studentDb.loadCurrent().map {
+ it.apply {
+ if (decryptPass && Sdk.Mode.valueOf(loginMode) != Sdk.Mode.API) password = decrypt(password)
+ }
+ }
}
fun setCurrentStudent(student: Student): Completable {
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
index 251d38344..944313082 100644
--- 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
@@ -1,34 +1,51 @@
package io.github.wulkanowy.data.repositories.student
-import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import org.threeten.bp.LocalDateTime.now
import javax.inject.Inject
import javax.inject.Singleton
+import io.github.wulkanowy.sdk.pojo.Student as SdkStudent
@Singleton
-class StudentRemote @Inject constructor(private val api: Api) {
+class StudentRemote @Inject constructor(private val sdk: Sdk) {
- 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,
- className = student.className,
- classId = student.classId,
- endpoint = endpoint,
- loginType = student.loginType.name,
- isCurrent = false,
- registrationDate = now()
- )
- }
+ private fun mapStudents(students: List, email: String, password: String): List {
+ return students.map { student ->
+ Student(
+ email = email,
+ password = password,
+ isParent = student.isParent,
+ symbol = student.symbol,
+ studentId = student.studentId,
+ userLoginId = student.userLoginId,
+ studentName = student.studentName,
+ schoolSymbol = student.schoolSymbol,
+ schoolName = student.schoolName,
+ className = student.className,
+ classId = student.classId,
+ scrapperBaseUrl = student.scrapperBaseUrl,
+ loginType = student.loginType.name,
+ isCurrent = false,
+ registrationDate = now(),
+ mobileBaseUrl = student.mobileBaseUrl,
+ privateKey = student.privateKey,
+ certificateKey = student.certificateKey,
+ loginMode = student.loginMode.name
+ )
}
}
+
+ fun getStudentsMobileApi(token: String, pin: String, symbol: String): Single> {
+ return sdk.getStudentsFromMobileApi(token, pin, symbol).map { mapStudents(it, "", "") }
+ }
+
+ fun getStudentsScrapper(email: String, password: String, scrapperBaseUrl: String, symbol: String): Single> {
+ return sdk.getStudentsFromScrapper(email, password, scrapperBaseUrl, symbol).map { mapStudents(it, email, password) }
+ }
+
+ fun getStudentsHybrid(email: String, password: String, scrapperBaseUrl: String, symbol: String): Single> {
+ return sdk.getStudentsHybrid(email, password, scrapperBaseUrl, symbol).map { mapStudents(it, email, password) }
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRepository.kt
index 5c4a60558..e06e654a9 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRepository.kt
@@ -2,7 +2,6 @@ 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.exceptions.NoCurrentStudentException
import io.reactivex.Completable
@@ -16,21 +15,32 @@ import javax.inject.Singleton
class StudentRepository @Inject constructor(
private val local: StudentLocal,
private val remote: StudentRemote,
- private val settings: InternetObservingSettings,
- private val apiHelper: ApiHelper
+ private val settings: InternetObservingSettings
) {
fun isStudentSaved(): Single = local.getStudents(false).isEmpty.map { !it }
fun isCurrentStudentSet(): Single = local.getCurrentStudent(false).isEmpty.map { !it }
- 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"))
- }
+ fun getStudentsApi(pin: String, symbol: String, token: String): Single> {
+ return ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
+ if (it) remote.getStudentsMobileApi(token, pin, symbol)
+ else Single.error(UnknownHostException("No internet connection"))
+ }
+ }
+
+ fun getStudentsScrapper(email: String, password: String, endpoint: String, symbol: String = ""): Single> {
+ return ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
+ if (it) remote.getStudentsScrapper(email, password, endpoint, symbol)
+ else Single.error(UnknownHostException("No internet connection"))
+ }
+ }
+
+ fun getStudentsHybrid(email: String, password: String, endpoint: String, symbol: String): Single> {
+ return ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
+ if (it) remote.getStudentsHybrid(email, password, endpoint, symbol)
+ else Single.error(UnknownHostException("No internet connection"))
+ }
}
fun getSavedStudents(decryptPass: Boolean = true): Single> {
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRemote.kt
index 88fbb196b..32dbb2f2e 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRemote.kt
@@ -1,25 +1,24 @@
package io.github.wulkanowy.data.repositories.subject
-import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Subject
+import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class SubjectRemote @Inject constructor(private val api: Api) {
+class SubjectRemote @Inject constructor(private val sdk: Sdk) {
fun getSubjects(semester: Semester): Single> {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { api.getSubjects() }
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).getSubjects()
.map { subjects ->
subjects.map {
Subject(
studentId = semester.studentId,
diaryId = semester.diaryId,
name = it.name,
- realId = it.value
+ realId = it.id
)
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/teacher/TeacherRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/teacher/TeacherRemote.kt
index 0ae1cdb1c..d4401bfb2 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/teacher/TeacherRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/teacher/TeacherRemote.kt
@@ -1,18 +1,17 @@
package io.github.wulkanowy.data.repositories.teacher
-import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Teacher
+import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class TeacherRemote @Inject constructor(private val api: Api) {
+class TeacherRemote @Inject constructor(private val sdk: Sdk) {
fun getTeachers(semester: Semester): Single> {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { it.getTeachers() }
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).getTeachers(semester.semesterId)
.map { teachers ->
teachers.map {
Teacher(
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemote.kt
index 77742e7b3..6036bd405 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemote.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemote.kt
@@ -1,30 +1,27 @@
package io.github.wulkanowy.data.repositories.timetable
-import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Timetable
-import io.github.wulkanowy.utils.toLocalDate
-import io.github.wulkanowy.utils.toLocalDateTime
+import io.github.wulkanowy.sdk.Sdk
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) {
+class TimetableRemote @Inject constructor(private val sdk: Sdk) {
fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> {
- return Single.just(api.apply { diaryId = semester.diaryId })
- .flatMap { it.getTimetable(startDate, endDate) }
+ return sdk.switchDiary(semester.diaryId, semester.schoolYear).getTimetable(startDate, endDate)
.map { lessons ->
lessons.map {
Timetable(
studentId = semester.studentId,
diaryId = semester.diaryId,
number = it.number,
- start = it.start.toLocalDateTime(),
- end = it.end.toLocalDateTime(),
- date = it.date.toLocalDate(),
+ start = it.start,
+ end = it.end,
+ date = it.date,
subject = it.subject,
subjectOld = it.subjectOld,
group = it.group,
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
index e10e958ec..20e183c25 100644
--- 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
@@ -36,7 +36,7 @@ class TimetableRepository @Inject constructor(
old.singleOrNull { new.start == it.start }?.let { old ->
return@map new.copy(
room = if (new.room.isEmpty()) old.room else new.room,
- teacher = if (new.teacher.isEmpty() && !new.changes) old.teacher else new.teacher
+ teacher = if (new.teacher.isEmpty() && !new.changes && !old.changes) old.teacher else new.teacher
)
}
}
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 42e50fa4e..4f5683850 100644
--- a/app/src/main/java/io/github/wulkanowy/di/AppModule.kt
+++ b/app/src/main/java/io/github/wulkanowy/di/AppModule.kt
@@ -2,6 +2,7 @@ package io.github.wulkanowy.di
import android.appwidget.AppWidgetManager
import android.content.Context
+import com.yariksoffice.lingver.Lingver
import dagger.Module
import dagger.Provides
import eu.davidea.flexibleadapter.FlexibleAdapter
@@ -32,4 +33,8 @@ internal class AppModule {
@Singleton
@Provides
fun provideAppInfo() = AppInfo()
+
+ @Singleton
+ @Provides
+ fun provideLingver() = Lingver.getInstance()
}
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
index 98fc35228..6b0469773 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/SyncManager.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/SyncManager.kt
@@ -11,6 +11,7 @@ import androidx.work.NetworkType.UNMETERED
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import io.github.wulkanowy.data.db.SharedPrefProvider
+import io.github.wulkanowy.data.db.SharedPrefProvider.Companion.APP_VERSION_CODE_KEY
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.services.sync.channels.DebugChannel
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
@@ -32,10 +33,6 @@ class SyncManager @Inject constructor(
appInfo: AppInfo
) {
- companion object {
- private const val APP_VERSION_CODE_KEY = "app_version_code"
- }
-
init {
if (now().isHolidays) stopSyncWorker()
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
index 192698999..68702d9a9 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/SyncWorker.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/SyncWorker.kt
@@ -11,10 +11,10 @@ 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.api.interceptor.FeatureDisabledException
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
import io.github.wulkanowy.data.repositories.student.StudentRepository
+import io.github.wulkanowy.sdk.exception.FeatureDisabledException
import io.github.wulkanowy.services.sync.channels.DebugChannel
import io.github.wulkanowy.services.sync.works.Work
import io.github.wulkanowy.utils.getCompatColor
@@ -78,4 +78,3 @@ class SyncWorker @AssistedInject constructor(
fun create(appContext: Context, workerParameters: WorkerParameters): ListenableWorker
}
}
-
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
index c94f3aaf2..d0890626f 100644
--- 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
@@ -30,7 +30,7 @@ class MessageWork @Inject constructor(
) : Work {
override fun create(student: Student, semester: Semester): Completable {
- return messageRepository.getMessages(student, RECEIVED, true, preferencesRepository.isNotificationsEnable)
+ return messageRepository.getMessages(student, semester, RECEIVED, true, preferencesRepository.isNotificationsEnable)
.flatMap { messageRepository.getNotNotifiedMessages(student) }
.flatMapCompletable {
if (it.isNotEmpty()) notify(it)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.kt
index f0e51e314..ee74832fd 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.kt
@@ -1,10 +1,10 @@
package io.github.wulkanowy.ui.base
import android.app.ActivityManager
-import android.os.Build.VERSION.SDK_INT
-import android.os.Build.VERSION_CODES.LOLLIPOP
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
+import android.os.Build.VERSION.SDK_INT
+import android.os.Build.VERSION_CODES.LOLLIPOP
import android.os.Bundle
import android.view.View
import android.widget.Toast
@@ -22,7 +22,8 @@ import io.github.wulkanowy.utils.FragmentLifecycleLogger
import io.github.wulkanowy.utils.getThemeAttrColor
import javax.inject.Inject
-abstract class BaseActivity> : AppCompatActivity(), BaseView, HasAndroidInjector {
+abstract class BaseActivity> : AppCompatActivity(), BaseView,
+ HasAndroidInjector {
@Inject
lateinit var androidInjector: DispatchingAndroidInjector
@@ -53,13 +54,15 @@ abstract class BaseActivity> : AppCompatActivity
override fun showError(text: String, error: Throwable) {
if (messageContainer != null) {
Snackbar.make(messageContainer!!, text, LENGTH_LONG)
- .setAction(R.string.all_details) {
- ErrorDialog.newInstance(error).show(supportFragmentManager, error.toString())
- }
+ .setAction(R.string.all_details) { showErrorDetailsDialog(error) }
.show()
} else showMessage(text)
}
+ override fun showErrorDetailsDialog(error: Throwable) {
+ ErrorDialog.newInstance(error).show(supportFragmentManager, error.toString())
+ }
+
override fun showMessage(text: String) {
if (messageContainer != null) Snackbar.make(messageContainer!!, text, LENGTH_LONG).show()
else Toast.makeText(this, text, Toast.LENGTH_LONG).show()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseDialogFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BaseDialogFragment.kt
new file mode 100644
index 000000000..fdc463714
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseDialogFragment.kt
@@ -0,0 +1,27 @@
+package io.github.wulkanowy.ui.base
+
+import android.widget.Toast
+import dagger.android.support.DaggerAppCompatDialogFragment
+
+abstract class BaseDialogFragment : DaggerAppCompatDialogFragment(), BaseView {
+
+ override fun showError(text: String, error: Throwable) {
+ showMessage(text)
+ }
+
+ override fun showMessage(text: String) {
+ Toast.makeText(context, text, Toast.LENGTH_LONG).show()
+ }
+
+ override fun showExpiredDialog() {
+ (activity as? BaseActivity<*>)?.showExpiredDialog()
+ }
+
+ override fun openClearLoginView() {
+ (activity as? BaseActivity<*>)?.openClearLoginView()
+ }
+
+ override fun showErrorDetailsDialog(error: Throwable) {
+ ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
+ }
+}
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 4b2ad053d..2f5878d0d 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,15 +13,17 @@ abstract class BaseFragment : DaggerFragment(), BaseView {
override fun showError(text: String, error: Throwable) {
if (messageContainer != null) {
Snackbar.make(messageContainer!!, text, LENGTH_LONG)
- .setAction(R.string.all_details) {
- if (isAdded) ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
- }
+ .setAction(R.string.all_details) { if (isAdded) showErrorDetailsDialog(error) }
.show()
} else {
(activity as? BaseActivity<*>)?.showError(text, error)
}
}
+ override fun showErrorDetailsDialog(error: Throwable) {
+ ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
+ }
+
override fun showMessage(text: String) {
if (messageContainer != null) {
Snackbar.make(messageContainer!!, text, LENGTH_LONG).show()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseView.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BaseView.kt
index 7681263b0..0f4df92cd 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseView.kt
@@ -9,4 +9,6 @@ interface BaseView {
fun showExpiredDialog()
fun openClearLoginView()
+
+ fun showErrorDetailsDialog(error: Throwable)
}
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 16e9a0480..ba10af6bf 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
@@ -3,11 +3,12 @@ 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.BadCredentialsException
-import io.github.wulkanowy.api.login.NotLoggedInException
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
+import io.github.wulkanowy.sdk.exception.BadCredentialsException
+import io.github.wulkanowy.sdk.exception.FeatureDisabledException
+import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
+import io.github.wulkanowy.sdk.exception.NotLoggedInException
+import io.github.wulkanowy.sdk.exception.ServiceUnavailableException
import io.github.wulkanowy.utils.security.ScramblerException
import timber.log.Timber
import java.net.SocketTimeoutException
@@ -38,6 +39,7 @@ open class ErrorHandler @Inject constructor(protected val resources: Resources,
is FeatureDisabledException -> showErrorMessage(getString(R.string.error_feature_disabled), error)
is ScramblerException, is BadCredentialsException -> onSessionExpired()
is NoCurrentStudentException -> onNoCurrentStudent()
+ is FeatureNotAvailableException -> showErrorMessage(getString(R.string.error_feature_not_available), error)
else -> showErrorMessage(getString(R.string.error_unknown), error)
}
}
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 46dc5cfe8..22276bdf9 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
@@ -47,6 +47,11 @@ class AboutFragment : BaseFragment(), AboutView, MainView.TitledView {
Triple(getString(R.string.about_feedback), getString(R.string.about_feedback_summary), getCompatDrawable(R.drawable.ic_about_feedback))
}
+ override val faqRes: Triple?
+ get() = context?.run {
+ Triple(getString(R.string.about_faq), getString(R.string.about_faq_summary), getCompatDrawable(R.drawable.ic_about_faq))
+ }
+
override val discordRes: Triple?
get() = context?.run {
Triple(getString(R.string.about_discord), getString(R.string.about_discord_summary), getCompatDrawable(R.drawable.ic_about_discord))
@@ -130,6 +135,10 @@ class AboutFragment : BaseFragment(), AboutView, MainView.TitledView {
}
}
+ override fun openFaqPage() {
+ context?.openInternetBrowser("https://wulkanowy.github.io/czesto-zadawane-pytania", ::showMessage)
+ }
+
override fun openLicenses() {
(activity as? MainActivity)?.pushView(LicenseFragment.newInstance())
}
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 5303d3619..8087c9556 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
@@ -28,10 +28,15 @@ class AboutPresenter @Inject constructor(
view?.run {
when (item.title) {
feedbackRes?.first -> {
- Timber.i("Opening email client ")
+ Timber.i("Opening email client")
openEmailClient()
analytics.logEvent("about_open", "name" to "feedback")
}
+ faqRes?.first -> {
+ Timber.i("Opening faq page")
+ openFaqPage()
+ analytics.logEvent("about_open", "name" to "faq")
+ }
discordRes?.first -> {
Timber.i("Opening discord")
openDiscordInvite()
@@ -61,6 +66,7 @@ class AboutPresenter @Inject constructor(
updateData(AboutScrollableHeader(), listOfNotNull(
versionRes?.let { (title, summary, image) -> AboutItem(title, summary, image) },
feedbackRes?.let { (title, summary, image) -> AboutItem(title, summary, image) },
+ faqRes?.let { (title, summary, image) -> AboutItem(title, summary, image) },
discordRes?.let { (title, summary, image) -> AboutItem(title, summary, image) },
homepageRes?.let { (title, summary, image) -> AboutItem(title, summary, image) },
licensesRes?.let { (title, summary, image) -> AboutItem(title, summary, image) },
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 318a75e4a..34850bae4 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
@@ -9,6 +9,8 @@ interface AboutView : BaseView {
val feedbackRes: Triple?
+ val faqRes: Triple?
+
val discordRes: Triple?
val homepageRes: Triple?
@@ -25,6 +27,8 @@ interface AboutView : BaseView {
fun openEmailClient()
+ fun openFaqPage()
+
fun openHomepage()
fun openLicenses()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountDialog.kt
index f23a1eb52..cfff31c98 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountDialog.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountDialog.kt
@@ -7,18 +7,17 @@ import android.view.ViewGroup
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
import androidx.appcompat.app.AlertDialog
-import dagger.android.support.DaggerAppCompatDialogFragment
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.ui.base.BaseActivity
+import io.github.wulkanowy.ui.base.BaseDialogFragment
import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.utils.setOnItemClickListener
import kotlinx.android.synthetic.main.dialog_account.*
import javax.inject.Inject
-class AccountDialog : DaggerAppCompatDialogFragment(), AccountView {
+class AccountDialog : BaseDialogFragment(), AccountView {
@Inject
lateinit var presenter: AccountPresenter
@@ -77,14 +76,6 @@ class AccountDialog : DaggerAppCompatDialogFragment(), AccountView {
}
}
- override fun showExpiredDialog() {
- (activity as? BaseActivity<*>)?.showExpiredDialog()
- }
-
- override fun openClearLoginView() {
- (activity as? BaseActivity<*>)?.openClearLoginView()
- }
-
override fun showConfirmDialog() {
context?.let {
AlertDialog.Builder(it)
@@ -105,4 +96,3 @@ class AccountDialog : DaggerAppCompatDialogFragment(), AccountView {
super.onDestroy()
}
}
-
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 fb6309f7e..bc7c1cacd 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
@@ -6,7 +6,11 @@ import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
+import android.view.View.GONE
+import android.view.View.INVISIBLE
+import android.view.View.VISIBLE
import android.view.ViewGroup
+import com.wdullaer.materialdatetimepicker.date.DatePickerDialog
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.common.FlexibleItemDecoration
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
@@ -17,9 +21,11 @@ import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.attendance.summary.AttendanceSummaryFragment
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainView
+import io.github.wulkanowy.utils.SchooldaysRangeLimiter
import io.github.wulkanowy.utils.dpToPx
import io.github.wulkanowy.utils.setOnItemClickListener
import kotlinx.android.synthetic.main.fragment_attendance.*
+import org.threeten.bp.LocalDate
import javax.inject.Inject
class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MainChildView,
@@ -70,7 +76,11 @@ class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MainChildVie
}
attendanceSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
+ attendanceErrorRetry.setOnClickListener { presenter.onRetry() }
+ attendanceErrorDetails.setOnClickListener { presenter.onDetailsClick() }
+
attendancePreviousButton.setOnClickListener { presenter.onPreviousDay() }
+ attendanceNavDate.setOnClickListener { presenter.onPickDate() }
attendanceNextButton.setOnClickListener { presenter.onNextDay() }
attendanceNavContainer.setElevationCompat(requireContext().dpToPx(8f))
@@ -110,11 +120,19 @@ class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MainChildVie
}
override fun showEmpty(show: Boolean) {
- attendanceEmpty.visibility = if (show) View.VISIBLE else View.GONE
+ attendanceEmpty.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun showErrorView(show: Boolean) {
+ attendanceError.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun setErrorDetails(message: String) {
+ attendanceErrorMessage.text = message
}
override fun showProgress(show: Boolean) {
- attendanceProgress.visibility = if (show) View.VISIBLE else View.GONE
+ attendanceProgress.visibility = if (show) VISIBLE else GONE
}
override fun enableSwipe(enable: Boolean) {
@@ -122,7 +140,7 @@ class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MainChildVie
}
override fun showContent(show: Boolean) {
- attendanceRecycler.visibility = if (show) View.VISIBLE else View.GONE
+ attendanceRecycler.visibility = if (show) VISIBLE else GONE
}
override fun hideRefresh() {
@@ -130,17 +148,32 @@ class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MainChildVie
}
override fun showPreButton(show: Boolean) {
- attendancePreviousButton.visibility = if (show) View.VISIBLE else View.INVISIBLE
+ attendancePreviousButton.visibility = if (show) VISIBLE else INVISIBLE
}
override fun showNextButton(show: Boolean) {
- attendanceNextButton.visibility = if (show) View.VISIBLE else View.INVISIBLE
+ attendanceNextButton.visibility = if (show) VISIBLE else INVISIBLE
}
override fun showAttendanceDialog(lesson: Attendance) {
(activity as? MainActivity)?.showDialogFragment(AttendanceDialog.newInstance(lesson))
}
+ override fun showDatePickerDialog(currentDate: LocalDate) {
+ val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
+ presenter.onDateSet(year, month + 1, dayOfMonth)
+ }
+ val datePickerDialog = DatePickerDialog.newInstance(dateSetListener,
+ currentDate.year, currentDate.monthValue - 1, currentDate.dayOfMonth)
+
+ with(datePickerDialog) {
+ setDateRangeLimiter(SchooldaysRangeLimiter())
+ version = DatePickerDialog.Version.VERSION_2
+ scrollOrientation = DatePickerDialog.ScrollOrientation.VERTICAL
+ show(this@AttendanceFragment.parentFragmentManager, null)
+ }
+ }
+
override fun openSummaryView() {
(activity as? MainActivity)?.pushView(AttendanceSummaryFragment.newInstance())
}
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 b8114208a..1490ee6e3 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
@@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.attendance
+import android.annotation.SuppressLint
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.data.repositories.attendance.AttendanceRepository
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
@@ -37,10 +38,13 @@ class AttendancePresenter @Inject constructor(
lateinit var currentDate: LocalDate
private set
+ private lateinit var lastError: Throwable
+
fun onAttachView(view: AttendanceView, date: Long?) {
super.onAttachView(view)
view.initView()
Timber.i("Attendance view was initialized")
+ errorHandler.showErrorMessage = ::showErrorViewOnError
loadData(ofEpochDay(date ?: baseDate.toEpochDay()))
if (currentDate.isHolidays) setBaseDateOnHolidays()
reloadView()
@@ -56,11 +60,32 @@ class AttendancePresenter @Inject constructor(
reloadView()
}
+ fun onPickDate() {
+ view?.showDatePickerDialog(currentDate)
+ }
+
+ fun onDateSet(year: Int, month: Int, day: Int) {
+ loadData(LocalDate.of(year, month, day))
+ reloadView()
+ }
+
fun onSwipeRefresh() {
Timber.i("Force refreshing the attendance")
loadData(currentDate, true)
}
+ fun onRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
+ loadData(currentDate, true)
+ }
+
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
+
fun onViewReselected() {
Timber.i("Attendance view is reselected")
view?.also { view ->
@@ -130,18 +155,29 @@ class AttendancePresenter @Inject constructor(
view?.apply {
updateData(it)
showEmpty(it.isEmpty())
+ showErrorView(false)
showContent(it.isNotEmpty())
}
analytics.logEvent("load_attendance", "items" to it.size, "force_refresh" to forceRefresh)
}) {
Timber.i("Loading attendance result: An exception occurred")
- view?.run { showEmpty(isViewEmpty) }
errorHandler.dispatch(it)
}
)
}
}
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ view?.run {
+ if (isViewEmpty) {
+ lastError = error
+ setErrorDetails(message)
+ showErrorView(true)
+ showEmpty(false)
+ } else showError(message, error)
+ }
+ }
+
private fun reloadView() {
Timber.i("Reload attendance view with the date ${currentDate.toFormattedString()}")
view?.apply {
@@ -149,11 +185,13 @@ class AttendancePresenter @Inject constructor(
enableSwipe(false)
showContent(false)
showEmpty(false)
+ showErrorView(false)
clearData()
reloadNavigation()
}
}
+ @SuppressLint("DefaultLocale")
private fun reloadNavigation() {
view?.apply {
showPreButton(!currentDate.minusDays(1).isHolidays)
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 04fe94a48..a6d0d4ba9 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
@@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.attendance
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.ui.base.BaseView
+import org.threeten.bp.LocalDate
interface AttendanceView : BaseView {
@@ -23,6 +24,10 @@ interface AttendanceView : BaseView {
fun showEmpty(show: Boolean)
+ fun showErrorView(show: Boolean)
+
+ fun setErrorDetails(message: String)
+
fun showProgress(show: Boolean)
fun enableSwipe(enable: Boolean)
@@ -35,6 +40,8 @@ interface AttendanceView : BaseView {
fun showAttendanceDialog(lesson: Attendance)
+ fun showDatePickerDialog(currentDate: LocalDate)
+
fun openSummaryView()
fun popView()
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 4fe490d5e..fc3601847 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
@@ -57,6 +57,8 @@ class AttendanceSummaryFragment : BaseFragment(), AttendanceSummaryView, MainVie
}
attendanceSummarySwipe.setOnRefreshListener(presenter::onSwipeRefresh)
+ attendanceSummaryErrorRetry.setOnClickListener { presenter.onRetry() }
+ attendanceSummaryErrorDetails.setOnClickListener { presenter.onDetailsClick() }
subjectsAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, mutableListOf())
subjectsAdapter.setDropDownViewResource(R.layout.item_attendance_summary_subject)
@@ -93,6 +95,14 @@ class AttendanceSummaryFragment : BaseFragment(), AttendanceSummaryView, MainVie
attendanceSummaryEmpty.visibility = if (show) VISIBLE else GONE
}
+ override fun showErrorView(show: Boolean) {
+ attendanceSummaryError.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun setErrorDetails(message: String) {
+ attendanceSummaryErrorMessage.text = message
+ }
+
override fun showProgress(show: Boolean) {
attendanceSummaryProgress.visibility = if (show) VISIBLE else GONE
}
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 403392996..3ce85d815 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
@@ -33,10 +33,13 @@ class AttendanceSummaryPresenter @Inject constructor(
var currentSubjectId = -1
private set
+ private lateinit var lastError: Throwable
+
fun onAttachView(view: AttendanceSummaryView, subjectId: Int?) {
super.onAttachView(view)
view.initView()
Timber.i("Attendance summary view was initialized with subject id ${subjectId ?: -1}")
+ errorHandler.showErrorMessage = ::showErrorViewOnError
loadData(subjectId ?: -1)
loadSubjects()
}
@@ -46,12 +49,26 @@ class AttendanceSummaryPresenter @Inject constructor(
loadData(currentSubjectId, true)
}
+ fun onRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
+ loadData(currentSubjectId, true)
+ }
+
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
+
fun onSubjectSelected(name: String?) {
Timber.i("Select attendance summary subject $name")
view?.run {
showContent(false)
showProgress(true)
enableSwipe(false)
+ showEmpty(false)
+ showErrorView(false)
clearView()
}
(subjects.singleOrNull { it.name == name }?.realId ?: -1).let {
@@ -88,13 +105,23 @@ class AttendanceSummaryPresenter @Inject constructor(
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)
}
)
}
}
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ view?.run {
+ if (isViewEmpty) {
+ lastError = error
+ setErrorDetails(message)
+ showErrorView(true)
+ showEmpty(false)
+ } else showError(message, error)
+ }
+ }
+
private fun loadSubjects() {
Timber.i("Loading attendance summary subjects started")
disposable.add(studentRepository.getCurrentStudent()
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 50f03e20a..b86f6590d 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
@@ -18,6 +18,10 @@ interface AttendanceSummaryView : BaseView {
fun showEmpty(show: Boolean)
+ fun showErrorView(show: Boolean)
+
+ fun setErrorDetails(message: String)
+
fun updateDataSet(data: List, header: AttendanceSummaryScrollableHeader)
fun updateSubjects(data: ArrayList)
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 c762fa154..b880f4650 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
@@ -61,6 +61,9 @@ class ExamFragment : BaseFragment(), ExamView, MainView.MainChildView, MainView.
}
examSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
+ examErrorRetry.setOnClickListener { presenter.onRetry() }
+ examErrorDetails.setOnClickListener { presenter.onDetailsClick() }
+
examPreviousButton.setOnClickListener { presenter.onPreviousWeek() }
examNextButton.setOnClickListener { presenter.onNextWeek() }
@@ -95,6 +98,14 @@ class ExamFragment : BaseFragment(), ExamView, MainView.MainChildView, MainView.
examEmpty.visibility = if (show) VISIBLE else GONE
}
+ override fun showErrorView(show: Boolean) {
+ examError.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun setErrorDetails(message: String) {
+ examErrorMessage.text = message
+ }
+
override fun showProgress(show: Boolean) {
examProgress.visibility = if (show) VISIBLE else GONE
}
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 93109922c..35cf5b945 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
@@ -36,10 +36,13 @@ class ExamPresenter @Inject constructor(
lateinit var currentDate: LocalDate
private set
+ private lateinit var lastError: Throwable
+
fun onAttachView(view: ExamView, date: Long?) {
super.onAttachView(view)
view.initView()
Timber.i("Exam view was initialized")
+ errorHandler.showErrorMessage = ::showErrorViewOnError
loadData(ofEpochDay(date ?: baseDate.toEpochDay()))
if (currentDate.isHolidays) setBaseDateOnHolidays()
reloadView()
@@ -60,6 +63,18 @@ class ExamPresenter @Inject constructor(
loadData(currentDate, true)
}
+ fun onRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
+ loadData(currentDate, true)
+ }
+
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
+
fun onExamItemSelected(item: AbstractFlexibleItem<*>?) {
if (item is ExamItem) {
Timber.i("Select exam item ${item.exam.id}")
@@ -116,17 +131,28 @@ class ExamPresenter @Inject constructor(
view?.apply {
updateData(it)
showEmpty(it.isEmpty())
+ showErrorView(false)
showContent(it.isNotEmpty())
}
analytics.logEvent("load_exam", "items" to it.size, "force_refresh" to forceRefresh)
}) {
Timber.i("Loading exam result: An exception occurred")
- view?.run { showEmpty(isViewEmpty) }
errorHandler.dispatch(it)
})
}
}
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ view?.run {
+ if (isViewEmpty) {
+ lastError = error
+ setErrorDetails(message)
+ showErrorView(true)
+ showEmpty(false)
+ } else showError(message, error)
+ }
+ }
+
private fun createExamItems(items: Map>): List {
return items.flatMap {
ExamHeader(it.key).let { header ->
@@ -142,6 +168,7 @@ class ExamPresenter @Inject constructor(
enableSwipe(false)
showContent(false)
showEmpty(false)
+ showErrorView(false)
clearData()
reloadNavigation()
}
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 888cb05e5..5f4a74306 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
@@ -21,6 +21,10 @@ interface ExamView : BaseView {
fun showEmpty(show: Boolean)
+ fun showErrorView(show: Boolean)
+
+ fun setErrorDetails(message: String)
+
fun showProgress(show: Boolean)
fun enableSwipe(enable: Boolean)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt
index 3f794ff1f..88635c37b 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt
@@ -5,6 +5,7 @@ import io.github.wulkanowy.data.db.entities.Student
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.sdk.Sdk
import io.github.wulkanowy.utils.calcAverage
import io.github.wulkanowy.utils.changeModifier
import io.reactivex.Maybe
@@ -40,7 +41,7 @@ class GradeAverageProvider @Inject constructor(
.map { secondGrades -> secondGrades + firstGrades }
}
}.map { grades ->
- grades.map { it.changeModifier(plusModifier, minusModifier) }
+ grades.map { if (student.loginMode == Sdk.Mode.SCRAPPER.name) it.changeModifier(plusModifier, minusModifier) else it }
.groupBy { it.subject }
.mapValues { it.value.calcAverage() }
})
@@ -54,7 +55,7 @@ class GradeAverageProvider @Inject constructor(
return getAverageFromGradeSummary(selectedSemester, forceRefresh)
.switchIfEmpty(gradeRepository.getGrades(student, selectedSemester, forceRefresh)
.map { grades ->
- grades.map { it.changeModifier(plusModifier, minusModifier) }
+ grades.map { if (student.loginMode == Sdk.Mode.SCRAPPER.name) it.changeModifier(plusModifier, minusModifier) else it }
.groupBy { it.subject }
.mapValues { it.value.calcAverage() }
})
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 68ae57eca..e8d970010 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
@@ -83,7 +83,8 @@ class GradeFragment : BaseFragment(), GradeView, MainView.MainChildView, MainVie
setElevationCompat(context.dpToPx(4f))
}
- gradeSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
+ gradeErrorRetry.setOnClickListener { presenter.onRetry() }
+ gradeErrorDetails.setOnClickListener { presenter.onDetailsClick() }
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
@@ -104,22 +105,18 @@ class GradeFragment : BaseFragment(), GradeView, MainView.MainChildView, MainVie
gradeProgress.visibility = if (show) VISIBLE else INVISIBLE
}
- override fun showEmpty(show: Boolean) {
- gradeEmpty.visibility = if (show) VISIBLE else INVISIBLE
+ override fun showErrorView(show: Boolean) {
+ gradeError.visibility = if (show) VISIBLE else INVISIBLE
}
- override fun showRefresh(show: Boolean) {
- gradeSwipe.isRefreshing = show
+ override fun setErrorDetails(message: String) {
+ gradeErrorMessage.text = message
}
override fun showSemesterSwitch(show: Boolean) {
semesterSwitchMenu?.isVisible = show
}
- override fun enableSwipe(enable: Boolean) {
- gradeSwipe.isEnabled = enable
- }
-
override fun showSemesterDialog(selectedIndex: Int) {
val choices = arrayOf(
getString(R.string.grade_semester, 1),
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 2ee69480c..d8c202381 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
@@ -25,14 +25,14 @@ class GradePresenter @Inject constructor(
private val loadedSemesterId = mutableMapOf()
+ private lateinit var lastError: Throwable
+
fun onAttachView(view: GradeView, savedIndex: Int?) {
super.onAttachView(view)
selectedIndex = savedIndex ?: 0
- view.run {
- initView()
- enableSwipe(false)
- }
+ view.initView()
Timber.i("Grade view was initialized with $selectedIndex index")
+ errorHandler.showErrorMessage = ::showErrorViewOnError
loadData()
}
@@ -71,7 +71,7 @@ class GradePresenter @Inject constructor(
view?.apply {
showContent(true)
showProgress(false)
- showEmpty(false)
+ showErrorView(false)
loadedSemesterId[currentPageIndex] = semesterId
}
}
@@ -80,10 +80,18 @@ class GradePresenter @Inject constructor(
if (semesters.isNotEmpty()) loadChild(index)
}
- fun onSwipeRefresh() {
+ fun onRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
loadData()
}
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
+
private fun loadData() {
Timber.i("Loading grade data started")
disposable.add(studentRepository.getCurrentStudent()
@@ -96,25 +104,28 @@ class GradePresenter @Inject constructor(
}
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
- .doFinally { view?.showRefresh(false) }
+ .doFinally { view?.showProgress(false) }
.subscribe({
view?.run {
Timber.i("Loading grade result: Attempt load index $currentPageIndex")
loadChild(currentPageIndex)
- enableSwipe(false)
+ showErrorView(false)
showSemesterSwitch(true)
}
}) {
Timber.i("Loading grade result: An exception occurred")
errorHandler.dispatch(it)
- view?.run {
- showProgress(false)
- showEmpty(true)
- enableSwipe(true)
- }
})
}
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ lastError = error
+ view?.run {
+ showErrorView(true)
+ setErrorDetails(message)
+ }
+ }
+
private fun loadChild(index: Int, forceRefresh: Boolean = false) {
semesters.first { it.semesterName == selectedIndex }.semesterId.also {
if (forceRefresh || loadedSemesterId[index] != it) {
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 a37e6d67f..bbdbc32ea 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,16 +12,14 @@ interface GradeView : BaseView {
fun showProgress(show: Boolean)
- fun showEmpty(show: Boolean)
+ fun showErrorView(show: Boolean)
- fun showRefresh(show: Boolean)
+ fun setErrorDetails(message: String)
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/GradeDetailsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt
index 8993760d6..195ae11df 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
@@ -90,6 +90,8 @@ class GradeDetailsFragment : BaseFragment(), GradeDetailsView, GradeView.GradeCh
)
}
gradeDetailsSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
+ gradeDetailsErrorRetry.setOnClickListener { presenter.onRetry() }
+ gradeDetailsErrorDetails.setOnClickListener { presenter.onDetailsClick() }
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
@@ -141,6 +143,14 @@ class GradeDetailsFragment : BaseFragment(), GradeDetailsView, GradeView.GradeCh
gradeDetailsEmpty.visibility = if (show) VISIBLE else INVISIBLE
}
+ override fun showErrorView(show: Boolean) {
+ gradeDetailsError.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun setErrorDetails(message: String) {
+ gradeDetailsErrorMessage.text = message
+ }
+
override fun showRefresh(show: Boolean) {
gradeDetailsSwipe.isRefreshing = show
}
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 e5f6e8249..9ed412808 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
+ if (newGrades > 0) gradeHeaderNote.text = newGrades.toString(10)
gradeHeaderContainer.isEnabled = isExpandable
isViewExpandable = isExpandable
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 96b556864..647047c69 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
@@ -1,6 +1,5 @@
package io.github.wulkanowy.ui.modules.grade.details
-import android.widget.Toast
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.repositories.grade.GradeRepository
@@ -31,9 +30,12 @@ class GradeDetailsPresenter @Inject constructor(
private var currentSemesterId = 0
+ private lateinit var lastError: Throwable
+
override fun onAttachView(view: GradeDetailsView) {
super.onAttachView(view)
view.initView()
+ errorHandler.showErrorMessage = ::showErrorViewOnError
}
fun onParentViewLoadData(semesterId: Int, forceRefresh: Boolean) {
@@ -90,6 +92,18 @@ class GradeDetailsPresenter @Inject constructor(
view?.notifyParentRefresh()
}
+ fun onRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
+ view?.notifyParentRefresh()
+ }
+
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
+
fun onParentViewReselected() {
view?.run {
if (!isViewEmpty) {
@@ -140,21 +154,32 @@ class GradeDetailsPresenter @Inject constructor(
}
.subscribe({
Timber.i("Loading grade details result: Success")
- newGradesAmount = it.sumBy { gradeDetailsHeader -> gradeDetailsHeader.newGrades }
+ newGradesAmount = it.sumBy { gradeDetailsHeader -> gradeDetailsHeader.newGrades }
updateMarkAsDoneButton()
view?.run {
showEmpty(it.isEmpty())
+ showErrorView(false)
showContent(it.isNotEmpty())
updateData(it)
}
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)
})
}
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ view?.run {
+ if (isViewEmpty) {
+ lastError = error
+ setErrorDetails(message)
+ showErrorView(true)
+ showEmpty(false)
+ } else showError(message, error)
+ }
+ }
+
private fun createGradeItems(items: Map>, averages: Map): List {
val isGradeExpandable = preferencesRepository.isGradeExpandable
val gradeColorTheme = preferencesRepository.gradeColorTheme
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 fb806351c..dad4ac6eb 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
@@ -38,6 +38,10 @@ interface GradeDetailsView : BaseView {
fun showProgress(show: Boolean)
+ fun showErrorView(show: Boolean)
+
+ fun setErrorDetails(message: String)
+
fun enableSwipe(enable: Boolean)
fun showRefresh(show: Boolean)
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
index 94b5f474b..a65cab9c9 100644
--- 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
@@ -47,6 +47,13 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
override val isBarViewEmpty get() = gradeStatisticsChartPoints.isEmpty
+ override val currentType
+ get() = when (gradeStatisticsTypeSwitch.checkedRadioButtonId) {
+ R.id.gradeStatisticsTypeSemester -> ViewType.SEMESTER
+ R.id.gradeStatisticsTypePartial -> ViewType.PARTIAL
+ else -> ViewType.POINTS
+ }
+
private lateinit var gradeColors: List>
private val vulcanGradeColors = listOf(
@@ -111,9 +118,11 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
setOnItemSelectedListener { presenter.onSubjectSelected(it?.text?.toString()) }
}
- gradeStatisticsSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
-
gradeStatisticsSubjectsContainer.setElevationCompat(requireContext().dpToPx(1f))
+
+ gradeStatisticsSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
+ gradeStatisticsErrorRetry.setOnClickListener { presenter.onRetry() }
+ gradeStatisticsErrorDetails.setOnClickListener { presenter.onDetailsClick() }
}
override fun updateSubjects(data: ArrayList) {
@@ -228,6 +237,14 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
gradeStatisticsEmpty.visibility = if (show) View.VISIBLE else View.INVISIBLE
}
+ override fun showErrorView(show: Boolean) {
+ gradeStatisticsError.visibility = if (show) View.VISIBLE else View.GONE
+ }
+
+ override fun setErrorDetails(message: String) {
+ gradeStatisticsErrorMessage.text = message
+ }
+
override fun showProgress(show: Boolean) {
gradeStatisticsProgress.visibility = if (show) View.VISIBLE else View.GONE
}
@@ -262,13 +279,7 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
override fun onResume() {
super.onResume()
- gradeStatisticsTypeSwitch.setOnCheckedChangeListener { _, checkedId ->
- presenter.onTypeChange(when (checkedId) {
- R.id.gradeStatisticsTypeSemester -> ViewType.SEMESTER
- R.id.gradeStatisticsTypePartial -> ViewType.PARTIAL
- else -> ViewType.POINTS
- })
- }
+ gradeStatisticsTypeSwitch.setOnCheckedChangeListener { _, _ -> presenter.onTypeChange() }
}
override fun onSaveInstanceState(outState: Bundle) {
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
index 1e0537016..bea70ea42 100644
--- 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
@@ -30,6 +30,8 @@ class GradeStatisticsPresenter @Inject constructor(
private var currentSubjectName: String = "Wszystkie"
+ private lateinit var lastError: Throwable
+
var currentType: ViewType = ViewType.PARTIAL
private set
@@ -37,6 +39,7 @@ class GradeStatisticsPresenter @Inject constructor(
super.onAttachView(view)
currentType = type ?: ViewType.PARTIAL
view.initView()
+ errorHandler.showErrorMessage = ::showErrorViewOnError
}
fun onParentViewLoadData(semesterId: Int, forceRefresh: Boolean) {
@@ -51,6 +54,7 @@ class GradeStatisticsPresenter @Inject constructor(
enableSwipe(false)
showRefresh(false)
showBarContent(false)
+ showErrorView(false)
showEmpty(false)
clearView()
}
@@ -62,6 +66,18 @@ class GradeStatisticsPresenter @Inject constructor(
view?.notifyParentRefresh()
}
+ fun onRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
+ view?.notifyParentRefresh()
+ }
+
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
+
fun onSubjectSelected(name: String?) {
Timber.i("Select grade stats subject $name")
view?.run {
@@ -70,6 +86,7 @@ class GradeStatisticsPresenter @Inject constructor(
showProgress(true)
enableSwipe(false)
showEmpty(false)
+ showErrorView(false)
clearView()
}
(subjects.singleOrNull { it.name == name }?.name)?.let {
@@ -77,7 +94,8 @@ class GradeStatisticsPresenter @Inject constructor(
}
}
- fun onTypeChange(type: ViewType) {
+ fun onTypeChange() {
+ val type = view?.let { it.currentType } ?: ViewType.POINTS
Timber.i("Select grade stats semester: $type")
disposable.clear()
view?.run {
@@ -86,6 +104,7 @@ class GradeStatisticsPresenter @Inject constructor(
showProgress(true)
enableSwipe(false)
showEmpty(false)
+ showErrorView(false)
clearView()
}
loadDataByType(currentSemesterId, currentSubjectName, type)
@@ -146,12 +165,12 @@ class GradeStatisticsPresenter @Inject constructor(
showEmpty(it.isEmpty())
showBarContent(false)
showPieContent(it.isNotEmpty())
+ showErrorView(false)
updatePieData(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(isPieViewEmpty) }
errorHandler.dispatch(it)
})
}
@@ -177,12 +196,12 @@ class GradeStatisticsPresenter @Inject constructor(
showEmpty(false)
showPieContent(false)
showBarContent(true)
+ showErrorView(false)
updateBarData(it)
}
analytics.logEvent("load_grade_points_statistics", "force_refresh" to forceRefresh)
}, {
Timber.e("Loading grade points stats result: An exception occurred")
- view?.run { showEmpty(isBarViewEmpty) }
errorHandler.dispatch(it)
}, {
Timber.d("Loading grade points stats result: No point stats found")
@@ -193,4 +212,15 @@ class GradeStatisticsPresenter @Inject constructor(
})
)
}
+
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ view?.run {
+ if ((isBarViewEmpty && currentType == ViewType.POINTS) || (isPieViewEmpty) && currentType != ViewType.POINTS) {
+ lastError = error
+ setErrorDetails(message)
+ showErrorView(true)
+ showEmpty(false)
+ } else showError(message, error)
+ }
+ }
}
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
index d6e66fac3..003520fbd 100644
--- 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
@@ -10,6 +10,8 @@ interface GradeStatisticsView : BaseView {
val isBarViewEmpty: Boolean
+ val currentType: ViewType
+
fun initView()
fun updateSubjects(data: ArrayList)
@@ -32,6 +34,10 @@ interface GradeStatisticsView : BaseView {
fun showEmpty(show: Boolean)
+ fun showErrorView(show: Boolean)
+
+ fun setErrorDetails(message: String)
+
fun showProgress(show: Boolean)
fun enableSwipe(enable: 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 7699a6411..05fde5227 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
@@ -56,6 +56,8 @@ class GradeSummaryFragment : BaseFragment(), GradeSummaryView, GradeView.GradeCh
adapter = gradeSummaryAdapter
}
gradeSummarySwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
+ gradeSummaryErrorRetry.setOnClickListener { presenter.onRetry() }
+ gradeSummaryErrorDetails.setOnClickListener { presenter.onDetailsClick() }
}
override fun updateData(data: List, header: GradeSummaryScrollableHeader) {
@@ -82,6 +84,14 @@ class GradeSummaryFragment : BaseFragment(), GradeSummaryView, GradeView.GradeCh
gradeSummaryEmpty.visibility = if (show) VISIBLE else INVISIBLE
}
+ override fun showErrorView(show: Boolean) {
+ gradeSummaryError.visibility = if (show) VISIBLE else INVISIBLE
+ }
+
+ override fun setErrorDetails(message: String) {
+ gradeSummaryErrorMessage.text = message
+ }
+
override fun showProgress(show: Boolean) {
gradeSummaryProgress.visibility = if (show) VISIBLE else GONE
}
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 3f8fd0edb..1aaa9d097 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
@@ -25,9 +25,12 @@ class GradeSummaryPresenter @Inject constructor(
private val analytics: FirebaseAnalyticsHelper
) : BasePresenter(errorHandler, studentRepository, schedulers) {
+ private lateinit var lastError: Throwable
+
override fun onAttachView(view: GradeSummaryView) {
super.onAttachView(view)
view.initView()
+ errorHandler.showErrorMessage = ::showErrorViewOnError
}
fun onParentViewLoadData(semesterId: Int, forceRefresh: Boolean) {
@@ -56,21 +59,44 @@ class GradeSummaryPresenter @Inject constructor(
view?.run {
showEmpty(gradeSummaryItems.isEmpty())
showContent(gradeSummaryItems.isNotEmpty())
+ showErrorView(false)
updateData(gradeSummaryItems, gradeSummaryHeader)
}
analytics.logEvent("load_grade_summary", "items" to gradeSummaryItems.size, "force_refresh" to forceRefresh)
}) {
Timber.i("Loading grade summary result: An exception occurred")
- view?.run { showEmpty(isViewEmpty) }
errorHandler.dispatch(it)
})
}
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ view?.run {
+ if (isViewEmpty) {
+ lastError = error
+ setErrorDetails(message)
+ showErrorView(true)
+ showEmpty(false)
+ } else showError(message, error)
+ }
+ }
+
fun onSwipeRefresh() {
Timber.i("Force refreshing the grade summary")
view?.notifyParentRefresh()
}
+ fun onRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
+ view?.notifyParentRefresh()
+ }
+
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
+
fun onParentViewReselected() {
view?.run {
if (!isViewEmpty) resetView()
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 9e9c6e58f..cf3184873 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
@@ -26,6 +26,10 @@ interface GradeSummaryView : BaseView {
fun showContent(show: Boolean)
+ fun showErrorView(show: Boolean)
+
+ fun setErrorDetails(message: String)
+
fun showEmpty(show: Boolean)
fun notifyParentDataLoaded(semesterId: Int)
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 8195dd20b..3f8f1359a 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
@@ -3,6 +3,8 @@ package io.github.wulkanowy.ui.modules.homework
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
import android.view.ViewGroup
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.common.FlexibleItemDecoration
@@ -34,6 +36,8 @@ class HomeworkFragment : BaseFragment(), HomeworkView, MainView.TitledView {
override val titleStringId get() = R.string.homework_title
+ override val isViewEmpty get() = homeworkAdapter.isEmpty
+
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_homework, container, false)
}
@@ -41,7 +45,7 @@ class HomeworkFragment : BaseFragment(), HomeworkView, MainView.TitledView {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
messageContainer = homeworkRecycler
- presenter.onAttachView(this, savedInstanceState?.getLong(HomeworkFragment.SAVED_DATE_KEY))
+ presenter.onAttachView(this, savedInstanceState?.getLong(SAVED_DATE_KEY))
}
override fun initView() {
@@ -56,6 +60,9 @@ class HomeworkFragment : BaseFragment(), HomeworkView, MainView.TitledView {
}
homeworkSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
+ homeworkErrorRetry.setOnClickListener { presenter.onRetry() }
+ homeworkErrorDetails.setOnClickListener { presenter.onDetailsClick() }
+
homeworkPreviousButton.setOnClickListener { presenter.onPreviousDay() }
homeworkNextButton.setOnClickListener { presenter.onNextDay() }
@@ -74,18 +81,24 @@ class HomeworkFragment : BaseFragment(), HomeworkView, MainView.TitledView {
homeworkNavDate.text = date
}
- override fun isViewEmpty() = homeworkAdapter.isEmpty
-
override fun hideRefresh() {
homeworkSwipe.isRefreshing = false
}
override fun showEmpty(show: Boolean) {
- homeworkEmpty.visibility = if (show) View.VISIBLE else View.GONE
+ homeworkEmpty.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun showErrorView(show: Boolean) {
+ homeworkError.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun setErrorDetails(message: String) {
+ homeworkErrorMessage.text = message
}
override fun showProgress(show: Boolean) {
- homeworkProgress.visibility = if (show) View.VISIBLE else View.GONE
+ homeworkProgress.visibility = if (show) VISIBLE else GONE
}
override fun enableSwipe(enable: Boolean) {
@@ -93,15 +106,15 @@ class HomeworkFragment : BaseFragment(), HomeworkView, MainView.TitledView {
}
override fun showContent(show: Boolean) {
- homeworkRecycler.visibility = if (show) View.VISIBLE else View.GONE
+ homeworkRecycler.visibility = if (show) VISIBLE else GONE
}
override fun showPreButton(show: Boolean) {
- homeworkPreviousButton.visibility = if (show) View.VISIBLE else View.INVISIBLE
+ homeworkPreviousButton.visibility = if (show) VISIBLE else View.INVISIBLE
}
override fun showNextButton(show: Boolean) {
- homeworkNextButton.visibility = if (show) View.VISIBLE else View.INVISIBLE
+ homeworkNextButton.visibility = if (show) VISIBLE else View.INVISIBLE
}
override fun showTimetableDialog(homework: Homework) {
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 6829031c1..7e1da314b 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
@@ -35,10 +35,13 @@ class HomeworkPresenter @Inject constructor(
lateinit var currentDate: LocalDate
private set
+ private lateinit var lastError: Throwable
+
fun onAttachView(view: HomeworkView, date: Long?) {
super.onAttachView(view)
view.initView()
Timber.i("Homework view was initialized")
+ errorHandler.showErrorMessage = ::showErrorViewOnError
loadData(ofEpochDay(date ?: baseDate.toEpochDay()))
if (currentDate.isHolidays) setBaseDateOnHolidays()
reloadView()
@@ -59,6 +62,18 @@ class HomeworkPresenter @Inject constructor(
loadData(currentDate, true)
}
+ fun onRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
+ loadData(currentDate, true)
+ }
+
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
+
fun onHomeworkItemSelected(item: AbstractFlexibleItem<*>?) {
if (item is HomeworkItem) {
Timber.i("Select homework item ${item.homework.id}")
@@ -105,17 +120,29 @@ class HomeworkPresenter @Inject constructor(
view?.apply {
updateData(it)
showEmpty(it.isEmpty())
+ showErrorView(false)
showContent(it.isNotEmpty())
}
analytics.logEvent("load_homework", "items" to it.size, "force_refresh" to forceRefresh)
}) {
Timber.i("Loading homework result: An exception occurred")
- view?.run { showEmpty(isViewEmpty()) }
+
errorHandler.dispatch(it)
})
}
}
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ view?.run {
+ if (isViewEmpty) {
+ lastError = error
+ setErrorDetails(message)
+ showErrorView(true)
+ showEmpty(false)
+ } else showError(message, error)
+ }
+ }
+
private fun createHomeworkItem(items: Map>): List {
return items.flatMap {
HomeworkHeader(it.key).let { header ->
@@ -131,6 +158,7 @@ class HomeworkPresenter @Inject constructor(
enableSwipe(false)
showContent(false)
showEmpty(false)
+ showErrorView(false)
clearData()
reloadNavigation()
}
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 977a5b73f..1d241df46 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
@@ -5,6 +5,8 @@ import io.github.wulkanowy.ui.base.BaseView
interface HomeworkView : BaseView {
+ val isViewEmpty: Boolean
+
fun initView()
fun updateData(data: List)
@@ -13,12 +15,14 @@ interface HomeworkView : BaseView {
fun updateNavigationWeek(date: String)
- fun isViewEmpty(): Boolean
-
fun hideRefresh()
fun showEmpty(show: Boolean)
+ fun showErrorView(show: Boolean)
+
+ fun setErrorDetails(message: String)
+
fun showProgress(show: Boolean)
fun enableSwipe(enable: 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 6043d50eb..455d1e8ec 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
@@ -8,6 +8,7 @@ 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.BaseFragmentPagerAdapter
+import io.github.wulkanowy.ui.modules.login.advanced.LoginAdvancedFragment
import io.github.wulkanowy.ui.modules.login.form.LoginFormFragment
import io.github.wulkanowy.ui.modules.login.studentselect.LoginStudentSelectFragment
import io.github.wulkanowy.ui.modules.login.symbol.LoginSymbolFragment
@@ -50,7 +51,8 @@ class LoginActivity : BaseActivity(), LoginView {
addFragments(listOf(
LoginFormFragment.newInstance(),
LoginSymbolFragment.newInstance(),
- LoginStudentSelectFragment.newInstance()
+ LoginStudentSelectFragment.newInstance(),
+ LoginAdvancedFragment.newInstance()
))
}
@@ -93,4 +95,8 @@ class LoginActivity : BaseActivity(), LoginView {
fun onSymbolFragmentAccountLogged(students: List) {
presenter.onSymbolViewAccountLogged(students)
}
+
+ fun onAdvancedLoginClick() {
+ presenter.onAdvancedLoginClick()
+ }
}
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 76832bdac..75a0ba6a6 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
@@ -4,7 +4,11 @@ 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.sdk.exception.BadCredentialsException
+import io.github.wulkanowy.sdk.mobile.exception.InvalidPinException
+import io.github.wulkanowy.sdk.mobile.exception.InvalidSymbolException
+import io.github.wulkanowy.sdk.mobile.exception.InvalidTokenException
+import io.github.wulkanowy.sdk.mobile.exception.TokenDeadException
import io.github.wulkanowy.ui.base.ErrorHandler
import javax.inject.Inject
@@ -15,12 +19,22 @@ class LoginErrorHandler @Inject constructor(
var onBadCredentials: () -> Unit = {}
+ var onInvalidToken: (String) -> Unit = {}
+
+ var onInvalidPin: (String) -> Unit = {}
+
+ var onInvalidSymbol: (String) -> Unit = {}
+
var onStudentDuplicate: (String) -> Unit = {}
override fun proceed(error: Throwable) {
when (error) {
is BadCredentialsException -> onBadCredentials()
is SQLiteConstraintException -> onStudentDuplicate(resources.getString(R.string.login_duplicate_student))
+ is TokenDeadException -> onInvalidToken(resources.getString(R.string.login_expired_token))
+ is InvalidTokenException -> onInvalidToken(resources.getString(R.string.login_invalid_token))
+ is InvalidPinException -> onInvalidPin(resources.getString(R.string.login_invalid_pin))
+ is InvalidSymbolException -> onInvalidSymbol(resources.getString(R.string.login_invalid_symbol))
else -> super.proceed(error)
}
}
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 8bcf042b5..28339a467 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
@@ -6,6 +6,7 @@ import dagger.android.ContributesAndroidInjector
import io.github.wulkanowy.di.scopes.PerActivity
import io.github.wulkanowy.di.scopes.PerFragment
import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter
+import io.github.wulkanowy.ui.modules.login.advanced.LoginAdvancedFragment
import io.github.wulkanowy.ui.modules.login.form.LoginFormFragment
import io.github.wulkanowy.ui.modules.login.studentselect.LoginStudentSelectFragment
import io.github.wulkanowy.ui.modules.login.symbol.LoginSymbolFragment
@@ -26,6 +27,10 @@ internal abstract class LoginModule {
@ContributesAndroidInjector
abstract fun bindLoginFormFragment(): LoginFormFragment
+ @PerFragment
+ @ContributesAndroidInjector
+ abstract fun bindLoginAdvancedFragment(): LoginAdvancedFragment
+
@PerFragment
@ContributesAndroidInjector
abstract fun bindLoginSymbolFragment(): LoginSymbolFragment
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 8ff5e4daf..afa2d145d 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
@@ -45,6 +45,10 @@ class LoginPresenter @Inject constructor(
}
}
+ fun onAdvancedLoginClick() {
+ view?.switchView(3)
+ }
+
fun onViewSelected(index: Int) {
view?.apply {
when (index) {
@@ -58,7 +62,7 @@ class LoginPresenter @Inject constructor(
Timber.i("Back pressed in login view")
view?.apply {
when (currentViewIndex) {
- 1, 2 -> switchView(0)
+ 1, 2, 3 -> switchView(0)
else -> default()
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedFragment.kt
new file mode 100644
index 000000000..353effa9b
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedFragment.kt
@@ -0,0 +1,259 @@
+package io.github.wulkanowy.ui.modules.login.advanced
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.inputmethod.EditorInfo
+import android.widget.ArrayAdapter
+import androidx.appcompat.widget.AppCompatEditText
+import androidx.core.widget.doOnTextChanged
+import io.github.wulkanowy.R
+import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.sdk.Sdk
+import io.github.wulkanowy.ui.base.BaseFragment
+import io.github.wulkanowy.ui.modules.login.LoginActivity
+import io.github.wulkanowy.ui.modules.login.form.LoginSymbolAdapter
+import io.github.wulkanowy.utils.hideSoftInput
+import io.github.wulkanowy.utils.showSoftInput
+import kotlinx.android.synthetic.main.fragment_login_advanced.*
+import javax.inject.Inject
+
+class LoginAdvancedFragment : BaseFragment(), LoginAdvancedView {
+
+ @Inject
+ lateinit var presenter: LoginAdvancedPresenter
+
+ companion object {
+ fun newInstance() = LoginAdvancedFragment()
+ }
+
+ override val formLoginType: String
+ get() = when (loginTypeSwitch.checkedRadioButtonId) {
+ R.id.loginTypeApi -> "API"
+ R.id.loginTypeScrapper -> "SCRAPPER"
+ else -> "HYBRID"
+ }
+
+ override val formNameValue: String
+ get() = loginFormName.text.toString().trim()
+
+ override val formPassValue: String
+ get() = loginFormPass.text.toString().trim()
+
+ private lateinit var hostKeys: Array
+
+ private lateinit var hostValues: Array
+
+ override val formHostValue: String?
+ get() = hostValues.getOrNull(hostKeys.indexOf(loginFormHost.text.toString()))
+
+ override val formPinValue: String
+ get() = loginFormPin.text.toString().trim()
+
+ override val formSymbolValue: String
+ get() = loginFormSymbol.text.toString().trim()
+
+ override val formTokenValue: String
+ get() = loginFormToken.text.toString().trim()
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ return inflater.inflate(R.layout.fragment_login_advanced, container, false)
+ }
+
+ override fun onActivityCreated(savedInstanceState: Bundle?) {
+ super.onActivityCreated(savedInstanceState)
+ presenter.onAttachView(this)
+ }
+
+ override fun initView() {
+ hostKeys = resources.getStringArray(R.array.hosts_keys)
+ hostValues = resources.getStringArray(R.array.hosts_values)
+
+ loginFormName.doOnTextChanged { _, _, _, _ -> presenter.onNameTextChanged() }
+ loginFormPass.doOnTextChanged { _, _, _, _ -> presenter.onPassTextChanged() }
+ loginFormPin.doOnTextChanged { _, _, _, _ -> presenter.onPinTextChanged() }
+ loginFormSymbol.doOnTextChanged { _, _, _, _ -> presenter.onSymbolTextChanged() }
+ loginFormToken.doOnTextChanged { _, _, _, _ -> presenter.onTokenTextChanged() }
+ loginFormHost.setOnItemClickListener { _, _, _, _ -> presenter.onHostSelected() }
+ loginFormSignIn.setOnClickListener { presenter.onSignInClick() }
+
+ loginTypeSwitch.setOnCheckedChangeListener { _, checkedId ->
+ presenter.onLoginModeSelected(when (checkedId) {
+ R.id.loginTypeApi -> Sdk.Mode.API
+ R.id.loginTypeScrapper -> Sdk.Mode.SCRAPPER
+ else -> Sdk.Mode.HYBRID
+ })
+ }
+
+ loginFormPin.setOnEditorDoneSignIn()
+ loginFormPass.setOnEditorDoneSignIn()
+
+ loginFormSymbol.setAdapter(ArrayAdapter(requireContext(), android.R.layout.simple_list_item_1, resources.getStringArray(R.array.symbols_values)))
+
+ with(loginFormHost) {
+ setText(hostKeys.getOrElse(0) { "" })
+ setAdapter(LoginSymbolAdapter(context, R.layout.support_simple_spinner_dropdown_item, hostKeys))
+ }
+ }
+
+ private fun AppCompatEditText.setOnEditorDoneSignIn() {
+ setOnEditorActionListener { _, id, _ ->
+ if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) loginFormSignIn.callOnClick() else false
+ }
+ }
+
+ override fun setDefaultCredentials(name: String, pass: String, symbol: String, token: String, pin: String) {
+ loginFormName.setText(name)
+ loginFormPass.setText(pass)
+ loginFormToken.setText(token)
+ loginFormSymbol.setText(symbol)
+ loginFormPin.setText(pin)
+ }
+
+ override fun setErrorNameRequired() {
+ with(loginFormNameLayout) {
+ requestFocus()
+ error = getString(R.string.login_field_required)
+ }
+ }
+
+ override fun setErrorPassRequired(focus: Boolean) {
+ with(loginFormPassLayout) {
+ if (focus) requestFocus()
+ error = getString(R.string.login_field_required)
+ }
+ }
+
+ override fun setErrorPassInvalid(focus: Boolean) {
+ with(loginFormPassLayout) {
+ if (focus) requestFocus()
+ error = getString(R.string.login_invalid_password)
+ }
+ }
+
+ override fun setErrorPassIncorrect() {
+ with(loginFormPassLayout) {
+ requestFocus()
+ error = getString(R.string.login_incorrect_password)
+ }
+ }
+
+ override fun setErrorPinRequired() {
+ with(loginFormPinLayout) {
+ requestFocus()
+ error = getString(R.string.login_field_required)
+ }
+ }
+
+ override fun setErrorPinInvalid(message: String) {
+ with(loginFormPinLayout) {
+ requestFocus()
+ error = message
+ }
+ }
+
+ override fun setErrorSymbolRequired() {
+ with(loginFormSymbolLayout) {
+ requestFocus()
+ error = getString(R.string.login_field_required)
+ }
+ }
+
+ override fun setErrorSymbolInvalid(message: String) {
+ with(loginFormSymbolLayout) {
+ requestFocus()
+ error = message
+ }
+ }
+
+ override fun setErrorTokenRequired() {
+ with(loginFormTokenLayout) {
+ requestFocus()
+ error = getString(R.string.login_field_required)
+ }
+ }
+
+ override fun setErrorTokenInvalid(message: String) {
+ with(loginFormTokenLayout) {
+ requestFocus()
+ error = message
+ }
+ }
+
+ override fun clearNameError() {
+ loginFormNameLayout.error = null
+ }
+
+ override fun clearPassError() {
+ loginFormPassLayout.error = null
+ }
+
+ override fun clearPinKeyError() {
+ loginFormPinLayout.error = null
+ }
+
+ override fun clearSymbolError() {
+ loginFormSymbolLayout.error = null
+ }
+
+ override fun clearTokenError() {
+ loginFormTokenLayout.error = null
+ }
+
+ override fun showOnlyHybridModeInputs() {
+ loginFormNameLayout.visibility = View.VISIBLE
+ loginFormPassLayout.visibility = View.VISIBLE
+ loginFormHostLayout.visibility = View.VISIBLE
+ loginFormPinLayout.visibility = View.GONE
+ loginFormSymbolLayout.visibility = View.VISIBLE
+ loginFormTokenLayout.visibility = View.GONE
+ }
+
+ override fun showOnlyScrapperModeInputs() {
+ loginFormNameLayout.visibility = View.VISIBLE
+ loginFormPassLayout.visibility = View.VISIBLE
+ loginFormHostLayout.visibility = View.VISIBLE
+ loginFormPinLayout.visibility = View.GONE
+ loginFormSymbolLayout.visibility = View.VISIBLE
+ loginFormTokenLayout.visibility = View.GONE
+ }
+
+ override fun showOnlyMobileApiModeInputs() {
+ loginFormNameLayout.visibility = View.GONE
+ loginFormPassLayout.visibility = View.GONE
+ loginFormHostLayout.visibility = View.GONE
+ loginFormPinLayout.visibility = View.VISIBLE
+ loginFormSymbolLayout.visibility = View.VISIBLE
+ loginFormTokenLayout.visibility = View.VISIBLE
+ }
+
+ override fun showSoftKeyboard() {
+ activity?.showSoftInput()
+ }
+
+ override fun hideSoftKeyboard() {
+ activity?.hideSoftInput()
+ }
+
+ override fun showProgress(show: Boolean) {
+ loginFormProgress.visibility = if (show) View.VISIBLE else View.GONE
+ }
+
+ override fun showContent(show: Boolean) {
+ loginFormContainer.visibility = if (show) View.VISIBLE else View.GONE
+ }
+
+ override fun notifyParentAccountLogged(students: List) {
+ (activity as? LoginActivity)?.onFormFragmentAccountLogged(students, Triple(
+ loginFormName.text.toString(),
+ loginFormPass.text.toString(),
+ resources.getStringArray(R.array.hosts_values)[1]
+ ))
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ presenter.onDetachView()
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedPresenter.kt
new file mode 100644
index 000000000..1e49e5d8b
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedPresenter.kt
@@ -0,0 +1,218 @@
+package io.github.wulkanowy.ui.modules.login.advanced
+
+import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.data.repositories.student.StudentRepository
+import io.github.wulkanowy.sdk.Sdk
+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 io.github.wulkanowy.utils.ifNullOrBlank
+import io.reactivex.Single
+import timber.log.Timber
+import javax.inject.Inject
+
+class LoginAdvancedPresenter @Inject constructor(
+ schedulers: SchedulersProvider,
+ studentRepository: StudentRepository,
+ private val loginErrorHandler: LoginErrorHandler,
+ private val analytics: FirebaseAnalyticsHelper
+) : BasePresenter(loginErrorHandler, studentRepository, schedulers) {
+
+ override fun onAttachView(view: LoginAdvancedView) {
+ super.onAttachView(view)
+ view.run {
+ initView()
+ showOnlyScrapperModeInputs()
+ with(loginErrorHandler) {
+ onBadCredentials = ::onBadCredentials
+ onInvalidToken = ::onInvalidToken
+ onInvalidSymbol = ::onInvalidSymbol
+ onInvalidPin = ::onInvalidPin
+ }
+ }
+ }
+
+ private fun onBadCredentials() {
+ view?.run {
+ setErrorPassIncorrect()
+ showSoftKeyboard()
+ Timber.i("Entered wrong username or password")
+ }
+ }
+
+ private fun onInvalidToken(message: String) {
+ view?.run {
+ setErrorTokenInvalid(message)
+ showSoftKeyboard()
+ Timber.i("Entered invalid token")
+ }
+ }
+
+ private fun onInvalidSymbol(message: String) {
+ view?.run {
+ setErrorSymbolInvalid(message)
+ showSoftKeyboard()
+ Timber.i("Entered invalid symbol")
+ }
+ }
+
+ private fun onInvalidPin(message: String) {
+ view?.run {
+ setErrorPinInvalid(message)
+ showSoftKeyboard()
+ Timber.i("Entered invalid PIN")
+ }
+ }
+
+ fun onHostSelected() {
+ view?.apply {
+ clearPassError()
+ clearNameError()
+ if (formHostValue?.contains("fakelog") == true) {
+ setDefaultCredentials("jan@fakelog.cf", "jan123", "powiatwulkanowy", "FK100000", "999999")
+ }
+ }
+ }
+
+ fun onLoginModeSelected(type: Sdk.Mode) {
+ view?.run {
+ when (type) {
+ Sdk.Mode.API -> showOnlyMobileApiModeInputs()
+ Sdk.Mode.SCRAPPER -> showOnlyScrapperModeInputs()
+ Sdk.Mode.HYBRID -> showOnlyHybridModeInputs()
+ }
+ }
+ }
+
+ fun onPassTextChanged() {
+ view?.clearPassError()
+ }
+
+ fun onNameTextChanged() {
+ view?.clearNameError()
+ }
+
+ fun onPinTextChanged() {
+ view?.clearPinKeyError()
+ }
+
+ fun onSymbolTextChanged() {
+ view?.clearSymbolError()
+ }
+
+ fun onTokenTextChanged() {
+ view?.clearTokenError()
+ }
+
+ fun onSignInClick() {
+ if (!validateCredentials()) return
+
+ disposable.add(getStudentsAppropriatesToLoginType()
+ .subscribeOn(schedulers.backgroundThread)
+ .observeOn(schedulers.mainThread)
+ .doOnSubscribe {
+ view?.apply {
+ hideSoftKeyboard()
+ showProgress(true)
+ showContent(false)
+ }
+ Timber.i("Login started")
+ }
+ .doFinally {
+ view?.apply {
+ showProgress(false)
+ showContent(true)
+ }
+ }
+ .subscribe({
+ Timber.i("Login result: Success")
+ analytics.logEvent("registration_form", "success" to true, "students" to it.size, "error" to "No error")
+ view?.notifyParentAccountLogged(it)
+ }, {
+ Timber.i("Login result: An exception occurred")
+ analytics.logEvent("registration_form", "success" to false, "students" to -1, "error" to it.message.ifNullOrBlank { "No message" })
+ loginErrorHandler.dispatch(it)
+ }))
+ }
+
+ private fun getStudentsAppropriatesToLoginType(): Single> {
+ val email = view?.formNameValue.orEmpty()
+ val password = view?.formPassValue.orEmpty()
+ val endpoint = view?.formHostValue.orEmpty()
+
+ val pin = view?.formPinValue.orEmpty()
+ val symbol = view?.formSymbolValue.orEmpty()
+ val token = view?.formTokenValue.orEmpty()
+
+ return when (Sdk.Mode.valueOf(view?.formLoginType ?: "")) {
+ Sdk.Mode.API -> studentRepository.getStudentsApi(pin, symbol, token)
+ Sdk.Mode.SCRAPPER -> studentRepository.getStudentsScrapper(email, password, endpoint, symbol)
+ Sdk.Mode.HYBRID -> studentRepository.getStudentsHybrid(email, password, endpoint, symbol)
+ }
+ }
+
+ private fun validateCredentials(): Boolean {
+ val login = view?.formNameValue.orEmpty()
+ val password = view?.formPassValue.orEmpty()
+
+ val pin = view?.formPinValue.orEmpty()
+ val symbol = view?.formSymbolValue.orEmpty()
+ val token = view?.formTokenValue.orEmpty()
+
+ var isCorrect = true
+
+ when (Sdk.Mode.valueOf(view?.formLoginType ?: "")) {
+ Sdk.Mode.API -> {
+ if (pin.isEmpty()) {
+ view?.setErrorPinRequired()
+ isCorrect = false
+ }
+
+ if (symbol.isEmpty()) {
+ view?.setErrorSymbolRequired()
+ isCorrect = false
+ }
+
+ if (token.isEmpty()) {
+ view?.setErrorTokenRequired()
+ isCorrect = false
+ }
+ }
+ Sdk.Mode.SCRAPPER -> {
+ if (login.isEmpty()) {
+ view?.setErrorNameRequired()
+ isCorrect = false
+ }
+
+ if (password.isEmpty()) {
+ view?.setErrorPassRequired(focus = isCorrect)
+ isCorrect = false
+ }
+
+ if (password.length < 6 && password.isNotEmpty()) {
+ view?.setErrorPassInvalid(focus = isCorrect)
+ isCorrect = false
+ }
+ }
+ Sdk.Mode.HYBRID -> {
+ if (login.isEmpty()) {
+ view?.setErrorNameRequired()
+ isCorrect = false
+ }
+
+ if (password.isEmpty()) {
+ view?.setErrorPassRequired(focus = isCorrect)
+ isCorrect = false
+ }
+
+ if (password.length < 6 && password.isNotEmpty()) {
+ view?.setErrorPassInvalid(focus = isCorrect)
+ isCorrect = false
+ }
+ }
+ }
+
+ return isCorrect
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedView.kt
new file mode 100644
index 000000000..85a85a331
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedView.kt
@@ -0,0 +1,71 @@
+package io.github.wulkanowy.ui.modules.login.advanced
+
+import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.ui.base.BaseView
+
+interface LoginAdvancedView : BaseView {
+
+ val formNameValue: String
+
+ val formPassValue: String
+
+ val formHostValue: String?
+
+ val formLoginType: String
+
+ val formPinValue: String
+
+ val formSymbolValue: String
+
+ val formTokenValue: String
+
+ fun initView()
+
+ fun setDefaultCredentials(name: String, pass: String, symbol: String, token: String, pin: String)
+
+ fun setErrorNameRequired()
+
+ fun setErrorPassRequired(focus: Boolean)
+
+ fun setErrorPassInvalid(focus: Boolean)
+
+ fun setErrorPassIncorrect()
+
+ fun clearNameError()
+
+ fun clearPassError()
+
+ fun clearPinKeyError()
+
+ fun clearSymbolError()
+
+ fun clearTokenError()
+
+ fun showSoftKeyboard()
+
+ fun hideSoftKeyboard()
+
+ fun showProgress(show: Boolean)
+
+ fun showContent(show: Boolean)
+
+ fun notifyParentAccountLogged(students: List)
+
+ fun setErrorPinRequired()
+
+ fun setErrorPinInvalid(message: String)
+
+ fun setErrorSymbolRequired()
+
+ fun setErrorSymbolInvalid(message: String)
+
+ fun setErrorTokenRequired()
+
+ fun setErrorTokenInvalid(message: String)
+
+ fun showOnlyHybridModeInputs()
+
+ fun showOnlyScrapperModeInputs()
+
+ fun showOnlyMobileApiModeInputs()
+}
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 1288e2991..cbd405c28 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
@@ -16,7 +16,7 @@ import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.hideSoftInput
-import io.github.wulkanowy.utils.openEmail
+import io.github.wulkanowy.utils.openEmailClient
import io.github.wulkanowy.utils.openInternetBrowser
import io.github.wulkanowy.utils.showSoftInput
import kotlinx.android.synthetic.main.fragment_login_form.*
@@ -61,8 +61,9 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
loginFormPass.doOnTextChanged { _, _, _, _ -> presenter.onPassTextChanged() }
loginFormHost.setOnItemClickListener { _, _, _, _ -> presenter.onHostSelected() }
loginFormSignIn.setOnClickListener { presenter.onSignInClick() }
+ loginFormAdvancedButton.setOnClickListener { presenter.onAdvancedLoginClick() }
loginFormPrivacyLink.setOnClickListener { presenter.onPrivacyLinkClick() }
- loginFormContactDiscord.setOnClickListener { presenter.onDiscordClick() }
+ loginFormFaq.setOnClickListener { presenter.onFaqClick() }
loginFormContactEmail.setOnClickListener { presenter.onEmailClick() }
loginFormPass.setOnEditorActionListener { _, id, _ ->
@@ -134,14 +135,7 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
@SuppressLint("SetTextI18n")
override fun showVersion() {
- with(loginFormVersion) {
- visibility = VISIBLE
- text = "${getString(R.string.app_name)} ${appInfo.versionName}"
- }
- }
-
- override fun showPrivacyPolicy() {
- loginFormPrivacyLink.visibility = VISIBLE
+ loginFormVersion.text = "v${appInfo.versionName}"
}
override fun notifyParentAccountLogged(students: List, loginData: Triple) {
@@ -156,17 +150,21 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
loginFormContact.visibility = if (show) VISIBLE else GONE
}
+ override fun openAdvancedLogin() {
+ (activity as? LoginActivity)?.onAdvancedLoginClick()
+ }
+
override fun onDestroyView() {
super.onDestroyView()
presenter.onDetachView()
}
- override fun openDiscordInvite() {
- context?.openInternetBrowser("https://discord.gg/vccAQBr", ::showMessage)
+ override fun openFaqPage() {
+ context?.openInternetBrowser("https://wulkanowy.github.io/czesto-zadawane-pytania/dlaczego-nie-moge-sie-zalogowac", ::showMessage)
}
override fun openEmail() {
- context?.openEmail(
+ context?.openEmailClient(
requireContext().getString(R.string.login_email_intent_title),
"wulkanowyinc@gmail.com",
requireContext().getString(R.string.login_email_subject),
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 bdab1dade..0b45c9a53 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
@@ -3,7 +3,6 @@ package io.github.wulkanowy.ui.modules.login.form
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.AppInfo
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.github.wulkanowy.utils.SchedulersProvider
import io.github.wulkanowy.utils.ifNullOrBlank
@@ -14,8 +13,7 @@ class LoginFormPresenter @Inject constructor(
schedulers: SchedulersProvider,
studentRepository: StudentRepository,
private val loginErrorHandler: LoginErrorHandler,
- private val analytics: FirebaseAnalyticsHelper,
- private val appInfo: AppInfo
+ private val analytics: FirebaseAnalyticsHelper
) : BasePresenter(loginErrorHandler, studentRepository, schedulers) {
override fun onAttachView(view: LoginFormView) {
@@ -23,7 +21,7 @@ class LoginFormPresenter @Inject constructor(
view.run {
initView()
showContact(false)
- if (appInfo.isDebug) showVersion() else showPrivacyPolicy()
+ showVersion()
loginErrorHandler.onBadCredentials = {
setErrorPassIncorrect()
@@ -37,6 +35,10 @@ class LoginFormPresenter @Inject constructor(
view?.openPrivacyPolicyPage()
}
+ fun onAdvancedLoginClick() {
+ view?.openAdvancedLogin()
+ }
+
fun onHostSelected() {
view?.apply {
clearPassError()
@@ -56,13 +58,13 @@ class LoginFormPresenter @Inject constructor(
}
fun onSignInClick() {
- val email = view?.formNameValue.orEmpty()
- val password = view?.formPassValue.orEmpty()
- val endpoint = view?.formHostValue.orEmpty()
+ val email = view?.formNameValue.orEmpty().trim()
+ val password = view?.formPassValue.orEmpty().trim()
+ val endpoint = view?.formHostValue.orEmpty().trim()
if (!validateCredentials(email, password)) return
- disposable.add(studentRepository.getStudents(email, password, endpoint)
+ disposable.add(studentRepository.getStudentsScrapper(email, password, endpoint)
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
.doOnSubscribe {
@@ -81,18 +83,18 @@ class LoginFormPresenter @Inject constructor(
}
.subscribe({
Timber.i("Login result: Success")
- analytics.logEvent("registration_form", "success" to true, "students" to it.size, "endpoint" to endpoint, "error" to "No error")
+ analytics.logEvent("registration_form", "success" to true, "students" to it.size, "scrapperBaseUrl" to endpoint, "error" to "No error")
view?.notifyParentAccountLogged(it, Triple(email, password, endpoint))
}, {
Timber.i("Login result: An exception occurred")
- analytics.logEvent("registration_form", "success" to false, "students" to -1, "endpoint" to endpoint, "error" to it.message.ifNullOrBlank { "No message" })
+ analytics.logEvent("registration_form", "success" to false, "students" to -1, "scrapperBaseUrl" to endpoint, "error" to it.message.ifNullOrBlank { "No message" })
loginErrorHandler.dispatch(it)
view?.showContact(true)
}))
}
- fun onDiscordClick() {
- view?.openDiscordInvite()
+ fun onFaqClick() {
+ view?.openFaqPage()
}
fun onEmailClick() {
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 7eec9477b..6da57c8c5 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
@@ -37,15 +37,15 @@ interface LoginFormView : BaseView {
fun showVersion()
- fun showPrivacyPolicy()
-
fun notifyParentAccountLogged(students: List, loginData: Triple)
fun openPrivacyPolicyPage()
fun showContact(show: Boolean)
- fun openDiscordInvite()
+ fun openFaqPage()
fun openEmail()
+
+ fun openAdvancedLogin()
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt
index dba0c951a..8478f7ccf 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt
@@ -14,7 +14,7 @@ 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.AppInfo
-import io.github.wulkanowy.utils.openEmail
+import io.github.wulkanowy.utils.openEmailClient
import io.github.wulkanowy.utils.openInternetBrowser
import io.github.wulkanowy.utils.setOnItemClickListener
import kotlinx.android.synthetic.main.fragment_login_student_select.*
@@ -102,7 +102,7 @@ class LoginStudentSelectFragment : BaseFragment(), LoginStudentSelectView {
}
override fun openEmail() {
- context?.openEmail(
+ context?.openEmailClient(
requireContext().getString(R.string.login_email_intent_title),
"wulkanowyinc@gmail.com",
requireContext().getString(R.string.login_email_subject),
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt
index 288531dcc..841c225d7 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt
@@ -79,11 +79,11 @@ class LoginStudentSelectPresenter @Inject constructor(
Timber.i("Registration started")
}
.subscribe({
- students.forEach { analytics.logEvent("registration_student_select", "success" to true, "endpoint" to it.endpoint, "symbol" to it.symbol, "error" to "No error") }
+ students.forEach { analytics.logEvent("registration_student_select", "success" to true, "scrapperBaseUrl" to it.scrapperBaseUrl, "symbol" to it.symbol, "error" to "No error") }
Timber.i("Registration result: Success")
view?.openMainView()
}, { error ->
- students.forEach { analytics.logEvent("registration_student_select", "success" to false, "endpoint" to it.endpoint, "symbol" to it.symbol, "error" to error.message.ifNullOrBlank { "No message" }) }
+ students.forEach { analytics.logEvent("registration_student_select", "success" to false, "scrapperBaseUrl" to it.scrapperBaseUrl, "symbol" to it.symbol, "error" to error.message.ifNullOrBlank { "No message" }) }
Timber.i("Registration result: An exception occurred ")
loginErrorHandler.dispatch(error)
view?.apply {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt
index 724e3fbb9..5e9ce3ba3 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt
@@ -16,7 +16,7 @@ import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.hideSoftInput
-import io.github.wulkanowy.utils.openEmail
+import io.github.wulkanowy.utils.openEmailClient
import io.github.wulkanowy.utils.openInternetBrowser
import io.github.wulkanowy.utils.showSoftInput
import kotlinx.android.synthetic.main.fragment_login_symbol.*
@@ -50,7 +50,7 @@ class LoginSymbolFragment : BaseFragment(), LoginSymbolView {
override fun initView() {
loginSymbolSignIn.setOnClickListener { presenter.attemptLogin(loginSymbolName.text.toString()) }
- loginSymbolContactDiscord.setOnClickListener { presenter.onDiscordClick() }
+ loginSymbolFaq.setOnClickListener { presenter.onFaqClick() }
loginSymbolContactEmail.setOnClickListener { presenter.onEmailClick() }
loginSymbolName.doOnTextChanged { _, _, _, _ -> presenter.onSymbolTextChanged() }
@@ -126,12 +126,12 @@ class LoginSymbolFragment : BaseFragment(), LoginSymbolView {
presenter.onDetachView()
}
- override fun openDiscordInvite() {
- context?.openInternetBrowser("https://discord.gg/vccAQBr", ::showMessage)
+ override fun openFaqPage() {
+ context?.openInternetBrowser("https://wulkanowy.github.io/czesto-zadawane-pytania/co-to-jest-symbol", ::showMessage)
}
override fun openEmail() {
- context?.openEmail(
+ context?.openEmailClient(
requireContext().getString(R.string.login_email_intent_title),
"wulkanowyinc@gmail.com",
requireContext().getString(R.string.login_email_subject),
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt
index 8e4dd3b0b..ee6c30c3b 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt
@@ -44,7 +44,7 @@ class LoginSymbolPresenter @Inject constructor(
disposable.add(
Single.fromCallable { if (loginData == null) throw IllegalArgumentException("Login data is null") else loginData }
- .flatMap { studentRepository.getStudents(it.first, it.second, it.third, symbol) }
+ .flatMap { studentRepository.getStudentsScrapper(it.first, it.second, it.third, symbol) }
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
.doOnSubscribe {
@@ -62,7 +62,7 @@ class LoginSymbolPresenter @Inject constructor(
}
}
.subscribe({
- analytics.logEvent("registration_symbol", "success" to true, "students" to it.size, "endpoint" to loginData?.third, "symbol" to symbol, "error" to "No error")
+ analytics.logEvent("registration_symbol", "success" to true, "students" to it.size, "scrapperBaseUrl" to loginData?.third, "symbol" to symbol, "error" to "No error")
view?.apply {
if (it.isEmpty()) {
Timber.i("Login with symbol result: Empty student list")
@@ -75,7 +75,7 @@ class LoginSymbolPresenter @Inject constructor(
}
}, {
Timber.i("Login with symbol result: An exception occurred")
- analytics.logEvent("registration_symbol", "success" to false, "students" to -1, "endpoint" to loginData?.third, "symbol" to symbol, "error" to it.message.ifNullOrBlank { "No message" })
+ analytics.logEvent("registration_symbol", "success" to false, "students" to -1, "scrapperBaseUrl" to loginData?.third, "symbol" to symbol, "error" to it.message.ifNullOrBlank { "No message" })
loginErrorHandler.dispatch(it)
view?.showContact(true)
}))
@@ -89,8 +89,8 @@ class LoginSymbolPresenter @Inject constructor(
}
}
- fun onDiscordClick() {
- view?.openDiscordInvite()
+ fun onFaqClick() {
+ view?.openFaqPage()
}
fun onEmailClick() {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt
index 9b5340cff..1afc15327 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt
@@ -29,7 +29,7 @@ interface LoginSymbolView : BaseView {
fun showContact(show: Boolean)
- fun openDiscordInvite()
+ fun openFaqPage()
fun openEmail()
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt
index 00204a876..12bf1a132 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt
@@ -3,6 +3,8 @@ package io.github.wulkanowy.ui.modules.luckynumber
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
import android.view.ViewGroup
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.LuckyNumber
@@ -23,17 +25,22 @@ class LuckyNumberFragment : BaseFragment(), LuckyNumberView, MainView.TitledView
override val titleStringId: Int
get() = R.string.lucky_number_title
+ override val isViewEmpty get() = luckyNumberText.text.isBlank()
+
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_lucky_number, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
+ messageContainer = luckyNumberSwipe
presenter.onAttachView(this)
}
override fun initView() {
luckyNumberSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
+ luckyNumberErrorRetry.setOnClickListener { presenter.onRetry() }
+ luckyNumberErrorDetails.setOnClickListener { presenter.onDetailsClick() }
}
override fun updateData(data: LuckyNumber) {
@@ -45,11 +52,19 @@ class LuckyNumberFragment : BaseFragment(), LuckyNumberView, MainView.TitledView
}
override fun showEmpty(show: Boolean) {
- luckyNumberEmpty.visibility = if (show) View.VISIBLE else View.GONE
+ luckyNumberEmpty.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun showErrorView(show: Boolean) {
+ luckyNumberError.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun setErrorDetails(message: String) {
+ luckyNumberErrorMessage.text = message
}
override fun showProgress(show: Boolean) {
- luckyNumberProgress.visibility = if (show) View.VISIBLE else View.GONE
+ luckyNumberProgress.visibility = if (show) VISIBLE else GONE
}
override fun enableSwipe(enable: Boolean) {
@@ -57,11 +72,7 @@ class LuckyNumberFragment : BaseFragment(), LuckyNumberView, MainView.TitledView
}
override fun showContent(show: Boolean) {
- luckyNumberContent.visibility = if (show) View.VISIBLE else View.GONE
- }
-
- override fun isViewEmpty(): Boolean {
- return luckyNumberText.text.isBlank()
+ luckyNumberContent.visibility = if (show) VISIBLE else GONE
}
override fun onDestroyView() {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt
index ee7260e6f..c86aab976 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt
@@ -19,6 +19,8 @@ class LuckyNumberPresenter @Inject constructor(
private val analytics: FirebaseAnalyticsHelper
) : BasePresenter(errorHandler, studentRepository, schedulers) {
+ private lateinit var lastError: Throwable
+
override fun onAttachView(view: LuckyNumberView) {
super.onAttachView(view)
view.run {
@@ -27,6 +29,7 @@ class LuckyNumberPresenter @Inject constructor(
enableSwipe(false)
}
Timber.i("Lucky number view was initialized")
+ errorHandler.showErrorMessage = ::showErrorViewOnError
loadData()
}
@@ -52,25 +55,49 @@ class LuckyNumberPresenter @Inject constructor(
updateData(it)
showContent(true)
showEmpty(false)
+ showErrorView(false)
}
analytics.logEvent("load_lucky_number", "lucky_number" to it.luckyNumber, "force_refresh" to forceRefresh)
}, {
Timber.i("Loading lucky number result: An exception occurred")
- view?.run { showEmpty(isViewEmpty()) }
errorHandler.dispatch(it)
}, {
Timber.i("Loading lucky number result: No lucky number found")
view?.run {
showContent(false)
showEmpty(true)
+ showErrorView(false)
}
})
)
}
}
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ view?.run {
+ if (isViewEmpty) {
+ lastError = error
+ setErrorDetails(message)
+ showErrorView(true)
+ showEmpty(false)
+ } else showError(message, error)
+ }
+ }
+
fun onSwipeRefresh() {
Timber.i("Force refreshing the lucky number")
loadData(true)
}
+
+ fun onRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
+ loadData(true)
+ }
+
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberView.kt
index 9ead2b1f7..a680c83eb 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberView.kt
@@ -5,6 +5,8 @@ import io.github.wulkanowy.ui.base.BaseView
interface LuckyNumberView : BaseView {
+ val isViewEmpty: Boolean
+
fun initView()
fun updateData(data: LuckyNumber)
@@ -13,11 +15,13 @@ interface LuckyNumberView : BaseView {
fun showEmpty(show: Boolean)
+ fun showErrorView(show: Boolean)
+
+ fun setErrorDetails(message: String)
+
fun showProgress(show: Boolean)
fun enableSwipe(enable: Boolean)
fun showContent(show: Boolean)
-
- fun isViewEmpty(): Boolean
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigurePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigurePresenter.kt
index 3c8f18a05..6e4716bfa 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigurePresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigurePresenter.kt
@@ -58,7 +58,10 @@ class LuckyNumberWidgetConfigurePresenter @Inject constructor(
.subscribe({
when {
it.isEmpty() -> view?.openLoginView()
- it.size == 1 -> registerStudent(it.single().student)
+ it.size == 1 -> {
+ selectedStudent = it.single().student
+ view?.showThemeDialog()
+ }
else -> view?.updateData(it)
}
}, { errorHandler.dispatch(it) }))
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt
index 4c7f77593..991c1d106 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt
@@ -100,7 +100,7 @@ class MainActivity : BaseActivity(), MainView {
override fun initView() {
with(mainToolbar) {
if (SDK_INT >= LOLLIPOP) stateListAnimator = null
- setBackgroundColor(overlayProvider.get().getSurfaceColorWithOverlayIfNeeded(dpToPx(4f)))
+ setBackgroundColor(overlayProvider.get().compositeOverlayWithThemeSurfaceColorIfNeeded(dpToPx(4f)))
}
with(mainBottomNav) {
@@ -113,7 +113,7 @@ class MainActivity : BaseActivity(), MainView {
))
accentColor = getThemeAttrColor(R.attr.colorPrimary)
inactiveColor = ColorUtils.setAlphaComponent(getThemeAttrColor(R.attr.colorOnSurface), 153)
- defaultBackgroundColor = overlayProvider.get().getSurfaceColorWithOverlayIfNeeded(dpToPx(8f))
+ defaultBackgroundColor = overlayProvider.get().compositeOverlayWithThemeSurfaceColorIfNeeded(dpToPx(8f))
titleState = ALWAYS_SHOW
currentItem = startMenuIndex
isBehaviorTranslationEnabled = false
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageItem.kt
index 26568e22f..19d6ad1de 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageItem.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageItem.kt
@@ -9,6 +9,7 @@ import eu.davidea.flexibleadapter.items.IFlexible
import eu.davidea.viewholders.FlexibleViewHolder
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Message
+import io.github.wulkanowy.data.repositories.message.MessageFolder
import io.github.wulkanowy.utils.toFormattedString
import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.item_message.*
@@ -27,7 +28,7 @@ class MessageItem(val message: Message, private val noSubjectString: String) :
val style = if (message.unread) BOLD else NORMAL
messageItemAuthor.run {
- text = if (message.recipient.isNotBlank()) message.recipient else message.sender
+ text = if (message.folderId == MessageFolder.SENT.id) message.recipient else message.sender
setTypeface(null, style)
}
messageItemSubject.run {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt
index 4f881e8ff..22231e429 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt
@@ -65,6 +65,10 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl
presenter.onAttachView(this, (savedInstanceState ?: arguments)?.getLong(MESSAGE_ID_KEY) ?: 0L)
}
+ override fun initView() {
+ messagePreviewErrorDetails.setOnClickListener { presenter.onDetailsClick() }
+ }
+
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.action_menu_message_preview, menu)
menuReplyButton = menu.findItem(R.id.messagePreviewMenuReply)
@@ -126,8 +130,16 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl
menuDeleteButton?.setTitle(R.string.message_move_to_bin)
}
- override fun showMessageError() {
- messagePreviewError.visibility = VISIBLE
+ override fun showErrorView(show: Boolean) {
+ messagePreviewError.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun setErrorDetails(message: String) {
+ messagePreviewErrorMessage.text = message
+ }
+
+ override fun setErrorRetryCallback(callback: () -> Unit) {
+ messagePreviewErrorRetry.setOnClickListener { callback() }
}
override fun openMessageReply(message: Message?) {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt
index a230c0b3a..7b7404b86 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt
@@ -1,6 +1,7 @@
package io.github.wulkanowy.ui.modules.message.preview
import io.github.wulkanowy.data.db.entities.Message
+import io.github.wulkanowy.data.repositories.message.MessageFolder
import io.github.wulkanowy.data.repositories.message.MessageRepository
import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
@@ -23,11 +24,29 @@ class MessagePreviewPresenter @Inject constructor(
private var message: Message? = null
+ private lateinit var lastError: Throwable
+
+ private var retryCallback: () -> Unit = {}
+
fun onAttachView(view: MessagePreviewView, id: Long) {
super.onAttachView(view)
+ view.initView()
+ errorHandler.showErrorMessage = ::showErrorViewOnError
loadData(id)
}
+ private fun onMessageLoadRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
+ loadData(messageId)
+ }
+
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
+
private fun loadData(id: Long) {
Timber.i("Loading message $id preview started")
messageId = id
@@ -45,17 +64,17 @@ class MessagePreviewPresenter @Inject constructor(
message.let {
setSubject(if (it.subject.isNotBlank()) it.subject else noSubjectString)
setDate(it.date.toFormattedString("yyyy-MM-dd HH:mm:ss"))
- setContent(it.content.orEmpty())
+ setContent(it.content)
initOptions()
- if (it.recipient.isNotBlank()) setRecipient(it.recipient)
+ if (it.folderId == MessageFolder.SENT.id) setRecipient(it.recipient)
else setSender(it.sender)
}
}
- analytics.logEvent("load_message_preview", "length" to message.content?.length)
+ analytics.logEvent("load_message_preview", "length" to message.content.length)
}) {
Timber.i("Loading message $id preview result: An exception occurred ")
- view?.showMessageError()
+ retryCallback = { onMessageLoadRetry() }
errorHandler.dispatch(it)
})
}
@@ -85,6 +104,7 @@ class MessagePreviewPresenter @Inject constructor(
showContent(false)
showProgress(true)
showOptions(false)
+ showErrorView(false)
}
}
.doFinally {
@@ -97,15 +117,24 @@ class MessagePreviewPresenter @Inject constructor(
popView()
}
}, { error ->
- view?.showMessageError()
+ retryCallback = { onMessageDelete() }
errorHandler.dispatch(error)
}, {
- view?.showMessageError()
+ view?.showErrorView(true)
})
)
}
}
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ view?.run {
+ lastError = error
+ setErrorDetails(message)
+ showErrorView(true)
+ setErrorRetryCallback { retryCallback() }
+ }
+ }
+
fun onMessageDelete(): Boolean {
deleteMessage()
return true
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt
index 373dee11e..d57766273 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt
@@ -9,6 +9,8 @@ interface MessagePreviewView : BaseView {
val deleteMessageSuccessString: String
+ fun initView()
+
fun setSubject(subject: String)
fun setRecipient(recipient: String)
@@ -23,19 +25,23 @@ interface MessagePreviewView : BaseView {
fun showContent(show: Boolean)
+ fun notifyParentMessageDeleted(message: Message)
+
+ fun showErrorView(show: Boolean)
+
+ fun setErrorDetails(message: String)
+
+ fun setErrorRetryCallback(callback: () -> Unit)
+
fun showOptions(show: Boolean)
fun setDeletedOptionsLabels()
fun setNotDeletedOptionsLabels()
- fun showMessageError()
-
fun openMessageReply(message: Message?)
fun openMessageForward(message: Message?)
fun popView()
-
- fun notifyParentMessageDeleted(message: Message)
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt
index 326cd6a75..d6065983d 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt
@@ -72,6 +72,8 @@ class MessageTabFragment : BaseFragment(), MessageTabView {
)
}
messageTabSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
+ messageTabErrorRetry.setOnClickListener { presenter.onRetry() }
+ messageTabErrorDetails.setOnClickListener { presenter.onDetailsClick() }
}
override fun updateData(data: List) {
@@ -102,6 +104,14 @@ class MessageTabFragment : BaseFragment(), MessageTabView {
messageTabEmpty.visibility = if (show) VISIBLE else INVISIBLE
}
+ override fun showErrorView(show: Boolean) {
+ messageTabError.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun setErrorDetails(message: String) {
+ messageTabErrorMessage.text = message
+ }
+
override fun showRefresh(show: Boolean) {
messageTabSwipe.isRefreshing = show
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt
index af5762939..dc199207a 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt
@@ -4,6 +4,7 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.repositories.message.MessageFolder
import io.github.wulkanowy.data.repositories.message.MessageRepository
+import io.github.wulkanowy.data.repositories.semester.SemesterRepository
import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
@@ -18,14 +19,18 @@ class MessageTabPresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
private val messageRepository: MessageRepository,
+ private val semesterRepository: SemesterRepository,
private val analytics: FirebaseAnalyticsHelper
) : BasePresenter(errorHandler, studentRepository, schedulers) {
lateinit var folder: MessageFolder
+ private lateinit var lastError: Throwable
+
fun onAttachView(view: MessageTabView, folder: MessageFolder) {
super.onAttachView(view)
view.initView()
+ errorHandler.showErrorMessage = ::showErrorViewOnError
this.folder = folder
}
@@ -34,6 +39,18 @@ class MessageTabPresenter @Inject constructor(
onParentViewLoadData(true)
}
+ fun onRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
+ loadData(true)
+ }
+
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
+
fun onDeleteMessage() {
loadData(false)
}
@@ -61,8 +78,11 @@ class MessageTabPresenter @Inject constructor(
disposable.apply {
clear()
add(studentRepository.getCurrentStudent()
- .flatMap { messageRepository.getMessages(it, folder, forceRefresh) }
- .map { items -> items.map { MessageItem(it, view?.noSubjectString.orEmpty()) } }
+ .flatMap { student ->
+ semesterRepository.getCurrentSemester(student)
+ .flatMap { messageRepository.getMessages(student, it, folder, forceRefresh) }
+ .map { items -> items.map { MessageItem(it, view?.noSubjectString.orEmpty()) } }
+ }
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
.doFinally {
@@ -78,17 +98,28 @@ class MessageTabPresenter @Inject constructor(
view?.run {
showEmpty(it.isEmpty())
showContent(it.isNotEmpty())
+ showErrorView(false)
updateData(it)
}
analytics.logEvent("load_messages", "items" to it.size, "folder" to folder.name)
}) {
Timber.i("Loading $folder message result: An exception occurred")
- view?.run { showEmpty(isViewEmpty) }
errorHandler.dispatch(it)
})
}
}
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ view?.run {
+ if (isViewEmpty) {
+ lastError = error
+ setErrorDetails(message)
+ showErrorView(true)
+ showEmpty(false)
+ } else showError(message, error)
+ }
+ }
+
private fun updateMessage(message: Message) {
Timber.i("Attempt to update message ${message.id}")
disposable.add(messageRepository.updateMessage(message)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabView.kt
index 967863de4..e5705c739 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabView.kt
@@ -26,6 +26,10 @@ interface MessageTabView : BaseView {
fun showEmpty(show: Boolean)
+ fun showErrorView(show: Boolean)
+
+ fun setErrorDetails(message: String)
+
fun showRefresh(show: Boolean)
fun openMessage(messageId: Long)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceFragment.kt
index 1d9104a81..d47574f60 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceFragment.kt
@@ -61,6 +61,8 @@ class MobileDeviceFragment : BaseFragment(), MobileDeviceView, MainView.TitledVi
onDeviceUnregisterListener = presenter::onUnregisterDevice
}
mobileDevicesSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
+ mobileDevicesErrorRetry.setOnClickListener { presenter.onRetry() }
+ mobileDevicesErrorDetails.setOnClickListener { presenter.onDetailsClick() }
mobileDeviceAddButton.setOnClickListener { presenter.onRegisterDevice() }
}
@@ -105,6 +107,14 @@ class MobileDeviceFragment : BaseFragment(), MobileDeviceView, MainView.TitledVi
mobileDevicesEmpty.visibility = if (show) VISIBLE else GONE
}
+ override fun showErrorView(show: Boolean) {
+ mobileDevicesError.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun setErrorDetails(message: String) {
+ mobileDevicesErrorMessage.text = message
+ }
+
override fun enableSwipe(enable: Boolean) {
mobileDevicesSwipe.isEnabled = enable
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDevicePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDevicePresenter.kt
index 71359a52a..e95d2ce0e 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDevicePresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDevicePresenter.kt
@@ -20,10 +20,13 @@ class MobileDevicePresenter @Inject constructor(
private val analytics: FirebaseAnalyticsHelper
) : BasePresenter(errorHandler, studentRepository, schedulers) {
+ private lateinit var lastError: Throwable
+
override fun onAttachView(view: MobileDeviceView) {
super.onAttachView(view)
view.initView()
Timber.i("Mobile device view was initialized")
+ errorHandler.showErrorMessage = ::showErrorViewOnError
loadData()
}
@@ -31,6 +34,18 @@ class MobileDevicePresenter @Inject constructor(
loadData(true)
}
+ fun onRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
+ loadData(true)
+ }
+
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
+
private fun loadData(forceRefresh: Boolean = false) {
Timber.i("Loading mobile devices data started")
disposable.add(studentRepository.getCurrentStudent()
@@ -51,6 +66,7 @@ class MobileDevicePresenter @Inject constructor(
updateData(it)
showContent(it.isNotEmpty())
showEmpty(it.isEmpty())
+ showErrorView(false)
}
analytics.logEvent("load_devices", "items" to it.size, "force_refresh" to forceRefresh)
}) {
@@ -59,6 +75,17 @@ class MobileDevicePresenter @Inject constructor(
})
}
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ view?.run {
+ if (isViewEmpty) {
+ lastError = error
+ setErrorDetails(message)
+ showErrorView(true)
+ showEmpty(false)
+ } else showError(message, error)
+ }
+ }
+
fun onRegisterDevice() {
view?.showTokenDialog()
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceView.kt
index 58804e245..869b59bb1 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceView.kt
@@ -25,6 +25,10 @@ interface MobileDeviceView : BaseView {
fun showEmpty(show: Boolean)
+ fun showErrorView(show: Boolean)
+
+ fun setErrorDetails(message: String)
+
fun showUndo(position: Int, device: MobileDevice)
fun showTokenDialog()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenDialog.kt
index a1812ece7..8b81156b1 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenDialog.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenDialog.kt
@@ -12,15 +12,13 @@ import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.content.getSystemService
-import dagger.android.support.DaggerDialogFragment
import io.github.wulkanowy.R
import io.github.wulkanowy.data.pojos.MobileDeviceToken
-import io.github.wulkanowy.data.repositories.mobiledevice.MobileDeviceRemote
-import io.github.wulkanowy.ui.base.BaseActivity
+import io.github.wulkanowy.ui.base.BaseDialogFragment
import kotlinx.android.synthetic.main.dialog_mobile_device.*
import javax.inject.Inject
-class MobileDeviceTokenDialog : DaggerDialogFragment(), MobileDeviceTokenVIew {
+class MobileDeviceTokenDialog : BaseDialogFragment(), MobileDeviceTokenVIew {
@Inject
lateinit var presenter: MobileDeviceTokenPresenter
@@ -66,6 +64,12 @@ class MobileDeviceTokenDialog : DaggerDialogFragment(), MobileDeviceTokenVIew {
})
}
+ private fun clickCopy(text: String) {
+ val clip = ClipData.newPlainText("wulkanowy", text)
+ activity?.getSystemService()?.setPrimaryClip(clip)
+ Toast.makeText(context, R.string.all_copied, Toast.LENGTH_LONG).show()
+ }
+
override fun hideLoading() {
mobileDeviceDialogProgress.visibility = GONE
}
@@ -78,30 +82,8 @@ class MobileDeviceTokenDialog : DaggerDialogFragment(), MobileDeviceTokenVIew {
dismiss()
}
- override fun showError(text: String, error: Throwable) {
- showMessage(text)
- }
-
- override fun showMessage(text: String) {
- Toast.makeText(context, text, Toast.LENGTH_LONG).show()
- }
-
- override fun showExpiredDialog() {
- (activity as? BaseActivity<*>)?.showExpiredDialog()
- }
-
- override fun openClearLoginView() {
- (activity as? BaseActivity<*>)?.openClearLoginView()
- }
-
override fun onDestroyView() {
presenter.onDetachView()
super.onDestroyView()
}
-
- fun clickCopy(text: String) {
- val clip = ClipData.newPlainText("wulkanowy", text)
- activity?.getSystemService()?.setPrimaryClip(clip)
- Toast.makeText(context, R.string.all_copied, Toast.LENGTH_LONG).show()
- }
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreFragment.kt
index 7a9625c04..ef9c36fab 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreFragment.kt
@@ -20,7 +20,6 @@ import io.github.wulkanowy.ui.modules.mobiledevice.MobileDeviceFragment
import io.github.wulkanowy.ui.modules.note.NoteFragment
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersFragment
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
-import io.github.wulkanowy.ui.modules.schoolandteachers.teacher.TeacherFragment
import io.github.wulkanowy.utils.getCompatDrawable
import io.github.wulkanowy.utils.setOnItemClickListener
import kotlinx.android.synthetic.main.fragment_more.*
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt
index 6117ae244..e5335e459 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt
@@ -60,6 +60,8 @@ class NoteFragment : BaseFragment(), NoteView, MainView.TitledView {
)
}
noteSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
+ noteErrorRetry.setOnClickListener { presenter.onRetry() }
+ noteErrorDetails.setOnClickListener { presenter.onDetailsClick() }
}
override fun showNoteDialog(note: Note) {
@@ -82,6 +84,14 @@ class NoteFragment : BaseFragment(), NoteView, MainView.TitledView {
noteEmpty.visibility = if (show) VISIBLE else GONE
}
+ override fun showErrorView(show: Boolean) {
+ noteError.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun setErrorDetails(message: String) {
+ noteErrorMessage.text = message
+ }
+
override fun showProgress(show: Boolean) {
noteProgress.visibility = if (show) VISIBLE else GONE
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NotePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NotePresenter.kt
index df98ab889..7acf37a4c 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NotePresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NotePresenter.kt
@@ -21,10 +21,13 @@ class NotePresenter @Inject constructor(
private val analytics: FirebaseAnalyticsHelper
) : BasePresenter(errorHandler, studentRepository, schedulers) {
+ private lateinit var lastError: Throwable
+
override fun onAttachView(view: NoteView) {
super.onAttachView(view)
view.initView()
Timber.i("Note view was initialized")
+ errorHandler.showErrorMessage = ::showErrorViewOnError
loadData()
}
@@ -33,6 +36,18 @@ class NotePresenter @Inject constructor(
loadData(true)
}
+ fun onRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
+ loadData(true)
+ }
+
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
+
private fun loadData(forceRefresh: Boolean = false) {
Timber.i("Loading note data started")
disposable.add(studentRepository.getCurrentStudent()
@@ -53,17 +68,28 @@ class NotePresenter @Inject constructor(
view?.apply {
updateData(it)
showEmpty(it.isEmpty())
+ showErrorView(false)
showContent(it.isNotEmpty())
}
analytics.logEvent("load_note", "items" to it.size, "force_refresh" to forceRefresh)
}, {
Timber.i("Loading note result: An exception occurred")
- view?.run { showEmpty(isViewEmpty) }
errorHandler.dispatch(it)
})
)
}
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ view?.run {
+ if (isViewEmpty) {
+ lastError = error
+ setErrorDetails(message)
+ showErrorView(true)
+ showEmpty(false)
+ } else showError(message, error)
+ }
+ }
+
fun onNoteItemSelected(item: AbstractFlexibleItem<*>?) {
if (item is NoteItem) {
Timber.i("Select note item ${item.note.id}")
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteView.kt
index 9a2c12ebf..a9c9f4f2f 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteView.kt
@@ -18,6 +18,10 @@ interface NoteView : BaseView {
fun showEmpty(show: Boolean)
+ fun showErrorView(show: Boolean)
+
+ fun setErrorDetails(message: String)
+
fun showProgress(show: Boolean)
fun enableSwipe(enable: Boolean)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolFragment.kt
index 92f74ca89..5a7c4cade 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolFragment.kt
@@ -3,6 +3,8 @@ package io.github.wulkanowy.ui.modules.schoolandteachers.school
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
import android.view.ViewGroup
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.School
@@ -10,8 +12,8 @@ import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersChildView
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersFragment
-import io.github.wulkanowy.utils.dialPhone
-import io.github.wulkanowy.utils.openMapLocation
+import io.github.wulkanowy.utils.openDialer
+import io.github.wulkanowy.utils.openNavigation
import kotlinx.android.synthetic.main.fragment_school.*
import javax.inject.Inject
@@ -22,6 +24,8 @@ class SchoolFragment : BaseFragment(), SchoolView, MainView.TitledView, SchoolAn
override val titleStringId get() = R.string.school_title
+ override val isViewEmpty get() = schoolName.text.isBlank()
+
companion object {
fun newInstance() = SchoolFragment()
}
@@ -37,6 +41,8 @@ class SchoolFragment : BaseFragment(), SchoolView, MainView.TitledView, SchoolAn
override fun initView() {
schoolSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
+ schoolErrorRetry.setOnClickListener { presenter.onRetry() }
+ schoolErrorDetails.setOnClickListener { presenter.onDetailsClick() }
schoolAddressButton.setOnClickListener { presenter.onAddressSelected() }
schoolTelephoneButton.setOnClickListener { presenter.onTelephoneSelected() }
@@ -45,19 +51,27 @@ class SchoolFragment : BaseFragment(), SchoolView, MainView.TitledView, SchoolAn
override fun updateData(data: School) {
schoolName.text = data.name
schoolAddress.text = data.address.ifBlank { "-" }
- schoolAddressButton.visibility = if (data.address.isNotBlank()) View.VISIBLE else View.GONE
+ schoolAddressButton.visibility = if (data.address.isNotBlank()) VISIBLE else GONE
schoolTelephone.text = data.contact.ifBlank { "-" }
- schoolTelephoneButton.visibility = if (data.contact.isNotBlank()) View.VISIBLE else View.GONE
+ schoolTelephoneButton.visibility = if (data.contact.isNotBlank()) VISIBLE else GONE
schoolHeadmaster.text = data.headmaster
schoolPedagogue.text = data.pedagogue
}
override fun showEmpty(show: Boolean) {
- schoolEmpty.visibility = if (show) View.VISIBLE else View.GONE
+ schoolEmpty.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun showErrorView(show: Boolean) {
+ schoolError.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun setErrorDetails(message: String) {
+ schoolErrorMessage.text = message
}
override fun showProgress(show: Boolean) {
- schoolProgress.visibility = if (show) View.VISIBLE else View.GONE
+ schoolProgress.visibility = if (show) VISIBLE else GONE
}
override fun enableSwipe(enable: Boolean) {
@@ -65,7 +79,7 @@ class SchoolFragment : BaseFragment(), SchoolView, MainView.TitledView, SchoolAn
}
override fun showContent(show: Boolean) {
- schoolContent.visibility = if (show) View.VISIBLE else View.GONE
+ schoolContent.visibility = if (show) VISIBLE else GONE
}
override fun hideRefresh() {
@@ -86,10 +100,10 @@ class SchoolFragment : BaseFragment(), SchoolView, MainView.TitledView, SchoolAn
}
override fun openMapsLocation(location: String) {
- context?.openMapLocation(location)
+ context?.openNavigation(location)
}
override fun dialPhone(phone: String) {
- context?.dialPhone(phone)
+ context?.openDialer(phone)
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolPresenter.kt
index 2b0a37b1c..d3299d90d 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolPresenter.kt
@@ -23,10 +23,13 @@ class SchoolPresenter @Inject constructor(
private var contact: String? = null
+ private lateinit var lastError: Throwable
+
override fun onAttachView(view: SchoolView) {
super.onAttachView(view)
view.initView()
Timber.i("School view was initialized")
+ errorHandler.showErrorMessage = ::showErrorViewOnError
loadData()
}
@@ -34,12 +37,24 @@ class SchoolPresenter @Inject constructor(
loadData(true)
}
+ fun onRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
+ loadData(true)
+ }
+
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
+
fun onParentViewLoadData(forceRefresh: Boolean) {
loadData(forceRefresh)
}
fun onAddressSelected() {
- address?.let{ view?.openMapsLocation(it) }
+ address?.let { view?.openMapsLocation(it) }
}
fun onTelephoneSelected() {
@@ -68,6 +83,7 @@ class SchoolPresenter @Inject constructor(
updateData(it)
showContent(true)
showEmpty(false)
+ showErrorView(false)
}
analytics.logEvent("load_school", "force_refresh" to forceRefresh)
}, {
@@ -76,9 +92,22 @@ class SchoolPresenter @Inject constructor(
}, {
Timber.i("Loading school result: No school info found")
view?.run {
- showContent(false)
- showEmpty(true)
+ showContent(!isViewEmpty)
+ showEmpty(isViewEmpty)
+ showErrorView(false)
}
}))
}
+
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ view?.run {
+ if (isViewEmpty) {
+ lastError = error
+ setErrorDetails(message)
+ showErrorView(true)
+ showEmpty(false)
+ showContent(false)
+ } else showError(message, error)
+ }
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolView.kt
index 39e7b805c..c42c2f91b 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolView.kt
@@ -6,12 +6,18 @@ import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersChildVi
interface SchoolView : BaseView, SchoolAndTeachersChildView {
+ val isViewEmpty: Boolean
+
fun initView()
fun updateData(data: School)
fun showEmpty(show: Boolean)
+ fun showErrorView(show: Boolean)
+
+ fun setErrorDetails(message: String)
+
fun showProgress(show: Boolean)
fun enableSwipe(enable: Boolean)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherFragment.kt
index 842e50fe1..b6bb9c101 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherFragment.kt
@@ -3,6 +3,8 @@ package io.github.wulkanowy.ui.modules.schoolandteachers.teacher
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
import android.view.ViewGroup
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.common.FlexibleItemDecoration
@@ -16,7 +18,8 @@ import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersFragmen
import kotlinx.android.synthetic.main.fragment_teacher.*
import javax.inject.Inject
-class TeacherFragment : BaseFragment(), TeacherView, MainView.TitledView, SchoolAndTeachersChildView {
+class TeacherFragment : BaseFragment(), TeacherView, MainView.TitledView,
+ SchoolAndTeachersChildView {
@Inject
lateinit var presenter: TeacherPresenter
@@ -55,6 +58,8 @@ class TeacherFragment : BaseFragment(), TeacherView, MainView.TitledView, School
)
}
teacherSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
+ teacherErrorRetry.setOnClickListener { presenter.onRetry() }
+ teacherErrorDetails.setOnClickListener { presenter.onDetailsClick() }
}
override fun updateData(data: List) {
@@ -70,11 +75,19 @@ class TeacherFragment : BaseFragment(), TeacherView, MainView.TitledView, School
}
override fun showEmpty(show: Boolean) {
- teacherEmpty.visibility = if (show) View.VISIBLE else View.GONE
+ teacherEmpty.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun showErrorView(show: Boolean) {
+ teacherError.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun setErrorDetails(message: String) {
+ teacherErrorMessage.text = message
}
override fun showProgress(show: Boolean) {
- teacherProgress.visibility = if (show) View.VISIBLE else View.GONE
+ teacherProgress.visibility = if (show) VISIBLE else GONE
}
override fun enableSwipe(enable: Boolean) {
@@ -82,7 +95,7 @@ class TeacherFragment : BaseFragment(), TeacherView, MainView.TitledView, School
}
override fun showContent(show: Boolean) {
- teacherRecycler.visibility = if (show) View.VISIBLE else View.GONE
+ teacherRecycler.visibility = if (show) VISIBLE else GONE
}
override fun hideRefresh() {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherPresenter.kt
index aabcff287..6aa4871d2 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherPresenter.kt
@@ -19,10 +19,13 @@ class TeacherPresenter @Inject constructor(
private val analytics: FirebaseAnalyticsHelper
) : BasePresenter(errorHandler, studentRepository, schedulers) {
+ private lateinit var lastError: Throwable
+
override fun onAttachView(view: TeacherView) {
super.onAttachView(view)
view.initView()
Timber.i("Teacher view was initialized")
+ errorHandler.showErrorMessage = ::showErrorViewOnError
loadData()
}
@@ -30,6 +33,18 @@ class TeacherPresenter @Inject constructor(
loadData(true)
}
+ fun onRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
+ loadData(true)
+ }
+
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
+
fun onParentViewLoadData(forceRefresh: Boolean) {
loadData(forceRefresh)
}
@@ -56,6 +71,7 @@ class TeacherPresenter @Inject constructor(
updateData(it)
showContent(it.isNotEmpty())
showEmpty(it.isEmpty())
+ showErrorView(false)
}
analytics.logEvent("load_teachers", "items" to it.size, "force_refresh" to forceRefresh)
}) {
@@ -63,4 +79,15 @@ class TeacherPresenter @Inject constructor(
errorHandler.dispatch(it)
})
}
+
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ view?.run {
+ if (isViewEmpty) {
+ lastError = error
+ setErrorDetails(message)
+ showErrorView(true)
+ showEmpty(false)
+ } else showError(message, error)
+ }
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherView.kt
index 2cc1139cc..b16be8ff9 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherView.kt
@@ -27,4 +27,8 @@ interface TeacherView : BaseView, SchoolAndTeachersChildView {
fun showContent(show: Boolean)
fun showEmpty(show: Boolean)
+
+ fun showErrorView(show: Boolean)
+
+ fun setErrorDetails(message: String)
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt
index cb172b98b..03a89d274 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt
@@ -5,14 +5,17 @@ import android.content.SharedPreferences
import android.os.Bundle
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
+import com.yariksoffice.lingver.Lingver
import dagger.android.support.AndroidSupportInjection
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseActivity
+import io.github.wulkanowy.ui.base.ErrorDialog
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.utils.AppInfo
import javax.inject.Inject
-class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener,
+class SettingsFragment : PreferenceFragmentCompat(),
+ SharedPreferences.OnSharedPreferenceChangeListener,
MainView.TitledView, SettingsView {
@Inject
@@ -21,6 +24,9 @@ class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedP
@Inject
lateinit var appInfo: AppInfo
+ @Inject
+ lateinit var lingver: Lingver
+
companion object {
fun newInstance() = SettingsFragment()
}
@@ -50,6 +56,10 @@ class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedP
activity?.recreate()
}
+ override fun updateLanguage(langCode: String) {
+ lingver.setLocale(requireContext(), langCode)
+ }
+
override fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean) {
findPreference(serviceEnablesKey)?.apply {
summary = if (isHolidays) getString(R.string.pref_services_suspended) else ""
@@ -73,6 +83,10 @@ class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedP
(activity as? BaseActivity<*>)?.openClearLoginView()
}
+ override fun showErrorDetailsDialog(error: Throwable) {
+ ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
+ }
+
override fun onResume() {
super.onResume()
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt
index 88d38e0d2..89ba0ee5e 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt
@@ -6,6 +6,7 @@ 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.AppInfo
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.github.wulkanowy.utils.SchedulersProvider
import io.github.wulkanowy.utils.isHolidays
@@ -20,7 +21,8 @@ class SettingsPresenter @Inject constructor(
private val preferencesRepository: PreferencesRepository,
private val analytics: FirebaseAnalyticsHelper,
private val syncManager: SyncManager,
- private val chuckCollector: ChuckCollector
+ private val chuckCollector: ChuckCollector,
+ private val appInfo: AppInfo
) : BasePresenter(errorHandler, studentRepository, schedulers) {
override fun onAttachView(view: SettingsView) {
@@ -38,6 +40,10 @@ class SettingsPresenter @Inject constructor(
servicesIntervalKey, servicesOnlyWifiKey -> syncManager.startSyncWorker(true)
isDebugNotificationEnableKey -> chuckCollector.showNotification(isDebugNotificationEnable)
appThemeKey -> view?.recreateView()
+ appLanguageKey -> view?.run {
+ updateLanguage(if (appLanguage == "system") appInfo.systemLanguage else appLanguage)
+ recreateView()
+ }
else -> Unit
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsView.kt
index 1c4bf3b0b..e50eb47b3 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsView.kt
@@ -6,5 +6,7 @@ interface SettingsView : BaseView {
fun recreateView()
+ fun updateLanguage(langCode: String)
+
fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean)
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt
index a64dee8d8..ef6057dfa 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt
@@ -6,7 +6,10 @@ import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
import android.view.ViewGroup
+import com.wdullaer.materialdatetimepicker.date.DatePickerDialog
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.common.FlexibleItemDecoration
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
@@ -17,9 +20,11 @@ import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.ui.modules.timetable.completed.CompletedLessonsFragment
+import io.github.wulkanowy.utils.SchooldaysRangeLimiter
import io.github.wulkanowy.utils.dpToPx
import io.github.wulkanowy.utils.setOnItemClickListener
import kotlinx.android.synthetic.main.fragment_timetable.*
+import org.threeten.bp.LocalDate
import javax.inject.Inject
class TimetableFragment : BaseFragment(), TimetableView, MainView.MainChildView,
@@ -71,7 +76,11 @@ class TimetableFragment : BaseFragment(), TimetableView, MainView.MainChildView,
}
timetableSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
+ timetableErrorRetry.setOnClickListener { presenter.onRetry() }
+ timetableErrorDetails.setOnClickListener { presenter.onDetailsClick() }
+
timetablePreviousButton.setOnClickListener { presenter.onPreviousDay() }
+ timetableNavDate.setOnClickListener { presenter.onPickDate() }
timetableNextButton.setOnClickListener { presenter.onNextDay() }
timetableNavContainer.setElevationCompat(requireContext().dpToPx(8f))
@@ -115,11 +124,19 @@ class TimetableFragment : BaseFragment(), TimetableView, MainView.MainChildView,
}
override fun showEmpty(show: Boolean) {
- timetableEmpty.visibility = if (show) View.VISIBLE else View.GONE
+ timetableEmpty.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun showErrorView(show: Boolean) {
+ timetableError.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun setErrorDetails(message: String) {
+ timetableErrorMessage.text = message
}
override fun showProgress(show: Boolean) {
- timetableProgress.visibility = if (show) View.VISIBLE else View.GONE
+ timetableProgress.visibility = if (show) VISIBLE else GONE
}
override fun enableSwipe(enable: Boolean) {
@@ -127,21 +144,36 @@ class TimetableFragment : BaseFragment(), TimetableView, MainView.MainChildView,
}
override fun showContent(show: Boolean) {
- timetableRecycler.visibility = if (show) View.VISIBLE else View.GONE
+ timetableRecycler.visibility = if (show) VISIBLE else GONE
}
override fun showPreButton(show: Boolean) {
- timetablePreviousButton.visibility = if (show) View.VISIBLE else View.INVISIBLE
+ timetablePreviousButton.visibility = if (show) VISIBLE else View.INVISIBLE
}
override fun showNextButton(show: Boolean) {
- timetableNextButton.visibility = if (show) View.VISIBLE else View.INVISIBLE
+ timetableNextButton.visibility = if (show) VISIBLE else View.INVISIBLE
}
override fun showTimetableDialog(lesson: Timetable) {
(activity as? MainActivity)?.showDialogFragment(TimetableDialog.newInstance(lesson))
}
+ override fun showDatePickerDialog(currentDate: LocalDate) {
+ val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
+ presenter.onDateSet(year, month + 1, dayOfMonth)
+ }
+ val datePickerDialog = DatePickerDialog.newInstance(dateSetListener,
+ currentDate.year, currentDate.monthValue - 1, currentDate.dayOfMonth)
+
+ with(datePickerDialog) {
+ setDateRangeLimiter(SchooldaysRangeLimiter())
+ version = DatePickerDialog.Version.VERSION_2
+ scrollOrientation = DatePickerDialog.ScrollOrientation.VERTICAL
+ show(this@TimetableFragment.parentFragmentManager, null)
+ }
+ }
+
override fun openCompletedLessonsView() {
(activity as? MainActivity)?.pushView(CompletedLessonsFragment.newInstance())
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt
index cea5bf2f5..4c30ecb7f 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt
@@ -17,6 +17,7 @@ import io.github.wulkanowy.utils.previousSchoolDay
import io.github.wulkanowy.utils.toFormattedString
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDate.now
+import org.threeten.bp.LocalDate.of
import org.threeten.bp.LocalDate.ofEpochDay
import timber.log.Timber
import java.util.concurrent.TimeUnit.MILLISECONDS
@@ -36,10 +37,13 @@ class TimetablePresenter @Inject constructor(
lateinit var currentDate: LocalDate
private set
+ private lateinit var lastError: Throwable
+
fun onAttachView(view: TimetableView, date: Long?) {
super.onAttachView(view)
view.initView()
Timber.i("Timetable was initialized")
+ errorHandler.showErrorMessage = ::showErrorViewOnError
loadData(ofEpochDay(date ?: baseDate.toEpochDay()))
if (currentDate.isHolidays) setBaseDateOnHolidays()
reloadView()
@@ -55,11 +59,32 @@ class TimetablePresenter @Inject constructor(
reloadView()
}
+ fun onPickDate() {
+ view?.showDatePickerDialog(currentDate)
+ }
+
+ fun onDateSet(year: Int, month: Int, day: Int) {
+ loadData(of(year, month, day))
+ reloadView()
+ }
+
fun onSwipeRefresh() {
Timber.i("Force refreshing the timetable")
loadData(currentDate, true)
}
+ fun onRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
+ loadData(currentDate, true)
+ }
+
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
+
fun onViewReselected() {
Timber.i("Timetable view is reselected")
view?.also { view ->
@@ -125,17 +150,28 @@ class TimetablePresenter @Inject constructor(
view?.apply {
updateData(it)
showEmpty(it.isEmpty())
+ showErrorView(false)
showContent(it.isNotEmpty())
}
analytics.logEvent("load_timetable", "items" to it.size, "force_refresh" to forceRefresh)
}) {
Timber.i("Loading timetable result: An exception occurred")
- view?.run { showEmpty(isViewEmpty) }
errorHandler.dispatch(it)
})
}
}
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ view?.run {
+ if (isViewEmpty) {
+ lastError = error
+ setErrorDetails(message)
+ showErrorView(true)
+ showEmpty(false)
+ } else showError(message, error)
+ }
+ }
+
private fun reloadView() {
Timber.i("Reload timetable view with the date ${currentDate.toFormattedString()}")
view?.apply {
@@ -143,6 +179,7 @@ class TimetablePresenter @Inject constructor(
enableSwipe(false)
showContent(false)
showEmpty(false)
+ showErrorView(false)
clearData()
reloadNavigation()
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableView.kt
index 84f28974f..f730a2712 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableView.kt
@@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.timetable
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.ui.base.BaseView
+import org.threeten.bp.LocalDate
interface TimetableView : BaseView {
@@ -23,6 +24,10 @@ interface TimetableView : BaseView {
fun showEmpty(show: Boolean)
+ fun showErrorView(show: Boolean)
+
+ fun setErrorDetails(message: String)
+
fun showProgress(show: Boolean)
fun enableSwipe(enable: Boolean)
@@ -35,6 +40,8 @@ interface TimetableView : BaseView {
fun showTimetableDialog(lesson: Timetable)
+ fun showDatePickerDialog(currentDate: LocalDate)
+
fun popView()
fun openCompletedLessonsView()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsErrorHandler.kt
index ed11607cd..1d043af3a 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsErrorHandler.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsErrorHandler.kt
@@ -2,7 +2,7 @@ package io.github.wulkanowy.ui.modules.timetable.completed
import android.content.res.Resources
import com.readystatesoftware.chuck.api.ChuckCollector
-import io.github.wulkanowy.api.interceptor.FeatureDisabledException
+import io.github.wulkanowy.sdk.exception.FeatureDisabledException
import io.github.wulkanowy.ui.base.ErrorHandler
import javax.inject.Inject
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt
index c7b5c6ca1..60c16b2dc 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt
@@ -3,7 +3,11 @@ package io.github.wulkanowy.ui.modules.timetable.completed
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 com.wdullaer.materialdatetimepicker.date.DatePickerDialog
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
@@ -12,10 +16,12 @@ import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainView
+import io.github.wulkanowy.utils.SchooldaysRangeLimiter
import io.github.wulkanowy.utils.dpToPx
import io.github.wulkanowy.utils.getCompatDrawable
import io.github.wulkanowy.utils.setOnItemClickListener
import kotlinx.android.synthetic.main.fragment_timetable_completed.*
+import org.threeten.bp.LocalDate
import javax.inject.Inject
class CompletedLessonsFragment : BaseFragment(), CompletedLessonsView, MainView.TitledView {
@@ -55,7 +61,11 @@ class CompletedLessonsFragment : BaseFragment(), CompletedLessonsView, MainView.
}
completedLessonsSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
+ completedLessonErrorRetry.setOnClickListener { presenter.onRetry() }
+ completedLessonErrorDetails.setOnClickListener { presenter.onDetailsClick() }
+
completedLessonsPreviousButton.setOnClickListener { presenter.onPreviousDay() }
+ completedLessonsNavDate.setOnClickListener { presenter.onPickDate() }
completedLessonsNextButton.setOnClickListener { presenter.onNextDay() }
completedLessonsNavContainer.setElevationCompat(requireContext().dpToPx(8f))
@@ -78,7 +88,15 @@ class CompletedLessonsFragment : BaseFragment(), CompletedLessonsView, MainView.
}
override fun showEmpty(show: Boolean) {
- completedLessonsEmpty.visibility = if (show) View.VISIBLE else View.GONE
+ completedLessonsEmpty.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun showErrorView(show: Boolean) {
+ completedLessonError.visibility = if (show) VISIBLE else GONE
+ }
+
+ override fun setErrorDetails(message: String) {
+ completedLessonErrorMessage.text = message
}
override fun showFeatureDisabled() {
@@ -87,7 +105,7 @@ class CompletedLessonsFragment : BaseFragment(), CompletedLessonsView, MainView.
}
override fun showProgress(show: Boolean) {
- completedLessonsProgress.visibility = if (show) View.VISIBLE else View.GONE
+ completedLessonsProgress.visibility = if (show) VISIBLE else GONE
}
override fun enableSwipe(enable: Boolean) {
@@ -95,21 +113,36 @@ class CompletedLessonsFragment : BaseFragment(), CompletedLessonsView, MainView.
}
override fun showContent(show: Boolean) {
- completedLessonsRecycler.visibility = if (show) View.VISIBLE else View.GONE
+ completedLessonsRecycler.visibility = if (show) VISIBLE else GONE
}
override fun showPreButton(show: Boolean) {
- completedLessonsPreviousButton.visibility = if (show) View.VISIBLE else View.INVISIBLE
+ completedLessonsPreviousButton.visibility = if (show) VISIBLE else INVISIBLE
}
override fun showNextButton(show: Boolean) {
- completedLessonsNextButton.visibility = if (show) View.VISIBLE else View.INVISIBLE
+ completedLessonsNextButton.visibility = if (show) VISIBLE else INVISIBLE
}
override fun showCompletedLessonDialog(completedLesson: CompletedLesson) {
(activity as? MainActivity)?.showDialogFragment(CompletedLessonDialog.newInstance(completedLesson))
}
+ override fun showDatePickerDialog(currentDate: LocalDate) {
+ val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
+ presenter.onDateSet(year, month + 1, dayOfMonth)
+ }
+ val datePickerDialog = DatePickerDialog.newInstance(dateSetListener,
+ currentDate.year, currentDate.monthValue - 1, currentDate.dayOfMonth)
+
+ with(datePickerDialog) {
+ setDateRangeLimiter(SchooldaysRangeLimiter())
+ version = DatePickerDialog.Version.VERSION_2
+ scrollOrientation = DatePickerDialog.ScrollOrientation.VERTICAL
+ show(this@CompletedLessonsFragment.parentFragmentManager, null)
+ }
+ }
+
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsPresenter.kt
index b936c6576..e2b569508 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsPresenter.kt
@@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.timetable.completed
+import android.annotation.SuppressLint
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.data.repositories.completedlessons.CompletedLessonsRepository
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
@@ -34,17 +35,20 @@ class CompletedLessonsPresenter @Inject constructor(
lateinit var currentDate: LocalDate
private set
+ private lateinit var lastError: Throwable
+
fun onAttachView(view: CompletedLessonsView, date: Long?) {
super.onAttachView(view)
Timber.i("Completed lessons is attached")
view.initView()
- loadData(ofEpochDay(date ?: baseDate.toEpochDay()))
- if (currentDate.isHolidays) setBaseDateOnHolidays()
- reloadView()
+ completedLessonsErrorHandler.showErrorMessage = ::showErrorViewOnError
completedLessonsErrorHandler.onFeatureDisabled = {
this.view?.showFeatureDisabled()
Timber.i("Completed lessons feature disabled by school")
}
+ loadData(ofEpochDay(date ?: baseDate.toEpochDay()))
+ if (currentDate.isHolidays) setBaseDateOnHolidays()
+ reloadView()
}
fun onPreviousDay() {
@@ -57,11 +61,32 @@ class CompletedLessonsPresenter @Inject constructor(
reloadView()
}
+ fun onPickDate() {
+ view?.showDatePickerDialog(currentDate)
+ }
+
+ fun onDateSet(year: Int, month: Int, day: Int) {
+ loadData(LocalDate.of(year, month, day))
+ reloadView()
+ }
+
fun onSwipeRefresh() {
Timber.i("Force refreshing the completed lessons")
loadData(currentDate, true)
}
+ fun onRetry() {
+ view?.run {
+ showErrorView(false)
+ showProgress(true)
+ }
+ loadData(currentDate, true)
+ }
+
+ fun onDetailsClick() {
+ view?.showErrorDetailsDialog(lastError)
+ }
+
fun onCompletedLessonsItemSelected(item: AbstractFlexibleItem<*>?) {
if (item is CompletedLessonItem) {
Timber.i("Select completed lessons item ${item.completedLesson.id}")
@@ -108,17 +133,28 @@ class CompletedLessonsPresenter @Inject constructor(
view?.apply {
updateData(it)
showEmpty(it.isEmpty())
+ showErrorView(false)
showContent(it.isNotEmpty())
}
analytics.logEvent("load_completed_lessons", "items" to it.size, "force_refresh" to forceRefresh)
}) {
Timber.i("Loading completed lessons result: An exception occurred")
- view?.run { showEmpty(isViewEmpty) }
completedLessonsErrorHandler.dispatch(it)
})
}
}
+ private fun showErrorViewOnError(message: String, error: Throwable) {
+ view?.run {
+ if (isViewEmpty) {
+ lastError = error
+ setErrorDetails(message)
+ showErrorView(true)
+ showEmpty(false)
+ } else showError(message, error)
+ }
+ }
+
private fun reloadView() {
Timber.i("Reload completed lessons view with the date ${currentDate.toFormattedString()}")
view?.apply {
@@ -126,11 +162,13 @@ class CompletedLessonsPresenter @Inject constructor(
enableSwipe(false)
showContent(false)
showEmpty(false)
+ showErrorView(false)
clearData()
reloadNavigation()
}
}
+ @SuppressLint("DefaultLocale")
private fun reloadNavigation() {
view?.apply {
showPreButton(!currentDate.minusDays(1).isHolidays)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsView.kt
index a8bef66f1..a6a327e2d 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsView.kt
@@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.timetable.completed
import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.ui.base.BaseView
+import org.threeten.bp.LocalDate
interface CompletedLessonsView : BaseView {
@@ -19,6 +20,10 @@ interface CompletedLessonsView : BaseView {
fun showEmpty(show: Boolean)
+ fun showErrorView(show: Boolean)
+
+ fun setErrorDetails(message: String)
+
fun showFeatureDisabled()
fun showProgress(show: Boolean)
@@ -32,4 +37,6 @@ interface CompletedLessonsView : BaseView {
fun showNextButton(show: Boolean)
fun showCompletedLessonDialog(completedLesson: CompletedLesson)
+
+ fun showDatePickerDialog(currentDate: LocalDate)
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt
index 0030ee54a..62192a1b0 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt
@@ -28,7 +28,6 @@ import io.github.wulkanowy.utils.SchedulersProvider
import io.github.wulkanowy.utils.nextOrSameSchoolDay
import io.github.wulkanowy.utils.nextSchoolDay
import io.github.wulkanowy.utils.previousSchoolDay
-import io.github.wulkanowy.utils.shortcutWeekDayName
import io.github.wulkanowy.utils.toFormattedString
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
diff --git a/app/src/main/java/io/github/wulkanowy/ui/widgets/MaterialLinearLayout.kt b/app/src/main/java/io/github/wulkanowy/ui/widgets/MaterialLinearLayout.kt
index cad26f2e8..a04922e5d 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/widgets/MaterialLinearLayout.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/widgets/MaterialLinearLayout.kt
@@ -33,7 +33,7 @@ class MaterialLinearLayout : LinearLayout {
if (SDK_INT >= LOLLIPOP) {
setElevation(elevation)
} else {
- setBackgroundColor(ElevationOverlayProvider(context).getSurfaceColorWithOverlayIfNeeded(elevation))
+ setBackgroundColor(ElevationOverlayProvider(context).compositeOverlayWithThemeSurfaceColorIfNeeded(elevation))
}
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/widgets/MaterialTabLayout.kt b/app/src/main/java/io/github/wulkanowy/ui/widgets/MaterialTabLayout.kt
index 3bcaae7d7..e19d01116 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/widgets/MaterialTabLayout.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/widgets/MaterialTabLayout.kt
@@ -19,7 +19,7 @@ open class MaterialTabLayout : TabLayout {
if (SDK_INT >= LOLLIPOP) {
setElevation(elevation)
} else {
- setBackgroundColor(ElevationOverlayProvider(context).getSurfaceColorWithOverlayIfNeeded(elevation))
+ setBackgroundColor(ElevationOverlayProvider(context).compositeOverlayWithThemeSurfaceColorIfNeeded(elevation))
}
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/utils/AppInfo.kt b/app/src/main/java/io/github/wulkanowy/utils/AppInfo.kt
index 3fa83a043..a444da6fe 100644
--- a/app/src/main/java/io/github/wulkanowy/utils/AppInfo.kt
+++ b/app/src/main/java/io/github/wulkanowy/utils/AppInfo.kt
@@ -1,5 +1,6 @@
package io.github.wulkanowy.utils
+import android.content.res.Resources
import android.os.Build.MANUFACTURER
import android.os.Build.MODEL
import android.os.Build.VERSION.SDK_INT
@@ -25,4 +26,8 @@ open class AppInfo {
open val systemManufacturer: String get() = MANUFACTURER
open val systemModel: String get() = MODEL
+
+ @Suppress("DEPRECATION")
+ open val systemLanguage: String
+ get() = Resources.getSystem().configuration.locale.language
}
diff --git a/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt
index 5110b0674..a265378e2 100644
--- a/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt
+++ b/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt
@@ -32,7 +32,7 @@ fun Context.openInternetBrowser(uri: String, onActivityNotFound: (uri: String) -
}
}
-fun Context.openEmail(chooserTitle: String, email: String, subject: String?, body: String?) {
+fun Context.openEmailClient(chooserTitle: String, email: String, subject: String?, body: String?) {
val emailIntent = Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", email, null))
emailIntent.putExtra(Intent.EXTRA_EMAIL, arrayOf(email))
if (subject != null) emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject)
@@ -40,7 +40,7 @@ fun Context.openEmail(chooserTitle: String, email: String, subject: String?, bod
startActivity(Intent.createChooser(emailIntent, chooserTitle))
}
-fun Context.openMapLocation(location: String) {
+fun Context.openNavigation(location: String) {
val intentUri = Uri.parse("geo:0,0?q=${Uri.encode(location)}")
val intent = Intent(Intent.ACTION_VIEW, intentUri)
if (intent.resolveActivity(packageManager) != null) {
@@ -48,7 +48,7 @@ fun Context.openMapLocation(location: String) {
}
}
-fun Context.dialPhone(phone: String) {
+fun Context.openDialer(phone: String) {
val intentUri = Uri.parse("tel:$phone")
val intent = Intent(Intent.ACTION_DIAL, intentUri)
startActivity(intent)
diff --git a/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt
index c863b030f..c1e182ba2 100644
--- a/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt
+++ b/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt
@@ -32,7 +32,7 @@ fun Grade.getBackgroundColor(theme: String): Int {
"B16CF1" -> R.color.grade_purple
else -> R.color.grade_material_default
}
- "material" -> when (value) {
+ "material" -> when (value.toInt()) {
6 -> R.color.grade_material_six
5 -> R.color.grade_material_five
4 -> R.color.grade_material_four
@@ -41,7 +41,7 @@ fun Grade.getBackgroundColor(theme: String): Int {
1 -> R.color.grade_material_one
else -> R.color.grade_material_default
}
- else -> when (value) {
+ else -> when (value.toInt()) {
6 -> R.color.grade_vulcan_six
5 -> R.color.grade_vulcan_five
4 -> R.color.grade_vulcan_four
@@ -67,8 +67,8 @@ inline val Grade.colorStringId: Int
fun Grade.changeModifier(plusModifier: Double, minusModifier: Double): Grade {
return when {
- modifier != .0 && plusModifier != .0 && modifier > 0 -> copy(modifier = plusModifier)
- modifier != .0 && minusModifier != .0 && modifier < 0 -> copy(modifier = -minusModifier)
+ modifier > 0 -> copy(modifier = plusModifier)
+ modifier < 0 -> copy(modifier = -minusModifier)
else -> this
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/utils/SchooldaysRangeLimiter.kt b/app/src/main/java/io/github/wulkanowy/utils/SchooldaysRangeLimiter.kt
new file mode 100644
index 000000000..922aafbd8
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/utils/SchooldaysRangeLimiter.kt
@@ -0,0 +1,51 @@
+package io.github.wulkanowy.utils
+
+import android.os.Parcel
+import android.os.Parcelable
+import com.wdullaer.materialdatetimepicker.date.DateRangeLimiter
+import org.threeten.bp.DayOfWeek
+import org.threeten.bp.LocalDate
+import java.util.Calendar
+
+@Suppress("UNUSED_PARAMETER")
+class SchooldaysRangeLimiter : DateRangeLimiter {
+
+ private val now = LocalDate.now()
+
+ override fun setToNearestDate(day: Calendar): Calendar = day
+
+ override fun isOutOfRange(year: Int, month: Int, day: Int): Boolean {
+ val date = LocalDate.of(year, month + 1, day)
+ val dayOfWeek = date.dayOfWeek
+ return dayOfWeek == DayOfWeek.SUNDAY || dayOfWeek == DayOfWeek.SATURDAY || date.isHolidays
+ }
+
+ override fun getStartDate(): Calendar {
+ val startYear = if (now.monthValue <= 6) now.year - 1 else now.year
+ val startOfSchoolYear = now.withYear(startYear).firstSchoolDay
+
+ val calendar = Calendar.getInstance()
+ calendar.set(startOfSchoolYear.year, startOfSchoolYear.monthValue - 1, startOfSchoolYear.dayOfMonth)
+ return calendar
+ }
+
+ override fun getEndDate(): Calendar {
+ val endYear = if (now.monthValue > 6) now.year + 1 else now.year
+ val endOfSchoolYear = now.withYear(endYear).lastSchoolDay
+
+ val calendar = Calendar.getInstance()
+ calendar.set(endOfSchoolYear.year, endOfSchoolYear.monthValue - 1, endOfSchoolYear.dayOfMonth)
+ return calendar
+ }
+
+ override fun writeToParcel(parcel: Parcel, flags: Int) {}
+
+ override fun describeContents() = 0
+
+ companion object CREATOR : Parcelable.Creator {
+
+ override fun createFromParcel(parcel: Parcel): SchooldaysRangeLimiter = SchooldaysRangeLimiter()
+
+ override fun newArray(size: Int): Array = arrayOfNulls(size)
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.kt b/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.kt
index 24e6d3ffa..264f45426 100644
--- a/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.kt
+++ b/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.kt
@@ -14,7 +14,6 @@ import android.security.keystore.KeyProperties.DIGEST_SHA512
import android.security.keystore.KeyProperties.ENCRYPTION_PADDING_RSA_OAEP
import android.security.keystore.KeyProperties.PURPOSE_DECRYPT
import android.security.keystore.KeyProperties.PURPOSE_ENCRYPT
-import android.util.Base64
import android.util.Base64.DEFAULT
import android.util.Base64.decode
import android.util.Base64.encode
@@ -60,7 +59,7 @@ fun encrypt(plainText: String, context: Context): String {
if (plainText.isEmpty()) throw ScramblerException("Text to be encrypted is empty")
if (SDK_INT < JELLY_BEAN_MR2) {
- return String(Base64.encode(plainText.toByteArray(KEY_CHARSET), DEFAULT), KEY_CHARSET)
+ return String(encode(plainText.toByteArray(KEY_CHARSET), DEFAULT), KEY_CHARSET)
}
return try {
diff --git a/app/src/main/play/listings/pl-PL/full-description.txt b/app/src/main/play/listings/pl-PL/full-description.txt
index d33cb56f2..641b7706d 100644
--- a/app/src/main/play/listings/pl-PL/full-description.txt
+++ b/app/src/main/play/listings/pl-PL/full-description.txt
@@ -1,4 +1,4 @@
-Aplikacja jest we wczesnej fazie rozwoju, ciągle pracujemy nad kolejnymi funkcjami.
+Aplikacja jest przeznaczona dla użytkowników dziennika VULCAN UONET+.
Wyróżnione cechy i funkcje:
- obliczanie średniej ważonej,
diff --git a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/1-grades.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/1-grades.png
new file mode 100644
index 000000000..56768bf57
Binary files /dev/null and b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/1-grades.png differ
diff --git a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/2-timetable-dialog.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/2-timetable-dialog.png
new file mode 100644
index 000000000..83d9353ae
Binary files /dev/null and b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/2-timetable-dialog.png differ
diff --git a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/3-exams.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/3-exams.png
new file mode 100644
index 000000000..f83a7af8b
Binary files /dev/null and b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/3-exams.png differ
diff --git a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/4-timetable-widget.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/4-timetable-widget.png
new file mode 100644
index 000000000..90d5fef4f
Binary files /dev/null and b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/4-timetable-widget.png differ
diff --git a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/5-messages.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/5-messages.png
new file mode 100644
index 000000000..eadbf2db2
Binary files /dev/null and b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/5-messages.png differ
diff --git a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/6-account-switcher.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/6-account-switcher.png
new file mode 100644
index 000000000..2a11a3db9
Binary files /dev/null and b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/6-account-switcher.png differ
diff --git a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/7-class-grades.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/7-class-grades.png
new file mode 100644
index 000000000..d9b2f1c76
Binary files /dev/null and b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/7-class-grades.png differ
diff --git a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/account-switcher.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/account-switcher.png
deleted file mode 100644
index 8a52d8de8..000000000
Binary files a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/account-switcher.png and /dev/null differ
diff --git a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/attendance-dialog.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/attendance-dialog.png
deleted file mode 100644
index c65085747..000000000
Binary files a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/attendance-dialog.png and /dev/null differ
diff --git a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/attendance-statistics.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/attendance-statistics.png
deleted file mode 100644
index 376fc3c3f..000000000
Binary files a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/attendance-statistics.png and /dev/null differ
diff --git a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/grades.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/grades.png
deleted file mode 100644
index 6b4089b02..000000000
Binary files a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/grades.png and /dev/null differ
diff --git a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/more.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/more.png
deleted file mode 100644
index c3dc523ff..000000000
Binary files a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/more.png and /dev/null differ
diff --git a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/timetable-dialog.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/timetable-dialog.png
deleted file mode 100644
index 511433d45..000000000
Binary files a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/timetable-dialog.png and /dev/null differ
diff --git a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/timetable-widget.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/timetable-widget.png
deleted file mode 100644
index 1d5024707..000000000
Binary files a/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/timetable-widget.png and /dev/null differ
diff --git a/app/src/main/play/release-notes/pl-PL/default.txt b/app/src/main/play/release-notes/pl-PL/default.txt
index 68608c38a..467c3ec82 100644
--- a/app/src/main/play/release-notes/pl-PL/default.txt
+++ b/app/src/main/play/release-notes/pl-PL/default.txt
@@ -1,9 +1,6 @@
-Wersja 0.12.0
+Wersja 0.14.2
-- wsparcie dla dziennika Lubelskiego Portalu Oświatowego
-- naprawa problemów z wyświetlaniem ocen punktowych
-- automatyczne przełączanie motywu na androidzie 10
-- wyświetlanie pomocy przy problemach z logowaniem
-- wyświetlanie informacji o szkole
+- naprawiliśmy błąd powodujący zatrzymanie aplikacji na urządzeniach z Androidem poniżej 5.0
+- zmieniliśmy mało mówiący komunikat o niedostępnym dzienniku na taki mówiący o przerwie technicznej dziennika
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
diff --git a/app/src/main/res/drawable-night/background_header_note.xml b/app/src/main/res/drawable-night/background_header_note.xml
new file mode 100644
index 000000000..2983b32c6
--- /dev/null
+++ b/app/src/main/res/drawable-night/background_header_note.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/background_header_note.xml b/app/src/main/res/drawable/background_header_note.xml
new file mode 100644
index 000000000..8e92e3abf
--- /dev/null
+++ b/app/src/main/res/drawable/background_header_note.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_about_faq.xml b/app/src/main/res/drawable/ic_about_faq.xml
new file mode 100644
index 000000000..d6ab255b2
--- /dev/null
+++ b/app/src/main/res/drawable/ic_about_faq.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_error.xml b/app/src/main/res/drawable/ic_error.xml
new file mode 100644
index 000000000..bb4cb3025
--- /dev/null
+++ b/app/src/main/res/drawable/ic_error.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/fragment_attendance.xml b/app/src/main/res/layout/fragment_attendance.xml
index 4877103ef..daf7e67f9 100644
--- a/app/src/main/res/layout/fragment_attendance.xml
+++ b/app/src/main/res/layout/fragment_attendance.xml
@@ -2,7 +2,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ tools:context=".ui.modules.attendance.AttendanceFragment">
+ android:layout_height="match_parent"
+ tools:listitem="@layout/item_attendance" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ app:srcCompat="@drawable/ic_chevron_left" />
+ app:srcCompat="@drawable/ic_chevron_right" />
diff --git a/app/src/main/res/layout/fragment_attendance_summary.xml b/app/src/main/res/layout/fragment_attendance_summary.xml
index 35bc09600..da0ce7f28 100644
--- a/app/src/main/res/layout/fragment_attendance_summary.xml
+++ b/app/src/main/res/layout/fragment_attendance_summary.xml
@@ -82,4 +82,55 @@
android:text="@string/attendance_no_items"
android:textSize="20sp" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_exam.xml b/app/src/main/res/layout/fragment_exam.xml
index adfbee32f..1e1b0c99e 100644
--- a/app/src/main/res/layout/fragment_exam.xml
+++ b/app/src/main/res/layout/fragment_exam.xml
@@ -2,7 +2,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ tools:context=".ui.modules.exam.ExamFragment">
+ android:layout_height="match_parent"
+ tools:listitem="@layout/header_exam" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ app:srcCompat="@drawable/ic_chevron_left" />
+ app:srcCompat="@drawable/ic_chevron_right" />
diff --git a/app/src/main/res/layout/fragment_grade.xml b/app/src/main/res/layout/fragment_grade.xml
index d134ec17c..0bc864b2d 100644
--- a/app/src/main/res/layout/fragment_grade.xml
+++ b/app/src/main/res/layout/fragment_grade.xml
@@ -13,23 +13,17 @@
android:visibility="invisible"
app:tabMode="scrollable"
app:tabSelectedTextColor="?colorPrimary"
- app:tabTextColor="@color/mtrl_on_surface_emphasis_medium"
+ app:tabTextColor="@color/material_on_surface_emphasis_medium"
tools:ignore="UnusedAttribute"
tools:visibility="visible" />
-
-
-
-
+ android:layout_marginTop="48dp"
+ android:visibility="invisible"
+ tools:visibility="visible" />
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_grade_details.xml b/app/src/main/res/layout/fragment_grade_details.xml
index 125d43a95..a1faefe7a 100644
--- a/app/src/main/res/layout/fragment_grade_details.xml
+++ b/app/src/main/res/layout/fragment_grade_details.xml
@@ -13,7 +13,8 @@
+ android:layout_height="match_parent"
+ tools:listitem="@layout/item_grade_details" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_grade_statistics.xml b/app/src/main/res/layout/fragment_grade_statistics.xml
index 6e88f8a89..10c8bb195 100644
--- a/app/src/main/res/layout/fragment_grade_statistics.xml
+++ b/app/src/main/res/layout/fragment_grade_statistics.xml
@@ -47,39 +47,45 @@
android:layout_height="wrap_content"
android:orientation="vertical">
-
+ android:layout_gravity="center">
-
+ android:orientation="horizontal"
+ android:paddingStart="16dp"
+ android:paddingTop="5dp"
+ android:paddingEnd="16dp"
+ android:visibility="invisible"
+ tools:visibility="visible">
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_grade_summary.xml b/app/src/main/res/layout/fragment_grade_summary.xml
index 2d9e7dc6f..3f21e61c7 100644
--- a/app/src/main/res/layout/fragment_grade_summary.xml
+++ b/app/src/main/res/layout/fragment_grade_summary.xml
@@ -13,7 +13,8 @@
+ android:layout_height="match_parent"
+ tools:listitem="@layout/item_grade_summary" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_homework.xml b/app/src/main/res/layout/fragment_homework.xml
index 799d3f42c..0fcde9c07 100644
--- a/app/src/main/res/layout/fragment_homework.xml
+++ b/app/src/main/res/layout/fragment_homework.xml
@@ -2,7 +2,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ tools:context=".ui.modules.homework.HomeworkFragment">
+ android:layout_height="match_parent"
+ tools:listitem="@layout/item_homework" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ app:srcCompat="@drawable/ic_chevron_left" />
+ app:srcCompat="@drawable/ic_chevron_right" />
diff --git a/app/src/main/res/layout/fragment_login_advanced.xml b/app/src/main/res/layout/fragment_login_advanced.xml
new file mode 100644
index 000000000..15e0904b6
--- /dev/null
+++ b/app/src/main/res/layout/fragment_login_advanced.xml
@@ -0,0 +1,267 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_login_form.xml b/app/src/main/res/layout/fragment_login_form.xml
index 299435154..bb93c1827 100644
--- a/app/src/main/res/layout/fragment_login_form.xml
+++ b/app/src/main/res/layout/fragment_login_form.xml
@@ -2,7 +2,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ tools:context=".ui.modules.login.form.LoginFormFragment">
+ android:layout_height="wrap_content"
+ android:paddingBottom="16dp">
+ android:text="@string/about_faq"
+ app:icon="@drawable/ic_about_faq" />
+
+
+
+
-
-
diff --git a/app/src/main/res/layout/fragment_login_symbol.xml b/app/src/main/res/layout/fragment_login_symbol.xml
index cf6537378..56b4a32e5 100644
--- a/app/src/main/res/layout/fragment_login_symbol.xml
+++ b/app/src/main/res/layout/fragment_login_symbol.xml
@@ -2,7 +2,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ tools:context=".ui.modules.login.symbol.LoginSymbolFragment">
+ android:layout_marginRight="16dp"
+ android:orientation="horizontal">
+
+ android:layout_marginLeft="8dp"
+ android:layout_weight="1"
+ android:text="@string/about_faq"
+ app:icon="@drawable/ic_about_faq" />
diff --git a/app/src/main/res/layout/fragment_lucky_number.xml b/app/src/main/res/layout/fragment_lucky_number.xml
index 5d3afda26..a6b9b8221 100644
--- a/app/src/main/res/layout/fragment_lucky_number.xml
+++ b/app/src/main/res/layout/fragment_lucky_number.xml
@@ -67,4 +67,55 @@
android:text="@string/lucky_number_empty"
android:textSize="20sp" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_message.xml b/app/src/main/res/layout/fragment_message.xml
index d396276fd..b4cc0c2fe 100644
--- a/app/src/main/res/layout/fragment_message.xml
+++ b/app/src/main/res/layout/fragment_message.xml
@@ -16,7 +16,7 @@
app:tabMaxWidth="0dp"
app:tabMode="fixed"
app:tabSelectedTextColor="?colorPrimary"
- app:tabTextColor="@color/mtrl_on_surface_emphasis_medium"
+ app:tabTextColor="@color/material_on_surface_emphasis_medium"
tools:ignore="UnusedAttribute"
tools:visibility="visible" />
@@ -35,8 +35,8 @@
android:layout_margin="16dp"
android:clickable="true"
android:focusable="true"
- android:tint="?colorOnSecondary"
android:text="@string/send_message_title"
+ android:tint="?colorOnSecondary"
app:icon="@drawable/ic_menu_message_write" />
+
+ tools:ignore="UseCompoundDrawables"
+ tools:visibility="invisible">
+
+
+
+
+
+
+
+ android:layout_height="match_parent"
+ tools:listitem="@layout/item_message" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_mobile_device.xml b/app/src/main/res/layout/fragment_mobile_device.xml
index b78dc067b..cf11c2831 100644
--- a/app/src/main/res/layout/fragment_mobile_device.xml
+++ b/app/src/main/res/layout/fragment_mobile_device.xml
@@ -14,6 +14,18 @@
android:indeterminate="true"
tools:visibility="invisible" />
+
+
+
+
+
-
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:visibility="invisible"
+ tools:ignore="UseCompoundDrawables"
+ tools:visibility="invisible">
-
+
+
+
+
-
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_school.xml b/app/src/main/res/layout/fragment_school.xml
index 2570251ba..a7e9a213b 100644
--- a/app/src/main/res/layout/fragment_school.xml
+++ b/app/src/main/res/layout/fragment_school.xml
@@ -229,7 +229,58 @@
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
- android:text="@string/teacher_no_items"
+ android:text="@string/school_no_info"
android:textSize="20sp" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_schoolandteachers.xml b/app/src/main/res/layout/fragment_schoolandteachers.xml
index 2b3f2203d..6414abb92 100644
--- a/app/src/main/res/layout/fragment_schoolandteachers.xml
+++ b/app/src/main/res/layout/fragment_schoolandteachers.xml
@@ -16,7 +16,7 @@
app:tabMaxWidth="0dp"
app:tabMode="fixed"
app:tabSelectedTextColor="?colorPrimary"
- app:tabTextColor="@color/mtrl_on_surface_emphasis_medium"
+ app:tabTextColor="@color/material_on_surface_emphasis_medium"
tools:ignore="UnusedAttribute"
tools:visibility="visible" />
diff --git a/app/src/main/res/layout/fragment_teacher.xml b/app/src/main/res/layout/fragment_teacher.xml
index 01cf87260..484bf0651 100644
--- a/app/src/main/res/layout/fragment_teacher.xml
+++ b/app/src/main/res/layout/fragment_teacher.xml
@@ -49,4 +49,55 @@
android:text="@string/teacher_no_items"
android:textSize="20sp" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_timetable.xml b/app/src/main/res/layout/fragment_timetable.xml
index db5c6fc23..98ccabbff 100644
--- a/app/src/main/res/layout/fragment_timetable.xml
+++ b/app/src/main/res/layout/fragment_timetable.xml
@@ -2,7 +2,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ tools:context=".ui.modules.timetable.TimetableFragment">
+ android:layout_height="match_parent"
+ tools:listitem="@layout/item_timetable" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ app:srcCompat="@drawable/ic_chevron_left" />
+ app:srcCompat="@drawable/ic_chevron_right" />
diff --git a/app/src/main/res/layout/fragment_timetable_completed.xml b/app/src/main/res/layout/fragment_timetable_completed.xml
index 7c093a4a7..110670449 100644
--- a/app/src/main/res/layout/fragment_timetable_completed.xml
+++ b/app/src/main/res/layout/fragment_timetable_completed.xml
@@ -57,6 +57,57 @@
android:text="@string/completed_lessons_no_items"
android:textSize="20sp" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/header_grade_details.xml b/app/src/main/res/layout/header_grade_details.xml
index 40f486cf5..0fa3872e1 100644
--- a/app/src/main/res/layout/header_grade_details.xml
+++ b/app/src/main/res/layout/header_grade_details.xml
@@ -7,7 +7,7 @@
android:background="?selectableItemBackground"
android:paddingLeft="16dp"
android:paddingTop="10dp"
- android:paddingRight="12dp"
+ android:paddingRight="14dp"
android:paddingBottom="10dp"
tools:context=".ui.modules.grade.details.GradeDetailsHeader"
android:paddingEnd="12dp"
@@ -50,14 +50,19 @@
android:textSize="12sp"
tools:text="12 grades" />
-
+ android:background="@drawable/background_header_note"
+ android:textColor="?colorOnPrimary"
+ android:textSize="14sp"
+ tools:text="255" />
diff --git a/app/src/main/res/layout/item_homework.xml b/app/src/main/res/layout/item_homework.xml
index 5d03ed583..68169039d 100644
--- a/app/src/main/res/layout/item_homework.xml
+++ b/app/src/main/res/layout/item_homework.xml
@@ -32,7 +32,7 @@
android:layout_toRightOf="@id/homeworkItemSubject"
android:gravity="end"
android:textSize="13sp"
- tools:text="@tools:sample/lorem" />
+ tools:text="@tools:sample/full_names" />
+ tools:text="@tools:sample/lorem" />
diff --git a/app/src/main/res/menu/action_menu_attendance.xml b/app/src/main/res/menu/action_menu_attendance.xml
index 86c2fed71..bb20c8ec2 100644
--- a/app/src/main/res/menu/action_menu_attendance.xml
+++ b/app/src/main/res/menu/action_menu_attendance.xml
@@ -6,6 +6,6 @@
android:icon="@drawable/ic_menu_attendance_summary"
android:orderInCategory="1"
android:title="@string/attendance_summary_button"
- app:iconTint="@color/mtrl_on_surface_emphasis_medium"
+ app:iconTint="@color/material_on_surface_emphasis_medium"
app:showAsAction="ifRoom" />
diff --git a/app/src/main/res/menu/action_menu_grade.xml b/app/src/main/res/menu/action_menu_grade.xml
index 4438309de..6357cbb51 100644
--- a/app/src/main/res/menu/action_menu_grade.xml
+++ b/app/src/main/res/menu/action_menu_grade.xml
@@ -6,6 +6,6 @@
android:icon="@drawable/ic_menu_grade_semester"
android:orderInCategory="1"
android:title="@string/grade_switch_semester"
- app:iconTint="@color/mtrl_on_surface_emphasis_medium"
+ app:iconTint="@color/material_on_surface_emphasis_medium"
app:showAsAction="ifRoom" />
diff --git a/app/src/main/res/menu/action_menu_grade_details.xml b/app/src/main/res/menu/action_menu_grade_details.xml
index fbd28eece..62516cbd7 100644
--- a/app/src/main/res/menu/action_menu_grade_details.xml
+++ b/app/src/main/res/menu/action_menu_grade_details.xml
@@ -6,6 +6,6 @@
android:enabled="false"
android:orderInCategory="100"
android:title="@string/grade_menu_read"
- app:iconTint="@color/mtrl_on_surface_emphasis_medium"
+ app:iconTint="@color/material_on_surface_emphasis_medium"
app:showAsAction="never" />
diff --git a/app/src/main/res/menu/action_menu_main.xml b/app/src/main/res/menu/action_menu_main.xml
index 78b4ee4a8..72bea25a2 100644
--- a/app/src/main/res/menu/action_menu_main.xml
+++ b/app/src/main/res/menu/action_menu_main.xml
@@ -6,6 +6,6 @@
android:icon="@drawable/ic_all_account"
android:orderInCategory="2"
android:title="@string/main_account_picker"
- app:iconTint="@color/mtrl_on_surface_emphasis_medium"
+ app:iconTint="@color/material_on_surface_emphasis_medium"
app:showAsAction="always" />
diff --git a/app/src/main/res/menu/action_menu_message_preview.xml b/app/src/main/res/menu/action_menu_message_preview.xml
index f79797801..dfc12e234 100644
--- a/app/src/main/res/menu/action_menu_message_preview.xml
+++ b/app/src/main/res/menu/action_menu_message_preview.xml
@@ -6,20 +6,20 @@
android:icon="@drawable/ic_menu_message_reply"
android:orderInCategory="1"
android:title="@string/message_reply"
- app:iconTint="@color/mtrl_on_surface_emphasis_medium"
+ app:iconTint="@color/material_on_surface_emphasis_medium"
app:showAsAction="ifRoom" />
diff --git a/app/src/main/res/menu/action_menu_send_message.xml b/app/src/main/res/menu/action_menu_send_message.xml
index 491f74f97..4b43764a8 100644
--- a/app/src/main/res/menu/action_menu_send_message.xml
+++ b/app/src/main/res/menu/action_menu_send_message.xml
@@ -6,6 +6,6 @@
android:icon="@drawable/ic_menu_message_send"
android:orderInCategory="1"
android:title="@string/send_message_title"
- app:iconTint="@color/mtrl_on_surface_emphasis_medium"
+ app:iconTint="@color/material_on_surface_emphasis_medium"
app:showAsAction="ifRoom" />
diff --git a/app/src/main/res/menu/action_menu_timetable.xml b/app/src/main/res/menu/action_menu_timetable.xml
index cfbdb6269..c3d0222c1 100644
--- a/app/src/main/res/menu/action_menu_timetable.xml
+++ b/app/src/main/res/menu/action_menu_timetable.xml
@@ -6,6 +6,6 @@
android:icon="@drawable/ic_menu_timetable_lessons_completed"
android:orderInCategory="1"
android:title="@string/completed_lessons_button"
- app:iconTint="@color/mtrl_on_surface_emphasis_medium"
+ app:iconTint="@color/material_on_surface_emphasis_medium"
app:showAsAction="ifRoom" />
diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml
index 3e4a2466f..492645381 100644
--- a/app/src/main/res/values-night/styles.xml
+++ b/app/src/main/res/values-night/styles.xml
@@ -10,6 +10,7 @@
- ?android:textColorPrimary
- @android:color/black
- false
+ - true
+
+
diff --git a/app/src/main/res/xml/scheme_preferences.xml b/app/src/main/res/xml/scheme_preferences.xml
index 28229f417..d9e6c5333 100644
--- a/app/src/main/res/xml/scheme_preferences.xml
+++ b/app/src/main/res/xml/scheme_preferences.xml
@@ -37,6 +37,14 @@
app:key="@string/pref_key_grade_color_scheme"
app:title="@string/pref_view_grade_color_scheme"
app:useSimpleSummaryProvider="true" />
+
+ app:title="@string/pref_view_grade_average_force_calc" />
()).`when`(semesterLocal).getSemesters(student)
doReturn(Single.just(semesters)).`when`(semesterRemote).getSemesters(student)
@@ -65,7 +65,7 @@ class SemesterRepositoryTest {
createSemesterEntity(true)
)
- doNothing().`when`(apiHelper).initApi(student)
+ doNothing().`when`(sdkHelper).init(student)
doReturn(Maybe.empty()).`when`(semesterLocal).getSemesters(student)
doReturn(Single.just(semesters)).`when`(semesterRemote).getSemesters(student)
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/student/StudentRemoteTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/student/StudentRemoteTest.kt
index 4d7b23ebd..f52c01424 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/student/StudentRemoteTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/student/StudentRemoteTest.kt
@@ -1,19 +1,23 @@
package io.github.wulkanowy.data.repositories.student
-import io.github.wulkanowy.api.Api
-import io.github.wulkanowy.api.register.Student
+import io.github.wulkanowy.data.SdkHelper
+import io.github.wulkanowy.sdk.Sdk
+import io.github.wulkanowy.sdk.pojo.Student
+import io.mockk.impl.annotations.SpyK
import io.reactivex.Single
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.anyString
import org.mockito.Mockito.doReturn
import org.mockito.MockitoAnnotations
class StudentRemoteTest {
@Mock
- private lateinit var mockApi: Api
+ private lateinit var mockSdk: Sdk
@Before
fun initApi() {
@@ -22,11 +26,31 @@ class StudentRemoteTest {
@Test
fun testRemoteAll() {
- doReturn(Single.just(listOf(Student("", "", 1, "test", "", "", "", 1, Api.LoginType.AUTO))))
- .`when`(mockApi).getStudents()
+ doReturn(Single.just(listOf(getStudent("test")))).`when`(mockSdk).getStudentsFromScrapper(anyString(), anyString(), anyString(), anyString())
- val students = StudentRemote(mockApi).getStudents("", "", "").blockingGet()
+ val students = StudentRemote(mockSdk).getStudentsScrapper("", "", "http://fakelog.cf", "").blockingGet()
assertEquals(1, students.size)
assertEquals("test", students.first().studentName)
}
+
+ private fun getStudent(name: String): Student {
+ return Student(
+ email = "",
+ symbol = "",
+ studentId = 0,
+ userLoginId = 0,
+ studentName = name,
+ schoolSymbol = "",
+ schoolName = "",
+ className = "",
+ classId = 0,
+ certificateKey = "",
+ privateKey = "",
+ loginMode = Sdk.Mode.SCRAPPER,
+ mobileBaseUrl = "",
+ loginType = Sdk.ScrapperLoginType.STANDARD,
+ scrapperBaseUrl = "",
+ isParent = false
+ )
+ }
}
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemoteTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemoteTest.kt
index 4bb4091fb..100bc0aed 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemoteTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemoteTest.kt
@@ -1,24 +1,23 @@
package io.github.wulkanowy.data.repositories.timetable
-import io.github.wulkanowy.api.Api
-import io.github.wulkanowy.api.timetable.Timetable
import io.github.wulkanowy.data.db.entities.Semester
-import io.github.wulkanowy.data.repositories.timetable.TimetableRemote
+import io.github.wulkanowy.sdk.Sdk
+import io.github.wulkanowy.sdk.pojo.Timetable
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.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.threeten.bp.LocalDate
-import java.sql.Date
+import org.threeten.bp.LocalDate.of
+import org.threeten.bp.LocalDateTime.now
class TimetableRemoteTest {
- @SpyK
- private var mockApi = Api()
+ @MockK
+ private lateinit var mockSdk: Sdk
@MockK
private lateinit var semesterMock: Semester
@@ -30,26 +29,46 @@ class TimetableRemoteTest {
@Test
fun getTimetableTest() {
- every { mockApi.getTimetable(
- LocalDate.of(2018, 9, 10),
- LocalDate.of(2018, 9, 15)
- ) } returns Single.just(listOf(
- getTimetable("2018-09-10"),
- getTimetable("2018-09-17")
+ every {
+ mockSdk.getTimetable(
+ of(2018, 9, 10),
+ of(2018, 9, 15)
+ )
+ } returns Single.just(listOf(
+ getTimetable(of(2018, 9, 10)),
+ getTimetable(of(2018, 9, 17))
))
- every { mockApi.diaryId } returns 1
every { semesterMock.studentId } returns 1
every { semesterMock.diaryId } returns 1
+ every { semesterMock.schoolYear } returns 2019
+ every { semesterMock.semesterId } returns 1
+ every { mockSdk.switchDiary(any(), any()) } returns mockSdk
- val timetable = TimetableRemote(mockApi).getTimetable(semesterMock,
- LocalDate.of(2018, 9, 10),
- LocalDate.of(2018, 9, 15)
+ val timetable = TimetableRemote(mockSdk).getTimetable(semesterMock,
+ of(2018, 9, 10),
+ of(2018, 9, 15)
).blockingGet()
assertEquals(2, timetable.size)
}
- private fun getTimetable(dateString: String): Timetable {
- return Timetable(date = Date.valueOf(dateString))
+ private fun getTimetable(date: LocalDate): Timetable {
+ return Timetable(
+ date = date,
+ number = 0,
+ teacherOld = "",
+ subjectOld = "",
+ roomOld = "",
+ subject = "",
+ teacher = "",
+ group = "",
+ canceled = false,
+ changes = false,
+ info = "",
+ room = "",
+ end = now(),
+ start = now(),
+ studentPlan = true
+ )
}
}
diff --git a/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt b/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt
index 3197bb794..56b1e66f8 100644
--- a/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt
@@ -7,6 +7,7 @@ import io.github.wulkanowy.data.db.entities.Student
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.sdk.Sdk
import io.reactivex.Single
import org.junit.Assert.assertEquals
import org.junit.Before
@@ -30,7 +31,7 @@ class GradeAverageProviderTest {
private lateinit var gradeAverageProvider: GradeAverageProvider
- private val student = Student("", "", "", "", "", 101, "", "", "", "", 1, true, LocalDateTime.now())
+ private val student = Student("", "", "", "SCRAPPER", "", "", false, "", "", "", 101, 0, "", "", "", "", 1, true, LocalDateTime.now())
private val semesters = mutableListOf(
Semester(101, 10, "", 1, 21, 1, false, now(), now(), 1, 1),
@@ -39,17 +40,22 @@ class GradeAverageProviderTest {
)
private val firstGrades = listOf(
- getGrade(22, "Matematyka", 4),
- getGrade(22, "Matematyka", 3),
- getGrade(22, "Fizyka", 6),
- getGrade(22, "Fizyka", 1)
+ getGrade(22, "Matematyka", 4.0),
+ getGrade(22, "Matematyka", 3.0),
+ getGrade(22, "Fizyka", 6.0),
+ getGrade(22, "Fizyka", 1.0)
)
private val secondGrade = listOf(
- getGrade(23, "Matematyka", 2),
- getGrade(23, "Matematyka", 3),
- getGrade(23, "Fizyka", 4),
- getGrade(23, "Fizyka", 2)
+ getGrade(23, "Matematyka", 2.0),
+ getGrade(23, "Matematyka", 3.0),
+ getGrade(23, "Fizyka", 4.0),
+ getGrade(23, "Fizyka", 2.0)
+ )
+
+ private val secondGradeWithModifier = listOf(
+ getGrade(24, "Język polski", 3.0, -0.50),
+ getGrade(24, "Język polski", 4.0, 0.25)
)
@Before
@@ -78,6 +84,54 @@ class GradeAverageProviderTest {
assertEquals(3.0, averages["Fizyka"])
}
+ @Test
+ fun onlyOneSemester_gradesWithModifiers_default() {
+ doReturn("only_one_semester").`when`(preferencesRepository).gradeAverageMode
+ doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(semesters[2], true)
+ doReturn(Single.just(secondGradeWithModifier)).`when`(gradeRepository).getGrades(student, semesters[2], true)
+
+ val averages = gradeAverageProvider.getGradeAverage(student, semesters, semesters[2].semesterId, true)
+ .blockingGet()
+
+ assertEquals(3.5, averages["Język polski"])
+ }
+
+ @Test
+ fun onlyOneSemester_gradesWithModifiers_api() {
+ doReturn("only_one_semester").`when`(preferencesRepository).gradeAverageMode
+ doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(semesters[2], true)
+ doReturn(Single.just(secondGradeWithModifier)).`when`(gradeRepository).getGrades(student.copy(loginMode = Sdk.Mode.API.name), semesters[2], true)
+
+ val averages = gradeAverageProvider.getGradeAverage(student.copy(loginMode = Sdk.Mode.API.name), semesters, semesters[2].semesterId, true)
+ .blockingGet()
+
+ assertEquals(3.375, averages["Język polski"])
+ }
+
+ @Test
+ fun onlyOneSemester_gradesWithModifiers_scrapper() {
+ doReturn("only_one_semester").`when`(preferencesRepository).gradeAverageMode
+ doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(semesters[2], true)
+ doReturn(Single.just(secondGradeWithModifier)).`when`(gradeRepository).getGrades(student.copy(loginMode = Sdk.Mode.SCRAPPER.name), semesters[2], true)
+
+ val averages = gradeAverageProvider.getGradeAverage(student.copy(loginMode = Sdk.Mode.SCRAPPER.name), semesters, semesters[2].semesterId, true)
+ .blockingGet()
+
+ assertEquals(3.5, averages["Język polski"])
+ }
+
+ @Test
+ fun onlyOneSemester_gradesWithModifiers_hybrid() {
+ doReturn("only_one_semester").`when`(preferencesRepository).gradeAverageMode
+ doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(semesters[2], true)
+ doReturn(Single.just(secondGradeWithModifier)).`when`(gradeRepository).getGrades(student.copy(loginMode = Sdk.Mode.HYBRID.name), semesters[2], true)
+
+ val averages = gradeAverageProvider.getGradeAverage(student.copy(loginMode = Sdk.Mode.HYBRID.name), semesters, semesters[2].semesterId, true)
+ .blockingGet()
+
+ assertEquals(3.375, averages["Język polski"])
+ }
+
@Test
fun allYearFirstSemesterTest() {
doReturn("all_year").`when`(preferencesRepository).gradeAverageMode
@@ -147,13 +201,13 @@ class GradeAverageProviderTest {
assertEquals(3.25, averages["Fizyka"])
}
- private fun getGrade(semesterId: Int, subject: String, value: Int): Grade {
+ private fun getGrade(semesterId: Int, subject: String, value: Double, modifier: Double = 0.0): Grade {
return Grade(
studentId = 101,
semesterId = semesterId,
subject = subject,
value = value,
- modifier = .0,
+ modifier = modifier,
weightValue = 1.0,
teacher = "",
date = now(),
diff --git a/app/src/test/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenterTest.kt b/app/src/test/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenterTest.kt
index 453adfba0..be99d4d46 100644
--- a/app/src/test/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenterTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenterTest.kt
@@ -43,7 +43,7 @@ class LoginFormPresenterTest {
fun initPresenter() {
MockitoAnnotations.initMocks(this)
clearInvocations(repository, loginFormView)
- presenter = LoginFormPresenter(TestSchedulersProvider(), repository, errorHandler, analytics, appInfo)
+ presenter = LoginFormPresenter(TestSchedulersProvider(), repository, errorHandler, analytics)
presenter.onAttachView(loginFormView)
}
@@ -90,9 +90,8 @@ class LoginFormPresenterTest {
@Test
fun loginTest() {
- val studentTest = Student(email = "test@", password = "123", endpoint = "https://fakelog.cf", loginType = "AUTO", studentName = "", schoolSymbol = "", schoolName = "", studentId = 0, classId = 1, isCurrent = false, symbol = "", registrationDate = now(), className = "")
- doReturn(Single.just(listOf(studentTest)))
- .`when`(repository).getStudents(anyString(), anyString(), anyString(), anyString())
+ val studentTest = Student(email = "test@", password = "123", scrapperBaseUrl = "https://fakelog.cf", loginType = "AUTO", studentName = "", schoolSymbol = "", schoolName = "", studentId = 0, classId = 1, isCurrent = false, symbol = "", registrationDate = now(), className = "", mobileBaseUrl = "", privateKey = "", certificateKey = "", loginMode = "", userLoginId = 0, isParent = false)
+ doReturn(Single.just(listOf(studentTest))).`when`(repository).getStudentsScrapper(anyString(), anyString(), anyString(), anyString())
`when`(loginFormView.formNameValue).thenReturn("@")
`when`(loginFormView.formPassValue).thenReturn("123456")
@@ -109,7 +108,7 @@ class LoginFormPresenterTest {
@Test
fun loginEmptyTest() {
doReturn(Single.just(emptyList()))
- .`when`(repository).getStudents(anyString(), anyString(), anyString(), anyString())
+ .`when`(repository).getStudentsScrapper(anyString(), anyString(), anyString(), anyString())
`when`(loginFormView.formNameValue).thenReturn("@")
`when`(loginFormView.formPassValue).thenReturn("123456")
`when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf")
@@ -125,7 +124,7 @@ class LoginFormPresenterTest {
@Test
fun loginEmptyTwiceTest() {
doReturn(Single.just(emptyList()))
- .`when`(repository).getStudents(anyString(), anyString(), anyString(), anyString())
+ .`when`(repository).getStudentsScrapper(anyString(), anyString(), anyString(), anyString())
`when`(loginFormView.formNameValue).thenReturn("@")
`when`(loginFormView.formPassValue).thenReturn("123456")
`when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf")
@@ -142,8 +141,7 @@ class LoginFormPresenterTest {
@Test
fun loginErrorTest() {
val testException = RuntimeException("test")
- doReturn(Single.error>(testException))
- .`when`(repository).getStudents(anyString(), anyString(), anyString(), anyString())
+ doReturn(Single.error>(testException)).`when`(repository).getStudentsScrapper(anyString(), anyString(), anyString(), anyString())
`when`(loginFormView.formNameValue).thenReturn("@")
`when`(loginFormView.formPassValue).thenReturn("123456")
`when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf")
@@ -157,4 +155,3 @@ class LoginFormPresenterTest {
verify(errorHandler).dispatch(testException)
}
}
-
diff --git a/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt b/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt
index 16bcdebe8..2c174fb58 100644
--- a/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt
@@ -32,7 +32,7 @@ class LoginStudentSelectPresenterTest {
private lateinit var presenter: LoginStudentSelectPresenter
- private val testStudent by lazy { Student(email = "test", password = "test123", endpoint = "https://fakelog.cf", loginType = "AUTO", symbol = "", isCurrent = false, studentId = 0, schoolName = "", schoolSymbol = "", classId = 1, studentName = "", registrationDate = now(), className = "") }
+ private val testStudent by lazy { Student(email = "test", password = "test123", scrapperBaseUrl = "https://fakelog.cf", loginType = "AUTO", symbol = "", isCurrent = false, studentId = 0, schoolName = "", schoolSymbol = "", classId = 1, studentName = "", registrationDate = now(), className = "", loginMode = "", certificateKey = "", privateKey = "", mobileBaseUrl = "", userLoginId = 1, isParent = false) }
private val testException by lazy { RuntimeException("Problem") }
diff --git a/app/src/test/java/io/github/wulkanowy/utils/GradeExtensionTest.kt b/app/src/test/java/io/github/wulkanowy/utils/GradeExtensionTest.kt
index 31618fd4f..ece7acf20 100644
--- a/app/src/test/java/io/github/wulkanowy/utils/GradeExtensionTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/utils/GradeExtensionTest.kt
@@ -1,5 +1,6 @@
package io.github.wulkanowy.utils
+import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.GradeSummary
import org.junit.Assert.assertEquals
@@ -22,11 +23,11 @@ class GradeExtensionTest {
@Test
fun calcWeightedAverage() {
assertEquals(3.47, listOf(
- createGrade(5, 6.0, 0.33),
- createGrade(5, 5.0, -0.33),
- createGrade(4, 1.0, 0.0),
- createGrade(1, 9.0, 0.5),
- createGrade(0, .0, 0.0)
+ createGrade(5.0, 6.0, 0.33),
+ createGrade(5.0, 5.0, -0.33),
+ createGrade(4.0, 1.0, 0.0),
+ createGrade(1.0, 9.0, 0.5),
+ createGrade(0.0, .0, 0.0)
).calcAverage(), 0.005)
}
@@ -41,24 +42,32 @@ class GradeExtensionTest {
}
@Test
- fun changeModifier_default() {
- assertEquals(.33, createGrade(5, .0, .33).changeModifier(.0, .0).modifier, .0)
- assertEquals(-.33, createGrade(5, .0, -.33).changeModifier(.0, .0).modifier, .0)
+ fun getBackgroundColor() {
+ assertEquals(R.color.grade_material_five, createGrade(5.0).getBackgroundColor("material"))
+ assertEquals(R.color.grade_material_five, createGrade(5.5).getBackgroundColor("material"))
+ assertEquals(R.color.grade_material_five, createGrade(5.9).getBackgroundColor("material"))
+ assertEquals(R.color.grade_vulcan_five, createGrade(5.9).getBackgroundColor("whatever"))
+ }
+
+ @Test
+ fun changeModifier_zero() {
+ assertEquals(.0, createGrade(5.0, .0, .5).changeModifier(.0, .0).modifier, .0)
+ assertEquals(.0, createGrade(5.0, .0, -.5).changeModifier(.0, .0).modifier, .0)
}
@Test
fun changeModifier_plus() {
- assertEquals(.33, createGrade(5, .0, .25).changeModifier(.33, .50).modifier, .0)
- assertEquals(.25, createGrade(5, .0, .33).changeModifier(.25, .0).modifier, .0)
+ assertEquals(.33, createGrade(5.0, .0, .25).changeModifier(.33, .50).modifier, .0)
+ assertEquals(.25, createGrade(5.0, .0, .33).changeModifier(.25, .0).modifier, .0)
}
@Test
fun changeModifier_minus() {
- assertEquals(-.33, createGrade(5, .0, -.25).changeModifier(.25, .33).modifier, .0)
- assertEquals(-.25, createGrade(5, .0, -.33).changeModifier(.0, .25).modifier, .0)
+ assertEquals(-.33, createGrade(5.0, .0, -.25).changeModifier(.25, .33).modifier, .0)
+ assertEquals(-.25, createGrade(5.0, .0, -.33).changeModifier(.0, .25).modifier, .0)
}
- private fun createGrade(value: Int, weightValue: Double = .0, modifier: Double = 0.25): Grade {
+ private fun createGrade(value: Double, weightValue: Double = .0, modifier: Double = 0.25): Grade {
return Grade(
semesterId = 1,
studentId = 1,
diff --git a/build.gradle b/build.gradle
index 6c004f6f4..0843a31a3 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,5 @@
buildscript {
- ext.kotlin_version = '1.3.50'
+ ext.kotlin_version = '1.3.61'
repositories {
mavenCentral()
google()
@@ -9,11 +9,11 @@ buildscript {
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath 'com.android.tools.build:gradle:3.5.1'
- classpath 'com.google.gms:google-services:4.3.2'
+ classpath 'com.android.tools.build:gradle:3.5.3'
+ classpath 'com.google.gms:google-services:4.3.3'
classpath "io.fabric.tools:gradle:1.31.2"
classpath "com.github.triplet.gradle:play-publisher:2.4.2"
- classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8"
+ classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8.0.1969"
classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0"
}
}
diff --git a/gradle.properties b/gradle.properties
index 44e7e13b1..113bb1069 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,9 +1,7 @@
# Project-wide Gradle settings.
-
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
-
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
@@ -18,4 +16,4 @@ kapt.incremental.apt=true
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
+# org.gradle.parallel=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index ca9d62814..0ebb3108e 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists