diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index ab7844747..1f93faefd 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -2,14 +2,6 @@
-
-
-
-
@@ -126,13 +118,6 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index ea74cd562..41be0d50e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -22,8 +22,8 @@ android {
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 21
targetSdkVersion 31
- versionCode 102
- versionName "1.4.4"
+ versionCode 103
+ versionName "1.5.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "app_name", "Wulkanowy"
@@ -149,8 +149,10 @@ kapt {
play {
defaultToAppBundles = false
- track = 'beta'
- updatePriority = 4
+ track = 'production'
+ releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS
+ userFraction = 0.25d
+ updatePriority = 1
enabled.set(false)
}
@@ -167,18 +169,18 @@ huaweiPublish {
ext {
work_manager = "2.7.1"
android_hilt = "1.0.0"
- room = "2.3.0"
+ room = "2.4.0"
chucker = "3.5.2"
mockk = "1.12.1"
- coroutines = "1.5.2"
+ coroutines = "1.6.0"
}
dependencies {
- implementation "io.github.wulkanowy:sdk:1.4.4"
+ implementation "io.github.wulkanowy:sdk:1.5.0"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
- implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1"
+ implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
implementation "androidx.core:core-ktx:1.7.0"
@@ -229,7 +231,7 @@ dependencies {
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
implementation 'com.fredporciuncula:flow-preferences:1.6.0'
- playImplementation platform('com.google.firebase:firebase-bom:29.0.2')
+ playImplementation platform('com.google.firebase:firebase-bom:29.0.3')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
@@ -238,7 +240,7 @@ dependencies {
playImplementation 'com.google.android.gms:play-services-ads:20.5.0'
hmsImplementation 'com.huawei.hms:hianalytics:6.3.2.300'
- hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.2.300'
+ hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.3.200'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/45.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/45.json
new file mode 100644
index 000000000..57f3d431d
--- /dev/null
+++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/45.json
@@ -0,0 +1,2430 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 45,
+ "identityHash": "f310243440ca00cbc35e62ebaca5c7d8",
+ "entities": [
+ {
+ "tableName": "Students",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `user_name` TEXT NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_short` 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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `nick` TEXT NOT NULL, `avatar_color` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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": "userName",
+ "columnName": "user_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentName",
+ "columnName": "student_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolSymbol",
+ "columnName": "school_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolShortName",
+ "columnName": "school_short",
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "nick",
+ "columnName": "nick",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "avatarColor",
+ "columnName": "avatar_color",
+ "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"
+ ],
+ "orders": [],
+ "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}` (`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, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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": "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "current",
+ "columnName": "is_current",
+ "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"
+ ],
+ "orders": [],
+ "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}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Timetable",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `student_plan` INTEGER NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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": "isStudentPlan",
+ "columnName": "student_plan",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "changes",
+ "columnName": "changes",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "canceled",
+ "columnName": "canceled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Attendance",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `time_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, `excusable` INTEGER NOT NULL, `excuse_status` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "timeId",
+ "columnName": "time_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
+ },
+ {
+ "fieldPath": "excusable",
+ "columnName": "excusable",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excuseStatus",
+ "columnName": "excuse_status",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AttendanceSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Grades",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "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
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_predicted_grade_notified` INTEGER NOT NULL, `is_final_grade_notified` INTEGER NOT NULL, `predicted_grade_last_change` INTEGER NOT NULL, `final_grade_last_change` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPredictedGradeNotified",
+ "columnName": "is_predicted_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFinalGradeNotified",
+ "columnName": "is_final_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "predictedGradeLastChange",
+ "columnName": "predicted_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalGradeLastChange",
+ "columnName": "final_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradePartialStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `class_average` TEXT NOT NULL, `student_average` TEXT NOT NULL, `class_amounts` TEXT NOT NULL, `student_amounts` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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": "classAverage",
+ "columnName": "class_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAverage",
+ "columnName": "student_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classAmounts",
+ "columnName": "class_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAmounts",
+ "columnName": "student_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesPointsStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `others` REAL NOT NULL, `student` REAL NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradeSemesterStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `amounts` TEXT NOT NULL, `student_grade` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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": "amounts",
+ "columnName": "amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentGrade",
+ "columnName": "student_grade",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Messages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `recipient_name` TEXT NOT NULL, `subject` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `removed` INTEGER NOT NULL, `has_attachments` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `unread_by` INTEGER NOT NULL, `read_by` INTEGER NOT NULL, `content` TEXT NOT NULL)",
+ "fields": [
+ {
+ "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": "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": "removed",
+ "columnName": "removed",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasAttachments",
+ "columnName": "has_attachments",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unreadBy",
+ "columnName": "unread_by",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "readBy",
+ "columnName": "read_by",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MessageAttachments",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `one_drive_id` TEXT NOT NULL, `url` TEXT NOT NULL, `filename` TEXT NOT NULL, PRIMARY KEY(`real_id`))",
+ "fields": [
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageId",
+ "columnName": "message_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "oneDriveId",
+ "columnName": "one_drive_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filename",
+ "columnName": "filename",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "real_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `category` TEXT NOT NULL, `category_type` INTEGER NOT NULL, `is_points_show` INTEGER NOT NULL, `points` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "categoryType",
+ "columnName": "category_type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPointsShow",
+ "columnName": "is_points_show",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "points",
+ "columnName": "points",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "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
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Homework",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `attachments` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_done` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `is_added_by_user` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "attachments",
+ "columnName": "attachments",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDone",
+ "columnName": "is_done",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Subjects",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "LuckyNumbers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "CompletedLesson",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "ReportingUnits",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unitId",
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Recipients",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MobileDevices",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "userLoginId",
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Teachers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "School",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Conferences",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `subject` TEXT NOT NULL, `agenda` TEXT NOT NULL, `present_on_conference` TEXT NOT NULL, `conference_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "agenda",
+ "columnName": "agenda",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presentOnConference",
+ "columnName": "present_on_conference",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "conferenceId",
+ "columnName": "conference_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableAdditional",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `repeat_id` BLOB DEFAULT NULL, `is_added_by_user` INTEGER NOT NULL DEFAULT 0)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "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": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "repeatId",
+ "columnName": "repeat_id",
+ "affinity": "BLOB",
+ "notNull": false,
+ "defaultValue": "NULL"
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "StudentInfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `full_name` TEXT NOT NULL, `first_name` TEXT NOT NULL, `second_name` TEXT NOT NULL, `surname` TEXT NOT NULL, `birth_date` INTEGER NOT NULL, `birth_place` TEXT NOT NULL, `gender` TEXT NOT NULL, `has_polish_citizenship` INTEGER NOT NULL, `family_name` TEXT NOT NULL, `parents_names` TEXT NOT NULL, `address` TEXT NOT NULL, `registered_address` TEXT NOT NULL, `correspondence_address` TEXT NOT NULL, `phone_number` TEXT NOT NULL, `cell_phone_number` TEXT NOT NULL, `email` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `first_guardian_full_name` TEXT, `first_guardian_kinship` TEXT, `first_guardian_address` TEXT, `first_guardian_phones` TEXT, `first_guardian_email` TEXT, `second_guardian_full_name` TEXT, `second_guardian_kinship` TEXT, `second_guardian_address` TEXT, `second_guardian_phones` TEXT, `second_guardian_email` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "full_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstName",
+ "columnName": "first_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "secondName",
+ "columnName": "second_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "surname",
+ "columnName": "surname",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthDate",
+ "columnName": "birth_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthPlace",
+ "columnName": "birth_place",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gender",
+ "columnName": "gender",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPolishCitizenship",
+ "columnName": "has_polish_citizenship",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "familyName",
+ "columnName": "family_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentsNames",
+ "columnName": "parents_names",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registeredAddress",
+ "columnName": "registered_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "correspondenceAddress",
+ "columnName": "correspondence_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "phoneNumber",
+ "columnName": "phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "cellPhoneNumber",
+ "columnName": "cell_phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstGuardian.fullName",
+ "columnName": "first_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.kinship",
+ "columnName": "first_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.address",
+ "columnName": "first_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.phones",
+ "columnName": "first_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.email",
+ "columnName": "first_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.fullName",
+ "columnName": "second_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.kinship",
+ "columnName": "second_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.address",
+ "columnName": "second_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.phones",
+ "columnName": "second_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.email",
+ "columnName": "second_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableHeaders",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "SchoolAnnouncements",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notifications",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `type` TEXT NOT NULL, `date` INTEGER NOT NULL, `data` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "data",
+ "columnName": "data",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AdminMessages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `version_name` INTEGER, `version_max` INTEGER, `target_register_host` TEXT, `target_flavor` TEXT, `destination_url` TEXT, `priority` TEXT NOT NULL, `type` TEXT NOT NULL, `is_dismissible` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "versionMin",
+ "columnName": "version_name",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "versionMax",
+ "columnName": "version_max",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetRegisterHost",
+ "columnName": "target_register_host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetFlavor",
+ "columnName": "target_flavor",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "destinationUrl",
+ "columnName": "destination_url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "priority",
+ "columnName": "priority",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDismissible",
+ "columnName": "is_dismissible",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "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, 'f310243440ca00cbc35e62ebaca5c7d8')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/46.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/46.json
new file mode 100644
index 000000000..04518141c
--- /dev/null
+++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/46.json
@@ -0,0 +1,2430 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 46,
+ "identityHash": "f310243440ca00cbc35e62ebaca5c7d8",
+ "entities": [
+ {
+ "tableName": "Students",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `user_name` TEXT NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_short` 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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `nick` TEXT NOT NULL, `avatar_color` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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": "userName",
+ "columnName": "user_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentName",
+ "columnName": "student_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolSymbol",
+ "columnName": "school_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolShortName",
+ "columnName": "school_short",
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "nick",
+ "columnName": "nick",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "avatarColor",
+ "columnName": "avatar_color",
+ "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"
+ ],
+ "orders": [],
+ "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}` (`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, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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": "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "current",
+ "columnName": "is_current",
+ "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"
+ ],
+ "orders": [],
+ "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}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Timetable",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `student_plan` INTEGER NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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": "isStudentPlan",
+ "columnName": "student_plan",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "changes",
+ "columnName": "changes",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "canceled",
+ "columnName": "canceled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Attendance",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `time_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, `excusable` INTEGER NOT NULL, `excuse_status` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "timeId",
+ "columnName": "time_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
+ },
+ {
+ "fieldPath": "excusable",
+ "columnName": "excusable",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excuseStatus",
+ "columnName": "excuse_status",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AttendanceSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Grades",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "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
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_predicted_grade_notified` INTEGER NOT NULL, `is_final_grade_notified` INTEGER NOT NULL, `predicted_grade_last_change` INTEGER NOT NULL, `final_grade_last_change` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPredictedGradeNotified",
+ "columnName": "is_predicted_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFinalGradeNotified",
+ "columnName": "is_final_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "predictedGradeLastChange",
+ "columnName": "predicted_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalGradeLastChange",
+ "columnName": "final_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradePartialStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `class_average` TEXT NOT NULL, `student_average` TEXT NOT NULL, `class_amounts` TEXT NOT NULL, `student_amounts` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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": "classAverage",
+ "columnName": "class_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAverage",
+ "columnName": "student_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classAmounts",
+ "columnName": "class_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAmounts",
+ "columnName": "student_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesPointsStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `others` REAL NOT NULL, `student` REAL NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradeSemesterStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `amounts` TEXT NOT NULL, `student_grade` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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": "amounts",
+ "columnName": "amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentGrade",
+ "columnName": "student_grade",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Messages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `recipient_name` TEXT NOT NULL, `subject` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `removed` INTEGER NOT NULL, `has_attachments` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `unread_by` INTEGER NOT NULL, `read_by` INTEGER NOT NULL, `content` TEXT NOT NULL)",
+ "fields": [
+ {
+ "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": "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": "removed",
+ "columnName": "removed",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasAttachments",
+ "columnName": "has_attachments",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unreadBy",
+ "columnName": "unread_by",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "readBy",
+ "columnName": "read_by",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MessageAttachments",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `one_drive_id` TEXT NOT NULL, `url` TEXT NOT NULL, `filename` TEXT NOT NULL, PRIMARY KEY(`real_id`))",
+ "fields": [
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageId",
+ "columnName": "message_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "oneDriveId",
+ "columnName": "one_drive_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filename",
+ "columnName": "filename",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "real_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `category` TEXT NOT NULL, `category_type` INTEGER NOT NULL, `is_points_show` INTEGER NOT NULL, `points` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "categoryType",
+ "columnName": "category_type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPointsShow",
+ "columnName": "is_points_show",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "points",
+ "columnName": "points",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "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
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Homework",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `attachments` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_done` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `is_added_by_user` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "attachments",
+ "columnName": "attachments",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDone",
+ "columnName": "is_done",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Subjects",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "LuckyNumbers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "CompletedLesson",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "ReportingUnits",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unitId",
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Recipients",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MobileDevices",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "userLoginId",
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Teachers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "School",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Conferences",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `subject` TEXT NOT NULL, `agenda` TEXT NOT NULL, `present_on_conference` TEXT NOT NULL, `conference_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "agenda",
+ "columnName": "agenda",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presentOnConference",
+ "columnName": "present_on_conference",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "conferenceId",
+ "columnName": "conference_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableAdditional",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `repeat_id` BLOB DEFAULT NULL, `is_added_by_user` INTEGER NOT NULL DEFAULT 0)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "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": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "repeatId",
+ "columnName": "repeat_id",
+ "affinity": "BLOB",
+ "notNull": false,
+ "defaultValue": "NULL"
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "StudentInfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `full_name` TEXT NOT NULL, `first_name` TEXT NOT NULL, `second_name` TEXT NOT NULL, `surname` TEXT NOT NULL, `birth_date` INTEGER NOT NULL, `birth_place` TEXT NOT NULL, `gender` TEXT NOT NULL, `has_polish_citizenship` INTEGER NOT NULL, `family_name` TEXT NOT NULL, `parents_names` TEXT NOT NULL, `address` TEXT NOT NULL, `registered_address` TEXT NOT NULL, `correspondence_address` TEXT NOT NULL, `phone_number` TEXT NOT NULL, `cell_phone_number` TEXT NOT NULL, `email` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `first_guardian_full_name` TEXT, `first_guardian_kinship` TEXT, `first_guardian_address` TEXT, `first_guardian_phones` TEXT, `first_guardian_email` TEXT, `second_guardian_full_name` TEXT, `second_guardian_kinship` TEXT, `second_guardian_address` TEXT, `second_guardian_phones` TEXT, `second_guardian_email` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "full_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstName",
+ "columnName": "first_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "secondName",
+ "columnName": "second_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "surname",
+ "columnName": "surname",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthDate",
+ "columnName": "birth_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthPlace",
+ "columnName": "birth_place",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gender",
+ "columnName": "gender",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPolishCitizenship",
+ "columnName": "has_polish_citizenship",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "familyName",
+ "columnName": "family_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentsNames",
+ "columnName": "parents_names",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registeredAddress",
+ "columnName": "registered_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "correspondenceAddress",
+ "columnName": "correspondence_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "phoneNumber",
+ "columnName": "phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "cellPhoneNumber",
+ "columnName": "cell_phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstGuardian.fullName",
+ "columnName": "first_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.kinship",
+ "columnName": "first_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.address",
+ "columnName": "first_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.phones",
+ "columnName": "first_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.email",
+ "columnName": "first_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.fullName",
+ "columnName": "second_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.kinship",
+ "columnName": "second_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.address",
+ "columnName": "second_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.phones",
+ "columnName": "second_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.email",
+ "columnName": "second_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableHeaders",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "SchoolAnnouncements",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notifications",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `type` TEXT NOT NULL, `date` INTEGER NOT NULL, `data` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "data",
+ "columnName": "data",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AdminMessages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `version_name` INTEGER, `version_max` INTEGER, `target_register_host` TEXT, `target_flavor` TEXT, `destination_url` TEXT, `priority` TEXT NOT NULL, `type` TEXT NOT NULL, `is_dismissible` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "versionMin",
+ "columnName": "version_name",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "versionMax",
+ "columnName": "version_max",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetRegisterHost",
+ "columnName": "target_register_host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetFlavor",
+ "columnName": "target_flavor",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "destinationUrl",
+ "columnName": "destination_url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "priority",
+ "columnName": "priority",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDismissible",
+ "columnName": "is_dismissible",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "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, 'f310243440ca00cbc35e62ebaca5c7d8')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/47.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/47.json
new file mode 100644
index 000000000..3f8291eac
--- /dev/null
+++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/47.json
@@ -0,0 +1,2438 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 47,
+ "identityHash": "ac88c80d4bb923b22f22ce4f91521306",
+ "entities": [
+ {
+ "tableName": "Students",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `user_name` TEXT NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_short` 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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `nick` TEXT NOT NULL, `avatar_color` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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": "userName",
+ "columnName": "user_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentName",
+ "columnName": "student_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolSymbol",
+ "columnName": "school_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolShortName",
+ "columnName": "school_short",
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "nick",
+ "columnName": "nick",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "avatarColor",
+ "columnName": "avatar_color",
+ "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"
+ ],
+ "orders": [],
+ "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}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `kindergarten_diary_id` INTEGER NOT NULL DEFAULT 0, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "kindergartenDiaryId",
+ "columnName": "kindergarten_diary_id",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ },
+ {
+ "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": "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "current",
+ "columnName": "is_current",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id",
+ "unique": true,
+ "columnNames": [
+ "student_id",
+ "diary_id",
+ "kindergarten_diary_id",
+ "semester_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id` ON `${TABLE_NAME}` (`student_id`, `diary_id`, `kindergarten_diary_id`, `semester_id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Exams",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Timetable",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `student_plan` INTEGER NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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": "isStudentPlan",
+ "columnName": "student_plan",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "changes",
+ "columnName": "changes",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "canceled",
+ "columnName": "canceled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Attendance",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `time_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, `excusable` INTEGER NOT NULL, `excuse_status` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "timeId",
+ "columnName": "time_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
+ },
+ {
+ "fieldPath": "excusable",
+ "columnName": "excusable",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excuseStatus",
+ "columnName": "excuse_status",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AttendanceSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Grades",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "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
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_predicted_grade_notified` INTEGER NOT NULL, `is_final_grade_notified` INTEGER NOT NULL, `predicted_grade_last_change` INTEGER NOT NULL, `final_grade_last_change` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPredictedGradeNotified",
+ "columnName": "is_predicted_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFinalGradeNotified",
+ "columnName": "is_final_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "predictedGradeLastChange",
+ "columnName": "predicted_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalGradeLastChange",
+ "columnName": "final_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradePartialStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `class_average` TEXT NOT NULL, `student_average` TEXT NOT NULL, `class_amounts` TEXT NOT NULL, `student_amounts` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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": "classAverage",
+ "columnName": "class_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAverage",
+ "columnName": "student_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classAmounts",
+ "columnName": "class_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAmounts",
+ "columnName": "student_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesPointsStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `others` REAL NOT NULL, `student` REAL NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradeSemesterStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `amounts` TEXT NOT NULL, `student_grade` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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": "amounts",
+ "columnName": "amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentGrade",
+ "columnName": "student_grade",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Messages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `recipient_name` TEXT NOT NULL, `subject` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `removed` INTEGER NOT NULL, `has_attachments` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `unread_by` INTEGER NOT NULL, `read_by` INTEGER NOT NULL, `content` TEXT NOT NULL)",
+ "fields": [
+ {
+ "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": "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": "removed",
+ "columnName": "removed",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasAttachments",
+ "columnName": "has_attachments",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unreadBy",
+ "columnName": "unread_by",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "readBy",
+ "columnName": "read_by",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MessageAttachments",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `one_drive_id` TEXT NOT NULL, `url` TEXT NOT NULL, `filename` TEXT NOT NULL, PRIMARY KEY(`real_id`))",
+ "fields": [
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageId",
+ "columnName": "message_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "oneDriveId",
+ "columnName": "one_drive_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filename",
+ "columnName": "filename",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "real_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `category` TEXT NOT NULL, `category_type` INTEGER NOT NULL, `is_points_show` INTEGER NOT NULL, `points` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "categoryType",
+ "columnName": "category_type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPointsShow",
+ "columnName": "is_points_show",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "points",
+ "columnName": "points",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "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
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Homework",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `attachments` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_done` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `is_added_by_user` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "attachments",
+ "columnName": "attachments",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDone",
+ "columnName": "is_done",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Subjects",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "LuckyNumbers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "CompletedLesson",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "ReportingUnits",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unitId",
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Recipients",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MobileDevices",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "userLoginId",
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Teachers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "School",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Conferences",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `subject` TEXT NOT NULL, `agenda` TEXT NOT NULL, `present_on_conference` TEXT NOT NULL, `conference_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "agenda",
+ "columnName": "agenda",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presentOnConference",
+ "columnName": "present_on_conference",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "conferenceId",
+ "columnName": "conference_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableAdditional",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `repeat_id` BLOB DEFAULT NULL, `is_added_by_user` INTEGER NOT NULL DEFAULT 0)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "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": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "repeatId",
+ "columnName": "repeat_id",
+ "affinity": "BLOB",
+ "notNull": false,
+ "defaultValue": "NULL"
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "StudentInfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `full_name` TEXT NOT NULL, `first_name` TEXT NOT NULL, `second_name` TEXT NOT NULL, `surname` TEXT NOT NULL, `birth_date` INTEGER NOT NULL, `birth_place` TEXT NOT NULL, `gender` TEXT NOT NULL, `has_polish_citizenship` INTEGER NOT NULL, `family_name` TEXT NOT NULL, `parents_names` TEXT NOT NULL, `address` TEXT NOT NULL, `registered_address` TEXT NOT NULL, `correspondence_address` TEXT NOT NULL, `phone_number` TEXT NOT NULL, `cell_phone_number` TEXT NOT NULL, `email` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `first_guardian_full_name` TEXT, `first_guardian_kinship` TEXT, `first_guardian_address` TEXT, `first_guardian_phones` TEXT, `first_guardian_email` TEXT, `second_guardian_full_name` TEXT, `second_guardian_kinship` TEXT, `second_guardian_address` TEXT, `second_guardian_phones` TEXT, `second_guardian_email` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "full_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstName",
+ "columnName": "first_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "secondName",
+ "columnName": "second_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "surname",
+ "columnName": "surname",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthDate",
+ "columnName": "birth_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthPlace",
+ "columnName": "birth_place",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gender",
+ "columnName": "gender",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPolishCitizenship",
+ "columnName": "has_polish_citizenship",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "familyName",
+ "columnName": "family_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentsNames",
+ "columnName": "parents_names",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registeredAddress",
+ "columnName": "registered_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "correspondenceAddress",
+ "columnName": "correspondence_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "phoneNumber",
+ "columnName": "phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "cellPhoneNumber",
+ "columnName": "cell_phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstGuardian.fullName",
+ "columnName": "first_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.kinship",
+ "columnName": "first_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.address",
+ "columnName": "first_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.phones",
+ "columnName": "first_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.email",
+ "columnName": "first_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.fullName",
+ "columnName": "second_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.kinship",
+ "columnName": "second_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.address",
+ "columnName": "second_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.phones",
+ "columnName": "second_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.email",
+ "columnName": "second_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableHeaders",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "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": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "SchoolAnnouncements",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notifications",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `type` TEXT NOT NULL, `date` INTEGER NOT NULL, `data` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "data",
+ "columnName": "data",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AdminMessages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `version_name` INTEGER, `version_max` INTEGER, `target_register_host` TEXT, `target_flavor` TEXT, `destination_url` TEXT, `priority` TEXT NOT NULL, `type` TEXT NOT NULL, `is_dismissible` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "versionMin",
+ "columnName": "version_name",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "versionMax",
+ "columnName": "version_max",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetRegisterHost",
+ "columnName": "target_register_host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetFlavor",
+ "columnName": "target_flavor",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "destinationUrl",
+ "columnName": "destination_url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "priority",
+ "columnName": "priority",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDismissible",
+ "columnName": "is_dismissible",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "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, 'ac88c80d4bb923b22f22ce4f91521306')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index de4a80b06..72fee08a7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -114,7 +114,6 @@
-
{
@Query("SELECT * FROM Conferences WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :startDate")
- fun loadAll(diaryId: Int, studentId: Int, startDate: LocalDateTime): Flow>
+ fun loadAll(diaryId: Int, studentId: Int, startDate: Instant): Flow>
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt
index 3dda8a44b..853a7cb74 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt
@@ -1,12 +1,7 @@
package io.github.wulkanowy.data.db.dao
-import androidx.room.Dao
-import androidx.room.Delete
-import androidx.room.Insert
+import androidx.room.*
import androidx.room.OnConflictStrategy.ABORT
-import androidx.room.Query
-import androidx.room.Transaction
-import androidx.room.Update
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/TimetableAdditionalDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/TimetableAdditionalDao.kt
index 335e003e1..914ce340a 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/TimetableAdditionalDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/TimetableAdditionalDao.kt
@@ -5,6 +5,7 @@ import androidx.room.Query
import io.github.wulkanowy.data.db.entities.TimetableAdditional
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
+import java.util.UUID
import javax.inject.Singleton
@Dao
@@ -12,5 +13,13 @@ import javax.inject.Singleton
interface TimetableAdditionalDao : BaseDao {
@Query("SELECT * FROM TimetableAdditional WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
- fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow>
+ fun loadAll(
+ diaryId: Int,
+ studentId: Int,
+ from: LocalDate,
+ end: LocalDate
+ ): Flow>
+
+ @Query("DELETE FROM TimetableAdditional WHERE repeat_id = :repeatId")
+ suspend fun deleteAllByRepeatId(repeatId: UUID)
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Conference.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Conference.kt
index 4ad946508..ba3958dbc 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Conference.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Conference.kt
@@ -4,7 +4,7 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
-import java.time.LocalDateTime
+import java.time.Instant
@Entity(tableName = "Conferences")
data class Conference(
@@ -27,7 +27,7 @@ data class Conference(
@ColumnInfo(name = "conference_id")
val conferenceId: Int,
- val date: LocalDateTime
+ val date: Instant,
) : Serializable {
@PrimaryKey(autoGenerate = true)
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/GradeSummary.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/GradeSummary.kt
index fb7b60bbc..a42832ced 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/GradeSummary.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/GradeSummary.kt
@@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
-import java.time.LocalDateTime
+import java.time.Instant
@Entity(tableName = "GradesSummary")
data class GradeSummary(
@@ -45,8 +45,8 @@ data class GradeSummary(
var isFinalGradeNotified: Boolean = true
@ColumnInfo(name = "predicted_grade_last_change")
- var predictedGradeLastChange: LocalDateTime = LocalDateTime.now()
+ var predictedGradeLastChange: Instant = Instant.now()
@ColumnInfo(name = "final_grade_last_change")
- var finalGradeLastChange: LocalDateTime = LocalDateTime.now()
+ var finalGradeLastChange: Instant = Instant.now()
}
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 7b6e0dbf2..8782bc765 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
@@ -4,7 +4,7 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
-import java.time.LocalDateTime
+import java.time.Instant
@Entity(tableName = "Messages")
data class Message(
@@ -29,7 +29,7 @@ data class Message(
val subject: String,
- val date: LocalDateTime,
+ val date: Instant,
@ColumnInfo(name = "folder_id")
val folderId: Int,
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/MobileDevice.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/MobileDevice.kt
index 83d82c0b9..887e43239 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/MobileDevice.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/MobileDevice.kt
@@ -4,7 +4,7 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
-import java.time.LocalDateTime
+import java.time.Instant
@Entity(tableName = "MobileDevices")
data class MobileDevice(
@@ -17,7 +17,7 @@ data class MobileDevice(
val name: String,
- val date: LocalDateTime
+ val date: Instant,
) : Serializable {
@PrimaryKey(autoGenerate = true)
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Notification.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Notification.kt
index 740137f0f..4867e3329 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Notification.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Notification.kt
@@ -4,7 +4,7 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import io.github.wulkanowy.services.sync.notifications.NotificationType
-import java.time.LocalDateTime
+import java.time.Instant
@Entity(tableName = "Notifications")
data class Notification(
@@ -18,7 +18,7 @@ data class Notification(
val type: NotificationType,
- val date: LocalDateTime,
+ val date: Instant,
val data: String? = null
) {
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Semester.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Semester.kt
index 3b1f0add5..187890c9b 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Semester.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Semester.kt
@@ -7,7 +7,12 @@ import androidx.room.PrimaryKey
import java.io.Serializable
import java.time.LocalDate
-@Entity(tableName = "Semesters", indices = [Index(value = ["student_id", "diary_id", "semester_id"], unique = true)])
+@Entity(
+ tableName = "Semesters", indices = [Index(
+ value = ["student_id", "diary_id", "kindergarten_diary_id", "semester_id"],
+ unique = true
+ )]
+)
data class Semester(
@ColumnInfo(name = "student_id")
@@ -16,6 +21,9 @@ data class Semester(
@ColumnInfo(name = "diary_id")
val diaryId: Int,
+ @ColumnInfo(name = "kindergarten_diary_id", defaultValue = "0")
+ val kindergartenDiaryId: Int,
+
@ColumnInfo(name = "diary_name")
val diaryName: String,
@@ -37,12 +45,11 @@ data class Semester(
@ColumnInfo(name = "unit_id")
val unitId: Int
-): Serializable {
+) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
-
@ColumnInfo(name = "is_current")
var current: Boolean = false
}
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 af9fe831a..76da9643d 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
@@ -5,7 +5,7 @@ import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import java.io.Serializable
-import java.time.LocalDateTime
+import java.time.Instant
@Entity(
tableName = "Students",
@@ -74,7 +74,7 @@ data class Student(
val isCurrent: Boolean,
@ColumnInfo(name = "registration_date")
- val registrationDate: LocalDateTime
+ val registrationDate: Instant,
) : Serializable {
@PrimaryKey(autoGenerate = true)
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Timetable.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Timetable.kt
index 29b3737bc..d23d388f9 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Timetable.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Timetable.kt
@@ -4,8 +4,8 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
+import java.time.Instant
import java.time.LocalDate
-import java.time.LocalDateTime
@Entity(tableName = "Timetable")
data class Timetable(
@@ -18,9 +18,9 @@ data class Timetable(
val number: Int,
- val start: LocalDateTime,
+ val start: Instant,
- val end: LocalDateTime,
+ val end: Instant,
val date: LocalDate,
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/TimetableAdditional.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/TimetableAdditional.kt
index c1f1365f9..478026102 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/TimetableAdditional.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/TimetableAdditional.kt
@@ -4,8 +4,9 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
+import java.time.Instant
import java.time.LocalDate
-import java.time.LocalDateTime
+import java.util.*
@Entity(tableName = "TimetableAdditional")
data class TimetableAdditional(
@@ -16,9 +17,9 @@ data class TimetableAdditional(
@ColumnInfo(name = "diary_id")
val diaryId: Int,
- val start: LocalDateTime,
+ val start: Instant,
- val end: LocalDateTime,
+ val end: Instant,
val date: LocalDate,
@@ -27,4 +28,10 @@ data class TimetableAdditional(
@PrimaryKey(autoGenerate = true)
var id: Long = 0
+
+ @ColumnInfo(name = "repeat_id", defaultValue = "NULL")
+ var repeatId: UUID? = null
+
+ @ColumnInfo(name = "is_added_by_user", defaultValue = "0")
+ var isAddedByUser: Boolean = false
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration12.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration12.kt
index 1dc38e14c..c827b82ba 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration12.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration12.kt
@@ -43,12 +43,14 @@ class Migration12 : Migration(11, 12) {
private fun getStudentsIds(database: SupportSQLiteDatabase): List {
val students = mutableListOf()
- val studentsCursor = database.query("SELECT student_id FROM Students")
- if (studentsCursor.moveToFirst()) {
- do {
- students.add(studentsCursor.getInt(0))
- } while (studentsCursor.moveToNext())
+ database.query("SELECT student_id FROM Students").use {
+ if (it.moveToFirst()) {
+ do {
+ students.add(it.getInt(0))
+ } while (it.moveToNext())
+ }
}
+
return students
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration13.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration13.kt
index 0cf8cd9b0..36de1e837 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration13.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration13.kt
@@ -25,12 +25,14 @@ class Migration13 : Migration(12, 13) {
private fun getStudentsIds(database: SupportSQLiteDatabase): MutableList> {
val students = mutableListOf>()
- val studentsCursor = database.query("SELECT id, school_name FROM Students")
- if (studentsCursor.moveToFirst()) {
- do {
- students.add(studentsCursor.getInt(0) to studentsCursor.getString(1))
- } while (studentsCursor.moveToNext())
+ database.query("SELECT id, school_name FROM Students").use {
+ if (it.moveToFirst()) {
+ do {
+ students.add(it.getInt(0) to it.getString(1))
+ } while (it.moveToNext())
+ }
}
+
return students
}
@@ -42,12 +44,14 @@ class Migration13 : Migration(12, 13) {
private fun getStudentsAndClassIds(database: SupportSQLiteDatabase): List> {
val students = mutableListOf>()
- val studentsCursor = database.query("SELECT student_id, class_id FROM Students")
- if (studentsCursor.moveToFirst()) {
- do {
- students.add(studentsCursor.getInt(0) to studentsCursor.getInt(1))
- } while (studentsCursor.moveToNext())
+ database.query("SELECT student_id, class_id FROM Students").use {
+ if (it.moveToFirst()) {
+ do {
+ students.add(it.getInt(0) to it.getInt(1))
+ } while (it.moveToNext())
+ }
}
+
return students
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration27.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration27.kt
index 6592228a1..5c60beead 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration27.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration27.kt
@@ -22,24 +22,28 @@ class Migration27 : Migration(26, 27) {
private fun getStudentsIdsAndNames(database: SupportSQLiteDatabase): MutableList> {
val students = mutableListOf>()
- val studentsCursor = database.query("SELECT id, user_login_id, student_name FROM Students")
- if (studentsCursor.moveToFirst()) {
- do {
- students.add(Triple(studentsCursor.getLong(0), studentsCursor.getInt(1), studentsCursor.getString(2)))
- } while (studentsCursor.moveToNext())
+ database.query("SELECT id, user_login_id, student_name FROM Students").use {
+ if (it.moveToFirst()) {
+ do {
+ students.add(Triple(it.getLong(0), it.getInt(1), it.getString(2)))
+ } while (it.moveToNext())
+ }
}
+
return students
}
private fun getReportingUnits(database: SupportSQLiteDatabase): MutableList> {
val units = mutableListOf>()
- val unitsCursor = database.query("SELECT sender_id, sender_name FROM ReportingUnits")
- if (unitsCursor.moveToFirst()) {
- do {
- units.add(unitsCursor.getInt(0) to unitsCursor.getString(1))
- } while (unitsCursor.moveToNext())
+ database.query("SELECT sender_id, sender_name FROM ReportingUnits").use {
+ if (it.moveToFirst()) {
+ do {
+ units.add(it.getInt(0) to it.getString(1))
+ } while (it.moveToNext())
+ }
}
+
return units
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration35.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration35.kt
index cc540388c..f63431d00 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration35.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration35.kt
@@ -10,15 +10,17 @@ class Migration35(private val appInfo: AppInfo) : Migration(34, 35) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN `avatar_color` INTEGER NOT NULL DEFAULT 0")
- val studentsCursor = database.query("SELECT * FROM Students")
-
- while (studentsCursor.moveToNext()) {
- val studentId = studentsCursor.getLongOrNull(0)
- database.execSQL(
- """UPDATE Students
- SET avatar_color = ${appInfo.defaultColorsForAvatar.random()}
- WHERE id = $studentId"""
- )
+ database.query("SELECT * FROM Students").use {
+ while (it.moveToNext()) {
+ val studentId = it.getLongOrNull(0)
+ database.execSQL(
+ """
+ UPDATE Students
+ SET avatar_color = ${appInfo.defaultColorsForAvatar.random()}
+ WHERE id = $studentId
+ """
+ )
+ }
}
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration46.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration46.kt
new file mode 100644
index 000000000..d3fa5cf93
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration46.kt
@@ -0,0 +1,102 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+import java.time.Instant
+import java.time.ZoneId
+import java.time.ZoneOffset
+
+class Migration46 : Migration(45, 46) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ migrateConferences(database)
+ migrateMessages(database)
+ migrateMobileDevices(database)
+ migrateNotifications(database)
+ migrateTimetable(database)
+ migrateTimetableAdditional(database)
+ }
+
+ private fun migrateConferences(database: SupportSQLiteDatabase) {
+ database.query("SELECT * FROM Conferences").use {
+ while (it.moveToNext()) {
+ val id = it.getLong(it.getColumnIndexOrThrow("id"))
+ val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date"))
+ val timestampUtc = timestampLocal.timestampLocalToUTC()
+
+ database.execSQL("UPDATE Conferences SET date = $timestampUtc WHERE id = $id")
+ }
+ }
+ }
+
+ private fun migrateMessages(database: SupportSQLiteDatabase) {
+ database.query("SELECT * FROM Messages").use {
+ while (it.moveToNext()) {
+ val id = it.getLong(it.getColumnIndexOrThrow("id"))
+ val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date"))
+ val timestampUtc = timestampLocal.timestampLocalToUTC()
+
+ database.execSQL("UPDATE Messages SET date = $timestampUtc WHERE id = $id")
+ }
+ }
+ }
+
+ private fun migrateMobileDevices(database: SupportSQLiteDatabase) {
+ database.query("SELECT * FROM MobileDevices").use {
+ while (it.moveToNext()) {
+ val id = it.getLong(it.getColumnIndexOrThrow("id"))
+ val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date"))
+ val timestampUtc = timestampLocal.timestampLocalToUTC()
+
+ database.execSQL("UPDATE MobileDevices SET date = $timestampUtc WHERE id = $id")
+ }
+ }
+ }
+
+ private fun migrateNotifications(database: SupportSQLiteDatabase) {
+ database.query("SELECT * FROM Notifications").use {
+ while (it.moveToNext()) {
+ val id = it.getLong(it.getColumnIndexOrThrow("id"))
+ val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date"))
+ val timestampUtc = timestampLocal.timestampLocalToUTC()
+
+ database.execSQL("UPDATE Notifications SET date = $timestampUtc WHERE id = $id")
+ }
+ }
+ }
+
+ private fun migrateTimetable(database: SupportSQLiteDatabase) {
+ database.query("SELECT * FROM Timetable").use {
+ while (it.moveToNext()) {
+ val id = it.getLong(it.getColumnIndexOrThrow("id"))
+ val timestampLocalStart = it.getLong(it.getColumnIndexOrThrow("start"))
+ val timestampLocalEnd = it.getLong(it.getColumnIndexOrThrow("end"))
+ val timestampUtcStart = timestampLocalStart.timestampLocalToUTC()
+ val timestampUtcEnd = timestampLocalEnd.timestampLocalToUTC()
+
+ database.execSQL("UPDATE Timetable SET start = $timestampUtcStart, end = $timestampUtcEnd WHERE id = $id")
+ }
+ }
+ }
+
+ private fun migrateTimetableAdditional(database: SupportSQLiteDatabase) {
+ database.query("SELECT * FROM TimetableAdditional").use {
+ while (it.moveToNext()) {
+ val id = it.getLong(it.getColumnIndexOrThrow("id"))
+ val timestampLocalStart = it.getLong(it.getColumnIndexOrThrow("start"))
+ val timestampLocalEnd = it.getLong(it.getColumnIndexOrThrow("end"))
+ val timestampUtcStart = timestampLocalStart.timestampLocalToUTC()
+ val timestampUtcEnd = timestampLocalEnd.timestampLocalToUTC()
+
+ database.execSQL("UPDATE TimetableAdditional SET start = $timestampUtcStart, end = $timestampUtcEnd WHERE id = $id")
+ }
+ }
+ }
+
+ private fun Long.timestampLocalToUTC(): Long = Instant.ofEpochMilli(this)
+ .atZone(ZoneOffset.UTC)
+ .withZoneSameLocal(ZoneId.of("Europe/Warsaw"))
+ .withZoneSameInstant(ZoneId.systemDefault())
+ .toInstant()
+ .toEpochMilli()
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/ConferenceMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/ConferenceMapper.kt
index 52dc9b30b..17a9e5cdb 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/ConferenceMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/ConferenceMapper.kt
@@ -10,7 +10,7 @@ fun List.mapToEntities(semester: Semester) = map {
diaryId = semester.diaryId,
agenda = it.agenda,
conferenceId = it.id,
- date = it.date,
+ date = it.dateZoned.toInstant(),
presentOnConference = it.presentOnConference,
subject = it.subject,
title = it.title
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/DirectorInformationMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/DirectorInformationMapper.kt
index e6bf000b1..d059db816 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/DirectorInformationMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/DirectorInformationMapper.kt
@@ -6,7 +6,7 @@ import io.github.wulkanowy.sdk.pojo.DirectorInformation as SdkDirectorInformatio
fun List.mapToEntities(student: Student) = map {
SchoolAnnouncement(
- studentId = student.studentId,
+ studentId = student.userLoginId,
date = it.date,
subject = it.subject,
content = it.content,
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
index 913e4d030..13f0ab33e 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
@@ -4,7 +4,7 @@ import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageAttachment
import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.Student
-import java.time.LocalDateTime
+import java.time.Instant
import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
@@ -18,7 +18,7 @@ fun List.mapToEntities(student: Student) = map {
senderId = it.sender?.loginId ?: 0,
recipient = it.recipients.singleOrNull()?.name ?: "Wielu adresatów",
subject = it.subject.trim(),
- date = it.date ?: LocalDateTime.now(),
+ date = it.dateZoned?.toInstant() ?: Instant.now(),
folderId = it.folderId,
unread = it.unread ?: false,
removed = it.removed,
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/MobileDeviceMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/MobileDeviceMapper.kt
index f0c375bfa..b1e96a27b 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/MobileDeviceMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/MobileDeviceMapper.kt
@@ -3,13 +3,13 @@ package io.github.wulkanowy.data.mappers
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.sdk.pojo.Token as SdkToken
import io.github.wulkanowy.sdk.pojo.Device as SdkDevice
+import io.github.wulkanowy.sdk.pojo.Token as SdkToken
fun List.mapToEntities(semester: Semester) = map {
MobileDevice(
userLoginId = semester.studentId,
- date = it.createDate,
+ date = it.createDateZoned.toInstant(),
deviceId = it.id,
name = it.name
)
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/SemesterMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/SemesterMapper.kt
index acd93a91a..67d68a1e3 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/SemesterMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/SemesterMapper.kt
@@ -7,6 +7,7 @@ fun List.mapToEntities(studentId: Int) = map {
Semester(
studentId = studentId,
diaryId = it.diaryId,
+ kindergartenDiaryId = it.kindergartenDiaryId,
diaryName = it.diaryName,
schoolYear = it.schoolYear,
semesterId = it.semesterId,
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/StudentMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/StudentMapper.kt
index c93323038..a2110d7f5 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/StudentMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/StudentMapper.kt
@@ -2,7 +2,7 @@ package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
-import java.time.LocalDateTime
+import java.time.Instant
import io.github.wulkanowy.sdk.pojo.Student as SdkStudent
fun List.mapToEntities(password: String = "", colors: List) = map {
@@ -24,7 +24,7 @@ fun List.mapToEntities(password: String = "", colors: List) =
scrapperBaseUrl = it.scrapperBaseUrl,
loginType = it.loginType.name,
isCurrent = false,
- registrationDate = LocalDateTime.now(),
+ registrationDate = Instant.now(),
mobileBaseUrl = it.mobileBaseUrl,
privateKey = it.privateKey,
certificateKey = it.certificateKey,
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/TimetableMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/TimetableMapper.kt
index 045101c42..e55aa3cf7 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/TimetableMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/TimetableMapper.kt
@@ -21,8 +21,8 @@ fun List.mapToEntities(semester: Semester) = map {
studentId = semester.studentId,
diaryId = semester.diaryId,
number = it.number,
- start = it.start,
- end = it.end,
+ start = it.startZoned.toInstant(),
+ end = it.endZoned.toInstant(),
date = it.date,
subject = it.subject,
subjectOld = it.subjectOld,
@@ -45,8 +45,8 @@ fun List.mapToEntities(semester: Semester) = map {
diaryId = semester.diaryId,
subject = it.subject,
date = it.date,
- start = it.start,
- end = it.end
+ start = it.startZoned.toInstant(),
+ end = it.endZoned.toInstant(),
)
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/AdminMessageRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/AdminMessageRepository.kt
index 1b17e3bf3..e455411ea 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/AdminMessageRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/AdminMessageRepository.kt
@@ -4,7 +4,6 @@ import io.github.wulkanowy.data.api.AdminMessageService
import io.github.wulkanowy.data.db.dao.AdminMessageDao
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.AppInfo
-import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.networkBoundResource
import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject
@@ -14,23 +13,17 @@ import javax.inject.Singleton
class AdminMessageRepository @Inject constructor(
private val adminMessageService: AdminMessageService,
private val adminMessageDao: AdminMessageDao,
- private val appInfo: AppInfo,
- private val refreshHelper: AutoRefreshHelper,
+ private val appInfo: AppInfo
) {
private val saveFetchResultMutex = Mutex()
- private val cacheKey = "admin_messages"
-
- suspend fun getAdminMessages(student: Student, forceRefresh: Boolean) = networkBoundResource(
+ suspend fun getAdminMessages(student: Student) = networkBoundResource(
mutex = saveFetchResultMutex,
query = { adminMessageDao.loadAll() },
fetch = { adminMessageService.getAdminMessages() },
- shouldFetch = {
- refreshHelper.shouldBeRefreshed(cacheKey) || forceRefresh
- },
+ shouldFetch = { true },
saveFetchResult = { oldItems, newItems ->
adminMessageDao.removeOldAndSaveNew(oldItems, newItems)
- refreshHelper.updateLastRefreshTimestamp(cacheKey)
},
showSavedOnLoading = false,
mapResult = { adminMessages ->
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceRepository.kt
index ec9198175..7184f5576 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceRepository.kt
@@ -7,13 +7,7 @@ import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Absent
-import io.github.wulkanowy.utils.AutoRefreshHelper
-import io.github.wulkanowy.utils.getRefreshKey
-import io.github.wulkanowy.utils.init
-import io.github.wulkanowy.utils.monday
-import io.github.wulkanowy.utils.networkBoundResource
-import io.github.wulkanowy.utils.sunday
-import io.github.wulkanowy.utils.uniqueSubtract
+import io.github.wulkanowy.utils.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex
import java.time.LocalDate
@@ -52,7 +46,8 @@ class AttendanceRepository @Inject constructor(
attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)
},
fetch = {
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getAttendance(start.monday, end.sunday, semester.semesterId)
.mapToEntities(semester)
},
@@ -90,7 +85,8 @@ class AttendanceRepository @Inject constructor(
timeId = attendance.timeId
)
}
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.excuseForAbsence(items, reason)
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceSummaryRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceSummaryRepository.kt
index bc1fb2343..0857475f8 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceSummaryRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceSummaryRepository.kt
@@ -5,11 +5,7 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
-import io.github.wulkanowy.utils.AutoRefreshHelper
-import io.github.wulkanowy.utils.getRefreshKey
-import io.github.wulkanowy.utils.init
-import io.github.wulkanowy.utils.networkBoundResource
-import io.github.wulkanowy.utils.uniqueSubtract
+import io.github.wulkanowy.utils.*
import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject
import javax.inject.Singleton
@@ -38,7 +34,8 @@ class AttendanceSummaryRepository @Inject constructor(
},
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId) },
fetch = {
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getAttendanceSummary(subjectId)
.mapToEntities(semester, subjectId)
},
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/CompletedLessonsRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/CompletedLessonsRepository.kt
index c2e5a7217..2055f3f47 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/CompletedLessonsRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/CompletedLessonsRepository.kt
@@ -5,13 +5,7 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
-import io.github.wulkanowy.utils.AutoRefreshHelper
-import io.github.wulkanowy.utils.getRefreshKey
-import io.github.wulkanowy.utils.init
-import io.github.wulkanowy.utils.monday
-import io.github.wulkanowy.utils.networkBoundResource
-import io.github.wulkanowy.utils.sunday
-import io.github.wulkanowy.utils.uniqueSubtract
+import io.github.wulkanowy.utils.*
import kotlinx.coroutines.sync.Mutex
import java.time.LocalDate
import javax.inject.Inject
@@ -51,7 +45,8 @@ class CompletedLessonsRepository @Inject constructor(
)
},
fetch = {
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getCompletedLessons(start.monday, end.sunday)
.mapToEntities(semester)
},
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/ConferenceRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/ConferenceRepository.kt
index e32271833..6af24d73f 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/ConferenceRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/ConferenceRepository.kt
@@ -6,16 +6,10 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
-import io.github.wulkanowy.utils.AutoRefreshHelper
-import io.github.wulkanowy.utils.getRefreshKey
-import io.github.wulkanowy.utils.init
-import io.github.wulkanowy.utils.networkBoundResource
-import io.github.wulkanowy.utils.uniqueSubtract
+import io.github.wulkanowy.utils.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex
import java.time.Instant
-import java.time.LocalDateTime
-import java.time.ZoneOffset
import javax.inject.Inject
import javax.inject.Singleton
@@ -35,7 +29,7 @@ class ConferenceRepository @Inject constructor(
semester: Semester,
forceRefresh: Boolean,
notify: Boolean = false,
- startDate: LocalDateTime = LocalDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC),
+ startDate: Instant = Instant.EPOCH,
) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = {
@@ -46,7 +40,8 @@ class ConferenceRepository @Inject constructor(
conferenceDb.loadAll(semester.diaryId, student.studentId, startDate)
},
fetch = {
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getConferences()
.mapToEntities(semester)
.filter { it.date >= startDate }
@@ -66,7 +61,7 @@ class ConferenceRepository @Inject constructor(
conferenceDb.loadAll(
diaryId = semester.diaryId,
studentId = semester.studentId,
- startDate = LocalDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC)
+ startDate = Instant.EPOCH,
)
suspend fun updateConference(conference: List) = conferenceDb.updateAll(conference)
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/ExamRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/ExamRepository.kt
index 9bdac0658..c655c8001 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/ExamRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/ExamRepository.kt
@@ -6,13 +6,7 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
-import io.github.wulkanowy.utils.AutoRefreshHelper
-import io.github.wulkanowy.utils.endExamsDay
-import io.github.wulkanowy.utils.getRefreshKey
-import io.github.wulkanowy.utils.init
-import io.github.wulkanowy.utils.networkBoundResource
-import io.github.wulkanowy.utils.startExamsDay
-import io.github.wulkanowy.utils.uniqueSubtract
+import io.github.wulkanowy.utils.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex
import java.time.LocalDate
@@ -54,7 +48,8 @@ class ExamRepository @Inject constructor(
)
},
fetch = {
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getExams(start.startExamsDay, start.endExamsDay, semester.semesterId)
.mapToEntities(semester)
},
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/GradeRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/GradeRepository.kt
index 6c574b48a..f4087a887 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/GradeRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/GradeRepository.kt
@@ -8,16 +8,12 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
-import io.github.wulkanowy.utils.AutoRefreshHelper
-import io.github.wulkanowy.utils.getRefreshKey
-import io.github.wulkanowy.utils.init
-import io.github.wulkanowy.utils.networkBoundResource
-import io.github.wulkanowy.utils.uniqueSubtract
+import io.github.wulkanowy.utils.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.sync.Mutex
-import java.time.LocalDateTime
+import java.time.Instant
import javax.inject.Inject
import javax.inject.Singleton
@@ -51,7 +47,7 @@ class GradeRepository @Inject constructor(
},
fetch = {
val (details, summary) = sdk.init(student)
- .switchDiary(semester.diaryId, semester.schoolYear)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getGrades(semester.semesterId)
details.mapToEntities(semester) to summary.mapToEntities(semester)
@@ -70,8 +66,8 @@ class GradeRepository @Inject constructor(
newDetails: List,
notify: Boolean
) {
- val notifyBreakDate = oldGrades.maxByOrNull {it.date }
- ?.date ?: student.registrationDate.toLocalDate()
+ val notifyBreakDate = oldGrades.maxByOrNull { it.date }?.date
+ ?: student.registrationDate.toLocalDate()
gradeDb.deleteAll(oldGrades uniqueSubtract newDetails)
gradeDb.insertAll((newDetails uniqueSubtract oldGrades).onEach {
if (it.date >= notifyBreakDate) it.apply {
@@ -101,13 +97,13 @@ class GradeRepository @Inject constructor(
}
summary.predictedGradeLastChange = when {
- oldSummary == null -> LocalDateTime.now()
- summary.predictedGrade != oldSummary.predictedGrade -> LocalDateTime.now()
+ oldSummary == null -> Instant.now()
+ summary.predictedGrade != oldSummary.predictedGrade -> Instant.now()
else -> oldSummary.predictedGradeLastChange
}
summary.finalGradeLastChange = when {
- oldSummary == null -> LocalDateTime.now()
- summary.finalGrade != oldSummary.finalGrade -> LocalDateTime.now()
+ oldSummary == null -> Instant.now()
+ summary.finalGrade != oldSummary.finalGrade -> Instant.now()
else -> oldSummary.finalGradeLastChange
}
})
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/GradeStatisticsRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/GradeStatisticsRepository.kt
index 6c36f163b..356c203d0 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/GradeStatisticsRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/GradeStatisticsRepository.kt
@@ -12,13 +12,9 @@ import io.github.wulkanowy.data.mappers.mapPointsToStatisticsItems
import io.github.wulkanowy.data.mappers.mapSemesterToStatisticItems
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
-import io.github.wulkanowy.utils.AutoRefreshHelper
-import io.github.wulkanowy.utils.getRefreshKey
-import io.github.wulkanowy.utils.init
-import io.github.wulkanowy.utils.networkBoundResource
-import io.github.wulkanowy.utils.uniqueSubtract
+import io.github.wulkanowy.utils.*
import kotlinx.coroutines.sync.Mutex
-import java.util.Locale
+import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
@@ -54,7 +50,8 @@ class GradeStatisticsRepository @Inject constructor(
},
query = { gradePartialStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = {
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getGradesPartialStatistics(semester.semesterId)
.mapToEntities(semester)
},
@@ -101,7 +98,8 @@ class GradeStatisticsRepository @Inject constructor(
},
query = { gradeSemesterStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = {
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getGradesSemesterStatistics(semester.semesterId)
.mapToEntities(semester)
},
@@ -155,7 +153,8 @@ class GradeStatisticsRepository @Inject constructor(
},
query = { gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = {
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getGradesPointsStatistics(semester.semesterId)
.mapToEntities(semester)
},
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/HomeworkRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/HomeworkRepository.kt
index 95a375a45..900d9a68e 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/HomeworkRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/HomeworkRepository.kt
@@ -6,13 +6,7 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
-import io.github.wulkanowy.utils.AutoRefreshHelper
-import io.github.wulkanowy.utils.getRefreshKey
-import io.github.wulkanowy.utils.init
-import io.github.wulkanowy.utils.monday
-import io.github.wulkanowy.utils.networkBoundResource
-import io.github.wulkanowy.utils.sunday
-import io.github.wulkanowy.utils.uniqueSubtract
+import io.github.wulkanowy.utils.*
import kotlinx.coroutines.sync.Mutex
import java.time.LocalDate
import javax.inject.Inject
@@ -53,7 +47,8 @@ class HomeworkRepository @Inject constructor(
)
},
fetch = {
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getHomework(start.monday, end.sunday)
.mapToEntities(semester)
},
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/MobileDeviceRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/MobileDeviceRepository.kt
index bf17cbbc5..f825c36df 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/MobileDeviceRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/MobileDeviceRepository.kt
@@ -8,11 +8,7 @@ import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.mappers.mapToMobileDeviceToken
import io.github.wulkanowy.data.pojos.MobileDeviceToken
import io.github.wulkanowy.sdk.Sdk
-import io.github.wulkanowy.utils.AutoRefreshHelper
-import io.github.wulkanowy.utils.getRefreshKey
-import io.github.wulkanowy.utils.init
-import io.github.wulkanowy.utils.networkBoundResource
-import io.github.wulkanowy.utils.uniqueSubtract
+import io.github.wulkanowy.utils.*
import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject
import javax.inject.Singleton
@@ -40,7 +36,8 @@ class MobileDeviceRepository @Inject constructor(
},
query = { mobileDb.loadAll(student.userLoginId.takeIf { it != 0 } ?: student.studentId) },
fetch = {
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getRegisteredDevices()
.mapToEntities(semester)
},
@@ -53,14 +50,16 @@ class MobileDeviceRepository @Inject constructor(
)
suspend fun unregisterDevice(student: Student, semester: Semester, device: MobileDevice) {
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.unregisterDevice(device.deviceId)
mobileDb.deleteAll(listOf(device))
}
suspend fun getToken(student: Student, semester: Semester): MobileDeviceToken {
- return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ return sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getToken()
.mapToMobileDeviceToken()
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/NoteRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/NoteRepository.kt
index c1738b36e..19ad8f037 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/NoteRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/NoteRepository.kt
@@ -6,11 +6,7 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
-import io.github.wulkanowy.utils.AutoRefreshHelper
-import io.github.wulkanowy.utils.getRefreshKey
-import io.github.wulkanowy.utils.init
-import io.github.wulkanowy.utils.networkBoundResource
-import io.github.wulkanowy.utils.uniqueSubtract
+import io.github.wulkanowy.utils.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject
@@ -42,7 +38,8 @@ class NoteRepository @Inject constructor(
},
query = { noteDb.loadAll(student.studentId) },
fetch = {
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getNotes(semester.semesterId)
.mapToEntities(semester)
},
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt
index 48eac48a2..4cd85586f 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt
@@ -7,24 +7,16 @@ import com.fredporciuncula.flow.preferences.FlowSharedPreferences
import com.fredporciuncula.flow.preferences.Preference
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.R
-import io.github.wulkanowy.data.enums.AppTheme
-import io.github.wulkanowy.data.enums.GradeColorTheme
-import io.github.wulkanowy.data.enums.GradeExpandMode
-import io.github.wulkanowy.data.enums.GradeSortingMode
-import io.github.wulkanowy.data.enums.TimetableMode
-import io.github.wulkanowy.sdk.toLocalDate
+import io.github.wulkanowy.data.enums.*
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
-import io.github.wulkanowy.utils.toLocalDateTime
-import io.github.wulkanowy.utils.toTimestamp
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
-import java.time.LocalDate
-import java.time.LocalDateTime
+import java.time.Instant
import javax.inject.Inject
import javax.inject.Singleton
@@ -133,6 +125,12 @@ class PreferencesRepository @Inject constructor(
R.bool.pref_default_notification_piggyback
)
+ val isNotificationPiggybackRemoveOriginalEnabled: Boolean
+ get() = getBoolean(
+ R.string.pref_key_notifications_piggyback_cancel_original,
+ R.bool.pref_default_notification_piggyback_cancel_original
+ )
+
val isDebugNotificationEnableKey = context.getString(R.string.pref_key_notification_debug)
val isDebugNotificationEnable: Boolean
get() = getBoolean(isDebugNotificationEnableKey, R.bool.pref_default_notification_debug)
@@ -202,10 +200,10 @@ class PreferencesRepository @Inject constructor(
R.bool.pref_default_optional_arithmetic_average
)
- var lasSyncDate: LocalDateTime
+ var lasSyncDate: Instant?
get() = getLong(R.string.pref_key_last_sync_date, R.string.pref_default_last_sync_date)
- .toLocalDateTime()
- set(value) = sharedPref.edit().putLong("last_sync_date", value.toTimestamp()).apply()
+ .takeIf { it != 0L }?.let(Instant::ofEpochMilli)
+ set(value) = sharedPref.edit().putLong("last_sync_date", value?.toEpochMilli() ?: 0).apply()
var dashboardItemsPosition: Map?
get() {
@@ -264,11 +262,12 @@ class PreferencesRepository @Inject constructor(
get() = sharedPref.getInt(PREF_KEY_IN_APP_REVIEW_COUNT, 0)
set(value) = sharedPref.edit().putInt(PREF_KEY_IN_APP_REVIEW_COUNT, value).apply()
- var inAppReviewDate: LocalDate?
+ var inAppReviewDate: Instant?
get() = sharedPref.getLong(PREF_KEY_IN_APP_REVIEW_DATE, 0).takeIf { it != 0L }
- ?.toLocalDate()
- set(value) = sharedPref.edit().putLong(PREF_KEY_IN_APP_REVIEW_DATE, value!!.toTimestamp())
- .apply()
+ ?.let(Instant::ofEpochMilli)
+ set(value) = sharedPref.edit {
+ putLong(PREF_KEY_IN_APP_REVIEW_DATE, value?.toEpochMilli() ?: 0)
+ }
var isAppReviewDone: Boolean
get() = sharedPref.getBoolean(PREF_KEY_IN_APP_REVIEW_DONE, false)
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolRepository.kt
index 288a1fb67..880a6a74c 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolRepository.kt
@@ -38,7 +38,9 @@ class SchoolRepository @Inject constructor(
},
query = { schoolDb.load(semester.studentId, semester.classId) },
fetch = {
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).getSchool()
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
+ .getSchool()
.mapToEntity(semester)
},
saveFetchResult = { old, new ->
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/SemesterRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/SemesterRepository.kt
index cc954558f..96f019223 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/SemesterRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/SemesterRepository.kt
@@ -5,11 +5,7 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
-import io.github.wulkanowy.utils.DispatchersProvider
-import io.github.wulkanowy.utils.getCurrentOrLast
-import io.github.wulkanowy.utils.init
-import io.github.wulkanowy.utils.isCurrent
-import io.github.wulkanowy.utils.uniqueSubtract
+import io.github.wulkanowy.utils.*
import kotlinx.coroutines.withContext
import timber.log.Timber
import javax.inject.Inject
@@ -43,10 +39,14 @@ class SemesterRepository @Inject constructor(
): Boolean {
val isNoSemesters = semesters.isEmpty()
- val isRefreshOnModeChangeRequired =
- if (Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
- semesters.firstOrNull { it.isCurrent }?.diaryId == 0
- } else false
+ val isRefreshOnModeChangeRequired = when {
+ Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API -> {
+ semesters.firstOrNull { it.isCurrent }?.let {
+ 0 == it.diaryId && 0 == it.kindergartenDiaryId
+ } == true
+ }
+ else -> false
+ }
val isRefreshOnNoCurrentAppropriate =
refreshOnNoCurrent && !semesters.any { semester -> semester.isCurrent }
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentInfoRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/StudentInfoRepository.kt
index e98daedf2..1fa91dd46 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentInfoRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/StudentInfoRepository.kt
@@ -28,7 +28,8 @@ class StudentInfoRepository @Inject constructor(
shouldFetch = { it == null || forceRefresh },
query = { studentInfoDao.loadStudentInfo(student.studentId) },
fetch = {
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getStudentInfo().mapToEntity(semester)
},
saveFetchResult = { old, new ->
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt
index 9e4a1aabc..570f8bdb9 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt
@@ -128,4 +128,7 @@ class StudentRepository @Inject constructor(
suspend fun updateStudentNickAndAvatar(studentNickAndAvatar: StudentNickAndAvatar) =
studentDb.update(studentNickAndAvatar)
+
+ suspend fun isOneUniqueStudent() = getSavedStudents(false)
+ .distinctBy { it.student.studentName }.size == 1
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/SubjectRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/SubjectRepository.kt
index d81cb7c92..b9bca028f 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/SubjectRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/SubjectRepository.kt
@@ -5,11 +5,7 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
-import io.github.wulkanowy.utils.AutoRefreshHelper
-import io.github.wulkanowy.utils.getRefreshKey
-import io.github.wulkanowy.utils.init
-import io.github.wulkanowy.utils.networkBoundResource
-import io.github.wulkanowy.utils.uniqueSubtract
+import io.github.wulkanowy.utils.*
import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject
import javax.inject.Singleton
@@ -37,7 +33,8 @@ class SubjectRepository @Inject constructor(
},
query = { subjectDao.loadAll(semester.diaryId, semester.studentId) },
fetch = {
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getSubjects().mapToEntities(semester)
},
saveFetchResult = { old, new ->
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/TeacherRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/TeacherRepository.kt
index 029b2707a..6b615c7a7 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/TeacherRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/TeacherRepository.kt
@@ -5,11 +5,7 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
-import io.github.wulkanowy.utils.AutoRefreshHelper
-import io.github.wulkanowy.utils.getRefreshKey
-import io.github.wulkanowy.utils.init
-import io.github.wulkanowy.utils.networkBoundResource
-import io.github.wulkanowy.utils.uniqueSubtract
+import io.github.wulkanowy.utils.*
import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject
import javax.inject.Singleton
@@ -37,7 +33,8 @@ class TeacherRepository @Inject constructor(
},
query = { teacherDb.loadAll(semester.studentId, semester.classId) },
fetch = {
- sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
+ sdk.init(student)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getTeachers(semester.semesterId)
.mapToEntities(semester)
},
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/TimetableRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/TimetableRepository.kt
index 8be621122..7534640c3 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/TimetableRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/TimetableRepository.kt
@@ -3,22 +3,12 @@ package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
import io.github.wulkanowy.data.db.dao.TimetableDao
import io.github.wulkanowy.data.db.dao.TimetableHeaderDao
-import io.github.wulkanowy.data.db.entities.Semester
-import io.github.wulkanowy.data.db.entities.Student
-import io.github.wulkanowy.data.db.entities.Timetable
-import io.github.wulkanowy.data.db.entities.TimetableAdditional
-import io.github.wulkanowy.data.db.entities.TimetableHeader
+import io.github.wulkanowy.data.db.entities.*
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.pojos.TimetableFull
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
-import io.github.wulkanowy.utils.AutoRefreshHelper
-import io.github.wulkanowy.utils.getRefreshKey
-import io.github.wulkanowy.utils.init
-import io.github.wulkanowy.utils.monday
-import io.github.wulkanowy.utils.networkBoundResource
-import io.github.wulkanowy.utils.sunday
-import io.github.wulkanowy.utils.uniqueSubtract
+import io.github.wulkanowy.utils.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.sync.Mutex
@@ -62,7 +52,7 @@ class TimetableRepository @Inject constructor(
query = { getFullTimetableFromDatabase(student, semester, start, end) },
fetch = {
val timetableFull = sdk.init(student)
- .switchDiary(semester.diaryId, semester.schoolYear)
+ .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getTimetableFull(start.monday, end.sunday)
timetableFull.mapToEntities(semester)
@@ -152,7 +142,8 @@ class TimetableRepository @Inject constructor(
old: List,
new: List
) {
- timetableAdditionalDb.deleteAll(old uniqueSubtract new)
+ val oldFiltered = old.filter { !it.isAddedByUser }
+ timetableAdditionalDb.deleteAll(oldFiltered uniqueSubtract new)
timetableAdditionalDb.insertAll(new uniqueSubtract old)
}
@@ -160,4 +151,14 @@ class TimetableRepository @Inject constructor(
timetableHeaderDb.deleteAll(old uniqueSubtract new)
timetableHeaderDb.insertAll(new uniqueSubtract old)
}
+
+ suspend fun saveAdditionalList(additionalList: List) =
+ timetableAdditionalDb.insertAll(additionalList)
+
+ suspend fun deleteAdditional(additional: TimetableAdditional, deleteSeries: Boolean) =
+ if (deleteSeries) {
+ timetableAdditionalDb.deleteAllByRepeatId(additional.repeatId!!)
+ } else {
+ timetableAdditionalDb.deleteAll(listOf(additional))
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/services/HiltBroadcastReceiver.kt b/app/src/main/java/io/github/wulkanowy/services/HiltBroadcastReceiver.kt
deleted file mode 100644
index 1e795d439..000000000
--- a/app/src/main/java/io/github/wulkanowy/services/HiltBroadcastReceiver.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package io.github.wulkanowy.services
-
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-
-abstract class HiltBroadcastReceiver : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {}
-}
diff --git a/app/src/main/java/io/github/wulkanowy/services/alarm/TimetableNotificationReceiver.kt b/app/src/main/java/io/github/wulkanowy/services/alarm/TimetableNotificationReceiver.kt
index b388d2ac5..c3ff1838e 100644
--- a/app/src/main/java/io/github/wulkanowy/services/alarm/TimetableNotificationReceiver.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/alarm/TimetableNotificationReceiver.kt
@@ -1,6 +1,7 @@
package io.github.wulkanowy.services.alarm
import android.app.PendingIntent
+import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Build
@@ -12,14 +13,12 @@ import io.github.wulkanowy.R
import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.StudentRepository
-import io.github.wulkanowy.services.HiltBroadcastReceiver
import io.github.wulkanowy.services.sync.channels.UpcomingLessonsChannel.Companion.CHANNEL_ID
import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.ui.modules.splash.SplashActivity
import io.github.wulkanowy.utils.PendingIntentCompat
import io.github.wulkanowy.utils.flowWithResource
import io.github.wulkanowy.utils.getCompatColor
-import io.github.wulkanowy.utils.toLocalDateTime
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.launchIn
@@ -28,7 +27,7 @@ import timber.log.Timber
import javax.inject.Inject
@AndroidEntryPoint
-class TimetableNotificationReceiver : HiltBroadcastReceiver() {
+class TimetableNotificationReceiver : BroadcastReceiver() {
@Inject
lateinit var studentRepository: StudentRepository
@@ -41,6 +40,8 @@ class TimetableNotificationReceiver : HiltBroadcastReceiver() {
const val NOTIFICATION_TYPE_UPCOMING = 2
const val NOTIFICATION_TYPE_LAST_LESSON_CANCELLATION = 3
+ // FIXME only shows one notification even if there are multiple students.
+ // Probably want to fix after #721 is merged.
const val NOTIFICATION_ID = 2137
const val STUDENT_NAME = "student_name"
@@ -56,20 +57,24 @@ class TimetableNotificationReceiver : HiltBroadcastReceiver() {
@OptIn(DelicateCoroutinesApi::class)
override fun onReceive(context: Context, intent: Intent) {
- super.onReceive(context, intent)
Timber.d("Receiving intent... ${intent.toUri(0)}")
flowWithResource {
+ val showStudentName = !studentRepository.isOneUniqueStudent()
val student = studentRepository.getCurrentStudent(false)
val studentId = intent.getIntExtra(STUDENT_ID, 0)
- if (student.studentId == studentId) prepareNotification(context, intent)
- else Timber.d("Notification studentId($studentId) differs from current(${student.studentId})")
+
+ if (student.studentId == studentId) {
+ prepareNotification(context, intent, showStudentName)
+ } else {
+ Timber.d("Notification studentId($studentId) differs from current(${student.studentId})")
+ }
}.onEach {
if (it.status == Status.ERROR) Timber.e(it.error!!)
}.launchIn(GlobalScope)
}
- private fun prepareNotification(context: Context, intent: Intent) {
+ private fun prepareNotification(context: Context, intent: Intent, showStudentName: Boolean) {
val type = intent.getIntExtra(LESSON_TYPE, 0)
val isPersistent = preferencesRepository.isUpcomingLessonsNotificationsPersistent
@@ -78,7 +83,7 @@ class TimetableNotificationReceiver : HiltBroadcastReceiver() {
}
val studentId = intent.getIntExtra(STUDENT_ID, 0)
- val studentName = intent.getStringExtra(STUDENT_NAME)
+ val studentName = intent.getStringExtra(STUDENT_NAME).takeIf { showStudentName }
val subject = intent.getStringExtra(LESSON_TITLE)
val room = intent.getStringExtra(LESSON_ROOM)
@@ -89,21 +94,28 @@ class TimetableNotificationReceiver : HiltBroadcastReceiver() {
val nextSubject = intent.getStringExtra(LESSON_NEXT_TITLE)
val nextRoom = intent.getStringExtra(LESSON_NEXT_ROOM)
- Timber.d("TimetableNotification receive: type: $type, subject: $subject, start: ${start.toLocalDateTime()}, student: $studentId")
+ Timber.d("TimetableNotification receive: type: $type, subject: $subject, start: $start, student: $studentId")
+
+ val notificationTitleResId =
+ if (type == NOTIFICATION_TYPE_CURRENT) R.string.timetable_now else R.string.timetable_next
+ val notificationTitle =
+ context.getString(notificationTitleResId, "($room) $subject".removePrefix("()"))
+
+ val nextLessonText = nextSubject?.let {
+ context.getString(
+ R.string.timetable_later,
+ "($nextRoom) $nextSubject".removePrefix("()")
+ )
+ }
showNotification(
- context, isPersistent, studentName,
- if (type == NOTIFICATION_TYPE_CURRENT) end else start, end - start,
- context.getString(
- if (type == NOTIFICATION_TYPE_CURRENT) R.string.timetable_now else R.string.timetable_next,
- "($room) $subject".removePrefix("()")
- ),
- nextSubject?.let {
- context.getString(
- R.string.timetable_later,
- "($nextRoom) $nextSubject".removePrefix("()")
- )
- }
+ context = context,
+ isPersistent = isPersistent,
+ studentName = studentName,
+ countDown = if (type == NOTIFICATION_TYPE_CURRENT) end else start,
+ timeout = end - start,
+ title = notificationTitle,
+ next = nextLessonText
)
}
@@ -130,10 +142,11 @@ class TimetableNotificationReceiver : HiltBroadcastReceiver() {
.setTimeoutAfter(timeout)
.setSmallIcon(R.drawable.ic_stat_timetable)
.setColor(context.getCompatColor(R.color.colorPrimary))
- .setStyle(NotificationCompat.InboxStyle().also {
- it.setSummaryText(studentName)
- it.addLine(next)
- })
+ .setStyle(NotificationCompat.InboxStyle()
+ .addLine(next)
+ .also { inboxStyle ->
+ studentName?.let { inboxStyle.setSummaryText(it) }
+ })
.setContentIntent(
PendingIntent.getActivity(
context,
diff --git a/app/src/main/java/io/github/wulkanowy/services/alarm/TimetableNotificationSchedulerHelper.kt b/app/src/main/java/io/github/wulkanowy/services/alarm/TimetableNotificationSchedulerHelper.kt
index dc9b8f1da..42078d03f 100644
--- a/app/src/main/java/io/github/wulkanowy/services/alarm/TimetableNotificationSchedulerHelper.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/alarm/TimetableNotificationSchedulerHelper.kt
@@ -28,12 +28,12 @@ import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companio
import io.github.wulkanowy.utils.DispatchersProvider
import io.github.wulkanowy.utils.PendingIntentCompat
import io.github.wulkanowy.utils.nickOrName
-import io.github.wulkanowy.utils.toTimestamp
import kotlinx.coroutines.withContext
import timber.log.Timber
+import java.time.Duration.ofMinutes
+import java.time.Instant
+import java.time.Instant.now
import java.time.LocalDate
-import java.time.LocalDateTime
-import java.time.LocalDateTime.now
import javax.inject.Inject
class TimetableNotificationSchedulerHelper @Inject constructor(
@@ -43,14 +43,14 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
private val dispatchersProvider: DispatchersProvider,
) {
- private fun getRequestCode(time: LocalDateTime, studentId: Int) =
- (time.toTimestamp() * studentId).toInt()
+ private fun getRequestCode(time: Instant, studentId: Int): Int =
+ (time.toEpochMilli() * studentId).toInt()
private fun getUpcomingLessonTime(
index: Int,
day: List,
lesson: Timetable
- ) = day.getOrNull(index - 1)?.end ?: lesson.start.minusMinutes(30)
+ ): Instant = day.getOrNull(index - 1)?.end ?: lesson.start.minus(ofMinutes(30))
suspend fun cancelScheduled(lessons: List, student: Student) {
val studentId = student.studentId
@@ -71,7 +71,7 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
}
}
- private fun cancelScheduledTo(range: ClosedRange, requestCode: Int) {
+ private fun cancelScheduledTo(range: ClosedRange, requestCode: Int) {
if (now() in range) cancelNotification()
alarmManager.cancel(
@@ -150,8 +150,8 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
putExtra(STUDENT_ID, student.studentId)
putExtra(STUDENT_NAME, student.nickOrName)
putExtra(LESSON_ROOM, lesson.room)
- putExtra(LESSON_START, lesson.start.toTimestamp())
- putExtra(LESSON_END, lesson.end.toTimestamp())
+ putExtra(LESSON_START, lesson.start.toEpochMilli())
+ putExtra(LESSON_END, lesson.end.toEpochMilli())
putExtra(LESSON_TITLE, lesson.subject)
putExtra(LESSON_NEXT_TITLE, nextLesson?.subject)
putExtra(LESSON_NEXT_ROOM, nextLesson?.room)
@@ -162,11 +162,11 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
intent: Intent,
studentId: Int,
notificationType: Int,
- time: LocalDateTime
+ time: Instant
) {
try {
AlarmManagerCompat.setExactAndAllowWhileIdle(
- alarmManager, RTC_WAKEUP, time.toTimestamp(),
+ alarmManager, RTC_WAKEUP, time.toEpochMilli(),
PendingIntent.getBroadcast(context, getRequestCode(time, studentId), intent.also {
it.putExtra(LESSON_TYPE, notificationType)
}, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE)
diff --git a/app/src/main/java/io/github/wulkanowy/services/piggyback/VulcanNotificationListenerService.kt b/app/src/main/java/io/github/wulkanowy/services/piggyback/VulcanNotificationListenerService.kt
index c7df2dbc1..3c173495a 100644
--- a/app/src/main/java/io/github/wulkanowy/services/piggyback/VulcanNotificationListenerService.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/piggyback/VulcanNotificationListenerService.kt
@@ -19,6 +19,9 @@ class VulcanNotificationListenerService : NotificationListenerService() {
override fun onNotificationPosted(statusBarNotification: StatusBarNotification?) {
if (statusBarNotification?.packageName == "pl.edu.vulcan.hebe" && preferenceRepository.isNotificationPiggybackEnabled) {
syncManager.startOneTimeSyncWorker()
+ if (preferenceRepository.isNotificationPiggybackRemoveOriginalEnabled) {
+ cancelNotification(statusBarNotification.key)
+ }
}
}
}
\ No newline at end of file
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 32ca20afc..c1bed4dd3 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
@@ -74,10 +74,12 @@ class SyncManager @Inject constructor(
}
}
- fun startOneTimeSyncWorker(): Flow {
+ // if quiet, no notifications will be sent
+ fun startOneTimeSyncWorker(quiet: Boolean = false): Flow {
val work = OneTimeWorkRequestBuilder()
.setInputData(
Data.Builder()
+ .putBoolean("quiet", quiet)
.putBoolean("one_time", true)
.build()
)
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 52979e635..5dddd9a78 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
@@ -23,7 +23,7 @@ import io.github.wulkanowy.utils.DispatchersProvider
import io.github.wulkanowy.utils.getCompatColor
import kotlinx.coroutines.withContext
import timber.log.Timber
-import java.time.LocalDateTime
+import java.time.Instant
import kotlin.random.Random
@HiltWorker
@@ -38,18 +38,23 @@ class SyncWorker @AssistedInject constructor(
private val dispatchersProvider: DispatchersProvider
) : CoroutineWorker(appContext, workerParameters) {
- override suspend fun doWork() = withContext(dispatchersProvider.io) {
+ override suspend fun doWork(): Result = withContext(dispatchersProvider.io) {
Timber.i("SyncWorker is starting")
if (!studentRepository.isCurrentStudentSet()) return@withContext Result.failure()
- val student = studentRepository.getCurrentStudent()
- val semester = semesterRepository.getCurrentSemester(student, true)
+ val (student, semester) = try {
+ val student = studentRepository.getCurrentStudent()
+ val semester = semesterRepository.getCurrentSemester(student, true)
+ student to semester
+ } catch (e: Throwable) {
+ return@withContext getResultFromErrors(listOf(e))
+ }
val exceptions = works.mapNotNull { work ->
try {
Timber.i("${work::class.java.simpleName} is starting")
- work.doWork(student, semester)
+ work.doWork(student, semester, isNotificationsEnabled())
Timber.i("${work::class.java.simpleName} result: Success")
null
} catch (e: Throwable) {
@@ -62,20 +67,7 @@ class SyncWorker @AssistedInject constructor(
}
}
}
- val result = when {
- exceptions.isNotEmpty() && inputData.getBoolean("one_time", false) -> {
- Result.failure(
- Data.Builder()
- .putString("error", exceptions.map { it.stackTraceToString() }.toString())
- .build()
- )
- }
- exceptions.isNotEmpty() -> Result.retry()
- else -> {
- preferencesRepository.lasSyncDate = LocalDateTime.now()
- Result.success()
- }
- }
+ val result = getResultFromErrors(exceptions)
if (preferencesRepository.isDebugNotificationEnable) notify(result)
Timber.i("SyncWorker result: $result")
@@ -83,6 +75,27 @@ class SyncWorker @AssistedInject constructor(
return@withContext result
}
+ private fun isNotificationsEnabled(): Boolean {
+ val quiet = inputData.getBoolean("quiet", false)
+ return preferencesRepository.isNotificationsEnable && !quiet
+ }
+
+ private fun getResultFromErrors(errors: List): Result = when {
+ errors.isNotEmpty() && inputData.getBoolean("one_time", false) -> {
+ Result.failure(
+ Data.Builder()
+ .putString("error_message", errors.joinToString { it.message.toString() })
+ .putString("error_stack", errors.map { it.stackTraceToString() }.toString())
+ .build()
+ )
+ }
+ errors.isNotEmpty() -> Result.retry()
+ else -> {
+ preferencesRepository.lasSyncDate = Instant.now()
+ Result.success()
+ }
+ }
+
private fun notify(result: Result) {
notificationManager.notify(
Random.nextInt(Int.MAX_VALUE),
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/AppNotificationManager.kt b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/AppNotificationManager.kt
index da8d094c6..7ac532aeb 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/AppNotificationManager.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/AppNotificationManager.kt
@@ -18,7 +18,7 @@ import io.github.wulkanowy.utils.PendingIntentCompat
import io.github.wulkanowy.utils.getCompatBitmap
import io.github.wulkanowy.utils.getCompatColor
import io.github.wulkanowy.utils.nickOrName
-import java.time.LocalDateTime
+import java.time.Instant
import javax.inject.Inject
import kotlin.random.Random
@@ -57,7 +57,7 @@ class AppNotificationManager @Inject constructor(
NotificationCompat.BigTextStyle()
.bigText(notificationData.content)
.also { builder ->
- if (shouldShowStudentName()) {
+ if (!studentRepository.isOneUniqueStudent()) {
builder.setSummaryText(student.nickOrName)
}
}
@@ -102,7 +102,7 @@ class AppNotificationManager @Inject constructor(
NotificationCompat.BigTextStyle()
.bigText(notificationData.content)
.also { builder ->
- if (shouldShowStudentName()) {
+ if (!studentRepository.isOneUniqueStudent()) {
builder.setSummaryText(student.nickOrName)
}
}
@@ -134,7 +134,7 @@ class AppNotificationManager @Inject constructor(
.setStyle(
NotificationCompat.InboxStyle()
.also { builder ->
- if (shouldShowStudentName()) {
+ if (!studentRepository.isOneUniqueStudent()) {
builder.setSummaryText(student.nickOrName)
}
groupNotificationData.notificationDataList.forEach {
@@ -169,12 +169,9 @@ class AppNotificationManager @Inject constructor(
title = notificationData.title,
content = notificationData.content,
type = notificationType,
- date = LocalDateTime.now()
+ date = Instant.now(),
)
notificationRepository.saveNotification(notificationEntity)
}
-
- private suspend fun shouldShowStudentName(): Boolean =
- studentRepository.getSavedStudents(decryptPass = false).size > 1
}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/ChangeTimetableNotification.kt b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/ChangeTimetableNotification.kt
index 7bfef96a4..b1f9a7b06 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/ChangeTimetableNotification.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/ChangeTimetableNotification.kt
@@ -11,8 +11,8 @@ import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.ui.modules.splash.SplashActivity
import io.github.wulkanowy.utils.getPlural
import io.github.wulkanowy.utils.toFormattedString
+import java.time.Instant
import java.time.LocalDate
-import java.time.LocalDateTime
import javax.inject.Inject
class ChangeTimetableNotification @Inject constructor(
@@ -21,7 +21,7 @@ class ChangeTimetableNotification @Inject constructor(
) {
suspend fun notify(items: List, student: Student) {
- val currentTime = LocalDateTime.now()
+ val currentTime = Instant.now()
val changedLessons = items.filter { (it.canceled || it.changes) && it.start > currentTime }
val notificationDataList = changedLessons.groupBy { it.date }
.map { (date, lessons) ->
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewConferenceNotification.kt b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewConferenceNotification.kt
index 8ef147886..d27c57285 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewConferenceNotification.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewConferenceNotification.kt
@@ -11,7 +11,7 @@ import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.ui.modules.splash.SplashActivity
import io.github.wulkanowy.utils.getPlural
import io.github.wulkanowy.utils.toFormattedString
-import java.time.LocalDateTime
+import java.time.Instant
import javax.inject.Inject
class NewConferenceNotification @Inject constructor(
@@ -20,7 +20,7 @@ class NewConferenceNotification @Inject constructor(
) {
suspend fun notify(items: List, student: Student) {
- val today = LocalDateTime.now()
+ val today = Instant.now()
val lines = items.filter { !it.date.isBefore(today) }
.map {
"${it.date.toFormattedString("dd.MM")} - ${it.title}: ${it.subject}"
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewGradeNotification.kt b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewGradeNotification.kt
index 39ecbe33d..32d2ba6a0 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewGradeNotification.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewGradeNotification.kt
@@ -22,7 +22,10 @@ class NewGradeNotification @Inject constructor(
val notificationDataList = items.map {
NotificationData(
title = context.getPlural(R.plurals.grade_new_items, 1),
- content = "${it.subject}: ${it.entry}",
+ content = buildString {
+ append("${it.subject}: ${it.entry}")
+ if (it.comment.isNotBlank()) append(" (${it.comment})")
+ },
intentToStart = SplashActivity.getStartIntent(context, Destination.Grade),
)
}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewSchoolAnnouncementNotification.kt b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewSchoolAnnouncementNotification.kt
index 6b839d298..695438a70 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewSchoolAnnouncementNotification.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewSchoolAnnouncementNotification.kt
@@ -1,6 +1,7 @@
package io.github.wulkanowy.services.sync.notifications
import android.content.Context
+import androidx.core.text.parseAsHtml
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
@@ -28,7 +29,7 @@ class NewSchoolAnnouncementNotification @Inject constructor(
R.plurals.school_announcement_notify_new_item_title,
1
),
- content = "${it.subject}: ${it.content}"
+ content = "${it.subject}: ${it.content.parseAsHtml()}"
)
}
val groupNotificationData = GroupNotificationData(
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceSummaryWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceSummaryWork.kt
index cbe1fe6bd..84b7017b1 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceSummaryWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceSummaryWork.kt
@@ -10,7 +10,12 @@ class AttendanceSummaryWork @Inject constructor(
private val attendanceSummaryRepository: AttendanceSummaryRepository
) : Work {
- override suspend fun doWork(student: Student, semester: Semester) {
- attendanceSummaryRepository.getAttendanceSummary(student, semester, -1, true).waitForResult()
+ override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
+ attendanceSummaryRepository.getAttendanceSummary(
+ student = student,
+ semester = semester,
+ subjectId = -1,
+ forceRefresh = true,
+ ).waitForResult()
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceWork.kt
index f7b680e31..9abf43e08 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceWork.kt
@@ -3,7 +3,6 @@ package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.AttendanceRepository
-import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.services.sync.notifications.NewAttendanceNotification
import io.github.wulkanowy.utils.previousOrSameSchoolDay
import io.github.wulkanowy.utils.waitForResult
@@ -14,17 +13,16 @@ import javax.inject.Inject
class AttendanceWork @Inject constructor(
private val attendanceRepository: AttendanceRepository,
private val newAttendanceNotification: NewAttendanceNotification,
- private val preferencesRepository: PreferencesRepository
) : Work {
- override suspend fun doWork(student: Student, semester: Semester) {
+ override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
attendanceRepository.getAttendance(
student = student,
semester = semester,
start = now().previousOrSameSchoolDay,
end = now().previousOrSameSchoolDay,
forceRefresh = true,
- notify = preferencesRepository.isNotificationsEnable
+ notify = notify,
)
.waitForResult()
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/CompletedLessonWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/CompletedLessonWork.kt
index 17bd61292..c6ada9446 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/CompletedLessonWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/CompletedLessonWork.kt
@@ -13,7 +13,13 @@ class CompletedLessonWork @Inject constructor(
private val completedLessonsRepository: CompletedLessonsRepository
) : Work {
- override suspend fun doWork(student: Student, semester: Semester) {
- completedLessonsRepository.getCompletedLessons(student, semester, now().monday, now().sunday, true).waitForResult()
+ override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
+ completedLessonsRepository.getCompletedLessons(
+ student = student,
+ semester = semester,
+ start = now().monday,
+ end = now().sunday,
+ forceRefresh = true,
+ ).waitForResult()
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/ConferenceWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/ConferenceWork.kt
index 002b4f764..becd74668 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/ConferenceWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/ConferenceWork.kt
@@ -3,7 +3,6 @@ package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.ConferenceRepository
-import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.services.sync.notifications.NewConferenceNotification
import io.github.wulkanowy.utils.waitForResult
import kotlinx.coroutines.flow.first
@@ -11,16 +10,15 @@ import javax.inject.Inject
class ConferenceWork @Inject constructor(
private val conferenceRepository: ConferenceRepository,
- private val preferencesRepository: PreferencesRepository,
private val newConferenceNotification: NewConferenceNotification,
) : Work {
- override suspend fun doWork(student: Student, semester: Semester) {
+ override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
conferenceRepository.getConferences(
student = student,
semester = semester,
forceRefresh = true,
- notify = preferencesRepository.isNotificationsEnable
+ notify = notify
).waitForResult()
conferenceRepository.getConferenceFromDatabase(semester).first()
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/ExamWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/ExamWork.kt
index a1ce553a7..39579dc8c 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/ExamWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/ExamWork.kt
@@ -3,7 +3,6 @@ package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.ExamRepository
-import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.services.sync.notifications.NewExamNotification
import io.github.wulkanowy.utils.waitForResult
import kotlinx.coroutines.flow.first
@@ -12,18 +11,17 @@ import javax.inject.Inject
class ExamWork @Inject constructor(
private val examRepository: ExamRepository,
- private val preferencesRepository: PreferencesRepository,
private val newExamNotification: NewExamNotification,
) : Work {
- override suspend fun doWork(student: Student, semester: Semester) {
+ override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
examRepository.getExams(
student = student,
semester = semester,
start = now(),
end = now(),
forceRefresh = true,
- notify = preferencesRepository.isNotificationsEnable
+ notify = notify,
).waitForResult()
examRepository.getExamsFromDatabase(semester, now()).first()
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeStatisticsWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeStatisticsWork.kt
index 4575b419b..2e915199e 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeStatisticsWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeStatisticsWork.kt
@@ -10,7 +10,7 @@ class GradeStatisticsWork @Inject constructor(
private val gradeStatisticsRepository: GradeStatisticsRepository
) : Work {
- override suspend fun doWork(student: Student, semester: Semester) {
+ override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
with(gradeStatisticsRepository) {
getGradesPartialStatistics(student, semester, "Wszystkie", forceRefresh = true).waitForResult()
getGradesSemesterStatistics(student, semester, "Wszystkie", forceRefresh = true).waitForResult()
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeWork.kt
index 0932405eb..dd49f143c 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeWork.kt
@@ -3,7 +3,6 @@ package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.GradeRepository
-import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.services.sync.notifications.NewGradeNotification
import io.github.wulkanowy.utils.waitForResult
import kotlinx.coroutines.flow.first
@@ -11,16 +10,15 @@ import javax.inject.Inject
class GradeWork @Inject constructor(
private val gradeRepository: GradeRepository,
- private val preferencesRepository: PreferencesRepository,
private val newGradeNotification: NewGradeNotification,
) : Work {
- override suspend fun doWork(student: Student, semester: Semester) {
+ override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
gradeRepository.getGrades(
student = student,
semester = semester,
forceRefresh = true,
- notify = preferencesRepository.isNotificationsEnable
+ notify = notify,
).waitForResult()
gradeRepository.getGradesFromDatabase(semester).first()
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/HomeworkWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/HomeworkWork.kt
index 2a5d2d7c0..1385191b7 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/HomeworkWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/HomeworkWork.kt
@@ -3,7 +3,6 @@ package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.HomeworkRepository
-import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.services.sync.notifications.NewHomeworkNotification
import io.github.wulkanowy.utils.nextOrSameSchoolDay
import io.github.wulkanowy.utils.waitForResult
@@ -13,18 +12,17 @@ import javax.inject.Inject
class HomeworkWork @Inject constructor(
private val homeworkRepository: HomeworkRepository,
- private val preferencesRepository: PreferencesRepository,
private val newHomeworkNotification: NewHomeworkNotification,
) : Work {
- override suspend fun doWork(student: Student, semester: Semester) {
+ override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
homeworkRepository.getHomework(
student = student,
semester = semester,
start = now().nextOrSameSchoolDay,
end = now().nextOrSameSchoolDay,
forceRefresh = true,
- notify = preferencesRepository.isNotificationsEnable
+ notify = notify,
).waitForResult()
homeworkRepository.getHomeworkFromDatabase(semester, now(), now().plusDays(7)).first()
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/LuckyNumberWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/LuckyNumberWork.kt
index 348f92142..f223a8546 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/LuckyNumberWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/LuckyNumberWork.kt
@@ -3,22 +3,20 @@ package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
-import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.services.sync.notifications.NewLuckyNumberNotification
import io.github.wulkanowy.utils.waitForResult
import javax.inject.Inject
class LuckyNumberWork @Inject constructor(
private val luckyNumberRepository: LuckyNumberRepository,
- private val preferencesRepository: PreferencesRepository,
private val newLuckyNumberNotification: NewLuckyNumberNotification,
) : Work {
- override suspend fun doWork(student: Student, semester: Semester) {
+ override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
luckyNumberRepository.getLuckyNumber(
student = student,
forceRefresh = true,
- notify = preferencesRepository.isNotificationsEnable
+ notify = notify,
).waitForResult()
luckyNumberRepository.getNotNotifiedLuckyNumber(student)?.let {
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 b5624a76d..5bf326c7b 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
@@ -4,7 +4,6 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
import io.github.wulkanowy.data.repositories.MessageRepository
-import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.services.sync.notifications.NewMessageNotification
import io.github.wulkanowy.utils.waitForResult
import kotlinx.coroutines.flow.first
@@ -12,17 +11,16 @@ import javax.inject.Inject
class MessageWork @Inject constructor(
private val messageRepository: MessageRepository,
- private val preferencesRepository: PreferencesRepository,
private val newMessageNotification: NewMessageNotification,
) : Work {
- override suspend fun doWork(student: Student, semester: Semester) {
+ override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
messageRepository.getMessages(
student = student,
semester = semester,
folder = RECEIVED,
forceRefresh = true,
- notify = preferencesRepository.isNotificationsEnable
+ notify = notify
).waitForResult()
messageRepository.getMessagesFromDatabase(student).first()
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/NoteWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/NoteWork.kt
index 6f18eddf1..d66c3d661 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/NoteWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/NoteWork.kt
@@ -3,7 +3,6 @@ package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.NoteRepository
-import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.services.sync.notifications.NewNoteNotification
import io.github.wulkanowy.utils.waitForResult
import kotlinx.coroutines.flow.first
@@ -11,16 +10,15 @@ import javax.inject.Inject
class NoteWork @Inject constructor(
private val noteRepository: NoteRepository,
- private val preferencesRepository: PreferencesRepository,
private val newNoteNotification: NewNoteNotification,
) : Work {
- override suspend fun doWork(student: Student, semester: Semester) {
+ override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
noteRepository.getNotes(
student = student,
semester = semester,
forceRefresh = true,
- notify = preferencesRepository.isNotificationsEnable
+ notify = notify,
).waitForResult()
noteRepository.getNotesFromDatabase(student).first()
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/RecipientWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/RecipientWork.kt
index 34ab3db04..425e68b91 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/RecipientWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/RecipientWork.kt
@@ -11,7 +11,7 @@ class RecipientWork @Inject constructor(
private val recipientRepository: RecipientRepository
) : Work {
- override suspend fun doWork(student: Student, semester: Semester) {
+ override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
reportingUnitRepository.refreshReportingUnits(student)
reportingUnitRepository.getReportingUnits(student).let { units ->
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/SchoolAnnouncementWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/SchoolAnnouncementWork.kt
index 268992f46..9cee59024 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/SchoolAnnouncementWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/SchoolAnnouncementWork.kt
@@ -2,7 +2,6 @@ package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
-import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.SchoolAnnouncementRepository
import io.github.wulkanowy.services.sync.notifications.NewSchoolAnnouncementNotification
import io.github.wulkanowy.utils.waitForResult
@@ -11,15 +10,14 @@ import javax.inject.Inject
class SchoolAnnouncementWork @Inject constructor(
private val schoolAnnouncementRepository: SchoolAnnouncementRepository,
- private val preferencesRepository: PreferencesRepository,
private val newSchoolAnnouncementNotification: NewSchoolAnnouncementNotification,
) : Work {
- override suspend fun doWork(student: Student, semester: Semester) {
+ override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
schoolAnnouncementRepository.getSchoolAnnouncements(
student = student,
forceRefresh = true,
- notify = preferencesRepository.isNotificationsEnable
+ notify = notify,
).waitForResult()
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/TeacherWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/TeacherWork.kt
index 7c614c6c5..751fb6cc7 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/TeacherWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/TeacherWork.kt
@@ -8,7 +8,7 @@ import javax.inject.Inject
class TeacherWork @Inject constructor(private val teacherRepository: TeacherRepository) : Work {
- override suspend fun doWork(student: Student, semester: Semester) {
+ override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
teacherRepository.getTeachers(student, semester, true).waitForResult()
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/TimetableWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/TimetableWork.kt
index fcc330638..575f9b961 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/TimetableWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/TimetableWork.kt
@@ -2,7 +2,6 @@ package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
-import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.TimetableRepository
import io.github.wulkanowy.services.sync.notifications.ChangeTimetableNotification
import io.github.wulkanowy.utils.nextOrSameSchoolDay
@@ -14,17 +13,16 @@ import javax.inject.Inject
class TimetableWork @Inject constructor(
private val timetableRepository: TimetableRepository,
private val changeTimetableNotification: ChangeTimetableNotification,
- private val preferencesRepository: PreferencesRepository
) : Work {
- override suspend fun doWork(student: Student, semester: Semester) {
+ override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
timetableRepository.getTimetable(
student = student,
semester = semester,
start = now().nextOrSameSchoolDay,
end = now().nextOrSameSchoolDay,
forceRefresh = true,
- notify = preferencesRepository.isNotificationsEnable
+ notify = notify,
)
.waitForResult()
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/Work.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/Work.kt
index c41f41ce2..1c0214cdd 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/Work.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/Work.kt
@@ -5,5 +5,5 @@ import io.github.wulkanowy.data.db.entities.Student
interface Work {
- suspend fun doWork(student: Student, semester: Semester)
+ suspend fun doWork(student: Student, semester: Semester, notify: Boolean)
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/ErrorDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/base/ErrorDialog.kt
index 4c279d816..48c003b7e 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/base/ErrorDialog.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/base/ErrorDialog.kt
@@ -1,102 +1,84 @@
package io.github.wulkanowy.ui.base
+import android.app.Dialog
import android.content.ClipData
import android.content.ClipboardManager
import android.os.Bundle
import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.HorizontalScrollView
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
import androidx.appcompat.app.AlertDialog
import androidx.core.content.getSystemService
+import androidx.core.os.bundleOf
import androidx.core.view.isGone
+import androidx.fragment.app.DialogFragment
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.databinding.DialogErrorBinding
-import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
-import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
-import io.github.wulkanowy.sdk.scrapper.exception.ServiceUnavailableException
-import io.github.wulkanowy.utils.AppInfo
-import io.github.wulkanowy.utils.getString
-import io.github.wulkanowy.utils.openAppInMarket
-import io.github.wulkanowy.utils.openEmailClient
-import io.github.wulkanowy.utils.openInternetBrowser
-import okhttp3.internal.http2.StreamResetException
-import java.io.InterruptedIOException
-import java.net.ConnectException
-import java.net.SocketTimeoutException
-import java.net.UnknownHostException
+import io.github.wulkanowy.utils.*
import javax.inject.Inject
@AndroidEntryPoint
-class ErrorDialog : BaseDialogFragment() {
-
- private lateinit var error: Throwable
+class ErrorDialog : DialogFragment() {
@Inject
lateinit var appInfo: AppInfo
companion object {
- private const val ARGUMENT_KEY = "Data"
+ private const val ARGUMENT_KEY = "error"
fun newInstance(error: Throwable) = ErrorDialog().apply {
- arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, error) }
+ arguments = bundleOf(ARGUMENT_KEY to error)
}
}
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setStyle(STYLE_NO_TITLE, 0)
- arguments?.run {
- error = getSerializable(ARGUMENT_KEY) as Throwable
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ val error = requireArguments().getSerializable(ARGUMENT_KEY) as Throwable
+
+ val binding = DialogErrorBinding.inflate(LayoutInflater.from(context))
+ binding.bindErrorDetails(error)
+
+ return getAlertDialog(binding, error).apply {
+ enableReportButtonIfErrorIsReportable(error)
}
}
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ) = DialogErrorBinding.inflate(inflater).apply { binding = this }.root
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- val errorStacktrace = error.stackTraceToString()
-
- with(binding) {
- errorDialogContent.text = errorStacktrace.replace(": ${error.localizedMessage}", "")
- with(errorDialogHorizontalScroll) {
- post { fullScroll(HorizontalScrollView.FOCUS_LEFT) }
- }
- errorDialogCopy.setOnClickListener {
- val clip = ClipData.newPlainText("Error details", errorStacktrace)
- activity?.getSystemService()?.setPrimaryClip(clip)
-
- Toast.makeText(context, R.string.all_copied, LENGTH_LONG).show()
- }
- errorDialogCancel.setOnClickListener { dismiss() }
- errorDialogReport.setOnClickListener {
+ private fun getAlertDialog(binding: DialogErrorBinding, error: Throwable): AlertDialog {
+ return MaterialAlertDialogBuilder(requireContext()).apply {
+ val errorStacktrace = error.stackTraceToString()
+ setTitle(R.string.all_details)
+ setView(binding.root)
+ setNeutralButton(R.string.about_feedback) { _, _ ->
openConfirmDialog { openEmailClient(errorStacktrace) }
}
- errorDialogHumanizedMessage.text = resources.getString(error)
+ setNegativeButton(android.R.string.cancel) { _, _ -> }
+ setPositiveButton(android.R.string.copy) { _, _ -> copyErrorToClipboard(errorStacktrace) }
+ }.create()
+ }
+
+ private fun DialogErrorBinding.bindErrorDetails(error: Throwable) {
+ return with(this) {
+ errorDialogHumanizedMessage.text = resources.getErrorString(error)
errorDialogErrorMessage.text = error.localizedMessage
errorDialogErrorMessage.isGone = error.localizedMessage.isNullOrBlank()
- errorDialogReport.isEnabled = when (error) {
- is UnknownHostException,
- is InterruptedIOException,
- is ConnectException,
- is StreamResetException,
- is SocketTimeoutException,
- is ServiceUnavailableException,
- is FeatureDisabledException,
- is FeatureNotAvailableException -> false
- else -> true
- }
+ errorDialogContent.text = error.stackTraceToString()
+ .replace(": ${error.localizedMessage}", "")
}
}
+ private fun AlertDialog.enableReportButtonIfErrorIsReportable(error: Throwable) {
+ setOnShowListener {
+ getButton(AlertDialog.BUTTON_NEUTRAL).isEnabled = error.isShouldBeReported()
+ }
+ }
+
+ private fun copyErrorToClipboard(errorStacktrace: String) {
+ val clip = ClipData.newPlainText("Error details", errorStacktrace)
+ requireActivity().getSystemService()?.setPrimaryClip(clip)
+ Toast.makeText(requireContext(), R.string.all_copied, LENGTH_LONG).show()
+ }
+
private fun openConfirmDialog(callback: () -> Unit) {
AlertDialog.Builder(requireContext())
.setTitle(R.string.dialog_error_check_update)
@@ -127,4 +109,8 @@ class ErrorDialog : BaseDialogFragment() {
}
)
}
+
+ private fun showMessage(text: String) {
+ Toast.makeText(requireContext(), text, LENGTH_LONG).show()
+ }
}
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 fbc994e2c..afe200e9a 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
@@ -5,7 +5,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
import io.github.wulkanowy.sdk.scrapper.login.BadCredentialsException
import io.github.wulkanowy.sdk.scrapper.login.PasswordChangeRequiredException
-import io.github.wulkanowy.utils.getString
+import io.github.wulkanowy.utils.getErrorString
import io.github.wulkanowy.utils.security.ScramblerException
import timber.log.Timber
import javax.inject.Inject
@@ -26,7 +26,7 @@ open class ErrorHandler @Inject constructor(@ApplicationContext protected val co
}
protected open fun proceed(error: Throwable) {
- showErrorMessage(context.resources.getString(error), error)
+ showErrorMessage(context.resources.getErrorString(error), error)
when (error) {
is PasswordChangeRequiredException -> onPasswordChangeRequired(error.redirectUrl)
is ScramblerException, is BadCredentialsException -> onSessionExpired()
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 1bf5c7ad9..701656b55 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
@@ -13,13 +13,8 @@ import io.github.wulkanowy.ui.modules.about.license.LicenseFragment
import io.github.wulkanowy.ui.modules.debug.DebugFragment
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainView
-import io.github.wulkanowy.utils.AppInfo
-import io.github.wulkanowy.utils.getCompatDrawable
-import io.github.wulkanowy.utils.openAppInMarket
-import io.github.wulkanowy.utils.openEmailClient
-import io.github.wulkanowy.utils.openInternetBrowser
-import io.github.wulkanowy.utils.toFormattedString
-import io.github.wulkanowy.utils.toLocalDateTime
+import io.github.wulkanowy.utils.*
+import java.time.Instant
import javax.inject.Inject
@AndroidEntryPoint
@@ -38,7 +33,7 @@ class AboutFragment : BaseFragment(R.layout.fragment_about
override val versionRes: Triple?
get() = context?.run {
val buildTimestamp =
- appInfo.buildTimestamp.toLocalDateTime().toFormattedString("yyyy-MM-dd")
+ Instant.ofEpochMilli(appInfo.buildTimestamp).toFormattedString("yyyy-MM-dd")
val versionSignature =
"${appInfo.versionName}-${appInfo.buildFlavor} (${appInfo.versionCode}), $buildTimestamp"
Triple(
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 bd9a66926..84af1ca32 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
@@ -14,8 +14,6 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.view.ActionMode
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
-import com.google.android.material.datepicker.CalendarConstraints
-import com.google.android.material.datepicker.MaterialDatePicker
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Attendance
@@ -27,12 +25,10 @@ import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
-import io.github.wulkanowy.utils.SchoolDaysValidator
import io.github.wulkanowy.utils.dpToPx
+import io.github.wulkanowy.utils.firstSchoolDayInSchoolYear
import io.github.wulkanowy.utils.getThemeAttrColor
-import io.github.wulkanowy.utils.schoolYearStart
-import io.github.wulkanowy.utils.toLocalDateTime
-import io.github.wulkanowy.utils.toTimestamp
+import io.github.wulkanowy.utils.openMaterialDatePicker
import java.time.LocalDate
import javax.inject.Inject
@@ -224,29 +220,15 @@ class AttendanceFragment : BaseFragment(R.layout.frag
(activity as? MainActivity)?.showDialogFragment(AttendanceDialog.newInstance(lesson))
}
- override fun showDatePickerDialog(currentDate: LocalDate) {
- val baseDate = currentDate.schoolYearStart
- val rangeStart = baseDate.toTimestamp()
- val rangeEnd = LocalDate.now().plusWeeks(1).toTimestamp()
-
- val constraintsBuilder = CalendarConstraints.Builder().apply {
- setValidator(SchoolDaysValidator(rangeStart, rangeEnd))
- setStart(rangeStart)
- setEnd(rangeEnd)
- }
- val datePicker = MaterialDatePicker.Builder.datePicker()
- .setCalendarConstraints(constraintsBuilder.build())
- .setSelection(currentDate.toTimestamp())
- .build()
-
- datePicker.addOnPositiveButtonClickListener {
- val date = it.toLocalDateTime()
- presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth)
- }
-
- if (!parentFragmentManager.isStateSaved) {
- datePicker.show(parentFragmentManager, null)
- }
+ override fun showDatePickerDialog(selectedDate: LocalDate) {
+ openMaterialDatePicker(
+ selected = selectedDate,
+ rangeStart = selectedDate.firstSchoolDayInSchoolYear,
+ rangeEnd = LocalDate.now().plusWeeks(1),
+ onDateSelected = {
+ presenter.onDateSet(it.year, it.monthValue, it.dayOfMonth)
+ }
+ )
}
override fun showExcuseDialog() {
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 7ddd75f48..b0123065a 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
@@ -48,7 +48,7 @@ interface AttendanceView : BaseView {
fun showAttendanceDialog(lesson: Attendance)
- fun showDatePickerDialog(currentDate: LocalDate)
+ fun showDatePickerDialog(selectedDate: LocalDate)
fun showExcuseDialog()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardAdapter.kt
index 12be144cd..3b6dc7298 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardAdapter.kt
@@ -37,9 +37,7 @@ import io.github.wulkanowy.utils.left
import io.github.wulkanowy.utils.nickOrName
import io.github.wulkanowy.utils.toFormattedString
import timber.log.Timber
-import java.time.Duration
-import java.time.LocalDate
-import java.time.LocalDateTime
+import java.time.*
import java.util.Timer
import javax.inject.Inject
import kotlin.concurrent.timer
@@ -291,7 +289,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter(R.layout.fragme
binding.dashboardErrorContainer.isVisible = show
}
- override fun setErrorDetails(message: String) {
- binding.dashboardErrorMessage.text = message
+ override fun setErrorDetails(error: Throwable) {
+ binding.dashboardErrorMessage.text = requireContext().resources.getErrorString(error)
}
override fun resetView() {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
index d081e19aa..a1845ab59 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
@@ -6,37 +6,17 @@ import io.github.wulkanowy.data.db.entities.AdminMessage
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.enums.MessageFolder
-import io.github.wulkanowy.data.repositories.AdminMessageRepository
-import io.github.wulkanowy.data.repositories.AttendanceSummaryRepository
-import io.github.wulkanowy.data.repositories.ConferenceRepository
-import io.github.wulkanowy.data.repositories.ExamRepository
-import io.github.wulkanowy.data.repositories.GradeRepository
-import io.github.wulkanowy.data.repositories.HomeworkRepository
-import io.github.wulkanowy.data.repositories.LuckyNumberRepository
-import io.github.wulkanowy.data.repositories.MessageRepository
-import io.github.wulkanowy.data.repositories.PreferencesRepository
-import io.github.wulkanowy.data.repositories.SchoolAnnouncementRepository
-import io.github.wulkanowy.data.repositories.SemesterRepository
-import io.github.wulkanowy.data.repositories.StudentRepository
-import io.github.wulkanowy.data.repositories.TimetableRepository
+import io.github.wulkanowy.data.repositories.*
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.calculatePercentage
import io.github.wulkanowy.utils.flowWithResourceIn
import io.github.wulkanowy.utils.nextOrSameSchoolDay
-import kotlinx.coroutines.flow.catch
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.emitAll
-import kotlinx.coroutines.flow.filterNot
-import kotlinx.coroutines.flow.flow
-import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import timber.log.Timber
+import java.time.Instant
import java.time.LocalDate
-import java.time.LocalDateTime
import javax.inject.Inject
class DashboardPresenter @Inject constructor(
@@ -552,7 +532,7 @@ class DashboardPresenter @Inject constructor(
student = student,
semester = semester,
forceRefresh = forceRefresh,
- startDate = LocalDateTime.now()
+ startDate = Instant.now(),
)
}.onEach {
when (it.status) {
@@ -582,7 +562,7 @@ class DashboardPresenter @Inject constructor(
}
private fun loadAdminMessage(student: Student, forceRefresh: Boolean) {
- flowWithResourceIn { adminMessageRepository.getAdminMessages(student, forceRefresh) }
+ flowWithResourceIn { adminMessageRepository.getAdminMessages(student) }
.map {
val isDismissed = it.data?.id in preferencesRepository.dismissedAdminMessageIds
it.copy(data = it.data.takeUnless { isDismissed })
@@ -716,7 +696,7 @@ class DashboardPresenter @Inject constructor(
itemsLoadedList.find { it.type == DashboardItem.Type.ACCOUNT }?.error != null
val isGeneralError =
filteredItems.none { it.error == null } && filteredItems.isNotEmpty() || isAccountItemError
- val errorMessage = itemsLoadedList.map { it.error?.stackTraceToString() }.toString()
+ val firstError = itemsLoadedList.mapNotNull { it.error }.firstOrNull()
val filteredOriginalLoadedList =
dashboardItemLoadedList.filterNot { it.type == DashboardItem.Type.ACCOUNT }
@@ -726,7 +706,7 @@ class DashboardPresenter @Inject constructor(
filteredOriginalLoadedList.none { it.error == null } && filteredOriginalLoadedList.isNotEmpty() || wasAccountItemError
if (isGeneralError && isItemsLoaded) {
- lastError = Exception(errorMessage)
+ lastError = requireNotNull(firstError)
view?.run {
showProgress(false)
@@ -734,6 +714,7 @@ class DashboardPresenter @Inject constructor(
if ((forceRefresh && wasGeneralError) || !forceRefresh) {
showContent(false)
showErrorView(true)
+ setErrorDetails(lastError)
}
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardView.kt
index 730e19a35..2cc2f1d2d 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardView.kt
@@ -18,7 +18,7 @@ interface DashboardView : BaseView {
fun showErrorView(show: Boolean)
- fun setErrorDetails(message: String)
+ fun setErrorDetails(error: Throwable)
fun resetView()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/conference.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/conference.kt
index 40af6bfbb..625ff4c9d 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/conference.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/conference.kt
@@ -1,7 +1,8 @@
package io.github.wulkanowy.ui.modules.debug.notification.mock
import io.github.wulkanowy.data.db.entities.Conference
-import java.time.LocalDateTime
+import java.time.Duration
+import java.time.Instant
val debugConferenceItems = listOf(
generateConference(
@@ -53,6 +54,6 @@ private fun generateConference(title: String, subject: String) = Conference(
diaryId = 0,
agenda = "",
conferenceId = 0,
- date = LocalDateTime.now().plusMinutes(10),
+ date = Instant.now().plus(Duration.ofMinutes(10)),
presentOnConference = "",
)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/gradeDetails.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/gradeDetails.kt
index f9c481e39..77b60188b 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/gradeDetails.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/gradeDetails.kt
@@ -5,7 +5,7 @@ import java.time.LocalDate
val debugGradeDetailsItems = listOf(
generateGrade("Matematyka", "+"),
- generateGrade("Matematyka", "2="),
+ generateGrade("Matematyka", "120", comment = "%"),
generateGrade("Fizyka", "-"),
generateGrade("Geografia", "4+"),
generateGrade("Sieci komputerowe", "1"),
@@ -17,14 +17,14 @@ val debugGradeDetailsItems = listOf(
generateGrade("Wychowanie fizyczne", "5"),
)
-private fun generateGrade(subject: String, entry: String) = Grade(
+private fun generateGrade(subject: String, entry: String, comment: String = "") = Grade(
subject = subject,
entry = entry,
semesterId = 0,
studentId = 0,
value = 0.0,
modifier = 0.0,
- comment = "",
+ comment = comment,
color = "",
gradeSymbol = "",
description = "",
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/message.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/message.kt
index f506d2f6e..53d439612 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/message.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/message.kt
@@ -1,7 +1,7 @@
package io.github.wulkanowy.ui.modules.debug.notification.mock
import io.github.wulkanowy.data.db.entities.Message
-import java.time.LocalDateTime
+import java.time.Instant
val debugMessageItems = listOf(
generateMessage("Kowalski Jan", "Tytuł"),
@@ -24,7 +24,7 @@ private fun generateMessage(sender: String, subject: String) = Message(
messageId = 0,
senderId = 0,
recipient = "",
- date = LocalDateTime.now(),
+ date = Instant.now(),
folderId = 0,
unread = true,
removed = false,
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/schoolAnnouncement.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/schoolAnnouncement.kt
index 42524e6e0..9b21f08e6 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/schoolAnnouncement.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/schoolAnnouncement.kt
@@ -4,13 +4,13 @@ import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
import java.time.LocalDate
val debugSchoolAnnouncementItems = listOf(
- generateAnnouncement("Dzień wolny od zajęć dydaktycznych", "Dzień wolny od zajęć dydaktycznych\n03.05.2021 - poniedziałek"),
+ generateAnnouncement("Dzień wolny od zajęć dydaktycznych", "Dzień wolny od zajęć dydaktycznych
03.05.2021 – poniedziałek"),
generateAnnouncement("Zasady bezpieczeństwa", "Wszyscy uczniowie są zobowiązani do noszenia maseczek"),
generateAnnouncement("Święto szkoły", "W najbliższych dniach obchodzimy święto szkoły, podczas którego..."),
generateAnnouncement("Rocznica odzyskania przez szkołę sztandaru", "Juz niedługo, bo za tydzień, a dokładnie za 8 dni..."),
generateAnnouncement("Ogłoszenie w sprawie otwarcia stołówki", "Wszyscy uczniowie zainteresowani obiadami w szkole..."),
generateAnnouncement("Uczniowie proszeni do sekretariatu", "Kuba i Jacek z klasy czwartej proszeni do dyrektora w trybie pilnym"),
- generateAnnouncement("Dzień wolny od zajęć dydaktycznych", "Dzień wolny od zajęć dydaktycznych\n21.06.2021 - poniedziałek"),
+ generateAnnouncement("Dzień wolny od zajęć dydaktycznych", "Dzień wolny od zajęć dydaktycznych
21.06.2021 – poniedziałek"),
generateAnnouncement("Zasady bezpieczeństwa", "Wszyscy uczniowie są zobowiązani do zdjęcia maseczek"),
generateAnnouncement("Święto państwowe", "W najbliższych dniach obchodzimy święto państwowe, podczas którego..."),
generateAnnouncement("Uczniowie proszeni do sekretariatu", "Kuba i Jacek z klasy czwartej proszeni do dyrektora w trybie wolnym"),
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/timetable.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/timetable.kt
index 428c001d6..bb8a8df36 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/timetable.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/timetable.kt
@@ -1,8 +1,9 @@
package io.github.wulkanowy.ui.modules.debug.notification.mock
import io.github.wulkanowy.data.db.entities.Timetable
+import java.time.Duration
+import java.time.Instant
import java.time.LocalDate
-import java.time.LocalDateTime
import kotlin.random.Random
val debugTimetableItems = listOf(
@@ -24,8 +25,8 @@ private fun generateTimetable(subject: String, room: String, roomOld: String) =
diaryId = 0,
date = LocalDate.now().minusDays(Random.nextLong(0, 8)),
number = 1,
- start = LocalDateTime.now().plusHours(1),
- end = LocalDateTime.now(),
+ start = Instant.now(),
+ end = Instant.now().plus(Duration.ofHours(1)),
subjectOld = "",
group = "",
room = room,
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 35d007749..2af59c011 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
@@ -33,6 +33,7 @@ class GradeStatisticsFragment :
companion object {
private const val SAVED_CHART_TYPE = "CURRENT_TYPE"
+ private const val SAVED_SUBJECT_NAME = "SUBJECT_NAME"
fun newInstance() = GradeStatisticsFragment()
}
@@ -46,8 +47,9 @@ class GradeStatisticsFragment :
binding = FragmentGradeStatisticsBinding.bind(view)
messageContainer = binding.gradeStatisticsRecycler
presenter.onAttachView(
- this,
- savedInstanceState?.getSerializable(SAVED_CHART_TYPE) as? GradeStatisticsItem.DataType
+ view = this,
+ type = savedInstanceState?.getSerializable(SAVED_CHART_TYPE) as? GradeStatisticsItem.DataType,
+ subjectName = savedInstanceState?.getSerializable(SAVED_SUBJECT_NAME) as? String,
)
}
@@ -56,6 +58,7 @@ class GradeStatisticsFragment :
with(binding.gradeStatisticsRecycler) {
layoutManager = LinearLayoutManager(requireContext())
+ statisticsAdapter.currentDataType = presenter.currentType
adapter = statisticsAdapter
}
@@ -81,7 +84,8 @@ class GradeStatisticsFragment :
}
}
- override fun updateSubjects(data: ArrayList) {
+ override fun updateSubjects(data: List, selectedIndex: Int) {
+ binding.gradeStatisticsSubjects.setSelection(selectedIndex)
with(subjectsAdapter) {
clear()
addAll(data)
@@ -161,6 +165,7 @@ class GradeStatisticsFragment :
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putSerializable(SAVED_CHART_TYPE, presenter.currentType)
+ outState.putSerializable(SAVED_SUBJECT_NAME, presenter.currentSubjectName)
}
override fun onDestroyView() {
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 53eccad65..e536f473a 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
@@ -31,16 +31,22 @@ class GradeStatisticsPresenter @Inject constructor(
private var currentSemesterId = 0
- private var currentSubjectName: String = "Wszystkie"
+ var currentSubjectName: String = "Wszystkie"
+ private set
private lateinit var lastError: Throwable
var currentType: GradeStatisticsItem.DataType = GradeStatisticsItem.DataType.PARTIAL
private set
- fun onAttachView(view: GradeStatisticsView, type: GradeStatisticsItem.DataType?) {
+ fun onAttachView(
+ view: GradeStatisticsView,
+ type: GradeStatisticsItem.DataType?,
+ subjectName: String?
+ ) {
super.onAttachView(view)
currentType = type ?: GradeStatisticsItem.DataType.PARTIAL
+ currentSubjectName = subjectName ?: currentSubjectName
view.initView()
errorHandler.showErrorMessage = ::showErrorViewOnError
}
@@ -127,12 +133,17 @@ class GradeStatisticsPresenter @Inject constructor(
when (it.status) {
Status.LOADING -> Timber.i("Loading grade stats subjects started")
Status.SUCCESS -> {
- subjects = it.data!!
-
+ subjects = requireNotNull(it.data)
Timber.i("Loading grade stats subjects result: Success")
+
view?.run {
- view?.updateSubjects(ArrayList(it.data.map { subject -> subject.name }))
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)
+ updateSubjects(
+ data = it.data.map { subject -> subject.name },
+ selectedIndex = it.data.indexOfFirst { subject ->
+ subject.name == currentSubjectName
+ },
+ )
}
}
Status.ERROR -> {
@@ -151,9 +162,11 @@ class GradeStatisticsPresenter @Inject constructor(
) {
Timber.i("Loading grade stats data started")
- currentSubjectName =
- if (preferencesRepository.showAllSubjectsOnStatisticsList) "Wszystkie" else subjectName
currentType = type
+ currentSubjectName = when {
+ preferencesRepository.showAllSubjectsOnStatisticsList -> "Wszystkie"
+ else -> subjectName
+ }
flowWithResourceIn {
val student = studentRepository.getCurrentStudent()
@@ -200,9 +213,9 @@ class GradeStatisticsPresenter @Inject constructor(
showRefresh(true)
showProgress(false)
updateData(
- if (isNoContent) emptyList() else it.data!!,
- preferencesRepository.gradeColorTheme,
- preferencesRepository.showAllSubjectsOnStatisticsList
+ newItems = if (isNoContent) emptyList() else it.data!!,
+ newTheme = preferencesRepository.gradeColorTheme,
+ showAllSubjectsOnStatisticsList = preferencesRepository.showAllSubjectsOnStatisticsList,
)
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)
}
@@ -215,9 +228,9 @@ class GradeStatisticsPresenter @Inject constructor(
showEmpty(isNoContent)
showErrorView(false)
updateData(
- if (isNoContent) emptyList() else it.data,
- preferencesRepository.gradeColorTheme,
- preferencesRepository.showAllSubjectsOnStatisticsList
+ newItems = if (isNoContent) emptyList() else it.data,
+ newTheme = preferencesRepository.gradeColorTheme,
+ showAllSubjectsOnStatisticsList = preferencesRepository.showAllSubjectsOnStatisticsList,
)
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)
}
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 8e9a206bc..4333bb0a9 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
@@ -12,7 +12,7 @@ interface GradeStatisticsView : BaseView {
fun initView()
- fun updateSubjects(data: ArrayList)
+ fun updateSubjects(data: List, selectedIndex: Int)
fun updateData(
newItems: List,
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/add/HomeworkAddDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/add/HomeworkAddDialog.kt
index 12168f142..c2aff2b13 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/add/HomeworkAddDialog.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/add/HomeworkAddDialog.kt
@@ -5,15 +5,13 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.widget.doOnTextChanged
-import com.google.android.material.datepicker.CalendarConstraints
-import com.google.android.material.datepicker.MaterialDatePicker
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.databinding.DialogHomeworkAddBinding
import io.github.wulkanowy.ui.base.BaseDialogFragment
+import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
+import io.github.wulkanowy.utils.openMaterialDatePicker
import io.github.wulkanowy.utils.toFormattedString
-import io.github.wulkanowy.utils.toLocalDateTime
-import io.github.wulkanowy.utils.toTimestamp
import java.time.LocalDate
import javax.inject.Inject
@@ -23,6 +21,7 @@ class HomeworkAddDialog : BaseDialogFragment(), Homewo
@Inject
lateinit var presenter: HomeworkAddPresenter
+ // todo: move it to presenter
private var date: LocalDate? = null
override fun onCreate(savedInstanceState: Bundle?) {
@@ -97,24 +96,16 @@ class HomeworkAddDialog : BaseDialogFragment(), Homewo
dismiss()
}
- override fun showDatePickerDialog(currentDate: LocalDate) {
- val constraintsBuilder = CalendarConstraints.Builder().apply {
- setStart(LocalDate.now().toEpochDay())
- }
- val datePicker =
- MaterialDatePicker.Builder.datePicker()
- .setCalendarConstraints(constraintsBuilder.build())
- .setSelection(currentDate.toTimestamp())
- .build()
-
- datePicker.addOnPositiveButtonClickListener {
- date = it.toLocalDateTime().toLocalDate()
- binding.homeworkDialogDate.editText?.setText(date!!.toFormattedString())
- }
-
- if (!parentFragmentManager.isStateSaved) {
- datePicker.show(this.parentFragmentManager, null)
- }
+ override fun showDatePickerDialog(selectedDate: LocalDate) {
+ openMaterialDatePicker(
+ selected = selectedDate,
+ rangeStart = LocalDate.now(),
+ rangeEnd = LocalDate.now().lastSchoolDayInSchoolYear,
+ onDateSelected = {
+ date = it
+ binding.homeworkDialogDate.editText?.setText(date!!.toFormattedString())
+ }
+ )
}
override fun onDestroyView() {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/add/HomeworkAddView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/add/HomeworkAddView.kt
index 3bb304d9c..91414ae2f 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/add/HomeworkAddView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/add/HomeworkAddView.kt
@@ -17,5 +17,5 @@ interface HomeworkAddView : BaseView {
fun closeDialog()
- fun showDatePickerDialog(currentDate: LocalDate)
+ fun showDatePickerDialog(selectedDate: LocalDate)
}
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 e607cef15..d7d77f73d 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt
@@ -4,18 +4,19 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.MenuItem
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.commit
import dagger.hilt.android.AndroidEntryPoint
+import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.databinding.ActivityLoginBinding
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.recover.LoginRecoverFragment
import io.github.wulkanowy.ui.modules.login.studentselect.LoginStudentSelectFragment
import io.github.wulkanowy.ui.modules.login.symbol.LoginSymbolFragment
import io.github.wulkanowy.utils.UpdateHelper
-import io.github.wulkanowy.utils.setOnSelectPageListener
import javax.inject.Inject
@AndroidEntryPoint
@@ -24,21 +25,10 @@ class LoginActivity : BaseActivity(), Logi
@Inject
override lateinit var presenter: LoginPresenter
- private val pagerAdapter by lazy {
- BaseFragmentPagerAdapter(
- fragmentManager = supportFragmentManager,
- pagesCount = 5,
- lifecycle = lifecycle,
- )
- }
-
@Inject
lateinit var updateHelper: UpdateHelper
- override val currentViewIndex get() = binding.loginViewpager.currentItem
-
companion object {
-
fun getStartIntent(context: Context) = Intent(context, LoginActivity::class.java)
}
@@ -51,6 +41,50 @@ class LoginActivity : BaseActivity(), Logi
presenter.onAttachView(this)
updateHelper.checkAndInstallUpdates(this)
+
+ if (savedInstanceState == null) {
+ openFragment(LoginFormFragment.newInstance(), clearBackStack = true)
+ }
+ }
+
+ override fun initView() {
+ with(requireNotNull(supportActionBar)) {
+ setDisplayHomeAsUpEnabled(true)
+ setDisplayShowTitleEnabled(false)
+ }
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) onBackPressed()
+ return true
+ }
+
+ fun showActionBar(show: Boolean) {
+ supportActionBar?.run { if (show) show() else hide() }
+ }
+
+ fun navigateToSymbolFragment(loginData: LoginData) {
+ openFragment(LoginSymbolFragment.newInstance(loginData))
+ }
+
+ fun navigateToStudentSelect(studentsWithSemesters: List) {
+ openFragment(LoginStudentSelectFragment.newInstance(studentsWithSemesters))
+ }
+
+ fun onAdvancedLoginClick() {
+ openFragment(LoginAdvancedFragment.newInstance())
+ }
+
+ fun onRecoverClick() {
+ openFragment(LoginRecoverFragment.newInstance())
+ }
+
+ private fun openFragment(fragment: Fragment, clearBackStack: Boolean = false) {
+ supportFragmentManager.commit {
+ replace(R.id.loginContainer, fragment)
+ setReorderingAllowed(true)
+ if (!clearBackStack) addToBackStack(fragment::class.java.name)
+ }
}
override fun onResume() {
@@ -64,78 +98,4 @@ class LoginActivity : BaseActivity(), Logi
super.onActivityResult(requestCode, resultCode, data)
updateHelper.onActivityResult(requestCode, resultCode)
}
-
- override fun initView() {
- with(requireNotNull(supportActionBar)) {
- setDisplayHomeAsUpEnabled(true)
- setDisplayShowTitleEnabled(false)
- }
-
- with(binding.loginViewpager) {
- adapter = pagerAdapter
- isUserInputEnabled = false
- offscreenPageLimit = 2
- setOnSelectPageListener(presenter::onViewSelected)
- }
-
- with(pagerAdapter) {
- containerId = binding.loginViewpager.id
- itemFactory = {
- when (it) {
- 0 -> LoginFormFragment.newInstance()
- 1 -> LoginSymbolFragment.newInstance()
- 2 -> LoginStudentSelectFragment.newInstance()
- 3 -> LoginAdvancedFragment.newInstance()
- 4 -> LoginRecoverFragment.newInstance()
- else -> throw IllegalStateException()
- }
- }
- }
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- if (item.itemId == android.R.id.home) onBackPressed()
- return true
- }
-
- override fun switchView(index: Int) {
- binding.loginViewpager.setCurrentItem(index, false)
- }
-
- override fun showActionBar(show: Boolean) {
- supportActionBar?.run { if (show) show() else hide() }
- }
-
- override fun onBackPressed() {
- presenter.onBackPressed { super.onBackPressed() }
- }
-
- override fun notifyInitSymbolFragment(loginData: Triple) {
- (pagerAdapter.getFragmentInstance(1) as? LoginSymbolFragment)
- ?.onParentInitSymbolFragment(loginData)
- }
-
- override fun notifyInitStudentSelectFragment(studentsWithSemesters: List) {
- (pagerAdapter.getFragmentInstance(2) as? LoginStudentSelectFragment)
- ?.onParentInitStudentSelectFragment(studentsWithSemesters)
- }
-
- fun onFormFragmentAccountLogged(
- studentsWithSemesters: List,
- loginData: Triple
- ) {
- presenter.onFormViewAccountLogged(studentsWithSemesters, loginData)
- }
-
- fun onSymbolFragmentAccountLogged(studentsWithSemesters: List) {
- presenter.onSymbolViewAccountLogged(studentsWithSemesters)
- }
-
- fun onAdvancedLoginClick() {
- presenter.onAdvancedLoginClick()
- }
-
- fun onRecoverClick() {
- presenter.onRecoverClick()
- }
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginData.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginData.kt
new file mode 100644
index 000000000..5d4743589
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginData.kt
@@ -0,0 +1,9 @@
+package io.github.wulkanowy.ui.modules.login
+
+import java.io.Serializable
+
+data class LoginData(
+ val login: String,
+ val password: String,
+ val baseUrl: String,
+) : Serializable
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 ea7215cea..37ab71dce 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
@@ -12,8 +12,9 @@ import io.github.wulkanowy.sdk.scrapper.login.BadCredentialsException
import io.github.wulkanowy.ui.base.ErrorHandler
import javax.inject.Inject
-class LoginErrorHandler @Inject constructor(@ApplicationContext context: Context) :
- ErrorHandler(context) {
+class LoginErrorHandler @Inject constructor(
+ @ApplicationContext context: Context,
+) : ErrorHandler(context) {
var onBadCredentials: (String?) -> Unit = {}
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 aa1e7eced..9031cb8ab 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginPresenter.kt
@@ -1,6 +1,5 @@
package io.github.wulkanowy.ui.modules.login
-import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
@@ -14,59 +13,7 @@ class LoginPresenter @Inject constructor(
override fun onAttachView(view: LoginView) {
super.onAttachView(view)
- with(view) {
- initView()
- showActionBar(false)
- }
+ view.initView()
Timber.i("Login view was initialized")
}
-
- fun onFormViewAccountLogged(studentsWithSemesters: List, loginData: Triple) {
- view?.apply {
- if (studentsWithSemesters.isEmpty()) {
- Timber.i("Switch to symbol form")
- notifyInitSymbolFragment(loginData)
- switchView(1)
- } else {
- Timber.i("Switch to student select")
- notifyInitStudentSelectFragment(studentsWithSemesters)
- switchView(2)
- }
- }
- }
-
- fun onSymbolViewAccountLogged(studentsWithSemesters: List) {
- view?.apply {
- Timber.i("Switch to student select")
- notifyInitStudentSelectFragment(studentsWithSemesters)
- switchView(2)
- }
- }
-
- fun onAdvancedLoginClick() {
- view?.switchView(3)
- }
-
- fun onRecoverClick() {
- view?.switchView(4)
- }
-
- fun onViewSelected(index: Int) {
- view?.apply {
- when (index) {
- 0 -> showActionBar(false)
- 1, 2, 3, 4 -> showActionBar(true)
- }
- }
- }
-
- fun onBackPressed(default: () -> Unit) {
- Timber.i("Back pressed in login view")
- view?.apply {
- when (currentViewIndex) {
- 1, 2, 3, 4 -> switchView(0)
- else -> default()
- }
- }
- }
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginView.kt
index 2a5cf316a..a0949e6d9 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginView.kt
@@ -1,19 +1,8 @@
package io.github.wulkanowy.ui.modules.login
-import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.ui.base.BaseView
interface LoginView : BaseView {
- val currentViewIndex: Int
-
fun initView()
-
- fun switchView(index: Int)
-
- fun showActionBar(show: Boolean)
-
- fun notifyInitSymbolFragment(loginData: Triple)
-
- fun notifyInitStudentSelectFragment(studentsWithSemesters: List)
}
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
index bc29cd146..37dcb38b3 100644
--- 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
@@ -13,6 +13,7 @@ import io.github.wulkanowy.databinding.FragmentLoginAdvancedBinding
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.LoginData
import io.github.wulkanowy.ui.modules.login.form.LoginSymbolAdapter
import io.github.wulkanowy.utils.hideSoftInput
import io.github.wulkanowy.utils.setOnEditorDoneSignIn
@@ -80,6 +81,8 @@ class LoginAdvancedFragment :
}
override fun initView() {
+ (requireActivity() as LoginActivity).showActionBar(true)
+
hostKeys = resources.getStringArray(R.array.hosts_keys)
hostValues = resources.getStringArray(R.array.hosts_values)
hostSymbols = resources.getStringArray(R.array.hosts_symbols)
@@ -320,14 +323,12 @@ class LoginAdvancedFragment :
binding.loginFormContainer.visibility = if (show) VISIBLE else GONE
}
- override fun notifyParentAccountLogged(studentsWithSemesters: List) {
- (activity as? LoginActivity)?.onFormFragmentAccountLogged(
- studentsWithSemesters, Triple(
- binding.loginFormUsername.text.toString(),
- binding.loginFormPass.text.toString(),
- resources.getStringArray(R.array.hosts_values)[1]
- )
- )
+ override fun navigateToSymbol(loginData: LoginData) {
+ (activity as? LoginActivity)?.navigateToSymbolFragment(loginData)
+ }
+
+ override fun navigateToStudentSelect(studentsWithSemesters: List) {
+ (activity as? LoginActivity)?.navigateToStudentSelect(studentsWithSemesters)
}
override fun onResume() {
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
index 17d8c5ecb..3543a3041 100644
--- 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
@@ -5,6 +5,7 @@ import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.ui.base.BasePresenter
+import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.afterLoading
@@ -77,7 +78,9 @@ class LoginAdvancedPresenter @Inject constructor(
clearPassError()
clearUsernameError()
if (formHostValue.contains("fakelog")) {
- setDefaultCredentials("jan@fakelog.cf", "jan123", "powiatwulkanowy", "FK100000", "999999")
+ setDefaultCredentials(
+ "jan@fakelog.cf", "jan123", "powiatwulkanowy", "FK100000", "999999"
+ )
}
setSymbol(formHostSymbol)
updateUsernameLabel()
@@ -136,12 +139,21 @@ class LoginAdvancedPresenter @Inject constructor(
}
Status.SUCCESS -> {
Timber.i("Login result: Success")
- analytics.logEvent("registration_form",
+ analytics.logEvent(
+ "registration_form",
"success" to true,
"students" to it.data!!.size,
"error" to "No error"
)
- view?.notifyParentAccountLogged(it.data)
+ val loginData = LoginData(
+ login = view?.formUsernameValue.orEmpty().trim(),
+ password = view?.formPassValue.orEmpty().trim(),
+ baseUrl = view?.formHostValue.orEmpty().trim()
+ )
+ when (it.data.size) {
+ 0 -> view?.navigateToSymbol(loginData)
+ else -> view?.navigateToStudentSelect(it.data)
+ }
}
Status.ERROR -> {
Timber.i("Login result: An exception occurred")
@@ -172,8 +184,12 @@ class LoginAdvancedPresenter @Inject constructor(
return when (Sdk.Mode.valueOf(view?.formLoginType.orEmpty())) {
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)
+ Sdk.Mode.SCRAPPER -> studentRepository.getStudentsScrapper(
+ email, password, endpoint, symbol
+ )
+ Sdk.Mode.HYBRID -> studentRepository.getStudentsHybrid(
+ email, password, endpoint, symbol
+ )
}
}
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
index 1d2b2856d..f9b84f1ab 100644
--- 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
@@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.login.advanced
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.ui.base.BaseView
+import io.github.wulkanowy.ui.modules.login.LoginData
interface LoginAdvancedView : BaseView {
@@ -69,7 +70,9 @@ interface LoginAdvancedView : BaseView {
fun showContent(show: Boolean)
- fun notifyParentAccountLogged(studentsWithSemesters: List)
+ fun navigateToSymbol(loginData: LoginData)
+
+ fun navigateToStudentSelect(studentsWithSemesters: List)
fun setErrorPinRequired()
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 c741da429..d31f5cf0f 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
@@ -13,6 +13,7 @@ import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.databinding.FragmentLoginFormBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.login.LoginActivity
+import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.hideSoftInput
import io.github.wulkanowy.utils.openEmailClient
@@ -68,6 +69,8 @@ class LoginFormFragment : BaseFragment(R.layout.fragme
}
override fun initView() {
+ (requireActivity() as LoginActivity).showActionBar(false)
+
hostKeys = resources.getStringArray(R.array.hosts_keys)
hostValues = resources.getStringArray(R.array.hosts_values)
hostSymbols = resources.getStringArray(R.array.hosts_symbols)
@@ -203,11 +206,9 @@ class LoginFormFragment : BaseFragment(R.layout.fragme
binding.loginFormVersion.text = "v${appInfo.versionName}"
}
- override fun notifyParentAccountLogged(
- studentsWithSemesters: List,
- loginData: Triple
- ) {
- (activity as? LoginActivity)?.onFormFragmentAccountLogged(studentsWithSemesters, loginData)
+ override fun showContact(show: Boolean) {
+ binding.loginFormContact.visibility = if (show) VISIBLE else GONE
+ binding.loginFormRecoverLink.visibility = if (show) GONE else VISIBLE
}
override fun openPrivacyPolicyPage() {
@@ -217,9 +218,12 @@ class LoginFormFragment : BaseFragment(R.layout.fragme
)
}
- override fun showContact(show: Boolean) {
- binding.loginFormContact.visibility = if (show) VISIBLE else GONE
- binding.loginFormRecoverLink.visibility = if (show) GONE else VISIBLE
+ override fun navigateToSymbol(loginData: LoginData) {
+ (activity as? LoginActivity)?.navigateToSymbolFragment(loginData)
+ }
+
+ override fun navigateToStudentSelect(studentsWithSemesters: List) {
+ (activity as? LoginActivity)?.navigateToStudentSelect(studentsWithSemesters)
}
override fun openAdvancedLogin() {
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 1002549cf..49be6fbb6 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
@@ -4,6 +4,7 @@ import androidx.core.net.toUri
import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
+import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.afterLoading
@@ -118,7 +119,10 @@ class LoginFormPresenter @Inject constructor(
"scrapperBaseUrl" to host,
"error" to "No error"
)
- view?.notifyParentAccountLogged(it.data, Triple(email, password, host))
+ when (it.data.size) {
+ 0 -> view?.navigateToSymbol(LoginData(email, password, host))
+ else -> view?.navigateToStudentSelect(it.data)
+ }
}
Status.ERROR -> {
Timber.i("Login result: An exception occurred")
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 300573559..8003975db 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
@@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.login.form
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.ui.base.BaseView
+import io.github.wulkanowy.ui.modules.login.LoginData
interface LoginFormView : BaseView {
@@ -57,7 +58,9 @@ interface LoginFormView : BaseView {
fun showVersion()
- fun notifyParentAccountLogged(studentsWithSemesters: List, loginData: Triple)
+ fun navigateToSymbol(loginData: LoginData)
+
+ fun navigateToStudentSelect(studentsWithSemesters: List)
fun openPrivacyPolicyPage()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverFragment.kt
index a91dfb618..c1c111d46 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverFragment.kt
@@ -11,8 +11,10 @@ import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.core.view.isVisible
import androidx.core.widget.doOnTextChanged
+import com.yariksoffice.lingver.Lingver
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
+import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.databinding.FragmentLoginRecoverBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.login.LoginActivity
@@ -32,6 +34,12 @@ class LoginRecoverFragment :
@Inject
lateinit var presenter: LoginRecoverPresenter
+ @Inject
+ lateinit var lingver: Lingver
+
+ @Inject
+ lateinit var preferencesRepository: PreferencesRepository
+
companion object {
fun newInstance() = LoginRecoverFragment()
}
@@ -64,11 +72,23 @@ class LoginRecoverFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
+ restoreCorrectLocale()
_binding = FragmentLoginRecoverBinding.bind(view)
presenter.onAttachView(this)
}
+ // https://issuetracker.google.com/issues/37113860
+ private fun restoreCorrectLocale() {
+ if (preferencesRepository.appLanguage == "system") {
+ lingver.setFollowSystemLocale(requireContext())
+ } else {
+ lingver.setLocale(requireContext(), lingver.getLocale())
+ }
+ }
+
override fun initView() {
+ (requireActivity() as LoginActivity).showActionBar(true)
+
hostKeys = resources.getStringArray(R.array.hosts_keys)
hostValues = resources.getStringArray(R.array.hosts_values)
hostSymbols = resources.getStringArray(R.array.hosts_symbols)
@@ -80,7 +100,7 @@ class LoginRecoverFragment :
loginRecoverButton.setOnClickListener { presenter.onRecoverClick() }
loginRecoverErrorRetry.setOnClickListener { presenter.onRecoverClick() }
loginRecoverErrorDetails.setOnClickListener { presenter.onDetailsClick() }
- loginRecoverLogin.setOnClickListener { (activity as LoginActivity).switchView(0) }
+ loginRecoverLogin.setOnClickListener { (activity as LoginActivity).onBackPressed() }
}
with(bindingLocal.loginRecoverHost) {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/RecoverErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/RecoverErrorHandler.kt
index ac4c03130..28686d626 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/RecoverErrorHandler.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/RecoverErrorHandler.kt
@@ -8,8 +8,9 @@ import io.github.wulkanowy.sdk.scrapper.exception.NoAccountFoundException
import io.github.wulkanowy.ui.base.ErrorHandler
import javax.inject.Inject
-class RecoverErrorHandler @Inject constructor(@ApplicationContext context: Context) :
- ErrorHandler(context) {
+class RecoverErrorHandler @Inject constructor(
+ @ApplicationContext context: Context,
+) : ErrorHandler(context) {
var onInvalidUsername: (String) -> Unit = {}
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 87cb505c4..6c910fe03 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
@@ -4,17 +4,18 @@ import android.os.Bundle
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
+import androidx.core.os.bundleOf
import androidx.recyclerview.widget.LinearLayoutManager
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.databinding.FragmentLoginStudentSelectBinding
import io.github.wulkanowy.ui.base.BaseFragment
+import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.openEmailClient
import io.github.wulkanowy.utils.openInternetBrowser
-import java.io.Serializable
import javax.inject.Inject
@AndroidEntryPoint
@@ -32,18 +33,27 @@ class LoginStudentSelectFragment :
lateinit var appInfo: AppInfo
companion object {
- const val SAVED_STUDENTS = "STUDENTS"
+ const val ARG_STUDENTS = "STUDENTS"
- fun newInstance() = LoginStudentSelectFragment()
+ fun newInstance(studentsWithSemesters: List) =
+ LoginStudentSelectFragment().apply {
+ arguments = bundleOf(ARG_STUDENTS to studentsWithSemesters)
+ }
}
+ @Suppress("UNCHECKED_CAST")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentLoginStudentSelectBinding.bind(view)
- presenter.onAttachView(this, savedInstanceState?.getSerializable(SAVED_STUDENTS))
+ presenter.onAttachView(
+ view = this,
+ students = requireArguments().getSerializable(ARG_STUDENTS) as List,
+ )
}
override fun initView() {
+ (requireActivity() as LoginActivity).showActionBar(true)
+
loginAdapter.onClickListener = presenter::onItemSelected
with(binding) {
@@ -82,15 +92,6 @@ class LoginStudentSelectFragment :
binding.loginStudentSelectSignIn.isEnabled = enable
}
- fun onParentInitStudentSelectFragment(studentsWithSemesters: List) {
- presenter.onParentInitStudentSelectView(studentsWithSemesters)
- }
-
- override fun onSaveInstanceState(outState: Bundle) {
- super.onSaveInstanceState(outState)
- outState.putSerializable(SAVED_STUDENTS, presenter.students as Serializable)
- }
-
override fun showContact(show: Boolean) {
binding.loginStudentSelectContact.visibility = if (show) VISIBLE else GONE
}
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 f0f5586cc..71c60e62d 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
@@ -4,6 +4,7 @@ import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.data.repositories.StudentRepository
+import io.github.wulkanowy.services.sync.SyncManager
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
import io.github.wulkanowy.utils.AnalyticsHelper
@@ -11,22 +12,20 @@ import io.github.wulkanowy.utils.flowWithResource
import io.github.wulkanowy.utils.ifNullOrBlank
import kotlinx.coroutines.flow.onEach
import timber.log.Timber
-import java.io.Serializable
import javax.inject.Inject
class LoginStudentSelectPresenter @Inject constructor(
studentRepository: StudentRepository,
private val loginErrorHandler: LoginErrorHandler,
+ private val syncManager: SyncManager,
private val analytics: AnalyticsHelper
) : BasePresenter(loginErrorHandler, studentRepository) {
private var lastError: Throwable? = null
- var students = emptyList()
-
private val selectedStudents = mutableListOf()
- fun onAttachView(view: LoginStudentSelectView, students: Serializable?) {
+ fun onAttachView(view: LoginStudentSelectView, students: List) {
super.onAttachView(view)
with(view) {
initView()
@@ -38,20 +37,14 @@ class LoginStudentSelectPresenter @Inject constructor(
}
}
- if (students is List<*> && students.isNotEmpty()) {
- loadData(students.filterIsInstance())
- }
+ if (students.size == 1) registerStudents(students)
+ loadData(students)
}
fun onSignIn() {
registerStudents(selectedStudents)
}
- fun onParentInitStudentSelectView(studentsWithSemesters: List) {
- loadData(studentsWithSemesters)
- if (studentsWithSemesters.size == 1) registerStudents(studentsWithSemesters)
- }
-
fun onItemSelected(studentWithSemester: StudentWithSemesters, alreadySaved: Boolean) {
if (alreadySaved) return
@@ -72,7 +65,6 @@ class LoginStudentSelectPresenter @Inject constructor(
private fun loadData(studentsWithSemesters: List) {
resetSelectedState()
- this.students = studentsWithSemesters
flowWithResource { studentRepository.getSavedStudents(false) }.onEach {
when (it.status) {
@@ -107,6 +99,7 @@ class LoginStudentSelectPresenter @Inject constructor(
}
Status.SUCCESS -> {
Timber.i("Registration result: Success")
+ syncManager.startOneTimeSyncWorker(quiet = true)
view?.openMainView()
logRegisterEvent(studentsWithSemesters)
}
@@ -143,7 +136,8 @@ class LoginStudentSelectPresenter @Inject constructor(
"success" to (error != null),
"scrapperBaseUrl" to student.student.scrapperBaseUrl,
"symbol" to student.student.symbol,
- "error" to (error?.message?.ifBlank { "No message" } ?: "No error"))
+ "error" to (error?.message?.ifBlank { "No message" } ?: "No error")
+ )
}
}
}
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 a8086935b..58bdf6cef 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
@@ -7,6 +7,7 @@ import android.view.View.VISIBLE
import android.view.inputmethod.EditorInfo.IME_ACTION_DONE
import android.view.inputmethod.EditorInfo.IME_NULL
import android.widget.ArrayAdapter
+import androidx.core.os.bundleOf
import androidx.core.text.parseAsHtml
import androidx.core.widget.doOnTextChanged
import dagger.hilt.android.AndroidEntryPoint
@@ -15,6 +16,7 @@ import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.databinding.FragmentLoginSymbolBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.login.LoginActivity
+import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.hideSoftInput
import io.github.wulkanowy.utils.openEmailClient
@@ -35,7 +37,9 @@ class LoginSymbolFragment :
companion object {
private const val SAVED_LOGIN_DATA = "LOGIN_DATA"
- fun newInstance() = LoginSymbolFragment()
+ fun newInstance(loginData: LoginData) = LoginSymbolFragment().apply {
+ arguments = bundleOf(SAVED_LOGIN_DATA to loginData)
+ }
}
override val symbolNameError: CharSequence?
@@ -44,10 +48,15 @@ class LoginSymbolFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentLoginSymbolBinding.bind(view)
- presenter.onAttachView(this, savedInstanceState?.getSerializable(SAVED_LOGIN_DATA))
+ presenter.onAttachView(
+ view = this,
+ loginData = requireArguments().getSerializable(SAVED_LOGIN_DATA) as LoginData,
+ )
}
override fun initView() {
+ (requireActivity() as LoginActivity).showActionBar(true)
+
with(binding) {
loginSymbolSignIn.setOnClickListener { presenter.attemptLogin(loginSymbolName.text.toString()) }
loginSymbolFaq.setOnClickListener { presenter.onFaqClick() }
@@ -70,12 +79,9 @@ class LoginSymbolFragment :
}
}
- fun onParentInitSymbolFragment(loginData: Triple) {
- presenter.onParentInitSymbolView(loginData)
- }
-
override fun setLoginToHeading(login: String) {
- binding.loginSymbolHeader.text = getString(R.string.login_header_symbol, login).parseAsHtml()
+ binding.loginSymbolHeader.text =
+ getString(R.string.login_header_symbol, login).parseAsHtml()
}
override fun setErrorSymbolIncorrect() {
@@ -119,8 +125,8 @@ class LoginSymbolFragment :
binding.loginSymbolContainer.visibility = if (show) VISIBLE else GONE
}
- override fun notifyParentAccountLogged(studentsWithSemesters: List) {
- (activity as? LoginActivity)?.onSymbolFragmentAccountLogged(studentsWithSemesters)
+ override fun navigateToStudentSelect(studentsWithSemesters: List) {
+ (activity as? LoginActivity)?.navigateToStudentSelect(studentsWithSemesters)
}
override fun onSaveInstanceState(outState: Bundle) {
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 1ba7e5b32..7e195893f 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
@@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.login.symbol
import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
+import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.afterLoading
@@ -10,7 +11,6 @@ import io.github.wulkanowy.utils.flowWithResource
import io.github.wulkanowy.utils.ifNullOrBlank
import kotlinx.coroutines.flow.onEach
import timber.log.Timber
-import java.io.Serializable
import javax.inject.Inject
class LoginSymbolPresenter @Inject constructor(
@@ -21,25 +21,15 @@ class LoginSymbolPresenter @Inject constructor(
private var lastError: Throwable? = null
- var loginData: Triple? = null
+ lateinit var loginData: LoginData
- @Suppress("UNCHECKED_CAST")
- fun onAttachView(view: LoginSymbolView, savedLoginData: Serializable?) {
+ fun onAttachView(view: LoginSymbolView, loginData: LoginData) {
super.onAttachView(view)
- view.run {
+ this.loginData = loginData
+ with(view) {
initView()
showContact(false)
- }
- if (savedLoginData is Triple<*, *, *>) {
- loginData = savedLoginData as Triple
- view.setLoginToHeading(requireNotNull(loginData?.first))
- }
- }
-
- fun onParentInitSymbolView(loginData: Triple) {
- this.loginData = loginData
- view?.apply {
- setLoginToHeading(loginData.first)
+ setLoginToHeading(loginData.login)
clearAndFocusSymbol()
showSoftKeyboard()
}
@@ -50,11 +40,6 @@ class LoginSymbolPresenter @Inject constructor(
}
fun attemptLogin(symbol: String) {
- if (loginData == null) {
- Timber.w("LoginSymbolPresenter - Login data is null")
- return
- }
-
if (symbol.isBlank()) {
view?.setErrorSymbolRequire()
return
@@ -62,9 +47,9 @@ class LoginSymbolPresenter @Inject constructor(
flowWithResource {
studentRepository.getStudentsScrapper(
- email = loginData!!.first,
- password = loginData!!.second,
- scrapperBaseUrl = loginData!!.third,
+ email = loginData.login,
+ password = loginData.password,
+ scrapperBaseUrl = loginData.baseUrl,
symbol = symbol,
)
}.onEach {
@@ -76,21 +61,24 @@ class LoginSymbolPresenter @Inject constructor(
showContent(false)
}
Status.SUCCESS -> {
- view?.run {
- if (it.data!!.isEmpty()) {
+ when (it.data?.size) {
+ 0 -> {
Timber.i("Login with symbol result: Empty student list")
- setErrorSymbolIncorrect()
- view?.showContact(true)
- } else {
+ view?.run {
+ setErrorSymbolIncorrect()
+ showContact(true)
+ }
+ }
+ else -> {
Timber.i("Login with symbol result: Success")
- notifyParentAccountLogged(it.data)
+ view?.navigateToStudentSelect(requireNotNull(it.data))
}
}
analytics.logEvent(
"registration_symbol",
"success" to true,
"students" to it.data!!.size,
- "scrapperBaseUrl" to loginData?.third,
+ "scrapperBaseUrl" to loginData.baseUrl,
"symbol" to symbol,
"error" to "No error"
)
@@ -101,7 +89,7 @@ class LoginSymbolPresenter @Inject constructor(
"registration_symbol",
"success" to false,
"students" to -1,
- "scrapperBaseUrl" to loginData?.third,
+ "scrapperBaseUrl" to loginData.baseUrl,
"symbol" to symbol,
"error" to it.error!!.message.ifNullOrBlank { "No message" }
)
@@ -123,6 +111,6 @@ class LoginSymbolPresenter @Inject constructor(
}
fun onEmailClick() {
- view?.openEmail(loginData?.third.orEmpty(), lastError?.message.ifNullOrBlank { "empty" })
+ view?.openEmail(loginData.baseUrl, lastError?.message.ifNullOrBlank { "empty" })
}
}
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 75523a7c7..527895b77 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
@@ -27,7 +27,7 @@ interface LoginSymbolView : BaseView {
fun showContent(show: Boolean)
- fun notifyParentAccountLogged(studentsWithSemesters: List)
+ fun navigateToStudentSelect(studentsWithSemesters: List)
fun showContact(show: Boolean)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/history/LuckyNumberHistoryFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/history/LuckyNumberHistoryFragment.kt
index 49d094b78..53f06cacd 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/history/LuckyNumberHistoryFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/history/LuckyNumberHistoryFragment.kt
@@ -5,8 +5,6 @@ import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import androidx.recyclerview.widget.LinearLayoutManager
-import com.google.android.material.datepicker.CalendarConstraints
-import com.google.android.material.datepicker.MaterialDatePicker
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.LuckyNumber
@@ -14,11 +12,9 @@ import io.github.wulkanowy.databinding.FragmentLuckyNumberHistoryBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
-import io.github.wulkanowy.utils.SchoolDaysValidator
import io.github.wulkanowy.utils.dpToPx
-import io.github.wulkanowy.utils.schoolYearStart
-import io.github.wulkanowy.utils.toLocalDateTime
-import io.github.wulkanowy.utils.toTimestamp
+import io.github.wulkanowy.utils.firstSchoolDayInSchoolYear
+import io.github.wulkanowy.utils.openMaterialDatePicker
import java.time.LocalDate
import javax.inject.Inject
@@ -111,29 +107,15 @@ class LuckyNumberHistoryFragment :
binding.luckyNumberHistoryNextButton.visibility = if (show) VISIBLE else View.INVISIBLE
}
- override fun showDatePickerDialog(currentDate: LocalDate) {
- val baseDate = currentDate.schoolYearStart
- val rangeStart = baseDate.toTimestamp()
- val rangeEnd = LocalDate.now().plusWeeks(1).toTimestamp()
-
- val constraintsBuilder = CalendarConstraints.Builder().apply {
- setValidator(SchoolDaysValidator(rangeStart, rangeEnd))
- setStart(rangeStart)
- setEnd(rangeEnd)
- }
- val datePicker = MaterialDatePicker.Builder.datePicker()
- .setCalendarConstraints(constraintsBuilder.build())
- .setSelection(currentDate.toTimestamp())
- .build()
-
- datePicker.addOnPositiveButtonClickListener {
- val date = it.toLocalDateTime()
- presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth)
- }
-
- if (!parentFragmentManager.isStateSaved) {
- datePicker.show(parentFragmentManager, null)
- }
+ override fun showDatePickerDialog(selectedDate: LocalDate) {
+ openMaterialDatePicker(
+ selected = selectedDate,
+ rangeStart = selectedDate.firstSchoolDayInSchoolYear,
+ rangeEnd = LocalDate.now().plusWeeks(1),
+ onDateSelected = {
+ presenter.onDateSet(it.year, it.monthValue, it.dayOfMonth)
+ }
+ )
}
override fun showContent(show: Boolean) {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/history/LuckyNumberHistoryView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/history/LuckyNumberHistoryView.kt
index 331e4ff86..7b9b0294f 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/history/LuckyNumberHistoryView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/history/LuckyNumberHistoryView.kt
@@ -28,7 +28,7 @@ interface LuckyNumberHistoryView : BaseView {
fun showNextButton(show: Boolean)
- fun showDatePickerDialog(currentDate: LocalDate)
+ fun showDatePickerDialog(selectedDate: LocalDate)
fun showContent(show: Boolean)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt
index c78931531..821b1e6ff 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt
@@ -19,7 +19,8 @@ import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.flowWithResource
import kotlinx.coroutines.flow.onEach
import timber.log.Timber
-import java.time.LocalDate
+import java.time.Duration
+import java.time.Instant
import javax.inject.Inject
class MainPresenter @Inject constructor(
@@ -158,11 +159,11 @@ class MainPresenter @Inject constructor(
prefRepository.inAppReviewCount++
if (prefRepository.inAppReviewDate == null) {
- prefRepository.inAppReviewDate = LocalDate.now()
+ prefRepository.inAppReviewDate = Instant.now()
}
if (!prefRepository.isAppReviewDone && prefRepository.inAppReviewCount >= 50 &&
- LocalDate.now().minusDays(14).isAfter(prefRepository.inAppReviewDate)
+ Instant.now().minus(Duration.ofDays(14)).isAfter(prefRepository.inAppReviewDate)
) {
view?.showInAppReview()
prefRepository.isAppReviewDone = true
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/advanced/AdvancedFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/advanced/AdvancedFragment.kt
index a2265b044..bef726cad 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/advanced/AdvancedFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/advanced/AdvancedFragment.kt
@@ -4,7 +4,6 @@ import android.content.SharedPreferences
import android.os.Bundle
import android.view.View
import androidx.preference.PreferenceFragmentCompat
-import com.yariksoffice.lingver.Lingver
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseActivity
@@ -24,9 +23,6 @@ class AdvancedFragment : PreferenceFragmentCompat(),
@Inject
lateinit var appInfo: AppInfo
- @Inject
- lateinit var lingver: Lingver
-
override val titleStringId get() = R.string.pref_settings_advanced_title
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/sync/SyncFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/sync/SyncFragment.kt
index 160b7c37b..d81c35d39 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/sync/SyncFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/sync/SyncFragment.kt
@@ -91,7 +91,7 @@ class SyncFragment : PreferenceFragmentCompat(),
}
override fun showErrorDetailsDialog(error: Throwable) {
- ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
+ ErrorDialog.newInstance(error).show(childFragmentManager, "error_details")
}
override fun onResume() {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/sync/SyncPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/sync/SyncPresenter.kt
index 0d404a138..1ecb4a6ef 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/sync/SyncPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/sync/SyncPresenter.kt
@@ -59,7 +59,10 @@ class SyncPresenter @Inject constructor(
WorkInfo.State.FAILED -> {
showError(
syncFailedString,
- Throwable(workInfo.outputData.getString("error"))
+ Throwable(
+ message = workInfo.outputData.getString("error_message"),
+ cause = Throwable(workInfo.outputData.getString("error_stack"))
+ )
)
analytics.logEvent("sync_now", "status" to "failed")
}
@@ -76,9 +79,7 @@ class SyncPresenter @Inject constructor(
}
private fun setSyncDateInView() {
- val lastSyncDate = preferencesRepository.lasSyncDate
-
- if (lastSyncDate.year == 1970) return
+ val lastSyncDate = preferencesRepository.lasSyncDate ?: return
view?.setLastSyncDate(lastSyncDate.toFormattedString("dd.MM.yyyy HH:mm:ss"))
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableAdapter.kt
index 422cc50e8..eacd12c69 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableAdapter.kt
@@ -15,15 +15,10 @@ import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.enums.TimetableMode
import io.github.wulkanowy.databinding.ItemTimetableBinding
import io.github.wulkanowy.databinding.ItemTimetableSmallBinding
-import io.github.wulkanowy.utils.getThemeAttrColor
-import io.github.wulkanowy.utils.isJustFinished
-import io.github.wulkanowy.utils.isShowTimeUntil
-import io.github.wulkanowy.utils.left
-import io.github.wulkanowy.utils.toFormattedString
-import io.github.wulkanowy.utils.until
+import io.github.wulkanowy.utils.*
import timber.log.Timber
-import java.time.LocalDateTime
-import java.util.Timer
+import java.time.Instant
+import java.util.*
import javax.inject.Inject
import kotlin.concurrent.timer
@@ -167,7 +162,7 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter i < position && !item.isStudentPlan }.size)
?.let {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableDialog.kt
index 5bbaaa60f..c9243b12e 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableDialog.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableDialog.kt
@@ -16,7 +16,7 @@ import io.github.wulkanowy.utils.capitalise
import io.github.wulkanowy.utils.getThemeAttrColor
import io.github.wulkanowy.utils.lifecycleAwareVariable
import io.github.wulkanowy.utils.toFormattedString
-import java.time.LocalDateTime
+import java.time.Instant
class TimetableDialog : DialogFragment() {
@@ -192,7 +192,7 @@ class TimetableDialog : DialogFragment() {
}
@SuppressLint("SetTextI18n")
- private fun setTime(start: LocalDateTime, end: LocalDateTime) {
+ private fun setTime(start: Instant, end: Instant) {
binding.timetableDialogTimeValue.text =
"${start.toFormattedString("HH:mm")} - ${end.toFormattedString("HH:mm")}"
}
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 b49d11c12..f59c6432c 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
@@ -9,8 +9,6 @@ import android.view.View.GONE
import android.view.View.VISIBLE
import androidx.core.text.parseAsHtml
import androidx.recyclerview.widget.LinearLayoutManager
-import com.google.android.material.datepicker.CalendarConstraints
-import com.google.android.material.datepicker.MaterialDatePicker
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Timetable
@@ -22,13 +20,11 @@ import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.ui.modules.timetable.additional.AdditionalLessonsFragment
import io.github.wulkanowy.ui.modules.timetable.completed.CompletedLessonsFragment
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
-import io.github.wulkanowy.utils.SchoolDaysValidator
import io.github.wulkanowy.utils.dpToPx
+import io.github.wulkanowy.utils.firstSchoolDayInSchoolYear
import io.github.wulkanowy.utils.getThemeAttrColor
-import io.github.wulkanowy.utils.schoolYearEnd
-import io.github.wulkanowy.utils.schoolYearStart
-import io.github.wulkanowy.utils.toLocalDateTime
-import io.github.wulkanowy.utils.toTimestamp
+import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
+import io.github.wulkanowy.utils.openMaterialDatePicker
import java.time.LocalDate
import javax.inject.Inject
@@ -193,29 +189,15 @@ class TimetableFragment : BaseFragment(R.layout.fragme
(activity as? MainActivity)?.showDialogFragment(TimetableDialog.newInstance(lesson))
}
- override fun showDatePickerDialog(currentDate: LocalDate) {
- val baseDate = currentDate.schoolYearStart
- val rangeStart = baseDate.toTimestamp()
- val rangeEnd = LocalDate.now().schoolYearEnd.toTimestamp()
-
- val constraintsBuilder = CalendarConstraints.Builder().apply {
- setValidator(SchoolDaysValidator(rangeStart, rangeEnd))
- setStart(rangeStart)
- setEnd(rangeEnd)
- }
- val datePicker = MaterialDatePicker.Builder.datePicker()
- .setCalendarConstraints(constraintsBuilder.build())
- .setSelection(currentDate.toTimestamp())
- .build()
-
- datePicker.addOnPositiveButtonClickListener {
- val date = it.toLocalDateTime()
- presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth)
- }
-
- if (!parentFragmentManager.isStateSaved) {
- datePicker.show(parentFragmentManager, null)
- }
+ override fun showDatePickerDialog(selectedDate: LocalDate) {
+ openMaterialDatePicker(
+ selected = selectedDate,
+ rangeStart = selectedDate.firstSchoolDayInSchoolYear,
+ rangeEnd = LocalDate.now().lastSchoolDayInSchoolYear,
+ onDateSelected = {
+ presenter.onDateSet(it.year, it.monthValue, it.dayOfMonth)
+ }
+ )
}
override fun openAdditionalLessonsView() {
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 eaf75cb0e..4f6af4b9e 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
@@ -48,7 +48,7 @@ interface TimetableView : BaseView {
fun showTimetableDialog(lesson: Timetable)
- fun showDatePickerDialog(currentDate: LocalDate)
+ fun showDatePickerDialog(selectedDate: LocalDate)
fun popView()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsAdapter.kt
index fdc8b8874..c2ce80289 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsAdapter.kt
@@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.timetable.additional
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.ViewGroup
+import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import io.github.wulkanowy.data.db.entities.TimetableAdditional
import io.github.wulkanowy.databinding.ItemTimetableAdditionalBinding
@@ -14,6 +15,8 @@ class AdditionalLessonsAdapter @Inject constructor() :
var items = emptyList()
+ var onDeleteClickListener: (timetableAdditional: TimetableAdditional) -> Unit = {}
+
override fun getItemCount() = items.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
@@ -25,8 +28,12 @@ class AdditionalLessonsAdapter @Inject constructor() :
val item = items[position]
with(holder.binding) {
- additionalLessonItemTime.text = "${item.start.toFormattedString("HH:mm")} - ${item.end.toFormattedString("HH:mm")}"
+ additionalLessonItemTime.text =
+ "${item.start.toFormattedString("HH:mm")} - ${item.end.toFormattedString("HH:mm")}"
additionalLessonItemSubject.text = item.subject
+
+ additionalLessonItemDelete.isVisible = item.isAddedByUser
+ additionalLessonItemDelete.setOnClickListener { onDeleteClickListener(item) }
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsFragment.kt
index e8fb9e440..043fa1f7d 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsFragment.kt
@@ -2,23 +2,22 @@ package io.github.wulkanowy.ui.modules.timetable.additional
import android.os.Bundle
import android.view.View
+import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.LinearLayoutManager
-import com.google.android.material.datepicker.CalendarConstraints
-import com.google.android.material.datepicker.MaterialDatePicker
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.TimetableAdditional
import io.github.wulkanowy.databinding.FragmentTimetableAdditionalBinding
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.additional.add.AdditionalLessonAddDialog
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
-import io.github.wulkanowy.utils.SchoolDaysValidator
import io.github.wulkanowy.utils.dpToPx
+import io.github.wulkanowy.utils.firstSchoolDayInSchoolYear
import io.github.wulkanowy.utils.getThemeAttrColor
-import io.github.wulkanowy.utils.schoolYearEnd
-import io.github.wulkanowy.utils.schoolYearStart
-import io.github.wulkanowy.utils.toLocalDateTime
-import io.github.wulkanowy.utils.toTimestamp
+import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
+import io.github.wulkanowy.utils.openMaterialDatePicker
import java.time.LocalDate
import javax.inject.Inject
@@ -53,7 +52,9 @@ class AdditionalLessonsFragment :
override fun initView() {
with(binding.additionalLessonsRecycler) {
layoutManager = LinearLayoutManager(context)
- adapter = additionalLessonsAdapter
+ adapter = additionalLessonsAdapter.apply {
+ onDeleteClickListener = { presenter.onDeleteLessonsSelected(it) }
+ }
addItemDecoration(DividerItemDecoration(context))
}
@@ -61,9 +62,7 @@ class AdditionalLessonsFragment :
additionalLessonsSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
additionalLessonsSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
additionalLessonsSwipe.setProgressBackgroundColorSchemeColor(
- requireContext().getThemeAttrColor(
- R.attr.colorSwipeRefresh
- )
+ requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)
)
additionalLessonsErrorRetry.setOnClickListener { presenter.onRetry() }
additionalLessonsErrorDetails.setOnClickListener { presenter.onDetailsClick() }
@@ -72,6 +71,8 @@ class AdditionalLessonsFragment :
additionalLessonsNavDate.setOnClickListener { presenter.onPickDate() }
additionalLessonsNextButton.setOnClickListener { presenter.onNextDay() }
+ openAddAdditionalLessonButton.setOnClickListener { presenter.onAdditionalLessonAddButtonClicked() }
+
additionalLessonsNavContainer.elevation = requireContext().dpToPx(8f)
}
}
@@ -90,6 +91,10 @@ class AdditionalLessonsFragment :
}
}
+ override fun showSuccessMessage() {
+ getString(R.string.additional_lessons_delete_success)
+ }
+
override fun updateNavigationDay(date: String) {
binding.additionalLessonsNavDate.text = date
}
@@ -131,30 +136,33 @@ class AdditionalLessonsFragment :
binding.additionalLessonsNextButton.visibility = if (show) View.VISIBLE else View.INVISIBLE
}
- override fun showDatePickerDialog(currentDate: LocalDate) {
+ override fun showAddAdditionalLessonDialog() {
+ (activity as? MainActivity)?.showDialogFragment(AdditionalLessonAddDialog.newInstance())
+ }
+
+ override fun showDatePickerDialog(selectedDate: LocalDate) {
val now = LocalDate.now()
- val startOfSchoolYear = now.schoolYearStart.toTimestamp()
- val endOfSchoolYear = now.schoolYearEnd.toTimestamp()
- val constraintsBuilder = CalendarConstraints.Builder().apply {
- setValidator(SchoolDaysValidator(startOfSchoolYear, endOfSchoolYear))
- setStart(startOfSchoolYear)
- setEnd(endOfSchoolYear)
- }
- val datePicker =
- MaterialDatePicker.Builder.datePicker()
- .setCalendarConstraints(constraintsBuilder.build())
- .setSelection(currentDate.toTimestamp())
- .build()
+ openMaterialDatePicker(
+ selected = selectedDate,
+ rangeStart = now.firstSchoolDayInSchoolYear,
+ rangeEnd = now.lastSchoolDayInSchoolYear,
+ onDateSelected = {
+ presenter.onDateSet(it.year, it.monthValue, it.dayOfMonth)
+ }
+ )
+ }
- datePicker.addOnPositiveButtonClickListener {
- val date = it.toLocalDateTime()
- presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth)
- }
-
- if (!parentFragmentManager.isStateSaved) {
- datePicker.show(parentFragmentManager, null)
- }
+ override fun showDeleteLessonDialog(timetableAdditional: TimetableAdditional) {
+ AlertDialog.Builder(requireContext())
+ .setTitle(getString(R.string.additional_lessons_delete_title))
+ .setItems(
+ arrayOf(
+ getString(R.string.additional_lessons_delete_one),
+ getString(R.string.additional_lessons_delete_series)
+ )
+ ) { _, position -> presenter.onDeleteDialogSelectItem(position, timetableAdditional) }
+ .show()
}
override fun onSaveInstanceState(outState: Bundle) {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsPresenter.kt
index 3496e141a..742a8d592 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsPresenter.kt
@@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.timetable.additional
import android.annotation.SuppressLint
import io.github.wulkanowy.data.Status
+import io.github.wulkanowy.data.db.entities.TimetableAdditional
import io.github.wulkanowy.data.repositories.SemesterRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.data.repositories.TimetableRepository
@@ -20,6 +21,7 @@ import io.github.wulkanowy.utils.toFormattedString
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
import timber.log.Timber
import java.time.LocalDate
import javax.inject.Inject
@@ -63,6 +65,10 @@ class AdditionalLessonsPresenter @Inject constructor(
view?.showDatePickerDialog(currentDate)
}
+ fun onAdditionalLessonAddButtonClicked() {
+ view?.showAddAdditionalLessonDialog()
+ }
+
fun onDateSet(year: Int, month: Int, day: Int) {
loadData(LocalDate.of(year, month, day))
reloadView()
@@ -98,6 +104,36 @@ class AdditionalLessonsPresenter @Inject constructor(
}.launch("holidays")
}
+ fun onDeleteLessonsSelected(timetableAdditional: TimetableAdditional) {
+ if (timetableAdditional.repeatId == null) {
+ deleteAdditionalLessons(timetableAdditional, false)
+ } else {
+ view?.showDeleteLessonDialog(timetableAdditional)
+ }
+ }
+
+ fun onDeleteDialogSelectItem(position: Int, timetableAdditional: TimetableAdditional) {
+ deleteAdditionalLessons(timetableAdditional, position == 1)
+ }
+
+ private fun deleteAdditionalLessons(
+ timetableAdditional: TimetableAdditional,
+ deleteSeries: Boolean
+ ) {
+ presenterScope.launch {
+ Timber.i("Additional Lesson delete start")
+ runCatching { timetableRepository.deleteAdditional(timetableAdditional, deleteSeries) }
+ .onSuccess {
+ Timber.i("Additional Lesson delete: Success")
+ view?.showSuccessMessage()
+ }
+ .onFailure {
+ Timber.i("Additional Lesson delete result: An exception occurred")
+ errorHandler.dispatch(it)
+ }
+ }
+ }
+
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) {
currentDate = date
@@ -111,7 +147,7 @@ class AdditionalLessonsPresenter @Inject constructor(
Status.SUCCESS -> {
Timber.i("Loading additional lessons lessons result: Success")
view?.apply {
- updateData(it.data!!.additional.sortedBy { item -> item.date })
+ updateData(it.data!!.additional.sortedBy { item -> item.start })
showEmpty(it.data.additional.isEmpty())
showErrorView(false)
showContent(it.data.additional.isNotEmpty())
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsView.kt
index 97eb2ae7b..76d37b754 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsView.kt
@@ -34,5 +34,11 @@ interface AdditionalLessonsView : BaseView {
fun showNextButton(show: Boolean)
- fun showDatePickerDialog(currentDate: LocalDate)
+ fun showDatePickerDialog(selectedDate: LocalDate)
+
+ fun showAddAdditionalLessonDialog()
+
+ fun showSuccessMessage()
+
+ fun showDeleteLessonDialog(timetableAdditional: TimetableAdditional)
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/add/AdditionalLessonAddDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/add/AdditionalLessonAddDialog.kt
new file mode 100644
index 000000000..f82d64830
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/add/AdditionalLessonAddDialog.kt
@@ -0,0 +1,172 @@
+package io.github.wulkanowy.ui.modules.timetable.additional.add
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.widget.doOnTextChanged
+import com.google.android.material.timepicker.MaterialTimePicker
+import com.google.android.material.timepicker.TimeFormat
+import dagger.hilt.android.AndroidEntryPoint
+import io.github.wulkanowy.R
+import io.github.wulkanowy.databinding.DialogAdditionalAddBinding
+import io.github.wulkanowy.ui.base.BaseDialogFragment
+import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
+import io.github.wulkanowy.utils.openMaterialDatePicker
+import io.github.wulkanowy.utils.toFormattedString
+import java.time.LocalDate
+import java.time.LocalTime
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class AdditionalLessonAddDialog : BaseDialogFragment(),
+ AdditionalLessonAddView {
+
+ @Inject
+ lateinit var presenter: AdditionalLessonAddPresenter
+
+ companion object {
+ fun newInstance() = AdditionalLessonAddDialog()
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setStyle(STYLE_NO_TITLE, 0)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ) = DialogAdditionalAddBinding.inflate(inflater).apply { binding = this }.root
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ presenter.onAttachView(this)
+ }
+
+ override fun initView() {
+ with(binding) {
+ additionalLessonDialogStartEdit.doOnTextChanged { _, _, _, _ ->
+ additionalLessonDialogStart.isErrorEnabled = false
+ additionalLessonDialogStart.error = null
+ }
+ additionalLessonDialogEndEdit.doOnTextChanged { _, _, _, _ ->
+ additionalLessonDialogEnd.isErrorEnabled = false
+ additionalLessonDialogEnd.error = null
+ }
+ additionalLessonDialogDateEdit.doOnTextChanged { _, _, _, _ ->
+ additionalLessonDialogDate.isErrorEnabled = false
+ additionalLessonDialogDate.error = null
+ }
+ additionalLessonDialogContentEdit.doOnTextChanged { _, _, _, _ ->
+ additionalLessonDialogContent.isErrorEnabled = false
+ additionalLessonDialogContent.error = null
+ }
+
+ additionalLessonDialogAdd.setOnClickListener {
+ presenter.onAddAdditionalClicked(
+ start = additionalLessonDialogStartEdit.text?.toString(),
+ end = additionalLessonDialogEndEdit.text?.toString(),
+ date = additionalLessonDialogDateEdit.text?.toString(),
+ content = additionalLessonDialogContentEdit.text?.toString(),
+ isRepeat = additionalLessonDialogRepeat.isChecked
+ )
+ }
+ additionalLessonDialogClose.setOnClickListener { dismiss() }
+ additionalLessonDialogDateEdit.setOnClickListener { presenter.showDatePicker() }
+ additionalLessonDialogStartEdit.setOnClickListener { presenter.showStartTimePicker() }
+ additionalLessonDialogEndEdit.setOnClickListener { presenter.showEndTimePicker() }
+ }
+ }
+
+ override fun showSuccessMessage() {
+ showMessage(getString(R.string.additional_lessons_add_success))
+ }
+
+ override fun setErrorDateRequired() {
+ with(binding.additionalLessonDialogDate) {
+ isErrorEnabled = true
+ error = getString(R.string.error_field_required)
+ }
+ }
+
+ override fun setErrorStartRequired() {
+ with(binding.additionalLessonDialogStart) {
+ isErrorEnabled = true
+ error = getString(R.string.error_field_required)
+ }
+ }
+
+ override fun setErrorEndRequired() {
+ with(binding.additionalLessonDialogEnd) {
+ isErrorEnabled = true
+ error = getString(R.string.error_field_required)
+ }
+ }
+
+ override fun setErrorContentRequired() {
+ with(binding.additionalLessonDialogContent) {
+ isErrorEnabled = true
+ error = getString(R.string.error_field_required)
+ }
+ }
+
+ override fun setErrorIncorrectEndTime() {
+ with(binding.additionalLessonDialogEnd) {
+ isErrorEnabled = true
+ error = getString(R.string.additional_lessons_end_time_error)
+ }
+ }
+
+ override fun closeDialog() {
+ dismiss()
+ }
+
+ override fun showDatePickerDialog(selectedDate: LocalDate) {
+ openMaterialDatePicker(
+ selected = selectedDate,
+ rangeStart = LocalDate.now(),
+ rangeEnd = LocalDate.now().lastSchoolDayInSchoolYear,
+ onDateSelected = {
+ presenter.onDateSelected(it)
+ binding.additionalLessonDialogDateEdit.setText(it.toFormattedString())
+ }
+ )
+ }
+
+ override fun showStartTimePickerDialog(selectedTime: LocalTime) {
+ showTimePickerDialog(selectedTime) {
+ presenter.onStartTimeSelected(it)
+ binding.additionalLessonDialogStartEdit.setText(it.toString())
+ }
+ }
+
+ override fun showEndTimePickerDialog(selectedTime: LocalTime) {
+ showTimePickerDialog(selectedTime) {
+ presenter.onEndTimeSelected(it)
+ binding.additionalLessonDialogEndEdit.setText(it.toString())
+ }
+ }
+
+ private fun showTimePickerDialog(defaultTime: LocalTime, onTimeSelected: (LocalTime) -> Unit) {
+ val timePicker = MaterialTimePicker.Builder()
+ .setTimeFormat(TimeFormat.CLOCK_24H)
+ .setHour(defaultTime.hour)
+ .setMinute(defaultTime.minute)
+ .build()
+
+ timePicker.addOnPositiveButtonClickListener {
+ onTimeSelected(LocalTime.of(timePicker.hour, timePicker.minute))
+ }
+
+ if (!parentFragmentManager.isStateSaved) {
+ timePicker.show(parentFragmentManager, null)
+ }
+ }
+
+ override fun onDestroyView() {
+ presenter.onDetachView()
+ super.onDestroyView()
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/add/AdditionalLessonAddPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/add/AdditionalLessonAddPresenter.kt
new file mode 100644
index 000000000..c207165d3
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/add/AdditionalLessonAddPresenter.kt
@@ -0,0 +1,164 @@
+package io.github.wulkanowy.ui.modules.timetable.additional.add
+
+import io.github.wulkanowy.data.db.entities.TimetableAdditional
+import io.github.wulkanowy.data.repositories.SemesterRepository
+import io.github.wulkanowy.data.repositories.StudentRepository
+import io.github.wulkanowy.data.repositories.TimetableRepository
+import io.github.wulkanowy.ui.base.BasePresenter
+import io.github.wulkanowy.ui.base.ErrorHandler
+import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
+import io.github.wulkanowy.utils.toLocalDate
+import kotlinx.coroutines.launch
+import timber.log.Timber
+import java.time.*
+import java.time.temporal.ChronoUnit
+import java.util.*
+import javax.inject.Inject
+
+class AdditionalLessonAddPresenter @Inject constructor(
+ errorHandler: ErrorHandler,
+ studentRepository: StudentRepository,
+ private val timetableRepository: TimetableRepository,
+ private val semesterRepository: SemesterRepository
+) : BasePresenter(errorHandler, studentRepository) {
+
+ private var selectedStartTime = LocalTime.of(15, 0)
+
+ private var selectedEndTime = LocalTime.of(15, 45)
+
+ private var selectedDate = LocalDate.now()
+
+ override fun onAttachView(view: AdditionalLessonAddView) {
+ super.onAttachView(view)
+ view.initView()
+ Timber.i("AdditionalLesson details view was initialized")
+ }
+
+ fun showDatePicker() {
+ view?.showDatePickerDialog(selectedDate)
+ }
+
+ fun showStartTimePicker() {
+ view?.showStartTimePickerDialog(selectedStartTime)
+ }
+
+ fun showEndTimePicker() {
+ view?.showEndTimePickerDialog(selectedEndTime)
+ }
+
+ fun onStartTimeSelected(time: LocalTime) {
+ selectedStartTime = time
+ }
+
+ fun onEndTimeSelected(time: LocalTime) {
+ selectedEndTime = time
+ }
+
+ fun onDateSelected(date: LocalDate) {
+ selectedDate = date
+ }
+
+ fun onAddAdditionalClicked(
+ start: String?,
+ end: String?,
+ date: String?,
+ content: String?,
+ isRepeat: Boolean
+ ) {
+ if (isUserInputValid(start, end, date, content)) {
+ addAdditionalLesson(
+ start = LocalTime.parse(start!!),
+ end = LocalTime.parse(end),
+ date = date!!.toLocalDate(),
+ subject = content!!,
+ isRepeat = isRepeat
+ )
+ }
+ }
+
+ private fun isUserInputValid(
+ start: String?,
+ end: String?,
+ date: String?,
+ content: String?
+ ): Boolean {
+ var isValid = true
+
+ if (start.isNullOrBlank()) {
+ view?.setErrorStartRequired()
+ isValid = false
+ }
+
+ if (end.isNullOrBlank()) {
+ view?.setErrorEndRequired()
+ isValid = false
+ }
+
+ if (date.isNullOrBlank()) {
+ view?.setErrorDateRequired()
+ isValid = false
+ }
+
+ if (content.isNullOrBlank()) {
+ view?.setErrorContentRequired()
+ isValid = false
+ }
+
+ if (selectedStartTime >= selectedEndTime) {
+ view?.setErrorIncorrectEndTime()
+ isValid = false
+ }
+
+ return isValid
+ }
+
+ private fun addAdditionalLesson(
+ start: LocalTime,
+ end: LocalTime,
+ date: LocalDate,
+ subject: String,
+ isRepeat: Boolean
+ ) {
+ presenterScope.launch {
+ val semester = runCatching {
+ val student = studentRepository.getCurrentStudent()
+ semesterRepository.getCurrentSemester(student)
+ }
+ .onFailure(errorHandler::dispatch)
+ .getOrNull() ?: return@launch
+
+ val weeks = if (isRepeat) {
+ ChronoUnit.WEEKS.between(date, date.lastSchoolDayInSchoolYear)
+ } else 0
+ val uniqueRepeatId = UUID.randomUUID().takeIf { isRepeat }
+
+ val lessonsToAdd = (0..weeks).map {
+ TimetableAdditional(
+ studentId = semester.studentId,
+ diaryId = semester.diaryId,
+ start = ZonedDateTime.of(date, start, ZoneId.systemDefault()).toInstant(),
+ end = ZonedDateTime.of(date, end, ZoneId.systemDefault()).toInstant(),
+ date = date.plusWeeks(it),
+ subject = subject
+ ).apply {
+ isAddedByUser = true
+ repeatId = uniqueRepeatId
+ }
+ }
+
+ Timber.i("AdditionalLesson insert start")
+ runCatching { timetableRepository.saveAdditionalList(lessonsToAdd) }
+ .onSuccess {
+ Timber.i("AdditionalLesson insert: Success")
+ view?.run {
+ showSuccessMessage()
+ closeDialog()
+ }
+ }
+ .onFailure {
+ Timber.i("AdditionalLesson insert result: An exception occurred")
+ errorHandler.dispatch(it)
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/add/AdditionalLessonAddView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/add/AdditionalLessonAddView.kt
new file mode 100644
index 000000000..0df53815b
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/add/AdditionalLessonAddView.kt
@@ -0,0 +1,30 @@
+package io.github.wulkanowy.ui.modules.timetable.additional.add
+
+import io.github.wulkanowy.ui.base.BaseView
+import java.time.LocalDate
+import java.time.LocalTime
+
+interface AdditionalLessonAddView : BaseView {
+
+ fun initView()
+
+ fun closeDialog()
+
+ fun showDatePickerDialog(selectedDate: LocalDate)
+
+ fun showStartTimePickerDialog(selectedTime: LocalTime)
+
+ fun showEndTimePickerDialog(selectedTime: LocalTime)
+
+ fun showSuccessMessage()
+
+ fun setErrorDateRequired()
+
+ fun setErrorStartRequired()
+
+ fun setErrorEndRequired()
+
+ fun setErrorContentRequired()
+
+ fun setErrorIncorrectEndTime()
+}
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 a6b126447..34a69e6ab 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
@@ -6,8 +6,6 @@ import android.view.View.GONE
import android.view.View.INVISIBLE
import android.view.View.VISIBLE
import androidx.recyclerview.widget.LinearLayoutManager
-import com.google.android.material.datepicker.CalendarConstraints
-import com.google.android.material.datepicker.MaterialDatePicker
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.CompletedLesson
@@ -16,14 +14,12 @@ 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.widgets.DividerItemDecoration
-import io.github.wulkanowy.utils.SchoolDaysValidator
import io.github.wulkanowy.utils.dpToPx
+import io.github.wulkanowy.utils.firstSchoolDayInSchoolYear
import io.github.wulkanowy.utils.getCompatDrawable
import io.github.wulkanowy.utils.getThemeAttrColor
-import io.github.wulkanowy.utils.schoolYearEnd
-import io.github.wulkanowy.utils.schoolYearStart
-import io.github.wulkanowy.utils.toLocalDateTime
-import io.github.wulkanowy.utils.toTimestamp
+import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
+import io.github.wulkanowy.utils.openMaterialDatePicker
import java.time.LocalDate
import javax.inject.Inject
@@ -68,9 +64,7 @@ class CompletedLessonsFragment :
completedLessonsSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
completedLessonsSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
completedLessonsSwipe.setProgressBackgroundColorSchemeColor(
- requireContext().getThemeAttrColor(
- R.attr.colorSwipeRefresh
- )
+ requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)
)
completedLessonErrorRetry.setOnClickListener { presenter.onRetry() }
completedLessonErrorDetails.setOnClickListener { presenter.onDetailsClick() }
@@ -152,30 +146,17 @@ class CompletedLessonsFragment :
)
}
- override fun showDatePickerDialog(currentDate: LocalDate) {
+ override fun showDatePickerDialog(selectedDate: LocalDate) {
val now = LocalDate.now()
- val startOfSchoolYear = now.schoolYearStart.toTimestamp()
- val endOfSchoolYear = now.schoolYearEnd.toTimestamp()
- val constraintsBuilder = CalendarConstraints.Builder().apply {
- setValidator(SchoolDaysValidator(startOfSchoolYear, endOfSchoolYear))
- setStart(startOfSchoolYear)
- setEnd(endOfSchoolYear)
- }
- val datePicker =
- MaterialDatePicker.Builder.datePicker()
- .setCalendarConstraints(constraintsBuilder.build())
- .setSelection(currentDate.toTimestamp())
- .build()
-
- datePicker.addOnPositiveButtonClickListener {
- val date = it.toLocalDateTime()
- presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth)
- }
-
- if (!parentFragmentManager.isStateSaved) {
- datePicker.show(parentFragmentManager, null)
- }
+ openMaterialDatePicker(
+ selected = selectedDate,
+ rangeStart = now.firstSchoolDayInSchoolYear,
+ rangeEnd = now.lastSchoolDayInSchoolYear,
+ onDateSelected = {
+ presenter.onDateSet(it.year, it.monthValue, it.dayOfMonth)
+ }
+ )
}
override fun onSaveInstanceState(outState: Bundle) {
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 7a98874e0..715ce01fc 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
@@ -38,5 +38,5 @@ interface CompletedLessonsView : BaseView {
fun showCompletedLessonDialog(completedLesson: CompletedLesson)
- fun showDatePickerDialog(currentDate: LocalDate)
+ fun showDatePickerDialog(selectedDate: LocalDate)
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetFactory.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetFactory.kt
index f3d760f09..18eefc5da 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetFactory.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetFactory.kt
@@ -22,6 +22,7 @@ import io.github.wulkanowy.data.repositories.TimetableRepository
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getCurrentThemeWidgetKey
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getDateWidgetKey
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getStudentWidgetKey
+import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getTodayLastLessonEndDateTimeWidgetKey
import io.github.wulkanowy.utils.getCompatColor
import io.github.wulkanowy.utils.toFirstResult
import io.github.wulkanowy.utils.toFormattedString
@@ -70,6 +71,15 @@ class TimetableWidgetFactory(
updateTheme(appWidgetId)
lessons = getLessons(date, studentId)
+
+ val todayLastLessonEndTimestamp = lessons.maxOfOrNull { it.end }
+ if (date == LocalDate.now() && todayLastLessonEndTimestamp != null) {
+ sharedPref.putLong(
+ key = getTodayLastLessonEndDateTimeWidgetKey(appWidgetId),
+ value = todayLastLessonEndTimestamp.epochSecond,
+ sync = true
+ )
+ }
}
}
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 0f0691160..07e717eaf 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
@@ -3,10 +3,8 @@ package io.github.wulkanowy.ui.modules.timetablewidget
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
-import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_DELETED
-import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE
-import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID
-import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS
+import android.appwidget.AppWidgetManager.*
+import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
@@ -21,30 +19,21 @@ import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
import io.github.wulkanowy.data.repositories.StudentRepository
-import io.github.wulkanowy.services.HiltBroadcastReceiver
import io.github.wulkanowy.services.widgets.TimetableWidgetService
import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.ui.modules.splash.SplashActivity
-import io.github.wulkanowy.utils.AnalyticsHelper
-import io.github.wulkanowy.utils.PendingIntentCompat
-import io.github.wulkanowy.utils.capitalise
-import io.github.wulkanowy.utils.createNameInitialsDrawable
-import io.github.wulkanowy.utils.getCompatColor
-import io.github.wulkanowy.utils.nextOrSameSchoolDay
-import io.github.wulkanowy.utils.nextSchoolDay
-import io.github.wulkanowy.utils.nickOrName
-import io.github.wulkanowy.utils.previousSchoolDay
-import io.github.wulkanowy.utils.toFormattedString
+import io.github.wulkanowy.utils.*
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import timber.log.Timber
import java.time.LocalDate
-import java.time.LocalDate.now
+import java.time.LocalDateTime
+import java.time.ZoneOffset
import javax.inject.Inject
@AndroidEntryPoint
-class TimetableWidgetProvider : HiltBroadcastReceiver() {
+class TimetableWidgetProvider : BroadcastReceiver() {
@Inject
lateinit var appWidgetManager: AppWidgetManager
@@ -76,6 +65,9 @@ class TimetableWidgetProvider : HiltBroadcastReceiver() {
fun getDateWidgetKey(appWidgetId: Int) = "timetable_widget_date_$appWidgetId"
+ fun getTodayLastLessonEndDateTimeWidgetKey(appWidgetId: Int) =
+ "timetable_widget_today_last_lesson_end_date_time_$appWidgetId"
+
fun getStudentWidgetKey(appWidgetId: Int) = "timetable_widget_student_$appWidgetId"
fun getThemeWidgetKey(appWidgetId: Int) = "timetable_widget_theme_$appWidgetId"
@@ -86,7 +78,6 @@ class TimetableWidgetProvider : HiltBroadcastReceiver() {
@OptIn(DelicateCoroutinesApi::class)
override fun onReceive(context: Context, intent: Intent) {
- super.onReceive(context, intent)
GlobalScope.launch {
when (intent.action) {
ACTION_APPWIDGET_UPDATE -> onUpdate(context, intent)
@@ -100,7 +91,8 @@ class TimetableWidgetProvider : HiltBroadcastReceiver() {
intent.getIntArrayExtra(EXTRA_APPWIDGET_IDS)?.forEach { appWidgetId ->
val student =
getStudent(sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0), appWidgetId)
- updateWidget(context, appWidgetId, now().nextOrSameSchoolDay, student)
+
+ updateWidget(context, appWidgetId, getWidgetDateToLoad(appWidgetId), student)
}
} else {
val buttonType = intent.getStringExtra(EXTRA_BUTTON_TYPE)
@@ -112,15 +104,17 @@ class TimetableWidgetProvider : HiltBroadcastReceiver() {
val savedDate =
LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(toggledWidgetId), 0))
val date = when (buttonType) {
- BUTTON_RESET -> now().nextOrSameSchoolDay
+ BUTTON_RESET -> getWidgetDateToLoad(toggledWidgetId)
BUTTON_NEXT -> savedDate.nextSchoolDay
BUTTON_PREV -> savedDate.previousSchoolDay
- else -> now().nextOrSameSchoolDay
+ else -> getWidgetDateToLoad(toggledWidgetId)
+ }
+ if (!buttonType.isNullOrBlank()) {
+ analytics.logEvent(
+ "changed_timetable_widget_day",
+ "button" to buttonType
+ )
}
- if (!buttonType.isNullOrBlank()) analytics.logEvent(
- "changed_timetable_widget_day",
- "button" to buttonType
- )
updateWidget(context, toggledWidgetId, date, student)
}
}
@@ -278,4 +272,21 @@ class TimetableWidgetProvider : HiltBroadcastReceiver() {
avatarDrawable.draw(canvas)
return avatarBitmap
}
+
+ private fun getWidgetDateToLoad(appWidgetId: Int): LocalDate {
+ val lastLessonEndTimestamp =
+ sharedPref.getLong(getTodayLastLessonEndDateTimeWidgetKey(appWidgetId), 0)
+ val lastLessonEndDateTime =
+ LocalDateTime.ofEpochSecond(lastLessonEndTimestamp, 0, ZoneOffset.UTC)
+
+ val todayDate = LocalDate.now()
+ val isLastLessonEndDateNow = lastLessonEndDateTime.toLocalDate() == todayDate
+ val isLastLessonEndDateAfterNowTime = LocalDateTime.now() > lastLessonEndDateTime
+
+ return if (isLastLessonEndDateNow && isLastLessonEndDateAfterNowTime) {
+ todayDate.nextSchoolDay
+ } else {
+ todayDate.nextOrSameSchoolDay
+ }
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt
new file mode 100644
index 000000000..43cecd400
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt
@@ -0,0 +1,74 @@
+package io.github.wulkanowy.utils
+
+import android.content.res.Resources
+import io.github.wulkanowy.R
+import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
+import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
+import io.github.wulkanowy.sdk.scrapper.exception.ScrapperException
+import io.github.wulkanowy.sdk.scrapper.exception.ServiceUnavailableException
+import io.github.wulkanowy.sdk.scrapper.exception.VulcanException
+import io.github.wulkanowy.sdk.scrapper.login.NotLoggedInException
+import io.github.wulkanowy.sdk.scrapper.login.PasswordChangeRequiredException
+import okhttp3.internal.http2.StreamResetException
+import java.io.InterruptedIOException
+import java.net.ConnectException
+import java.net.SocketException
+import java.net.SocketTimeoutException
+import java.net.UnknownHostException
+import java.security.cert.CertificateExpiredException
+import java.security.cert.CertificateNotYetValidException
+import javax.net.ssl.SSLHandshakeException
+
+fun Resources.getErrorString(error: Throwable): String = when (error) {
+ is UnknownHostException -> R.string.error_no_internet
+ is SocketException,
+ is SocketTimeoutException,
+ is InterruptedIOException,
+ is ConnectException,
+ is StreamResetException -> R.string.error_timeout
+ is NotLoggedInException -> R.string.error_login_failed
+ is PasswordChangeRequiredException -> R.string.error_password_change_required
+ is ServiceUnavailableException -> R.string.error_service_unavailable
+ is FeatureDisabledException -> R.string.error_feature_disabled
+ is FeatureNotAvailableException -> R.string.error_feature_not_available
+ is VulcanException -> R.string.error_unknown_uonet
+ is ScrapperException -> R.string.error_unknown_app
+ is SSLHandshakeException -> when {
+ error.isCausedByCertificateNotValidNow() -> R.string.error_invalid_device_datetime
+ else -> R.string.error_timeout
+ }
+ else -> R.string.error_unknown
+}.let { getString(it) }
+
+fun Throwable.isShouldBeReported(): Boolean = when (this) {
+ is UnknownHostException,
+ is SocketException,
+ is SocketTimeoutException,
+ is InterruptedIOException,
+ is ConnectException,
+ is StreamResetException,
+ is ServiceUnavailableException,
+ is FeatureDisabledException,
+ is FeatureNotAvailableException -> false
+ is SSLHandshakeException -> when {
+ isCausedByCertificateNotValidNow() -> false
+ else -> true
+ }
+ else -> true
+}
+
+private fun Throwable?.isCausedByCertificateNotValidNow(): Boolean {
+ var exception = this
+ do {
+ if (exception.isCertificateNotValidNow()) return true
+
+ exception = exception?.cause
+ } while (exception != null)
+ return false
+}
+
+private fun Throwable?.isCertificateNotValidNow(): Boolean {
+ val isNotYetValid = this is CertificateNotYetValidException
+ val isExpired = this is CertificateExpiredException
+ return isNotYetValid || isExpired
+}
diff --git a/app/src/main/java/io/github/wulkanowy/utils/MaterialDatePickerUtils.kt b/app/src/main/java/io/github/wulkanowy/utils/MaterialDatePickerUtils.kt
new file mode 100644
index 000000000..09ccda899
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/utils/MaterialDatePickerUtils.kt
@@ -0,0 +1,50 @@
+package io.github.wulkanowy.utils
+
+import androidx.fragment.app.Fragment
+import com.google.android.material.datepicker.CalendarConstraints
+import com.google.android.material.datepicker.MaterialDatePicker
+import kotlinx.parcelize.Parcelize
+import java.time.LocalDate
+import java.time.temporal.ChronoUnit
+
+fun Fragment.openMaterialDatePicker(
+ selected: LocalDate,
+ rangeStart: LocalDate,
+ rangeEnd: LocalDate,
+ onDateSelected: (LocalDate) -> Unit,
+) {
+ val constraintsBuilder = CalendarConstraints.Builder().apply {
+ setValidator(CalendarDayRangeValidator(rangeStart, rangeEnd))
+ setStart(rangeStart.toTimestamp())
+ setEnd(rangeEnd.toTimestamp())
+ }
+
+ val datePicker = MaterialDatePicker.Builder.datePicker()
+ .setCalendarConstraints(constraintsBuilder.build())
+ .setSelection(selected.toTimestamp())
+ .build()
+
+ datePicker.addOnPositiveButtonClickListener {
+ val date = it.toLocalDateTime().toLocalDate()
+ onDateSelected(date)
+ }
+
+ if (!parentFragmentManager.isStateSaved) {
+ datePicker.show(parentFragmentManager, null)
+ }
+}
+
+@Parcelize
+private class CalendarDayRangeValidator(
+ val start: LocalDate,
+ val end: LocalDate,
+) : CalendarConstraints.DateValidator {
+
+ override fun isValid(dateLong: Long): Boolean {
+ val date = dateLong.toLocalDateTime().toLocalDate()
+ val daysUntilEnd = date.until(end, ChronoUnit.DAYS)
+ val daysUntilStart = date.until(start, ChronoUnit.DAYS)
+
+ return daysUntilStart <= 0 && daysUntilEnd >= 0
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/utils/RefreshUtils.kt b/app/src/main/java/io/github/wulkanowy/utils/RefreshUtils.kt
index 6bf97bae7..c69fec65c 100644
--- a/app/src/main/java/io/github/wulkanowy/utils/RefreshUtils.kt
+++ b/app/src/main/java/io/github/wulkanowy/utils/RefreshUtils.kt
@@ -8,8 +8,9 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.enums.MessageFolder
import timber.log.Timber
+import java.time.Duration.ofMinutes
+import java.time.Instant
import java.time.LocalDate
-import java.time.LocalDateTime
import javax.inject.Inject
fun getRefreshKey(name: String, semester: Semester, start: LocalDate, end: LocalDate): String {
@@ -34,10 +35,10 @@ class AutoRefreshHelper @Inject constructor(
) {
fun shouldBeRefreshed(key: String): Boolean {
- val timestamp = sharedPref.getLong(key, 0).toLocalDateTime()
+ val timestamp = sharedPref.getLong(key, 0).let(Instant::ofEpochMilli)
val servicesInterval = sharedPref.getString(context.getString(R.string.pref_key_services_interval), context.getString(R.string.pref_default_services_interval)).toLong()
- val shouldBeRefreshed = timestamp < LocalDateTime.now().minusMinutes(servicesInterval)
+ val shouldBeRefreshed = timestamp < Instant.now().minus(ofMinutes(servicesInterval))
Timber.d("Check if $key need to be refreshed: $shouldBeRefreshed (last refresh: $timestamp, interval: $servicesInterval min)")
@@ -45,6 +46,6 @@ class AutoRefreshHelper @Inject constructor(
}
fun updateLastRefreshTimestamp(key: String) {
- sharedPref.putLong(key, LocalDateTime.now().toTimestamp())
+ sharedPref.putLong(key, Instant.now().toEpochMilli())
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/utils/ResourcesExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/ResourcesExtension.kt
deleted file mode 100644
index da5fd3dbb..000000000
--- a/app/src/main/java/io/github/wulkanowy/utils/ResourcesExtension.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package io.github.wulkanowy.utils
-
-import android.content.res.Resources
-import io.github.wulkanowy.R
-import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
-import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
-import io.github.wulkanowy.sdk.scrapper.exception.ScrapperException
-import io.github.wulkanowy.sdk.scrapper.exception.ServiceUnavailableException
-import io.github.wulkanowy.sdk.scrapper.exception.VulcanException
-import io.github.wulkanowy.sdk.scrapper.login.NotLoggedInException
-import io.github.wulkanowy.sdk.scrapper.login.PasswordChangeRequiredException
-import okhttp3.internal.http2.StreamResetException
-import java.io.InterruptedIOException
-import java.net.ConnectException
-import java.net.SocketTimeoutException
-import java.net.UnknownHostException
-
-fun Resources.getString(error: Throwable) = when (error) {
- is UnknownHostException -> getString(R.string.error_no_internet)
- is SocketTimeoutException, is InterruptedIOException, is ConnectException, is StreamResetException -> getString(R.string.error_timeout)
- is NotLoggedInException -> getString(R.string.error_login_failed)
- is PasswordChangeRequiredException -> getString(R.string.error_password_change_required)
- is ServiceUnavailableException -> getString(R.string.error_service_unavailable)
- is FeatureDisabledException -> getString(R.string.error_feature_disabled)
- is FeatureNotAvailableException -> getString(R.string.error_feature_not_available)
- is VulcanException -> getString(R.string.error_unknown_uonet)
- is ScrapperException -> getString(R.string.error_unknown_app)
- else -> getString(R.string.error_unknown)
-}
diff --git a/app/src/main/java/io/github/wulkanowy/utils/SchooldaysValidator.kt b/app/src/main/java/io/github/wulkanowy/utils/SchooldaysValidator.kt
deleted file mode 100644
index b6dd528f5..000000000
--- a/app/src/main/java/io/github/wulkanowy/utils/SchooldaysValidator.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package io.github.wulkanowy.utils
-
-import com.google.android.material.datepicker.CalendarConstraints
-import kotlinx.parcelize.Parcelize
-import java.time.temporal.ChronoUnit
-
-@Parcelize
-class SchoolDaysValidator(val start: Long, val end: Long) : CalendarConstraints.DateValidator {
-
- override fun isValid(dateLong: Long): Boolean {
- val date = dateLong.toLocalDateTime()
-
- return date.until(end.toLocalDateTime(), ChronoUnit.DAYS) >= 0 &&
- date.until(start.toLocalDateTime(), ChronoUnit.DAYS) <= 0
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/utils/TimeExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/TimeExtension.kt
index 94b6a2191..e7a50d0c3 100644
--- a/app/src/main/java/io/github/wulkanowy/utils/TimeExtension.kt
+++ b/app/src/main/java/io/github/wulkanowy/utils/TimeExtension.kt
@@ -1,41 +1,34 @@
package io.github.wulkanowy.utils
import java.text.SimpleDateFormat
-import java.time.DayOfWeek.FRIDAY
-import java.time.DayOfWeek.MONDAY
-import java.time.DayOfWeek.SATURDAY
-import java.time.DayOfWeek.SUNDAY
-import java.time.Instant
-import java.time.LocalDate
-import java.time.LocalDateTime
-import java.time.LocalTime
-import java.time.Month
-import java.time.ZoneId
-import java.time.ZoneOffset
+import java.time.*
+import java.time.DayOfWeek.*
import java.time.format.DateTimeFormatter
-import java.time.temporal.TemporalAdjusters.firstInMonth
-import java.time.temporal.TemporalAdjusters.next
-import java.time.temporal.TemporalAdjusters.previous
-import java.util.Locale
+import java.time.temporal.TemporalAdjusters.*
+import java.util.*
private const val DEFAULT_DATE_PATTERN = "dd.MM.yyyy"
+fun LocalDate.toTimestamp(): Long = atStartOfDay()
+ .toInstant(ZoneOffset.UTC)
+ .toEpochMilli()
+
+fun Long.toLocalDateTime(): LocalDateTime = LocalDateTime.ofInstant(
+ Instant.ofEpochMilli(this), ZoneOffset.UTC
+)
+
+fun Instant.toLocalDate(): LocalDate = atZone(ZoneOffset.UTC).toLocalDate()
+
fun String.toLocalDate(format: String = DEFAULT_DATE_PATTERN): LocalDate =
LocalDate.parse(this, DateTimeFormatter.ofPattern(format))
-fun LocalDateTime.toTimestamp() =
- atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC).toInstant().toEpochMilli()
-
-fun Long.toLocalDateTime(): LocalDateTime =
- LocalDateTime.ofInstant(Instant.ofEpochMilli(this), ZoneId.systemDefault())
-
-fun LocalDate.toTimestamp() = atTime(LocalTime.now()).toTimestamp()
-
fun LocalDate.toFormattedString(pattern: String = DEFAULT_DATE_PATTERN): String =
format(DateTimeFormatter.ofPattern(pattern))
-fun LocalDateTime.toFormattedString(pattern: String = DEFAULT_DATE_PATTERN): String =
- format(DateTimeFormatter.ofPattern(pattern))
+fun Instant.toFormattedString(
+ pattern: String = DEFAULT_DATE_PATTERN,
+ tz: ZoneId = ZoneId.systemDefault()
+): String = atZone(tz).format(DateTimeFormatter.ofPattern(pattern))
fun Month.getFormattedName(): String {
val formatter = SimpleDateFormat("LLLL", Locale.getDefault())
@@ -85,35 +78,31 @@ inline val LocalDate.previousOrSameSchoolDay: LocalDate
inline val LocalDate.weekDayName: String
get() = format(DateTimeFormatter.ofPattern("EEEE", Locale.getDefault()))
-inline val LocalDate.monday: LocalDate
- get() = with(MONDAY)
+inline val LocalDate.monday: LocalDate get() = with(MONDAY)
-inline val LocalDate.sunday: LocalDate
- get() = with(SUNDAY)
+inline val LocalDate.sunday: LocalDate get() = with(SUNDAY)
/**
* [Dz.U. 2016 poz. 1335](http://prawo.sejm.gov.pl/isap.nsf/DocDetails.xsp?id=WDU20160001335)
*/
-inline val LocalDate.isHolidays: Boolean
- get() = isBefore(firstSchoolDay) && isAfter(lastSchoolDay)
+val LocalDate.isHolidays: Boolean
+ get() = isBefore(firstSchoolDayInCalendarYear) && isAfter(lastSchoolDayInCalendarYear)
-inline val LocalDate.firstSchoolDay: LocalDate
- get() = LocalDate.of(year, 9, 1).run {
- when (dayOfWeek) {
- FRIDAY, SATURDAY, SUNDAY -> with(firstInMonth(MONDAY))
- else -> this
- }
+val LocalDate.firstSchoolDayInSchoolYear: LocalDate
+ get() = withYear(if (this.monthValue <= 6) this.year - 1 else this.year).firstSchoolDayInCalendarYear
+
+val LocalDate.lastSchoolDayInSchoolYear: LocalDate
+ get() = withYear(if (this.monthValue > 6) this.year + 1 else this.year).lastSchoolDayInCalendarYear
+
+fun LocalDate.getLastSchoolDayIfHoliday(schoolYear: Int): LocalDate {
+ val date = LocalDate.of(schoolYear.getSchoolYearByMonth(monthValue), monthValue, dayOfMonth)
+
+ if (date.isHolidays) {
+ return date.lastSchoolDayInCalendarYear
}
-inline val LocalDate.lastSchoolDay: LocalDate
- get() = LocalDate.of(year, 6, 20)
- .with(next(FRIDAY))
-
-inline val LocalDate.schoolYearStart: LocalDate
- get() = withYear(if (this.monthValue <= 6) this.year - 1 else this.year).firstSchoolDay
-
-inline val LocalDate.schoolYearEnd: LocalDate
- get() = withYear(if (this.monthValue > 6) this.year + 1 else this.year).lastSchoolDay
+ return date
+}
private fun Int.getSchoolYearByMonth(monthValue: Int): Int {
return when (monthValue) {
@@ -122,12 +111,15 @@ private fun Int.getSchoolYearByMonth(monthValue: Int): Int {
}
}
-fun LocalDate.getLastSchoolDayIfHoliday(schoolYear: Int): LocalDate {
- val date = LocalDate.of(schoolYear.getSchoolYearByMonth(monthValue), monthValue, dayOfMonth)
-
- if (date.isHolidays) {
- return date.lastSchoolDay
+private inline val LocalDate.firstSchoolDayInCalendarYear: LocalDate
+ get() = LocalDate.of(year, 9, 1).run {
+ when (dayOfWeek) {
+ FRIDAY, SATURDAY, SUNDAY -> with(firstInMonth(MONDAY))
+ else -> this
+ }
}
- return date
-}
+private inline val LocalDate.lastSchoolDayInCalendarYear: LocalDate
+ get() = LocalDate.of(year, 6, 20)
+ .with(next(FRIDAY))
+
diff --git a/app/src/main/java/io/github/wulkanowy/utils/TimetableExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/TimetableExtension.kt
index 9d15216c6..3e94463b9 100644
--- a/app/src/main/java/io/github/wulkanowy/utils/TimetableExtension.kt
+++ b/app/src/main/java/io/github/wulkanowy/utils/TimetableExtension.kt
@@ -3,10 +3,10 @@ package io.github.wulkanowy.utils
import io.github.wulkanowy.data.db.entities.Timetable
import java.time.Duration
import java.time.Duration.between
-import java.time.LocalDateTime
-import java.time.LocalDateTime.now
+import java.time.Instant
+import java.time.Instant.now
-fun Timetable.isShowTimeUntil(previousLessonEnd: LocalDateTime?) = when {
+fun Timetable.isShowTimeUntil(previousLessonEnd: Instant?) = when {
!isStudentPlan -> false
canceled -> false
now().isAfter(start) -> false
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 f40e3fc33..6e768ac3a 100644
--- a/app/src/main/play/release-notes/pl-PL/default.txt
+++ b/app/src/main/play/release-notes/pl-PL/default.txt
@@ -1,6 +1,8 @@
-Wersja 1.4.4
+Wersja 1.5.0
-- naprawiliśmy logowanie do Gdańskiej Platformy Edukacyjnej
-- naprawiliśmy sortowanie ocen oraz ogłoszeń
+- dodaliśmy możliwość dodawania własnych lekcji dodatkowych
+- dodaliśmy wsparcie dla różnych stref czasowych
+- dodaliśmy eksperymentalne wsparcie dla przedszkola
+- wprowadziliśmy też wiele innych mniejszych poprawek, poprawiających komfort używania aplikacji
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
diff --git a/app/src/main/res/drawable/ic_all_clock.xml b/app/src/main/res/drawable/ic_all_clock.xml
new file mode 100644
index 000000000..4b98ed233
--- /dev/null
+++ b/app/src/main/res/drawable/ic_all_clock.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_calendat_all.xml b/app/src/main/res/drawable/ic_calendat_all.xml
new file mode 100644
index 000000000..5908035ed
--- /dev/null
+++ b/app/src/main/res/drawable/ic_calendat_all.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
index 1d5b5280d..912792638 100644
--- a/app/src/main/res/layout/activity_login.xml
+++ b/app/src/main/res/layout/activity_login.xml
@@ -1,5 +1,5 @@
@@ -10,8 +10,11 @@
android:layout_height="wrap_content"
android:background="@android:color/transparent" />
-
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ tools:layout="@layout/fragment_login_form" />
+
diff --git a/app/src/main/res/layout/dialog_additional_add.xml b/app/src/main/res/layout/dialog_additional_add.xml
new file mode 100644
index 000000000..884018e55
--- /dev/null
+++ b/app/src/main/res/layout/dialog_additional_add.xml
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/dialog_error.xml b/app/src/main/res/layout/dialog_error.xml
index b52c99aca..98b9c8b16 100644
--- a/app/src/main/res/layout/dialog_error.xml
+++ b/app/src/main/res/layout/dialog_error.xml
@@ -7,15 +7,6 @@
android:orientation="vertical"
tools:context=".ui.base.ErrorDialog">
-
-
-
+ android:layout_height="200dp"
+ android:overScrollMode="ifContentScrolls"
+ android:paddingHorizontal="24dp"
+ app:layout_constraintTop_toTopOf="parent">
-
+ android:layout_height="wrap_content">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/app/src/main/res/layout/dialog_grade.xml b/app/src/main/res/layout/dialog_grade.xml
index 9ed2bc068..9c52c1d0b 100644
--- a/app/src/main/res/layout/dialog_grade.xml
+++ b/app/src/main/res/layout/dialog_grade.xml
@@ -204,7 +204,6 @@
android:insetBottom="0dp"
android:minWidth="88dp"
android:text="@string/all_close" />
-
diff --git a/app/src/main/res/layout/dialog_homework_add.xml b/app/src/main/res/layout/dialog_homework_add.xml
index b9b8d1a2e..74c583aa1 100644
--- a/app/src/main/res/layout/dialog_homework_add.xml
+++ b/app/src/main/res/layout/dialog_homework_add.xml
@@ -5,8 +5,8 @@
android:layout_height="match_parent"
android:fillViewport="true"
android:minWidth="300dp"
- android:paddingStart="24dp"
- android:paddingEnd="24dp">
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp">
+ app:startIconDrawable="@drawable/ic_calendat_all">
@@ -66,7 +66,7 @@
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="0dp"
+ android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
android:hint="@string/all_teacher">
@@ -81,7 +81,7 @@
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="0dp"
+ android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:hint="@string/all_content">
@@ -105,13 +105,12 @@
android:layout_gravity="center_vertical"
android:layout_marginStart="0dp"
android:layout_marginLeft="0dp"
- android:layout_marginTop="8dp"
- android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minWidth="88dp"
android:text="@string/all_close"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
@@ -126,6 +125,7 @@
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
+ android:minWidth="88dp"
android:text="@string/all_add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
diff --git a/app/src/main/res/layout/fragment_login_recover.xml b/app/src/main/res/layout/fragment_login_recover.xml
index 76bdad228..028d6bc1f 100644
--- a/app/src/main/res/layout/fragment_login_recover.xml
+++ b/app/src/main/res/layout/fragment_login_recover.xml
@@ -155,7 +155,7 @@
android:orientation="vertical"
android:visibility="invisible"
tools:ignore="UseCompoundDrawables"
- tools:visibility="visible">
+ tools:visibility="gone">
@@ -108,6 +110,18 @@
android:text="@string/all_retry" />
+
+
+ tools:maxLines="2"
+ tools:text="@tools:sample/lorem/random" />
+
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 93ea10a11..b56617ed7 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -12,7 +12,7 @@
O aplikaci
Prohlížeč protokolů
Ladění
- Ladění upozornění
+ Ladění oznámení
Tvůrci
Licence
Zprávy
@@ -25,7 +25,7 @@
Podrobnosti účtu
Informace o žáku
Domů
- Centrum upozornění
+ Centrum oznámení
Semestr %1$d, %2$d/%3$d
@@ -204,6 +204,17 @@
Další lekce
Zobrazit další lekce
Žádné informace o dalších lekcích
+ Nová lekce
+ Nová další lekce
+ Další lekce byla úspěšně přidána
+ Další lekce byla úspěšně odstraněna
+ Opakovat každý týden
+ Odstranit další lekci
+ Pouze tato lekce
+ Všechny v sérii
+ Čas zahájení
+ Čas ukončení
+ Čas ukončení musí být pozdější než čas zahájení
Shrnutí frekvencí
Neprítomnosť zo školských dôvodov
@@ -253,10 +264,10 @@
- Nové zkoušky
- - Máte %d novou zkoušku
- - Máte %d nové zkoušky
- - Máte %d nových zkoušek
- - Máte %d nových zkoušek
+ - %d nová zkouška
+ - %d nové zkoušky
+ - %d nových zkoušek
+ - %d nových zkoušek
- %d zkouška
@@ -657,21 +668,23 @@
Známky barevné schéma
Třídění předmětů
Jazyk
- Upozornění
+ Oznámení
Jiné
- Zobrazit upozornění
- Zobrazit upozornění o nadcházející lekci
- Nastavit upozornění o nadcházející lekci jako trvalé
- Vypnout, když upozornění není ve vašem hodinkách/náramku viditelné
- Otevřít systémová nastavení upozornění
- Opravte problémy se synchronizací a upozorněním
- Vaše zařízení může mít problémy se synchronizací dat as upozorněními.\n\nChcete-li je opravit, přidejte Wulkanového do funkce Autostart a vypněte optimalizaci/úsporu baterie v nastavení systému telefonu.
- Zobrazit upozornění o ladění
+ Zobrazit oznámení
+ Zobrazit oznámení o nadcházející lekci
+ Nastavit oznámení o nadcházející lekci jako trvalé
+ Vypnout, když oznámení není ve vašem hodinkách/náramku viditelné
+ Otevřít systémová nastavení oznámení
+ Opravte problémy se synchronizací a oznámením
+ Vaše zařízení může mít problémy se synchronizací dat as oznámeními.\n\nChcete-li je opravit, přidejte Wulkanového do funkce Autostart a vypněte optimalizaci/úsporu baterie v nastavení systému telefonu.
+ Zobrazit oznámení o ladění
Synchronizace je vypnutá
- Zachytit upozornění oficiální aplikací
- Zachytit upozornění
- S touto funkcí můžete získat náhradu push upozornění jako v oficiální aplikaci. Vše, co musíte udělat, je povolit Wulkanowému číst všechna vaše upozornění v nastaveních systému.\n\nJak to funguje?\nKdyž obdržíte oznámení v Deníčku VULCAN, Wulkanowy bude o tom informován (k tomu je to dodatečné povolení) a spustí synchronizaci, aby mohl zaslat vlastní upozornění.\n\nPOUZE PRO POKROČILÉ UŽIVATELE
- Upozornění o nadcházející lekci
+ Oznámení oficiální aplikace
+ Zachytit oznámení oficiální aplikací
+ Odstranit oznámení oficiální aplikace po zachycení
+ Zachytit oznámení
+ S touto funkcí můžete získat náhradu push oznámení jako v oficiální aplikaci. Vše, co musíte udělat, je povolit Wulkanowému číst všechna vaše oznámení v nastaveních systému.\n\nJak to funguje?\nKdyž obdržíte oznámení v Deníčku VULCAN, Wulkanowy bude o tom informován (k tomu je to dodatečné povolení) a spustí synchronizaci, aby mohl zaslat vlastní oznámení.\n\nPOUZE PRO POKROČILÉ UŽIVATELE
+ Oznámení o nadcházející lekci
Musíte povolit Wulkanovému nastavit budíky a připomenutí v nastavení vašeho systému pro použití této funkce.
Přejít do nastavení
Synchronizace
@@ -698,7 +711,7 @@
Děkujeme za vaši podporu, vraťte se později pro více reklam
Pokročilé
Vzhled a chování
- Upozornění
+ Oznámení
Synchronizace
Reklamy
Známky
@@ -711,8 +724,8 @@
Zprávy
Vzhled a chování
Jazyky, motivy, třídění předmětů
- Upozornění aplikace, oprava problémů
- Upozornění
+ Oznámení aplikací, oprava problémů
+ Oznámení
Synchronizace
Automatická aktualizace, interval aktualizací
Hodnota plusu a mínusu, výpočet průměru
@@ -728,7 +741,7 @@
Nové zprávy
Nové poznámky
Nové školní oznámení
- Push upozornění
+ Push oznámení
Nadcházející lekce
Ladění
Změny plánu lekcí
@@ -747,11 +760,12 @@
Aktualizace selhala! Wulkanowy nemusí fungovat správně. Zvažte aktualizaci
Žádné internetové připojení
+ Vyskytla se chyba. Zkontrolujte hodiny svého zařízení
Nelze se připojit ke deníku. Servery mohou být přetíženy. Prosím zkuste to znovu později
Načítání dat se nezdařilo. Prosím zkuste to znovu později
Je vyžadována změna hesla pro deník
- Probíhá údržba UONET+ deník. Zkuste to později znovu
- Neznámá chyba denika UONET+. Prosím zkuste to znovu později
+ Probíhá údržba deníku UONET+. Zkuste to později znovu
+ Neznámá chyba deniku UONET+. Prosím zkuste to znovu později
Neznámá chyba aplikace. Prosím zkuste to znovu později
Vyskytla se neočekávaná chyba
Funkce je deaktivována přes vaší školou
diff --git a/app/src/main/res/values-de/preferences_values.xml b/app/src/main/res/values-de/preferences_values.xml
index 23e54cb78..08b9d240b 100644
--- a/app/src/main/res/values-de/preferences_values.xml
+++ b/app/src/main/res/values-de/preferences_values.xml
@@ -41,9 +41,9 @@
- Farben der Bewertungen im Logbuch
- - Up to 1 at once
- - Always expanded
- - Unlimited expansions
+ - Bis zu 1 auf einmal
+ - Immer erweitert
+ - Unbegrenzte Erweiterungen
- Durchschnitt der Noten aus beiden Semestern
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index f81724a21..931f643a6 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -6,7 +6,7 @@
Noten
Schulbesuch
Prüfungen
- Stundenplan
+ Zeitplan
Einstellungen
Mehr
Über die Applikation
@@ -17,7 +17,7 @@
Lizenzen
Nachrichten
neue Nachricht
- New homework
+ Neue Hausaufgaben
Eintragen und Erfolgen
Hausaufgaben
Konten-Manager
@@ -56,7 +56,7 @@
Schüler nicht gefunden. Überprüfen Sie das Symbol und die gewählte Variation des UONET+ Registers
Ausgewählter Student ist bereits angemeldet.
Das Symbol kann auf der Registerseite in Uczeń→ Dostęp Mobilny → Zarejestruj urządzenie mobilnegefunden werden.\n\nStellen Sie sicher, dass Sie die entsprechende Registervariante im Feld UONET+ Registervariante auf dem vorherigen Bildschirm festgelegt haben. Wulkanowy erkennt zur Zeit keine Vorschulstudenten
- Wählen Sie die Studenten aus, die sich bei der Anwendung anmelden sollen.
+ Wählen Sie die Studenten aus, die sich bei der Anwendung anmelden sollen
Andere Optionen
In diesem Modus funktioniert eine Glücknummer, eine Klassenstatistik, eine Zusammenfassung der Anwesenheit, eine Entschuldigung für die Abwesenheit, abgeschlossene Lektionen, Schulinformationen und eine Vorschau der Liste der registrierten Geräte nicht
In diesem Modus werden dieselben Daten angezeigt, die auf der Klassenbuch-Website angezeigt werden
@@ -95,7 +95,7 @@
Wie funktioniert der berechnete Durchschnitt?
The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\nAverage of grades only from selected semester:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\nAverage of averages from both semesters:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\nAverage of grades from the whole year:\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n3. Adding calculated averages\n4. Calculating the arithmetic average of summed averages
Wie funktioniert der endgültige Durchschnitt?
- The Final Average is the arithmetic average calculated from all currently available final grades in the given semester.\n\nThe calculation scheme consists of the following steps:\n1. Summing up the final grades given by teachers\n2. Divide by the number of subjects that have already been graded
+ Der Final Average ist das arithmetische Mittel, das aus allen derzeit verfügbaren Abschlussnoten des jeweiligen Semesters berechnet wird. \n\nDas Berechnungsschema besteht aus folgenden Schritten:\n1. Zusammenfassung der von den Lehrern gegebenen Abschlussnoten\n2. Division durch die Anzahl der Fächer, die bereits bewertet wurden
Finaler Durchschnitt
aus %1$d von %2$d Schulfächern
Zusammenfassung
@@ -151,25 +151,25 @@
Jetzt: %s
In einem Moment: %s
Später: %s
- %1$s lesson %2$d - %3$s
- Change of room from %1$s to %2$s
- Change of teacher from %1$s to %2$s
- Change of subject from %1$s to %2$s
+ %1$s Lektion %2$d - %3$s
+ Änderung des Raumes von %1$s zu %2$s
+ Wechsel des Lehrers von %1$s zu %2$s
+ Thema von %1$s zu %2$s wechseln
- - Timetable change
- - Timetable changes
+ - Änderung des Zeitplans
+ - Änderungen des Zeitplans
- - %1$s - %2$d change in timetable
- - %1$s - %2$d changes in timetable
+ - %1$s – %2$d Änderung im Zeitplan
+ - %1$s - %2$d Änderungen im Zeitplan
- - %1$d change in timetable
- - %1$d changes in timetable
+ - %1$d Änderung im Zeitplan
+ - %1$d Änderungen im Zeitplan
- - %d change
- - %d changes
+ - %d Änderung
+ - %d Änderungen
Beendete Lektionen
@@ -182,6 +182,17 @@
Zusätzliche Lektionen
Zusätzliche Lektionen anzeigen
Keine Informationen über zusätzlichen Lektionen
+ Neue Lektion
+ Neue zusätzliche Lektion
+ Zusätzliche Lektion erfolgreich hinzugefügt
+ Zusätzliche Lektion erfolgreich gelöscht
+ Wöchentlich wiederholen
+ Zusätzliche Lektion löschen
+ Nur diese Lektion
+ Alle in der Reihe
+ Startzeit
+ Endzeit
+ Endzeit muss grösser sein als Startzeit
Übersicht über die Schulbesuch
Aus schulischen Gründen abwesend
@@ -201,16 +212,16 @@
Sie müssen mindestens eine Abwesenheit auswählen!
Verzeihung
- - New attendance
- - New attendance
+ - Neue Teilnehmerzahl
+ - Neue Teilnehmerzahl
- - %1$d new attendance
- - %1$d attendance
+ - %1$d neue Teilnahme
+ - %1$d Teilnahme
- - %d attendance
- - %d attendance
+ - %d Teilnahme
+ - %d Teilnahme
Gesamt
@@ -223,8 +234,8 @@
- Neue prüfungen
- - Du hast %d neue Prüfung
- - Du hast %d neue Prüfungen
+ - %d neue Prüfung
+ - %d neue Prüfungen
- %d prüfung
@@ -316,9 +327,9 @@
Keine Informationen über Hausaufgaben
Gemacht
Unvollständig
- Add homework
- Homework added successfully
- Homework deleted successfully
+ Hausaufgaben hinzufügen
+ Hausaufgaben erfolgreich hinzugefügt
+ Heimarbeit erfolgreich gelöscht
Anhänge
- Neue hausaufgaben
@@ -472,7 +483,7 @@
Lektionen
(Morgen)
- (Today and tomorrow)
+ (Heute und morgen)
Gleich:
Bald:
Erstens:
@@ -546,7 +557,7 @@
Nein
Speichern
Titel
- Add
+ Hinzufügen
Kopiert
lösen
Ändern
@@ -563,7 +574,7 @@
Mittelwertberechnung durch App erzwingen
Anwesendheit zeigen
Thema
- Grades expanding
+ Steigende Sorten
Aktuelle Lektion markieren
Gruppen neben Schulfächen anzeigen
Liste der Diagramme in Klassenbewertungen anzeigen
@@ -572,7 +583,7 @@
Schulfachen sortieren
Sprache
Benachrichtigungen
- Other
+ Sonstiges
Benachrichtigungen anzeigen
Benachrichtigungen über bevorstehende Lektionen anzeigen
Festlegen einer Benachrichtigung über die bevorstehende Lektion dauerhaft
@@ -582,12 +593,14 @@
Ihr Gerät hat möglicherweise Probleme mit der Datensynchronisierung und Benachrichtigungen.\n\nUm diese zu reparieren, fügen Sie Wulkanowy zum Autostart hinzu und deaktivieren Sie die Batterieoptimierung in den Systemeinstellungen des Geräts.
Debug-Benachrichtigungen anzeigen
Synchronisierung ist deaktiviert
+ Offizielle Benachrichtigungen
Offizielle App-Benachrichtigungen erfassen
+ Entfernen Sie offizielle App-Benachrichtigungen nach der Erfassung
Benachrichtigungen erfassen
With this feature you can gain a substitute of push notifications like in the official app. All you need to do is allow Wulkanowy to receive all notifications in your system settings.\n\nHow it works?\nWhen you get a notification in Dziennik VULCAN, Wulkanowy will be notified (that\'s what these extra permissions are for) and will trigger a sync so that can send its own notification.\n\nFOR ADVANCED USERS ONLY
- Upcoming lesson notifications
- You must allow the Wulkanowy app to set alarms and reminders in your system settings to use this feature.
- Go to settings
+ Bevorstehende Unterrichtsbenachrichtigungen
+ Sie müssen der Wulkanowy-App erlauben, in Ihren Systemeinstellungen Alarme und Erinnerungen einzustellen, damit diese Funktion verwendet werden kann.
+ Gehe zu den Einstellungen
Synchronisierung
Automatische Aktualisierung
An Feiertagen suspendiert
@@ -602,26 +615,26 @@
Wert des Minus
Antwort mit Nachrichtenhistorie
Arithmetisches Mittel anzeigen, wenn keine Gewichte angegeben sind
- Support
- Watch single ad to support project
- Consent to data processing
- To view an advertisement you must agree to the data processing terms of our Privacy Policy
- Agree
- Privacy policy
- Ad is loading
- Thank you for your support, come back later for more ads
+ Unterstützung
+ Einzelanzeige ansehen, um Projekt zu unterstützen
+ Einwilligung in die Datenverarbeitung
+ Um eine Anzeige zu sehen, müssen Sie mit den Datenverarbeitungsbedingungen unserer Datenschutzerklärung einverstanden sein
+ Einverstanden
+ Datenschutzerklärung
+ Anzeige wird geladen
+ Vielen Dank für Ihre Unterstützung, kommen Sie später wieder für weitere Anzeigen
Erweitert
Aussehen & Verhalten
Benachrichtigungen
Synchronisierung
- Advertisements
+ Werbung
Noten
Dashboard
Sichtbarkeit der Kacheln
Schulbesuch
Stundenplan
Noten
- Calculated average
+ Berechneter Durchschnitt
Nachrichten
Aussehen & Verhalten
Sprachen, Themen, Schulfachen sortieren
@@ -631,8 +644,8 @@
Automatisches Update, Synchronisierungsintervall
Plus und Minus Werte, Durchschnittsberechnung
Erweitert
- App version, contributors, social portals
- Displaying advertisements, project support
+ App-Version, Mitwirkende, soziale Portale
+ Anzeigen, Projektunterstützung
Neue Noten
Neue Hausaufgaben
@@ -645,8 +658,8 @@
Push-Benachrichtigungen
Bevorstehende Lektionen
Debuggen
- Timetable change
- New attendance
+ Änderung des Zeitplans
+ Neue Teilnehmerzahl
Schwarz
Rot
@@ -661,6 +674,7 @@
Update fehlgeschlagen! Wulkanowy funktioniert möglicherweise nicht richtig. Überlegen Sie die Aktualisierung
Keine Internetverbindung
+ Es ist ein Fehler aufgetreten. Überprüfen Sie Ihre Geräteuhr
Registrierungsverbindung fehlgeschlagen. Server können überlastet sein. Bitte versuchen Sie es später noch einmal
Das Laden der Daten ist fehlgeschlagen. Bitte versuchen Sie es später noch einmal
Passwortänderung für Registrierung erforderlich
@@ -670,5 +684,5 @@
Ein unerwarteter Fehler ist aufgetreten
Funktion, die von Ihrer Schule deaktiviert wurde
Feature in diesem Modus nicht verfügbar
- This field is required
+ Dieses Feld ist erforderlich
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 93bdd5354..208e6f3ea 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -204,6 +204,17 @@
Dodatkowe lekcje
Pokaż dodatkowe lekcje
Brak informacji o dodatkowych lekcjach
+ Nowa lekcja
+ Nowa dodatkowa lekcja
+ Dodatkowa lekcja dodana pomyślnie
+ Dodatkowa lekcja usunięta pomyślnie
+ Powtarzaj co tydzień
+ Usuń dodatkową lekcję
+ Tylko ta lekcja
+ Wszystkie w serii
+ Godzina rozpoczęcia
+ Godzina zakończenia
+ Godzina zakończenia musi być późniejsza niż godzina rozpoczęcia
Podsumowanie frekwencji
Nieobecność z przyczyn szkolnych
@@ -253,10 +264,10 @@
- Nowe sprawdziany
- - Masz %d nowy sprawdzian
- - Masz %d nowe sprawdziany
- - Masz %d nowych sprawdzianów
- - Masz %d nowych sprawdzianów
+ - %d nowy sprawdzian
+ - %d nowe sprawdziany
+ - %d nowych sprawdzianów
+ - %d nowych sprawdzianów
- %d sprawdzian
@@ -668,7 +679,9 @@
Na twoim urządzeniu mogą występować problemy z synchronizacją danych i powiadomieniami.\n\nBy je naprawić, dodaj Wulkanowego do autostartu i wyłącz optymalizację/oszczędzanie baterii w ustawieniach systemowych telefonu.
Pokazuj powiadomienia debugowania
Synchronizacja jest wyłączona
+ Powiadomienia oficjalnej aplikacji
Przechwytywanie powiadomień oficjalnej aplikacji
+ Usuwaj powiadomienia oficjalnej aplikacji po przechwyceniu
Przechwytywanie powiadomień
Dzięki tej funkcji możesz uzyskać namiastkę powiadomień push, takich jak w oficjalnej aplikacji. Wszystko, co musisz zrobić, to zezwolić Wulkanowemu na odczytywanie wszystkich powiadomień w ustawieniach systemowych.\n\nJak to działa?\nKiedy otrzymasz powiadomienie w Dzienniczku VULCAN, Wulkanowy zostanie o tym powiadomiony (do tego jest to dodatkowe uprawnienie) i uruchomi synchronizację, aby mógł wysłać własne powiadomienie.\n\nWYŁĄCZNIE DLA ZAAWANSOWANYCH UŻYTKOWNIKÓW
Powiadomienia o nadchodzących lekcjach
@@ -747,6 +760,7 @@
Aktualizacja nie powiodła się! Wulkanowy może nie działać prawidłowo. Rozważ aktualizację
Brak połączenia z internetem
+ Wystąpił błąd. Sprawdź poprawność daty w urządzeniu
Nie udało się połączyć z dziennikiem. Serwery mogą być przeciążone. Spróbuj ponownie później
Ładowanie danych nie powiodło się. Spróbuj ponownie później
Wymagana zmiana hasła do dziennika
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 33ec21826..b5ad3683e 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -204,6 +204,17 @@
Дополнительные уроки
Показать дополнительные уроки
Нет информации о дополнительных уроках
+ New lesson
+ New additional lesson
+ Additional lesson added successfully
+ Additional lesson deleted successfully
+ Repeat weekly
+ Delete additional lesson
+ Just this lesson
+ All in the series
+ Start time
+ End time
+ End time must be greater than start time
Итоговая посещаемость
Отсутствие по школьным причинам
@@ -253,10 +264,10 @@
- Новые экзамены
- - Вы получили %d новый экзамен
- - Вы получили %d новый экзамен
- - Вы получили %d новый экзамен
- - Вы получили %d новых экзаменов
+ - %d new exam
+ - %d new exams
+ - %d new exams
+ - %d new exams
- %d экзамен
@@ -668,12 +679,14 @@
На вашем устройстве могут быть проблемы с синхронизацией данных и уведомлениями.\n\nЧтобы их исправить, вам необходимо добавить Wulkanowy в авто-старт и выключить оптимизацию/экономию батареи в настройках устройства.
Показывать дебаг-уведомления
Синхронизация отключена
+ Official app notifications
Записывать официальные уведомления
+ Remove official app notifications after capture
Показывать push-уведомления
С помощью этой функции вы можете получить замену push-уведомлений, как в официальном приложении. Все, что вам нужно сделать, это разрешить Wulkanowy получать все уведомления в настройках системы.\n\nКак это работает?\nКогда вы получаете уведомление в Dziennik VULCAN, Wulkanowy будет уведомлен (это требует дополнительных прав) и запустит синхронизацию, чтобы отправить свое уведомление.\n\nТОЛЬКО ДЛЯ ПОЛЬЗОВАТЕЛЯ
- Upcoming lesson notifications
- You must allow the Wulkanowy app to set alarms and reminders in your system settings to use this feature.
- Go to settings
+ Показывать уведомления о будущих уроках
+ Вы должны разрешить приложению Wulkanowy установить будильник и напоминания в настройках системы, чтобы использовать эту функцию.
+ Перейти к настройкам
Синхронизация
Автоматическая синхронизация
Приостановить синхронизации во время каникул
@@ -695,7 +708,7 @@
Согласен
Политика конфиденциальности
Объявление загружается
- Thank you for your support, come back later for more ads
+ Спасибо за вашу поддержку, возвращайтесь позже для дополнительной рекламы
Расширенные
Внешний вид & Поведение
Уведомления
@@ -747,6 +760,7 @@
Не удалось обновить! Wulkanowy может работать некорректно. Рассмотрите возможность обновления
Нет интернет-подключения
+ An error occurred. Check your device clock
Не удалось подключиться к регистрации. Серверы могут быть перегружены. Пожалуйста, повторите попытку позже
Не удалось загрузить данные. Пожалуйста, повторите попытку позже
Необходимо изменить пароль реестра
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index 77e402add..30365fe56 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -12,7 +12,7 @@
O aplikácii
Prehliadač protokolov
Ladenie
- Ladenie upozornení
+ Ladenie oznámení
Tvorcovia
Licencie
Správy
@@ -25,7 +25,7 @@
Podrobnosti účtu
Informácie o žiakovi
Domov
- Centrum upozornení
+ Centrum oznámení
Semester %1$d, %2$d/%3$d
@@ -204,6 +204,17 @@
Ďalšie lekcie
Zobraziť ďalšie lekcie
Žiadne informácie o ďalších lekciách
+ Nová lekcia
+ Nová ďalšia lekcia
+ Ďalšia lekcia bola úspešne pridaná
+ Ďalšia lekcia bola úspešne odstránená
+ Opakovať každý týždeň
+ Odstrániť ďalšiu lekciu
+ Iba táto lekcia
+ Všetky v sérii
+ Čas začatia
+ Čas ukončenia
+ Čas ukončenia musí byť neskorší ako čas začatia
Zhrnutie frekvencií
Neprítomnosť zo školských dôvodov
@@ -253,10 +264,10 @@
- Nové skúšky
- - Máte %d novú skúšku
- - Máte %d nové skúšky
- - Máte %d nových skúšok
- - Máte %d nových skúšok
+ - %d nová skúška
+ - %d nové skúšky
+ - %d nových skúšok
+ - %d nových skúšok
- %d skúška
@@ -657,21 +668,23 @@
Známky farebnú schému
Triedenie predmetov
Jazyk
- Upozornenia
+ Oznámenia
Iné
- Zobraziť upozornenia
- Zobraziť upozornenia o nadchádzajúcej lekciu
- Nastaviť upozornenia o nadchádzajúcej lekcii ako trvalé
- Vypnúť, keď upozornenia nie je vo vašom hodinkách/náramku viditeľné
- Otvoriť systémové nastavenia upozornení
- Opravte problémy so synchronizáciou a upozornením
- Vaše zariadenie môže mať problémy so synchronizáciou dát as upozorneniami.\n\nAk ich chcete opraviť, pridajte Wulkanového do funkcie Autostart a vypnite optimalizáciu/úsporu batérie v nastavení systému telefóne.
- Zobraziť upozornenia o ladení
+ Zobraziť oznámenia
+ Zobraziť oznámenia o nadchádzajúcich lekciách
+ Nastaviť oznámenia o nadchádzajúcej lekcií ako trvalé
+ Vypnúť, keď oznámenia nie je vo vašom hodinkách/náramku viditeľné
+ Otvoriť systémové nastavenia oznámení
+ Opravte problémy so synchronizáciou a oznámeniami
+ Vaše zariadenie môže mať problémy so synchronizáciou dát as oznámeniami.\n\nAk ich chcete opraviť, pridajte Wulkanového do funkcie Autostart a vypnite optimalizáciu/úsporu batérie v nastavení systému telefóne.
+ Zobraziť oznámenia o ladení
Synchronizácia je vypnutá
+ Oznámenia oficiálnej aplikácie
Zachytiť upozornenia oficiálnej aplikácie
- Zachytiť upozornenia
- S touto funkciou môžete získať náhradu push upozornení ako v oficiálnej aplikácii. Všetko, čo musíte urobiť, je povoliť Wulkanowému čítať všetky vaše upozornenia v nastaveniach systému.\n\nAko to funguje?\nKeď dostanete oznámenie v Deníčku VULCAN, Wulkanowy bude o tom informovaný (k tomu je to dodatočné povolenie) a spustí synchronizáciu, aby mohol zaslať vlastné upozornenie.\n\nLEN PRE POKROČILÝCH POUŽĺVATEĹOV
- Upozornenia o nadchádzajúcej lekciu
+ Odstrániť oznámenia oficiálnej aplikácie po zachytení
+ Zachytiť oznámení
+ S touto funkciou môžete získať náhradu push oznámení ako v oficiálnej aplikácii. Všetko, čo musíte urobiť, je povoliť Wulkanowému čítať všetky vaše oznámenia v nastaveniach systému.\n\nAko to funguje?\nKeď dostanete oznámenie v Deníčku VULCAN, Wulkanowy bude o tom informovaný (k tomu je to dodatočné povolenie) a spustí synchronizáciu, aby mohol zaslať vlastné oznámenie.\n\nLEN PRE POKROČILÝCH POUŽĺVATEĹOV
+ Oznámenia o nadchádzajúcej lekcií
Musíte povoliť Wulkanovému nastaviť budíky a pripomenutie v nastavení vášho systému pre použitie tejto funkcie.
Prejsť do nastavení
Synchronizácia
@@ -698,7 +711,7 @@
Ďakujeme za vašu podporu, vráťte sa neskôr pre viac reklám
Pokročilé
Vzhľad a správanie
- Upozornenia
+ Oznámenia
Synchronizácia
Reklamy
Známky
@@ -711,8 +724,8 @@
Správy
Vzhľad a správanie
Jazyky, motívy, triedenie predmetov
- Upozornenia aplikácie, oprava problémov
- Upozornenia
+ Oznámenia aplikácie, oprava problémov
+ Oznámenia
Synchronizácia
Automatická aktualizácia, interval aktualizácií
Hodnota plusu a mínusu, výpočet priemeru
@@ -728,7 +741,7 @@
Nové správy
Nové poznámky
Nové školské oznámenia
- Push upozornenia
+ Push oznámenia
Nadchádzajúce lekcie
Ladenie
Zmeny plánu lekcií
@@ -747,10 +760,11 @@
Aktualizácia zlyhala! Wulkanowy nemusí fungovať správne. Zvážte aktualizáciu
Žiadne internetové pripojenie
+ Vyskytla sa chyba. Skontrolujte hodiny svojho zariadenia
Nedá sa pripojiť ku denníku. Servery môžu byť preťažené. Prosím skúste to znova neskôr
Načítanie údajov zlyhalo. Skúste neskôr prosím
Je vyžadovaná zmena hesla pre denník
- Prebieha údržba UONET+ denník. Skúste to neskôr znova
+ Prebieha údržba denníka UONET+. Skúste to neskôr znova
Neznáma chyba dennika UONET+. Prosím skúste to znova neskôr
Neznáma chyba aplikácie. Prosím skúste to znova neskôr
Vyskytla sa neočakávaná chyba
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 8543a4708..0c88df317 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -204,6 +204,17 @@
Додаткові уроки
Показати додаткові уроки
Немає інформації про додаткових уроків
+ New lesson
+ New additional lesson
+ Additional lesson added successfully
+ Additional lesson deleted successfully
+ Repeat weekly
+ Delete additional lesson
+ Just this lesson
+ All in the series
+ Start time
+ End time
+ End time must be greater than start time
Підсумок відвідуваності
Відсутність зі шкільних причин
@@ -253,10 +264,10 @@
- Нові іспити
- - Ви отримали %d новий іспит
- - Ви отримали %d новий іспит
- - Ви отримали %d новий іспит
- - Ви отримали %d нових іспитів
+ - %d new exam
+ - %d new exams
+ - %d new exams
+ - %d new exams
- %d екзамен
@@ -668,12 +679,14 @@
На вашому пристрої можуть бути помилки з синхронізацією і повідомленнями\n\nЩоб виправити іх, вам необхідно додати Wulkanowy в авто-старт и вимкнути оптимізацію/экономію батареї в налаштуваннях пристрою.
Показувати дебаг-повідомлення
Синхронізація вимкнена
+ Official app notifications
Захоплювати офіційні сповіщення програм
+ Remove official app notifications after capture
Показувати push-повідомлення
За допомогою цієї функції ви можете отримати заміну push -повідомлень, як у офіційному додатку. Все, що вам потрібно зробити, це дозволити Wulkanowy отримувати всі сповіщення у налаштуваннях вашої системи. \ N \ nЯк це працює? \ NКоли ви отримаєте сповіщення у Dziennik VULCAN, Wulkanowy отримає сповіщення (для цього призначені ці додаткові дозволи) і запустить синхронізація, яка може надсилати власне сповіщення. \ n \ n ТІЛЬКИ ДЛЯ РОЗШИРЕНИХ КОРИСТУВАЧІВ
- Upcoming lesson notifications
- You must allow the Wulkanowy app to set alarms and reminders in your system settings to use this feature.
- Go to settings
+ Показувати повідомлення о наступних уроках
+ Ви повинні дозволити Wulkanowy встановити будильник та нагадування у налаштуваннях вашої системи для використання цієї функції.
+ Перейти до налаштувань
Синхронізація
Автоматична синхронізація
Призупинено на час канікул
@@ -695,7 +708,7 @@
Погоджуюсь
Політика конфіденційності
Реклама завантажується
- Thank you for your support, come back later for more ads
+ Дякуємо за вашу підтримку, повертайтеся пізніше для більшої кількості оголошень
Додатково
Вигляд & Поведінка
Повідомлення
@@ -747,6 +760,7 @@
Помилка оновлення! Wulkanowy може не працювати належним чином. Подумайте про оновлення
Брак з\'єднання з інтернетом
+ An error occurred. Check your device clock
Помилка підключення до реєстрації. Сервери можуть бути перевантажені. Будь-ласка спробуйте пізніше
Помилка завантаження даних. Будь-ласка спробуйте пізніше
Потрібна реєстрація зміни пароля
diff --git a/app/src/main/res/values/preferences_defaults.xml b/app/src/main/res/values/preferences_defaults.xml
index 7fb3d5c05..deeb36961 100644
--- a/app/src/main/res/values/preferences_defaults.xml
+++ b/app/src/main/res/values/preferences_defaults.xml
@@ -28,6 +28,7 @@
false
0
false
+ false
- LUCKY_NUMBER
- MESSAGES
diff --git a/app/src/main/res/values/preferences_keys.xml b/app/src/main/res/values/preferences_keys.xml
index fef062dd1..849d989ee 100644
--- a/app/src/main/res/values/preferences_keys.xml
+++ b/app/src/main/res/values/preferences_keys.xml
@@ -35,5 +35,6 @@
message_send_recipients
last_sync_date
notifications_piggyback
+ notifications_piggyback_cancel_original
single_ad_support
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 97c8f0345..9c63073e2 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -198,6 +198,17 @@
Additional lessons
Show additional lessons
No info about additional lessons
+ New lesson
+ New additional lesson
+ Additional lesson added successfully
+ Additional lesson deleted successfully
+ Repeat weekly
+ Delete additional lesson
+ Just this lesson
+ All in the series
+ Start time
+ End time
+ End time must be greater than start time
@@ -661,7 +672,9 @@
Your device may have data synchronization issues and with notifications.\n\nTo fix them, you need to add Wulkanowy to the autostart and turn off battery optimization/saving in the phone settings.
Show debug notifications
Synchronization is disabled
+ Official app notifications
Capture official app notifications
+ Remove official app notifications after capture
Capture notifications
With this feature you can gain a substitute of push notifications like in the official app. All you need to do is allow Wulkanowy to receive all notifications in your system settings.\n\nHow it works?\nWhen you get a notification in Dziennik VULCAN, Wulkanowy will be notified (that\'s what these extra permissions are for) and will trigger a sync so that can send its own notification.\n\nFOR ADVANCED USERS ONLY
Upcoming lesson notifications
@@ -754,6 +767,7 @@
No internet connection
+ An error occurred. Check your device clock
Connection to register failed. Servers can be overloaded. Please try again later
Loading data failed. Please try again later
Register password change required
diff --git a/app/src/main/res/xml/scheme_preferences_notifications.xml b/app/src/main/res/xml/scheme_preferences_notifications.xml
index 442581bfd..0366914ac 100644
--- a/app/src/main/res/xml/scheme_preferences_notifications.xml
+++ b/app/src/main/res/xml/scheme_preferences_notifications.xml
@@ -16,9 +16,9 @@
app:title="@string/pref_notify_upcoming_lessons_switch" />
@@ -31,13 +31,24 @@
+ app:title="@string/pref_notify_notifications_piggyback_header">
+
+
+
> {
val semesters = mutableListOf>()
- val cursor = db.query(query)
- if (cursor.moveToFirst()) {
- do {
- semesters.add(Semester(
- studentId = cursor.getInt(1),
- diaryId = cursor.getInt(2),
- diaryName = cursor.getString(3),
- semesterId = cursor.getInt(4),
- semesterName = cursor.getInt(5),
- classId = cursor.getInt(7),
- unitId = cursor.getInt(8),
- schoolYear = cursor.getInt(9),
- start = Converters().timestampToDate(cursor.getLong(10))!!,
- end = Converters().timestampToDate(cursor.getLong(11))!!
- ) to (cursor.getInt(6) == 1))
- } while (cursor.moveToNext())
+ db.query(query).use {
+ if (it.moveToFirst()) {
+ do {
+ semesters.add(Semester(
+ studentId = it.getInt(1),
+ diaryId = it.getInt(2),
+ kindergartenDiaryId = 0,
+ diaryName = it.getString(3),
+ semesterId = it.getInt(4),
+ semesterName = it.getInt(5),
+ classId = it.getInt(7),
+ unitId = it.getInt(8),
+ schoolYear = it.getInt(9),
+ start = Converters().timestampToLocalDate(it.getLong(10))!!,
+ end = Converters().timestampToLocalDate(it.getLong(11))!!
+ ) to (it.getInt(6) == 1))
+ } while (it.moveToNext())
+ }
}
+
return semesters.toList()
}
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/GradeRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/GradeRepositoryTest.kt
index 6dd30a579..f7968bc41 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/GradeRepositoryTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/GradeRepositoryTest.kt
@@ -8,23 +8,17 @@ import io.github.wulkanowy.getStudentEntity
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.toFirstResult
-import io.mockk.MockKAnnotations
-import io.mockk.Runs
-import io.mockk.coEvery
-import io.mockk.coVerify
-import io.mockk.every
+import io.mockk.*
import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
-import io.mockk.just
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
+import org.junit.Assert.*
import org.junit.Before
import org.junit.Test
import java.time.LocalDate
import java.time.LocalDate.of
+import java.time.ZoneOffset
import io.github.wulkanowy.sdk.pojo.Grade as SdkGrade
class GradeRepositoryTest {
@@ -57,7 +51,11 @@ class GradeRepositoryTest {
coEvery { gradeDb.deleteAll(any()) } just Runs
coEvery { gradeDb.insertAll(any()) } returns listOf()
- coEvery { gradeSummaryDb.loadAll(1, 1) } returnsMany listOf(flowOf(listOf()), flowOf(listOf()), flowOf(listOf()))
+ coEvery { gradeSummaryDb.loadAll(1, 1) } returnsMany listOf(
+ flowOf(listOf()),
+ flowOf(listOf()),
+ flowOf(listOf())
+ )
coEvery { gradeSummaryDb.deleteAll(any()) } just Runs
coEvery { gradeSummaryDb.insertAll(any()) } returns listOf()
}
@@ -65,7 +63,7 @@ class GradeRepositoryTest {
@Test
fun `mark grades older than registration date as read`() {
// prepare
- val boundaryDate = of(2019, 2, 27).atStartOfDay()
+ val boundaryDate = of(2019, 2, 27).atStartOfDay().toInstant(ZoneOffset.UTC)
val remoteList = 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"),
@@ -81,7 +79,13 @@ class GradeRepositoryTest {
)
// execute
- val res = runBlocking { gradeRepository.getGrades(student.copy(registrationDate = boundaryDate), semester, true).toFirstResult() }
+ val res = runBlocking {
+ gradeRepository.getGrades(
+ student = student.copy(registrationDate = boundaryDate),
+ semester = semester,
+ forceRefresh = true
+ ).toFirstResult()
+ }
// verify
assertEquals(null, res.error)
@@ -101,9 +105,19 @@ class GradeRepositoryTest {
fun `mitigate mark grades as unread when old grades changed`() {
// prepare
val remoteList = listOf(
- createGradeApi(5, 2.0, of(2019, 2, 25), "Ocena ma datę, jest inna, ale nie zostanie powiadomiona"),
+ createGradeApi(
+ 5,
+ 2.0,
+ of(2019, 2, 25),
+ "Ocena ma datę, jest inna, ale nie zostanie powiadomiona"
+ ),
createGradeApi(4, 3.0, of(2019, 2, 26), "starszą niż ostatnia lokalnie"),
- createGradeApi(3, 4.0, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie"),
+ createGradeApi(
+ 3,
+ 4.0,
+ of(2019, 2, 27),
+ "Ta jest z tego samego dnia co ostatnia lokalnie"
+ ),
createGradeApi(2, 5.0, of(2019, 2, 28), "Ta jest już w ogóle nowa")
)
coEvery { sdk.getGrades(1) } returns (remoteList to emptyList())
@@ -111,7 +125,12 @@ class GradeRepositoryTest {
val localList = listOf(
createGradeApi(5, 3.0, of(2019, 2, 25), "Jedna ocena"),
createGradeApi(4, 4.0, of(2019, 2, 26), "Druga"),
- createGradeApi(3, 4.0, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie")
+ createGradeApi(
+ 3,
+ 4.0,
+ of(2019, 2, 27),
+ "Ta jest z tego samego dnia co ostatnia lokalnie"
+ )
)
coEvery { gradeDb.loadAll(1, 1) } returnsMany listOf(
flowOf(localList.mapToEntities(semester)),
@@ -248,18 +267,19 @@ class GradeRepositoryTest {
assertEquals(0, res.data?.first?.size)
}
- private fun createGradeApi(value: Int, weight: Double, date: LocalDate, desc: String) = SdkGrade(
- subject = "",
- color = "",
- comment = "",
- date = date,
- description = desc,
- entry = "",
- modifier = .0,
- symbol = "",
- teacher = "",
- value = value.toDouble(),
- weight = weight.toString(),
- weightValue = weight
- )
+ private fun createGradeApi(value: Int, weight: Double, date: LocalDate, desc: String) =
+ SdkGrade(
+ 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/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
index 052f08f00..f21fc1780 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
@@ -16,27 +16,25 @@ import io.github.wulkanowy.sdk.pojo.MessageDetails
import io.github.wulkanowy.sdk.pojo.Sender
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.toFirstResult
-import io.mockk.MockKAnnotations
-import io.mockk.Runs
-import io.mockk.checkEquals
-import io.mockk.coEvery
-import io.mockk.coVerify
-import io.mockk.every
+import io.mockk.*
import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
-import io.mockk.just
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.Json
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import java.net.UnknownHostException
-import java.time.LocalDateTime
+import java.time.Instant
+import java.time.ZoneOffset
import kotlin.test.assertTrue
+@OptIn(ExperimentalCoroutinesApi::class)
class MessageRepositoryTest {
@SpyK
@@ -80,7 +78,7 @@ class MessageRepositoryTest {
}
@Test
- fun `get messages when read by values was changed on already read message`() = runBlocking {
+ fun `get messages when read by values was changed on already read message`() = runTest {
every { messageDb.loadAll(any(), any()) } returns flow {
val dbMessage = getMessageEntity(3, "", false).apply {
unreadBy = 10
@@ -239,7 +237,7 @@ class MessageRepositoryTest {
senderId = 0,
recipient = "Wielu adresatów",
subject = "",
- date = LocalDateTime.MAX,
+ date = Instant.EPOCH,
folderId = 1,
unread = unread,
removed = false,
@@ -261,7 +259,8 @@ class MessageRepositoryTest {
recipients = listOf(),
subject = "",
content = content,
- date = LocalDateTime.MAX,
+ date = Instant.EPOCH.atZone(ZoneOffset.UTC).toLocalDateTime(),
+ dateZoned = Instant.EPOCH.atZone(ZoneOffset.UTC),
folderId = 1,
unread = unread,
unreadBy = 0,
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/MobileDeviceRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/MobileDeviceRepositoryTest.kt
index 52a076d3c..c5a7756ff 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/MobileDeviceRepositoryTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/MobileDeviceRepositoryTest.kt
@@ -22,6 +22,7 @@ import org.junit.Assert
import org.junit.Before
import org.junit.Test
import java.time.LocalDateTime.of
+import java.time.ZoneId
class MobileDeviceRepositoryTest {
@@ -137,6 +138,8 @@ class MobileDeviceRepositoryTest {
name = "",
deviceId = "",
createDate = of(2019, 5, day, 0, 0, 0),
- modificationDate = of(2019, 5, day, 0, 0, 0)
+ modificationDate = of(2019, 5, day, 0, 0, 0),
+ createDateZoned = of(2019, 5, day, 0, 0, 0).atZone(ZoneId.systemDefault()),
+ modificationDateZoned = of(2019, 5, day, 0, 0, 0).atZone(ZoneId.systemDefault())
)
}
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/TimetableRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/TimetableRepositoryTest.kt
index edb3125eb..adb4f33a1 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/TimetableRepositoryTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/TimetableRepositoryTest.kt
@@ -27,6 +27,7 @@ import org.junit.Test
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalDateTime.of
+import java.time.ZoneId
import io.github.wulkanowy.sdk.pojo.Timetable as SdkTimetable
class TimetableRepositoryTest {
@@ -107,6 +108,8 @@ class TimetableRepositoryTest {
number = number,
start = start,
end = start.plusMinutes(45),
+ startZoned = start.atZone(ZoneId.systemDefault()),
+ endZoned = start.plusMinutes(45).atZone(ZoneId.systemDefault()),
date = start.toLocalDate(),
subject = subject,
group = "",
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 ec07e149f..f097cb845 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
@@ -23,9 +23,9 @@ import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
+import java.time.Instant
import java.time.LocalDate.now
import java.time.LocalDate.of
-import java.time.LocalDateTime
class GradeAverageProviderTest {
@@ -63,7 +63,7 @@ class GradeAverageProviderTest {
className = "",
classId = 1,
isCurrent = true,
- registrationDate = LocalDateTime.now()
+ registrationDate = Instant.now()
)
private val semesters = mutableListOf(
diff --git a/app/src/test/java/io/github/wulkanowy/ui/modules/login/LoginPresenterTest.kt b/app/src/test/java/io/github/wulkanowy/ui/modules/login/LoginPresenterTest.kt
deleted file mode 100644
index 35cda35bd..000000000
--- a/app/src/test/java/io/github/wulkanowy/ui/modules/login/LoginPresenterTest.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-package io.github.wulkanowy.ui.modules.login
-
-import io.github.wulkanowy.data.repositories.StudentRepository
-import io.mockk.MockKAnnotations
-import io.mockk.clearMocks
-import io.mockk.every
-import io.mockk.impl.annotations.MockK
-import io.mockk.verify
-import org.junit.Assert.assertNotEquals
-import org.junit.Before
-import org.junit.Test
-
-class LoginPresenterTest {
-
- @MockK(relaxed = true)
- lateinit var loginView: LoginView
-
- @MockK(relaxed = true)
- lateinit var errorHandler: LoginErrorHandler
-
- @MockK
- lateinit var studentRepository: StudentRepository
-
- private lateinit var presenter: LoginPresenter
-
- @Before
- fun initPresenter() {
- MockKAnnotations.init(this)
- clearMocks(loginView)
-
- presenter = LoginPresenter(errorHandler, studentRepository)
- presenter.onAttachView(loginView)
- }
-
- @Test
- fun initViewTest() {
- verify { loginView.initView() }
- verify { loginView.showActionBar(false) }
- }
-
- @Test
- fun onBackPressedTest() {
- clearMocks(loginView)
- every { loginView.currentViewIndex } returns 1
- presenter.onBackPressed { }
- verify { loginView.switchView(0) }
- }
-
- @Test
- fun onBackPressedDefaultTest() {
- var i = 0
- every { loginView.currentViewIndex } returns 0
- presenter.onBackPressed { i++ }
- assertNotEquals(0, i)
- }
-}
-
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 67d3e6266..9bcfb8b6c 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
@@ -6,18 +6,13 @@ import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
import io.github.wulkanowy.utils.AnalyticsHelper
-import io.mockk.MockKAnnotations
-import io.mockk.Runs
-import io.mockk.coEvery
-import io.mockk.every
+import io.mockk.*
import io.mockk.impl.annotations.MockK
-import io.mockk.just
-import io.mockk.verify
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import java.io.IOException
-import java.time.LocalDateTime.now
+import java.time.Instant
class LoginFormPresenterTest {
@@ -121,7 +116,7 @@ class LoginFormPresenterTest {
classId = 1,
isCurrent = false,
symbol = "",
- registrationDate = now(),
+ registrationDate = Instant.now(),
className = "",
mobileBaseUrl = "",
privateKey = "",
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 c79d739e8..e52ec3ae2 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
@@ -4,20 +4,15 @@ import io.github.wulkanowy.MainCoroutineRule
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.data.repositories.StudentRepository
+import io.github.wulkanowy.services.sync.SyncManager
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
import io.github.wulkanowy.utils.AnalyticsHelper
-import io.mockk.MockKAnnotations
-import io.mockk.Runs
-import io.mockk.clearMocks
-import io.mockk.coEvery
-import io.mockk.every
+import io.mockk.*
import io.mockk.impl.annotations.MockK
-import io.mockk.just
-import io.mockk.verify
import org.junit.Before
import org.junit.Rule
import org.junit.Test
-import java.time.LocalDateTime.now
+import java.time.Instant
class LoginStudentSelectPresenterTest {
@@ -36,6 +31,9 @@ class LoginStudentSelectPresenterTest {
@MockK(relaxed = true)
lateinit var analytics: AnalyticsHelper
+ @MockK(relaxed = true)
+ lateinit var syncManager: SyncManager
+
private lateinit var presenter: LoginStudentSelectPresenter
private val testStudent by lazy {
@@ -51,7 +49,7 @@ class LoginStudentSelectPresenterTest {
schoolSymbol = "",
classId = 1,
studentName = "",
- registrationDate = now(),
+ registrationDate = Instant.now(),
className = "",
loginMode = "",
certificateKey = "",
@@ -77,8 +75,8 @@ class LoginStudentSelectPresenterTest {
every { loginStudentSelectView.showProgress(any()) } just Runs
every { loginStudentSelectView.showContent(any()) } just Runs
- presenter = LoginStudentSelectPresenter(studentRepository, errorHandler, analytics)
- presenter.onAttachView(loginStudentSelectView, null)
+ presenter = LoginStudentSelectPresenter(studentRepository, errorHandler, syncManager, analytics)
+ presenter.onAttachView(loginStudentSelectView, emptyList())
}
@Test
diff --git a/app/src/test/java/io/github/wulkanowy/utils/FlowUtilsKtTest.kt b/app/src/test/java/io/github/wulkanowy/utils/FlowUtilsKtTest.kt
index 375a24038..57045a29d 100644
--- a/app/src/test/java/io/github/wulkanowy/utils/FlowUtilsKtTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/utils/FlowUtilsKtTest.kt
@@ -1,23 +1,21 @@
package io.github.wulkanowy.utils
-import io.mockk.Runs
-import io.mockk.coEvery
-import io.mockk.coVerifyOrder
-import io.mockk.just
-import io.mockk.mockk
+import io.mockk.*
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.sync.Mutex
-import kotlinx.coroutines.test.TestCoroutineScope
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.advanceTimeBy
import org.junit.Test
import kotlin.test.assertEquals
@OptIn(ExperimentalCoroutinesApi::class)
class FlowUtilsKtTest {
- private val testScope = TestCoroutineScope()
+ private val testScope = TestScope(UnconfinedTestDispatcher())
@Test
fun `fetch from two places with same remote data`() {
diff --git a/app/src/test/java/io/github/wulkanowy/utils/TimeExtensionTest.kt b/app/src/test/java/io/github/wulkanowy/utils/TimeExtensionTest.kt
index 0ffbf78ec..70ad6d534 100644
--- a/app/src/test/java/io/github/wulkanowy/utils/TimeExtensionTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/utils/TimeExtensionTest.kt
@@ -1,13 +1,13 @@
package io.github.wulkanowy.utils
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
+import org.junit.Assert.*
import org.junit.Test
+import java.time.Instant
import java.time.LocalDate.of
import java.time.LocalDateTime
import java.time.Month.JANUARY
-import java.util.Locale
+import java.time.ZoneOffset
+import java.util.*
class TimeExtensionTest {
@@ -23,9 +23,16 @@ class TimeExtensionTest {
}
@Test
- fun toFormattedStringLocalDateTimeTest() {
- assertEquals("01.10.2018", LocalDateTime.of(2018, 10, 1, 10, 0, 0).toFormattedString())
- assertEquals("2018-10-01 10:00:00", LocalDateTime.of(2018, 10, 1, 10, 0, 0).toFormattedString("uuuu-MM-dd HH:mm:ss"))
+ fun toFormattedStringFromInstantTest() {
+ assertEquals(
+ "01.10.2018",
+ LocalDateTime.of(2018, 10, 1, 10, 0, 0).toInstant(ZoneOffset.UTC).toFormattedString()
+ )
+ assertEquals(
+ "2018-10-01 10:00:00",
+ LocalDateTime.of(2018, 10, 1, 10, 0, 0).toInstant(ZoneOffset.UTC)
+ .toFormattedString("uuuu-MM-dd HH:mm:ss", ZoneOffset.UTC)
+ )
}
@Test
@@ -222,4 +229,25 @@ class TimeExtensionTest {
assertEquals(of(2020, 10, 18), endExamsDay)
}
}
+
+ @Test
+ fun getLocalDateToTimestamp() {
+ assertEquals(0L, of(1970, 1, 1).toTimestamp())
+ assertEquals(946684800000L, of(2000, 1, 1).toTimestamp())
+ assertEquals(1640131200000L, of(2021, 12, 22).toTimestamp())
+ }
+
+ @Test
+ fun getLocalDateFromInstant() {
+ assertEquals(of(1970, 1, 1), Instant.ofEpochMilli(0).toLocalDate())
+ assertEquals(of(2000, 1, 1), Instant.ofEpochMilli(946684800000).toLocalDate())
+ assertEquals(of(2021, 12, 22), Instant.ofEpochMilli(1640131200000L).toLocalDate())
+ }
+
+ @Test
+ fun timestampToLocalDateTime() {
+ assertEquals(LocalDateTime.of(1970, 1, 1, 0, 0, 0), 0L.toLocalDateTime())
+ assertEquals(LocalDateTime.of(2000, 1, 1, 0, 0, 0), 946684800000.toLocalDateTime())
+ assertEquals(LocalDateTime.of(2021, 12, 22, 0, 0, 0), 1640131200000L.toLocalDateTime())
+ }
}
diff --git a/app/src/test/java/io/github/wulkanowy/utils/TimetableExtensionTest.kt b/app/src/test/java/io/github/wulkanowy/utils/TimetableExtensionTest.kt
index b7fa58c6f..a4d649e26 100644
--- a/app/src/test/java/io/github/wulkanowy/utils/TimetableExtensionTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/utils/TimetableExtensionTest.kt
@@ -6,9 +6,8 @@ import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertTrue
import org.junit.Test
-import java.time.LocalDate
-import java.time.LocalDateTime
-import java.time.LocalDateTime.now
+import java.time.*
+import java.time.Duration.ofMinutes
class TimetableExtensionTest {
@@ -17,52 +16,38 @@ class TimetableExtensionTest {
assertFalse(getTimetableEntity().isShowTimeUntil(null))
assertFalse(getTimetableEntity(isStudentPlan = false).isShowTimeUntil(null))
assertFalse(getTimetableEntity(isStudentPlan = true, canceled = true).isShowTimeUntil(null))
- assertFalse(getTimetableEntity(isStudentPlan = true, canceled = false, start = now().minusSeconds(1)).isShowTimeUntil(null))
- assertFalse(getTimetableEntity(isStudentPlan = true, canceled = false, start = now().plusMinutes(5)).isShowTimeUntil(now().plusMinutes(5)))
- assertFalse(getTimetableEntity(isStudentPlan = true, canceled = false, start = now().plusMinutes(61)).isShowTimeUntil(now().minusMinutes(5)))
+ assertFalse(getTimetableEntity(isStudentPlan = true, canceled = false, start = Instant.now().minusSeconds(1)).isShowTimeUntil(null))
+ assertFalse(getTimetableEntity(isStudentPlan = true, canceled = false, start = Instant.now().plus(ofMinutes(5))).isShowTimeUntil(Instant.now().plus(ofMinutes(5))))
+ assertFalse(getTimetableEntity(isStudentPlan = true, canceled = false, start = Instant.now().plus(ofMinutes(61))).isShowTimeUntil(Instant.now().minus(ofMinutes(5))))
- assertTrue(getTimetableEntity(isStudentPlan = true, canceled = false, start = now().plusMinutes(60)).isShowTimeUntil(now().minusMinutes(5)))
- assertTrue(getTimetableEntity(isStudentPlan = true, canceled = false, start = now().plusMinutes(60)).isShowTimeUntil(null))
+ assertTrue(getTimetableEntity(isStudentPlan = true, canceled = false, start = Instant.now().plus(ofMinutes(60))).isShowTimeUntil(Instant.now().minus(ofMinutes(5))))
+ assertTrue(getTimetableEntity(isStudentPlan = true, canceled = false, start = Instant.now().plus(ofMinutes(60))).isShowTimeUntil(null))
- assertFalse(getTimetableEntity(isStudentPlan = true, canceled = false, start = now().minusSeconds(1)).isShowTimeUntil(null))
+ assertFalse(getTimetableEntity(isStudentPlan = true, canceled = false, start = Instant.now().minusSeconds(1)).isShowTimeUntil(null))
}
@Test
fun getLeft() {
assertEquals(null, getTimetableEntity(canceled = true).left)
- assertEquals(null, getTimetableEntity(start = now().plusMinutes(5), end = now().plusMinutes(50)).left)
- assertEquals(null, getTimetableEntity(start = now().minusMinutes(1), end = now().plusMinutes(44), isStudentPlan = false).left)
- assertNotEquals(
- null,
- getTimetableEntity(
- start = now().minusMinutes(1),
- end = now().plusMinutes(44),
- isStudentPlan = true
- ).left
- )
- assertNotEquals(
- null,
- getTimetableEntity(
- start = now(),
- end = now().plusMinutes(45),
- isStudentPlan = true
- ).left
- )
+ assertEquals(null, getTimetableEntity(start = Instant.now().plus(ofMinutes(5)), end = Instant.now().plus(ofMinutes(50))).left)
+ assertEquals(null, getTimetableEntity(start = Instant.now().minus(ofMinutes(1)), end = Instant.now().plus(ofMinutes(44)), isStudentPlan = false).left)
+ assertNotEquals(null, getTimetableEntity(start = Instant.now().minus(ofMinutes(1)), end = Instant.now().plus(ofMinutes(44)), isStudentPlan = true).left)
+ assertNotEquals(null, getTimetableEntity(start = Instant.now(), end = Instant.now().plus(ofMinutes(45)), isStudentPlan = true).left)
}
@Test
fun isJustFinished() {
- assertFalse(getTimetableEntity(end = now().minusSeconds(16)).isJustFinished)
- assertTrue(getTimetableEntity(end = now().minusSeconds(14)).isJustFinished)
- assertTrue(getTimetableEntity(end = now().minusSeconds(1)).isJustFinished)
- assertFalse(getTimetableEntity(end = now().plusSeconds(1)).isJustFinished)
+ assertFalse(getTimetableEntity(end = Instant.now().minusSeconds(16)).isJustFinished)
+ assertTrue(getTimetableEntity(end = Instant.now().minusSeconds(14)).isJustFinished)
+ assertTrue(getTimetableEntity(end = Instant.now().minusSeconds(1)).isJustFinished)
+ assertFalse(getTimetableEntity(end = Instant.now().plusSeconds(1)).isJustFinished)
}
private fun getTimetableEntity(
isStudentPlan: Boolean = false,
canceled: Boolean = false,
- start: LocalDateTime = now(),
- end: LocalDateTime = now()
+ start: Instant = Instant.now(),
+ end: Instant = Instant.now()
) = Timetable(
studentId = 0,
subject = "",
diff --git a/build.gradle b/build.gradle
index bd74bab41..b06af2e16 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,6 @@
buildscript {
ext {
- kotlin_version = '1.6.0'
+ kotlin_version = '1.6.10'
about_libraries = '8.9.4'
hilt_version = "2.40.5"
}
@@ -16,7 +16,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:7.0.4'
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.google.gms:google-services:4.3.10'
- classpath 'com.huawei.agconnect:agcp:1.6.2.300'
+ classpath 'com.huawei.agconnect:agcp:1.6.3.200'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
classpath "com.github.triplet.gradle:play-publisher:3.6.0"
classpath "ru.cian:huawei-publish-gradle-plugin:1.3.0"