diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/21.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/21.json new file mode 100644 index 000000000..dfad69f5d --- /dev/null +++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/21.json @@ -0,0 +1,1652 @@ +{ + "formatVersion": 1, + "database": { + "version": 21, + "identityHash": "f905d8a3ff4718d30ae7413a5a717b1f", + "entities": [ + { + "tableName": "Students", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `scrapper_base_url` TEXT NOT NULL, `mobile_base_url` TEXT NOT NULL, `login_type` TEXT NOT NULL, `login_mode` TEXT NOT NULL, `certificate_key` TEXT NOT NULL, `private_key` TEXT NOT NULL, `is_parent` INTEGER NOT NULL, `email` TEXT NOT NULL, `password` TEXT NOT NULL, `symbol` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `user_login_id` INTEGER NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_name` TEXT NOT NULL, `class_name` TEXT NOT NULL, `class_id` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `registration_date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "scrapperBaseUrl", + "columnName": "scrapper_base_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "mobileBaseUrl", + "columnName": "mobile_base_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginType", + "columnName": "login_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginMode", + "columnName": "login_mode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "certificateKey", + "columnName": "certificate_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "privateKey", + "columnName": "private_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isParent", + "columnName": "is_parent", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "password", + "columnName": "password", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "symbol", + "columnName": "symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userLoginId", + "columnName": "user_login_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentName", + "columnName": "student_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolSymbol", + "columnName": "school_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolName", + "columnName": "school_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "className", + "columnName": "class_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isCurrent", + "columnName": "is_current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "registrationDate", + "columnName": "registration_date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_Students_email_symbol_student_id_school_id_class_id", + "unique": true, + "columnNames": [ + "email", + "symbol", + "student_id", + "school_id", + "class_id" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Students_email_symbol_student_id_school_id_class_id` ON `${TABLE_NAME}` (`email`, `symbol`, `student_id`, `school_id`, `class_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Semesters", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryName", + "columnName": "diary_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolYear", + "columnName": "school_year", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterName", + "columnName": "semester_name", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isCurrent", + "columnName": "is_current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "unit_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_Semesters_student_id_diary_id_semester_id", + "unique": true, + "columnNames": [ + "student_id", + "diary_id", + "semester_id" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_semester_id` ON `${TABLE_NAME}` (`student_id`, `diary_id`, `semester_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Exams", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `group` TEXT NOT NULL, `type` TEXT NOT NULL, `description` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryDate", + "columnName": "entry_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "group", + "columnName": "group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Timetable", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `number` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `subjectOld` TEXT NOT NULL, `group` TEXT NOT NULL, `room` TEXT NOT NULL, `roomOld` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacherOld` TEXT NOT NULL, `info` TEXT NOT NULL, `student_plan` INTEGER NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subjectOld", + "columnName": "subjectOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "group", + "columnName": "group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "room", + "columnName": "room", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roomOld", + "columnName": "roomOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherOld", + "columnName": "teacherOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "info", + "columnName": "info", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentPlan", + "columnName": "student_plan", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "changes", + "columnName": "changes", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "canceled", + "columnName": "canceled", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Attendance", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `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)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "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 + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "AttendanceSummary", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `subject_id` INTEGER NOT NULL, `month` INTEGER NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `absence_excused` INTEGER NOT NULL, `absence_for_school_reasons` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `lateness_excused` INTEGER NOT NULL, `exemption` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subjectId", + "columnName": "subject_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "month", + "columnName": "month", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "presence", + "columnName": "presence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absenceExcused", + "columnName": "absence_excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absenceForSchoolReasons", + "columnName": "absence_for_school_reasons", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lateness", + "columnName": "lateness", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "latenessExcused", + "columnName": "lateness_excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "exemption", + "columnName": "exemption", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Grades", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `entry` TEXT NOT NULL, `value` REAL NOT NULL, `modifier` REAL NOT NULL, `comment` TEXT NOT NULL, `color` TEXT NOT NULL, `grade_symbol` TEXT NOT NULL, `description` TEXT NOT NULL, `weight` TEXT NOT NULL, `weightValue` REAL NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRead", + "columnName": "is_read", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "entry", + "columnName": "entry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "modifier", + "columnName": "modifier", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "comment", + "columnName": "comment", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "gradeSymbol", + "columnName": "grade_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "weight", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weightValue", + "columnName": "weightValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesSummary", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `position` INTEGER NOT NULL, `subject` TEXT NOT NULL, `predicted_grade` TEXT NOT NULL, `final_grade` TEXT NOT NULL, `proposed_points` TEXT NOT NULL, `final_points` TEXT NOT NULL, `points_sum` TEXT NOT NULL, `average` REAL NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "predictedGrade", + "columnName": "predicted_grade", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "finalGrade", + "columnName": "final_grade", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "proposedPoints", + "columnName": "proposed_points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "finalPoints", + "columnName": "final_points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pointsSum", + "columnName": "points_sum", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "average", + "columnName": "average", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesStatistics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `grade` INTEGER NOT NULL, `amount` INTEGER NOT NULL, `is_semester` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "grade", + "columnName": "grade", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semester", + "columnName": "is_semester", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesPointsStatistics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `others` REAL NOT NULL, `student` REAL NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "others", + "columnName": "others", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "student", + "columnName": "student", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `recipient_name` TEXT NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `unread_by` INTEGER NOT NULL, `read_by` INTEGER NOT NULL, `removed` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sender", + "columnName": "sender_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "sender_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "recipient", + "columnName": "recipient_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "folderId", + "columnName": "folder_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unread", + "columnName": "unread", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unreadBy", + "columnName": "unread_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "readBy", + "columnName": "read_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "removed", + "columnName": "removed", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Notes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `category` TEXT NOT NULL, `content` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRead", + "columnName": "is_read", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Homework", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryDate", + "columnName": "entry_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Subjects", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "LuckyNumbers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "luckyNumber", + "columnName": "lucky_number", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "CompletedLesson", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `topic` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `substitution` TEXT NOT NULL, `absence` TEXT NOT NULL, `resources` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "topic", + "columnName": "topic", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "substitution", + "columnName": "substitution", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "resources", + "columnName": "resources", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "ReportingUnits", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `short` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `roles` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shortName", + "columnName": "short", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "sender_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "senderName", + "columnName": "sender_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roles", + "columnName": "roles", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Recipients", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` TEXT NOT NULL, `name` TEXT NOT NULL, `real_name` TEXT NOT NULL, `login_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `role` INTEGER NOT NULL, `hash` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "realName", + "columnName": "real_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginId", + "columnName": "login_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "unit_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "role", + "columnName": "role", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hash", + "columnName": "hash", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "MobileDevices", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deviceId", + "columnName": "device_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Teachers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shortName", + "columnName": "short_name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "School", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT NOT NULL, `contact` TEXT NOT NULL, `headmaster` TEXT NOT NULL, `pedagogue` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "contact", + "columnName": "contact", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "headmaster", + "columnName": "headmaster", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pedagogue", + "columnName": "pedagogue", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f905d8a3ff4718d30ae7413a5a717b1f')" + ] + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/attendance/AttendanceLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/attendance/AttendanceLocalTest.kt index 69502e742..5fd5b193a 100644 --- a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/attendance/AttendanceLocalTest.kt +++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/attendance/AttendanceLocalTest.kt @@ -35,9 +35,9 @@ class AttendanceLocalTest { @Test fun saveAndReadTest() { attendanceLocal.saveAttendance(listOf( - Attendance(1, 2, LocalDate.of(2018, 9, 10), 0, "", "", false, false, false, false, false, false), - Attendance(1, 2, LocalDate.of(2018, 9, 14), 0, "", "", false, false, false, false, false, false), - Attendance(1, 2, LocalDate.of(2018, 9, 17), 0, "", "", false, false, false, false, false, false) + Attendance(1, 2, 3, LocalDate.of(2018, 9, 10), 0, "", "", false, false, false, false, false, false, false, SentExcuseStatus.ACCEPTED.name), + Attendance(1, 2, 3, LocalDate.of(2018, 9, 14), 0, "", "", false, false, false, false, false, false, false, SentExcuseStatus.WAITING.name), + Attendance(1, 2, 3, LocalDate.of(2018, 9, 17), 0, "", "", false, false, false, false, false, false, false, SentExcuseStatus.ACCEPTED.name) )) val attendance = attendanceLocal diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TestTimetableEntityCreator.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TestTimetableEntityCreator.kt index c1e23c578..77c061821 100644 --- a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TestTimetableEntityCreator.kt +++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TestTimetableEntityCreator.kt @@ -2,8 +2,8 @@ package io.github.wulkanowy.data.repositories.timetable import org.threeten.bp.LocalDateTime import org.threeten.bp.LocalDateTime.now -import io.github.wulkanowy.sdk.pojo.Timetable as TimetableRemote import io.github.wulkanowy.data.db.entities.Timetable as TimetableLocal +import io.github.wulkanowy.sdk.pojo.Timetable as TimetableRemote fun createTimetableLocal(start: LocalDateTime, number: Int, room: String = "", subject: String = "", teacher: String = "", changes: Boolean = false): TimetableLocal { return TimetableLocal( 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 fe4285052..b5293a53c 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 @@ -61,6 +61,7 @@ import io.github.wulkanowy.data.db.migrations.Migration18 import io.github.wulkanowy.data.db.migrations.Migration19 import io.github.wulkanowy.data.db.migrations.Migration2 import io.github.wulkanowy.data.db.migrations.Migration20 +import io.github.wulkanowy.data.db.migrations.Migration21 import io.github.wulkanowy.data.db.migrations.Migration3 import io.github.wulkanowy.data.db.migrations.Migration4 import io.github.wulkanowy.data.db.migrations.Migration5 @@ -102,7 +103,7 @@ import javax.inject.Singleton abstract class AppDatabase : RoomDatabase() { companion object { - const val VERSION_SCHEMA = 20 + const val VERSION_SCHEMA = 21 fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array { return arrayOf( @@ -124,7 +125,8 @@ abstract class AppDatabase : RoomDatabase() { Migration17(), Migration18(), Migration19(sharedPrefProvider), - Migration20() + Migration20(), + Migration21() ) } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Attendance.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Attendance.kt index 3c58971ae..aa8da8db7 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Attendance.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Attendance.kt @@ -15,6 +15,9 @@ data class Attendance( @ColumnInfo(name = "diary_id") val diaryId: Int, + @ColumnInfo(name = "time_id") + val timeId: Int, + val date: LocalDate, val number: Int, @@ -33,7 +36,13 @@ data class Attendance( val excused: Boolean, - val deleted: Boolean + val deleted: Boolean, + + val excusable: Boolean, + + @ColumnInfo(name = "excuse_status") + val excuseStatus: String? + ) : Serializable { @PrimaryKey(autoGenerate = true) diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration21.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration21.kt new file mode 100644 index 000000000..9d95f2ba4 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration21.kt @@ -0,0 +1,13 @@ +package io.github.wulkanowy.data.db.migrations + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +class Migration21 : Migration(20, 21) { + + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("ALTER TABLE Attendance ADD COLUMN excusable INTEGER NOT NULL DEFAULT 0") + database.execSQL("ALTER TABLE Attendance ADD COLUMN time_id INTEGER NOT NULL DEFAULT 0") + database.execSQL("ALTER TABLE Attendance ADD COLUMN excuse_status TEXT DEFAULT NULL") + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemote.kt index cd7702c10..1828c2bdf 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemote.kt @@ -3,8 +3,11 @@ package io.github.wulkanowy.data.repositories.attendance import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.sdk.pojo.Absent import io.reactivex.Single import org.threeten.bp.LocalDate +import org.threeten.bp.LocalDateTime +import org.threeten.bp.LocalTime import javax.inject.Inject import javax.inject.Singleton @@ -19,6 +22,7 @@ class AttendanceRemote @Inject constructor(private val sdk: Sdk) { studentId = semester.studentId, diaryId = semester.diaryId, date = it.date, + timeId = it.timeId, number = it.number, subject = it.subject, name = it.name, @@ -27,9 +31,20 @@ class AttendanceRemote @Inject constructor(private val sdk: Sdk) { exemption = it.exemption, lateness = it.lateness, excused = it.excused, - deleted = it.deleted + deleted = it.deleted, + excusable = it.excusable, + excuseStatus = it.excuseStatus?.name ) } } } + + fun excuseAbsence(semester: Semester, absenceList: List, reason: String?): Single { + return sdk.switchDiary(semester.diaryId, semester.schoolYear).excuseForAbsence(absenceList.map { attendance -> + Absent( + date = LocalDateTime.of(attendance.date, LocalTime.of(0, 0)), + timeId = attendance.timeId + ) + }, reason) + } } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRepository.kt index 85102b3c5..fc3830c2e 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRepository.kt @@ -41,4 +41,8 @@ class AttendanceRepository @Inject constructor( }).map { list -> list.filter { it.date in startDate..endDate } } } } + + fun excuseForAbsence(semester: Semester, attendanceList: List, reason: String? = null): Single { + return remote.excuseAbsence(semester, attendanceList, reason) + } } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/SentExcuseStatus.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/SentExcuseStatus.kt new file mode 100644 index 000000000..50d6b8ed5 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/SentExcuseStatus.kt @@ -0,0 +1,7 @@ +package io.github.wulkanowy.data.repositories.attendance + +enum class SentExcuseStatus(val id: Int = 0) { + WAITING, + ACCEPTED, + DENIED +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceAdapter.kt new file mode 100644 index 000000000..75f998404 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceAdapter.kt @@ -0,0 +1,12 @@ +package io.github.wulkanowy.ui.modules.attendance + +import eu.davidea.flexibleadapter.FlexibleAdapter +import eu.davidea.flexibleadapter.items.IFlexible +import io.github.wulkanowy.data.db.entities.Attendance + +class AttendanceAdapter> : FlexibleAdapter(null, null, true) { + + var excuseActionMode: Boolean = false + + var onExcuseCheckboxSelect: (attendanceItem: Attendance, checked: Boolean) -> Unit = { _, _ -> } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt index bc7c1cacd..9969b1c78 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt @@ -1,5 +1,6 @@ package io.github.wulkanowy.ui.modules.attendance +import android.content.DialogInterface.BUTTON_POSITIVE import android.os.Bundle import android.view.LayoutInflater import android.view.Menu @@ -10,8 +11,9 @@ import android.view.View.GONE import android.view.View.INVISIBLE import android.view.View.VISIBLE import android.view.ViewGroup +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.view.ActionMode import com.wdullaer.materialdatetimepicker.date.DatePickerDialog -import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.common.FlexibleItemDecoration import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager import eu.davidea.flexibleadapter.items.AbstractFlexibleItem @@ -24,6 +26,7 @@ import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.SchooldaysRangeLimiter import io.github.wulkanowy.utils.dpToPx import io.github.wulkanowy.utils.setOnItemClickListener +import kotlinx.android.synthetic.main.dialog_excuse.* import kotlinx.android.synthetic.main.fragment_attendance.* import org.threeten.bp.LocalDate import javax.inject.Inject @@ -35,7 +38,13 @@ class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MainChildVie lateinit var presenter: AttendancePresenter @Inject - lateinit var attendanceAdapter: FlexibleAdapter> + lateinit var attendanceAdapter: AttendanceAdapter> + + override val excuseSuccessString: String + get() = getString(R.string.attendance_excuse_success) + + override val excuseNoSelectionString: String + get() = getString(R.string.attendance_excuse_no_selection) companion object { private const val SAVED_DATE_KEY = "CURRENT_DATE" @@ -49,6 +58,34 @@ class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MainChildVie override val currentStackSize get() = (activity as? MainActivity)?.currentStackSize + override val excuseActionMode: Boolean get() = attendanceAdapter.excuseActionMode + + private var actionMode: ActionMode? = null + private val actionModeCallback = object : ActionMode.Callback { + override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean { + val inflater = mode.menuInflater + inflater.inflate(R.menu.context_menu_excuse, menu) + return true + } + + override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean { + mode.title = getString(R.string.attendance_excuse_title) + return presenter.onPrepareActionMode() + } + + override fun onDestroyActionMode(mode: ActionMode) { + presenter.onDestroyActionMode() + actionMode = null + } + + override fun onActionItemClicked(mode: ActionMode, menu: MenuItem): Boolean { + return when (menu.itemId) { + R.id.excuseMenuSubmit -> presenter.onExcuseSubmitButtonClick() + else -> false + } + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) @@ -66,6 +103,7 @@ class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MainChildVie override fun initView() { attendanceAdapter.setOnItemClickListener(presenter::onAttendanceItemSelected) + attendanceAdapter.onExcuseCheckboxSelect = presenter::onExcuseCheckboxSelect with(attendanceRecycler) { layoutManager = SmoothScrollLinearLayoutManager(context) @@ -83,6 +121,8 @@ class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MainChildVie attendanceNavDate.setOnClickListener { presenter.onPickDate() } attendanceNextButton.setOnClickListener { presenter.onNextDay() } + attendanceExcuseButton.setOnClickListener { presenter.onExcuseButtonClick() } + attendanceNavContainer.setElevationCompat(requireContext().dpToPx(8f)) } @@ -115,6 +155,10 @@ class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MainChildVie if (::presenter.isInitialized) presenter.onViewReselected() } + override fun onFragmentChanged() { + if (::presenter.isInitialized) presenter.onMainViewChanged() + } + override fun popView() { (activity as? MainActivity)?.popView() } @@ -155,6 +199,10 @@ class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MainChildVie attendanceNextButton.visibility = if (show) VISIBLE else INVISIBLE } + override fun showExcuseButton(show: Boolean) { + attendanceExcuseButton.visibility = if (show) VISIBLE else GONE + } + override fun showAttendanceDialog(lesson: Attendance) { (activity as? MainActivity)?.showDialogFragment(AttendanceDialog.newInstance(lesson)) } @@ -174,10 +222,38 @@ class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MainChildVie } } + override fun showExcuseDialog() { + AlertDialog.Builder(requireContext()) + .setTitle(R.string.attendance_excuse_title) + .setView(R.layout.dialog_excuse) + .setNegativeButton(android.R.string.cancel) { _, _ -> } + .create() + .apply { + setButton(BUTTON_POSITIVE, getString(R.string.attendance_excuse_dialog_submit)) { _, _ -> + presenter.onExcuseDialogSubmit(excuseReason.text?.toString().orEmpty()) + } + }.show() + } + override fun openSummaryView() { (activity as? MainActivity)?.pushView(AttendanceSummaryFragment.newInstance()) } + override fun startActionMode() { + actionMode = (activity as MainActivity?)?.startSupportActionMode(actionModeCallback) + } + + override fun showExcuseCheckboxes(show: Boolean) { + attendanceAdapter.apply { + excuseActionMode = show + notifyDataSetChanged() + } + } + + override fun finishActionMode() { + actionMode?.finish() + } + override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay()) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceItem.kt index 16a140cbf..7355aec2e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceItem.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceItem.kt @@ -1,18 +1,22 @@ package io.github.wulkanowy.ui.modules.attendance import android.view.View +import android.view.View.GONE import android.view.View.INVISIBLE import android.view.View.VISIBLE +import androidx.core.view.isVisible import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.viewholders.FlexibleViewHolder import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Attendance +import io.github.wulkanowy.data.repositories.attendance.SentExcuseStatus import kotlinx.android.extensions.LayoutContainer import kotlinx.android.synthetic.main.item_attendance.* -class AttendanceItem(val attendance: Attendance) : AbstractFlexibleItem() { +class AttendanceItem(val attendance: Attendance) : + AbstractFlexibleItem() { override fun getLayoutRes() = R.layout.item_attendance @@ -26,6 +30,34 @@ class AttendanceItem(val attendance: Attendance) : AbstractFlexibleItem + (adapter as AttendanceAdapter).onExcuseCheckboxSelect(attendance, checked) + } + + when (if (attendance.excuseStatus != null) SentExcuseStatus.valueOf(attendance.excuseStatus) else null) { + SentExcuseStatus.WAITING -> { + attendanceItemExcuseInfo.setImageResource(R.drawable.ic_excuse_waiting) + attendanceItemExcuseInfo.visibility = VISIBLE + attendanceItemAlert.visibility = INVISIBLE + } + SentExcuseStatus.DENIED -> { + attendanceItemExcuseInfo.setImageResource(R.drawable.ic_excuse_denied) + attendanceItemExcuseInfo.visibility = VISIBLE + } + else -> { + if (attendance.excusable && (adapter as AttendanceAdapter).excuseActionMode) { + attendanceItemNumber.visibility = GONE + attendanceItemExcuseCheckbox.visibility = VISIBLE + } else { + attendanceItemNumber.visibility = VISIBLE + attendanceItemExcuseCheckbox.visibility = GONE + } + } + } } } @@ -46,8 +78,20 @@ class AttendanceItem(val attendance: Attendance) : AbstractFlexibleItem) : FlexibleViewHolder(view, adapter), LayoutContainer { + class ViewHolder(view: View, val adapter: FlexibleAdapter<*>) : + FlexibleViewHolder(view, adapter), + LayoutContainer { + override val containerView: View get() = contentView + + override fun onClick(view: View?) { + super.onClick(view) + attendanceItemExcuseCheckbox.apply { + if ((adapter as AttendanceAdapter).excuseActionMode && isVisible) { + isChecked = !isChecked + } + } + } } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceModule.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceModule.kt new file mode 100644 index 000000000..eb35fea1b --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceModule.kt @@ -0,0 +1,12 @@ +package io.github.wulkanowy.ui.modules.attendance + +import dagger.Module +import dagger.Provides +import eu.davidea.flexibleadapter.items.AbstractFlexibleItem + +@Module +class AttendanceModule { + + @Provides + fun provideAttendanceFlexibleAdapter() = AttendanceAdapter>() +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt index 1490ee6e3..679d5367d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt @@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.attendance import android.annotation.SuppressLint import eu.davidea.flexibleadapter.items.AbstractFlexibleItem +import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.repositories.attendance.AttendanceRepository import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository import io.github.wulkanowy.data.repositories.semester.SemesterRepository @@ -40,6 +41,8 @@ class AttendancePresenter @Inject constructor( private lateinit var lastError: Throwable + private val attendanceToExcuseList = mutableListOf() + fun onAttachView(view: AttendanceView, date: Long?) { super.onAttachView(view) view.initView() @@ -51,11 +54,15 @@ class AttendancePresenter @Inject constructor( } fun onPreviousDay() { + view?.finishActionMode() + attendanceToExcuseList.clear() loadData(currentDate.previousSchoolDay) reloadView() } fun onNextDay() { + view?.finishActionMode() + attendanceToExcuseList.clear() loadData(currentDate.nextSchoolDay) reloadView() } @@ -100,10 +107,59 @@ class AttendancePresenter @Inject constructor( } } + fun onMainViewChanged() { + view?.finishActionMode() + } + fun onAttendanceItemSelected(item: AbstractFlexibleItem<*>?) { - if (item is AttendanceItem) { - Timber.i("Select attendance item ${item.attendance.id}") - view?.showAttendanceDialog(item.attendance) + view?.apply { + if (item is AttendanceItem && !excuseActionMode) { + Timber.i("Select attendance item ${item.attendance.id}") + showAttendanceDialog(item.attendance) + } + } + } + + fun onExcuseButtonClick() { + view?.startActionMode() + } + + fun onExcuseCheckboxSelect(attendanceItem: Attendance, checked: Boolean) { + if (checked) attendanceToExcuseList.add(attendanceItem) + else attendanceToExcuseList.remove(attendanceItem) + } + + fun onExcuseSubmitButtonClick(): Boolean { + view?.apply { + return if (attendanceToExcuseList.isNotEmpty()) { + showExcuseDialog() + true + } else { + showMessage(excuseNoSelectionString) + false + } + } + return false + } + + fun onExcuseDialogSubmit(reason: String) { + view?.finishActionMode() + excuseAbsence(if (reason != "") reason else null, attendanceToExcuseList.toList()) + } + + fun onPrepareActionMode(): Boolean { + view?.apply { + showExcuseCheckboxes(true) + showExcuseButton(false) + } + attendanceToExcuseList.clear() + return true + } + + fun onDestroyActionMode() { + view?.apply { + showExcuseCheckboxes(false) + showExcuseButton(true) } } @@ -157,6 +213,7 @@ class AttendancePresenter @Inject constructor( showEmpty(it.isEmpty()) showErrorView(false) showContent(it.isNotEmpty()) + showExcuseButton(it.any { item -> item.attendance.excusable }) } analytics.logEvent("load_attendance", "items" to it.size, "force_refresh" to forceRefresh) }) { @@ -167,6 +224,39 @@ class AttendancePresenter @Inject constructor( } } + private fun excuseAbsence(reason: String?, toExcuseList: List) { + Timber.i("Excusing absence started") + disposable.apply { + add(studentRepository.getCurrentStudent() + .delay(200, MILLISECONDS) + .flatMap { semesterRepository.getCurrentSemester(it) } + .flatMap { attendanceRepository.excuseForAbsence(it, toExcuseList, reason) } + .subscribeOn(schedulers.backgroundThread) + .observeOn(schedulers.mainThread) + .doOnSubscribe { + view?.apply { + showProgress(true) + showContent(false) + showExcuseButton(false) + } + } + .subscribe({ + Timber.i("Excusing for absence result: Success") + analytics.logEvent("excuse_absence", "items" to attendanceToExcuseList.size) + attendanceToExcuseList.clear() + view?.apply { + showExcuseButton(false) + showMessage(excuseSuccessString) + } + loadData(currentDate, true) + }) { + Timber.i("Excusing for absence result: An exception occurred") + view?.showProgress(false) + errorHandler.dispatch(it) + }) + } + } + private fun showErrorViewOnError(message: String, error: Throwable) { view?.run { if (isViewEmpty) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceView.kt index a6d0d4ba9..03e95053f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceView.kt @@ -10,6 +10,12 @@ interface AttendanceView : BaseView { val currentStackSize: Int? + val excuseSuccessString: String + + val excuseNoSelectionString: String + + val excuseActionMode: Boolean + fun initView() fun updateData(data: List) @@ -38,11 +44,21 @@ interface AttendanceView : BaseView { fun showNextButton(show: Boolean) + fun showExcuseButton(show: Boolean) + fun showAttendanceDialog(lesson: Attendance) fun showDatePickerDialog(currentDate: LocalDate) + fun showExcuseDialog() + fun openSummaryView() + fun startActionMode() + + fun showExcuseCheckboxes(show: Boolean) + + fun finishActionMode() + fun popView() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt index 991c1d106..ae4be9530 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt @@ -36,6 +36,7 @@ import io.github.wulkanowy.utils.getThemeAttrColor import io.github.wulkanowy.utils.safelyPopFragments import io.github.wulkanowy.utils.setOnViewChangeListener import kotlinx.android.synthetic.main.activity_main.* +import timber.log.Timber import javax.inject.Inject class MainActivity : BaseActivity(), MainView { @@ -167,6 +168,11 @@ class MainActivity : BaseActivity(), MainView { (navController.currentStack?.getOrNull(0) as? MainView.MainChildView)?.onFragmentReselected() } + override fun notifyMenuViewChanged() { + Timber.d("Menu view changed") + (navController.currentStack?.getOrNull(0) as? MainView.MainChildView)?.onFragmentChanged() + } + fun showDialogFragment(dialog: DialogFragment) { navController.showDialogFragment(dialog) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainModule.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainModule.kt index 41f4d5f2c..50e5896fe 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainModule.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainModule.kt @@ -13,6 +13,7 @@ import io.github.wulkanowy.ui.modules.about.license.LicenseFragment import io.github.wulkanowy.ui.modules.about.license.LicenseModule import io.github.wulkanowy.ui.modules.account.AccountDialog import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment +import io.github.wulkanowy.ui.modules.attendance.AttendanceModule import io.github.wulkanowy.ui.modules.attendance.summary.AttendanceSummaryFragment import io.github.wulkanowy.ui.modules.exam.ExamFragment import io.github.wulkanowy.ui.modules.grade.GradeFragment @@ -51,7 +52,7 @@ abstract class MainModule { } @PerFragment - @ContributesAndroidInjector + @ContributesAndroidInjector(modules = [AttendanceModule::class]) abstract fun bindAttendanceFragment(): AttendanceFragment @PerFragment diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt index 1c0fd39f3..8eccbc67e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt @@ -75,6 +75,7 @@ class MainPresenter @Inject constructor( notifyMenuViewReselected() false } else { + notifyMenuViewChanged() switchMenuView(index) true } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainView.kt index 033b6a1f6..0d8b14169 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainView.kt @@ -26,6 +26,8 @@ interface MainView : BaseView { fun notifyMenuViewReselected() + fun notifyMenuViewChanged() + fun setViewTitle(title: String) fun popView(depth: Int = 1) @@ -33,6 +35,8 @@ interface MainView : BaseView { interface MainChildView { fun onFragmentReselected() + + fun onFragmentChanged() {} } interface TitledView { diff --git a/app/src/main/res/drawable-night/background_header_note.xml b/app/src/main/res/drawable-night/background_header_note.xml index 2983b32c6..6b594e7c6 100644 --- a/app/src/main/res/drawable-night/background_header_note.xml +++ b/app/src/main/res/drawable-night/background_header_note.xml @@ -1,5 +1,5 @@ - - + + diff --git a/app/src/main/res/drawable/background_header_note.xml b/app/src/main/res/drawable/background_header_note.xml index 8e92e3abf..c21e55c6b 100644 --- a/app/src/main/res/drawable/background_header_note.xml +++ b/app/src/main/res/drawable/background_header_note.xml @@ -1,5 +1,5 @@ - - - \ No newline at end of file + + + diff --git a/app/src/main/res/drawable/ic_all_done.xml b/app/src/main/res/drawable/ic_all_done.xml new file mode 100644 index 000000000..bb657f6ec --- /dev/null +++ b/app/src/main/res/drawable/ic_all_done.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_all_done_all.xml b/app/src/main/res/drawable/ic_all_done_all.xml new file mode 100644 index 000000000..e27672efa --- /dev/null +++ b/app/src/main/res/drawable/ic_all_done_all.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_excuse_denied.xml b/app/src/main/res/drawable/ic_excuse_denied.xml new file mode 100644 index 000000000..218cfbdc4 --- /dev/null +++ b/app/src/main/res/drawable/ic_excuse_denied.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_excuse_waiting.xml b/app/src/main/res/drawable/ic_excuse_waiting.xml new file mode 100644 index 000000000..863418b7b --- /dev/null +++ b/app/src/main/res/drawable/ic_excuse_waiting.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/dialog_excuse.xml b/app/src/main/res/layout/dialog_excuse.xml new file mode 100644 index 000000000..4ed9294ce --- /dev/null +++ b/app/src/main/res/layout/dialog_excuse.xml @@ -0,0 +1,21 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_grade.xml b/app/src/main/res/layout/dialog_grade.xml index fad7bae57..be0570c20 100644 --- a/app/src/main/res/layout/dialog_grade.xml +++ b/app/src/main/res/layout/dialog_grade.xml @@ -40,16 +40,16 @@ @@ -57,16 +57,17 @@ android:id="@+id/gradeDialogHeader" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:minHeight="120dp" - android:gravity="center_vertical" - android:layout_toLeftOf="@+id/gradeDialogValueLayout" + android:layout_marginEnd="12dp" + android:layout_marginRight="12dp" android:layout_toStartOf="@+id/gradeDialogValueLayout" + android:layout_toLeftOf="@+id/gradeDialogValueLayout" android:layout_alignParentStart="true" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" - android:layout_marginRight="12dp" - android:layout_marginEnd="12dp" + android:gravity="center_vertical" + android:minHeight="120dp" android:orientation="vertical"> + + + diff --git a/app/src/main/res/layout/item_attendance.xml b/app/src/main/res/layout/item_attendance.xml index 95a8f0174..56bcab440 100644 --- a/app/src/main/res/layout/item_attendance.xml +++ b/app/src/main/res/layout/item_attendance.xml @@ -13,16 +13,40 @@ android:paddingBottom="7dp" tools:context=".ui.modules.attendance.AttendanceItem"> - + android:orientation="vertical"> + + + + + + + + + + + diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 458f64b45..f5f9f45d1 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -141,6 +141,11 @@ %1$d nieobecności %1$d nieobecności + Powód nieobecności (opcjonalny) + Wyślij + Usprawiedliwiono pomyślnie! + Musisz wybrać co najmniej jedną nieobecność! + Usprawiedliw diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8bdc54105..08b17825a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -135,6 +135,11 @@ %1$d absence %1$d absences + Absence reason (optional) + Send + Absence excused successfully! + You must select at least one absence! + Excuse diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 68c0800b1..8f30e3457 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -16,6 +16,7 @@