From 9d47127921d5a1d8bff07bb708e284f00ef10bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Mon, 22 Aug 2022 14:30:50 +0200 Subject: [PATCH] Add support for messages plus API (#1945) --- app/build.gradle | 2 +- .../51.json | 2409 +++++++++++++++++ .../io/github/wulkanowy/data/DataModule.kt | 4 +- .../github/wulkanowy/data/db/AppDatabase.kt | 9 +- .../wulkanowy/data/db/dao/MailboxDao.kt | 17 + .../wulkanowy/data/db/dao/MessagesDao.kt | 8 +- .../wulkanowy/data/db/dao/RecipientDao.kt | 5 +- .../wulkanowy/data/db/dao/ReportingUnitDao.kt | 17 - .../wulkanowy/data/db/entities/Mailbox.kt | 25 + .../wulkanowy/data/db/entities/Message.kt | 27 +- .../data/db/entities/MessageAttachment.kt | 7 +- .../data/db/entities/MessageWithAttachment.kt | 2 +- .../wulkanowy/data/db/entities/Recipient.kt | 31 +- .../data/db/entities/ReportingUnit.kt | 32 - .../data/db/migrations/Migration51.kt | 88 + .../wulkanowy/data/mappers/MailboxMapper.kt | 18 + .../wulkanowy/data/mappers/MessageMapper.kt | 46 +- .../wulkanowy/data/mappers/RecipientMapper.kt | 17 +- .../data/mappers/ReportingUnitMapper.kt | 16 - .../data/repositories/MailboxRepository.kt | 48 + .../data/repositories/MessageRepository.kt | 114 +- .../data/repositories/RecipientRepository.kt | 37 +- .../repositories/ReportingUnitRepository.kt | 53 - .../notifications/NewMessageNotification.kt | 2 +- .../services/sync/works/MessageWork.kt | 7 +- .../services/sync/works/RecipientWork.kt | 15 +- .../modules/dashboard/DashboardPresenter.kt | 4 +- .../debug/notification/mock/message.kt | 13 +- .../message/preview/MessagePreviewAdapter.kt | 26 +- .../message/preview/MessagePreviewFragment.kt | 4 +- .../preview/MessagePreviewPresenter.kt | 114 +- .../message/preview/MessagePreviewView.kt | 2 +- .../message/send/SendMessageActivity.kt | 31 +- .../message/send/SendMessagePresenter.kt | 128 +- .../modules/message/send/SendMessageView.kt | 12 +- .../modules/message/tab/MessageTabAdapter.kt | 11 +- .../message/tab/MessageTabPresenter.kt | 22 +- .../main/res/layout/activity_send_message.xml | 3 +- app/src/main/res/values/strings.xml | 5 +- .../io/github/wulkanowy/TestEnityCreator.kt | 12 + .../repositories/MessageRepositoryTest.kt | 116 +- .../data/repositories/RecipientLocalTest.kt | 81 +- 42 files changed, 3065 insertions(+), 575 deletions(-) create mode 100644 app/schemas/io.github.wulkanowy.data.db.AppDatabase/51.json create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/dao/MailboxDao.kt delete mode 100644 app/src/main/java/io/github/wulkanowy/data/db/dao/ReportingUnitDao.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/entities/Mailbox.kt delete mode 100644 app/src/main/java/io/github/wulkanowy/data/db/entities/ReportingUnit.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration51.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/mappers/MailboxMapper.kt delete mode 100644 app/src/main/java/io/github/wulkanowy/data/mappers/ReportingUnitMapper.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt delete mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/ReportingUnitRepository.kt diff --git a/app/build.gradle b/app/build.gradle index 6d33ac47..0efb9c30 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -186,7 +186,7 @@ ext { } dependencies { - implementation "io.github.wulkanowy:sdk:9032e33686" + implementation "io.github.wulkanowy:sdk:dbe87aac" coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/51.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/51.json new file mode 100644 index 00000000..271b8c90 --- /dev/null +++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/51.json @@ -0,0 +1,2409 @@ +{ + "formatVersion": 1, + "database": { + "version": 51, + "identityHash": "51f9cb1d80df003c03bb655c0162487c", + "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}` (`message_global_key` TEXT NOT NULL, `mailbox_key` TEXT NOT NULL, `message_id` INTEGER NOT NULL, `correspondents` TEXT NOT NULL, `subject` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `has_attachments` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `content` TEXT NOT NULL, `sender` TEXT, `recipients` TEXT)", + "fields": [ + { + "fieldPath": "messageGlobalKey", + "columnName": "message_global_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "mailboxKey", + "columnName": "mailbox_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "correspondents", + "columnName": "correspondents", + "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": "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": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sender", + "columnName": "sender", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "recipients", + "columnName": "recipients", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "MessageAttachments", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`real_id` INTEGER NOT NULL, `message_global_key` 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": "messageGlobalKey", + "columnName": "message_global_key", + "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": "Mailboxes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`globalKey` TEXT NOT NULL, `fullName` TEXT NOT NULL, `userName` TEXT NOT NULL, `userLoginId` INTEGER NOT NULL, `studentName` TEXT NOT NULL, `schoolNameShort` TEXT NOT NULL, `type` TEXT NOT NULL, PRIMARY KEY(`globalKey`))", + "fields": [ + { + "fieldPath": "globalKey", + "columnName": "globalKey", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fullName", + "columnName": "fullName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userName", + "columnName": "userName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userLoginId", + "columnName": "userLoginId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentName", + "columnName": "studentName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolNameShort", + "columnName": "schoolNameShort", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "globalKey" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Recipients", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`mailboxGlobalKey` TEXT NOT NULL, `studentMailboxGlobalKey` TEXT NOT NULL, `fullName` TEXT NOT NULL, `userName` TEXT NOT NULL, `schoolShortName` TEXT NOT NULL, `type` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", + "fields": [ + { + "fieldPath": "mailboxGlobalKey", + "columnName": "mailboxGlobalKey", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentMailboxGlobalKey", + "columnName": "studentMailboxGlobalKey", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fullName", + "columnName": "fullName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userName", + "columnName": "userName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolShortName", + "columnName": "schoolShortName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "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}` (`user_login_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": "user_login_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}` (`user_login_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": "userLoginId", + "columnName": "user_login_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, `destination` TEXT NOT NULL DEFAULT '{\"type\":\"io.github.wulkanowy.ui.modules.Destination.Dashboard\"}', `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": "destination", + "columnName": "destination", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'{\"type\":\"io.github.wulkanowy.ui.modules.Destination.Dashboard\"}'" + }, + { + "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, '51f9cb1d80df003c03bb655c0162487c')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/io/github/wulkanowy/data/DataModule.kt b/app/src/main/java/io/github/wulkanowy/data/DataModule.kt index cac3ffc2..22123cbe 100644 --- a/app/src/main/java/io/github/wulkanowy/data/DataModule.kt +++ b/app/src/main/java/io/github/wulkanowy/data/DataModule.kt @@ -19,7 +19,6 @@ import io.github.wulkanowy.data.db.SharedPrefProvider import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.utils.AppInfo -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json import okhttp3.MediaType.Companion.toMediaType @@ -110,7 +109,6 @@ internal class DataModule { fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) - @OptIn(ExperimentalCoroutinesApi::class) @Singleton @Provides fun provideFlowSharedPref(sharedPreferences: SharedPreferences) = @@ -197,7 +195,7 @@ internal class DataModule { @Singleton @Provides - fun provideReportingUnitDao(database: AppDatabase) = database.reportingUnitDao + fun provideMailboxesDao(database: AppDatabase) = database.mailboxDao @Singleton @Provides diff --git a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt index 87915a9e..15b38805 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt @@ -30,7 +30,7 @@ import javax.inject.Singleton Subject::class, LuckyNumber::class, CompletedLesson::class, - ReportingUnit::class, + Mailbox::class, Recipient::class, MobileDevice::class, Teacher::class, @@ -55,7 +55,7 @@ import javax.inject.Singleton abstract class AppDatabase : RoomDatabase() { companion object { - const val VERSION_SCHEMA = 50 + const val VERSION_SCHEMA = 51 fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf( Migration2(), @@ -103,7 +103,8 @@ abstract class AppDatabase : RoomDatabase() { Migration44(), Migration46(), Migration49(), - Migration50() + Migration50(), + Migration51(), ) fun newInstance( @@ -154,7 +155,7 @@ abstract class AppDatabase : RoomDatabase() { abstract val completedLessonsDao: CompletedLessonsDao - abstract val reportingUnitDao: ReportingUnitDao + abstract val mailboxDao: MailboxDao abstract val recipientDao: RecipientDao diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/MailboxDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/MailboxDao.kt new file mode 100644 index 00000000..8589db31 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/MailboxDao.kt @@ -0,0 +1,17 @@ +package io.github.wulkanowy.data.db.dao + +import androidx.room.Dao +import androidx.room.Query +import io.github.wulkanowy.data.db.entities.Mailbox +import javax.inject.Singleton + +@Singleton +@Dao +interface MailboxDao : BaseDao { + + @Query("SELECT * FROM Mailboxes WHERE userLoginId = :userLoginId ") + suspend fun loadAll(userLoginId: Int): List + + @Query("SELECT * FROM Mailboxes WHERE userLoginId = :userLoginId AND studentName = :studentName ") + suspend fun load(userLoginId: Int, studentName: String): Mailbox? +} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt index 729ba6a6..8c730c9b 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt @@ -11,9 +11,9 @@ import kotlinx.coroutines.flow.Flow interface MessagesDao : BaseDao { @Transaction - @Query("SELECT * FROM Messages WHERE student_id = :studentId AND message_id = :messageId") - fun loadMessageWithAttachment(studentId: Int, messageId: Int): Flow + @Query("SELECT * FROM Messages WHERE message_global_key = :messageGlobalKey") + fun loadMessageWithAttachment(messageGlobalKey: String): Flow - @Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder ORDER BY date DESC") - fun loadAll(studentId: Int, folder: Int): Flow> + @Query("SELECT * FROM Messages WHERE mailbox_key = :mailboxKey AND folder_id = :folder ORDER BY date DESC") + fun loadAll(mailboxKey: String, folder: Int): Flow> } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/RecipientDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/RecipientDao.kt index c2787ac3..1956261e 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/RecipientDao.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/RecipientDao.kt @@ -2,6 +2,7 @@ package io.github.wulkanowy.data.db.dao import androidx.room.Dao import androidx.room.Query +import io.github.wulkanowy.data.db.entities.MailboxType import io.github.wulkanowy.data.db.entities.Recipient import javax.inject.Singleton @@ -9,6 +10,6 @@ import javax.inject.Singleton @Dao interface RecipientDao : BaseDao { - @Query("SELECT * FROM Recipients WHERE student_id = :studentId AND unit_id = :unitId AND role = :role") - suspend fun loadAll(studentId: Int, unitId: Int, role: Int): List + @Query("SELECT * FROM Recipients WHERE type = :type AND studentMailboxGlobalKey = :studentMailboxGlobalKey") + suspend fun loadAll(type: MailboxType, studentMailboxGlobalKey: String): List } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/ReportingUnitDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/ReportingUnitDao.kt deleted file mode 100644 index ca697eda..00000000 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/ReportingUnitDao.kt +++ /dev/null @@ -1,17 +0,0 @@ -package io.github.wulkanowy.data.db.dao - -import androidx.room.Dao -import androidx.room.Query -import io.github.wulkanowy.data.db.entities.ReportingUnit -import javax.inject.Singleton - -@Singleton -@Dao -interface ReportingUnitDao : BaseDao { - - @Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId") - suspend fun load(studentId: Int): List - - @Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId AND real_id = :unitId") - suspend fun loadOne(studentId: Int, unitId: Int): ReportingUnit? -} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Mailbox.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Mailbox.kt new file mode 100644 index 00000000..7c08e481 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Mailbox.kt @@ -0,0 +1,25 @@ +package io.github.wulkanowy.data.db.entities + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "Mailboxes") +data class Mailbox( + + @PrimaryKey + val globalKey: String, + val fullName: String, + val userName: String, + val userLoginId: Int, + val studentName: String, + val schoolNameShort: String, + val type: MailboxType, +) + +enum class MailboxType { + STUDENT, + PARENT, + GUARDIAN, + EMPLOYEE, + UNKNOWN, +} 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 8782bc76..77874e03 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 @@ -9,23 +9,16 @@ import java.time.Instant @Entity(tableName = "Messages") data class Message( - @ColumnInfo(name = "student_id") - val studentId: Long, + @ColumnInfo(name = "message_global_key") + val messageGlobalKey: String, - @ColumnInfo(name = "real_id") - val realId: Int, + @ColumnInfo(name = "mailbox_key") + val mailboxKey: String, @ColumnInfo(name = "message_id") val messageId: Int, - @ColumnInfo(name = "sender_name") - val sender: String, - - @ColumnInfo(name = "sender_id") - val senderId: Int, - - @ColumnInfo(name = "recipient_name") - val recipient: String, + val correspondents: String, val subject: String, @@ -36,8 +29,6 @@ data class Message( var unread: Boolean, - val removed: Boolean, - @ColumnInfo(name = "has_attachments") val hasAttachments: Boolean ) : Serializable { @@ -48,11 +39,7 @@ data class Message( @ColumnInfo(name = "is_notified") var isNotified: Boolean = true - @ColumnInfo(name = "unread_by") - var unreadBy: Int = 0 - - @ColumnInfo(name = "read_by") - var readBy: Int = 0 - var content: String = "" + var sender: String? = null + var recipients: String? = null } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageAttachment.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageAttachment.kt index d1886e91..93f04299 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageAttachment.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageAttachment.kt @@ -12,11 +12,8 @@ data class MessageAttachment( @ColumnInfo(name = "real_id") val realId: Int, - @ColumnInfo(name = "message_id") - val messageId: Int, - - @ColumnInfo(name = "one_drive_id") - val oneDriveId: String, + @ColumnInfo(name = "message_global_key") + val messageGlobalKey: String, @ColumnInfo(name = "url") val url: String, diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageWithAttachment.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageWithAttachment.kt index 2e7af0f4..cd468215 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageWithAttachment.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageWithAttachment.kt @@ -7,6 +7,6 @@ data class MessageWithAttachment( @Embedded val message: Message, - @Relation(parentColumn = "message_id", entityColumn = "message_id") + @Relation(parentColumn = "message_global_key", entityColumn = "message_global_key") val attachments: List ) diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Recipient.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Recipient.kt index 22332270..d09742cd 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Recipient.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Recipient.kt @@ -1,6 +1,5 @@ package io.github.wulkanowy.data.db.entities -import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey import java.io.Serializable @@ -8,32 +7,16 @@ import java.io.Serializable @kotlinx.serialization.Serializable @Entity(tableName = "Recipients") data class Recipient( - - @ColumnInfo(name = "student_id") - val studentId: Int, - - @ColumnInfo(name = "real_id") - val realId: String, - - val name: String, - - @ColumnInfo(name = "real_name") - val realName: String, - - @ColumnInfo(name = "login_id") - val loginId: Int, - - @ColumnInfo(name = "unit_id") - val unitId: Int, - - val role: Int, - - val hash: String - + val mailboxGlobalKey: String, + val studentMailboxGlobalKey: String, + val fullName: String, + val userName: String, + val schoolShortName: String, + val type: MailboxType, ) : Serializable { @PrimaryKey(autoGenerate = true) var id: Long = 0 - override fun toString() = name + override fun toString() = userName } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/ReportingUnit.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/ReportingUnit.kt deleted file mode 100644 index 0570a2ff..00000000 --- a/app/src/main/java/io/github/wulkanowy/data/db/entities/ReportingUnit.kt +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.wulkanowy.data.db.entities - -import androidx.room.ColumnInfo -import androidx.room.Entity -import androidx.room.PrimaryKey -import java.io.Serializable - -@Entity(tableName = "ReportingUnits") -data class ReportingUnit( - - @ColumnInfo(name = "student_id") - val studentId: Int, - - @ColumnInfo(name = "real_id") - val unitId: Int, - - @ColumnInfo(name = "short") - val shortName: String, - - @ColumnInfo(name = "sender_id") - val senderId: Int, - - @ColumnInfo(name = "sender_name") - val senderName: String, - - val roles: List - -) : Serializable { - - @PrimaryKey(autoGenerate = true) - var id: Long = 0 -} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration51.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration51.kt new file mode 100644 index 00000000..e78e2e3a --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration51.kt @@ -0,0 +1,88 @@ +package io.github.wulkanowy.data.db.migrations + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +class Migration51 : Migration(50, 51) { + + override fun migrate(database: SupportSQLiteDatabase) { + createMailboxTable(database) + recreateMessagesTable(database) + recreateMessageAttachmentsTable(database) + recreateRecipientsTable(database) + deleteReportingUnitTable(database) + } + + private fun createMailboxTable(database: SupportSQLiteDatabase) { + database.execSQL("DROP TABLE IF EXISTS Mailboxes") + database.execSQL( + """ + CREATE TABLE IF NOT EXISTS `Mailboxes` ( + `globalKey` TEXT NOT NULL, + `fullName` TEXT NOT NULL, + `userName` TEXT NOT NULL, + `userLoginId` INTEGER NOT NULL, + `studentName` TEXT NOT NULL, + `schoolNameShort` TEXT NOT NULL, + `type` TEXT NOT NULL, + PRIMARY KEY(`globalKey`) + )""".trimIndent() + ) + } + + private fun recreateMessagesTable(database: SupportSQLiteDatabase) { + database.execSQL("DROP TABLE IF EXISTS Messages") + database.execSQL( + """ + CREATE TABLE IF NOT EXISTS `Messages` ( + `message_global_key` TEXT NOT NULL, + `mailbox_key` TEXT NOT NULL, + `message_id` INTEGER NOT NULL, + `correspondents` TEXT NOT NULL, + `subject` TEXT NOT NULL, + `date` INTEGER NOT NULL, + `folder_id` INTEGER NOT NULL, + `unread` INTEGER NOT NULL, + `has_attachments` INTEGER NOT NULL, + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + `is_notified` INTEGER NOT NULL, + `content` TEXT NOT NULL, + `sender` TEXT, `recipients` TEXT + )""".trimIndent() + ) + } + + private fun recreateMessageAttachmentsTable(database: SupportSQLiteDatabase) { + database.execSQL("DROP TABLE IF EXISTS MessageAttachments") + database.execSQL( + """ + CREATE TABLE IF NOT EXISTS `MessageAttachments` ( + `real_id` INTEGER NOT NULL, + `message_global_key` TEXT NOT NULL, + `url` TEXT NOT NULL, + `filename` TEXT NOT NULL, + PRIMARY KEY(`real_id`) + )""".trimIndent() + ) + } + + private fun recreateRecipientsTable(database: SupportSQLiteDatabase) { + database.execSQL("DROP TABLE IF EXISTS Recipients") + database.execSQL( + """ + CREATE TABLE IF NOT EXISTS `Recipients` ( + `mailboxGlobalKey` TEXT NOT NULL, + `studentMailboxGlobalKey` TEXT NOT NULL, + `fullName` TEXT NOT NULL, + `userName` TEXT NOT NULL, + `schoolShortName` TEXT NOT NULL, + `type` TEXT NOT NULL, + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL + )""".trimIndent() + ) + } + + private fun deleteReportingUnitTable(database: SupportSQLiteDatabase) { + database.execSQL("DROP TABLE IF EXISTS ReportingUnits") + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/MailboxMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/MailboxMapper.kt new file mode 100644 index 00000000..2ccca1b9 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/mappers/MailboxMapper.kt @@ -0,0 +1,18 @@ +package io.github.wulkanowy.data.mappers + +import io.github.wulkanowy.data.db.entities.Mailbox +import io.github.wulkanowy.data.db.entities.MailboxType +import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.sdk.pojo.Mailbox as SdkMailbox + +fun List.mapToEntities(student: Student) = map { + Mailbox( + globalKey = it.globalKey, + fullName = it.fullName, + userName = it.userName, + userLoginId = student.userLoginId, + studentName = it.studentName, + schoolNameShort = it.schoolNameShort, + type = MailboxType.valueOf(it.type.name), + ) +} 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 13f0ab33..2e7967f0 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 @@ -1,40 +1,31 @@ package io.github.wulkanowy.data.mappers -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.Instant +import io.github.wulkanowy.data.db.entities.* +import io.github.wulkanowy.sdk.pojo.MailboxType 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 -fun List.mapToEntities(student: Student) = map { +fun List.mapToEntities(mailbox: Mailbox) = map { Message( - studentId = student.id, - realId = it.id ?: 0, - messageId = it.messageId ?: 0, - sender = it.sender?.name.orEmpty(), - senderId = it.sender?.loginId ?: 0, - recipient = it.recipients.singleOrNull()?.name ?: "Wielu adresatów", + messageGlobalKey = it.globalKey, + mailboxKey = mailbox.globalKey, + messageId = it.id, + correspondents = it.correspondents, subject = it.subject.trim(), - date = it.dateZoned?.toInstant() ?: Instant.now(), + date = it.dateZoned.toInstant(), folderId = it.folderId, - unread = it.unread ?: false, - removed = it.removed, + unread = it.unread, hasAttachments = it.hasAttachments ).apply { content = it.content.orEmpty() - unreadBy = it.unreadBy ?: 0 - readBy = it.readBy ?: 0 } } -fun List.mapToEntities() = map { +fun List.mapToEntities(messageGlobalKey: String) = map { MessageAttachment( - realId = it.id, - messageId = it.messageId, - oneDriveId = it.oneDriveId, + messageGlobalKey = messageGlobalKey, + realId = it.url.hashCode(), url = it.url, filename = it.filename ) @@ -42,12 +33,11 @@ fun List.mapToEntities() = map { fun List.mapFromEntities() = map { SdkRecipient( - id = it.realId, - name = it.realName, - loginId = it.loginId, - reportingUnitId = it.unitId, - role = it.role, - hash = it.hash, - shortName = it.name + fullName = it.fullName, + userName = it.userName, + studentName = it.userName, + mailboxGlobalKey = it.mailboxGlobalKey, + schoolNameShort = it.schoolShortName, + type = MailboxType.valueOf(it.type.name), ) } diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/RecipientMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/RecipientMapper.kt index 80bddaab..eb993a0f 100644 --- a/app/src/main/java/io/github/wulkanowy/data/mappers/RecipientMapper.kt +++ b/app/src/main/java/io/github/wulkanowy/data/mappers/RecipientMapper.kt @@ -1,17 +1,16 @@ package io.github.wulkanowy.data.mappers +import io.github.wulkanowy.data.db.entities.MailboxType import io.github.wulkanowy.data.db.entities.Recipient import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient -fun List.mapToEntities(userLoginId: Int) = map { +fun List.mapToEntities(studentMailboxGlobalKey: String) = map { Recipient( - studentId = userLoginId, - realId = it.id, - realName = it.name, - name = it.shortName, - hash = it.hash, - loginId = it.loginId, - role = it.role, - unitId = it.reportingUnitId ?: 0 + mailboxGlobalKey = it.mailboxGlobalKey, + fullName = it.fullName, + userName = it.userName, + studentMailboxGlobalKey = studentMailboxGlobalKey, + schoolShortName = it.schoolNameShort, + type = MailboxType.valueOf(it.type.name), ) } diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/ReportingUnitMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/ReportingUnitMapper.kt deleted file mode 100644 index 6a21d59f..00000000 --- a/app/src/main/java/io/github/wulkanowy/data/mappers/ReportingUnitMapper.kt +++ /dev/null @@ -1,16 +0,0 @@ -package io.github.wulkanowy.data.mappers - -import io.github.wulkanowy.data.db.entities.ReportingUnit -import io.github.wulkanowy.data.db.entities.Student -import io.github.wulkanowy.sdk.pojo.ReportingUnit as SdkReportingUnit - -fun List.mapToEntities(student: Student) = map { - ReportingUnit( - studentId = student.id.toInt(), - unitId = it.id, - roles = it.roles, - senderId = it.senderId, - senderName = it.senderName, - shortName = it.short - ) -} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt new file mode 100644 index 00000000..7f597492 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt @@ -0,0 +1,48 @@ +package io.github.wulkanowy.data.repositories + +import io.github.wulkanowy.data.db.dao.MailboxDao +import io.github.wulkanowy.data.db.entities.Mailbox +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.uniqueSubtract +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class MailboxRepository @Inject constructor( + private val mailboxDao: MailboxDao, + private val sdk: Sdk, + private val refreshHelper: AutoRefreshHelper, +) { + private val cacheKey = "mailboxes" + + suspend fun refreshMailboxes(student: Student) { + val new = sdk.init(student).getMailboxes().mapToEntities(student) + val old = mailboxDao.loadAll(student.userLoginId) + + mailboxDao.deleteAll(old uniqueSubtract new) + mailboxDao.insertAll(new uniqueSubtract old) + + refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student)) + } + + suspend fun getMailbox(student: Student): Mailbox { + val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student)) + val mailbox = mailboxDao.load(student.userLoginId, student.studentName) + + return if (isExpired || mailbox == null) { + refreshMailboxes(student) + val newMailbox = mailboxDao.load(student.userLoginId, student.studentName) + + requireNotNull(newMailbox) { + "Mailbox for ${student.userName} - ${student.studentName} not found!" + } + + newMailbox + } else mailbox + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt index 05fb9765..00cbffb8 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt @@ -10,24 +10,24 @@ import io.github.wulkanowy.data.db.dao.MessagesDao import io.github.wulkanowy.data.db.entities.* import io.github.wulkanowy.data.enums.MessageFolder import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED +import io.github.wulkanowy.data.enums.MessageFolder.TRASHED import io.github.wulkanowy.data.mappers.mapFromEntities import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.pojos.MessageDraft import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.pojo.Folder -import io.github.wulkanowy.sdk.pojo.SentMessage import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.uniqueSubtract import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first import kotlinx.coroutines.sync.Mutex import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import timber.log.Timber -import java.time.LocalDateTime.now import javax.inject.Inject import javax.inject.Singleton @@ -49,7 +49,7 @@ class MessageRepository @Inject constructor( @Suppress("UNUSED_PARAMETER") fun getMessages( student: Student, - semester: Semester, + mailbox: Mailbox, folder: MessageFolder, forceRefresh: Boolean, notify: Boolean = false, @@ -62,42 +62,20 @@ class MessageRepository @Inject constructor( ) it.isEmpty() || forceRefresh || isExpired }, - query = { messagesDb.loadAll(student.id.toInt(), folder.id) }, + query = { messagesDb.loadAll(mailbox.globalKey, folder.id) }, fetch = { - sdk.init(student).getMessages(Folder.valueOf(folder.name), now().minusMonths(3), now()) - .mapToEntities(student) + sdk.init(student).getMessages(Folder.valueOf(folder.name)).mapToEntities(mailbox) }, saveFetchResult = { old, new -> messagesDb.deleteAll(old uniqueSubtract new) messagesDb.insertAll((new uniqueSubtract old).onEach { it.isNotified = !notify }) - messagesDb.updateAll(getMessagesWithReadByChange(old, new, !notify)) refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student, folder)) } ) - private fun getMessagesWithReadByChange( - old: List, - new: List, - setNotified: Boolean - ): List { - val oldMeta = old.map { Triple(it, it.readBy, it.unreadBy) } - val newMeta = new.map { Triple(it, it.readBy, it.unreadBy) } - - val updatedItems = newMeta uniqueSubtract oldMeta - - return updatedItems.map { - val oldItem = old.find { item -> item.messageId == it.first.messageId } - it.first.apply { - id = oldItem?.id ?: 0 - isNotified = oldItem?.isNotified ?: setNotified - content = oldItem?.content.orEmpty() - } - } - } - fun getMessage( student: Student, message: Message, @@ -106,34 +84,34 @@ class MessageRepository @Inject constructor( isResultEmpty = { it?.message?.content.isNullOrBlank() }, shouldFetch = { checkNotNull(it) { "This message no longer exist!" } - Timber.d("Message content in db empty: ${it.message.content.isEmpty()}") - it.message.unread || it.message.content.isEmpty() + Timber.d("Message content in db empty: ${it.message.content.isBlank()}") + it.message.unread || it.message.content.isBlank() }, - query = { messagesDb.loadMessageWithAttachment(student.id.toInt(), message.messageId) }, + query = { messagesDb.loadMessageWithAttachment(message.messageGlobalKey) }, fetch = { - sdk.init(student).getMessageDetails( - messageId = it!!.message.messageId, - folderId = message.folderId, - read = markAsRead, - id = message.realId - ).let { details -> - details.content to details.attachments.mapToEntities() - } + sdk.init(student).getMessageDetails(it!!.message.messageGlobalKey) }, - saveFetchResult = { old, (downloadedMessage, attachments) -> + saveFetchResult = { old, new -> checkNotNull(old) { "Fetched message no longer exist!" } - messagesDb.updateAll(listOf(old.message.apply { - id = old.message.id - unread = !markAsRead - content = content.ifBlank { downloadedMessage } - })) - messageAttachmentDao.insertAttachments(attachments) + messagesDb.updateAll( + listOf(old.message.apply { + id = message.id + unread = !markAsRead + sender = new.sender + recipients = new.recipients.firstOrNull() ?: "Wielu adresoatów" + content = content.ifBlank { new.content } + }) + ) + messageAttachmentDao.insertAttachments( + items = new.attachments.mapToEntities(message.messageGlobalKey), + ) + Timber.d("Message ${message.messageId} with blank content: ${old.message.content.isBlank()}, marked as read") } ) - fun getMessagesFromDatabase(student: Student): Flow> { - return messagesDb.loadAll(student.id.toInt(), RECEIVED.id) + fun getMessagesFromDatabase(mailbox: Mailbox): Flow> { + return messagesDb.loadAll(mailbox.globalKey, RECEIVED.id) } suspend fun updateMessages(messages: List) { @@ -145,32 +123,48 @@ class MessageRepository @Inject constructor( subject: String, content: String, recipients: List, - ): SentMessage = sdk.init(student).sendMessage( - subject = subject, - content = content, - recipients = recipients.mapFromEntities() - ) + mailboxId: String, + ) { + sdk.init(student).sendMessage( + subject = subject, + content = content, + recipients = recipients.mapFromEntities(), + mailboxId = mailboxId, + ) + } - suspend fun deleteMessages(student: Student, messages: List) { - val folderId = messages.first().folderId - val isDeleted = sdk.init(student) - .deleteMessages(messages = messages.map { it.messageId }, folderId = folderId) + suspend fun deleteMessages(student: Student, mailbox: Mailbox, messages: List) { + val firstMessage = messages.first() + sdk.init(student).deleteMessages( + messages = messages.map { it.messageGlobalKey }, + removeForever = firstMessage.folderId == TRASHED.id, + ) - if (folderId != MessageFolder.TRASHED.id && isDeleted) { + if (firstMessage.folderId != TRASHED.id) { val deletedMessages = messages.map { - it.copy(folderId = MessageFolder.TRASHED.id) + it.copy(folderId = TRASHED.id) .apply { id = it.id content = it.content + sender = it.sender + recipients = it.recipients } } messagesDb.updateAll(deletedMessages) } else messagesDb.deleteAll(messages) + + getMessages( + student = student, + mailbox = mailbox, + folder = TRASHED, + forceRefresh = true, + ).first() } - suspend fun deleteMessage(student: Student, message: Message) = - deleteMessages(student, listOf(message)) + suspend fun deleteMessage(student: Student, mailbox: Mailbox, message: Message) { + deleteMessages(student, mailbox, listOf(message)) + } var draftMessage: MessageDraft? get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_send_draft)) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/RecipientRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/RecipientRepository.kt index 60e6f248..e80f028e 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/RecipientRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/RecipientRepository.kt @@ -1,10 +1,7 @@ package io.github.wulkanowy.data.repositories import io.github.wulkanowy.data.db.dao.RecipientDao -import io.github.wulkanowy.data.db.entities.Message -import io.github.wulkanowy.data.db.entities.Recipient -import io.github.wulkanowy.data.db.entities.ReportingUnit -import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.data.db.entities.* import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.utils.AutoRefreshHelper @@ -23,9 +20,10 @@ class RecipientRepository @Inject constructor( private val cacheKey = "recipient" - suspend fun refreshRecipients(student: Student, unit: ReportingUnit, role: Int) { - val new = sdk.init(student).getRecipients(unit.unitId, role).mapToEntities(unit.studentId) - val old = recipientDb.loadAll(unit.studentId, unit.unitId, role) + suspend fun refreshRecipients(student: Student, mailbox: Mailbox, type: MailboxType) { + val new = sdk.init(student).getRecipients(mailbox.globalKey) + .mapToEntities(mailbox.globalKey) + val old = recipientDb.loadAll(type, mailbox.globalKey) recipientDb.deleteAll(old uniqueSubtract new) recipientDb.insertAll(new uniqueSubtract old) @@ -33,18 +31,27 @@ class RecipientRepository @Inject constructor( refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student)) } - suspend fun getRecipients(student: Student, unit: ReportingUnit, role: Int): List { - val cached = recipientDb.loadAll(unit.studentId, unit.unitId, role) + suspend fun getRecipients( + student: Student, + mailbox: Mailbox, + type: MailboxType + ): List { + val cached = recipientDb.loadAll(type, mailbox.globalKey) val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student)) return if (cached.isEmpty() || isExpired) { - refreshRecipients(student, unit, role) - recipientDb.loadAll(unit.studentId, unit.unitId, role) + refreshRecipients(student, mailbox, type) + recipientDb.loadAll(type, mailbox.globalKey) } else cached } - suspend fun getMessageRecipients(student: Student, message: Message): List { - return sdk.init(student).getMessageRecipients(message.messageId, message.senderId) - .mapToEntities(student.studentId) - } + suspend fun getMessageSender( + student: Student, + mailbox: Mailbox, + message: Message + ): List = sdk.init(student) + .getMessageReplayDetails(message.messageGlobalKey) + .sender + .let(::listOf) + .mapToEntities(mailbox.globalKey) } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/ReportingUnitRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/ReportingUnitRepository.kt deleted file mode 100644 index 84055cef..00000000 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/ReportingUnitRepository.kt +++ /dev/null @@ -1,53 +0,0 @@ -package io.github.wulkanowy.data.repositories - -import io.github.wulkanowy.data.db.dao.ReportingUnitDao -import io.github.wulkanowy.data.db.entities.ReportingUnit -import io.github.wulkanowy.data.db.entities.Student -import io.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.uniqueSubtract -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class ReportingUnitRepository @Inject constructor( - private val reportingUnitDb: ReportingUnitDao, - private val sdk: Sdk, - private val refreshHelper: AutoRefreshHelper, -) { - - private val cacheKey = "reporting_unit" - - suspend fun refreshReportingUnits(student: Student) { - val new = sdk.init(student).getReportingUnits().mapToEntities(student) - val old = reportingUnitDb.load(student.id.toInt()) - - reportingUnitDb.deleteAll(old.uniqueSubtract(new)) - reportingUnitDb.insertAll(new.uniqueSubtract(old)) - - refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student)) - } - - suspend fun getReportingUnits(student: Student): List { - val cached = reportingUnitDb.load(student.id.toInt()) - val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student)) - - return if (cached.isEmpty() || isExpired) { - refreshReportingUnits(student) - reportingUnitDb.load(student.id.toInt()) - } else cached - } - - suspend fun getReportingUnit(student: Student, unitId: Int): ReportingUnit? { - val cached = reportingUnitDb.loadOne(student.id.toInt(), unitId) - val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student)) - - return if (cached == null || isExpired) { - refreshReportingUnits(student) - reportingUnitDb.loadOne(student.id.toInt(), unitId) - } else cached - } -} diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewMessageNotification.kt b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewMessageNotification.kt index 5c3c52c5..3b7bcff0 100644 --- a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewMessageNotification.kt +++ b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewMessageNotification.kt @@ -21,7 +21,7 @@ class NewMessageNotification @Inject constructor( val notificationDataList = items.map { NotificationData( title = context.getPlural(R.plurals.message_new_items, 1), - content = "${it.sender}: ${it.subject}", + content = "${it.correspondents}: ${it.subject}", destination = Destination.Message, ) } 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 26fac1a2..18056826 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 @@ -3,6 +3,7 @@ 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.enums.MessageFolder.RECEIVED +import io.github.wulkanowy.data.repositories.MailboxRepository import io.github.wulkanowy.data.repositories.MessageRepository import io.github.wulkanowy.data.waitForResult import io.github.wulkanowy.services.sync.notifications.NewMessageNotification @@ -11,19 +12,21 @@ import javax.inject.Inject class MessageWork @Inject constructor( private val messageRepository: MessageRepository, + private val mailboxRepository: MailboxRepository, private val newMessageNotification: NewMessageNotification, ) : Work { override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) { + val mailbox = mailboxRepository.getMailbox(student) messageRepository.getMessages( student = student, - semester = semester, + mailbox = mailbox, folder = RECEIVED, forceRefresh = true, notify = notify ).waitForResult() - messageRepository.getMessagesFromDatabase(student).first() + messageRepository.getMessagesFromDatabase(mailbox).first() .filter { !it.isNotified && it.unread }.let { if (it.isNotEmpty()) newMessageNotification.notify(it, student) messageRepository.updateMessages(it.onEach { message -> message.isNotified = true }) 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 425e68b9..b1322ada 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 @@ -1,23 +1,22 @@ package io.github.wulkanowy.services.sync.works +import io.github.wulkanowy.data.db.entities.MailboxType import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.data.repositories.MailboxRepository import io.github.wulkanowy.data.repositories.RecipientRepository -import io.github.wulkanowy.data.repositories.ReportingUnitRepository import javax.inject.Inject class RecipientWork @Inject constructor( - private val reportingUnitRepository: ReportingUnitRepository, + private val mailboxRepository: MailboxRepository, private val recipientRepository: RecipientRepository ) : Work { override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) { - reportingUnitRepository.refreshReportingUnits(student) + mailboxRepository.refreshMailboxes(student) - reportingUnitRepository.getReportingUnits(student).let { units -> - units.map { - recipientRepository.refreshRecipients(student, it, 2) - } - } + val mailbox = mailboxRepository.getMailbox(student) + + recipientRepository.refreshRecipients(student, mailbox, MailboxType.EMPLOYEE) } } 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 5d7c7df4..35030093 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 @@ -25,6 +25,7 @@ class DashboardPresenter @Inject constructor( private val gradeRepository: GradeRepository, private val semesterRepository: SemesterRepository, private val messageRepository: MessageRepository, + private val mailboxRepository: MailboxRepository, private val attendanceSummaryRepository: AttendanceSummaryRepository, private val timetableRepository: TimetableRepository, private val homeworkRepository: HomeworkRepository, @@ -227,6 +228,7 @@ class DashboardPresenter @Inject constructor( private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) { flow { val semester = semesterRepository.getCurrentSemester(student) + val mailbox = mailboxRepository.getMailbox(student) val selectedTiles = preferencesRepository.selectedDashboardTiles val flowSuccess = flowOf(Resource.Success(null)) @@ -238,7 +240,7 @@ class DashboardPresenter @Inject constructor( val messageFLow = messageRepository.getMessages( student = student, - semester = semester, + mailbox = mailbox, folder = MessageFolder.RECEIVED, forceRefresh = forceRefresh ).takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowSuccess 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 53d43961..6ff26162 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 @@ -17,16 +17,13 @@ val debugMessageItems = listOf( ) private fun generateMessage(sender: String, subject: String) = Message( - sender = sender, subject = subject, - studentId = 0, - realId = 0, - messageId = 0, - senderId = 0, - recipient = "", + messageId = 123, date = Instant.now(), folderId = 0, unread = true, - removed = false, - hasAttachments = false + hasAttachments = false, + messageGlobalKey = "", + correspondents = sender, + mailboxKey = "", ) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewAdapter.kt index d75128be..3c1c53d3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewAdapter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewAdapter.kt @@ -4,6 +4,8 @@ import android.annotation.SuppressLint import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.text.HtmlCompat.FROM_HTML_MODE_COMPACT +import androidx.core.text.parseAsHtml import androidx.recyclerview.widget.RecyclerView import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Message @@ -75,29 +77,25 @@ class MessagePreviewAdapter @Inject constructor() : @SuppressLint("SetTextI18n") private fun bindMessage(holder: MessageViewHolder, message: Message) { val context = holder.binding.root.context - val recipientCount = message.unreadBy + message.readBy - val readText = when { - recipientCount > 1 -> { - context.getString(R.string.message_read_by, message.readBy, recipientCount) - } - message.readBy == 1 -> { - context.getString(R.string.message_read, context.getString(R.string.all_yes)) - } - else -> context.getString(R.string.message_read, context.getString(R.string.all_no)) + val readTextValue = when { + !message.unread -> R.string.all_yes + else -> R.string.all_no } + val readText = context.getString(R.string.message_read, context.getString(readTextValue)) with(holder.binding) { - messagePreviewSubject.text = - message.subject.ifBlank { root.context.getString(R.string.message_no_subject) } - messagePreviewDate.text = root.context.getString( + messagePreviewSubject.text = message.subject.ifBlank { + context.getString(R.string.message_no_subject) + } + messagePreviewDate.text = context.getString( R.string.message_date, message.date.toFormattedString("yyyy-MM-dd HH:mm:ss") ) messagePreviewRead.text = readText - messagePreviewContent.text = message.content + messagePreviewContent.text = message.content.parseAsHtml(FROM_HTML_MODE_COMPACT) messagePreviewFromSender.text = message.sender - messagePreviewToRecipient.text = message.recipient + messagePreviewToRecipient.text = message.recipients } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt index 4b2685c6..2a5523f4 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt @@ -135,8 +135,8 @@ class MessagePreviewFragment : binding.messagePreviewRecycler.visibility = if (show) VISIBLE else GONE } - override fun showOptions(show: Boolean) { - menuReplyButton?.isVisible = show + override fun showOptions(show: Boolean, isReplayable: Boolean) { + menuReplyButton?.isVisible = isReplayable menuForwardButton?.isVisible = show menuDeleteButton?.isVisible = show menuShareButton?.isVisible = show diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt index 39c337bf..c011f41f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt @@ -1,10 +1,12 @@ package io.github.wulkanowy.ui.modules.message.preview import android.annotation.SuppressLint +import androidx.core.text.parseAsHtml import io.github.wulkanowy.data.* import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.MessageAttachment import io.github.wulkanowy.data.enums.MessageFolder +import io.github.wulkanowy.data.repositories.MailboxRepository import io.github.wulkanowy.data.repositories.MessageRepository import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.ui.base.BasePresenter @@ -19,6 +21,7 @@ class MessagePreviewPresenter @Inject constructor( errorHandler: ErrorHandler, studentRepository: StudentRepository, private val messageRepository: MessageRepository, + private val mailboxRepository: MailboxRepository, private val analytics: AnalyticsHelper ) : BasePresenter(errorHandler, studentRepository) { @@ -52,7 +55,7 @@ class MessagePreviewPresenter @Inject constructor( private fun loadData(messageToLoad: Message) { flatResourceFlow { - val student = studentRepository.getStudentById(messageToLoad.studentId) + val student = studentRepository.getCurrentStudent() messageRepository.getMessage(student, messageToLoad, true) } .logResourceStatus("message ${messageToLoad.messageId} preview") @@ -104,62 +107,69 @@ class MessagePreviewPresenter @Inject constructor( } fun onShare(): Boolean { - message?.let { - var text = - "Temat: ${it.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }}\n" + when (it.sender.isNotEmpty()) { - true -> "Od: ${it.sender}\n" - false -> "Do: ${it.recipient}\n" - } + "Data: ${it.date.toFormattedString("yyyy-MM-dd HH:mm:ss")}\n\n${it.content}" + val message = message ?: return false + val subject = message.subject.ifBlank { view?.messageNoSubjectString.orEmpty() } - attachments?.let { attachments -> - if (attachments.isNotEmpty()) { - text += "\n\nZałączniki:" + val text = buildString { + appendLine("Temat: $subject") + appendLine("Od: ${message.sender}") + appendLine("Do: ${message.recipients}") + appendLine("Data: ${message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")}") - attachments.forEach { attachment -> - text += "\n${attachment.filename}: ${attachment.url}" - } - } + appendLine() + + appendLine(message.content.parseAsHtml()) + + if (!attachments.isNullOrEmpty()) { + appendLine() + appendLine("Załączniki:") + + append(attachments.orEmpty().joinToString(separator = "\n") { attachment -> + "${attachment.filename}: ${attachment.url}" + }) } - - view?.shareText( - text, - "FW: ${it.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }}" - ) - return true } - return false + + view?.shareText( + subject = "FW: $subject", + text = text, + ) + return true } @SuppressLint("NewApi") fun onPrint(): Boolean { - message?.let { - val dateString = it.date.toFormattedString("yyyy-MM-dd HH:mm:ss") - val infoContent = "

Data wysłania

$dateString
" + when { - it.sender.isNotEmpty() -> "

Od

${it.sender}
" - else -> "

Do

${it.recipient}
" - } + val message = message ?: return false + val subject = message.subject.ifBlank { view?.messageNoSubjectString.orEmpty() } - val messageContent = "

${it.content}

" - .replace(Regex("[\\n\\r]{2,}"), "

") - .replace(Regex("[\\n\\r]"), "
") + val dateString = message.date.toFormattedString("yyyy-MM-dd HH:mm:ss") - val jobName = "Wiadomość " + when { - it.sender.isNotEmpty() -> "od ${it.sender}" - else -> "do ${it.recipient}" - } + " $dateString: ${it.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }} | Wulkanowy" + val infoContent = buildString { + append("

Data wysłania

$dateString
") - view?.apply { - val html = printHTML - .replace( - "%SUBJECT%", - it.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }) - .replace("%CONTENT%", messageContent) - .replace("%INFO%", infoContent) - printDocument(html, jobName) - } - return true + append("

Od

${message.sender}
") + append("

DO

${message.recipients}
") } - return false + val messageContent = "

${message.content}

" + .replace(Regex("[\\n\\r]{2,}"), "

") + .replace(Regex("[\\n\\r]"), "
") + + val jobName = buildString { + append("Wiadomość ") + append("od ${message.correspondents}") + append("do ${message.correspondents}") + append(" $dateString: $subject | Wulkanowy") + } + + view?.apply { + val html = printHTML + .replace("%SUBJECT%", subject) + .replace("%CONTENT%", messageContent) + .replace("%INFO%", infoContent) + printDocument(html, jobName) + } + + return true } private fun deleteMessage() { @@ -168,16 +178,17 @@ class MessagePreviewPresenter @Inject constructor( view?.run { showContent(false) showProgress(true) - showOptions(false) + showOptions(show = false, isReplayable = false) showErrorView(false) } - Timber.i("Delete message ${message?.id}") + Timber.i("Delete message ${message?.messageGlobalKey}") presenterScope.launch { runCatching { - val student = studentRepository.getCurrentStudent() - messageRepository.deleteMessage(student, message!!) + val student = studentRepository.getCurrentStudent(decryptPass = true) + val mailbox = mailboxRepository.getMailbox(student) + messageRepository.deleteMessage(student, mailbox, message!!) } .onFailure { retryCallback = { onMessageDelete() } @@ -211,7 +222,10 @@ class MessagePreviewPresenter @Inject constructor( private fun initOptions() { view?.apply { - showOptions(message != null) + showOptions( + show = message != null, + isReplayable = message?.folderId != MessageFolder.SENT.id, + ) message?.let { when (it.folderId == MessageFolder.TRASHED.id) { true -> setDeletedOptionsLabels() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt index 88fe77d9..c5a94793 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt @@ -28,7 +28,7 @@ interface MessagePreviewView : BaseView { fun setErrorRetryCallback(callback: () -> Unit) - fun showOptions(show: Boolean) + fun showOptions(show: Boolean, isReplayable: Boolean) fun setDeletedOptionsLabels() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageActivity.kt index 70f9a9b5..334e389e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageActivity.kt @@ -6,6 +6,7 @@ import android.content.Context import android.content.Intent import android.graphics.Rect import android.os.Bundle +import android.text.Spanned import android.view.Menu import android.view.MenuItem import android.view.TouchDelegate @@ -13,11 +14,12 @@ import android.view.View.GONE import android.view.View.VISIBLE import android.widget.Toast import android.widget.Toast.LENGTH_LONG +import androidx.core.text.parseAsHtml +import androidx.core.text.toHtml import androidx.core.widget.doOnTextChanged import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Message -import io.github.wulkanowy.data.db.entities.ReportingUnit import io.github.wulkanowy.databinding.ActivitySendMessageBinding import io.github.wulkanowy.ui.base.BaseActivity import io.github.wulkanowy.utils.dpToPx @@ -72,17 +74,32 @@ class SendMessageActivity : BaseActivity formSubjectValue = binding.sendMessageSubject.text.toString() - formContentValue = binding.sendMessageMessageContent.text.toString() + formContentValue = + binding.sendMessageMessageContent.text.toString().parseAsHtml().toString() presenter.onAttachView( view = this, @@ -110,7 +127,7 @@ class SendMessageActivity : BaseActivity) { @@ -165,7 +182,7 @@ class SendMessageActivity : BaseActivity "Re: " + true -> "RE: " else -> "FW: " } + message.subject ) if (preferencesRepository.fillMessageContent || reply != true) { - setContent( - when (reply) { - true -> "\n\n" - else -> "" - } + when (message.sender.isNotEmpty()) { - true -> "Od: ${message.sender}\n" - false -> "Do: ${message.recipient}\n" - } + "Data: ${message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")}\n\n${message.content}" - ) + setContent(buildString { + if (reply == true) { + append("

") + } + + append("Od: ${message.sender}
") + append("Do: ${message.recipients}
") + append("Data: ${message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")}

") + append(message.content) + }) } } } @@ -111,21 +113,24 @@ class SendMessagePresenter @Inject constructor( private fun loadData(message: Message?, reply: Boolean?) { resourceFlow { val student = studentRepository.getCurrentStudent() - val semester = semesterRepository.getCurrentSemester(student) - val unit = reportingUnitRepository.getReportingUnit(student, semester.unitId) + val mailbox = mailboxRepository.getMailbox(student) Timber.i("Loading recipients started") - val recipients = when { - unit != null -> recipientRepository.getRecipients(student, unit, 2) - else -> listOf() - }.let { createChips(it) } + val recipients = createChips( + recipients = recipientRepository.getRecipients( + student = student, + mailbox = mailbox, + type = MailboxType.EMPLOYEE, + ) + ) Timber.i("Loading recipients result: Success, fetched %d recipients", recipients.size) Timber.i("Loading message recipients started") val messageRecipients = when { - message != null && reply == true -> recipientRepository.getMessageRecipients( - student, - message + message != null && reply == true -> recipientRepository.getMessageSender( + student = student, + message = message, + mailbox = mailbox, ) else -> emptyList() }.let { createChips(it) } @@ -134,7 +139,7 @@ class SendMessagePresenter @Inject constructor( messageRecipients.size ) - Triple(unit, recipients, messageRecipients) + Triple(mailbox, recipients, messageRecipients) } .logResourceStatus("load recipients") .onEach { @@ -143,19 +148,14 @@ class SendMessagePresenter @Inject constructor( showProgress(true) showContent(false) } - is Resource.Success -> it.data.let { (reportingUnit, recipientChips, selectedRecipientChips) -> + is Resource.Success -> it.data.let { (mailbox, recipientChips, selectedRecipientChips) -> view?.run { - if (reportingUnit != null) { - setReportingUnit(reportingUnit) - setRecipients(recipientChips) - if (selectedRecipientChips.isNotEmpty()) setSelectedRecipients( - selectedRecipientChips - ) - showContent(true) - } else { - Timber.i("Loading recipients result: Can't find the reporting unit") - view?.showEmpty(true) - } + setMailbox(getMailboxName(mailbox)) + setRecipients(recipientChips) + if (selectedRecipientChips.isNotEmpty()) setSelectedRecipients( + selectedRecipientChips + ) + showContent(true) } } is Resource.Error -> { @@ -171,7 +171,14 @@ class SendMessagePresenter @Inject constructor( private fun sendMessage(subject: String, content: String, recipients: List) { resourceFlow { val student = studentRepository.getCurrentStudent() - messageRepository.sendMessage(student, subject, content, recipients) + val mailbox = mailboxRepository.getMailbox(student) + messageRepository.sendMessage( + student = student, + subject = subject, + content = content, + recipients = recipients, + mailboxId = mailbox.globalKey, + ) }.logResourceStatus("sending message").onEach { when (it) { is Resource.Loading -> view?.run { @@ -201,31 +208,44 @@ class SendMessagePresenter @Inject constructor( } private fun createChips(recipients: List): List { - fun generateCorrectSummary(recipientRealName: String): String { - val substring = recipientRealName.substringBeforeLast("-") - return when { - substring == recipientRealName -> recipientRealName - substring.indexOf("(") != -1 -> { - recipientRealName.indexOf("(") - .let { recipientRealName.substring(if (it != -1) it else 0) } - } - substring.indexOf("[") != -1 -> { - recipientRealName.indexOf("[") - .let { recipientRealName.substring(if (it != -1) it else 0) } - } - else -> recipientRealName.substringAfter("-") - }.trim() - } - return recipients.map { RecipientChipItem( - title = it.name, - summary = generateCorrectSummary(it.realName), + title = it.userName, + summary = buildString { + getMailboxType(it.type)?.let(::append) + if (isNotBlank()) append(" ") + + append("(${it.schoolShortName})") + }, recipient = it ) } } + private fun getMailboxName(mailbox: Mailbox): String { + return buildString { + append(mailbox.userName) + append(" - ") + append(getMailboxType(mailbox.type)) + + if (mailbox.type == MailboxType.PARENT) { + append(" - ") + append(mailbox.studentName) + } + + append(" - ") + append("(${mailbox.schoolNameShort})") + } + } + + private fun getMailboxType(type: MailboxType): String? = when (type) { + MailboxType.STUDENT -> view?.mailboxStudent + MailboxType.PARENT -> view?.mailboxParent + MailboxType.GUARDIAN -> view?.mailboxGuardian + MailboxType.EMPLOYEE -> view?.mailboxEmployee + MailboxType.UNKNOWN -> null + } + fun onMessageContentChange() { presenterScope.launch { messageUpdateChannel.send(Unit) @@ -263,7 +283,7 @@ class SendMessagePresenter @Inject constructor( fun getRecipientsNames(): String { return messageRepository.draftMessage?.recipients.orEmpty() - .joinToString { it.recipient.name } + .joinToString { it.recipient.userName } } fun clearDraft() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageView.kt index 21b42e3e..1057114b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageView.kt @@ -1,6 +1,6 @@ package io.github.wulkanowy.ui.modules.message.send -import io.github.wulkanowy.data.db.entities.ReportingUnit +import io.github.wulkanowy.data.db.entities.Mailbox import io.github.wulkanowy.ui.base.BaseView interface SendMessageView : BaseView { @@ -18,9 +18,17 @@ interface SendMessageView : BaseView { val messageSuccess: String + val mailboxStudent: String + + val mailboxParent: String + + val mailboxGuardian: String + + val mailboxEmployee: String + fun initView() - fun setReportingUnit(unit: ReportingUnit) + fun setMailbox(mailbox: String) fun setRecipients(recipients: List) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt index af0923b9..55f03ef8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt @@ -8,7 +8,6 @@ import androidx.core.view.isVisible import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import io.github.wulkanowy.R -import io.github.wulkanowy.data.enums.MessageFolder import io.github.wulkanowy.databinding.ItemMessageBinding import io.github.wulkanowy.databinding.ItemMessageChipsBinding import io.github.wulkanowy.utils.toFormattedString @@ -88,12 +87,8 @@ class MessageTabAdapter @Inject constructor() : with(holder.binding) { val style = if (message.unread) Typeface.BOLD else Typeface.NORMAL - messageItemAuthor.run { - text = if (message.folderId == MessageFolder.SENT.id) { - message.recipient - } else { - message.sender - } + with(messageItemAuthor) { + text = message.correspondents setTypeface(null, style) } messageItemSubject.run { @@ -145,7 +140,7 @@ class MessageTabAdapter @Inject constructor() : val newItem = new[newItemPosition] return if (oldItem is MessageTabDataItem.MessageItem && newItem is MessageTabDataItem.MessageItem) { - oldItem.message.id == newItem.message.id + oldItem.message.messageGlobalKey == newItem.message.messageGlobalKey } else { oldItem.viewType == newItem.viewType } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt index 870b6433..54711a68 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt @@ -3,8 +3,8 @@ package io.github.wulkanowy.ui.modules.message.tab import io.github.wulkanowy.data.* import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.enums.MessageFolder +import io.github.wulkanowy.data.repositories.MailboxRepository import io.github.wulkanowy.data.repositories.MessageRepository -import io.github.wulkanowy.data.repositories.SemesterRepository import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler @@ -26,7 +26,7 @@ class MessageTabPresenter @Inject constructor( errorHandler: ErrorHandler, studentRepository: StudentRepository, private val messageRepository: MessageRepository, - private val semesterRepository: SemesterRepository, + private val mailboxRepository: MailboxRepository, private val analytics: AnalyticsHelper ) : BasePresenter(errorHandler, studentRepository) { @@ -122,7 +122,8 @@ class MessageTabPresenter @Inject constructor( runCatching { val student = studentRepository.getCurrentStudent(true) - messageRepository.deleteMessages(student, messageList) + val mailbox = mailboxRepository.getMailbox(student) + messageRepository.deleteMessages(student, mailbox, messageList) } .onFailure(errorHandler::dispatch) .onSuccess { view?.showMessagesDeleted() } @@ -159,7 +160,7 @@ class MessageTabPresenter @Inject constructor( } fun onMessageItemSelected(messageItem: MessageTabDataItem.MessageItem, position: Int) { - Timber.i("Select message ${messageItem.message.id} item (position: $position)") + Timber.i("Select message ${messageItem.message.messageGlobalKey} item (position: $position)") if (!isActionMode) { view?.run { @@ -206,8 +207,8 @@ class MessageTabPresenter @Inject constructor( flatResourceFlow { val student = studentRepository.getCurrentStudent() - val semester = semesterRepository.getCurrentSemester(student) - messageRepository.getMessages(student, semester, folder, forceRefresh) + val mailbox = mailboxRepository.getMailbox(student) + messageRepository.getMessages(student, mailbox, folder, forceRefresh) } .logResourceStatus("load $folder message") .onResourceData { @@ -333,7 +334,7 @@ class MessageTabPresenter @Inject constructor( addAll(data.map { message -> MessageTabDataItem.MessageItem( message = message, - isSelected = messagesToDelete.any { it.id == message.id }, + isSelected = messagesToDelete.any { it.messageGlobalKey == message.messageGlobalKey }, isActionMode = isActionMode ) }) @@ -345,10 +346,9 @@ class MessageTabPresenter @Inject constructor( private fun calculateMatchRatio(message: Message, query: String): Int { val subjectRatio = FuzzySearch.tokenSortPartialRatio(query.lowercase(), message.subject) - val senderOrRecipientRatio = FuzzySearch.tokenSortPartialRatio( + val correspondentsRatio = FuzzySearch.tokenSortPartialRatio( query.lowercase(), - if (message.sender.isNotEmpty()) message.sender.lowercase() - else message.recipient.lowercase() + message.correspondents ) val dateRatio = listOf( @@ -364,7 +364,7 @@ class MessageTabPresenter @Inject constructor( return (subjectRatio.toDouble().pow(2) - + senderOrRecipientRatio.toDouble().pow(2) + + correspondentsRatio.toDouble().pow(2) + dateRatio.toDouble().pow(2) * 2 ).toInt() } diff --git a/app/src/main/res/layout/activity_send_message.xml b/app/src/main/res/layout/activity_send_message.xml index 10b581f7..320782bd 100644 --- a/app/src/main/res/layout/activity_send_message.xml +++ b/app/src/main/res/layout/activity_send_message.xml @@ -16,8 +16,7 @@ app:layout_constraintBottom_toTopOf="@id/sendMessageScroll" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - tools:targetApi="lollipop" /> + app:layout_constraintTop_toTopOf="parent" /> Move to trash Delete permanently Message deleted successfully + student + parent + guardian + employee Share Print Subject @@ -300,7 +304,6 @@ Only unread Only with attachments Read: %s - Read by: %1$d of %2$d people %1$d message %1$d messages diff --git a/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt b/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt index 22539930..ff0a5313 100644 --- a/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt +++ b/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt @@ -1,5 +1,7 @@ package io.github.wulkanowy +import io.github.wulkanowy.data.db.entities.Mailbox +import io.github.wulkanowy.data.db.entities.MailboxType import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk @@ -21,6 +23,16 @@ fun getSemesterEntity(diaryId: Int = 1, semesterId: Int = 1, start: LocalDate = end = end ) +fun getMailboxEntity() = Mailbox( + globalKey = "v4", + fullName = "", + userName = "", + userLoginId = 0, + studentName = "", + schoolNameShort = "", + type = MailboxType.UNKNOWN, +) + fun getSemesterPojo(diaryId: Int, semesterId: Int, start: LocalDate, end: LocalDate, semesterName: Int = 1) = SdkSemester( diaryId = diaryId, kindergartenDiaryId = 0, 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 2a5d2e2b..24306bfe 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 @@ -10,12 +10,10 @@ import io.github.wulkanowy.data.db.entities.MessageWithAttachment import io.github.wulkanowy.data.enums.MessageFolder import io.github.wulkanowy.data.errorOrNull import io.github.wulkanowy.data.toFirstResult -import io.github.wulkanowy.getSemesterEntity +import io.github.wulkanowy.getMailboxEntity import io.github.wulkanowy.getStudentEntity import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.pojo.Folder -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.Status import io.github.wulkanowy.utils.status @@ -23,7 +21,6 @@ import io.mockk.* import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.SpyK import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.toList import kotlinx.coroutines.runBlocking @@ -60,7 +57,7 @@ class MessageRepositoryTest { private val student = getStudentEntity() - private val semester = getSemesterEntity() + private val mailbox = getMailboxEntity() private lateinit var repository: MessageRepository @@ -80,59 +77,18 @@ class MessageRepositoryTest { ) } - @Test - 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 - readBy = 5 - isNotified = true - } - emit(listOf(dbMessage)) - } - coEvery { sdk.getMessages(Folder.RECEIVED, any(), any()) } returns listOf( - getMessageDto(messageId = 3, content = "", unread = false).copy( - unreadBy = 5, - readBy = 10, - ) - ) - coEvery { messageDb.deleteAll(any()) } just Runs - coEvery { messageDb.insertAll(any()) } returns listOf() - - repository.getMessages( - student = student, - semester = semester, - folder = MessageFolder.RECEIVED, - forceRefresh = true, - notify = true, // all new messages will be marked as not notified - ).toFirstResult().dataOrNull.orEmpty() - - coVerify(exactly = 1) { messageDb.deleteAll(emptyList()) } - coVerify(exactly = 1) { messageDb.insertAll(emptyList()) } - coVerify(exactly = 1) { - messageDb.updateAll(withArg { - assertEquals(1, it.size) - assertEquals(5, it.single().unreadBy) - assertEquals(10, it.single().readBy) - }) - } - } - @Test fun `get messages when fetched completely new message without notify`() = runBlocking { every { messageDb.loadAll(any(), any()) } returns flowOf(emptyList()) - coEvery { sdk.getMessages(Folder.RECEIVED, any(), any()) } returns listOf( - getMessageDto(messageId = 4, content = "Test", unread = true).copy( - unreadBy = 5, - readBy = 10, - ) + coEvery { sdk.getMessages(Folder.RECEIVED, any()) } returns listOf( + getMessageDto() ) coEvery { messageDb.deleteAll(any()) } just Runs coEvery { messageDb.insertAll(any()) } returns listOf() repository.getMessages( student = student, - semester = semester, + mailbox = mailbox, folder = MessageFolder.RECEIVED, forceRefresh = true, notify = false, @@ -151,7 +107,7 @@ class MessageRepositoryTest { fun `throw error when message is not in the db`() { val testMessage = getMessageEntity(1, "", false) coEvery { - messageDb.loadMessageWithAttachment(1, 1) + messageDb.loadMessageWithAttachment("v4") } throws NoSuchElementException("No message in database") runBlocking { repository.getMessage(student, testMessage).toFirstResult() } @@ -162,7 +118,7 @@ class MessageRepositoryTest { val testMessage = getMessageEntity(123, "Test", false) val messageWithAttachment = MessageWithAttachment(testMessage, emptyList()) - coEvery { messageDb.loadMessageWithAttachment(1, testMessage.messageId) } returns flowOf( + coEvery { messageDb.loadMessageWithAttachment("v4") } returns flowOf( messageWithAttachment ) @@ -174,7 +130,7 @@ class MessageRepositoryTest { } @Test - fun `get message when content in db is empty`() { + fun `get message when content in db is empty`() = runTest { val testMessage = getMessageEntity(123, "", true) val testMessageWithContent = testMessage.copy().apply { content = "Test" } @@ -182,23 +138,19 @@ class MessageRepositoryTest { val mWaWithContent = MessageWithAttachment(testMessageWithContent, emptyList()) coEvery { - messageDb.loadMessageWithAttachment( - 1, - testMessage.messageId - ) + messageDb.loadMessageWithAttachment("v4") } returnsMany listOf(flowOf(mWa), flowOf(mWaWithContent)) coEvery { - sdk.getMessageDetails( - messageId = testMessage.messageId, - folderId = 1, - read = false, - id = testMessage.realId - ) - } returns MessageDetails("Test", emptyList()) + sdk.getMessageDetails("v4") + } returns mockk { + every { sender } returns "" + every { recipients } returns listOf("") + every { attachments } returns listOf() + } coEvery { messageDb.updateAll(any()) } just Runs coEvery { messageAttachmentDao.insertAttachments(any()) } returns listOf(1) - val res = runBlocking { repository.getMessage(student, testMessage).toFirstResult() } + val res = repository.getMessage(student, testMessage).toFirstResult() assertEquals(null, res.errorOrNull) assertEquals(Status.SUCCESS, res.status) @@ -211,7 +163,7 @@ class MessageRepositoryTest { val testMessage = getMessageEntity(123, "", false) coEvery { - messageDb.loadMessageWithAttachment(1, testMessage.messageId) + messageDb.loadMessageWithAttachment("v4") } throws UnknownHostException() runBlocking { repository.getMessage(student, testMessage).toFirstResult() } @@ -222,7 +174,7 @@ class MessageRepositoryTest { val testMessage = getMessageEntity(123, "", true) coEvery { - messageDb.loadMessageWithAttachment(1, testMessage.messageId) + messageDb.loadMessageWithAttachment("v4") } throws UnknownHostException() runBlocking { repository.getMessage(student, testMessage).toList()[1] } @@ -233,42 +185,30 @@ class MessageRepositoryTest { content: String, unread: Boolean ) = Message( - studentId = 1, - realId = 1, + messageGlobalKey = "v4", + mailboxKey = "", + correspondents = "", messageId = messageId, - sender = "", - senderId = 0, - recipient = "Wielu adresatów", subject = "", date = Instant.EPOCH, folderId = 1, unread = unread, - removed = false, hasAttachments = false ).apply { this.content = content - unreadBy = 1 - readBy = 1 } - private fun getMessageDto( - messageId: Int, - content: String, - unread: Boolean, - ) = io.github.wulkanowy.sdk.pojo.Message( - id = 1, - messageId = messageId, - sender = Sender("", "", 0, 0, 0, ""), + private fun getMessageDto() = io.github.wulkanowy.sdk.pojo.Message( + globalKey = "v4", + mailbox = "", + correspondents = "", + id = 4, recipients = listOf(), subject = "", - content = content, - date = Instant.EPOCH.atZone(ZoneOffset.UTC).toLocalDateTime(), + content = "Test", dateZoned = Instant.EPOCH.atZone(ZoneOffset.UTC), folderId = 1, - unread = unread, - unreadBy = 0, - readBy = 0, - removed = false, + unread = true, hasAttachments = false, ) } diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/RecipientLocalTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/RecipientLocalTest.kt index 980abac0..ae73a795 100644 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/RecipientLocalTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/RecipientLocalTest.kt @@ -1,19 +1,15 @@ package io.github.wulkanowy.data.repositories import io.github.wulkanowy.data.db.dao.RecipientDao -import io.github.wulkanowy.data.db.entities.ReportingUnit import io.github.wulkanowy.data.mappers.mapToEntities +import io.github.wulkanowy.getMailboxEntity import io.github.wulkanowy.getStudentEntity import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.sdk.pojo.MailboxType import io.github.wulkanowy.utils.AutoRefreshHelper -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.runBlocking import org.junit.Assert.assertEquals import org.junit.Before @@ -36,9 +32,30 @@ class RecipientLocalTest { private lateinit var recipientRepository: RecipientRepository private val remoteList = listOf( - SdkRecipient("2rPracownik", "Kowalski Jan", 3, 4, 2, "hash", "Kowalski Jan [KJ] - Pracownik (Fake123456)"), - SdkRecipient("3rPracownik", "Kowalska Karolina", 4, 4, 2, "hash", "Kowalska Karolina [KK] - Pracownik (Fake123456)"), - SdkRecipient("4rPracownik", "Krupa Stanisław", 5, 4, 1, "hash", "Krupa Stanisław [KS] - Uczeń (Fake123456)") + SdkRecipient( + mailboxGlobalKey = "2rPracownik", + userName = "Kowalski Jan", + fullName = "Kowalski Jan [KJ] - Pracownik (Fake123456)", + studentName = "", + schoolNameShort = "", + type = MailboxType.UNKNOWN, + ), + SdkRecipient( + mailboxGlobalKey = "3rPracownik", + userName = "Kowalska Karolina", + fullName = "Kowalska Karolina [KK] - Pracownik (Fake123456)", + studentName = "", + schoolNameShort = "", + type = MailboxType.UNKNOWN, + ), + SdkRecipient( + mailboxGlobalKey = "4rPracownik", + userName = "Krupa Stanisław", + fullName = "Krupa Stanisław [KS] - Uczeń (Fake123456)", + studentName = "", + schoolNameShort = "", + type = MailboxType.UNKNOWN, + ) ) @Before @@ -52,39 +69,61 @@ class RecipientLocalTest { @Test fun `load recipients when items already in database`() { // prepare - coEvery { recipientDb.loadAll(4, 123, 7) } returnsMany listOf( - remoteList.mapToEntities(4), - remoteList.mapToEntities(4) + coEvery { recipientDb.loadAll(io.github.wulkanowy.data.db.entities.MailboxType.UNKNOWN, "v4") } returnsMany listOf( + remoteList.mapToEntities("v4"), + remoteList.mapToEntities("v4") ) coEvery { recipientDb.insertAll(any()) } returns listOf(1, 2, 3) coEvery { recipientDb.deleteAll(any()) } just Runs // execute - val res = runBlocking { recipientRepository.getRecipients(student, ReportingUnit(4, 123, "", 4, "", listOf()), 7) } + val res = runBlocking { + recipientRepository.getRecipients( + student = student, + mailbox = getMailboxEntity(), + type = io.github.wulkanowy.data.db.entities.MailboxType.UNKNOWN, + ) + } // verify assertEquals(3, res.size) - coVerify { recipientDb.loadAll(4, 123, 7) } + coVerify { + recipientDb.loadAll( + type = io.github.wulkanowy.data.db.entities.MailboxType.UNKNOWN, + studentMailboxGlobalKey = "v4" + ) + } } @Test fun `load recipients when database is empty`() { // prepare - coEvery { sdk.getRecipients(123, 7) } returns remoteList - coEvery { recipientDb.loadAll(4, 123, 7) } returnsMany listOf( + coEvery { sdk.getRecipients("v4") } returns remoteList + coEvery { + recipientDb.loadAll( + io.github.wulkanowy.data.db.entities.MailboxType.UNKNOWN, + "v4" + ) + } returnsMany listOf( emptyList(), - remoteList.mapToEntities(4) + remoteList.mapToEntities("v4") ) coEvery { recipientDb.insertAll(any()) } returns listOf(1, 2, 3) coEvery { recipientDb.deleteAll(any()) } just Runs // execute - val res = runBlocking { recipientRepository.getRecipients(student, ReportingUnit(4, 123, "", 4, "", listOf()), 7) } + val res = runBlocking { + recipientRepository.getRecipients( + student = student, + mailbox = getMailboxEntity(), + type = io.github.wulkanowy.data.db.entities.MailboxType.UNKNOWN, + ) + } // verify assertEquals(3, res.size) - coVerify { sdk.getRecipients(123, 7) } - coVerify { recipientDb.loadAll(4, 123, 7) } + coVerify { sdk.getRecipients("v4") } + coVerify { recipientDb.loadAll(io.github.wulkanowy.data.db.entities.MailboxType.UNKNOWN, "v4") } coVerify { recipientDb.insertAll(match { it.isEmpty() }) } coVerify { recipientDb.deleteAll(match { it.isEmpty() }) } }