diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7f8591bb1..3def08953 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,12 +2,10 @@ name: Tests on: push: - branches: - - master - - develop - - 'hotfix/**' + branches: [ master, develop ] tags: [ '*' ] pull_request: + branches: [ master, develop ] jobs: diff --git a/LICENSE b/LICENSE index a1fc37058..c97032f74 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2023 Wulkanowy + Copyright 2022 Wulkanowy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.cs.md b/README.cs.md index 8171b27d6..5c1e5ea71 100644 --- a/README.cs.md +++ b/README.cs.md @@ -1,13 +1,18 @@ -Česká verze / [Deutsche Version](README.de.md) / [English version](README.en.md) / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md) +[English version of README](README.en.md) + +[Deutsche Version von README](README.de.md) + +[Polska wersja README](README.md) + +[Slovenská verzia README](README.sk.md) # Wulkanowy -[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/wulkanowy/wulkanowy/test.yml?branch=develop&style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions) +[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions) [![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy) [![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr) [![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/) [![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases) -[![Crowdin](https://badges.crowdin.net/wulkanowy2/localized.svg)](https://translate.wulkanowy.net.pl) Neoficiální klient deníku VULCAN UONET+ pro žáka a rodiče @@ -34,7 +39,7 @@ Neoficiální klient deníku VULCAN UONET+ pro žáka a rodiče * podpora více účtů s možností přejmenování žáků * tmavý a černý (AMOLED) motiv * offline režim -* volitelné reklamy na podporu projektu +* žádné reklamy ## Stáhnout @@ -52,7 +57,7 @@ Aktuální verzi si můžete stáhnout z Google Play, F-Droid nebo Huawei AppGal Můžete si také stáhnout [vývojovou verzi](https://wulkanowy.github.io/#download), která zahrnuje nové funkce připravované pro příští vydání -## Postaveno s pomocí +## Postaveno s * [Wulkanowy SDK](https://github.com/wulkanowy/sdk) diff --git a/README.de.md b/README.de.md index 972f66ba9..b9e1d1ec1 100644 --- a/README.de.md +++ b/README.de.md @@ -1,13 +1,14 @@ -[Česká verze](README.cs.md) / Deutsche Version / [English version](README.en.md) / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md) +[Polska wersja README](README.md) + +[English version of README](README.en.md) # Wulkanowy -[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/wulkanowy/wulkanowy/test.yml?branch=develop&style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions) +[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions) [![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy) [![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr) [![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/) [![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases) -[![Crowdin](https://badges.crowdin.net/wulkanowy2/localized.svg)](https://translate.wulkanowy.net.pl) Inoffizieller Android VULCAN UONET+ Registrierungsclient für Schüler und ihre Eltern @@ -21,7 +22,7 @@ Inoffizieller Android VULCAN UONET+ Registrierungsclient für Schüler und ihre * Prozentsatz der Anwesenheit * Prüfungen * Stundenplan - * abgeschlossene Unterrichtsstunden + * Unterricht abgeschlossen * Nachrichten * Hausaufgaben * Anmerkungen @@ -34,7 +35,7 @@ Inoffizieller Android VULCAN UONET+ Registrierungsclient für Schüler und ihre * Unterstützung für mehrere Konten mit der Möglichkeit, den Namen des Schülers zu ändern * dunkles und schwarzes (AMOLED) Thema * Offline-Modus -* optionale Werbungen, die es uns ermöglichen das Projekt zu unterstützen +* keine Werbung ## Herunterladen diff --git a/README.en.md b/README.en.md index 6e4da4637..1ac2a6721 100644 --- a/README.en.md +++ b/README.en.md @@ -1,13 +1,18 @@ -[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / English version / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md) +[Polska wersja README](README.md) + +[Deutsche Version von README](README.de.md) + +[Česká verze README](README.cs.md) + +[Slovenská verzia README](README.sk.md) # Wulkanowy -[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/wulkanowy/wulkanowy/test.yml?branch=develop&style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions) +[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions) [![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy) [![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr) [![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/) [![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases) -[![Crowdin](https://badges.crowdin.net/wulkanowy2/localized.svg)](https://translate.wulkanowy.net.pl) Unofficial android VULCAN UONET+ register client for both students and their parents @@ -34,7 +39,7 @@ Unofficial android VULCAN UONET+ register client for both students and their par * support for multiple accounts with the ability to rename students * dark and black (AMOLED) theme * offline mode -* optional ads which allow to support the project +* no ads ## Download diff --git a/README.md b/README.md index f3d2e29a2..e7c7d4c5e 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,18 @@ -[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / [English version](README.en.md) / Polska wersja / [Slovenská verzia](README.sk.md) +[English version of README](README.en.md) + +[Deutsche Version von README](README.de.md) + +[Česká verze README](README.cs.md) + +[Slovenská verzia README](README.sk.md) # Wulkanowy -[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/wulkanowy/wulkanowy/test.yml?branch=develop&style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions) +[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions) [![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy) [![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr) [![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/) [![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases) -[![Crowdin](https://badges.crowdin.net/wulkanowy2/localized.svg)](https://translate.wulkanowy.net.pl) Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica @@ -34,7 +39,7 @@ Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica * obsługa wielu kont wraz z możliwością zmiany nazwy ucznia * ciemny i czarny (AMOLED) motyw * tryb offline -* opcjonalne reklamy umożliwiające wsparcie projektu +* brak reklam ## Pobierz diff --git a/README.sk.md b/README.sk.md index ff0c6e3c9..2f3ba41dd 100644 --- a/README.sk.md +++ b/README.sk.md @@ -1,13 +1,18 @@ -[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / [English version](README.en.md) / [Polska wersja](README.md) / Slovenská verzia +[English version of README](README.en.md) + +[Deutsche Version von README](README.de.md) + +[Polska wersja README](README.md) + +[Česká verze README](README.cs.md) # Wulkanowy -[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/wulkanowy/wulkanowy/test.yml?branch=develop&style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions) +[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions) [![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy) [![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr) [![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/) [![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases) -[![Crowdin](https://badges.crowdin.net/wulkanowy2/localized.svg)](https://translate.wulkanowy.net.pl) Neoficiálny klient denníka VULCAN UONET+ pre žiaka a rodičov @@ -34,7 +39,7 @@ Neoficiálny klient denníka VULCAN UONET+ pre žiaka a rodičov * podpora viacerých účtov s možnosťou premenovania žiakov * tmavý a čierny (AMOLED) motív * offline režim -* voliteľné reklamy na podporu projektu +* žiadne reklamy ## Stiahnuť @@ -52,7 +57,7 @@ Aktuálnu verziu si môžete stiahnuť z Google Play, F-Droid alebo Huawei AppGa Môžete si tiež stiahnuť [vývojovú verziu](https://wulkanowy.github.io/#download), ktorá zahrňuje nové funkcie pripravované pre budúce vydanie -## Postavené s pomocou +## Postavené s * [Wulkanowy SDK](https://github.com/wulkanowy/sdk) diff --git a/app/build.gradle b/app/build.gradle index ce9039dfa..5fb07377a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,15 +16,15 @@ apply from: 'hooks.gradle' android { namespace 'io.github.wulkanowy' - compileSdkVersion 33 + compileSdkVersion 32 defaultConfig { applicationId "io.github.wulkanowy" testApplicationId "io.github.tests.wulkanowy" minSdkVersion 21 - targetSdkVersion 33 - versionCode 119 - versionName "1.9.0" + targetSdkVersion 32 + versionCode 110 + versionName "1.7.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" resValue "string", "app_name", "Wulkanowy" @@ -161,8 +161,8 @@ play { defaultToAppBundles = false track = 'production' releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS - userFraction = 0.10d - updatePriority = 1 + userFraction = 0.95d + updatePriority = 5 enabled.set(false) } @@ -181,24 +181,24 @@ ext { android_hilt = "1.0.0" room = "2.4.3" chucker = "3.5.2" - mockk = "1.13.3" + mockk = "1.12.5" coroutines = "1.6.4" } dependencies { - implementation "io.github.wulkanowy:sdk:1.9.0" + implementation "io.github.wulkanowy:sdk:1.7.0" - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.6' - implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1" + implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines" - implementation "androidx.core:core-ktx:1.9.0" + implementation "androidx.core:core-ktx:1.8.0" implementation 'androidx.core:core-splashscreen:1.0.0' - implementation "androidx.activity:activity-ktx:1.6.1" - implementation "androidx.appcompat:appcompat:1.5.1" - implementation "androidx.fragment:fragment-ktx:1.5.5" - implementation "androidx.annotation:annotation:1.5.0" + implementation "androidx.activity:activity-ktx:1.5.1" + implementation "androidx.appcompat:appcompat:1.5.0" + implementation "androidx.fragment:fragment-ktx:1.5.2" + implementation "androidx.annotation:annotation:1.4.0" implementation "androidx.preference:preference-ktx:1.2.0" implementation "androidx.recyclerview:recyclerview:1.2.1" @@ -206,10 +206,10 @@ dependencies { implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" implementation "androidx.constraintlayout:constraintlayout:2.1.4" implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0" - implementation "com.google.android.material:material:1.7.0" + implementation "com.google.android.material:material:1.6.1" implementation "com.github.wulkanowy:material-chips-input:2.3.1" implementation "com.github.PhilJay:MPAndroidChart:v3.1.0" - implementation 'com.github.lopspower:CircularImageView:4.3.0' + implementation 'com.github.lopspower:CircularImageView:4.2.0' implementation "androidx.work:work-runtime-ktx:$work_manager" playImplementation "androidx.work:work-gcm:$work_manager" @@ -236,22 +236,21 @@ dependencies { implementation "at.favre.lib:slf4j-timber:1.0.1" implementation 'com.github.bastienpaulfr:Treessence:1.0.5' implementation "com.mikepenz:aboutlibraries-core:$about_libraries" - implementation "io.coil-kt:coil:2.2.2" - implementation "io.github.wulkanowy:AppKillerManager:3.0.1" + implementation "io.coil-kt:coil:2.2.0" + implementation "io.github.wulkanowy:AppKillerManager:3.0.0" implementation 'me.xdrop:fuzzywuzzy:1.4.0' implementation 'com.fredporciuncula:flow-preferences:1.8.0' - implementation 'org.apache.commons:commons-text:1.10.0' - playImplementation platform('com.google.firebase:firebase-bom:31.1.1') + playImplementation platform('com.google.firebase:firebase-bom:30.3.2') playImplementation 'com.google.firebase:firebase-analytics-ktx' playImplementation 'com.google.firebase:firebase-messaging:' playImplementation 'com.google.firebase:firebase-crashlytics:' playImplementation 'com.google.android.play:core:1.10.3' playImplementation 'com.google.android.play:core-ktx:1.8.1' - playImplementation 'com.google.android.gms:play-services-ads:21.4.0' + playImplementation 'com.google.android.gms:play-services-ads:21.1.0' - hmsImplementation 'com.huawei.hms:hianalytics:6.9.0.301' - hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.3.302' + hmsImplementation 'com.huawei.hms:hianalytics:6.7.0.300' + hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.1.300' releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker" @@ -264,17 +263,17 @@ dependencies { testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines" testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" - testImplementation 'org.robolectric:robolectric:4.9.1' - testImplementation "androidx.test:runner:1.5.1" - testImplementation "androidx.test.ext:junit:1.1.4" - testImplementation "androidx.test:core:1.5.0" + testImplementation 'org.robolectric:robolectric:4.8.1' + testImplementation "androidx.test:runner:1.4.0" + testImplementation "androidx.test.ext:junit:1.1.3" + testImplementation "androidx.test:core:1.4.0" testImplementation "androidx.room:room-testing:$room" testImplementation "com.google.dagger:hilt-android-testing:$hilt_version" kaptTest "com.google.dagger:hilt-android-compiler:$hilt_version" - androidTestImplementation "androidx.test:core:1.5.0" - androidTestImplementation "androidx.test:runner:1.5.1" - androidTestImplementation "androidx.test.ext:junit:1.1.4" + androidTestImplementation "androidx.test:core:1.4.0" + androidTestImplementation "androidx.test:runner:1.4.0" + androidTestImplementation "androidx.test.ext:junit:1.1.3" androidTestImplementation "io.mockk:mockk-android:$mockk" androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" } diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/52.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/52.json deleted file mode 100644 index 129d1917b..000000000 --- a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/52.json +++ /dev/null @@ -1,2421 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 52, - "identityHash": "8742176f26afcc81279d4a073dca2949", - "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, `read_by` INTEGER, `unread_by` INTEGER, `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": "readBy", - "columnName": "read_by", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "unreadBy", - "columnName": "unread_by", - "affinity": "INTEGER", - "notNull": false - }, - { - "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, '8742176f26afcc81279d4a073dca2949')" - ] - } -} \ No newline at end of file diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/53.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/53.json deleted file mode 100644 index 985617872..000000000 --- a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/53.json +++ /dev/null @@ -1,2439 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 53, - "identityHash": "1dc96a366125ec9f8567da87cdc9c863", - "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}` (`email` TEXT NOT NULL, `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, `read_by` INTEGER, `unread_by` INTEGER, `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": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "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": "readBy", - "columnName": "read_by", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "unreadBy", - "columnName": "unread_by", - "affinity": "INTEGER", - "notNull": false - }, - { - "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, `email` TEXT NOT NULL, `symbol` TEXT NOT NULL, `schoolId` TEXT NOT NULL, `fullName` TEXT NOT NULL, `userName` TEXT 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": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "symbol", - "columnName": "symbol", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "schoolId", - "columnName": "schoolId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "fullName", - "columnName": "fullName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "userName", - "columnName": "userName", - "affinity": "TEXT", - "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, '1dc96a366125ec9f8567da87cdc9c863')" - ] - } -} \ No newline at end of file diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/54.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/54.json deleted file mode 100644 index 7b41672b9..000000000 --- a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/54.json +++ /dev/null @@ -1,2439 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 54, - "identityHash": "1dc96a366125ec9f8567da87cdc9c863", - "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}` (`email` TEXT NOT NULL, `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, `read_by` INTEGER, `unread_by` INTEGER, `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": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "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": "readBy", - "columnName": "read_by", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "unreadBy", - "columnName": "unread_by", - "affinity": "INTEGER", - "notNull": false - }, - { - "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, `email` TEXT NOT NULL, `symbol` TEXT NOT NULL, `schoolId` TEXT NOT NULL, `fullName` TEXT NOT NULL, `userName` TEXT 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": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "symbol", - "columnName": "symbol", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "schoolId", - "columnName": "schoolId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "fullName", - "columnName": "fullName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "userName", - "columnName": "userName", - "affinity": "TEXT", - "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, '1dc96a366125ec9f8567da87cdc9c863')" - ] - } -} \ No newline at end of file diff --git a/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml index b7b756b9e..7dbec2cb9 100644 --- a/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml @@ -2,5 +2,4 @@ - - + \ No newline at end of file diff --git a/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000..7dbec2cb9 --- /dev/null +++ b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/debug/res/mipmap-hdpi/ic_launcher_round.png b/app/src/debug/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 000000000..81e723ecc Binary files /dev/null and b/app/src/debug/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/debug/res/mipmap-mdpi/ic_launcher_round.png b/app/src/debug/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 000000000..394b57076 Binary files /dev/null and b/app/src/debug/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 000000000..365b4d663 Binary files /dev/null and b/app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..463c089b3 Binary files /dev/null and b/app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..53d6f5bbd Binary files /dev/null and b/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/fdroid/java/io/github/wulkanowy/utils/AnalyticsHelper.kt b/app/src/fdroid/java/io/github/wulkanowy/utils/AnalyticsHelper.kt index a3eed484a..3bf7e1693 100644 --- a/app/src/fdroid/java/io/github/wulkanowy/utils/AnalyticsHelper.kt +++ b/app/src/fdroid/java/io/github/wulkanowy/utils/AnalyticsHelper.kt @@ -8,7 +8,15 @@ import javax.inject.Singleton @Suppress("UNUSED_PARAMETER") class AnalyticsHelper @Inject constructor() { - fun logEvent(name: String, vararg params: Pair) = Unit - fun setCurrentScreen(activity: Activity, name: String?) = Unit - fun popCurrentScreen(name: String?) = Unit + fun logEvent(name: String, vararg params: Pair) { + // do nothing + } + + fun setCurrentScreen(activity: Activity, name: String?) { + // do nothing + } + + fun popCurrentScreen(name: String?) { + // do nothing + } } diff --git a/app/src/hms/java/io/github/wulkanowy/utils/AnalyticsHelper.kt b/app/src/hms/java/io/github/wulkanowy/utils/AnalyticsHelper.kt index 1f78931ae..5d33825f1 100644 --- a/app/src/hms/java/io/github/wulkanowy/utils/AnalyticsHelper.kt +++ b/app/src/hms/java/io/github/wulkanowy/utils/AnalyticsHelper.kt @@ -3,38 +3,26 @@ package io.github.wulkanowy.utils import android.app.Activity import android.content.Context import android.os.Bundle -import com.huawei.agconnect.crash.AGConnectCrash import com.huawei.hms.analytics.HiAnalytics import dagger.hilt.android.qualifiers.ApplicationContext -import io.github.wulkanowy.data.repositories.PreferencesRepository import javax.inject.Inject import javax.inject.Singleton @Singleton class AnalyticsHelper @Inject constructor( - @ApplicationContext private val context: Context, - preferencesRepository: PreferencesRepository, - appInfo: AppInfo, + @ApplicationContext private val context: Context ) { private val analytics by lazy { HiAnalytics.getInstance(context) } - private val connectCrash by lazy { AGConnectCrash.getInstance() } - - init { - if (!appInfo.isDebug) { - connectCrash.setUserId(preferencesRepository.installationId) - } - } - fun logEvent(name: String, vararg params: Pair) { Bundle().apply { - params.forEach { (key, value) -> - if (value == null) return@forEach - when (value) { - is String -> putString(key, value) - is Int -> putInt(key, value) - is Boolean -> putBoolean(key, value) + params.forEach { + if (it.second == null) return@forEach + when (it.second) { + is String, is String? -> putString(it.first, it.second as String) + is Int, is Int? -> putInt(it.first, it.second as Int) + is Boolean, is Boolean? -> putBoolean(it.first, it.second as Boolean) } } analytics.onEvent(name, this) diff --git a/app/src/hms/java/io/github/wulkanowy/utils/CrashLogUtils.kt b/app/src/hms/java/io/github/wulkanowy/utils/CrashLogUtils.kt index 377e83666..b0c34f413 100644 --- a/app/src/hms/java/io/github/wulkanowy/utils/CrashLogUtils.kt +++ b/app/src/hms/java/io/github/wulkanowy/utils/CrashLogUtils.kt @@ -3,7 +3,6 @@ package io.github.wulkanowy.utils import android.util.Log import com.huawei.agconnect.crash.AGConnectCrash import fr.bipi.tressence.base.FormatterPriorityTree -import fr.bipi.tressence.common.StackTraceRecorder class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) { @@ -23,10 +22,16 @@ class CrashLogExceptionTree : FormatterPriorityTree(Log.ERROR, ExceptionFilter) override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { if (skipLog(priority, tag, message, t)) return + // Disabled due to a bug in the Huawei library + + /*connectCrash.setCustomKey("priority", priority) + connectCrash.setCustomKey("tag", tag.orEmpty()) + connectCrash.setCustomKey("message", message) + if (t != null) { connectCrash.recordException(t) } else { connectCrash.recordException(StackTraceRecorder(format(priority, tag, message))) - } + }*/ } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3773093b2..7835db902 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -8,8 +8,7 @@ - - + @@ -37,14 +36,13 @@ + tools:ignore="GoogleAppIndexingWarning,UnusedAttribute"> Resource.mapData(block: (T) -> U) = when (this) { fun Flow>.logResourceStatus(name: String, showData: Boolean = false) = onEach { val description = when (it) { - is Resource.Intermediate -> "intermediate data received" + if (showData) " (data: `${it.data}`)" else "" is Resource.Loading -> "started" + is Resource.Intermediate -> "intermediate data received" + if (showData) " (data: `${it.data}`)" else "" is Resource.Success -> "success" + if (showData) " (data: `${it.data}`)" else "" is Resource.Error -> "exception occurred: ${it.error}" } 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 cfb53485f..15b38805b 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 @@ -47,7 +47,6 @@ import javax.inject.Singleton AutoMigration(from = 44, to = 45), AutoMigration(from = 46, to = 47), AutoMigration(from = 47, to = 48), - AutoMigration(from = 51, to = 52), ], version = AppDatabase.VERSION_SCHEMA, exportSchema = true @@ -56,7 +55,7 @@ import javax.inject.Singleton abstract class AppDatabase : RoomDatabase() { companion object { - const val VERSION_SCHEMA = 54 + const val VERSION_SCHEMA = 51 fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf( Migration2(), @@ -106,8 +105,6 @@ abstract class AppDatabase : RoomDatabase() { Migration49(), Migration50(), Migration51(), - Migration53(), - Migration54(), ) fun newInstance( diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/BaseDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/BaseDao.kt index 056a5cbd1..048e9e3cd 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/BaseDao.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/BaseDao.kt @@ -2,12 +2,11 @@ package io.github.wulkanowy.data.db.dao import androidx.room.Delete import androidx.room.Insert -import androidx.room.OnConflictStrategy import androidx.room.Update interface BaseDao { - @Insert(onConflict = OnConflictStrategy.REPLACE) + @Insert suspend fun insertAll(items: List): List @Update 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 index 084192a07..8589db311 100644 --- 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 @@ -3,16 +3,15 @@ package io.github.wulkanowy.data.db.dao import androidx.room.Dao import androidx.room.Query import io.github.wulkanowy.data.db.entities.Mailbox -import kotlinx.coroutines.flow.Flow import javax.inject.Singleton @Singleton @Dao interface MailboxDao : BaseDao { - @Query("SELECT * FROM Mailboxes WHERE email = :email") - suspend fun loadAll(email: String): List + @Query("SELECT * FROM Mailboxes WHERE userLoginId = :userLoginId ") + suspend fun loadAll(userLoginId: Int): List - @Query("SELECT * FROM Mailboxes WHERE email = :email AND symbol = :symbol AND schoolId = :schoolId") - fun loadAll(email: String, symbol: String, schoolId: String): Flow> + @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 1709f7636..8c730c9bc 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 @@ -16,7 +16,4 @@ interface MessagesDao : BaseDao { @Query("SELECT * FROM Messages WHERE mailbox_key = :mailboxKey AND folder_id = :folder ORDER BY date DESC") fun loadAll(mailboxKey: String, folder: Int): Flow> - - @Query("SELECT * FROM Messages WHERE email = :email AND folder_id = :folder ORDER BY date DESC") - fun loadAll(folder: Int, email: String): Flow> } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/TimetableDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/TimetableDao.kt index b4b7379f2..5e6eec668 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/TimetableDao.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/TimetableDao.kt @@ -13,7 +13,4 @@ interface TimetableDao : BaseDao { @Query("SELECT * FROM Timetable WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end") fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow> - - @Query("SELECT * FROM Timetable WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end") - fun load(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): List } 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 index e65e213dd..7c08e481d 100644 --- 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 @@ -1,27 +1,20 @@ package io.github.wulkanowy.data.db.entities -import android.os.Parcelable import androidx.room.Entity import androidx.room.PrimaryKey -import kotlinx.parcelize.Parcelize -@Parcelize @Entity(tableName = "Mailboxes") data class Mailbox( @PrimaryKey val globalKey: String, - - val email: String, - val symbol: String, - val schoolId: String, - val fullName: String, val userName: String, + val userLoginId: Int, val studentName: String, val schoolNameShort: String, val type: MailboxType, -) : java.io.Serializable, Parcelable +) enum class MailboxType { STUDENT, 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 d1356b33d..77874e03d 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,9 +9,6 @@ import java.time.Instant @Entity(tableName = "Messages") data class Message( - @ColumnInfo(name = "email") - val email: String, - @ColumnInfo(name = "message_global_key") val messageGlobalKey: String, @@ -32,12 +29,6 @@ data class Message( var unread: Boolean, - @ColumnInfo(name = "read_by") - val readBy: Int?, - - @ColumnInfo(name = "unread_by") - val unreadBy: Int?, - @ColumnInfo(name = "has_attachments") val hasAttachments: Boolean ) : Serializable { diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration53.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration53.kt deleted file mode 100644 index 12624a51a..000000000 --- a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration53.kt +++ /dev/null @@ -1,57 +0,0 @@ -package io.github.wulkanowy.data.db.migrations - -import androidx.room.migration.Migration -import androidx.sqlite.db.SupportSQLiteDatabase - -class Migration53 : Migration(52, 53) { - - override fun migrate(database: SupportSQLiteDatabase) { - createMailboxTable(database) - recreateMessagesTable(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, - `email` TEXT NOT NULL, - `symbol` TEXT NOT NULL, - `schoolId` TEXT NOT NULL, - `fullName` TEXT NOT NULL, - `userName` TEXT 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` ( - `email` TEXT NOT NULL, - `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, - `read_by` INTEGER, - `unread_by` INTEGER, - `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() - ) - } -} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration54.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration54.kt deleted file mode 100644 index 678bd32f2..000000000 --- a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration54.kt +++ /dev/null @@ -1,26 +0,0 @@ -package io.github.wulkanowy.data.db.migrations - -import androidx.room.migration.Migration -import androidx.sqlite.db.SupportSQLiteDatabase - -class Migration54 : Migration(53, 54) { - - override fun migrate(database: SupportSQLiteDatabase) { - migrateResman(database) - removeTomaszowMazowieckiStudents(database) - } - - private fun migrateResman(database: SupportSQLiteDatabase) { - database.execSQL(""" - UPDATE Students SET - scrapper_base_url = 'https://vulcan.net.pl', - login_type = 'ADFSLightScoped', - symbol = 'rzeszowprojekt' - WHERE scrapper_base_url = 'https://resman.pl' - """.trimIndent()) - } - - private fun removeTomaszowMazowieckiStudents(database: SupportSQLiteDatabase) { - database.execSQL("DELETE FROM Students WHERE symbol = 'tomaszowmazowiecki'") - } -} diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/AttendanceMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/AttendanceMapper.kt index c0ed0c8c2..46e67fdaa 100644 --- a/app/src/main/java/io/github/wulkanowy/data/mappers/AttendanceMapper.kt +++ b/app/src/main/java/io/github/wulkanowy/data/mappers/AttendanceMapper.kt @@ -3,22 +3,17 @@ package io.github.wulkanowy.data.mappers import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.db.entities.AttendanceSummary import io.github.wulkanowy.data.db.entities.Semester -import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.sdk.pojo.Attendance as SdkAttendance import io.github.wulkanowy.sdk.pojo.AttendanceSummary as SdkAttendanceSummary -fun List.mapToEntities(semester: Semester, lessons: List) = map { +fun List.mapToEntities(semester: Semester) = map { Attendance( studentId = semester.studentId, diaryId = semester.diaryId, date = it.date, timeId = it.timeId, number = it.number, - subject = it.subject.ifBlank { - lessons.find { lesson -> - lesson.date == it.date && lesson.number == it.number - }?.subject.orEmpty() - }, + subject = it.subject, name = it.name, presence = it.presence, absence = it.absence, 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 index 0cf547770..2ccca1b90 100644 --- a/app/src/main/java/io/github/wulkanowy/data/mappers/MailboxMapper.kt +++ b/app/src/main/java/io/github/wulkanowy/data/mappers/MailboxMapper.kt @@ -10,11 +10,9 @@ fun List.mapToEntities(student: Student) = map { globalKey = it.globalKey, fullName = it.fullName, userName = it.userName, + userLoginId = student.userLoginId, studentName = it.studentName, schoolNameShort = it.schoolNameShort, type = MailboxType.valueOf(it.type.name), - email = student.email, - symbol = student.symbol, - schoolId = student.schoolSymbol, ) } 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 2ede5aa1b..2e7967f0e 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 @@ -2,36 +2,21 @@ package io.github.wulkanowy.data.mappers import io.github.wulkanowy.data.db.entities.* import io.github.wulkanowy.sdk.pojo.MailboxType -import timber.log.Timber 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, - mailbox: Mailbox?, - allMailboxes: List -): List = map { +fun List.mapToEntities(mailbox: Mailbox) = map { Message( messageGlobalKey = it.globalKey, - mailboxKey = mailbox?.globalKey ?: allMailboxes.find { box -> - box.fullName == it.mailbox - }?.globalKey.let { mailboxKey -> - if (mailboxKey == null) { - Timber.e("Can't find ${it.mailbox} in $allMailboxes") - "unknown" - } else mailboxKey - }, - email = student.email, + mailboxKey = mailbox.globalKey, messageId = it.id, correspondents = it.correspondents, subject = it.subject.trim(), date = it.dateZoned.toInstant(), folderId = it.folderId, unread = it.unread, - unreadBy = it.unreadBy, - readBy = it.readBy, - hasAttachments = it.hasAttachments, + hasAttachments = it.hasAttachments ).apply { content = it.content.orEmpty() } diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/RegisterUserMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/RegisterUserMapper.kt deleted file mode 100644 index 2dfd7e062..000000000 --- a/app/src/main/java/io/github/wulkanowy/data/mappers/RegisterUserMapper.kt +++ /dev/null @@ -1,87 +0,0 @@ -package io.github.wulkanowy.data.mappers - -import io.github.wulkanowy.data.db.entities.Student -import io.github.wulkanowy.data.db.entities.StudentWithSemesters -import io.github.wulkanowy.data.pojos.* -import io.github.wulkanowy.sdk.Sdk -import io.github.wulkanowy.sdk.mapper.mapSemesters -import java.time.Instant -import io.github.wulkanowy.sdk.scrapper.register.RegisterStudent as SdkRegisterStudent -import io.github.wulkanowy.sdk.scrapper.register.RegisterUser as SdkRegisterUser - -fun SdkRegisterUser.mapToPojo(password: String) = RegisterUser( - email = email, - login = login, - password = password, - baseUrl = baseUrl, - loginType = loginType, - symbols = symbols.map { registerSymbol -> - RegisterSymbol( - symbol = registerSymbol.symbol, - error = registerSymbol.error, - userName = registerSymbol.userName, - schools = registerSymbol.schools.map { - RegisterUnit( - userLoginId = it.userLoginId, - schoolId = it.schoolId, - schoolName = it.schoolName, - schoolShortName = it.schoolShortName, - parentIds = it.parentIds, - studentIds = it.studentIds, - employeeIds = it.employeeIds, - error = it.error, - students = it.subjects - .filterIsInstance() - .map { registerSubject -> - RegisterStudent( - studentId = registerSubject.studentId, - studentName = registerSubject.studentName, - studentSecondName = registerSubject.studentSecondName, - studentSurname = registerSubject.studentSurname, - className = registerSubject.className, - classId = registerSubject.classId, - isParent = registerSubject.isParent, - semesters = registerSubject.semesters - .mapSemesters() - .mapToEntities(registerSubject.studentId), - ) - }, - ) - } - ) - } -) - -fun RegisterStudent.mapToStudentWithSemesters( - user: RegisterUser, - symbol: RegisterSymbol, - unit: RegisterUnit, - colors: List, -): StudentWithSemesters = StudentWithSemesters( - semesters = semesters, - student = Student( - email = user.login, // for compatibility - userName = symbol.userName, - userLoginId = unit.userLoginId, - isParent = isParent, - className = className, - classId = classId, - studentId = studentId, - symbol = symbol.symbol, - loginType = user.loginType.name, - schoolName = unit.schoolName, - schoolShortName = unit.schoolShortName, - schoolSymbol = unit.schoolId, - studentName = "$studentName $studentSurname", - loginMode = Sdk.Mode.SCRAPPER.name, - scrapperBaseUrl = user.baseUrl, - mobileBaseUrl = "", - certificateKey = "", - privateKey = "", - password = user.password, - isCurrent = false, - registrationDate = Instant.now(), - ).apply { - avatarColor = colors.random() - }, -) diff --git a/app/src/main/java/io/github/wulkanowy/data/pojos/RegisterUser.kt b/app/src/main/java/io/github/wulkanowy/data/pojos/RegisterUser.kt deleted file mode 100644 index 4aea33771..000000000 --- a/app/src/main/java/io/github/wulkanowy/data/pojos/RegisterUser.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.github.wulkanowy.data.pojos - -import io.github.wulkanowy.data.db.entities.Semester -import io.github.wulkanowy.sdk.scrapper.Scrapper - -data class RegisterUser( - val email: String, - val password: String, - val login: String, // may be the same as email - val baseUrl: String, - val loginType: Scrapper.LoginType, - val symbols: List, -) : java.io.Serializable - -data class RegisterSymbol( - val symbol: String, - val error: Throwable?, - val userName: String, - val schools: List, -) : java.io.Serializable - -data class RegisterUnit( - val userLoginId: Int, - val schoolId: String, - val schoolName: String, - val schoolShortName: String, - val parentIds: List, - val studentIds: List, - val employeeIds: List, - val error: Throwable?, - val students: List, -) : java.io.Serializable - -data class RegisterStudent( - val studentId: Int, - val studentName: String, - val studentSecondName: String, - val studentSurname: String, - val className: String, - val classId: Int, - val isParent: Boolean, - val semesters: List, -) : java.io.Serializable diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceRepository.kt index fd5d8bd16..9aa6562a6 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceRepository.kt @@ -1,7 +1,6 @@ package io.github.wulkanowy.data.repositories import io.github.wulkanowy.data.db.dao.AttendanceDao -import io.github.wulkanowy.data.db.dao.TimetableDao import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student @@ -10,10 +9,8 @@ import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.pojo.Absent import io.github.wulkanowy.utils.* -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.withContext import java.time.LocalDate import java.time.LocalDateTime import java.time.LocalTime @@ -23,7 +20,6 @@ import javax.inject.Singleton @Singleton class AttendanceRepository @Inject constructor( private val attendanceDb: AttendanceDao, - private val timetableDb: TimetableDao, private val sdk: Sdk, private val refreshHelper: AutoRefreshHelper, ) { @@ -52,15 +48,10 @@ class AttendanceRepository @Inject constructor( attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday) }, fetch = { - val lessons = withContext(Dispatchers.IO) { - timetableDb.load( - semester.diaryId, semester.studentId, start.monday, end.sunday - ) - } sdk.init(student) .switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear) .getAttendance(start.monday, end.sunday, semester.semesterId) - .mapToEntities(semester, lessons) + .mapToEntities(semester) }, saveFetchResult = { old, new -> attendanceDb.deleteAll(old uniqueSubtract new) 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 000000000..7f5974920 --- /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 6dfc3ab73..00cbffb84 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 @@ -3,9 +3,8 @@ package io.github.wulkanowy.data.repositories import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import io.github.wulkanowy.R -import io.github.wulkanowy.data.* +import io.github.wulkanowy.data.Resource import io.github.wulkanowy.data.db.SharedPrefProvider -import io.github.wulkanowy.data.db.dao.MailboxDao import io.github.wulkanowy.data.db.dao.MessageAttachmentDao import io.github.wulkanowy.data.db.dao.MessagesDao import io.github.wulkanowy.data.db.entities.* @@ -14,8 +13,8 @@ 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.domain.messages.GetMailboxByStudentUseCase import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.pojo.Folder import io.github.wulkanowy.utils.AutoRefreshHelper @@ -41,18 +40,16 @@ class MessageRepository @Inject constructor( private val refreshHelper: AutoRefreshHelper, private val sharedPrefProvider: SharedPrefProvider, private val json: Json, - private val mailboxDao: MailboxDao, - private val getMailboxByStudentUseCase: GetMailboxByStudentUseCase, ) { private val saveFetchResultMutex = Mutex() - private val messagesCacheKey = "message" - private val mailboxCacheKey = "mailboxes" + private val cacheKey = "message" + @Suppress("UNUSED_PARAMETER") fun getMessages( student: Student, - mailbox: Mailbox?, + mailbox: Mailbox, folder: MessageFolder, forceRefresh: Boolean, notify: Boolean = false, @@ -61,20 +58,13 @@ class MessageRepository @Inject constructor( isResultEmpty = { it.isEmpty() }, shouldFetch = { val isExpired = refreshHelper.shouldBeRefreshed( - key = getRefreshKey(messagesCacheKey, mailbox, folder) + key = getRefreshKey(cacheKey, student, folder) ) it.isEmpty() || forceRefresh || isExpired }, - query = { - if (mailbox == null) { - messagesDb.loadAll(folder.id, student.email) - } else messagesDb.loadAll(mailbox.globalKey, folder.id) - }, + query = { messagesDb.loadAll(mailbox.globalKey, folder.id) }, fetch = { - sdk.init(student).getMessages( - folder = Folder.valueOf(folder.name), - mailboxKey = mailbox?.globalKey, - ).mapToEntities(student, mailbox, mailboxDao.loadAll(student.email)) + sdk.init(student).getMessages(Folder.valueOf(folder.name)).mapToEntities(mailbox) }, saveFetchResult = { old, new -> messagesDb.deleteAll(old uniqueSubtract new) @@ -82,9 +72,7 @@ class MessageRepository @Inject constructor( it.isNotified = !notify }) - refreshHelper.updateLastRefreshTimestamp( - getRefreshKey(messagesCacheKey, mailbox, folder) - ) + refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student, folder)) } ) @@ -99,11 +87,9 @@ class MessageRepository @Inject constructor( Timber.d("Message content in db empty: ${it.message.content.isBlank()}") it.message.unread || it.message.content.isBlank() }, - query = { - messagesDb.loadMessageWithAttachment(message.messageGlobalKey) - }, + query = { messagesDb.loadMessageWithAttachment(message.messageGlobalKey) }, fetch = { - sdk.init(student).getMessageDetails(it!!.message.messageGlobalKey, markAsRead) + sdk.init(student).getMessageDetails(it!!.message.messageGlobalKey) }, saveFetchResult = { old, new -> checkNotNull(old) { "Fetched message no longer exist!" } @@ -112,7 +98,7 @@ class MessageRepository @Inject constructor( id = message.id unread = !markAsRead sender = new.sender - recipients = new.recipients.singleOrNull() ?: "Wielu adresatów" + recipients = new.recipients.firstOrNull() ?: "Wielu adresoatów" content = content.ifBlank { new.content } }) ) @@ -124,10 +110,8 @@ class MessageRepository @Inject constructor( } ) - fun getMessagesFromDatabase(student: Student, mailbox: Mailbox?): Flow> { - return if (mailbox == null) { - messagesDb.loadAll(RECEIVED.id, student.email) - } else messagesDb.loadAll(mailbox.globalKey, RECEIVED.id) + fun getMessagesFromDatabase(mailbox: Mailbox): Flow> { + return messagesDb.loadAll(mailbox.globalKey, RECEIVED.id) } suspend fun updateMessages(messages: List) { @@ -149,7 +133,7 @@ class MessageRepository @Inject constructor( ) } - suspend fun deleteMessages(student: Student, mailbox: Mailbox?, messages: List) { + suspend fun deleteMessages(student: Student, mailbox: Mailbox, messages: List) { val firstMessage = messages.first() sdk.init(student).deleteMessages( messages = messages.map { it.messageGlobalKey }, @@ -178,49 +162,15 @@ class MessageRepository @Inject constructor( ).first() } - suspend fun deleteMessage(student: Student, mailbox: Mailbox?, message: Message) { + suspend fun deleteMessage(student: Student, mailbox: Mailbox, message: Message) { deleteMessages(student, mailbox, listOf(message)) } - suspend fun getMailboxes(student: Student, forceRefresh: Boolean) = networkBoundResource( - mutex = saveFetchResultMutex, - isResultEmpty = { it.isEmpty() }, - shouldFetch = { - val isExpired = refreshHelper.shouldBeRefreshed( - key = getRefreshKey(mailboxCacheKey, student), - ) - it.isEmpty() || isExpired || forceRefresh - }, - query = { mailboxDao.loadAll(student.email, student.symbol, student.schoolSymbol) }, - fetch = { - sdk.init(student).getMailboxes().mapToEntities(student) - }, - saveFetchResult = { old, new -> - mailboxDao.deleteAll(old uniqueSubtract new) - mailboxDao.insertAll(new uniqueSubtract old) - - refreshHelper.updateLastRefreshTimestamp(getRefreshKey(mailboxCacheKey, student)) - } - ) - - suspend fun getMailboxByStudent(student: Student): Mailbox? { - val mailbox = getMailboxByStudentUseCase(student) - - return if (mailbox == null) { - getMailboxes(student, forceRefresh = true) - .onResourceError { throw it } - .onResourceSuccess { Timber.i("Found ${it.size} new mailboxes") } - .waitForResult() - - getMailboxByStudentUseCase(student) - } else mailbox - } - var draftMessage: MessageDraft? - get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_draft)) + get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_send_draft)) ?.let { json.decodeFromString(it) } set(value) = sharedPrefProvider.putString( - context.getString(R.string.pref_key_message_draft), + context.getString(R.string.pref_key_message_send_draft), value?.let { json.encodeToString(it) } ) } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt index afc262868..486538e0c 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt @@ -10,16 +10,17 @@ import io.github.wulkanowy.R import io.github.wulkanowy.data.enums.* import io.github.wulkanowy.ui.modules.dashboard.DashboardItem import io.github.wulkanowy.ui.modules.grade.GradeAverageMode +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import java.time.Instant -import java.util.* import javax.inject.Inject import javax.inject.Singleton +@OptIn(ExperimentalCoroutinesApi::class) @Singleton class PreferencesRepository @Inject constructor( @ApplicationContext val context: Context, @@ -315,16 +316,6 @@ class PreferencesRepository @Inject constructor( putBoolean(context.getString(R.string.pref_key_ads_enabled), value) } - var installationId: String - get() = sharedPref.getString(PREF_KEY_INSTALLATION_ID, null).orEmpty() - private set(value) = sharedPref.edit { putString(PREF_KEY_INSTALLATION_ID, value) } - - init { - if (installationId.isEmpty()) { - installationId = UUID.randomUUID().toString() - } - } - private fun getLong(id: Int, default: Int) = getLong(context.getString(id), default) private fun getLong(id: String, default: Int) = @@ -340,14 +331,23 @@ class PreferencesRepository @Inject constructor( private fun getBoolean(id: String, default: Int) = sharedPref.getBoolean(id, context.resources.getBoolean(default)) + private fun getBoolean(id: Int, default: Boolean) = + sharedPref.getBoolean(context.getString(id), default) + private companion object { - private const val PREF_KEY_INSTALLATION_ID = "installation_id" + private const val PREF_KEY_DASHBOARD_ITEMS_POSITION = "dashboard_items_position" + private const val PREF_KEY_IN_APP_REVIEW_COUNT = "in_app_review_count" + private const val PREF_KEY_IN_APP_REVIEW_DATE = "in_app_review_date" + private const val PREF_KEY_IN_APP_REVIEW_DONE = "in_app_review_done" + private const val PREF_KEY_APP_SUPPORT_SHOWN = "app_support_shown" + private const val PREF_KEY_PERSONALIZED_ADS_ENABLED = "personalized_ads_enabled" + private const val PREF_KEY_ADMIN_DISMISSED_MESSAGE_IDS = "admin_message_dismissed_ids" } } 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 79984ce6d..e80f028e1 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 @@ -33,11 +33,9 @@ class RecipientRepository @Inject constructor( suspend fun getRecipients( student: Student, - mailbox: Mailbox?, - type: MailboxType, + mailbox: Mailbox, + type: MailboxType ): List { - mailbox ?: return emptyList() - val cached = recipientDb.loadAll(type, mailbox.globalKey) val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student)) @@ -49,15 +47,11 @@ class RecipientRepository @Inject constructor( suspend fun getMessageSender( student: Student, - mailbox: Mailbox?, - message: Message, - ): List { - mailbox ?: return emptyList() - - return sdk.init(student) - .getMessageReplayDetails(message.messageGlobalKey) - .sender - .let(::listOf) - .mapToEntities(mailbox.globalKey) - } + 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/StudentRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt index b1d1ba832..f006b7d28 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt @@ -11,8 +11,6 @@ import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.data.exceptions.NoCurrentStudentException import io.github.wulkanowy.data.mappers.mapToEntities -import io.github.wulkanowy.data.mappers.mapToPojo -import io.github.wulkanowy.data.pojos.RegisterUser import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.DispatchersProvider @@ -54,14 +52,6 @@ class StudentRepository @Inject constructor( sdk.getStudentsFromScrapper(email, password, scrapperBaseUrl, symbol) .mapToEntities(password, appInfo.defaultColorsForAvatar) - suspend fun getUserSubjectsFromScrapper( - email: String, - password: String, - scrapperBaseUrl: String, - symbol: String - ): RegisterUser = sdk.getUserSubjectsFromScrapper(email, password, scrapperBaseUrl, symbol) - .mapToPojo(password) - suspend fun getStudentsHybrid( email: String, password: String, diff --git a/app/src/main/java/io/github/wulkanowy/domain/messages/GetMailboxByStudentUseCase.kt b/app/src/main/java/io/github/wulkanowy/domain/messages/GetMailboxByStudentUseCase.kt deleted file mode 100644 index 669514aae..000000000 --- a/app/src/main/java/io/github/wulkanowy/domain/messages/GetMailboxByStudentUseCase.kt +++ /dev/null @@ -1,65 +0,0 @@ -package io.github.wulkanowy.domain.messages - -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 javax.inject.Inject - -class GetMailboxByStudentUseCase @Inject constructor( - private val mailboxDao: MailboxDao, -) { - - suspend operator fun invoke(student: Student): Mailbox? { - return mailboxDao.loadAll(student.email) - .filterByStudent(student) - } - - private fun List.filterByStudent(student: Student): Mailbox? { - val normalizedStudentName = student.studentName.normalizeStudentName() - - return singleOrNull { - it.studentName.normalizeStudentName() == normalizedStudentName - } ?: singleOrNull { - it.studentName.normalizeStudentName() == normalizedStudentName - && it.schoolNameShort == student.schoolShortName - } ?: singleOrNull { - it.studentName.getFirstAndLastPart() == normalizedStudentName.getFirstAndLastPart() - } ?: singleOrNull { - it.studentName.getReversedName() == normalizedStudentName - } ?: singleOrNull { - it.studentName.getUnauthorizedVersion() == normalizedStudentName - } - } - - private fun String.normalizeStudentName(): String { - return trim().split(" ") - .filter { it.isNotBlank() } - .joinToString(" ") { part -> - part.lowercase().replaceFirstChar { it.uppercase() } - } - } - - private fun String.getFirstAndLastPart(): String { - val parts = normalizeStudentName().split(" ") - - val endParts = parts.filterIndexed { i, _ -> - i == 0 || parts.size - 1 == i - } - return endParts.joinToString(" ") - } - - private fun String.getReversedName(): String { - val parts = normalizeStudentName().split(" ") - - return parts - .asReversed() - .joinToString(" ") - } - - private fun String.getUnauthorizedVersion(): String { - return normalizeStudentName().split(" ") - .joinToString(" ") { - it.first() + "*".repeat(it.length - 1) - } - } -} diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewAttendanceNotification.kt b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewAttendanceNotification.kt index 99473a8ec..49842c9a6 100644 --- a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewAttendanceNotification.kt +++ b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewAttendanceNotification.kt @@ -8,6 +8,7 @@ import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.pojos.GroupNotificationData import io.github.wulkanowy.data.pojos.NotificationData import io.github.wulkanowy.ui.modules.Destination +import io.github.wulkanowy.ui.modules.splash.SplashActivity import io.github.wulkanowy.utils.descriptionRes import io.github.wulkanowy.utils.getPlural import io.github.wulkanowy.utils.toFormattedString @@ -21,9 +22,8 @@ class NewAttendanceNotification @Inject constructor( suspend fun notify(items: List, student: Student) { val lines = items.filterNot { it.presence || it.name == "UNKNOWN" } .map { - val lesson = it.subject.ifBlank { "Lekcja ${it.number}" } val description = context.getString(it.descriptionRes) - "${it.date.toFormattedString("dd.MM")} - $lesson: $description" + "${it.date.toFormattedString("dd.MM")} - ${it.subject}: $description" } .ifEmpty { return } 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 45523d51e..3b7bcff05 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 @@ -8,6 +8,7 @@ import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.pojos.GroupNotificationData import io.github.wulkanowy.data.pojos.NotificationData import io.github.wulkanowy.ui.modules.Destination +import io.github.wulkanowy.ui.modules.splash.SplashActivity import io.github.wulkanowy.utils.getPlural import javax.inject.Inject 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 c7824e61f..180568267 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,11 +12,12 @@ 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 = messageRepository.getMailboxByStudent(student) + val mailbox = mailboxRepository.getMailbox(student) messageRepository.getMessages( student = student, mailbox = mailbox, @@ -24,7 +26,7 @@ class MessageWork @Inject constructor( notify = notify ).waitForResult() - messageRepository.getMessagesFromDatabase(student, mailbox).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 90b20651d..b1322ada3 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.dataOrNull 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.MessageRepository +import io.github.wulkanowy.data.repositories.MailboxRepository import io.github.wulkanowy.data.repositories.RecipientRepository -import io.github.wulkanowy.data.toFirstResult import javax.inject.Inject class RecipientWork @Inject constructor( - private val messageRepository: MessageRepository, + private val mailboxRepository: MailboxRepository, private val recipientRepository: RecipientRepository ) : Work { override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) { - val mailboxes = messageRepository.getMailboxes(student, forceRefresh = true).toFirstResult() - mailboxes.dataOrNull?.forEach { - recipientRepository.refreshRecipients(student, it, MailboxType.EMPLOYEE) - } + mailboxRepository.refreshMailboxes(student) + + val mailbox = mailboxRepository.getMailbox(student) + + recipientRepository.refreshRecipients(student, mailbox, MailboxType.EMPLOYEE) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/ErrorDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/base/ErrorDialog.kt index fe0e64697..48c003b7e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/ErrorDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/ErrorDialog.kt @@ -4,6 +4,7 @@ import android.app.Dialog import android.content.ClipData import android.content.ClipboardManager import android.os.Bundle +import android.view.LayoutInflater import android.widget.Toast import android.widget.Toast.LENGTH_LONG import androidx.appcompat.app.AlertDialog @@ -14,7 +15,6 @@ import androidx.fragment.app.DialogFragment import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R -import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.databinding.DialogErrorBinding import io.github.wulkanowy.utils.* import javax.inject.Inject @@ -25,9 +25,6 @@ class ErrorDialog : DialogFragment() { @Inject lateinit var appInfo: AppInfo - @Inject - lateinit var preferencesRepository: PreferencesRepository - companion object { private const val ARGUMENT_KEY = "error" @@ -37,9 +34,9 @@ class ErrorDialog : DialogFragment() { } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val error = requireArguments().serializable(ARGUMENT_KEY) + val error = requireArguments().getSerializable(ARGUMENT_KEY) as Throwable - val binding = DialogErrorBinding.inflate(layoutInflater) + val binding = DialogErrorBinding.inflate(LayoutInflater.from(context)) binding.bindErrorDetails(error) return getAlertDialog(binding, error).apply { @@ -102,8 +99,7 @@ class ErrorDialog : DialogFragment() { R.string.about_feedback_template, "${appInfo.systemManufacturer} ${appInfo.systemModel}", appInfo.systemVersion.toString(), - "${appInfo.versionName}-${appInfo.buildFlavor}", - preferencesRepository.installationId, + "${appInfo.versionName}-${appInfo.buildFlavor}" ) + "\n" + content, onActivityNotFound = { requireContext().openInternetBrowser( diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/ThemeManager.kt b/app/src/main/java/io/github/wulkanowy/ui/base/ThemeManager.kt index e1c234575..2d83bbbf9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/ThemeManager.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/ThemeManager.kt @@ -1,9 +1,6 @@ package io.github.wulkanowy.ui.base -import android.content.pm.PackageInfo -import android.content.pm.PackageManager import android.content.pm.PackageManager.GET_ACTIVITIES -import android.os.Build import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM @@ -44,8 +41,9 @@ class ThemeManager @Inject constructor(private val preferencesRepository: Prefer ) } - private fun isThemeApplicable(activity: AppCompatActivity): Boolean = - getPackageInfo(activity) + private fun isThemeApplicable(activity: AppCompatActivity) = + activity.packageManager + .getPackageInfo(activity.packageName, GET_ACTIVITIES) .activities .singleOrNull { it.name == activity::class.java.canonicalName } ?.theme @@ -54,14 +52,4 @@ class ThemeManager @Inject constructor(private val preferencesRepository: Prefer || it == R.style.WulkanowyTheme_Login || it == R.style.WulkanowyTheme_Login_Black || it == R.style.WulkanowyTheme_MessageSend || it == R.style.WulkanowyTheme_MessageSend_Black } - - @Suppress("DEPRECATION") - private fun getPackageInfo(activity: AppCompatActivity): PackageInfo { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - activity.packageManager.getPackageInfo( - activity.packageName, - PackageManager.PackageInfoFlags.of(GET_ACTIVITIES.toLong()) - ) - } else activity.packageManager.getPackageInfo(activity.packageName, GET_ACTIVITIES) - } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt index d7f39e303..701656b55 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt @@ -6,7 +6,6 @@ import android.view.View import androidx.recyclerview.widget.LinearLayoutManager import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R -import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.databinding.FragmentAboutBinding import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.about.contributor.ContributorFragment @@ -31,9 +30,6 @@ class AboutFragment : BaseFragment(R.layout.fragment_about @Inject lateinit var appInfo: AppInfo - @Inject - lateinit var preferencesRepository: PreferencesRepository - override val versionRes: Triple? get() = context?.run { val buildTimestamp = @@ -189,8 +185,7 @@ class AboutFragment : BaseFragment(R.layout.fragment_about R.string.about_feedback_template, "${appInfo.systemManufacturer} ${appInfo.systemModel}", appInfo.systemVersion.toString(), - "${appInfo.versionName}-${appInfo.buildFlavor}", - preferencesRepository.installationId, + "${appInfo.versionName}-${appInfo.buildFlavor}" ), onActivityNotFound = { requireContext().openInternetBrowser( diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountFragment.kt index f115372a5..051c93c95 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountFragment.kt @@ -34,7 +34,6 @@ class AccountFragment : BaseFragment(R.layout.fragment_a override val titleStringId = R.string.account_title - @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsFragment.kt index 41b97b075..c3137ec58 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountdetails/AccountDetailsFragment.kt @@ -6,7 +6,6 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import androidx.appcompat.app.AlertDialog -import androidx.core.os.bundleOf import androidx.core.view.get import androidx.core.view.isVisible import dagger.hilt.android.AndroidEntryPoint @@ -22,7 +21,6 @@ import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoFragment import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView import io.github.wulkanowy.utils.createNameInitialsDrawable import io.github.wulkanowy.utils.nickOrName -import io.github.wulkanowy.utils.serializable import javax.inject.Inject @AndroidEntryPoint @@ -39,12 +37,12 @@ class AccountDetailsFragment : private const val ARGUMENT_KEY = "Data" - fun newInstance(student: Student) = AccountDetailsFragment().apply { - arguments = bundleOf(ARGUMENT_KEY to student) - } + fun newInstance(student: Student) = + AccountDetailsFragment().apply { + arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, student) } + } } - @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) @@ -53,7 +51,7 @@ class AccountDetailsFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding = FragmentAccountDetailsBinding.bind(view) - presenter.onAttachView(this, requireArguments().serializable(ARGUMENT_KEY)) + presenter.onAttachView(this, requireArguments()[ARGUMENT_KEY] as Student) } override fun initView() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountedit/AccountEditDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountedit/AccountEditDialog.kt index 6e2bc8c44..21a7a492d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountedit/AccountEditDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountedit/AccountEditDialog.kt @@ -4,13 +4,11 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.os.bundleOf import androidx.recyclerview.widget.GridLayoutManager import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.databinding.DialogAccountEditBinding import io.github.wulkanowy.ui.base.BaseDialogFragment -import io.github.wulkanowy.utils.serializable import javax.inject.Inject @AndroidEntryPoint @@ -26,9 +24,12 @@ class AccountEditDialog : BaseDialogFragment(), Accoun private const val ARGUMENT_KEY = "student_with_semesters" - fun newInstance(student: Student) = AccountEditDialog().apply { - arguments = bundleOf(ARGUMENT_KEY to student) - } + fun newInstance(student: Student) = + AccountEditDialog().apply { + arguments = Bundle().apply { + putSerializable(ARGUMENT_KEY, student) + } + } } override fun onCreate(savedInstanceState: Bundle?) { @@ -44,7 +45,7 @@ class AccountEditDialog : BaseDialogFragment(), Accoun override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - presenter.onAttachView(this, requireArguments().serializable(ARGUMENT_KEY)) + presenter.onAttachView(this, requireArguments()[ARGUMENT_KEY] as Student) } override fun initView() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickDialog.kt index d23978f5f..4279102e1 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/accountquick/AccountQuickDialog.kt @@ -4,7 +4,6 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.os.bundleOf import androidx.recyclerview.widget.LinearLayoutManager import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.data.db.entities.StudentWithSemesters @@ -14,7 +13,6 @@ import io.github.wulkanowy.ui.modules.account.AccountAdapter import io.github.wulkanowy.ui.modules.account.AccountFragment import io.github.wulkanowy.ui.modules.account.AccountItem import io.github.wulkanowy.ui.modules.main.MainActivity -import io.github.wulkanowy.utils.serializable import javax.inject.Inject @AndroidEntryPoint @@ -32,7 +30,9 @@ class AccountQuickDialog : BaseDialogFragment(), Acco fun newInstance(studentsWithSemesters: List) = AccountQuickDialog().apply { - arguments = bundleOf(STUDENTS_ARGUMENT_KEY to studentsWithSemesters.toTypedArray()) + arguments = Bundle().apply { + putSerializable(STUDENTS_ARGUMENT_KEY, studentsWithSemesters.toTypedArray()) + } } } @@ -49,8 +49,8 @@ class AccountQuickDialog : BaseDialogFragment(), Acco @Suppress("UNCHECKED_CAST") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - val studentsWithSemesters = requireArguments() - .serializable>(STUDENTS_ARGUMENT_KEY).toList() + val studentsWithSemesters = + (requireArguments()[STUDENTS_ARGUMENT_KEY] as Array).toList() presenter.onAttachView(this, studentsWithSemesters) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceDialog.kt index eab24f91d..9b5c63e4c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceDialog.kt @@ -4,13 +4,11 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.os.bundleOf import androidx.fragment.app.DialogFragment import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.databinding.DialogAttendanceBinding import io.github.wulkanowy.utils.descriptionRes import io.github.wulkanowy.utils.lifecycleAwareVariable -import io.github.wulkanowy.utils.serializable import io.github.wulkanowy.utils.toFormattedString class AttendanceDialog : DialogFragment() { @@ -24,14 +22,16 @@ class AttendanceDialog : DialogFragment() { private const val ARGUMENT_KEY = "Item" fun newInstance(exam: Attendance) = AttendanceDialog().apply { - arguments = bundleOf(ARGUMENT_KEY to exam) + arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setStyle(STYLE_NO_TITLE, 0) - attendance = requireArguments().serializable(ARGUMENT_KEY) + arguments?.run { + attendance = getSerializable(ARGUMENT_KEY) as Attendance + } } override fun onCreateView( 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 21f30b046..6354b5e04 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 @@ -84,7 +84,6 @@ class AttendanceFragment : BaseFragment(R.layout.frag } } - @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/conference/ConferenceDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/conference/ConferenceDialog.kt index 7834b6e8b..477b762b9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/conference/ConferenceDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/conference/ConferenceDialog.kt @@ -4,13 +4,11 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.os.bundleOf import androidx.core.view.isVisible import androidx.fragment.app.DialogFragment import io.github.wulkanowy.data.db.entities.Conference import io.github.wulkanowy.databinding.DialogConferenceBinding import io.github.wulkanowy.utils.lifecycleAwareVariable -import io.github.wulkanowy.utils.serializable import io.github.wulkanowy.utils.toFormattedString class ConferenceDialog : DialogFragment() { @@ -24,14 +22,16 @@ class ConferenceDialog : DialogFragment() { private const val ARGUMENT_KEY = "item" fun newInstance(conference: Conference) = ConferenceDialog().apply { - arguments = bundleOf(ARGUMENT_KEY to conference) + arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, conference) } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setStyle(STYLE_NO_TITLE, 0) - conference = requireArguments().serializable(ARGUMENT_KEY) + arguments?.let { + conference = it.getSerializable(ARGUMENT_KEY) as Conference + } } override fun onCreateView( @@ -57,4 +57,4 @@ class ConferenceDialog : DialogFragment() { conferenceDialogAgendaTitle.isVisible = conference.agenda.isNotBlank() } } -} +} \ No newline at end of file diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardFragment.kt index cd66d6c2f..de0b4a6c9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardFragment.kt @@ -61,7 +61,6 @@ class DashboardFragment : BaseFragment(R.layout.fragme fun newInstance() = DashboardFragment() } - @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardItem.kt index d019dea68..e220ae236 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardItem.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardItem.kt @@ -33,27 +33,18 @@ sealed class DashboardItem(val type: Type) { } data class HorizontalGroup( - val unreadMessagesCount: Cell? = null, - val attendancePercentage: Cell? = null, - val luckyNumber: Cell? = null, + val unreadMessagesCount: Int? = null, + val attendancePercentage: Double? = null, + val luckyNumber: Int? = null, override val error: Throwable? = null, override val isLoading: Boolean = false ) : DashboardItem(Type.HORIZONTAL_GROUP) { - data class Cell( - val data: T?, - val error: Boolean, - val isLoading: Boolean, - ) { - val isHidden: Boolean - get() = data == null && !error && !isLoading - } - override val isDataLoaded - get() = unreadMessagesCount?.isLoading == false || attendancePercentage?.isLoading == false || luckyNumber?.isLoading == false + get() = unreadMessagesCount != null || attendancePercentage != null || luckyNumber != null val isFullDataLoaded - get() = luckyNumber?.isLoading != true && attendancePercentage?.isLoading != true && unreadMessagesCount?.isLoading != true + get() = luckyNumber != -1 && attendancePercentage != -1.0 && unreadMessagesCount != -1 } data class Grades( 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 22b0d267e..350300937 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, @@ -226,71 +227,50 @@ 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)) + val flowSuccess = flowOf(Resource.Success(null)) val luckyNumberFlow = luckyNumberRepository.getLuckyNumber(student, forceRefresh) .mapResourceData { it ?: LuckyNumber(0, LocalDate.now(), 0) } - .onResourceError { errorHandler.dispatch(it) } .takeIf { DashboardItem.Tile.LUCKY_NUMBER in selectedTiles } ?: flowSuccess - val messageFLow = flatResourceFlow { - val mailbox = messageRepository.getMailboxByStudent(student) + val messageFLow = messageRepository.getMessages( + student = student, + mailbox = mailbox, + folder = MessageFolder.RECEIVED, + forceRefresh = forceRefresh + ).takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowSuccess - messageRepository.getMessages( - student = student, - mailbox = mailbox, - folder = MessageFolder.RECEIVED, - forceRefresh = forceRefresh - ) - } - .onResourceError { errorHandler.dispatch(it) } - .takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowSuccess - - val attendanceFlow = flatResourceFlow { - val semester = semesterRepository.getCurrentSemester(student) - attendanceSummaryRepository.getAttendanceSummary( - student = student, - semester = semester, - subjectId = -1, - forceRefresh = forceRefresh - ) - } - .onResourceError { errorHandler.dispatch(it) } - .takeIf { DashboardItem.Tile.ATTENDANCE in selectedTiles } ?: flowSuccess + val attendanceFlow = attendanceSummaryRepository.getAttendanceSummary( + student = student, + semester = semester, + subjectId = -1, + forceRefresh = forceRefresh + ).takeIf { DashboardItem.Tile.ATTENDANCE in selectedTiles } ?: flowSuccess emitAll( combine( - flow = luckyNumberFlow, - flow2 = messageFLow, - flow3 = attendanceFlow, + luckyNumberFlow, + messageFLow, + attendanceFlow ) { luckyNumberResource, messageResource, attendanceResource -> val resList = listOf(luckyNumberResource, messageResource, attendanceResource) + resList.firstNotNullOfOrNull { it.errorOrNull }?.let { throw it } + val isLoading = resList.any { it is Resource.Loading } + + val luckyNumber = luckyNumberResource.dataOrNull?.luckyNumber + val messageCount = messageResource.dataOrNull?.count { it.unread } + val attendancePercentage = attendanceResource.dataOrNull?.calculatePercentage() DashboardItem.HorizontalGroup( - isLoading = resList.any { it is Resource.Loading }, - error = resList.map { it.errorOrNull }.let { errors -> - if (errors.all { it != null }) { - errors.firstOrNull() - } else null - }, - attendancePercentage = DashboardItem.HorizontalGroup.Cell( - data = attendanceResource.dataOrNull?.calculatePercentage(), - error = attendanceResource.errorOrNull != null, - isLoading = attendanceResource is Resource.Loading, - ), - unreadMessagesCount = DashboardItem.HorizontalGroup.Cell( - data = messageResource.dataOrNull?.count { it.unread }, - error = messageResource.errorOrNull != null, - isLoading = messageResource is Resource.Loading, - ), - luckyNumber = DashboardItem.HorizontalGroup.Cell( - data = luckyNumberResource.dataOrNull?.luckyNumber, - error = luckyNumberResource.errorOrNull != null, - isLoading = luckyNumberResource is Resource.Loading, - ) + isLoading = isLoading, + attendancePercentage = if (attendancePercentage == 0.0 && isLoading) -1.0 else attendancePercentage, + unreadMessagesCount = if (messageCount == 0 && isLoading) -1 else messageCount, + luckyNumber = if (luckyNumber == 0 && isLoading) -1 else luckyNumber ) }) } @@ -301,8 +281,11 @@ class DashboardPresenter @Inject constructor( if (it.isLoading) { Timber.i("Loading horizontal group data started") + + if (it.isFullDataLoaded) { + firstLoadedItemList += DashboardItem.Type.HORIZONTAL_GROUP + } } else { - firstLoadedItemList += DashboardItem.Type.HORIZONTAL_GROUP Timber.i("Loading horizontal group result: Success") } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardAdapter.kt index 2c06e45fd..a3c423a8b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardAdapter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardAdapter.kt @@ -171,105 +171,81 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter { - updateMarginsRelative( - end = if (isAttendanceHidden && isMessagesHidden && !isLuckyNumberHidden) { - 0 - } else context.dpToPx(8f).toInt() - ) - } - } - } - - private fun ItemDashboardHorizontalGroupBinding.bindMessages( - item: DashboardItem.HorizontalGroup, - isWideErrorShow: Boolean - ) { - dashboardHorizontalGroupItemMessageError.isVisible = item.unreadMessagesCount?.error == true - with(dashboardHorizontalGroupItemMessageValue) { - isVisible = item.unreadMessagesCount?.error != true - text = item.unreadMessagesCount?.data.toString() - } - with(dashboardHorizontalGroupItemMessageContainer) { - isVisible = item.unreadMessagesCount?.isHidden == false && !isWideErrorShow - setOnClickListener { onMessageTileClickListener() } - } - } - - private fun ItemDashboardHorizontalGroupBinding.bindAttendance( - item: DashboardItem.HorizontalGroup, - isWideErrorShow: Boolean - ) { - val attendancePercentage = item.attendancePercentage?.data + (isLoading && !item.isDataLoaded) || (isLoading && !item.isFullDataLoaded) val attendanceColor = when { attendancePercentage == null || attendancePercentage == .0 -> { - root.context.getThemeAttrColor(R.attr.colorOnSurface) + context.getThemeAttrColor(R.attr.colorOnSurface) } attendancePercentage <= ATTENDANCE_SECOND_WARNING_THRESHOLD -> { - root.context.getThemeAttrColor(R.attr.colorPrimary) + context.getThemeAttrColor(R.attr.colorPrimary) } attendancePercentage <= ATTENDANCE_FIRST_WARNING_THRESHOLD -> { - root.context.getThemeAttrColor(R.attr.colorTimetableChange) + context.getThemeAttrColor(R.attr.colorTimetableChange) } - else -> root.context.getThemeAttrColor(R.attr.colorOnSurface) + else -> context.getThemeAttrColor(R.attr.colorOnSurface) } val attendanceString = if (attendancePercentage == null || attendancePercentage == .0) { - root.context.getString(R.string.dashboard_horizontal_group_no_data) + context.getString(R.string.dashboard_horizontal_group_no_data) } else { "%.2f%%".format(attendancePercentage) } - dashboardHorizontalGroupItemAttendanceError.isVisible = - item.attendancePercentage?.error == true - with(dashboardHorizontalGroupItemAttendanceValue) { - isVisible = item.attendancePercentage?.error != true + with(binding.dashboardHorizontalGroupItemAttendanceValue) { text = attendanceString setTextColor(attendanceColor) } - with(dashboardHorizontalGroupItemAttendanceContainer) { - isVisible = item.attendancePercentage?.isHidden == false && !isWideErrorShow - setOnClickListener { onAttendanceTileClickListener() } - updateLayoutParams { - matchConstraintPercentWidth = when { - item.luckyNumber?.isHidden == true && item.unreadMessagesCount?.isHidden == true -> 1.0f - item.luckyNumber?.isHidden == true || item.unreadMessagesCount?.isHidden == true -> 0.5f - else -> 0.4f + + with(binding) { + dashboardHorizontalGroupItemMessageValue.text = unreadMessagesCount.toString() + dashboardHorizontalGroupItemLuckyValue.text = if (luckyNumber == 0) { + context.getString(R.string.dashboard_horizontal_group_no_data) + } else luckyNumber?.toString() + + dashboardHorizontalGroupItemInfoContainer.isVisible = error != null || isLoadingVisible + dashboardHorizontalGroupItemInfoProgress.isVisible = isLoadingVisible + dashboardHorizontalGroupItemInfoErrorText.isVisible = error != null + + with(dashboardHorizontalGroupItemLuckyContainer) { + isVisible = luckyNumber != null && luckyNumber != -1 && !isLoadingVisible + setOnClickListener { onLuckyNumberTileClickListener() } + + updateLayoutParams { + updateMarginsRelative( + end = if (attendancePercentage == null && unreadMessagesCount == null && luckyNumber != null) { + 0 + } else { + context.dpToPx(8f).toInt() + } + ) } } + + with(dashboardHorizontalGroupItemAttendanceContainer) { + isVisible = + attendancePercentage != null && attendancePercentage != -1.0 && !isLoadingVisible + updateLayoutParams { + matchConstraintPercentWidth = when { + luckyNumber == null && unreadMessagesCount == null -> 1.0f + luckyNumber == null || unreadMessagesCount == null -> 0.5f + else -> 0.4f + } + } + setOnClickListener { onAttendanceTileClickListener() } + } + + with(dashboardHorizontalGroupItemMessageContainer) { + isVisible = + unreadMessagesCount != null && unreadMessagesCount != -1 && !isLoadingVisible + setOnClickListener { onMessageTileClickListener() } + } } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/logviewer/LogViewerFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/logviewer/LogViewerFragment.kt index 929e72645..1e11c874b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/logviewer/LogViewerFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/logviewer/LogViewerFragment.kt @@ -1,7 +1,9 @@ package io.github.wulkanowy.ui.modules.debug.logviewer import android.content.Intent -import android.content.Intent.* +import android.content.Intent.EXTRA_EMAIL +import android.content.Intent.EXTRA_STREAM +import android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION import android.os.Bundle import android.view.Menu import android.view.MenuInflater @@ -34,7 +36,6 @@ class LogViewerFragment : BaseFragment(R.layout.fragme fun newInstance() = LogViewerFragment() } - @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) 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 27d8613a3..6ff26162b 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 @@ -19,12 +19,9 @@ val debugMessageItems = listOf( private fun generateMessage(sender: String, subject: String) = Message( subject = subject, messageId = 123, - email = "", date = Instant.now(), folderId = 0, unread = true, - readBy = 2, - unreadBy = 2, hasAttachments = false, messageGlobalKey = "", correspondents = sender, diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamDialog.kt index 876b563f9..41adc008a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamDialog.kt @@ -4,14 +4,12 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.os.bundleOf import androidx.fragment.app.DialogFragment import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Exam import io.github.wulkanowy.databinding.DialogExamBinding import io.github.wulkanowy.utils.lifecycleAwareVariable import io.github.wulkanowy.utils.openCalendarEventAdd -import io.github.wulkanowy.utils.serializable import io.github.wulkanowy.utils.toFormattedString import java.time.LocalTime @@ -26,14 +24,16 @@ class ExamDialog : DialogFragment() { private const val ARGUMENT_KEY = "Item" fun newInstance(exam: Exam) = ExamDialog().apply { - arguments = bundleOf(ARGUMENT_KEY to exam) + arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setStyle(STYLE_NO_TITLE, 0) - exam = requireArguments().serializable(ARGUMENT_KEY) + arguments?.run { + exam = getSerializable(ARGUMENT_KEY) as Exam + } } override fun onCreateView( diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt index 15df47a19..0a8561eec 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt @@ -51,7 +51,6 @@ class GradeFragment : BaseFragment(R.layout.fragment_grade override val currentPageIndex get() = binding.gradeViewPager.currentItem - @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsDialog.kt index a1ef2ec5a..34594111f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsDialog.kt @@ -5,7 +5,6 @@ import android.view.LayoutInflater import android.view.View import android.view.View.GONE import android.view.ViewGroup -import androidx.core.os.bundleOf import androidx.fragment.app.DialogFragment import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Grade @@ -28,19 +27,22 @@ class GradeDetailsDialog : DialogFragment() { private const val COLOR_THEME_KEY = "Theme" - fun newInstance(grade: Grade, colorTheme: GradeColorTheme) = GradeDetailsDialog().apply { - arguments = bundleOf( - ARGUMENT_KEY to grade, - COLOR_THEME_KEY to colorTheme - ) - } + fun newInstance(grade: Grade, colorTheme: GradeColorTheme) = + GradeDetailsDialog().apply { + arguments = Bundle().apply { + putSerializable(ARGUMENT_KEY, grade) + putSerializable(COLOR_THEME_KEY, colorTheme) + } + } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setStyle(STYLE_NO_TITLE, 0) - grade = requireArguments().serializable(ARGUMENT_KEY) - gradeColorTheme = requireArguments().serializable(COLOR_THEME_KEY) + arguments?.run { + grade = getSerializable(ARGUMENT_KEY) as Grade + gradeColorTheme = getSerializable(COLOR_THEME_KEY) as GradeColorTheme + } } override fun onCreateView( diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt index 23d767a6f..81f3226ad 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt @@ -5,7 +5,9 @@ import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import android.view.View -import android.view.View.* +import android.view.View.GONE +import android.view.View.INVISIBLE +import android.view.View.VISIBLE import androidx.recyclerview.widget.LinearLayoutManager import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R @@ -40,7 +42,6 @@ class GradeDetailsFragment : override val isViewEmpty get() = gradeDetailsAdapter.itemCount == 0 - @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt index 4261c507d..8cde5d6b9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt @@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.grade.details import io.github.wulkanowy.data.* import io.github.wulkanowy.data.db.entities.Grade import io.github.wulkanowy.data.enums.GradeExpandMode +import io.github.wulkanowy.data.enums.GradeSortingMode import io.github.wulkanowy.data.enums.GradeSortingMode.* import io.github.wulkanowy.data.repositories.GradeRepository import io.github.wulkanowy.data.repositories.PreferencesRepository @@ -131,17 +132,16 @@ class GradeDetailsPresenter @Inject constructor( } .logResourceStatus("load grade details") .onResourceData { - val gradeItems = createGradeItems(it) view?.run { enableSwipe(true) showProgress(false) showErrorView(false) - showContent(gradeItems.isNotEmpty()) - showEmpty(gradeItems.isEmpty()) + showContent(it.isNotEmpty()) + showEmpty(it.isEmpty()) updateNewGradesAmount(it) updateMarkAsDoneButton() updateData( - data = gradeItems, + data = createGradeItems(it), expandMode = preferencesRepository.gradeExpandMode, preferencesRepository.gradeColorTheme ) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsFragment.kt index edc384c5e..2af59c011 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsFragment.kt @@ -15,7 +15,6 @@ import io.github.wulkanowy.ui.modules.grade.GradeFragment import io.github.wulkanowy.ui.modules.grade.GradeView import io.github.wulkanowy.utils.dpToPx import io.github.wulkanowy.utils.getThemeAttrColor -import io.github.wulkanowy.utils.serializable import io.github.wulkanowy.utils.setOnItemSelectedListener import javax.inject.Inject @@ -49,8 +48,8 @@ class GradeStatisticsFragment : messageContainer = binding.gradeStatisticsRecycler presenter.onAttachView( view = this, - type = savedInstanceState?.serializable(SAVED_CHART_TYPE), - subjectName = savedInstanceState?.serializable(SAVED_SUBJECT_NAME), + type = savedInstanceState?.getSerializable(SAVED_CHART_TYPE) as? GradeStatisticsItem.DataType, + subjectName = savedInstanceState?.getSerializable(SAVED_SUBJECT_NAME) as? String, ) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryAdapter.kt index 8dcade56e..082c847e5 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryAdapter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryAdapter.kt @@ -10,7 +10,6 @@ import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.databinding.ItemGradeSummaryBinding import io.github.wulkanowy.databinding.ScrollableHeaderGradeSummaryBinding -import io.github.wulkanowy.sdk.scrapper.grades.isGradeValid import io.github.wulkanowy.utils.calcFinalAverage import java.util.Locale import javax.inject.Inject @@ -62,7 +61,7 @@ class GradeSummaryAdapter @Inject constructor( if (items.isEmpty()) return val context = binding.root.context - val finalItemsCount = items.count { isGradeValid(it.finalGrade) } + val finalItemsCount = items.count { it.finalGrade.matches("[0-6][+-]?".toRegex()) } val calculatedItemsCount = items.count { value -> value.average != 0.0 } val allItemsCount = items.count { !it.subject.equals("zachowanie", true) } val finalAverage = items.calcFinalAverage( diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsDialog.kt index 5e2cc65dc..f9d463510 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsDialog.kt @@ -7,7 +7,6 @@ import android.view.View import android.view.ViewGroup import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.ViewGroup.LayoutParams.WRAP_CONTENT -import androidx.core.os.bundleOf import androidx.recyclerview.widget.LinearLayoutManager import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R @@ -15,7 +14,6 @@ import io.github.wulkanowy.data.db.entities.Homework import io.github.wulkanowy.databinding.DialogHomeworkBinding import io.github.wulkanowy.ui.base.BaseDialogFragment import io.github.wulkanowy.utils.openInternetBrowser -import io.github.wulkanowy.utils.serializable import javax.inject.Inject @AndroidEntryPoint @@ -37,14 +35,16 @@ class HomeworkDetailsDialog : BaseDialogFragment(), Homew private const val ARGUMENT_KEY = "Item" fun newInstance(homework: Homework) = HomeworkDetailsDialog().apply { - arguments = bundleOf(ARGUMENT_KEY to homework) + arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, homework) } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setStyle(STYLE_NO_TITLE, 0) - homework = requireArguments().serializable(ARGUMENT_KEY) + arguments?.run { + homework = getSerializable(ARGUMENT_KEY) as Homework + } } override fun onCreateView( diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt index c17c92efd..aac60b56d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt @@ -2,17 +2,13 @@ package io.github.wulkanowy.ui.modules.login import android.content.Context import android.content.Intent -import android.content.pm.PackageManager -import android.os.Build.VERSION_CODES.TIRAMISU import android.os.Bundle import android.view.MenuItem -import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE import androidx.fragment.app.commit import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R -import io.github.wulkanowy.data.pojos.RegisterUser +import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.databinding.ActivityLoginBinding import io.github.wulkanowy.ui.base.BaseActivity import io.github.wulkanowy.ui.modules.login.advanced.LoginAdvancedFragment @@ -20,9 +16,6 @@ import io.github.wulkanowy.ui.modules.login.form.LoginFormFragment import io.github.wulkanowy.ui.modules.login.recover.LoginRecoverFragment import io.github.wulkanowy.ui.modules.login.studentselect.LoginStudentSelectFragment import io.github.wulkanowy.ui.modules.login.symbol.LoginSymbolFragment -import io.github.wulkanowy.ui.modules.main.MainActivity -import io.github.wulkanowy.ui.modules.notifications.NotificationsFragment -import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.UpdateHelper import javax.inject.Inject @@ -35,9 +28,6 @@ class LoginActivity : BaseActivity(), Logi @Inject lateinit var updateHelper: UpdateHelper - @Inject - lateinit var appInfo: AppInfo - companion object { fun getStartIntent(context: Context) = Intent(context, LoginActivity::class.java) } @@ -65,7 +55,7 @@ class LoginActivity : BaseActivity(), Logi } override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == android.R.id.home) onBackPressedDispatcher.onBackPressed() + if (item.itemId == android.R.id.home) onBackPressed() return true } @@ -77,24 +67,8 @@ class LoginActivity : BaseActivity(), Logi openFragment(LoginSymbolFragment.newInstance(loginData)) } - fun navigateToStudentSelect(loginData: LoginData, registerUser: RegisterUser) { - openFragment(LoginStudentSelectFragment.newInstance(loginData, registerUser)) - } - - fun navigateToNotifications() { - val isNotificationsPermissionRequired = appInfo.systemVersion >= TIRAMISU - val isPermissionGranted = ContextCompat.checkSelfPermission( - this, "android.permission.POST_NOTIFICATIONS" - ) == PackageManager.PERMISSION_GRANTED - - if (isNotificationsPermissionRequired && !isPermissionGranted) { - openFragment(NotificationsFragment.newInstance(), clearBackStack = true) - } else navigateToFinish() - } - - fun navigateToFinish() { - startActivity(MainActivity.getStartIntent(this)) - finish() + fun navigateToStudentSelect(studentsWithSemesters: List) { + openFragment(LoginStudentSelectFragment.newInstance(studentsWithSemesters)) } fun onAdvancedLoginClick() { @@ -106,8 +80,6 @@ class LoginActivity : BaseActivity(), Logi } private fun openFragment(fragment: Fragment, clearBackStack: Boolean = false) { - supportFragmentManager.popBackStack(fragment::class.java.name, POP_BACK_STACK_INCLUSIVE) - supportFragmentManager.commit { replace(R.id.loginContainer, fragment) setReorderingAllowed(true) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginData.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginData.kt index ae6c22492..5d4743589 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginData.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginData.kt @@ -6,5 +6,4 @@ data class LoginData( val login: String, val password: String, val baseUrl: String, - val symbol: String?, ) : Serializable diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedFragment.kt index 8c90623e1..37dcb38b3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedFragment.kt @@ -8,7 +8,7 @@ import android.widget.ArrayAdapter import androidx.core.widget.doOnTextChanged import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R -import io.github.wulkanowy.data.pojos.RegisterUser +import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.databinding.FragmentLoginAdvancedBinding import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.ui.base.BaseFragment @@ -327,8 +327,8 @@ class LoginAdvancedFragment : (activity as? LoginActivity)?.navigateToSymbolFragment(loginData) } - override fun navigateToStudentSelect(loginData: LoginData, registerUser: RegisterUser) { - (activity as? LoginActivity)?.navigateToStudentSelect(loginData, registerUser) + override fun navigateToStudentSelect(studentsWithSemesters: List) { + (activity as? LoginActivity)?.navigateToStudentSelect(studentsWithSemesters) } override fun onResume() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedPresenter.kt index 33a76e5f9..1b42c6c52 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedPresenter.kt @@ -4,15 +4,9 @@ import io.github.wulkanowy.data.Resource import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.data.logResourceStatus import io.github.wulkanowy.data.onResourceNotLoading -import io.github.wulkanowy.data.pojos.RegisterStudent -import io.github.wulkanowy.data.pojos.RegisterSymbol -import io.github.wulkanowy.data.pojos.RegisterUnit -import io.github.wulkanowy.data.pojos.RegisterUser import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.data.resourceFlow import io.github.wulkanowy.sdk.Sdk -import io.github.wulkanowy.sdk.scrapper.Scrapper -import io.github.wulkanowy.sdk.scrapper.getNormalizedSymbol import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.modules.login.LoginData import io.github.wulkanowy.ui.modules.login.LoginErrorHandler @@ -148,23 +142,19 @@ class LoginAdvancedPresenter @Inject constructor( is Resource.Success -> { analytics.logEvent( "registration_form", - "success" to true, - "students" to it.data.size, - "error" to "No error" - ) - val loginData = LoginData( - login = view?.formUsernameValue.orEmpty().trim(), - password = view?.formPassValue.orEmpty().trim(), - baseUrl = view?.formHostValue.orEmpty().trim(), - symbol = view?.formSymbolValue.orEmpty().trim().getNormalizedSymbol(), - ) - when (it.data.size) { - 0 -> view?.navigateToSymbol(loginData) - else -> view?.navigateToStudentSelect( - loginData = loginData, - registerUser = it.data.toRegisterUser(loginData), - ) - } + "success" to true, + "students" to it.data.size, + "error" to "No error" + ) + val loginData = LoginData( + login = view?.formUsernameValue.orEmpty().trim(), + password = view?.formPassValue.orEmpty().trim(), + baseUrl = view?.formHostValue.orEmpty().trim() + ) + when (it.data.size) { + 0 -> view?.navigateToSymbol(loginData) + else -> view?.navigateToStudentSelect(it.data) + } } is Resource.Error -> { analytics.logEvent( @@ -183,58 +173,6 @@ class LoginAdvancedPresenter @Inject constructor( }.launch("login") } - private fun List.toRegisterUser(loginData: LoginData) = RegisterUser( - email = loginData.login, - password = loginData.password, - login = loginData.login, - baseUrl = loginData.baseUrl, - loginType = firstOrNull()?.student?.loginType?.let( - Scrapper.LoginType::valueOf - ) ?: Scrapper.LoginType.AUTO, - symbols = this - .groupBy { students -> students.student.symbol } - .map { (symbol, students) -> - RegisterSymbol( - symbol = symbol, - error = null, - userName = "", - schools = students - .groupBy { student -> - Triple( - first = student.student.schoolSymbol, - second = student.student.userLoginId, - third = student.student.schoolShortName - ) - } - .map { (groupKey, students) -> - val (schoolId, loginId, schoolName) = groupKey - RegisterUnit( - students = students.map { - RegisterStudent( - studentId = it.student.studentId, - studentName = it.student.studentName, - studentSecondName = it.student.studentName, - studentSurname = it.student.studentName, - className = it.student.className, - classId = it.student.classId, - isParent = it.student.isParent, - semesters = it.semesters, - ) - }, - userLoginId = loginId, - schoolId = schoolId, - schoolName = schoolName, - schoolShortName = schoolName, - parentIds = listOf(), - studentIds = listOf(), - employeeIds = listOf(), - error = null - ) - } - ) - }, - ) - private suspend fun getStudentsAppropriatesToLoginType(): List { val email = view?.formUsernameValue.orEmpty() val password = view?.formPassValue.orEmpty() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedView.kt index 824fa0288..f9b84f1ab 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedView.kt @@ -1,7 +1,6 @@ package io.github.wulkanowy.ui.modules.login.advanced import io.github.wulkanowy.data.db.entities.StudentWithSemesters -import io.github.wulkanowy.data.pojos.RegisterUser import io.github.wulkanowy.ui.base.BaseView import io.github.wulkanowy.ui.modules.login.LoginData @@ -73,7 +72,7 @@ interface LoginAdvancedView : BaseView { fun navigateToSymbol(loginData: LoginData) - fun navigateToStudentSelect(loginData: LoginData, registerUser: RegisterUser) + fun navigateToStudentSelect(studentsWithSemesters: List) fun setErrorPinRequired() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt index a0e7608d6..d31f5cf0f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt @@ -9,8 +9,7 @@ import androidx.core.view.isVisible import androidx.core.widget.doOnTextChanged import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R -import io.github.wulkanowy.data.pojos.RegisterUser -import io.github.wulkanowy.data.repositories.PreferencesRepository +import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.databinding.FragmentLoginFormBinding import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.login.LoginActivity @@ -33,9 +32,6 @@ class LoginFormFragment : BaseFragment(R.layout.fragme @Inject lateinit var appInfo: AppInfo - @Inject - lateinit var preferencesRepository: PreferencesRepository - companion object { fun newInstance() = LoginFormFragment() } @@ -226,8 +222,8 @@ class LoginFormFragment : BaseFragment(R.layout.fragme (activity as? LoginActivity)?.navigateToSymbolFragment(loginData) } - override fun navigateToStudentSelect(loginData: LoginData, registerUser: RegisterUser) { - (activity as? LoginActivity)?.navigateToStudentSelect(loginData, registerUser) + override fun navigateToStudentSelect(studentsWithSemesters: List) { + (activity as? LoginActivity)?.navigateToStudentSelect(studentsWithSemesters) } override fun openAdvancedLogin() { @@ -264,9 +260,8 @@ class LoginFormFragment : BaseFragment(R.layout.fragme R.string.login_email_text, "${appInfo.systemManufacturer} ${appInfo.systemModel}", appInfo.systemVersion.toString(), - "${appInfo.versionName}-${appInfo.buildFlavor}", + appInfo.versionName, "$formHostValue/$formHostSymbol", - preferencesRepository.installationId, lastError ) ) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt index 8035ea0ad..0acb0ea6d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt @@ -93,7 +93,7 @@ class LoginFormPresenter @Inject constructor( if (!validateCredentials(email, password, host)) return resourceFlow { - studentRepository.getUserSubjectsFromScrapper( + studentRepository.getStudentsScrapper( email = email, password = password, scrapperBaseUrl = host, @@ -109,14 +109,14 @@ class LoginFormPresenter @Inject constructor( } } .onResourceSuccess { - val loginData = LoginData(email, password, host, symbol) - when (it.symbols.size) { - 0 -> view?.navigateToSymbol(loginData) - else -> view?.navigateToStudentSelect(loginData, it) + when (it.size) { + 0 -> view?.navigateToSymbol(LoginData(email, password, host)) + else -> view?.navigateToStudentSelect(it) } analytics.logEvent( "registration_form", "success" to true, + "students" to it.size, "scrapperBaseUrl" to host, "error" to "No error" ) @@ -134,6 +134,7 @@ class LoginFormPresenter @Inject constructor( analytics.logEvent( "registration_form", "success" to false, + "students" to -1, "scrapperBaseUrl" to host, "error" to it.message.ifNullOrBlank { "No message" } ) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt index 5a816fb32..8003975db 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt @@ -1,6 +1,6 @@ package io.github.wulkanowy.ui.modules.login.form -import io.github.wulkanowy.data.pojos.RegisterUser +import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.ui.base.BaseView import io.github.wulkanowy.ui.modules.login.LoginData @@ -60,7 +60,7 @@ interface LoginFormView : BaseView { fun navigateToSymbol(loginData: LoginData) - fun navigateToStudentSelect(loginData: LoginData, registerUser: RegisterUser) + fun navigateToStudentSelect(studentsWithSemesters: List) fun openPrivacyPolicyPage() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverFragment.kt index b9afba986..786bbfce8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverFragment.kt @@ -98,7 +98,7 @@ class LoginRecoverFragment : loginRecoverButton.setOnClickListener { presenter.onRecoverClick() } loginRecoverErrorRetry.setOnClickListener { presenter.onRecoverClick() } loginRecoverErrorDetails.setOnClickListener { presenter.onDetailsClick() } - loginRecoverLogin.setOnClickListener { (activity as LoginActivity).onBackPressedDispatcher.onBackPressed() } + loginRecoverLogin.setOnClickListener { (activity as LoginActivity).onBackPressed() } } with(bindingLocal.loginRecoverHost) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectAdapter.kt index e6d131829..c046c2ff5 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectAdapter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectAdapter.kt @@ -2,182 +2,65 @@ package io.github.wulkanowy.ui.modules.login.studentselect import android.annotation.SuppressLint import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup -import androidx.core.view.isVisible -import androidx.recyclerview.widget.DiffUtil.ItemCallback -import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import io.github.wulkanowy.R -import io.github.wulkanowy.databinding.* +import io.github.wulkanowy.data.db.entities.StudentWithSemesters +import io.github.wulkanowy.databinding.ItemLoginStudentSelectBinding import javax.inject.Inject -@SuppressLint("SetTextI18n") class LoginStudentSelectAdapter @Inject constructor() : - ListAdapter(Differ) { + RecyclerView.Adapter() { - override fun getItemViewType(position: Int): Int = getItem(position).type.ordinal + private val checkedList = mutableMapOf() - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { - val inflater = LayoutInflater.from(parent.context) - return when (LoginStudentSelectItemType.values()[viewType]) { - LoginStudentSelectItemType.EMPTY_SYMBOLS_HEADER -> EmptySymbolsHeaderViewHolder( - ItemLoginStudentSelectEmptySymbolHeaderBinding.inflate(inflater, parent, false), - ) - LoginStudentSelectItemType.SYMBOL_HEADER -> SymbolsHeaderViewHolder( - ItemLoginStudentSelectHeaderSymbolBinding.inflate(inflater, parent, false) - ) - LoginStudentSelectItemType.SCHOOL_HEADER -> SchoolHeaderViewHolder( - ItemLoginStudentSelectHeaderSchoolBinding.inflate(inflater, parent, false) - ) - LoginStudentSelectItemType.STUDENT -> StudentViewHolder( - ItemLoginStudentSelectStudentBinding.inflate(inflater, parent, false) - ) - LoginStudentSelectItemType.HELP -> HelpViewHolder( - ItemLoginStudentSelectHelpBinding.inflate(inflater, parent, false) - ) + var items = emptyList>() + set(value) { + field = value + checkedList.clear() } - } - override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - when (holder) { - is EmptySymbolsHeaderViewHolder -> holder.bind(getItem(position) as LoginStudentSelectItem.EmptySymbolsHeader) - is SymbolsHeaderViewHolder -> holder.bind(getItem(position) as LoginStudentSelectItem.SymbolHeader) - is SchoolHeaderViewHolder -> holder.bind(getItem(position) as LoginStudentSelectItem.SchoolHeader) - is StudentViewHolder -> holder.bind(getItem(position) as LoginStudentSelectItem.Student) - is HelpViewHolder -> holder.bind(getItem(position) as LoginStudentSelectItem.Help) - } - } + var onClickListener: (StudentWithSemesters, alreadySaved: Boolean) -> Unit = { _, _ -> } - private class EmptySymbolsHeaderViewHolder( - private val binding: ItemLoginStudentSelectEmptySymbolHeaderBinding, - ) : RecyclerView.ViewHolder(binding.root) { + override fun getItemCount() = items.size - fun bind(item: LoginStudentSelectItem.EmptySymbolsHeader) { - with(binding) { - loginStudentSelectEmptySymbolChevron.rotation = if (item.isExpanded) 270f else 90f - root.setOnClickListener { item.onClick() } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + ItemLoginStudentSelectBinding.inflate(LayoutInflater.from(parent.context), parent, false) + ) + + @SuppressLint("SetTextI18n") + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + val (studentAndSemesters, alreadySaved) = items[position] + val student = studentAndSemesters.student + val semesters = studentAndSemesters.semesters + val diary = semesters.maxByOrNull { it.semesterId } + + with(holder.binding) { + loginItemName.text = "${student.studentName} ${diary?.diaryName.orEmpty()}" + loginItemSchool.text = student.schoolName + loginItemName.isEnabled = !alreadySaved + loginItemSchool.isEnabled = !alreadySaved + loginItemSignedIn.visibility = if (alreadySaved) View.VISIBLE else View.GONE + + with(loginItemCheck) { + isEnabled = !alreadySaved + keyListener = null + isChecked = checkedList[position] ?: false } - } - } - private class SymbolsHeaderViewHolder( - private val binding: ItemLoginStudentSelectHeaderSymbolBinding, - ) : RecyclerView.ViewHolder(binding.root) { - - fun bind(item: LoginStudentSelectItem.SymbolHeader) { - with(binding) { - loginStudentSelectHeaderSymbolValue.text = buildString { - append(root.context.getString(R.string.mobile_device_symbol)) - append(": ") - append(item.humanReadableName ?: item.symbol.symbol) - if (!item.humanReadableName.isNullOrBlank()) { - append(" (${item.symbol.symbol})") - } - } - loginStudentSelectHeaderSymbolUsername.text = item.symbol.userName - loginStudentSelectHeaderSymbolUsername.isVisible = item.symbol.userName.isNotBlank() - loginStudentSelectHeaderSymbolError.text = item.symbol.error?.message - loginStudentSelectHeaderSymbolError.isVisible = item.symbol.error != null - loginStudentSelectHeaderSymbolError.maxLines = when { - item.isErrorExpanded -> Int.MAX_VALUE - else -> 2 - } - - if (item.symbol.error != null) { - root.setOnClickListener { item.onClick(item.symbol) } - } else root.setOnClickListener(null) - } - } - } - - private class SchoolHeaderViewHolder( - private val binding: ItemLoginStudentSelectHeaderSchoolBinding, - ) : RecyclerView.ViewHolder(binding.root) { - - fun bind(item: LoginStudentSelectItem.SchoolHeader) { - with(binding) { - loginStudentSelectHeaderSchoolName.text = buildString { - append(item.unit.schoolName.trim()) - append(" (") - append(item.unit.schoolShortName) - append(")") - } - loginStudentSelectHeaderSchoolDetails.isVisible = item.unit.students.isEmpty() - loginStudentSelectHeaderSchoolError.text = item.unit.error?.message - loginStudentSelectHeaderSchoolError.isVisible = item.unit.error != null - loginStudentSelectHeaderSchoolError.maxLines = when { - item.isErrorExpanded -> Int.MAX_VALUE - else -> 2 - } - - if (item.unit.error != null) { - root.setOnClickListener { item.onClick(item.unit) } - } else root.setOnClickListener(null) - } - } - } - - private class StudentViewHolder( - private val binding: ItemLoginStudentSelectStudentBinding, - ) : RecyclerView.ViewHolder(binding.root) { - - fun bind(item: LoginStudentSelectItem.Student) { - val student = item.student - val semesters = student.semesters - val diary = semesters.maxByOrNull { it.semesterId } - - with(binding) { - loginItemName.text = "${student.studentName} ${student.studentSurname}" - loginItemName.isEnabled = item.isEnabled - loginItemSignedIn.text = if (!item.isEnabled) { - root.context.getString(R.string.login_signed_in) - } else diary?.diaryName + root.setOnClickListener { + onClickListener(studentAndSemesters, alreadySaved) with(loginItemCheck) { - keyListener = null - isEnabled = item.isEnabled - isChecked = item.isSelected || !item.isEnabled - } - - root.isEnabled = item.isEnabled - root.setOnClickListener { - item.onClick(item) + if (isEnabled) { + isChecked = !isChecked + checkedList[position] = isChecked + } } } } } - private class HelpViewHolder( - private val binding: ItemLoginStudentSelectHelpBinding, - ) : RecyclerView.ViewHolder(binding.root) { - - fun bind(item: LoginStudentSelectItem.Help) { - with(binding) { - loginStudentSelectHelpSymbol.isVisible = item.isSymbolButtonVisible - loginStudentSelectHelpSymbol.setOnClickListener { item.onEnterSymbolClick() } - loginStudentSelectHelpMail.setOnClickListener { item.onContactUsClick() } - loginStudentSelectHelpDiscord.setOnClickListener { item.onDiscordClick() } - } - } - } - - private object Differ : ItemCallback() { - - override fun areItemsTheSame( - oldItem: LoginStudentSelectItem, newItem: LoginStudentSelectItem - ): Boolean = when { - oldItem is LoginStudentSelectItem.EmptySymbolsHeader && newItem is LoginStudentSelectItem.EmptySymbolsHeader -> true - oldItem is LoginStudentSelectItem.SymbolHeader && newItem is LoginStudentSelectItem.SymbolHeader -> { - oldItem.symbol == newItem.symbol - } - oldItem is LoginStudentSelectItem.Student && newItem is LoginStudentSelectItem.Student -> { - oldItem.student == newItem.student - } - else -> oldItem == newItem - } - - override fun areContentsTheSame( - oldItem: LoginStudentSelectItem, newItem: LoginStudentSelectItem - ): Boolean = oldItem == newItem - } + class ItemViewHolder(val binding: ItemLoginStudentSelectBinding) : + RecyclerView.ViewHolder(binding.root) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt index 169702151..6c910fe03 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt @@ -2,20 +2,20 @@ package io.github.wulkanowy.ui.modules.login.studentselect import android.os.Bundle import android.view.View +import android.view.View.GONE +import android.view.View.VISIBLE import androidx.core.os.bundleOf -import androidx.core.view.isVisible +import androidx.recyclerview.widget.LinearLayoutManager import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R -import io.github.wulkanowy.data.pojos.RegisterUser -import io.github.wulkanowy.data.repositories.PreferencesRepository +import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.databinding.FragmentLoginStudentSelectBinding import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.login.LoginActivity -import io.github.wulkanowy.ui.modules.login.LoginData +import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.openEmailClient import io.github.wulkanowy.utils.openInternetBrowser -import io.github.wulkanowy.utils.serializable import javax.inject.Inject @AndroidEntryPoint @@ -32,26 +32,12 @@ class LoginStudentSelectFragment : @Inject lateinit var appInfo: AppInfo - @Inject - lateinit var preferencesRepository: PreferencesRepository - - private lateinit var symbolsNames: Array - private lateinit var symbolsValues: Array - - override val symbols: Map by lazy { - symbolsValues.zip(symbolsNames).toMap() - } - companion object { - private const val ARG_LOGIN = "LOGIN" - private const val ARG_STUDENTS = "STUDENTS" + const val ARG_STUDENTS = "STUDENTS" - fun newInstance(loginData: LoginData, registerUser: RegisterUser) = + fun newInstance(studentsWithSemesters: List) = LoginStudentSelectFragment().apply { - arguments = bundleOf( - ARG_LOGIN to loginData, - ARG_STUDENTS to registerUser, - ) + arguments = bundleOf(ARG_STUDENTS to studentsWithSemesters) } } @@ -59,50 +45,62 @@ class LoginStudentSelectFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding = FragmentLoginStudentSelectBinding.bind(view) - - symbolsNames = resources.getStringArray(R.array.symbols) - symbolsValues = resources.getStringArray(R.array.symbols_values) - presenter.onAttachView( view = this, - loginData = requireArguments().serializable(ARG_LOGIN), - registerUser = requireArguments().serializable(ARG_STUDENTS), + students = requireArguments().getSerializable(ARG_STUDENTS) as List, ) } override fun initView() { (requireActivity() as LoginActivity).showActionBar(true) + loginAdapter.onClickListener = presenter::onItemSelected + with(binding) { loginStudentSelectSignIn.setOnClickListener { presenter.onSignIn() } - loginStudentSelectRecycler.adapter = loginAdapter + loginStudentSelectContactDiscord.setOnClickListener { presenter.onDiscordClick() } + loginStudentSelectContactEmail.setOnClickListener { presenter.onEmailClick() } + + with(loginStudentSelectRecycler) { + layoutManager = LinearLayoutManager(context) + adapter = loginAdapter + } } } - override fun updateData(data: List) { - loginAdapter.submitList(data) + override fun updateData(data: List>) { + with(loginAdapter) { + items = data + notifyDataSetChanged() + } } - override fun navigateToSymbol(loginData: LoginData) { - (requireActivity() as LoginActivity).navigateToSymbolFragment(loginData) - } - - override fun navigateToNext() { - (requireActivity() as LoginActivity).navigateToNotifications() + override fun openMainView() { + startActivity(MainActivity.getStartIntent(requireContext())) + requireActivity().finish() } override fun showProgress(show: Boolean) { - binding.loginStudentSelectProgress.isVisible = show + binding.loginStudentSelectProgress.visibility = if (show) VISIBLE else GONE } override fun showContent(show: Boolean) { - binding.loginStudentSelectContent.isVisible = show + binding.loginStudentSelectContent.visibility = if (show) VISIBLE else GONE } override fun enableSignIn(enable: Boolean) { binding.loginStudentSelectSignIn.isEnabled = enable } + override fun showContact(show: Boolean) { + binding.loginStudentSelectContact.visibility = if (show) VISIBLE else GONE + } + + override fun onDestroyView() { + presenter.onDetachView() + super.onDestroyView() + } + override fun openDiscordInvite() { context?.openInternetBrowser("https://discord.gg/vccAQBr", ::showMessage) } @@ -113,19 +111,12 @@ class LoginStudentSelectFragment : email = "wulkanowyinc@gmail.com", subject = requireContext().getString(R.string.login_email_subject), body = requireContext().getString( - R.string.login_email_text, - "${appInfo.systemManufacturer} ${appInfo.systemModel}", + R.string.login_email_text, appInfo.systemModel, appInfo.systemVersion.toString(), - "${appInfo.versionName}-${appInfo.buildFlavor}", + appInfo.versionName, "Select users to log in", - preferencesRepository.installationId, lastError ) ) } - - override fun onDestroyView() { - presenter.onDetachView() - super.onDestroyView() - } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectItem.kt deleted file mode 100644 index 1edc8e7b4..000000000 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectItem.kt +++ /dev/null @@ -1,50 +0,0 @@ -package io.github.wulkanowy.ui.modules.login.studentselect - -import io.github.wulkanowy.data.pojos.RegisterStudent -import io.github.wulkanowy.data.pojos.RegisterSymbol -import io.github.wulkanowy.data.pojos.RegisterUnit - -sealed class LoginStudentSelectItem(val type: LoginStudentSelectItemType) { - - data class EmptySymbolsHeader( - val isExpanded: Boolean, - val onClick: () -> Unit, - ) : LoginStudentSelectItem(LoginStudentSelectItemType.EMPTY_SYMBOLS_HEADER) - - data class SymbolHeader( - val symbol: RegisterSymbol, - val humanReadableName: String?, - val isErrorExpanded: Boolean, - val onClick: (RegisterSymbol) -> Unit, - ) : LoginStudentSelectItem(LoginStudentSelectItemType.SYMBOL_HEADER) - - data class SchoolHeader( - val unit: RegisterUnit, - val isErrorExpanded: Boolean, - val onClick: (RegisterUnit) -> Unit, - ) : LoginStudentSelectItem(LoginStudentSelectItemType.SCHOOL_HEADER) - - data class Student( - val symbol: RegisterSymbol, - val unit: RegisterUnit, - val student: RegisterStudent, - val isEnabled: Boolean, - val isSelected: Boolean, - val onClick: (Student) -> Unit, - ) : LoginStudentSelectItem(LoginStudentSelectItemType.STUDENT) - - data class Help( - val onEnterSymbolClick: () -> Unit, - val onContactUsClick: () -> Unit, - val onDiscordClick: () -> Unit, - val isSymbolButtonVisible: Boolean, - ) : LoginStudentSelectItem(LoginStudentSelectItemType.HELP) -} - -enum class LoginStudentSelectItemType { - EMPTY_SYMBOLS_HEADER, - SYMBOL_HEADER, - SCHOOL_HEADER, - STUDENT, - HELP, -} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt index f94ea7b72..3455b3cf1 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt @@ -1,23 +1,15 @@ package io.github.wulkanowy.ui.modules.login.studentselect import io.github.wulkanowy.data.Resource -import io.github.wulkanowy.data.dataOrNull +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.data.logResourceStatus -import io.github.wulkanowy.data.mappers.mapToStudentWithSemesters -import io.github.wulkanowy.data.pojos.RegisterStudent -import io.github.wulkanowy.data.pojos.RegisterSymbol -import io.github.wulkanowy.data.pojos.RegisterUnit -import io.github.wulkanowy.data.pojos.RegisterUser import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.data.resourceFlow -import io.github.wulkanowy.sdk.scrapper.login.AccountPermissionException import io.github.wulkanowy.services.sync.SyncManager import io.github.wulkanowy.ui.base.BasePresenter -import io.github.wulkanowy.ui.modules.login.LoginData import io.github.wulkanowy.ui.modules.login.LoginErrorHandler import io.github.wulkanowy.utils.AnalyticsHelper -import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.ifNullOrBlank import kotlinx.coroutines.flow.onEach import timber.log.Timber @@ -27,30 +19,18 @@ class LoginStudentSelectPresenter @Inject constructor( studentRepository: StudentRepository, private val loginErrorHandler: LoginErrorHandler, private val syncManager: SyncManager, - private val analytics: AnalyticsHelper, - private val appInfo: AppInfo, + private val analytics: AnalyticsHelper ) : BasePresenter(loginErrorHandler, studentRepository) { private var lastError: Throwable? = null - private lateinit var registerUser: RegisterUser - private lateinit var loginData: LoginData + private val selectedStudents = mutableListOf() - private lateinit var students: List - private var isEmptySymbolsExpanded = false - private var expandedSymbolError: RegisterSymbol? = null - private var expandedSchoolError: RegisterUnit? = null - - private val selectedStudents = mutableListOf() - - fun onAttachView( - view: LoginStudentSelectView, - loginData: LoginData, - registerUser: RegisterUser, - ) { + fun onAttachView(view: LoginStudentSelectView, students: List) { super.onAttachView(view) with(view) { initView() + showContact(false) enableSignIn(false) loginErrorHandler.onStudentDuplicate = { showMessage(it) @@ -58,171 +38,50 @@ class LoginStudentSelectPresenter @Inject constructor( } } - this.loginData = loginData - this.registerUser = registerUser - loadData() + if (students.size == 1) registerStudents(students) + loadData(students) } - private fun loadData() { - resetSelectedState() - - resourceFlow { studentRepository.getSavedStudents(false) }.onEach { - students = it.dataOrNull.orEmpty() - when (it) { - is Resource.Loading -> Timber.d("Login student select students load started") - is Resource.Success -> refreshItems() - is Resource.Error -> { - errorHandler.dispatch(it.error) - lastError = it.error - refreshItems() - } - } - }.launch() - } - - private fun createItems(): List = buildList { - val notEmptySymbols = registerUser.symbols.filter { it.schools.isNotEmpty() } - val emptySymbols = registerUser.symbols.filter { it.schools.isEmpty() } - - if (emptySymbols.isNotEmpty() && notEmptySymbols.isNotEmpty() && emptySymbols.any { it.symbol == loginData.symbol }) { - add(createEmptySymbolItem(emptySymbols.first { it.symbol == loginData.symbol })) - } - - addAll(createNotEmptySymbolItems(notEmptySymbols, students)) - addAll(createEmptySymbolItems(emptySymbols, notEmptySymbols.isNotEmpty())) - - val helpItem = LoginStudentSelectItem.Help( - onEnterSymbolClick = ::onEnterSymbol, - onContactUsClick = ::onEmailClick, - onDiscordClick = ::onDiscordClick, - isSymbolButtonVisible = "login" !in loginData.baseUrl, - ) - add(helpItem) - } - - private fun createNotEmptySymbolItems( - notEmptySymbols: List, - students: List, - ) = buildList { - notEmptySymbols.forEach { registerSymbol -> - val symbolHeader = LoginStudentSelectItem.SymbolHeader( - symbol = registerSymbol, - humanReadableName = view?.symbols?.get(registerSymbol.symbol), - isErrorExpanded = expandedSymbolError == registerSymbol, - onClick = ::onSymbolItemClick, - ) - add(symbolHeader) - - registerSymbol.schools.forEach { registerUnit -> - val schoolHeader = LoginStudentSelectItem.SchoolHeader( - unit = registerUnit, - isErrorExpanded = expandedSchoolError == registerUnit, - onClick = ::onUnitItemClick, - ) - add(schoolHeader) - - registerUnit.students.forEach { - add(createStudentItem(it, registerSymbol, registerUnit, students)) - } - } - } - } - - private fun createStudentItem( - student: RegisterStudent, - symbol: RegisterSymbol, - school: RegisterUnit, - students: List, - ) = LoginStudentSelectItem.Student( - symbol = symbol, - unit = school, - student = student, - onClick = ::onItemSelected, - isEnabled = students.none { - it.student.email == registerUser.login - && it.student.symbol == symbol.symbol - && it.student.studentId == student.studentId - && it.student.schoolSymbol == school.schoolId - && it.student.classId == student.classId - }, - isSelected = selectedStudents - .filter { it.symbol.symbol == symbol.symbol } - .filter { it.unit.schoolId == school.schoolId } - .filter { it.student.studentId == student.studentId } - .filter { it.student.classId == student.classId } - .size == 1, - ) - - private fun createEmptySymbolItems( - emptySymbols: List, - isNotEmptySymbolsExist: Boolean, - ) = buildList { - val filteredEmptySymbols = emptySymbols.filter { - it.error !is AccountPermissionException - }.ifEmpty { emptySymbols.takeIf { !isNotEmptySymbolsExist }.orEmpty() } - - if (filteredEmptySymbols.isNotEmpty() && isNotEmptySymbolsExist) { - val emptyHeader = LoginStudentSelectItem.EmptySymbolsHeader( - isExpanded = isEmptySymbolsExpanded, - onClick = ::onEmptySymbolsToggle, - ) - add(emptyHeader) - if (isEmptySymbolsExpanded) { - filteredEmptySymbols.forEach { - add(createEmptySymbolItem(it)) - } - } - } - - if (filteredEmptySymbols.isNotEmpty() && !isNotEmptySymbolsExist) { - filteredEmptySymbols.forEach { - add(createEmptySymbolItem(it)) - } - } - } - - private fun createEmptySymbolItem(registerSymbol: RegisterSymbol) = - LoginStudentSelectItem.SymbolHeader( - symbol = registerSymbol, - humanReadableName = view?.symbols?.get(registerSymbol.symbol), - isErrorExpanded = expandedSymbolError == registerSymbol, - onClick = ::onSymbolItemClick, - ) - fun onSignIn() { registerStudents(selectedStudents) } - private fun onEmptySymbolsToggle() { - isEmptySymbolsExpanded = !isEmptySymbolsExpanded - - refreshItems() - } - - private fun onItemSelected(item: LoginStudentSelectItem.Student) { - if (!item.isEnabled) return + fun onItemSelected(studentWithSemester: StudentWithSemesters, alreadySaved: Boolean) { + if (alreadySaved) return selectedStudents - .removeAll { - it.student.studentId == item.student.studentId && - it.student.classId == item.student.classId && - it.unit.schoolId == item.unit.schoolId && - it.symbol.symbol == item.symbol.symbol - } - .let { if (!it) selectedStudents.add(item) } + .removeAll { it == studentWithSemester } + .let { if (!it) selectedStudents.add(studentWithSemester) } view?.enableSignIn(selectedStudents.isNotEmpty()) - refreshItems() } - private fun onSymbolItemClick(symbol: RegisterSymbol) { - expandedSymbolError = if (symbol != expandedSymbolError) symbol else null - refreshItems() + private fun compareStudents(a: Student, b: Student): Boolean { + return a.email == b.email + && a.symbol == b.symbol + && a.studentId == b.studentId + && a.schoolSymbol == b.schoolSymbol + && a.classId == b.classId } - private fun onUnitItemClick(unit: RegisterUnit) { - expandedSchoolError = if (unit != expandedSchoolError) unit else null - refreshItems() + private fun loadData(studentsWithSemesters: List) { + resetSelectedState() + + resourceFlow { studentRepository.getSavedStudents(false) }.onEach { + when (it) { + is Resource.Loading -> Timber.d("Login student select students load started") + is Resource.Success -> view?.updateData(studentsWithSemesters.map { studentWithSemesters -> + studentWithSemesters to it.data.any { item -> + compareStudents(studentWithSemesters.student, item.student) + } + }) + is Resource.Error -> { + errorHandler.dispatch(it.error) + lastError = it.error + view?.updateData(studentsWithSemesters.map { student -> student to false }) + } + } + }.launch() } private fun resetSelectedState() { @@ -230,20 +89,7 @@ class LoginStudentSelectPresenter @Inject constructor( view?.enableSignIn(false) } - private fun refreshItems() { - view?.updateData(createItems()) - } - - private fun registerStudents(students: List) { - val studentsWithSemesters = students - .filterIsInstance().map { item -> - item.student.mapToStudentWithSemesters( - user = registerUser, - symbol = item.symbol, - unit = item.unit, - colors = appInfo.defaultColorsForAvatar, - ) - } + private fun registerStudents(studentsWithSemesters: List) { resourceFlow { studentRepository.saveStudents(studentsWithSemesters) } .logResourceStatus("registration") .onEach { @@ -254,13 +100,14 @@ class LoginStudentSelectPresenter @Inject constructor( } is Resource.Success -> { syncManager.startOneTimeSyncWorker(quiet = true) - view?.navigateToNext() + view?.openMainView() logRegisterEvent(studentsWithSemesters) } is Resource.Error -> { view?.apply { showProgress(false) showContent(true) + showContact(true) } lastError = it.error loginErrorHandler.dispatch(it.error) @@ -270,22 +117,12 @@ class LoginStudentSelectPresenter @Inject constructor( }.launch("register") } - private fun onEnterSymbol() { - view?.navigateToSymbol(loginData) - } - - private fun onDiscordClick() { + fun onDiscordClick() { view?.openDiscordInvite() } - private fun onEmailClick() { - view?.openEmail(lastError?.message.ifNullOrBlank { - registerUser.symbols.flatMap { symbol -> - symbol.schools.map { it.error?.message } + symbol.error?.message - }.filterNotNull().distinct().joinToString("; ") { - it.take(46) + "..." - }.ifEmpty { "blank" } - }) + fun onEmailClick() { + view?.openEmail(lastError?.message.ifNullOrBlank { "empty" }) } private fun logRegisterEvent( diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectView.kt index 39f312bf3..f2acd76c5 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectView.kt @@ -1,19 +1,15 @@ package io.github.wulkanowy.ui.modules.login.studentselect +import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.ui.base.BaseView -import io.github.wulkanowy.ui.modules.login.LoginData interface LoginStudentSelectView : BaseView { - val symbols: Map - fun initView() - fun updateData(data: List) + fun updateData(data: List>) - fun navigateToSymbol(loginData: LoginData) - - fun navigateToNext() + fun openMainView() fun showProgress(show: Boolean) @@ -21,6 +17,8 @@ interface LoginStudentSelectView : BaseView { fun enableSignIn(enable: Boolean) + fun showContact(show: Boolean) + fun openDiscordInvite() fun openEmail(lastError: String) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt index 67416cb63..58bdf6cef 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt @@ -12,13 +12,16 @@ import androidx.core.text.parseAsHtml import androidx.core.widget.doOnTextChanged import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R -import io.github.wulkanowy.data.pojos.RegisterUser -import io.github.wulkanowy.data.repositories.PreferencesRepository +import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.databinding.FragmentLoginSymbolBinding import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.login.LoginActivity import io.github.wulkanowy.ui.modules.login.LoginData -import io.github.wulkanowy.utils.* +import io.github.wulkanowy.utils.AppInfo +import io.github.wulkanowy.utils.hideSoftInput +import io.github.wulkanowy.utils.openEmailClient +import io.github.wulkanowy.utils.openInternetBrowser +import io.github.wulkanowy.utils.showSoftInput import javax.inject.Inject @AndroidEntryPoint @@ -31,9 +34,6 @@ class LoginSymbolFragment : @Inject lateinit var appInfo: AppInfo - @Inject - lateinit var preferencesRepository: PreferencesRepository - companion object { private const val SAVED_LOGIN_DATA = "LOGIN_DATA" @@ -42,8 +42,6 @@ class LoginSymbolFragment : } } - override val symbolValue: String? get() = binding.loginSymbolName.text?.toString() - override val symbolNameError: CharSequence? get() = binding.loginSymbolNameLayout.error @@ -52,7 +50,7 @@ class LoginSymbolFragment : binding = FragmentLoginSymbolBinding.bind(view) presenter.onAttachView( view = this, - loginData = requireArguments().serializable(SAVED_LOGIN_DATA), + loginData = requireArguments().getSerializable(SAVED_LOGIN_DATA) as LoginData, ) } @@ -60,7 +58,7 @@ class LoginSymbolFragment : (requireActivity() as LoginActivity).showActionBar(true) with(binding) { - loginSymbolSignIn.setOnClickListener { presenter.attemptLogin() } + loginSymbolSignIn.setOnClickListener { presenter.attemptLogin(loginSymbolName.text.toString()) } loginSymbolFaq.setOnClickListener { presenter.onFaqClick() } loginSymbolContactEmail.setOnClickListener { presenter.onEmailClick() } @@ -94,13 +92,9 @@ class LoginSymbolFragment : } override fun setErrorSymbolRequire() { - setErrorSymbol(getString(R.string.error_field_required)) - } - - override fun setErrorSymbol(message: String) { - with(binding.loginSymbolNameLayout) { + binding.loginSymbolNameLayout.apply { requestFocus() - error = message + error = getString(R.string.error_field_required) } } @@ -131,8 +125,8 @@ class LoginSymbolFragment : binding.loginSymbolContainer.visibility = if (show) VISIBLE else GONE } - override fun navigateToStudentSelect(loginData: LoginData, registerUser: RegisterUser) { - (activity as? LoginActivity)?.navigateToStudentSelect(loginData, registerUser) + override fun navigateToStudentSelect(studentsWithSemesters: List) { + (activity as? LoginActivity)?.navigateToStudentSelect(studentsWithSemesters) } override fun onSaveInstanceState(outState: Bundle) { @@ -165,9 +159,8 @@ class LoginSymbolFragment : R.string.login_email_text, "${appInfo.systemManufacturer} ${appInfo.systemModel}", appInfo.systemVersion.toString(), - "${appInfo.versionName}-${appInfo.buildFlavor}", + appInfo.versionName, "$host/${binding.loginSymbolName.text}", - preferencesRepository.installationId, lastError ) ) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt index a6ccd7a57..691cd4481 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt @@ -1,12 +1,9 @@ package io.github.wulkanowy.ui.modules.login.symbol import io.github.wulkanowy.data.Resource -import io.github.wulkanowy.data.dataOrNull import io.github.wulkanowy.data.onResourceNotLoading -import io.github.wulkanowy.data.pojos.RegisterUser import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.data.resourceFlow -import io.github.wulkanowy.sdk.scrapper.getNormalizedSymbol import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.modules.login.LoginData import io.github.wulkanowy.ui.modules.login.LoginErrorHandler @@ -26,14 +23,9 @@ class LoginSymbolPresenter @Inject constructor( lateinit var loginData: LoginData - private var registerUser: RegisterUser? = null - fun onAttachView(view: LoginSymbolView, loginData: LoginData) { super.onAttachView(view) this.loginData = loginData - loginErrorHandler.onBadCredentials = { - view.setErrorSymbol(it.orEmpty()) - } with(view) { initView() showContact(false) @@ -47,24 +39,20 @@ class LoginSymbolPresenter @Inject constructor( view?.apply { if (symbolNameError != null) clearSymbolError() } } - fun attemptLogin() { - if (view?.symbolValue.isNullOrBlank()) { + fun attemptLogin(symbol: String) { + if (symbol.isBlank()) { view?.setErrorSymbolRequire() return } - loginData = loginData.copy( - symbol = view?.symbolValue?.getNormalizedSymbol(), - ) resourceFlow { - studentRepository.getUserSubjectsFromScrapper( + studentRepository.getStudentsScrapper( email = loginData.login, password = loginData.password, scrapperBaseUrl = loginData.baseUrl, - symbol = view?.symbolValue.orEmpty(), + symbol = symbol, ) }.onEach { - registerUser = it.dataOrNull when (it) { is Resource.Loading -> view?.run { Timber.i("Login with symbol started") @@ -73,7 +61,7 @@ class LoginSymbolPresenter @Inject constructor( showContent(false) } is Resource.Success -> { - when (it.data.symbols.size) { + when (it.data.size) { 0 -> { Timber.i("Login with symbol result: Empty student list") view?.run { @@ -83,14 +71,15 @@ class LoginSymbolPresenter @Inject constructor( } else -> { Timber.i("Login with symbol result: Success") - view?.navigateToStudentSelect(loginData, requireNotNull(it.data)) + view?.navigateToStudentSelect(requireNotNull(it.data)) } } analytics.logEvent( "registration_symbol", "success" to true, + "students" to it.data.size, "scrapperBaseUrl" to loginData.baseUrl, - "symbol" to view?.symbolValue, + "symbol" to symbol, "error" to "No error" ) } @@ -101,7 +90,7 @@ class LoginSymbolPresenter @Inject constructor( "success" to false, "students" to -1, "scrapperBaseUrl" to loginData.baseUrl, - "symbol" to view?.symbolValue, + "symbol" to symbol, "error" to it.error.message.ifNullOrBlank { "No message" } ) loginErrorHandler.dispatch(it.error) @@ -122,12 +111,6 @@ class LoginSymbolPresenter @Inject constructor( } fun onEmailClick() { - view?.openEmail(loginData.baseUrl, lastError?.message.ifNullOrBlank { - registerUser?.symbols?.flatMap { symbol -> - symbol.schools.map { it.error?.message } + symbol.error?.message - }?.filterNotNull()?.distinct()?.joinToString(";") { - it.take(46) + "..." - } ?: "blank" - }) + view?.openEmail(loginData.baseUrl, lastError?.message.ifNullOrBlank { "empty" }) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt index 6b62d1f7f..527895b77 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt @@ -1,13 +1,10 @@ package io.github.wulkanowy.ui.modules.login.symbol -import io.github.wulkanowy.data.pojos.RegisterUser +import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.ui.base.BaseView -import io.github.wulkanowy.ui.modules.login.LoginData interface LoginSymbolView : BaseView { - val symbolValue: String? - val symbolNameError: CharSequence? fun initView() @@ -18,8 +15,6 @@ interface LoginSymbolView : BaseView { fun setErrorSymbolRequire() - fun setErrorSymbol(message: String) - fun clearSymbolError() fun clearAndFocusSymbol() @@ -32,7 +27,7 @@ interface LoginSymbolView : BaseView { fun showContent(show: Boolean) - fun navigateToStudentSelect(loginData: LoginData, registerUser: RegisterUser) + fun navigateToStudentSelect(studentsWithSemesters: List) fun showContact(show: Boolean) 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 d332ee350..5cd6fa103 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 @@ -6,8 +6,6 @@ import android.os.Build.VERSION_CODES.P import android.os.Bundle import android.view.Menu import android.view.MenuItem -import androidx.activity.OnBackPressedCallback -import androidx.activity.addCallback import androidx.core.view.ViewCompat import androidx.core.view.isVisible import androidx.fragment.app.DialogFragment @@ -52,8 +50,6 @@ class MainActivity : BaseActivity(), MainVie @Inject lateinit var appInfo: AppInfo - private var onBackCallback: OnBackPressedCallback? = null - private var accountMenu: MenuItem? = null private val overlayProvider by lazy { ElevationOverlayProvider(this) } @@ -92,9 +88,6 @@ class MainActivity : BaseActivity(), MainVie this.savedInstanceState = savedInstanceState messageContainer = binding.mainMessageContainer updateHelper.messageContainer = binding.mainFragmentContainer - onBackCallback = onBackPressedDispatcher.addCallback(this, enabled = false) { - presenter.onBackPressed() - } val destination = intent.getStringExtra(EXTRA_START_DESTINATION) ?.takeIf { savedInstanceState == null } @@ -273,7 +266,6 @@ class MainActivity : BaseActivity(), MainVie analytics.popCurrentScreen(navController.currentFrag!!::class.simpleName) navController.pushFragment(fragment) - onBackCallback?.isEnabled = !isRootView } override fun popView(depth: Int) { @@ -281,7 +273,10 @@ class MainActivity : BaseActivity(), MainVie analytics.popCurrentScreen(navController.currentFrag!!::class.simpleName) navController.safelyPopFragments(depth) - onBackCallback?.isEnabled = !isRootView + } + + override fun onBackPressed() { + presenter.onBackPressed { super.onBackPressed() } } override fun showStudentAvatar(student: Student) { 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 458e966d4..9c32d8583 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 @@ -139,9 +139,12 @@ class MainPresenter @Inject constructor( return true } - fun onBackPressed() { + fun onBackPressed(default: () -> Unit) { Timber.i("Back pressed in main view") - view?.popView() + view?.run { + if (isRootView) default() + else popView() + } } fun onTabSelected(index: Int, wasSelected: Boolean): Boolean { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserAdapter.kt deleted file mode 100644 index 59f6d288d..000000000 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserAdapter.kt +++ /dev/null @@ -1,81 +0,0 @@ -package io.github.wulkanowy.ui.modules.message.mailboxchooser - -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.core.view.isVisible -import androidx.recyclerview.widget.DiffUtil.ItemCallback -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView -import io.github.wulkanowy.R -import io.github.wulkanowy.data.db.entities.Mailbox -import io.github.wulkanowy.data.db.entities.MailboxType -import io.github.wulkanowy.databinding.ItemMailboxChooserBinding -import javax.inject.Inject - -class MailboxChooserAdapter @Inject constructor() : - ListAdapter(Differ) { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( - ItemMailboxChooserBinding.inflate( - LayoutInflater.from(parent.context), parent, false - ) - ) - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - holder.bind(getItem(position)) - } - - class ItemViewHolder( - private val binding: ItemMailboxChooserBinding, - ) : RecyclerView.ViewHolder(binding.root) { - - fun bind(item: MailboxChooserItem) { - with(binding) { - mailboxItemName.text = item.mailbox?.getFirstLine() - ?: root.resources.getString(R.string.message_chip_all_mailboxes) - mailboxItemSchool.text = item.mailbox?.getSecondLine() - mailboxItemSchool.isVisible = !item.isAll - - root.setOnClickListener { item.onClickListener(item.mailbox) } - } - } - - private fun Mailbox.getFirstLine() = buildString { - if (studentName.isNotBlank() && studentName != userName) { - append(studentName) - append(" - ") - } - append(userName) - } - - private fun Mailbox.getSecondLine() = buildString { - append(schoolNameShort) - append(" - ") - append(getMailboxType(type)) - } - - private fun getMailboxType(type: MailboxType): String = when (type) { - MailboxType.STUDENT -> R.string.message_mailbox_type_student - MailboxType.PARENT -> R.string.message_mailbox_type_parent - MailboxType.GUARDIAN -> R.string.message_mailbox_type_guardian - MailboxType.EMPLOYEE -> R.string.message_mailbox_type_employee - MailboxType.UNKNOWN -> null - }.let { it?.let { it1 -> binding.root.resources.getString(it1) }.orEmpty() } - } - - private object Differ : ItemCallback() { - override fun areItemsTheSame( - oldItem: MailboxChooserItem, - newItem: MailboxChooserItem - ): Boolean { - return oldItem.mailbox?.globalKey == newItem.mailbox?.globalKey - } - - override fun areContentsTheSame( - oldItem: MailboxChooserItem, - newItem: MailboxChooserItem - ): Boolean { - return oldItem == newItem - } - } -} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserDialog.kt deleted file mode 100644 index 37f9a19b5..000000000 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserDialog.kt +++ /dev/null @@ -1,75 +0,0 @@ -package io.github.wulkanowy.ui.modules.message.mailboxchooser - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.core.os.bundleOf -import androidx.fragment.app.setFragmentResult -import dagger.hilt.android.AndroidEntryPoint -import io.github.wulkanowy.data.db.entities.Mailbox -import io.github.wulkanowy.databinding.DialogMailboxChooserBinding -import io.github.wulkanowy.ui.base.BaseDialogFragment -import io.github.wulkanowy.utils.parcelableArray -import javax.inject.Inject - -@AndroidEntryPoint -class MailboxChooserDialog : BaseDialogFragment(), MailboxChooserView { - - @Inject - lateinit var presenter: MailboxChooserPresenter - - @Inject - lateinit var mailboxAdapter: MailboxChooserAdapter - - companion object { - const val LISTENER_KEY = "mailbox_selected" - const val MAILBOX_KEY = "selected_mailbox" - const val REQUIRED_KEY = "is_mailbox_required" - - fun newInstance(mailboxes: List, isMailboxRequired: Boolean, folder: String) = - MailboxChooserDialog().apply { - arguments = bundleOf( - MAILBOX_KEY to mailboxes.toTypedArray(), - REQUIRED_KEY to isMailboxRequired, - LISTENER_KEY to folder, - ) - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setStyle(STYLE_NO_TITLE, 0) - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ) = DialogMailboxChooserBinding.inflate(inflater).apply { binding = this }.root - - @Suppress("UNCHECKED_CAST") - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - presenter.onAttachView( - view = this, - requireMailbox = requireArguments().getBoolean(REQUIRED_KEY, false), - mailboxes = requireArguments().parcelableArray(MAILBOX_KEY).orEmpty().toList(), - ) - } - - override fun initView() { - binding.accountQuickDialogRecycler.adapter = mailboxAdapter - } - - override fun submitData(items: List) { - mailboxAdapter.submitList(items) - } - - override fun onMailboxSelected(item: Mailbox?) { - setFragmentResult( - requestKey = requireArguments().getString(LISTENER_KEY).orEmpty(), - result = bundleOf(MAILBOX_KEY to item), - ) - dismiss() - } -} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserItem.kt deleted file mode 100644 index 6923cf085..000000000 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserItem.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.github.wulkanowy.ui.modules.message.mailboxchooser - -import io.github.wulkanowy.data.db.entities.Mailbox - -data class MailboxChooserItem( - val mailbox: Mailbox? = null, - val isAll: Boolean = false, - val onClickListener: (Mailbox?) -> Unit, -) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserPresenter.kt deleted file mode 100644 index 5bd7c84ab..000000000 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserPresenter.kt +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.wulkanowy.ui.modules.message.mailboxchooser - -import io.github.wulkanowy.data.db.entities.Mailbox -import io.github.wulkanowy.data.repositories.StudentRepository -import io.github.wulkanowy.ui.base.BasePresenter -import io.github.wulkanowy.ui.base.ErrorHandler -import timber.log.Timber -import javax.inject.Inject - -class MailboxChooserPresenter @Inject constructor( - errorHandler: ErrorHandler, - studentRepository: StudentRepository -) : BasePresenter(errorHandler, studentRepository) { - - fun onAttachView(view: MailboxChooserView, mailboxes: List, requireMailbox: Boolean) { - super.onAttachView(view) - - view.initView() - Timber.i("Mailbox chooser view was initialized") - view.submitData(getMailboxItems(mailboxes, requireMailbox)) - } - - private fun getMailboxItems( - mailboxes: List, - requireMailbox: Boolean, - ): List = buildList { - if (!requireMailbox) { - add(MailboxChooserItem(isAll = true, onClickListener = ::onMailboxSelect)) - } - addAll(mailboxes.map { - MailboxChooserItem(mailbox = it, isAll = false, onClickListener = ::onMailboxSelect) - }) - } - - fun onMailboxSelect(item: Mailbox?) { - view?.onMailboxSelected(item) - } -} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserView.kt deleted file mode 100644 index 2e20ee815..000000000 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserView.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.github.wulkanowy.ui.modules.message.mailboxchooser - -import io.github.wulkanowy.data.db.entities.Mailbox -import io.github.wulkanowy.ui.base.BaseView - -interface MailboxChooserView : BaseView { - - fun initView() - - fun submitData(items: List) - - fun onMailboxSelected(item: Mailbox?) -} 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 d3c6b95c7..3c1c53d39 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 @@ -1,5 +1,6 @@ package io.github.wulkanowy.ui.modules.message.preview +import android.annotation.SuppressLint import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -73,20 +74,15 @@ class MessagePreviewAdapter @Inject constructor() : } } + @SuppressLint("SetTextI18n") private fun bindMessage(holder: MessageViewHolder, message: Message) { val context = holder.binding.root.context - val recipientCount = (message.unreadBy ?: 0) + (message.readBy ?: 0) - val isReceived = message.unreadBy == null - val readText = when { - recipientCount > 1 -> { - context.getString(R.string.message_read_by, message.readBy, recipientCount) - } - message.readBy == 1 || (isReceived && !message.unread) -> { - 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 { 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 6c54d9fcb..2a5523f4d 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 @@ -13,7 +13,6 @@ import android.webkit.WebResourceRequest import android.webkit.WebView import android.webkit.WebViewClient import androidx.core.content.getSystemService -import androidx.core.os.bundleOf import androidx.recyclerview.widget.LinearLayoutManager import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R @@ -24,7 +23,6 @@ import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity -import io.github.wulkanowy.utils.serializable import io.github.wulkanowy.utils.shareText import javax.inject.Inject @@ -68,12 +66,13 @@ class MessagePreviewFragment : companion object { const val MESSAGE_ID_KEY = "message_id" - fun newInstance(message: Message) = MessagePreviewFragment().apply { - arguments = bundleOf(MESSAGE_ID_KEY to message) + fun newInstance(message: Message): MessagePreviewFragment { + return MessagePreviewFragment().apply { + arguments = Bundle().apply { putSerializable(MESSAGE_ID_KEY, message) } + } } } - @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) @@ -84,8 +83,8 @@ class MessagePreviewFragment : binding = FragmentMessagePreviewBinding.bind(view) messageContainer = binding.messagePreviewContainer presenter.onAttachView( - view = this, - message = (savedInstanceState ?: arguments)?.serializable(MESSAGE_ID_KEY), + this, + (savedInstanceState ?: arguments)?.getSerializable(MESSAGE_ID_KEY) as? Message ) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt index 56f23b6fa..c011f41f3 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 @@ -6,6 +6,7 @@ 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 @@ -20,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) { @@ -185,7 +187,7 @@ class MessagePreviewPresenter @Inject constructor( presenterScope.launch { runCatching { val student = studentRepository.getCurrentStudent(decryptPass = true) - val mailbox = messageRepository.getMailboxByStudent(student) + val mailbox = mailboxRepository.getMailbox(student) messageRepository.deleteMessage(student, mailbox, message!!) } .onFailure { 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 14f3d718d..334e389e2 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 @@ -19,16 +19,11 @@ 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.Mailbox import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.databinding.ActivitySendMessageBinding import io.github.wulkanowy.ui.base.BaseActivity -import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog -import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog.Companion.MAILBOX_KEY -import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog.Companion.LISTENER_KEY import io.github.wulkanowy.utils.dpToPx import io.github.wulkanowy.utils.hideSoftInput -import io.github.wulkanowy.utils.nullableSerializable import io.github.wulkanowy.utils.showSoftInput import javax.inject.Inject @@ -105,17 +100,13 @@ class SendMessageActivity : BaseActivity - presenter.onMailboxSelected(bundle.nullableSerializable(MAILBOX_KEY)) - } } @SuppressLint("ClickableViewAccessibility") @@ -214,14 +205,6 @@ class SendMessageActivity : BaseActivity) { - MailboxChooserDialog.newInstance( - mailboxes = mailboxes, - isMailboxRequired = true, - folder = LISTENER_KEY, - ).show(supportFragmentManager, "chooser") - } - override fun popView() { finish() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt index e776e9941..6c07ee6ad 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt @@ -1,15 +1,15 @@ package io.github.wulkanowy.ui.modules.message.send -import io.github.wulkanowy.data.* +import io.github.wulkanowy.data.Resource import io.github.wulkanowy.data.db.entities.Mailbox import io.github.wulkanowy.data.db.entities.MailboxType import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.Recipient +import io.github.wulkanowy.data.logResourceStatus +import io.github.wulkanowy.data.onResourceNotLoading import io.github.wulkanowy.data.pojos.MessageDraft -import io.github.wulkanowy.data.repositories.MessageRepository -import io.github.wulkanowy.data.repositories.PreferencesRepository -import io.github.wulkanowy.data.repositories.RecipientRepository -import io.github.wulkanowy.data.repositories.StudentRepository +import io.github.wulkanowy.data.repositories.* +import io.github.wulkanowy.data.resourceFlow import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.AnalyticsHelper @@ -28,6 +28,7 @@ class SendMessagePresenter @Inject constructor( errorHandler: ErrorHandler, studentRepository: StudentRepository, private val messageRepository: MessageRepository, + private val mailboxRepository: MailboxRepository, private val recipientRepository: RecipientRepository, private val preferencesRepository: PreferencesRepository, private val analytics: AnalyticsHelper @@ -35,19 +36,10 @@ class SendMessagePresenter @Inject constructor( private val messageUpdateChannel = Channel() - private var message: Message? = null - private var isReplay: Boolean? = null - - private var mailboxes: List = emptyList() - private var selectedMailbox: Mailbox? = null - fun onAttachView(view: SendMessageView, reason: String?, message: Message?, reply: Boolean?) { super.onAttachView(view) view.initView() initializeSubjectStream() - this.message = message - this.isReplay = reply - Timber.i("Send message view was initialized") loadData(message, reply) with(view) { @@ -55,7 +47,7 @@ class SendMessagePresenter @Inject constructor( view.showMessageBackupDialog() } reason?.let { - setSubject("Usprawiedliwienie") + setSubject("Usprawiedliwenie") setContent(it) } message?.let { @@ -118,31 +110,16 @@ class SendMessagePresenter @Inject constructor( return false } - fun onOpenMailboxChooser() { - view?.showMailboxChooser(mailboxes) - } - - fun onMailboxSelected(mailbox: Mailbox?) { - selectedMailbox = mailbox - - loadData(message, isReplay) - } - private fun loadData(message: Message?, reply: Boolean?) { resourceFlow { val student = studentRepository.getCurrentStudent() - - if (selectedMailbox == null && mailboxes.isEmpty()) { - selectedMailbox = messageRepository.getMailboxByStudent(student) - mailboxes = messageRepository.getMailboxes(student, false).toFirstResult() - .dataOrNull.orEmpty() - } + val mailbox = mailboxRepository.getMailbox(student) Timber.i("Loading recipients started") val recipients = createChips( recipients = recipientRepository.getRecipients( student = student, - mailbox = selectedMailbox, + mailbox = mailbox, type = MailboxType.EMPLOYEE, ) ) @@ -153,7 +130,7 @@ class SendMessagePresenter @Inject constructor( message != null && reply == true -> recipientRepository.getMessageSender( student = student, message = message, - mailbox = selectedMailbox, + mailbox = mailbox, ) else -> emptyList() }.let { createChips(it) } @@ -162,42 +139,39 @@ class SendMessagePresenter @Inject constructor( messageRecipients.size ) - recipients to messageRecipients + Triple(mailbox, recipients, messageRecipients) } .logResourceStatus("load recipients") - .onResourceLoading { - view?.run { - showProgress(true) - showContent(false) - } - } - .onResourceNotLoading { - view?.run { showProgress(false) } - } - .onResourceError { - view?.showContent(true) - errorHandler.dispatch(it) - } - .onResourceSuccess { - it.let { (recipientChips, selectedRecipientChips) -> - view?.run { - setMailbox(getMailboxName(selectedMailbox)) - setRecipients(recipientChips) - if (selectedRecipientChips.isNotEmpty()) setSelectedRecipients( - selectedRecipientChips - ) - showContent(true) + .onEach { + when (it) { + is Resource.Loading -> view?.run { + showProgress(true) + showContent(false) + } + is Resource.Success -> it.data.let { (mailbox, recipientChips, selectedRecipientChips) -> + view?.run { + setMailbox(getMailboxName(mailbox)) + setRecipients(recipientChips) + if (selectedRecipientChips.isNotEmpty()) setSelectedRecipients( + selectedRecipientChips + ) + showContent(true) + } + } + is Resource.Error -> { + view?.showContent(true) + errorHandler.dispatch(it.error) } } - } - .launch() + }.onResourceNotLoading { + view?.run { showProgress(false) } + }.launch() } private fun sendMessage(subject: String, content: String, recipients: List) { - val mailbox = selectedMailbox ?: return - resourceFlow { val student = studentRepository.getCurrentStudent() + val mailbox = mailboxRepository.getMailbox(student) messageRepository.sendMessage( student = student, subject = subject, @@ -248,21 +222,18 @@ class SendMessagePresenter @Inject constructor( } } - private fun getMailboxName(mailbox: Mailbox?): String { - mailbox ?: return "" - - // username - accountType [\n student name - ] (school short name) + private fun getMailboxName(mailbox: Mailbox): String { return buildString { append(mailbox.userName) append(" - ") append(getMailboxType(mailbox.type)) - appendLine() if (mailbox.type == MailboxType.PARENT) { - append(mailbox.studentName) append(" - ") + append(mailbox.studentName) } + append(" - ") append("(${mailbox.schoolNameShort})") } } @@ -296,9 +267,9 @@ class SendMessagePresenter @Inject constructor( private fun saveDraftMessage() { messageRepository.draftMessage = MessageDraft( - recipients = view?.formRecipientsData!!, - subject = view?.formSubjectValue!!, - content = view?.formContentValue!!, + view?.formRecipientsData!!, + view?.formSubjectValue!!, + view?.formContentValue!! ) } 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 e27a09d60..1057114b8 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 @@ -61,5 +61,4 @@ interface SendMessageView : BaseView { fun getMessageBackupDialogStringWithRecipients(recipients: String): String fun clearDraft() - fun showMailboxChooser(mailboxes: 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 6df6153c5..55f03ef84 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 @@ -1,34 +1,28 @@ package io.github.wulkanowy.ui.modules.message.tab -import android.content.res.ColorStateList import android.graphics.Typeface import android.view.LayoutInflater import android.view.ViewGroup import android.widget.CompoundButton import androidx.core.view.isVisible -import androidx.core.widget.ImageViewCompat import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import io.github.wulkanowy.R import io.github.wulkanowy.databinding.ItemMessageBinding import io.github.wulkanowy.databinding.ItemMessageChipsBinding -import io.github.wulkanowy.utils.getCompatColor -import io.github.wulkanowy.utils.getThemeAttrColor import io.github.wulkanowy.utils.toFormattedString import javax.inject.Inject class MessageTabAdapter @Inject constructor() : RecyclerView.Adapter() { - lateinit var onItemClickListener: (MessageTabDataItem.MessageItem, position: Int) -> Unit + var onItemClickListener: (MessageTabDataItem.MessageItem, position: Int) -> Unit = { _, _ -> } - lateinit var onLongItemClickListener: (MessageTabDataItem.MessageItem) -> Unit + var onLongItemClickListener: (MessageTabDataItem.MessageItem) -> Unit = {} - lateinit var onHeaderClickListener: (CompoundButton, Boolean) -> Unit + var onHeaderClickListener: (CompoundButton, Boolean) -> Unit = { _, _ -> } - lateinit var onMailboxClickListener: () -> Unit - - lateinit var onChangesDetectedListener: () -> Unit + var onChangesDetectedListener = {} private var items = mutableListOf() @@ -52,12 +46,12 @@ class MessageTabAdapter @Inject constructor() : val inflater = LayoutInflater.from(parent.context) return when (MessageItemViewType.values()[viewType]) { - MessageItemViewType.FILTERS -> HeaderViewHolder( - ItemMessageChipsBinding.inflate(inflater, parent, false) - ) MessageItemViewType.MESSAGE -> ItemViewHolder( ItemMessageBinding.inflate(inflater, parent, false) ) + MessageItemViewType.FILTERS -> HeaderViewHolder( + ItemMessageChipsBinding.inflate(inflater, parent, false) + ) } } @@ -72,20 +66,6 @@ class MessageTabAdapter @Inject constructor() : val item = items[position] as MessageTabDataItem.FilterHeader with(holder.binding) { - chipMailbox.text = item.selectedMailbox - ?: root.context.getString(R.string.message_chip_all_mailboxes) - chipMailbox.chipBackgroundColor = ColorStateList.valueOf( - if (item.selectedMailbox == null) { - root.context.getCompatColor(R.color.mtrl_choice_chip_background_color) - } else root.context.getThemeAttrColor(android.R.attr.colorPrimary, 64) - ) - chipMailbox.setTextColor( - if (item.selectedMailbox == null) { - root.context.getThemeAttrColor(android.R.attr.textColorPrimary) - } else root.context.getThemeAttrColor(android.R.attr.colorPrimary) - ) - chipMailbox.setOnClickListener { onMailboxClickListener() } - if (item.onlyUnread == null) { chipUnread.isVisible = false } else { @@ -94,7 +74,6 @@ class MessageTabAdapter @Inject constructor() : chipUnread.setOnCheckedChangeListener(onHeaderClickListener) } chipUnread.isEnabled = item.isEnabled - chipAttachments.isEnabled = item.isEnabled chipAttachments.isChecked = item.onlyWithAttachments chipAttachments.setOnCheckedChangeListener(onHeaderClickListener) @@ -106,35 +85,21 @@ class MessageTabAdapter @Inject constructor() : val message = item.message with(holder.binding) { - val normalFont = Typeface.create("sans-serif", Typeface.NORMAL) - val boldFont = Typeface.create("sans-serif-black", Typeface.NORMAL) - - val primaryColor = root.context.getThemeAttrColor(android.R.attr.textColorPrimary) - val secondaryColor = root.context.getThemeAttrColor(android.R.attr.textColorSecondary) - - val currentFont = if (message.unread) boldFont else normalFont - val currentTextColor = if (message.unread) primaryColor else secondaryColor + val style = if (message.unread) Typeface.BOLD else Typeface.NORMAL with(messageItemAuthor) { text = message.correspondents - setTextColor(currentTextColor) - typeface = currentFont + setTypeface(null, style) } - with(messageItemSubject) { + messageItemSubject.run { text = message.subject.ifBlank { context.getString(R.string.message_no_subject) } - setTextColor(currentTextColor) - typeface = currentFont + setTypeface(null, style) } - with(messageItemDate) { + messageItemDate.run { text = message.date.toFormattedString() - setTextColor(currentTextColor) - typeface = currentFont + setTypeface(null, style) } - with(messageItemAttachmentIcon) { - ImageViewCompat.setImageTintList(this, ColorStateList.valueOf(currentTextColor)) - isVisible = message.hasAttachments - } - messageItemUnreadIndicator.isVisible = message.unread + messageItemAttachmentIcon.isVisible = message.hasAttachments root.setOnClickListener { holder.bindingAdapterPosition.let { @@ -146,7 +111,7 @@ class MessageTabAdapter @Inject constructor() : root.setOnLongClickListener { onLongItemClickListener(item) - true + return@setOnLongClickListener true } with(messageItemCheckbox) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabDataItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabDataItem.kt index c0bd4170e..634dfc0e7 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabDataItem.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabDataItem.kt @@ -11,7 +11,6 @@ sealed class MessageTabDataItem(val viewType: MessageItemViewType) { ) : MessageTabDataItem(MessageItemViewType.MESSAGE) data class FilterHeader( - val selectedMailbox: String?, val onlyUnread: Boolean?, val onlyWithAttachments: Boolean, val isEnabled: Boolean diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt index c78ccc6ec..654b0e226 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt @@ -9,26 +9,21 @@ import android.view.View.* import android.widget.CompoundButton import androidx.appcompat.view.ActionMode import androidx.appcompat.widget.SearchView -import androidx.core.os.bundleOf import androidx.core.view.updatePadding -import androidx.fragment.app.setFragmentResultListener import androidx.recyclerview.widget.LinearLayoutManager import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R -import io.github.wulkanowy.data.db.entities.Mailbox import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.enums.MessageFolder import io.github.wulkanowy.databinding.FragmentMessageTabBinding import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.message.MessageFragment -import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog import io.github.wulkanowy.ui.modules.message.preview.MessagePreviewFragment import io.github.wulkanowy.ui.widgets.DividerItemDecoration import io.github.wulkanowy.utils.dpToPx import io.github.wulkanowy.utils.getThemeAttrColor import io.github.wulkanowy.utils.hideSoftInput -import io.github.wulkanowy.utils.nullableSerializable import javax.inject.Inject @AndroidEntryPoint @@ -45,8 +40,12 @@ class MessageTabFragment : BaseFragment(R.layout.frag const val MESSAGE_TAB_FOLDER_ID = "message_tab_folder_id" - fun newInstance(folder: MessageFolder) = MessageTabFragment().apply { - arguments = bundleOf(MESSAGE_TAB_FOLDER_ID to folder.name) + fun newInstance(folder: MessageFolder): MessageTabFragment { + return MessageTabFragment().apply { + arguments = Bundle().apply { + putString(MESSAGE_TAB_FOLDER_ID, folder.name) + } + } } } @@ -84,7 +83,6 @@ class MessageTabFragment : BaseFragment(R.layout.frag } } - @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) @@ -106,7 +104,6 @@ class MessageTabFragment : BaseFragment(R.layout.frag onItemClickListener = presenter::onMessageItemSelected onLongItemClickListener = presenter::onMessageItemLongSelected onHeaderClickListener = ::onChipChecked - onMailboxClickListener = presenter::onMailboxFilterSelected onChangesDetectedListener = ::resetListPosition } @@ -126,15 +123,8 @@ class MessageTabFragment : BaseFragment(R.layout.frag messageTabErrorRetry.setOnClickListener { presenter.onRetry() } messageTabErrorDetails.setOnClickListener { presenter.onDetailsClick() } } - - setFragmentResultListener(requireArguments().getString(MESSAGE_TAB_FOLDER_ID)!!) { _, bundle -> - presenter.onMailboxSelected( - mailbox = bundle.nullableSerializable(MailboxChooserDialog.MAILBOX_KEY), - ) - } } - @Suppress("DEPRECATION") override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { super.onCreateOptionsMenu(menu, inflater) inflater.inflate(R.menu.action_menu_message_tab, menu) @@ -256,16 +246,6 @@ class MessageTabFragment : BaseFragment(R.layout.frag ) } - override fun showMailboxChooser(mailboxes: List) { - (activity as? MainActivity)?.showDialogFragment( - MailboxChooserDialog.newInstance( - mailboxes = mailboxes, - isMailboxRequired = false, - folder = requireArguments().getString(MESSAGE_TAB_FOLDER_ID)!!, - ) - ) - } - override fun hideKeyboard() { activity?.hideSoftInput() } 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 ea142db2b..54711a689 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 @@ -1,9 +1,9 @@ package io.github.wulkanowy.ui.modules.message.tab import io.github.wulkanowy.data.* -import io.github.wulkanowy.data.db.entities.Mailbox 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.StudentRepository import io.github.wulkanowy.ui.base.BasePresenter @@ -26,6 +26,7 @@ class MessageTabPresenter @Inject constructor( errorHandler: ErrorHandler, studentRepository: StudentRepository, private val messageRepository: MessageRepository, + private val mailboxRepository: MailboxRepository, private val analytics: AnalyticsHelper ) : BasePresenter(errorHandler, studentRepository) { @@ -35,9 +36,6 @@ class MessageTabPresenter @Inject constructor( private var lastSearchQuery = "" - private var mailboxes: List = emptyList() - private var selectedMailbox: Mailbox? = null - private var messages = emptyList() private val searchChannel = Channel() @@ -124,7 +122,8 @@ class MessageTabPresenter @Inject constructor( runCatching { val student = studentRepository.getCurrentStudent(true) - messageRepository.deleteMessages(student, selectedMailbox, messageList) + val mailbox = mailboxRepository.getMailbox(student) + messageRepository.deleteMessages(student, mailbox, messageList) } .onFailure(errorHandler::dispatch) .onSuccess { view?.showMessagesDeleted() } @@ -203,28 +202,13 @@ class MessageTabPresenter @Inject constructor( } } - fun onMailboxFilterSelected() { - view?.showMailboxChooser(mailboxes) - } - - fun onMailboxSelected(mailbox: Mailbox?) { - selectedMailbox = mailbox - loadData(false) - } - private fun loadData(forceRefresh: Boolean) { Timber.i("Loading $folder message data started") flatResourceFlow { val student = studentRepository.getCurrentStudent() - - if (selectedMailbox == null && mailboxes.isEmpty()) { - selectedMailbox = messageRepository.getMailboxByStudent(student) - mailboxes = messageRepository.getMailboxes(student, forceRefresh).toFirstResult() - .dataOrNull.orEmpty() - } - - messageRepository.getMessages(student, selectedMailbox, folder, forceRefresh) + val mailbox = mailboxRepository.getMailbox(student) + messageRepository.getMessages(student, mailbox, folder, forceRefresh) } .logResourceStatus("load $folder message") .onResourceData { @@ -343,16 +327,7 @@ class MessageTabPresenter @Inject constructor( MessageTabDataItem.FilterHeader( onlyUnread = onlyUnread.takeIf { folder != MessageFolder.SENT }, onlyWithAttachments = onlyWithAttachments, - isEnabled = !isActionMode, - selectedMailbox = selectedMailbox?.let { - buildString { - if (it.studentName.isNotBlank() && it.studentName != it.userName) { - append(it.studentName) - append(" - ") - } - append(it.userName) - } - }, + isEnabled = !isActionMode ) ) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabView.kt index 6ece6621b..bfa43b209 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabView.kt @@ -1,6 +1,5 @@ package io.github.wulkanowy.ui.modules.message.tab -import io.github.wulkanowy.data.db.entities.Mailbox import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.ui.base.BaseView @@ -47,6 +46,4 @@ interface MessageTabView : BaseView { fun showActionMode(show: Boolean) fun showRecyclerBottomPadding(show: Boolean) - - fun showMailboxChooser(mailboxes: List) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteDialog.kt index e46ab42cc..5811456b6 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteDialog.kt @@ -6,7 +6,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat -import androidx.core.os.bundleOf import androidx.fragment.app.DialogFragment import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Note @@ -14,7 +13,6 @@ import io.github.wulkanowy.databinding.DialogNoteBinding import io.github.wulkanowy.sdk.scrapper.notes.NoteCategory import io.github.wulkanowy.utils.getThemeAttrColor import io.github.wulkanowy.utils.lifecycleAwareVariable -import io.github.wulkanowy.utils.serializable import io.github.wulkanowy.utils.toFormattedString class NoteDialog : DialogFragment() { @@ -27,15 +25,17 @@ class NoteDialog : DialogFragment() { private const val ARGUMENT_KEY = "Item" - fun newInstance(note: Note) = NoteDialog().apply { - arguments = bundleOf(ARGUMENT_KEY to note) + fun newInstance(exam: Note) = NoteDialog().apply { + arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setStyle(STYLE_NO_TITLE, 0) - note = requireArguments().serializable(ARGUMENT_KEY) + arguments?.run { + note = getSerializable(ARGUMENT_KEY) as Note + } } override fun onCreateView( diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/notifications/NotificationsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/notifications/NotificationsFragment.kt deleted file mode 100644 index 163ba8cdf..000000000 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/notifications/NotificationsFragment.kt +++ /dev/null @@ -1,64 +0,0 @@ -package io.github.wulkanowy.ui.modules.notifications - -import android.os.Bundle -import android.view.View -import androidx.activity.result.contract.ActivityResultContracts.RequestPermission -import androidx.appcompat.app.AlertDialog -import dagger.hilt.android.AndroidEntryPoint -import io.github.wulkanowy.R -import io.github.wulkanowy.databinding.FragmentNotificationsBinding -import io.github.wulkanowy.ui.base.BaseFragment -import io.github.wulkanowy.ui.modules.login.LoginActivity -import io.github.wulkanowy.utils.openNotificationSettings - -@AndroidEntryPoint -class NotificationsFragment : - BaseFragment(R.layout.fragment_notifications) { - - private val permission = "android.permission.POST_NOTIFICATIONS" - - private val requestPermissionLauncher = registerForActivityResult(RequestPermission()) { - if (it) { - navigateToFinish() - } else showSettingsDialog() - } - - companion object { - fun newInstance() = NotificationsFragment() - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - binding = FragmentNotificationsBinding.bind(view) - initView() - } - - private fun initView() { - with(binding) { - notificationsSkip.setOnClickListener { navigateToFinish() } - notificationsEnable.setOnClickListener { requestPermission() } - } - } - - private fun showSettingsDialog() { - AlertDialog.Builder(requireContext()) - .setTitle(R.string.notifications_header_title) - .setMessage(R.string.notifications_header_description) - .setNegativeButton(R.string.notifications_skip) { dialog, _ -> - dialog.dismiss() - navigateToFinish() - } - .setPositiveButton(R.string.pref_notification_go_to_settings) { _, _ -> - requireActivity().openNotificationSettings() - } - .show() - } - - private fun requestPermission() { - requestPermissionLauncher.launch(permission) - } - - private fun navigateToFinish() { - (requireActivity() as LoginActivity).navigateToFinish() - } -} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolannouncement/SchoolAnnouncementAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolannouncement/SchoolAnnouncementAdapter.kt index 46999599b..62f6251ec 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolannouncement/SchoolAnnouncementAdapter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolannouncement/SchoolAnnouncementAdapter.kt @@ -2,10 +2,10 @@ package io.github.wulkanowy.ui.modules.schoolannouncement import android.view.LayoutInflater import android.view.ViewGroup +import androidx.core.text.parseAsHtml import androidx.recyclerview.widget.RecyclerView import io.github.wulkanowy.data.db.entities.SchoolAnnouncement import io.github.wulkanowy.databinding.ItemSchoolAnnouncementBinding -import io.github.wulkanowy.utils.parseUonetHtml import io.github.wulkanowy.utils.toFormattedString import javax.inject.Inject @@ -28,7 +28,7 @@ class SchoolAnnouncementAdapter @Inject constructor() : with(holder.binding) { schoolAnnouncementItemDate.text = item.date.toFormattedString() schoolAnnouncementItemType.text = item.subject - schoolAnnouncementItemContent.text = item.content.parseUonetHtml() + schoolAnnouncementItemContent.text = item.content.parseAsHtml() root.setOnClickListener { onItemClickListener(item) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolannouncement/SchoolAnnouncementDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolannouncement/SchoolAnnouncementDialog.kt index e33a48f03..7dcd51cea 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolannouncement/SchoolAnnouncementDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolannouncement/SchoolAnnouncementDialog.kt @@ -4,13 +4,11 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.os.bundleOf +import androidx.core.text.parseAsHtml import androidx.fragment.app.DialogFragment import io.github.wulkanowy.data.db.entities.SchoolAnnouncement import io.github.wulkanowy.databinding.DialogSchoolAnnouncementBinding import io.github.wulkanowy.utils.lifecycleAwareVariable -import io.github.wulkanowy.utils.parseUonetHtml -import io.github.wulkanowy.utils.serializable import io.github.wulkanowy.utils.toFormattedString class SchoolAnnouncementDialog : DialogFragment() { @@ -23,15 +21,17 @@ class SchoolAnnouncementDialog : DialogFragment() { private const val ARGUMENT_KEY = "item" - fun newInstance(announcement: SchoolAnnouncement) = SchoolAnnouncementDialog().apply { - arguments = bundleOf(ARGUMENT_KEY to announcement) + fun newInstance(exam: SchoolAnnouncement) = SchoolAnnouncementDialog().apply { + arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setStyle(STYLE_NO_TITLE, 0) - announcement = requireArguments().serializable(ARGUMENT_KEY) + arguments?.run { + announcement = getSerializable(ARGUMENT_KEY) as SchoolAnnouncement + } } override fun onCreateView( @@ -46,7 +46,7 @@ class SchoolAnnouncementDialog : DialogFragment() { with(binding) { announcementDialogSubjectValue.text = announcement.subject announcementDialogDateValue.text = announcement.date.toFormattedString() - announcementDialogDescriptionValue.text = announcement.content.parseUonetHtml() + announcementDialogDescriptionValue.text = announcement.content.parseAsHtml() announcementDialogClose.setOnClickListener { dismiss() } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsFragment.kt index 77a3c6cf4..364ad2137 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsFragment.kt @@ -1,16 +1,18 @@ package io.github.wulkanowy.ui.modules.settings.notifications +import android.annotation.SuppressLint import android.content.Intent import android.content.SharedPreferences -import android.content.pm.PackageManager +import android.net.Uri +import android.os.Build import android.os.Bundle +import android.provider.Settings import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AlertDialog import androidx.core.app.NotificationManagerCompat -import androidx.core.content.ContextCompat import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreferenceCompat @@ -24,7 +26,7 @@ import io.github.wulkanowy.ui.base.ErrorDialog import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.openInternetBrowser -import io.github.wulkanowy.utils.openNotificationSettings +import timber.log.Timber import javax.inject.Inject @AndroidEntryPoint @@ -40,14 +42,7 @@ class NotificationsFragment : PreferenceFragmentCompat(), override val titleStringId get() = R.string.pref_settings_notifications_title - private val notificationsPermission = "android.permission.POST_NOTIFICATIONS" - override val isNotificationPermissionGranted: Boolean - get() = ContextCompat.checkSelfPermission( - requireContext(), notificationsPermission - ) == PackageManager.PERMISSION_GRANTED - - override val isNotificationPiggybackPermissionGranted: Boolean get() { val packageNameList = NotificationManagerCompat.getEnabledListenerPackages(requireContext()) @@ -56,13 +51,6 @@ class NotificationsFragment : PreferenceFragmentCompat(), return appPackageName in packageNameList } - private val requestPermissionLauncher = - registerForActivityResult(ActivityResultContracts.RequestPermission()) { - if (it) { - presenter.onNotificationsPermissionResult() - } else openNotificationsPermissionDialog() - } - private val notificationSettingsPiggybackContract = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { presenter.onNotificationPiggybackPermissionResult() @@ -168,29 +156,25 @@ class NotificationsFragment : PreferenceFragmentCompat(), .show() } + @SuppressLint("InlinedApi") override fun openSystemSettings() { - requireActivity().openNotificationSettings() - } - - override fun requestNotificationPermissions() { - requestPermissionLauncher.launch(notificationsPermission) - } - - override fun openNotificationsPermissionDialog() { - AlertDialog.Builder(requireContext()) - .setTitle(R.string.notifications_header_title) - .setMessage(R.string.notifications_header_description) - .setPositiveButton(R.string.pref_notification_go_to_settings) { _, _ -> - requireActivity().openNotificationSettings() + val intent = if (appInfo.systemVersion >= Build.VERSION_CODES.O) { + Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { + putExtra("android.provider.extra.APP_PACKAGE", requireActivity().packageName) } - .setNegativeButton(android.R.string.cancel) { _, _ -> - setNotificationPreferencesChecked(false) + } else { + Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { + data = Uri.fromParts("package", requireActivity().packageName, null) } - .setOnDismissListener { setNotificationPreferencesChecked(false) } - .show() + } + try { + requireActivity().startActivity(intent) + } catch (e: Exception) { + Timber.e(e) + } } - override fun openNotificationPiggyBackPermissionDialog() { + override fun openNotificationPermissionDialog() { AlertDialog.Builder(requireContext()) .setTitle(getString(R.string.pref_notification_piggyback_popup_title)) .setMessage(getString(R.string.pref_notification_piggyback_popup_description)) @@ -218,11 +202,6 @@ class NotificationsFragment : PreferenceFragmentCompat(), .show() } - override fun setNotificationPreferencesChecked(isChecked: Boolean) { - findPreference(getString(R.string.pref_key_notifications_enable))?.isChecked = - isChecked - } - override fun setNotificationPiggybackPreferenceChecked(isChecked: Boolean) { findPreference(getString(R.string.pref_key_notifications_piggyback))?.isChecked = isChecked diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsPresenter.kt index 232b03480..4cbdac945 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsPresenter.kt @@ -26,13 +26,12 @@ class NotificationsPresenter @Inject constructor( with(view) { enableNotification( - notificationKey = preferencesRepository.notificationsEnableKey, - enable = preferencesRepository.isServiceEnabled + preferencesRepository.notificationsEnableKey, + preferencesRepository.isServiceEnabled ) initView(appInfo.isDebug) } - checkNotificationsPermissionState() checkNotificationPiggybackState() Timber.i("Settings notifications view was initialized") @@ -50,17 +49,12 @@ class NotificationsPresenter @Inject constructor( view?.openNotificationExactAlarmSettings() } } - notificationsEnableKey -> { - if (isNotificationsEnable && view?.isNotificationPermissionGranted == false) { - view?.requestNotificationPermissions() - } - } isDebugNotificationEnableKey -> { chuckerCollector.showNotification = isDebugNotificationEnable } isNotificationPiggybackEnabledKey -> { - if (isNotificationPiggybackEnabled && view?.isNotificationPiggybackPermissionGranted == false) { - view?.openNotificationPiggyBackPermissionDialog() + if (isNotificationPiggybackEnabled && view?.isNotificationPermissionGranted == false) { + view?.openNotificationPermissionDialog() } } } @@ -76,15 +70,9 @@ class NotificationsPresenter @Inject constructor( view?.openSystemSettings() } - fun onNotificationsPermissionResult() { - view?.run { - setNotificationPreferencesChecked(isNotificationPermissionGranted) - } - } - fun onNotificationPiggybackPermissionResult() { view?.run { - setNotificationPiggybackPreferenceChecked(isNotificationPiggybackPermissionGranted) + setNotificationPiggybackPreferenceChecked(isNotificationPermissionGranted) } } @@ -92,18 +80,10 @@ class NotificationsPresenter @Inject constructor( view?.setUpcomingLessonsNotificationPreferenceChecked(timetableNotificationHelper.canScheduleExactAlarms()) } - private fun checkNotificationsPermissionState() { - if (preferencesRepository.isNotificationsEnable) { - view?.run { - setNotificationPreferencesChecked(isNotificationPermissionGranted) - } - } - } - private fun checkNotificationPiggybackState() { if (preferencesRepository.isNotificationPiggybackEnabled) { view?.run { - setNotificationPiggybackPreferenceChecked(isNotificationPiggybackPermissionGranted) + setNotificationPiggybackPreferenceChecked(isNotificationPermissionGranted) } } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsView.kt index a391681cb..2bf8e31f4 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsView.kt @@ -6,8 +6,6 @@ interface NotificationsView : BaseView { val isNotificationPermissionGranted: Boolean - val isNotificationPiggybackPermissionGranted: Boolean - fun initView(showDebugNotificationSwitch: Boolean) fun showFixSyncDialog() @@ -16,16 +14,10 @@ interface NotificationsView : BaseView { fun enableNotification(notificationKey: String, enable: Boolean) - fun requestNotificationPermissions() - - fun openNotificationsPermissionDialog() - - fun openNotificationPiggyBackPermissionDialog() + fun openNotificationPermissionDialog() fun openNotificationExactAlarmSettings() - fun setNotificationPreferencesChecked(isChecked: Boolean) - fun setNotificationPiggybackPreferenceChecked(isChecked: Boolean) fun setUpcomingLessonsNotificationPreferenceChecked(isChecked: Boolean) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt index 598046a2d..361a59440 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/studentinfo/StudentInfoFragment.kt @@ -8,7 +8,6 @@ import android.view.MenuInflater import android.view.View import android.widget.Toast import androidx.core.content.getSystemService -import androidx.core.os.bundleOf import androidx.core.view.get import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager @@ -25,8 +24,6 @@ import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.capitalise import io.github.wulkanowy.utils.getThemeAttrColor -import io.github.wulkanowy.utils.nullableSerializable -import io.github.wulkanowy.utils.serializable import javax.inject.Inject @AndroidEntryPoint @@ -41,9 +38,7 @@ class StudentInfoFragment : lateinit var studentInfoAdapter: StudentInfoAdapter override val titleStringId: Int - get() = when ( - requireArguments().nullableSerializable(INFO_TYPE_ARGUMENT_KEY) - ) { + get() = when (requireArguments().getSerializable(INFO_TYPE_ARGUMENT_KEY) as? StudentInfoView.Type) { StudentInfoView.Type.PERSONAL -> R.string.account_personal_data StudentInfoView.Type.CONTACT -> R.string.account_contact StudentInfoView.Type.ADDRESS -> R.string.account_address @@ -63,14 +58,13 @@ class StudentInfoFragment : fun newInstance(type: StudentInfoView.Type, studentWithSemesters: StudentWithSemesters) = StudentInfoFragment().apply { - arguments = bundleOf( - INFO_TYPE_ARGUMENT_KEY to type, - STUDENT_ARGUMENT_KEY to studentWithSemesters - ) + arguments = Bundle().apply { + putSerializable(INFO_TYPE_ARGUMENT_KEY, type) + putSerializable(STUDENT_ARGUMENT_KEY, studentWithSemesters) + } } } - @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) @@ -80,9 +74,9 @@ class StudentInfoFragment : super.onViewCreated(view, savedInstanceState) binding = FragmentStudentInfoBinding.bind(view) presenter.onAttachView( - view = this, - type = requireArguments().serializable(INFO_TYPE_ARGUMENT_KEY), - studentWithSemesters = requireArguments().serializable(STUDENT_ARGUMENT_KEY), + this, + requireArguments().getSerializable(INFO_TYPE_ARGUMENT_KEY) as StudentInfoView.Type, + requireArguments().getSerializable(STUDENT_ARGUMENT_KEY) as StudentWithSemesters ) } @@ -159,6 +153,7 @@ class StudentInfoFragment : ) } + @OptIn(ExperimentalStdlibApi::class) override fun showFamilyTypeData(studentInfo: StudentInfo) { val items = buildList { add(studentInfo.firstGuardian?.let { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableAdapter.kt index 2f0d697fc..d6917672a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableAdapter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableAdapter.kt @@ -191,7 +191,7 @@ class TimetableAdapter @Inject constructor() : ) } else { timetableItemDescription.visibility = GONE - timetableItemRoom.isVisible = lesson.room.isNotBlank() || lesson.roomOld.isNotBlank() + timetableItemRoom.visibility = VISIBLE timetableItemGroup.isVisible = item.showGroupsInPlan && lesson.group.isNotBlank() timetableItemTeacher.visibility = VISIBLE } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableDialog.kt index 4f5547d20..c9243b12e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableDialog.kt @@ -8,12 +8,14 @@ import android.view.View import android.view.View.GONE import android.view.View.VISIBLE import android.view.ViewGroup -import androidx.core.os.bundleOf import androidx.fragment.app.DialogFragment import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.databinding.DialogTimetableBinding -import io.github.wulkanowy.utils.* +import io.github.wulkanowy.utils.capitalise +import io.github.wulkanowy.utils.getThemeAttrColor +import io.github.wulkanowy.utils.lifecycleAwareVariable +import io.github.wulkanowy.utils.toFormattedString import java.time.Instant class TimetableDialog : DialogFragment() { @@ -26,15 +28,17 @@ class TimetableDialog : DialogFragment() { private const val ARGUMENT_KEY = "Item" - fun newInstance(lesson: Timetable) = TimetableDialog().apply { - arguments = bundleOf(ARGUMENT_KEY to lesson) + fun newInstance(exam: Timetable) = TimetableDialog().apply { + arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setStyle(STYLE_NO_TITLE, 0) - lesson = requireArguments().serializable(ARGUMENT_KEY) + arguments?.run { + lesson = getSerializable(ARGUMENT_KEY) as Timetable + } } override fun onCreateView( diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt index e95d6f827..fdd4aface 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt @@ -7,7 +7,6 @@ import android.view.MenuItem import android.view.View import android.view.View.GONE import android.view.View.VISIBLE -import androidx.core.os.bundleOf import androidx.core.text.parseAsHtml import androidx.recyclerview.widget.LinearLayoutManager import dagger.hilt.android.AndroidEntryPoint @@ -40,7 +39,9 @@ class TimetableFragment : BaseFragment(R.layout.fragme private const val ARGUMENT_DATE_KEY = "ARGUMENT_DATE" fun newInstance(date: LocalDate? = null) = TimetableFragment().apply { - arguments = date?.let { bundleOf(ARGUMENT_DATE_KEY to it.toEpochDay()) } + arguments = Bundle().apply { + date?.let { putLong(ARGUMENT_DATE_KEY, it.toEpochDay()) } + } } } @@ -50,7 +51,6 @@ class TimetableFragment : BaseFragment(R.layout.fragme override val currentStackSize get() = (activity as? MainActivity)?.currentStackSize - @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonDialog.kt index ddd7488e4..7d32278f0 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonDialog.kt @@ -4,12 +4,10 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.os.bundleOf import androidx.fragment.app.DialogFragment import io.github.wulkanowy.data.db.entities.CompletedLesson import io.github.wulkanowy.databinding.DialogLessonCompletedBinding import io.github.wulkanowy.utils.lifecycleAwareVariable -import io.github.wulkanowy.utils.serializable class CompletedLessonDialog : DialogFragment() { @@ -21,15 +19,17 @@ class CompletedLessonDialog : DialogFragment() { private const val ARGUMENT_KEY = "Item" - fun newInstance(lesson: CompletedLesson) = CompletedLessonDialog().apply { - arguments = bundleOf(ARGUMENT_KEY to lesson) + fun newInstance(exam: CompletedLesson) = CompletedLessonDialog().apply { + arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setStyle(STYLE_NO_TITLE, 0) - completedLesson = requireArguments().serializable(ARGUMENT_KEY) + arguments?.run { + completedLesson = getSerializable(ARGUMENT_KEY) as CompletedLesson + } } override fun onCreateView( diff --git a/app/src/main/java/io/github/wulkanowy/utils/BundleExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/BundleExtension.kt deleted file mode 100644 index d0d47025e..000000000 --- a/app/src/main/java/io/github/wulkanowy/utils/BundleExtension.kt +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.wulkanowy.utils - -import android.content.Intent -import android.os.Build -import android.os.Bundle -import java.io.Serializable - -inline fun Bundle.serializable(key: String): T = when { - Build.VERSION.SDK_INT >= 33 -> getSerializable(key, T::class.java)!! - else -> @Suppress("DEPRECATION") getSerializable(key) as T -} - -inline fun Bundle.nullableSerializable(key: String): T? = when { - Build.VERSION.SDK_INT >= 33 -> getSerializable(key, T::class.java) - else -> @Suppress("DEPRECATION") getSerializable(key) as T? -} - -@Suppress("DEPRECATION", "UNCHECKED_CAST") -inline fun Bundle.parcelableArray(key: String): Array? = when { - Build.VERSION.SDK_INT >= 33 -> getParcelableArray(key, T::class.java) - else -> getParcelableArray(key) as Array? -} - -inline fun Intent.serializable(key: String): T = when { - Build.VERSION.SDK_INT >= 33 -> getSerializableExtra(key, T::class.java)!! - else -> @Suppress("DEPRECATION") getSerializableExtra(key) as T -} - -inline fun Intent.nullableSerializable(key: String): T? = when { - Build.VERSION.SDK_INT >= 33 -> getSerializableExtra(key, T::class.java) - else -> @Suppress("DEPRECATION") getSerializableExtra(key) as T? -} diff --git a/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt index cc4c5aaa4..dd91d36d4 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt @@ -2,11 +2,9 @@ package io.github.wulkanowy.utils import android.annotation.SuppressLint import android.content.Context -import android.content.res.ColorStateList import android.graphics.* import android.text.TextPaint import android.util.DisplayMetrics.DENSITY_DEFAULT -import android.widget.ImageView import androidx.annotation.* import androidx.core.content.ContextCompat import androidx.core.graphics.ColorUtils @@ -14,7 +12,6 @@ import androidx.core.graphics.applyCanvas import androidx.core.graphics.drawable.RoundedBitmapDrawable import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory import androidx.core.graphics.drawable.toBitmap -import androidx.core.widget.ImageViewCompat @ColorInt @@ -88,7 +85,3 @@ fun Context.createNameInitialsDrawable( return RoundedBitmapDrawableFactory.create(this.resources, bitmap) .apply { isCircular = true } } - -fun ImageView.setTint(@ColorInt color: Int) { - ImageViewCompat.setImageTintList(this, ColorStateList.valueOf(color)) -} diff --git a/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt index a4c2537ac..43cecd400 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt @@ -15,17 +15,16 @@ import java.net.ConnectException import java.net.SocketException import java.net.SocketTimeoutException import java.net.UnknownHostException -import java.security.cert.CertPathValidatorException import java.security.cert.CertificateExpiredException import java.security.cert.CertificateNotYetValidException import javax.net.ssl.SSLHandshakeException fun Resources.getErrorString(error: Throwable): String = when (error) { is UnknownHostException -> R.string.error_no_internet - is ConnectException, is SocketException, is SocketTimeoutException, is InterruptedIOException, + is ConnectException, is StreamResetException -> R.string.error_timeout is NotLoggedInException -> R.string.error_login_failed is PasswordChangeRequiredException -> R.string.error_password_change_required @@ -43,10 +42,10 @@ fun Resources.getErrorString(error: Throwable): String = when (error) { fun Throwable.isShouldBeReported(): Boolean = when (this) { is UnknownHostException, - is ConnectException, is SocketException, is SocketTimeoutException, is InterruptedIOException, + is ConnectException, is StreamResetException, is ServiceUnavailableException, is FeatureDisabledException, @@ -71,6 +70,5 @@ private fun Throwable?.isCausedByCertificateNotValidNow(): Boolean { private fun Throwable?.isCertificateNotValidNow(): Boolean { val isNotYetValid = this is CertificateNotYetValidException val isExpired = this is CertificateExpiredException - val isInvalidPath = this is CertPathValidatorException - return isNotYetValid || isExpired || isInvalidPath + return isNotYetValid || isExpired } diff --git a/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt index 61924d4e9..ff65d6376 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt @@ -4,7 +4,6 @@ import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Grade import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.enums.GradeColorTheme -import io.github.wulkanowy.sdk.scrapper.grades.getGradeValueWithModifier import io.github.wulkanowy.sdk.scrapper.grades.isGradeValid fun List.calcAverage(isOptionalArithmeticAverage: Boolean): Double { @@ -21,15 +20,20 @@ fun List.calcAverage(isOptionalArithmeticAverage: Boolean): Double { } fun List.calcFinalAverage(plusModifier: Double, minusModifier: Double) = asSequence() - .mapNotNull { summary -> - val (gradeValue, gradeModifier) = getGradeValueWithModifier(summary.finalGrade) - if (gradeValue == null || gradeModifier == null) return@mapNotNull null - - when { - gradeModifier > 0 -> gradeValue + plusModifier - gradeModifier < 0 -> gradeValue - minusModifier - else -> gradeValue + 0.0 - } + .mapNotNull { + if (it.finalGrade.matches("[0-6][+-]?".toRegex())) { + when { + it.finalGrade.endsWith('+') -> { + it.finalGrade.removeSuffix("+").toDouble() + plusModifier + } + it.finalGrade.endsWith('-') -> { + it.finalGrade.removeSuffix("-").toDouble() - minusModifier + } + else -> { + it.finalGrade.toDouble() + } + } + } else null } .average() .let { if (it.isNaN()) 0.0 else it } diff --git a/app/src/main/java/io/github/wulkanowy/utils/IntentUtils.kt b/app/src/main/java/io/github/wulkanowy/utils/IntentUtils.kt index 62b85af4d..1ef03f2e6 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/IntentUtils.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/IntentUtils.kt @@ -1,15 +1,11 @@ package io.github.wulkanowy.utils -import android.app.Activity import android.content.ActivityNotFoundException import android.content.Context import android.content.Intent import android.net.Uri -import android.os.Build import android.provider.CalendarContract -import android.provider.Settings import io.github.wulkanowy.BuildConfig -import timber.log.Timber import java.time.LocalDateTime import java.time.ZoneId @@ -90,23 +86,6 @@ fun Context.openDialer(phone: String) { } } -fun Activity.openNotificationSettings() { - val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { - putExtra("android.provider.extra.APP_PACKAGE", packageName) - } - } else { - Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { - data = Uri.fromParts("package", packageName, null) - } - } - try { - startActivity(intent) - } catch (e: Exception) { - Timber.e(e) - } -} - fun Context.shareText(text: String, subject: String?) { val sendIntent: Intent = Intent().apply { action = Intent.ACTION_SEND diff --git a/app/src/main/java/io/github/wulkanowy/utils/RefreshUtils.kt b/app/src/main/java/io/github/wulkanowy/utils/RefreshUtils.kt index 93e67be01..c69fec65c 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/RefreshUtils.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/RefreshUtils.kt @@ -4,7 +4,6 @@ import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import io.github.wulkanowy.R import io.github.wulkanowy.data.db.SharedPrefProvider -import io.github.wulkanowy.data.db.entities.Mailbox import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.enums.MessageFolder @@ -26,8 +25,8 @@ fun getRefreshKey(name: String, student: Student): String { return "${name}_${student.userLoginId}" } -fun getRefreshKey(name: String, mailbox: Mailbox?, folder: MessageFolder): String { - return "${name}_${mailbox?.globalKey ?: "all"}_${folder.id}" +fun getRefreshKey(name: String, student: Student, folder: MessageFolder): String { + return "${name}_${student.id}_${folder.id}" } class AutoRefreshHelper @Inject constructor( diff --git a/app/src/main/java/io/github/wulkanowy/utils/SemesterExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/SemesterExtension.kt index 380d6bf6e..6e11a8b2c 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/SemesterExtension.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/SemesterExtension.kt @@ -15,8 +15,5 @@ fun List.getCurrentOrLast(): Semester { // when there is more than one current semester - find one with higher id singleOrNull { semester -> semester.semesterId == maxByOrNull { it.semesterId }?.semesterId }?.let { return it } - // when there is no active kindergarten semester - get one from last year - singleOrNull { semester -> semester.schoolYear == maxByOrNull { it.schoolYear }?.schoolYear }?.let { return it } - throw IllegalArgumentException("Duplicated last semester! Semesters: ${joinToString(separator = "\n")}") } diff --git a/app/src/main/java/io/github/wulkanowy/utils/StringExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/StringExtension.kt index 8043e3659..bddd7df4c 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/StringExtension.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/StringExtension.kt @@ -1,15 +1,7 @@ package io.github.wulkanowy.utils -import androidx.core.text.parseAsHtml -import org.apache.commons.text.StringEscapeUtils - inline fun String?.ifNullOrBlank(defaultValue: () -> String) = if (isNullOrBlank()) defaultValue() else this fun String.capitalise() = - replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() } - -fun String.parseUonetHtml() = this - .let(StringEscapeUtils::unescapeHtml4) - .replace("\n", "
") - .parseAsHtml() + replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() } \ No newline at end of file diff --git a/app/src/main/play/release-notes/pl-PL/default.txt b/app/src/main/play/release-notes/pl-PL/default.txt index 9e24f9d9e..4b6dcaf28 100644 --- a/app/src/main/play/release-notes/pl-PL/default.txt +++ b/app/src/main/play/release-notes/pl-PL/default.txt @@ -1,10 +1,9 @@ -Wersja 1.9.0 +Wersja 1.7.1 -- dodaliśmy obsługę Androida 13 (w tym ikona aplikacji obsługująca Material You) -- przerobiliśmy ekran wyboru ucznia przy pierwszym logowaniu -- naprawiliśmy usuwanie wiadomości w niektórych przypadkach -- naprawiliśmy błąd występujący przy resecie hasła -- naprawiliśmy literówkę w tytule domyślnej treści wiadomości usprawiedliwiania -- naprawiliśmy nazwę aplikacji przy ustawionym w telefonie jezyku francuskim +- naprawiliśmy logowanie do aplikacji +- dodaliśmy wsparcie nowego modułu Wiadomości Plus +- dodaliśmy nową możliwość wsparcia naszego projektu przez opcjonalne reklamy +- dodaliśmy sortowanie po średniej +- naprawiliśmy też kilka usterek wpływających na komfort używania aplikacji Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases diff --git a/app/src/main/res/drawable/ic_circle.xml b/app/src/main/res/drawable/ic_circle.xml deleted file mode 100644 index d2932fe62..000000000 --- a/app/src/main/res/drawable/ic_circle.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/drawable/ic_error_filled.xml b/app/src/main/res/drawable/ic_error_filled.xml deleted file mode 100644 index 61b575dc6..000000000 --- a/app/src/main/res/drawable/ic_error_filled.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_launcher_foreground_dev_mono.xml b/app/src/main/res/drawable/ic_launcher_foreground_dev_mono.xml deleted file mode 100644 index b1b01a0b6..000000000 --- a/app/src/main/res/drawable/ic_launcher_foreground_dev_mono.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/drawable/ic_launcher_foreground_mono.xml b/app/src/main/res/drawable/ic_launcher_foreground_mono.xml deleted file mode 100644 index e2e747316..000000000 --- a/app/src/main/res/drawable/ic_launcher_foreground_mono.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/app/src/main/res/layout/activity_send_message.xml b/app/src/main/res/layout/activity_send_message.xml index a8041d61c..320782bdc 100644 --- a/app/src/main/res/layout/activity_send_message.xml +++ b/app/src/main/res/layout/activity_send_message.xml @@ -55,29 +55,17 @@ android:id="@+id/sendMessageFrom" android:layout_width="0dp" android:layout_height="58dp" - android:layout_marginStart="8dp" - android:background="?selectableItemBackground" + android:layout_marginStart="16dp" + android:layout_marginLeft="16dp" + android:layout_marginEnd="16dp" + android:layout_marginRight="16dp" android:gravity="center_vertical" - android:paddingStart="8dp" - android:paddingEnd="32dp" android:textSize="18sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/sendMessageFromHint" app:layout_constraintTop_toTopOf="parent" tools:text="Jan Kowalski" /> - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_login_student_select.xml b/app/src/main/res/layout/fragment_login_student_select.xml index c47b9ae35..bf5431164 100644 --- a/app/src/main/res/layout/fragment_login_student_select.xml +++ b/app/src/main/res/layout/fragment_login_student_select.xml @@ -3,14 +3,92 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical" - tools:context=".ui.modules.login.studentselect.LoginStudentSelectFragment"> + android:orientation="vertical"> + + + + + + + + + + + + + + + + + + + tools:itemCount="6" + tools:listitem="@layout/item_login_student_select" /> - - diff --git a/app/src/main/res/layout/fragment_notifications.xml b/app/src/main/res/layout/fragment_notifications.xml deleted file mode 100644 index 8e506e1e7..000000000 --- a/app/src/main/res/layout/fragment_notifications.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/item_dashboard_horizontal_group.xml b/app/src/main/res/layout/item_dashboard_horizontal_group.xml index 0c59d1ebf..1d43d5115 100644 --- a/app/src/main/res/layout/item_dashboard_horizontal_group.xml +++ b/app/src/main/res/layout/item_dashboard_horizontal_group.xml @@ -37,25 +37,9 @@ app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - app:layout_goneMarginEnd="16dp" app:tint="?colorOnSurface" tools:ignore="ContentDescription" /> - - - - + tools:text="16" /> @@ -178,25 +145,9 @@ app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - app:layout_goneMarginEnd="16dp" app:tint="?colorOnSurface" tools:ignore="ContentDescription" /> - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/item_login_student_select_student.xml b/app/src/main/res/layout/item_login_student_select.xml similarity index 71% rename from app/src/main/res/layout/item_login_student_select_student.xml rename to app/src/main/res/layout/item_login_student_select.xml index d071b1bbf..1003636fc 100644 --- a/app/src/main/res/layout/item_login_student_select_student.xml +++ b/app/src/main/res/layout/item_login_student_select.xml @@ -4,7 +4,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?selectableItemBackground" - android:minHeight="56dp" + android:minHeight="72dp" android:paddingTop="8dp" android:paddingBottom="8dp" tools:context=".ui.modules.login.studentselect.LoginStudentSelectAdapter"> @@ -14,10 +14,9 @@ android:layout_width="32dp" android:layout_height="24dp" android:layout_centerVertical="true" - android:layout_marginStart="32dp" + android:layout_marginStart="12dp" android:layout_marginEnd="28dp" android:background="@android:color/transparent" - android:clickable="false" tools:text=" " /> + + + android:textSize="14sp" + android:visibility="gone" + tools:visibility="visible" /> diff --git a/app/src/main/res/layout/item_login_student_select_empty_symbol_header.xml b/app/src/main/res/layout/item_login_student_select_empty_symbol_header.xml deleted file mode 100644 index be0fd905c..000000000 --- a/app/src/main/res/layout/item_login_student_select_empty_symbol_header.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - diff --git a/app/src/main/res/layout/item_login_student_select_header_school.xml b/app/src/main/res/layout/item_login_student_select_header_school.xml deleted file mode 100644 index 30a8bbf0b..000000000 --- a/app/src/main/res/layout/item_login_student_select_header_school.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - diff --git a/app/src/main/res/layout/item_login_student_select_header_symbol.xml b/app/src/main/res/layout/item_login_student_select_header_symbol.xml deleted file mode 100644 index cc1bf709d..000000000 --- a/app/src/main/res/layout/item_login_student_select_header_symbol.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - diff --git a/app/src/main/res/layout/item_login_student_select_help.xml b/app/src/main/res/layout/item_login_student_select_help.xml deleted file mode 100644 index b6d81c7cd..000000000 --- a/app/src/main/res/layout/item_login_student_select_help.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - diff --git a/app/src/main/res/layout/item_mailbox_chooser.xml b/app/src/main/res/layout/item_mailbox_chooser.xml deleted file mode 100644 index 7c93199bc..000000000 --- a/app/src/main/res/layout/item_mailbox_chooser.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/layout/item_message.xml b/app/src/main/res/layout/item_message.xml index 39fbaad01..c25faacc8 100644 --- a/app/src/main/res/layout/item_message.xml +++ b/app/src/main/res/layout/item_message.xml @@ -30,7 +30,6 @@ android:layout_marginEnd="10dp" android:ellipsize="end" android:singleLine="true" - android:textColor="?android:textColorSecondary" android:textSize="15sp" app:layout_constraintEnd_toStartOf="@+id/messageItemDate" app:layout_constraintStart_toEndOf="@id/messageItemCheckbox" @@ -41,13 +40,10 @@ android:id="@+id/messageItemDate" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginEnd="8dp" android:gravity="end" - android:textColor="?android:textColorSecondary" android:textSize="13sp" - app:layout_constraintEnd_toStartOf="@id/messageItemUnreadIndicator" + app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" - app:layout_goneMarginEnd="0dp" tools:text="@tools:sample/date/ddmmyy" /> - - diff --git a/app/src/main/res/layout/item_message_chips.xml b/app/src/main/res/layout/item_message_chips.xml index da2e20311..481a94835 100644 --- a/app/src/main/res/layout/item_message_chips.xml +++ b/app/src/main/res/layout/item_message_chips.xml @@ -1,30 +1,21 @@ - - - + app:layout_constraintTop_toTopOf="parent"> - + diff --git a/app/src/main/res/menu/action_menu_message_preview.xml b/app/src/main/res/menu/action_menu_message_preview.xml index 57cf05ddb..5011e2356 100644 --- a/app/src/main/res/menu/action_menu_message_preview.xml +++ b/app/src/main/res/menu/action_menu_message_preview.xml @@ -8,20 +8,6 @@ android:title="@string/message_reply" app:iconTint="@color/material_on_surface_emphasis_medium" app:showAsAction="ifRoom" /> - - + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index da1bca126..d59ec8e17 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -2,5 +2,4 @@ - - + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000..d59ec8e17 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 000000000..85f6a2c87 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 000000000..dc6ac682d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 000000000..dd67b8771 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..b7d82f5d5 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..7ad000eec Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 4a91cc852..d036e7e42 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -55,7 +55,7 @@ Neplatný symbol Žák nebyl nalezen. Zkontrolujte správnost symbolu a vybrané varianty deníku UONET+ Vybraný žák je už přihlášen - Symbol najdete na stránce deníku v  Uczeń→ Dostęp Mobilny → Wygeneruj kod dostępu.\n\nUjistěte se, že jste nastavili správnou variantu deníku v poli Variace deníku UONET+ na první přihlašovací obrazovce + Symbol najdete na stránce deníku v  Uczeń→ Dostęp Mobilny → Zarejestruj urządzenie mobilne.\n\nUjistěte se, že jste na předchozí obrazovce nastavili správnou variantu deníku do pole Variace deníku UONET+ Vyberte žáky, kteří se mají do aplikace přihlásit Jiné možnosti V tomto režimu nefungují následující: šťastné číslo, statistiky třídy, shrnutí frekvencí, ospravedlnění nepřítomnosti, dokončené lekce, informace o škole a prohlížení seznamu registrovaných zařízení @@ -72,14 +72,6 @@ Obnovit Žák je už přihlášen Standardní - Jiná místa vyhledávání - Nebyli nalezeni žádní aktivní žáci - Zadejte jiný symbol - - Povolit oznámení - Povolit upozornění, abyste nezmeškali zprávu od učitele nebo o nové známce - Přeskočit - Zapnout Manažer účtů Přihlásit se @@ -317,11 +309,9 @@ Zpráva neexistuje Musíte vybrat alespoň 1 příjemce Obsah zprávy musí mít alespoň 3 znaky - Všechny poštovní schránky Pouze nepřečtené Pouze s přílohami Přečtena: %s - Přečtena přes: %1$d z %2$d osob %1$d zpráva %1$d zprávy @@ -349,7 +339,6 @@ %1$d vybraných Zprávy odstraněné - Vyberte poštovní schránku Žádné informace o poznámkách Body @@ -493,8 +482,6 @@ Přítomnost na setkání Agenda - Místo - Téma Školní oznámení Žádná školní oznámení @@ -748,7 +735,7 @@ Volbu můžete kdykoliv změnit v nastavení aplikace. Můžeme použít Vaše data k zobrazení reklam šitých pro vás nebo pomocí méně vašich dat zobrazovat nepřizpůsobené reklamy. Podrobnosti naleznete v našich Zásadách ochrany osobních údajů Přizpůsobené reklamy Nepřizpůsobené reklamy - Je mi více než 18 let + Mám ukončené 18 let Ano, přizpůsobené reklamy Ano, nepřizpůsobené reklamy Pokročilé diff --git a/app/src/main/res/values-da-rDK/preferences_values.xml b/app/src/main/res/values-da-rDK/preferences_values.xml deleted file mode 100644 index ac2b6e9e5..000000000 --- a/app/src/main/res/values-da-rDK/preferences_values.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - Light - Dark - Black (AMOLED) - - - System language - Polski - English - Pусский - Українська - Deutsch - Čeština - Slovenčina - - - 15 minutes - 30 minutes - 1 hour - 2 hours - 6 hours - 12 hours - 24 hours - - - 0,00 - 0,25 - 0,33 - 0,5 - 0,75 - - - Alphabetically - By date - By average - - - Dzienniczek+ - Wulkanowy - Grade colors in register - - - Up to 1 at once - Always expanded - Unlimited expansions - - - Average of grades only from selected semester - Average of averages from both semesters - Average of grades from the whole year - - - Lucky number - Unread messages - Attendance - Lessons - Grades - Homework - School announcements - Exams - Conferences - - diff --git a/app/src/main/res/values-da-rDK/strings.xml b/app/src/main/res/values-da-rDK/strings.xml deleted file mode 100644 index 667231274..000000000 --- a/app/src/main/res/values-da-rDK/strings.xml +++ /dev/null @@ -1,728 +0,0 @@ - - - - Login - Wulkanowy - Grades - Attendance - Exams - Timetable - Settings - More - About - Log viewer - Debug - Notification debug - Contributors - Licenses - Messages - New message - New homework - Notes and achievements - Homework - Accounts manager - Select account - Account details - Student info - Dashboard - Notifications center - - Semester %1$d, %2$d/%3$d - - Sign in with the student or parent account - Enter the symbol from the register page for account: <b>%1$s</b> - Username - Email - Login, PESEL or e-mail - Password - UONET+ register variant - Mobile API - Scraper - Hybrid - Token - PIN - Symbol - Sign in - Password too short - Login details are incorrect - %1$s. Make sure the correct UONET+ register variation is selected below - Invalid PIN - Invalid token - Token expired - Invalid email - Use the assigned login instead of email - Use the assigned login or email in @%1$s - Invalid symbol - Student not found. Validate the symbol and the chosen variation of the UONET+ register - Selected student is already logged in - The symbol can be found on the register page in Uczeń → Dostęp Mobilny → Wygeneruj kod dostępu.\n\nMake sure that you have set the appropriate register variant in the UONET+ register variant field on the first login screen - Select students to log in to the application - Other options - In this mode, a lucky number does not work, a class grade stats, summary of attendance, excuse for absence, completed lessons, school information and preview of the list of registered devices - This mode displays the same data as it appears on the register website - The combination of the best features of the other two modes. It works faster than scraper and provides features not available in the Mobile API mode. It is in the experimental phase - Privacy policy - Trouble signing in? Contact us! - Email - Discord - Send email - Make sure you select the correct UONET+ register variation! - I forgot my password - Recover your account - Recover - Student is already signed in - Standard - Other search locations - No active students found - Enter a different symbol - - Enable notifications - Enable notifications so you don\'t miss message from teacher or new grade - Skip - Enable - - Account manager - Log in - Session expired - Session expired, log in again - Application support - Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time - Enable ads - - Grade - Semester %d - Change semester - No grades - Weight - Weight: %s - Comment - Number of new ratings: %1$d - Average: %1$.2f - Points: %s - No average - Total points - Final grade - Predicted grade - Calculated average - How does Calculated Average work? - The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\nAverage of grades only from selected semester:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\nAverage of averages from both semesters:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\nAverage of grades from the whole year:\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n2. Adding calculated averages\n3. Calculating the arithmetic average of summed averages - How does the Final Average work? - The Final Average is the arithmetic average calculated from all currently available final grades in the given semester.\n\nThe calculation scheme consists of the following steps:\n1. Summing up the final grades given by teachers\n2. Divide by the number of subjects that have already been graded - Final average - from %1$d of %2$d subjects - Summary - Class - Mark as read - Partial - Semester - Points - Legend - Class average: %1$s - Your average: %1$s - Your grade: %1$s - Class - Student - - %d grade - %d grades - - - New grade - New grades - - - New predicted grade - New predicted grades - - - New final grade - New final grades - - - You received %1$d grade - You received %1$d grades - - - You received %1$d predicted grade - You received %1$d predicted grades - - - You received %1$d final grade - You received %1$d final grades - - - Lesson - Room - Group - Hours - Changes - No lessons this day - %s min - %s sec - %1$s left - in %1$s - Finished - Now: %s - Next: %s - Later: %s - %1$s lesson %2$d - %3$s - Change of room from %1$s to %2$s - Change of teacher from %1$s to %2$s - Change of subject from %1$s to %2$s - - Timetable change - Timetable changes - - - %1$s - %2$d change in timetable - %1$s - %2$d changes in timetable - - - %1$d change in timetable - %1$d changes in timetable - - - %d change - %d changes - - - Completed lessons - Show completed lessons - No info about completed lessons - Topic - Absence - Resources - - Additional lessons - Show additional lessons - No info about additional lessons - New lesson - New additional lesson - Additional lesson added successfully - Additional lesson deleted successfully - Repeat weekly - Delete additional lesson - Just this lesson - All in the series - Start time - End time - End time must be greater than start time - - Attendance summary - Absent for school reasons - Excused absence - Unexcused absence - Exemption - Excused lateness - Unexcused lateness - Present - Deleted - Unknown - Number of lesson - No entries - Absence reason (optional) - Send - Absence excuse request sent successfully! - You must select at least one absence! - Excuse - - New attendance - New attendance - - - %1$d new attendance - %1$d attendance - - - %d attendance - %d attendance - - - Total - - No exams this week - Type - Entry date - - New exam - New exams - - - %d new exam - %d new exams - - - %d exam - %d exams - - - Inbox - Sent - Trash - (no subject) - No messages - From: - To: - Date: %1$s - Reply - Forward - Select all - Unselect all - Move to trash - Delete permanently - Message deleted successfully - student - parent - guardian - employee - Share - Print - Subject - Content - Message sent successfully - Message does not exist - You need to choose at least 1 recipient - The message content must be at least 3 characters - All mailboxes - Only unread - Only with attachments - Read: %s - Read by: %1$d of %2$d people - - %1$d message - %1$d messages - - - New message - New messages - - Do you want to restore draft message? - Do you want to restore draft message with recipients: %s? - - You received %1$d message - You received %1$d messages - - - %1$d selected - %1$d selected - - Messages deleted - Choose mailbox - - No info about notes - Points - - %d note - %d notes - - - New note - New notes - - - You received %1$d note - You received %1$d notes - - - - %d praise - %d praises - - - New praise - New praises - - - You received %1$d praise - You received %1$d praises - - - - %d neutral note - %d neutral notes - - - New neutral note - New neutral notes - - - You received %1$d neutral note - You received %1$d neutral notes - - - No info about homework - Mark as done - Mark as undone - Add homework - Homework added successfully - Homework deleted successfully - Attachments - - New homework - New homework - - - You received %d new homework - You received %d new homework - - - %d homework - %d homework - - - Lucky number - Today\'s lucky number is - No info about the lucky number - Lucky number for today - Today\'s lucky number is: %s - Show history - - Lucky number history - No info about lucky numbers - - Mobile devices - No devices - Deregister - Device removed - QR code - Token - Symbol - PIN - - School and teachers - - School - No info about school - School name - School address - Telephone - Name of headmaster - Name of pedagogue - Show on map - Call - - Teachers - No info about teachers - No subject - - Conferences - No info about conferences - - %d conference - %d conferences - - - New conference - New conferences - - - You have %1$d new conference - You have %1$d new conferences - - Present at conference - Agenda - Place - Topic - - School announcements - No school announcements - - %d school announcement - %d school announcements - - - New school announcement - New school announcements - - - You have %1$d new school announcement - You have %1$d new school announcements - - - Add account - Logout - Do you want to log out this student? - Student logout - Student account - Parent account - Edit data - Accounts manager - Select student - Family - Contact - Residence details - Personal information - - App version - Contributors - List of Wulkanowy developers - Report a bug - Send a bug report via e-mail - FAQ - Read Frequently Asked Questions - Discord server - Join the Wulkanowy community - Facebook fanpage - Twitter page - Follow us on twitter - Like our facebook fanpage - Privacy policy - Rules for collecting personal data - System settings - Open system settings - Homepage - Visit the website and help develop the application - Licenses - Licenses of libraries used in the application - - License - - Avatar - See more on GitHub - - No info about student or student family - Name - Second name - Gender - Polish citizenship - Family name - Mother\'s and father\'s names - Phone - Cellphone - E-mail - Address of residence - Address of registration - Correspondence address - Surname and first name - Degree of kinship - Address - Phones - Male - Female - Last name - Guardian - - Nick - Add nick - Choose avatar color - - Share logs - Refresh - - Lessons - (Tomorrow) - (Today and tomorrow) - In a moment: - Soon: - First: - Now: - End of lessons - Next: - Later: - - %1$d more lesson - %1$d more lessons - - until %1$s - No upcoming lessons - An error occurred while loading the lessons - Homework - No homework to do - An error occurred while loading the homework - - %1$d more homework - %1$d more homework - - due %1$s - Last grades - No new grades - An error occurred while loading the grades - School announcements - No current announcements - An error occurred while loading the announcements - - %1$d more announcement - %1$d more announcements - - Exams - No upcoming exams - An error occurred while loading the exams - - %1$d more exam - %1$d more exams - - Conferences - No upcoming conferences - An error occurred while loading the conferences - - %1$d more conference - %1$d more conferences - - An error occurred while loading data - None - - Check for updates - Before reporting a bug, check first if an update with the bug fix is available - - Content - Retry - Description - No description - Teacher - Date - Entry date - Color - Details - Category - Close - No data - Subject - Prev - Next - Search - Search… - Yes - No - Save - Title - Add - Copied - Undo - Change - Add to calendar - - No lessons - Choose theme - Light - Dark - System Theme - - App - Default view - Calculated average options - Force average calculation by app - Show presence - Theme - Grades expanding - Mark current lesson - Show groups next to subjects - Show chart list in class grades - Show subjects without grades - Grades color scheme - Subjects sorting - Language - Notifications - Other - Show notifications - Show upcoming lesson notifications - Make upcoming lesson notification persistent - Turn off when notification is not showing in your watch/band - Open system notification settings - Fix synchronization & notifications issues - Your device may have data synchronization issues and with notifications.\n\nTo fix them, you need to add Wulkanowy to the autostart and turn off battery optimization/saving in the phone settings. - Show debug notifications - Synchronization is disabled - Official app notifications - Capture official app notifications - Remove official app notifications after capture - Capture notifications - With this feature you can gain a substitute of push notifications like in the official app. All you need to do is allow Wulkanowy to receive all notifications in your system settings.\n\nHow it works?\nWhen you get a notification in Dziennik VULCAN, Wulkanowy will be notified (that\'s what these extra permissions are for) and will trigger a sync so that can send its own notification.\n\nFOR ADVANCED USERS ONLY - Upcoming lesson notifications - You must allow the Wulkanowy app to set alarms and reminders in your system settings to use this feature. - Go to settings - Synchronization - Automatic update - Suspended on holidays - Updates interval - Wi-Fi only - Sync now - Synced! - Sync failed - Sync in progress - Last full sync: %s - Value of the plus - Value of the minus - Reply with message history - Show arithmetic average when no weights provided - Support - Privacy Policy - Agreements - Consent to processing of data related to ads - Show ads in app - Watch single ad to support project - Consent to data processing - To view an advertisement you must agree to the data processing terms of our Privacy Policy - Agree - Privacy policy - Ad is loading - Thank you for your support, come back later for more ads - Can we use your data to display ads? - You can change your choice anytime in the app settings. We may use your data to display ads tailored to you or, using less of your data, display non-personalized ads. Please see our Privacy Policy for details - Personalized ads - Non-personalized ads - I am over 18 years old - Yes, personalized ads - Yes, non-personalized ads - Advanced - Appearance & Behavior - Notifications - Synchronization - Advertisements - Grades - Dashboard - Tiles visibility - Attendance - Timetable - Grades - Calculated average - Messages - Appearance & Behavior - Languages, themes, subjects sorting - App notifications, fix problems - Notifications - Synchronization - Automatic update, synchronization interval - Plus and minus values, average calculation - Advanced - App version, contributors, social portals - Displaying advertisements, project support - - New grades - New homework - New conferences - New exams - Lucky number - New messages - New notes - New school announcements - Push notifications - Upcoming lessons - Debug - Timetable change - New attendance - - Black - Red - Blue - Green - Purple - No color - - Download of updates has started… - An update has just been downloaded. - Restart - Update failed! Wulkanowy may not function properly. Consider updating - - No internet connection - An error occurred. Check your device clock - Connection to register failed. Servers can be overloaded. Please try again later - Loading data failed. Please try again later - Register password change required - Maintenance underway UONET + register. Try again later - Unknown UONET + register error. Try again later - Unknown application error. Please try again later - An unexpected error occurred - Feature disabled by your school - Feature not available. Login in a mode other than Mobile API - This field is required - diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index f7b8e7c4d..4dfeee4f6 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -55,7 +55,7 @@ Ungültige symbol Schüler nicht gefunden. Überprüfen Sie das Symbol und die gewählte Variation des UONET+ Registers Ausgewählter Student ist bereits angemeldet. - The symbol can be found on the register page in Uczeń → Dostęp Mobilny → Wygeneruj kod dostępu.\n\nMake sure that you have set the appropriate register variant in the UONET+ register variant field on the first login screen + Das Symbol kann auf der Registerseite in Uczeń→ Dostęp Mobilny → Zarejestruj urządzenie mobilnegefunden werden.\n\nStellen Sie sicher, dass Sie die entsprechende Registervariante im Feld UONET+ Registervariante auf dem vorherigen Bildschirm festgelegt haben Wählen Sie die Studenten aus, die sich bei der Anwendung anmelden sollen Andere Optionen In diesem Modus funktioniert eine Glücknummer, eine Klassenstatistik, eine Zusammenfassung der Anwesenheit, eine Entschuldigung für die Abwesenheit, abgeschlossene Lektionen, Schulinformationen und eine Vorschau der Liste der registrierten Geräte nicht @@ -72,14 +72,6 @@ Wiederherstellen Student ist bereits angemeldet Standard - Other search locations - No active students found - Enter a different symbol - - Enable notifications - Enable notifications so you don\'t miss message from teacher or new grade - Skip - Enable Kundenbetreuer Anmelden @@ -283,11 +275,9 @@ Nachricht nicht vorhanden Sie müssen mindestens 1 Empfänger auswählen. Der Inhalt der Nachricht muss mindestens 3 Zeichen lang sein. - Alle postfächer Nur ungelesen Nur mit Anhängen Lesen: %s - Read by: %1$d of %2$d people %1$d Nachricht %1$d Nachrichten @@ -307,7 +297,6 @@ %1$d ausgewählt Nachrichten gelöscht - Postfach auswählen Keine Informationen über Eintragen Punkte @@ -421,8 +410,6 @@ Teilnahme an einem Meeting Agenda - Place - Topic Schulankündigungen Keine schulankündigungen @@ -645,10 +632,10 @@ Antwort mit Nachrichtenhistorie Arithmetisches Mittel anzeigen, wenn keine Gewichte angegeben sind Unterstützung - Datenschutz-Bestimmungen - Vereinbarungen - Zustimmung zur Verarbeitung von Daten im Zusammenhang mit Anzeigen - Anzeigen in der App anzeigen + Privacy Policy + Agreements + Consent to processing of data related to ads + Show ads in app Einzelanzeige ansehen, um Projekt zu unterstützen Einwilligung in die Datenverarbeitung Um eine Anzeige zu sehen, müssen Sie mit den Datenverarbeitungsbedingungen unserer Datenschutzerklärung einverstanden sein @@ -660,9 +647,9 @@ Sie können Ihre Wahl jederzeit in den App-Einstellungen ändern. Wir verwenden Ihre Daten, um auf Sie zugeschnittene Anzeigen anzuzeigen oder unter Verwendung weniger Ihrer Daten nicht personalisierte Werbung anzuzeigen. Bitte lesen Sie unsere Datenschutzerklärung für Details Personalisierte Werbung keine personalisierte Werbung - Ich bin über 18 Jahre alt - Ja, personalisierte Werbung - Ja, nicht personalisierte Werbung + I am over 18 years old + Yes, personalized ads + Yes, non-personalized ads Erweitert Aussehen & Verhalten Benachrichtigungen diff --git a/app/src/main/res/values-es-rES/preferences_values.xml b/app/src/main/res/values-es-rES/preferences_values.xml deleted file mode 100644 index ac2b6e9e5..000000000 --- a/app/src/main/res/values-es-rES/preferences_values.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - Light - Dark - Black (AMOLED) - - - System language - Polski - English - Pусский - Українська - Deutsch - Čeština - Slovenčina - - - 15 minutes - 30 minutes - 1 hour - 2 hours - 6 hours - 12 hours - 24 hours - - - 0,00 - 0,25 - 0,33 - 0,5 - 0,75 - - - Alphabetically - By date - By average - - - Dzienniczek+ - Wulkanowy - Grade colors in register - - - Up to 1 at once - Always expanded - Unlimited expansions - - - Average of grades only from selected semester - Average of averages from both semesters - Average of grades from the whole year - - - Lucky number - Unread messages - Attendance - Lessons - Grades - Homework - School announcements - Exams - Conferences - - diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml deleted file mode 100644 index 667231274..000000000 --- a/app/src/main/res/values-es-rES/strings.xml +++ /dev/null @@ -1,728 +0,0 @@ - - - - Login - Wulkanowy - Grades - Attendance - Exams - Timetable - Settings - More - About - Log viewer - Debug - Notification debug - Contributors - Licenses - Messages - New message - New homework - Notes and achievements - Homework - Accounts manager - Select account - Account details - Student info - Dashboard - Notifications center - - Semester %1$d, %2$d/%3$d - - Sign in with the student or parent account - Enter the symbol from the register page for account: <b>%1$s</b> - Username - Email - Login, PESEL or e-mail - Password - UONET+ register variant - Mobile API - Scraper - Hybrid - Token - PIN - Symbol - Sign in - Password too short - Login details are incorrect - %1$s. Make sure the correct UONET+ register variation is selected below - Invalid PIN - Invalid token - Token expired - Invalid email - Use the assigned login instead of email - Use the assigned login or email in @%1$s - Invalid symbol - Student not found. Validate the symbol and the chosen variation of the UONET+ register - Selected student is already logged in - The symbol can be found on the register page in Uczeń → Dostęp Mobilny → Wygeneruj kod dostępu.\n\nMake sure that you have set the appropriate register variant in the UONET+ register variant field on the first login screen - Select students to log in to the application - Other options - In this mode, a lucky number does not work, a class grade stats, summary of attendance, excuse for absence, completed lessons, school information and preview of the list of registered devices - This mode displays the same data as it appears on the register website - The combination of the best features of the other two modes. It works faster than scraper and provides features not available in the Mobile API mode. It is in the experimental phase - Privacy policy - Trouble signing in? Contact us! - Email - Discord - Send email - Make sure you select the correct UONET+ register variation! - I forgot my password - Recover your account - Recover - Student is already signed in - Standard - Other search locations - No active students found - Enter a different symbol - - Enable notifications - Enable notifications so you don\'t miss message from teacher or new grade - Skip - Enable - - Account manager - Log in - Session expired - Session expired, log in again - Application support - Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time - Enable ads - - Grade - Semester %d - Change semester - No grades - Weight - Weight: %s - Comment - Number of new ratings: %1$d - Average: %1$.2f - Points: %s - No average - Total points - Final grade - Predicted grade - Calculated average - How does Calculated Average work? - The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\nAverage of grades only from selected semester:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\nAverage of averages from both semesters:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\nAverage of grades from the whole year:\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n2. Adding calculated averages\n3. Calculating the arithmetic average of summed averages - How does the Final Average work? - The Final Average is the arithmetic average calculated from all currently available final grades in the given semester.\n\nThe calculation scheme consists of the following steps:\n1. Summing up the final grades given by teachers\n2. Divide by the number of subjects that have already been graded - Final average - from %1$d of %2$d subjects - Summary - Class - Mark as read - Partial - Semester - Points - Legend - Class average: %1$s - Your average: %1$s - Your grade: %1$s - Class - Student - - %d grade - %d grades - - - New grade - New grades - - - New predicted grade - New predicted grades - - - New final grade - New final grades - - - You received %1$d grade - You received %1$d grades - - - You received %1$d predicted grade - You received %1$d predicted grades - - - You received %1$d final grade - You received %1$d final grades - - - Lesson - Room - Group - Hours - Changes - No lessons this day - %s min - %s sec - %1$s left - in %1$s - Finished - Now: %s - Next: %s - Later: %s - %1$s lesson %2$d - %3$s - Change of room from %1$s to %2$s - Change of teacher from %1$s to %2$s - Change of subject from %1$s to %2$s - - Timetable change - Timetable changes - - - %1$s - %2$d change in timetable - %1$s - %2$d changes in timetable - - - %1$d change in timetable - %1$d changes in timetable - - - %d change - %d changes - - - Completed lessons - Show completed lessons - No info about completed lessons - Topic - Absence - Resources - - Additional lessons - Show additional lessons - No info about additional lessons - New lesson - New additional lesson - Additional lesson added successfully - Additional lesson deleted successfully - Repeat weekly - Delete additional lesson - Just this lesson - All in the series - Start time - End time - End time must be greater than start time - - Attendance summary - Absent for school reasons - Excused absence - Unexcused absence - Exemption - Excused lateness - Unexcused lateness - Present - Deleted - Unknown - Number of lesson - No entries - Absence reason (optional) - Send - Absence excuse request sent successfully! - You must select at least one absence! - Excuse - - New attendance - New attendance - - - %1$d new attendance - %1$d attendance - - - %d attendance - %d attendance - - - Total - - No exams this week - Type - Entry date - - New exam - New exams - - - %d new exam - %d new exams - - - %d exam - %d exams - - - Inbox - Sent - Trash - (no subject) - No messages - From: - To: - Date: %1$s - Reply - Forward - Select all - Unselect all - Move to trash - Delete permanently - Message deleted successfully - student - parent - guardian - employee - Share - Print - Subject - Content - Message sent successfully - Message does not exist - You need to choose at least 1 recipient - The message content must be at least 3 characters - All mailboxes - Only unread - Only with attachments - Read: %s - Read by: %1$d of %2$d people - - %1$d message - %1$d messages - - - New message - New messages - - Do you want to restore draft message? - Do you want to restore draft message with recipients: %s? - - You received %1$d message - You received %1$d messages - - - %1$d selected - %1$d selected - - Messages deleted - Choose mailbox - - No info about notes - Points - - %d note - %d notes - - - New note - New notes - - - You received %1$d note - You received %1$d notes - - - - %d praise - %d praises - - - New praise - New praises - - - You received %1$d praise - You received %1$d praises - - - - %d neutral note - %d neutral notes - - - New neutral note - New neutral notes - - - You received %1$d neutral note - You received %1$d neutral notes - - - No info about homework - Mark as done - Mark as undone - Add homework - Homework added successfully - Homework deleted successfully - Attachments - - New homework - New homework - - - You received %d new homework - You received %d new homework - - - %d homework - %d homework - - - Lucky number - Today\'s lucky number is - No info about the lucky number - Lucky number for today - Today\'s lucky number is: %s - Show history - - Lucky number history - No info about lucky numbers - - Mobile devices - No devices - Deregister - Device removed - QR code - Token - Symbol - PIN - - School and teachers - - School - No info about school - School name - School address - Telephone - Name of headmaster - Name of pedagogue - Show on map - Call - - Teachers - No info about teachers - No subject - - Conferences - No info about conferences - - %d conference - %d conferences - - - New conference - New conferences - - - You have %1$d new conference - You have %1$d new conferences - - Present at conference - Agenda - Place - Topic - - School announcements - No school announcements - - %d school announcement - %d school announcements - - - New school announcement - New school announcements - - - You have %1$d new school announcement - You have %1$d new school announcements - - - Add account - Logout - Do you want to log out this student? - Student logout - Student account - Parent account - Edit data - Accounts manager - Select student - Family - Contact - Residence details - Personal information - - App version - Contributors - List of Wulkanowy developers - Report a bug - Send a bug report via e-mail - FAQ - Read Frequently Asked Questions - Discord server - Join the Wulkanowy community - Facebook fanpage - Twitter page - Follow us on twitter - Like our facebook fanpage - Privacy policy - Rules for collecting personal data - System settings - Open system settings - Homepage - Visit the website and help develop the application - Licenses - Licenses of libraries used in the application - - License - - Avatar - See more on GitHub - - No info about student or student family - Name - Second name - Gender - Polish citizenship - Family name - Mother\'s and father\'s names - Phone - Cellphone - E-mail - Address of residence - Address of registration - Correspondence address - Surname and first name - Degree of kinship - Address - Phones - Male - Female - Last name - Guardian - - Nick - Add nick - Choose avatar color - - Share logs - Refresh - - Lessons - (Tomorrow) - (Today and tomorrow) - In a moment: - Soon: - First: - Now: - End of lessons - Next: - Later: - - %1$d more lesson - %1$d more lessons - - until %1$s - No upcoming lessons - An error occurred while loading the lessons - Homework - No homework to do - An error occurred while loading the homework - - %1$d more homework - %1$d more homework - - due %1$s - Last grades - No new grades - An error occurred while loading the grades - School announcements - No current announcements - An error occurred while loading the announcements - - %1$d more announcement - %1$d more announcements - - Exams - No upcoming exams - An error occurred while loading the exams - - %1$d more exam - %1$d more exams - - Conferences - No upcoming conferences - An error occurred while loading the conferences - - %1$d more conference - %1$d more conferences - - An error occurred while loading data - None - - Check for updates - Before reporting a bug, check first if an update with the bug fix is available - - Content - Retry - Description - No description - Teacher - Date - Entry date - Color - Details - Category - Close - No data - Subject - Prev - Next - Search - Search… - Yes - No - Save - Title - Add - Copied - Undo - Change - Add to calendar - - No lessons - Choose theme - Light - Dark - System Theme - - App - Default view - Calculated average options - Force average calculation by app - Show presence - Theme - Grades expanding - Mark current lesson - Show groups next to subjects - Show chart list in class grades - Show subjects without grades - Grades color scheme - Subjects sorting - Language - Notifications - Other - Show notifications - Show upcoming lesson notifications - Make upcoming lesson notification persistent - Turn off when notification is not showing in your watch/band - Open system notification settings - Fix synchronization & notifications issues - Your device may have data synchronization issues and with notifications.\n\nTo fix them, you need to add Wulkanowy to the autostart and turn off battery optimization/saving in the phone settings. - Show debug notifications - Synchronization is disabled - Official app notifications - Capture official app notifications - Remove official app notifications after capture - Capture notifications - With this feature you can gain a substitute of push notifications like in the official app. All you need to do is allow Wulkanowy to receive all notifications in your system settings.\n\nHow it works?\nWhen you get a notification in Dziennik VULCAN, Wulkanowy will be notified (that\'s what these extra permissions are for) and will trigger a sync so that can send its own notification.\n\nFOR ADVANCED USERS ONLY - Upcoming lesson notifications - You must allow the Wulkanowy app to set alarms and reminders in your system settings to use this feature. - Go to settings - Synchronization - Automatic update - Suspended on holidays - Updates interval - Wi-Fi only - Sync now - Synced! - Sync failed - Sync in progress - Last full sync: %s - Value of the plus - Value of the minus - Reply with message history - Show arithmetic average when no weights provided - Support - Privacy Policy - Agreements - Consent to processing of data related to ads - Show ads in app - Watch single ad to support project - Consent to data processing - To view an advertisement you must agree to the data processing terms of our Privacy Policy - Agree - Privacy policy - Ad is loading - Thank you for your support, come back later for more ads - Can we use your data to display ads? - You can change your choice anytime in the app settings. We may use your data to display ads tailored to you or, using less of your data, display non-personalized ads. Please see our Privacy Policy for details - Personalized ads - Non-personalized ads - I am over 18 years old - Yes, personalized ads - Yes, non-personalized ads - Advanced - Appearance & Behavior - Notifications - Synchronization - Advertisements - Grades - Dashboard - Tiles visibility - Attendance - Timetable - Grades - Calculated average - Messages - Appearance & Behavior - Languages, themes, subjects sorting - App notifications, fix problems - Notifications - Synchronization - Automatic update, synchronization interval - Plus and minus values, average calculation - Advanced - App version, contributors, social portals - Displaying advertisements, project support - - New grades - New homework - New conferences - New exams - Lucky number - New messages - New notes - New school announcements - Push notifications - Upcoming lessons - Debug - Timetable change - New attendance - - Black - Red - Blue - Green - Purple - No color - - Download of updates has started… - An update has just been downloaded. - Restart - Update failed! Wulkanowy may not function properly. Consider updating - - No internet connection - An error occurred. Check your device clock - Connection to register failed. Servers can be overloaded. Please try again later - Loading data failed. Please try again later - Register password change required - Maintenance underway UONET + register. Try again later - Unknown UONET + register error. Try again later - Unknown application error. Please try again later - An unexpected error occurred - Feature disabled by your school - Feature not available. Login in a mode other than Mobile API - This field is required - diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 4891015d2..c9abbd022 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -55,7 +55,7 @@ Nieprawidłowy symbol Nie znaleziono ucznia. Sprawdź poprawność symbolu i wybranej odmiany dziennika UONET+ Wybrany uczeń jest już zalogowany - Symbol można znaleźć na stronie dziennika w Uczeń→ Dostęp Mobilny → Wygeneruj kod dostępu.\n\nUpewnij się, że ustawiłeś odpowiednią odmianę dziennika w polu Odmiana dziennika UONET+ na pierwszym ekranie logowania + Symbol znajdziesz na stronie dziennika w Uczeń → Dostęp Mobilny → Zarejestruj urządzenie mobilne.\n\nUpewnij się, że w polu Dziennik UONET+ na poprzednim ekranie została ustawiona odpowiednia odmiana dziennika Wybierz uczniów do zalogowania w aplikacji Inne opcje W tym trybie nie działa szczęśliwy numerek, uczeń na tle klasy, podsumowanie frekwencji, usprawiedliwianie nieobecności, lekcje zrealizowane, informacje o szkole i podgląd listy zarejestrowanych urządzeń @@ -72,14 +72,6 @@ Przywróć Uczeń jest już zalogowany Standardowa - Inne lokalizacje wyszukiwania - Nie znaleziono aktywnych uczniów - Wprowadź inny symbol - - Włącz powiadomienia - Włącz powiadomienia, aby nie przegapić wiadomości od nauczyciela lub nowej oceny - Pomiń - Włącz Menadżer kont Zaloguj się @@ -317,11 +309,9 @@ Wiadomość nie istnieje Musisz wybrać co najmniej 1 adresata Treść wiadomości musi zawierać co najmniej 3 znaki - Wszystkie skrzynki Tylko nieprzeczytane Tylko z załącznikami Przeczytana: %s - Przeczytana przez: %1$d z %2$d osób %1$d wiadomość %1$d wiadomości @@ -349,7 +339,6 @@ %1$d wybranych Wiadomości zostały usunięte - Wybierz skrzynkę Brak informacji o uwagach Punkty @@ -493,8 +482,6 @@ Obecność na zebraniu Agenda - Miejsce - Temat Ogłoszenia szkolne Brak ogłoszeń szkolnych diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 01e43183f..e1abb0293 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -55,7 +55,7 @@ Неверный symbol Ученик не найден. Проверьте symbol и выбранный тип дненика UONET+ Данный ученик уже авторизован - The symbol can be found on the register page in Uczeń → Dostęp Mobilny → Wygeneruj kod dostępu.\n\nMake sure that you have set the appropriate register variant in the UONET+ register variant field on the first login screen + Symbol можно найти на странице регистрации в  Uczeń → Dostęp Mobilny → Zarejestruj urządzenie mobilne.\n\nУбедитесь, что вы выбрали соответствующий тип дневника в поле Тип дневника UONET+ на предыдущем экране Выберите учеников для авторизации в приложении Другие варианты В этом режиме не работают: счастливый номер, статистика класса по оценкам, статистика посещаемости и уроков, информация о школе и список зарегистрированных устройств @@ -72,22 +72,14 @@ Восстановить Ученик уже авторизован Стандартный - Other search locations - No active students found - Enter a different symbol - - Enable notifications - Enable notifications so you don\'t miss message from teacher or new grade - Skip - Enable Менеджер аккаунтов Войти Сеанс истёк Сеанс истёк, авторизуйтесь снова - Поддержка приложения - Вам нравится это приложение? Поддержите его разработку, включив неинвазивную рекламу, которую можно отключить в любое время - Включить рекламу + Application support + Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time + Enable ads Оценка %d семестр @@ -105,7 +97,7 @@ Ожидаемая оценка Рассчитанная средняя оценка Как работает \"Рассчитанная средняя оценка\"? - Рассчитанная средняя оценка - это среднее арифметическое, рассчитанное на основе средних оценок по предметам. Это позволяет узнать приблизительную итоговую среднюю оценку. Она рассчитывается способом, выбранным пользователем в настройках приложения. Рекомендуется выбрать подходящий вариант, так как каждая школа по разному считает среднюю оценку. Кроме того, если ваша школа выставляет средние оценки по предметам на странице Vulcan, приложение просто загрузит их. Это можно изменить, заставив приложение считать среднюю оценку в настройках.\n\nСредняя из оценок выбранного семестра:\n1. Вычисление средневзвешенного значения по каждому предмету за семестр\n2.Суммирование вычисленных значений\n3. Вычисление среднего арифметического суммированных значений\n\nСредняя из средних оценок семестров:\n1.Расчет средневзвешенного значения для каждого предмета в семестрах. \n2. Вычисление среднего арифметического из средневзвешенных значений для каждого предмета в семестрах.\n3. Суммирование средних арифметических\n4. Вычисление среднего арифматического из суммированных значений\n\nСредняя из оценок со всего года:\n1. Расчет средневзвешенного значения по каждому предмету за год. Итоговое среднее значение за 1 семестр не имеет значения.\n2. Суммирование вычисленных средних\n3. Расчет среднего арифметического суммированных чисел + The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\nAverage of grades only from selected semester:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\nAverage of averages from both semesters:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\nAverage of grades from the whole year:\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n2. Adding calculated averages\n3. Calculating the arithmetic average of summed averages Как работает \"Итоговая средняя оценка\"? Итоговая средняя оценка - это среднее арифметическое, рассчитанное из всех имеющихся на данный момент итоговых оценок в семестре.\n\nРассчет происходит следующим образом:\n1. Суммирование итоговых оценок, выставленных преподавателями\n2. Полученная сумма делится на число предметов, по которым выставлены оценки Итоговая средняя оценка @@ -305,10 +297,10 @@ Перенести в корзину Удалить навсегда Письмо успешно удалено - ученик - родитель - опекун - работник + student + parent + guardian + employee Поделиться Печать Тема @@ -317,11 +309,9 @@ Письма не существует Вы должны выбрать как минимум одного получателя Текст сообщения должен содержать как минимум 3 знака - Все почтовые ящики Только непрочитанные Только с вложениями Прочитано: %s - Прочитано: %1$d из %2$d человек %1$d сообщение %1$d сообщения @@ -349,7 +339,6 @@ %1$d выбрано Сообщение удалено - Выбрать почтовый ящик Нет записей о замечаниях и свершениях Баллы @@ -493,8 +482,6 @@ Присутствует на встрече Повестка дня - Place - Topic Объявления школы Нет школьных объявлений @@ -733,10 +720,10 @@ Отвечать с историей сообщений Показывать среднее арифметическое при отсутствии стоимости Поддержка - Политика приватности - Соглашения - Согласие на обработку данных, связанных с объявлениями - Показать рекламу в приложении + Privacy Policy + Agreements + Consent to processing of data related to ads + Show ads in app Посмотреть рекламу для поддержки проекта Согласие на обработку данных Для просмотра рекламы вы должны согласиться с условиями обработки данных нашей Политики конфиденциальности @@ -744,13 +731,13 @@ Политика конфиденциальности Реклама загружается Спасибо за вашу поддержку, возвращайтесь позже для дополнительной рекламы - Можем ли мы использовать ваши данные для показа рекламы? - Вы можете изменить свой выбор в любое время в настройках приложения. Мы можем использовать ваши данные для показа объявлений в соответствии с вашими пожеланиями или, используя меньше данных, отображать неперсональную рекламу. Пожалуйста, ознакомьтесь с нашей политикой конфиденциальности для подробностей - Персонализированная реклама - Неперсонализированная реклама - Я старше 18 лет - Да, персонализировать рекламу - Да, не персонализировать рекламу + Can we use your data to display ads? + You can change your choice anytime in the app settings. We may use your data to display ads tailored to you or, using less of your data, display non-personalized ads. Please see our Privacy Policy for details + Personalized ads + Non-personalized ads + I am over 18 years old + Yes, personalized ads + Yes, non-personalized ads Расширенные Внешний вид и поведение Уведомления diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 4189c5349..1c6eae8c0 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -35,7 +35,7 @@ Email Prihlásenie, číslo PESEL alebo e-mail Heslo - Variácia denníka UONET+ + Variácie denníka UONET+ Mobile API Scraper Hybridné @@ -55,7 +55,7 @@ Neplatný symbol Žiak nebol nájdený. Skontrolujte správnosť symbolu a vybrané varianty denníka UONET+ Vybraný žiak už je prihlásený - Symbol nájdete na stránke denníka v  Uczeń→ Dostęp Mobilny → Wygeneruj kod dostępu.\n\nUistite sa, že ste nastavili správny variant denníka v poli Variácia denníka UONET+ na prvej prihlasovacej obrazovke + Symbol nájdete na stránke denníka v  Uczeń→ Dostęp Mobilny → Zarejestruj urządzenie mobilne.\n\nUistite sa, že ste na predchádzajúcu obrazovke nastaviť správny variant denníka do poľa Variácie denníka UONET+ Vyberte žiakov, ktorí sa majú do aplikácie prihlásiť Iné možnosti V tomto režime nefungujú nasledovné: šťastné číslo, štatistiky triedy, zhrnutie frekvencií, ospravedlnenie neprítomnosti, dokončené lekcie, informácie o škole a prezeranie zoznamu registrovaných zariadení @@ -72,14 +72,6 @@ Obnoviť Žiak je už prihlásený Štandardná - Iné miesta vyhľadávania - Neboli nájdení žiadni aktívni žiaci - Zadajte iný symbol - - Povoliť oznámenia - Povoliť oznámenia, aby ste nezmeškali správu od učiteľa alebo o novej známke - Preskočiť - Zapnúť Manažér účtov Prihlásiť sa @@ -317,11 +309,9 @@ Správa neexistuje Musíte vybrať aspoň 1 príjemca Obsah správy musí mať aspoň 3 znaky - Všetky poštové schránky Iba neprečítané Iba s prílohami Prečítaná: %s - Prečítaná cez: %1$d z %2$d osôb %1$d správa %1$d správy @@ -349,7 +339,6 @@ %1$d vybraných Správy odstránené - Vyberte poštovú schránku Žiadne informácie o poznámkach Body @@ -493,8 +482,6 @@ Prítomnosť na stretnutí Agenda - Miesto - Téma Školské oznámenia Žiadne školské oznámenia @@ -748,7 +735,7 @@ Voľbu môžete kedykoľvek zmeniť v nastavení aplikácie. Môžeme použiť vaše údaje na zobrazenie reklám šitých pre vás alebo pomocou menej vašich dát zobrazovať neprispôsobené reklamy. Podrobnosti nájdete v našich Zásadách ochrany osobných údajov Prispôsobené reklamy Neprispôsobené reklamy - Mám viac ako 18 rokov + Mám ukončené 18 rokov Áno, prispôsobené reklamy Áno, neprispôsobené reklamy Pokročilé diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 99c340650..f90e78e7d 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -55,7 +55,7 @@ Неправильний symbol Студента не знайдено. Перевірте symbol та обранний тип щоденника UONET+ Цього учня вже авторизовано - The symbol can be found on the register page in Uczeń → Dostęp Mobilny → Wygeneruj kod dostępu.\n\nMake sure that you have set the appropriate register variant in the UONET+ register variant field on the first login screen + Symbol можна знайти на сторінці реєстрації в  Uczeń→ Dostęp Mobilny → Zarejestruj urządzenie mobilne.\n\nПереконайтесь, що ви встановили відповідний тип щоденника в полі Тип щоденника UONET+ на попередньому екрані Виберіть учнів для авторизації в додатку Інші варіанти У цьому режимі не працюють: щасливий номер, статистика класу по оцінкам, статистика відвідуваності та уроків, інформація про школу та список зареєстрованих пристроїв @@ -72,22 +72,14 @@ Відновити Учня вже авторизовано Стандартний - Other search locations - No active students found - Enter a different symbol - - Enable notifications - Enable notifications so you don\'t miss message from teacher or new grade - Skip - Enable Змінити облікові записи Увійти Минув термін дії сесії Минув термін дії сесії, авторизуйтеся знову - Підтримка додатку - Вам подобається цей додаток? Підтримайте його розвиток, увімкнувши неінвазивну рекламу, яку ви можете відключити в будь-який час - Увімкнути рекламу + Application support + Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time + Enable ads Оцінка %d семестр @@ -105,7 +97,7 @@ Передбачувана оцінка Розрахована середня оцінка Як працює \"Розрахована середня оцінка\"? - Розрахована середня оцінка - це середнє арифметичне, обчислене з середніх оцінок з предметів. Це дозволяє дізнатися приблизну кінцеву середню оцінку. Вона розраховується спосібом, обраним користувачем у налаштуваннях програми. Рекомендується вибрати відповідний варіант, тому що кожна школа по різному розраховує середню оцінку. Крім того, якщо у вашій школі повідомляється середня оцінка з предметів на сторінці Vulcan, програма тільки завантажує ці оцінки і не розраховує їх самостійно. Це можна змінити шляхом примусового розрахунку середньоЇ оцінки в налаштуваннях програми.\n\nСередні оцінки тільки за обраний семестр:\n1. Розрахунок середньозваженого числа для кожного предмета в даному семестрі\n2. Сумування розрахованих числ\n3. Розрахунок середнього арифметичного з сумованих чисел\n\nСереднє значення з обох семестрів:\n1. Обчислення середньозваженого числа для кожного предмета у 1 та 2 семестрі\n2. Обчислення середнього арифметичного з розрахованих середньозважених числ за 1 та 2 семестри для кожного предмета.\n3. Додавання розрахованих середніх\n4. Розрахунок середнього арифметичного підсумованих середніх значень\n\nСереднє значення оцінок за весь рік: \n1. Розрахунок середньозваженого числа за рік для кожного предмета. Підсумковий середній показник у 1-му семестрі не має значення.\n2. Сумування розрахованих середніх\n3. Обчислення середнього арифметичного з суммованих середніх + The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\nAverage of grades only from selected semester:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\nAverage of averages from both semesters:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\nAverage of grades from the whole year:\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n2. Adding calculated averages\n3. Calculating the arithmetic average of summed averages Як працює \"Підсумкова середня оцінка\"? Підсумкове середнє значення - це середнє арифметичне, обчислене з усіх наявних наразі підсумкових оцінок у даному семестрі. \n\nСхема обчислення складається з таких кроків:\n1. Сумування підсумкових оцінок, виставленних викладачами\n2. Ділення на кількість предметів, з яких виставлені ці оцінки Підсумкова середня оцінка @@ -228,7 +220,7 @@ Всі в серії Час початку Час завершення - Час завершення має бути пізніше часу початку + Час завершення має бути більшим, ніж час початку Підсумок відвідуваності Відсутність зі шкільних причин @@ -305,10 +297,10 @@ Перемістити до кошика Видалити назавжди Лист було успішно видалено - учень - родич - опікун - працівник + student + parent + guardian + employee Поділитись Друк Тема @@ -317,11 +309,9 @@ Такого листа не існує Необхідно обрати принаймні 1 адресата Зміст листа повинен складатися принаймні з 3 знаків - Усі поштові скриньки Лише непрочитані Тільки з вкладеннями Прочитаний: %s - Прочитано: %1$d з %2$d осіб %1$d лист %1$d листи @@ -348,8 +338,7 @@ %1$d вибрано %1$d вибрано - Листи видалено - Вибрати поштову скриньку + Листи видалені Немає інформації о зауваженнях Бали @@ -493,8 +482,6 @@ Присутність на зустрічі Порядок денний - Place - Topic Оголошення школи Немає шкільних оголошень @@ -733,10 +720,10 @@ Відповісти з історією повідомлень Вилічити середню аритметичну, якщо оцінка немає вартості Підтримка - Політика конфіденційності - Угоди - Згода на обробку даних, пов\'язаних з рекламою - Показувати рекламу в додатку + Privacy Policy + Agreements + Consent to processing of data related to ads + Show ads in app Подивіться одну рекламу для підтримки проєкту Згода в обробці даних Щоб переглянути рекламу, ви повинні погодитися з умовами обробки даних нашої Політики конфіденційності @@ -744,13 +731,13 @@ Політика конфіденційності Реклама завантажується Дякуємо за вашу підтримку, повертайтеся пізніше для більшої кількості реклам - Чи можемо ми використовувати ваші дані для висвітлювання реклами? - Ви можете змінити свій вибір в будь-який час в налаштуваннях додатку. Ми можемо використовувати ваші дані для висвітлювання реклами, адаптованої до вас або, використовуючи менше ваших даних, висвітлювати неперсоналізовану рекламу. Перегляньте нашу Політику конфіденційності для подробиць - Персоналізована реклама - Неперсоналізована реклама - Мені більше 18 років - Так, персоналізована реклама - Так, неперсоналізована реклама + Can we use your data to display ads? + You can change your choice anytime in the app settings. We may use your data to display ads tailored to you or, using less of your data, display non-personalized ads. Please see our Privacy Policy for details + Personalized ads + Non-personalized ads + I am over 18 years old + Yes, personalized ads + Yes, non-personalized ads Додатково Вигляд та поведінка Сповіщення diff --git a/app/src/main/res/values/api_hosts.xml b/app/src/main/res/values/api_hosts.xml index 04f4a12bf..8413d68e4 100644 --- a/app/src/main/res/values/api_hosts.xml +++ b/app/src/main/res/values/api_hosts.xml @@ -6,9 +6,8 @@ Gdańska Platforma Edukacyjna Lubelski Portal Oświatowy EduNet Miasta Tarnowa - Platforma Edukacyjna Koszalina - Gmina-miasto Tomaszów Mazowiecki - System zarządzania oświatą ResMan Rzeszów + Platforma Edukacyjna Koszalina Rawa Mazowiecka - Platforma vEdukacja Zduńska Wola - e-Urząd Sieradz - Portal oświatowy @@ -28,6 +27,7 @@ https://edu.gdansk.pl https://edu.lublin.eu https://umt.tarnow.pl + https://resman.pl https://eduportal.koszalin.pl https://vulcan.net.pl/?login https://vulcan.net.pl/?login @@ -40,9 +40,7 @@ https://vulcan.net.pl/?login https://vulcan.net.pl/?login https://vulcan.net.pl/?login - https://vulcan.net.pl/?login - https://vulcan.net.pl/?login - https://fakelog.cf/?email + http://fakelog.cf/?email Default @@ -50,9 +48,8 @@ gdansk lublin tarnow + rzeszow koszalin - tomaszowmazowieckiprojekt - rzeszowprojekt rawamazowiecka zdunskawola sieradz diff --git a/app/src/main/res/values/api_symbols.xml b/app/src/main/res/values/api_symbols.xml index 4b61db48d..6f9b1739d 100644 --- a/app/src/main/res/values/api_symbols.xml +++ b/app/src/main/res/values/api_symbols.xml @@ -4,11 +4,13 @@ Andrychów Augustów Baranów Sandomierski + Bartoszyce Będzin Bełchatów Bełżyce Biała Podlaska Biała Rawska + Białogard Biały Bór Białystok Biecz @@ -16,9 +18,11 @@ Bielsko-Biała Bierawa Bierutów + Biskupice Blachownia Błaszki Błonie + Bochnia Bogatynia Boguchwała Boguty-Pianki @@ -41,7 +45,6 @@ Chełmża Chocianów Chodzież - Chojnice Chojnów Chorzów Ciechanów @@ -55,9 +58,7 @@ Dąbrowa Górnicza Dąbrowa Tarnowska Dębica - Dębno Dobrzeń Wielki - Dobrzeń Wielki 2 Dobrzyń Nad Wisłą Dolnośląskie Duszniki-Zdrój @@ -75,9 +76,6 @@ Głogów Małopolski Głowno Głubczyce - Głubczyce 2 - Głuchołazy - Gmina Abramów Gmina Adamówka Gmina Aleksandrów Kujawski Gmina Aleksandrów Łódzki @@ -89,17 +87,14 @@ Gmina Bądkowo Gmina Bałtów Gmina Baranów + Gmina Barciany Gmina Barcin - Gmina Barczewo Gmina Baruchowo - Gmina Batorz Gmina Będzino Gmina Bełchatów - Gmina Besko Gmina Białaczów Gmina Białe Błota - Gmina Białopole - Gmina Bielsk + Gmina Bielsk Podlaski Gmina Bircza Gmina Błażowa Gmina Błędów @@ -109,6 +104,7 @@ Gmina Bobrowniki Gmina Bodzentyn Gmina Bogoria + Gmina Bojanów Gmina Bojanowo Gmina Bojszowy Gmina Bolesławiec @@ -117,14 +113,10 @@ Gmina Borów Gmina Borowa Gmina Borzęcin - Gmina Borzytuchom - Gmina Bralin Gmina Branice Gmina Braniewo - Gmina Brańszczyk Gmina Brąszewice Gmina Brenna - Gmina Brok Gmina Brzeg Dolny Gmina Brzeziny Gmina Brzeźnio @@ -133,14 +125,13 @@ Gmina Brzuze Gmina Brzyska Gmina Buczek + Gmina Buczkowice Gmina Budzów Gmina Budzyń - Gmina Bukowina Tatrzańska Gmina Bukowsko Gmina Byczyna Gmina Bystra-Sidzina - Gmina Cegłów - Gmina Cekcyn + Gmina Bytoń Gmina Ceków-Kolonia Gmina Celestynów Gmina Cewice @@ -148,25 +139,16 @@ Gmina Chełm Gmina Chełmiec Gmina Chełmno - Gmina Chłopice Gmina Chmielnik - Gmina Chociwel Gmina Chocz Gmina Chodel - Gmina Chodów Gmina Chojnice Gmina Chojnów - Gmina Chotcza - Gmina Chrząstowice Gmina Chrzypsko Wielkie Gmina Chybie Gmina Ciasna - Gmina Ciechanów Gmina Ciechocin - Gmina Cielądz - Gmina Cieszanów Gmina Ciężkowice - Gmina Cisek Gmina Cisna Gmina Cmolas Gmina Cyców @@ -174,26 +156,19 @@ Gmina Czarna Gmina Czarnków Gmina Czarny Dunajec - Gmina Czastary Gmina Czechowice-Dziedzice Gmina Czernichów Gmina Czerniejewo - Gmina Czerniewice - Gmina Czernikowo Gmina Czerwionka-Leszczyny - Gmina Czerwonak + Gmina Czerwonka Gmina Człuchów Gmina Czosnów - Gmina Dąbrowa Zielona - Gmina Dąbrowice Gmina Damasławek Gmina Damnica Gmina Darłowo Gmina Dębe Wielkie Gmina Dębica Gmina Dębno - Gmina Dębowa Kłoda - Gmina Debrzno Gmina Dłutów Gmina Dobczyce Gmina Dobra @@ -201,31 +176,19 @@ Gmina Dobrodzień Gmina Dobroń Gmina Dobrzany - Gmina Dobrzyca Gmina Dobrzyniewo Duże - Gmina Dolsk Gmina Dominowo Gmina Dorohusk - Gmina Doruchów - Gmina Dragacz - Gmina Drawsko - Gmina Drużbice Gmina Drzewica Gmina Dubiecko - Gmina Dubienka Gmina Dukla Gmina Dwikozy - Gmina Dydnia Gmina Dynów Gmina Dziadowa Kłoda Gmina Działoszyce - Gmina Dziemiany Gmina Dzierżoniów - Gmina Dzwola Gmina Elbląg - Gmina Ełk - Gmina Fredropol - Gmina Garbatka-Letnisko + Gmina Fajsławice Gmina Garbów Gmina Garwolin Gmina Gąsawa @@ -235,37 +198,29 @@ Gmina Gdów Gmina Gielniów Gmina Gierałtowice + Gmina Glinojeck Gmina Głogów - Gmina Głogówek Gmina Głuchów - Gmina Głusk Gmina Głuszyca Gmina Gniew - Gmina Gniewino Gmina Gniewoszów Gmina Gniezno Gmina Goczałkowice-Zdrój Gmina Godkowo Gmina Godów Gmina Godziesze Wielkie - Gmina Godziszów Gmina Gołańcz - Gmina Gołcza Gmina Goleszów Gmina Golina Gmina Golub-Dobrzyń - Gmina Gołuchów - Gmina Gomunice Gmina Goraj Gmina Gorlice Gmina Górno - Gmina Górzyca Gmina Gościeradów Gmina Gostyń Gmina Gostynin Gmina Goszczyn Gmina Gózd - Gmina Grabica Gmina Grabów Gmina Grabowiec Gmina Grabów Nad Pilicą @@ -284,52 +239,45 @@ Gmina Grudziądz Gmina Gruta Gmina Grybów - Gmina Gryfice - Gmina Grzmiąca Gmina Haczów Gmina Halinów Gmina Hańsk Gmina Harasiuki Gmina Hażlach Gmina Herby - Gmina Horodło Gmina Hrubieszów Gmina Huszlew Gmina Hyżne Gmina Imielno Gmina Inowrocław - Gmina Irządze Gmina Istebna - Gmina Iwanowice Gmina Iwierzyce Gmina Iwonicz-Zdrój Gmina Izabelin Gmina Izbica - Gmina Izbicko - Gmina Jabłoń + Gmina Jadów Gmina Jaktorów - Gmina Jakubów Gmina Janikowo - Gmina Janów Gmina Janowiec Gmina Janów Podlaski - Gmina Jarczów + Gmina Jaraczewo Gmina Jarocin Gmina Jasienica Rosielna - Gmina Jaśliska Gmina Jasło Gmina Jastków Gmina Jastrowie Gmina Jastrząb Gmina Jedlicze + Gmina Jedlińsk + Gmina Jedlnia-Letnisko Gmina Jejkowice Gmina Jemielnica + Gmina Jemielno Gmina Jerzmanowa Gmina Jeżewo Gmina Jeziora Wielkie Gmina Jeziorzany Gmina Jeżowe - Gmina Joniec Gmina Jordanów Gmina Józefów Gmina Józefów Nad Wisłą @@ -337,18 +285,14 @@ Gmina Kąkolewnica Gmina Kamień Gmina Kamienica - Gmina Kamiennik + Gmina Kamieniec Gmina Kamionka Gmina Karczmiska Gmina Kargowa - Gmina Karlino - Gmina Karniewo Gmina Kawęczyn Gmina Kazimierz Biskupi Gmina Kępice - Gmina Kęsowo Gmina Kiełczygłów - Gmina Kietrz Gmina Kikół Gmina Kiszkowo Gmina Kleczew @@ -363,30 +307,22 @@ Gmina Klucze Gmina Kluczewsko Gmina Kobiele Wielkie - Gmina Kobylanka Gmina Kochanowice Gmina Kock Gmina Kodrąb Gmina Kołaczyce Gmina Kołbaskowo - Gmina Kołbiel Gmina Kołczygłowy - Gmina Kołobrzeg Gmina Koluszki Gmina Komańcza - Gmina Komarówka Podlaska Gmina Komorniki Gmina Komprachcice Gmina Konarzyny Gmina Kondratowice - Gmina Koneck Gmina Koniusza Gmina Konopiska Gmina Końskowola - Gmina Konstantynów Gmina Koprzywnica - Gmina Korfantów - Gmina Kórnik Gmina Korsze Gmina Korycin Gmina Korzenna @@ -396,14 +332,10 @@ Gmina Kościerzyna Gmina Kosów Lacki Gmina Kostrzyn - Gmina Koszęcin + Gmina Koszyce Gmina Kotla Gmina Kotuń - Gmina Kowiesy - Gmina Koziegłowy Gmina Kozłów - Gmina Kramsk - Gmina Kraśniczyn Gmina Kraśnik Gmina Krasnobród Gmina Krasnystaw @@ -413,16 +345,12 @@ Gmina Krośnice Gmina Krupski Młyn Gmina Kruszwica - Gmina Krynice Gmina Krynki Gmina Krzanowice Gmina Krzemieniewo - Gmina Krzeszów Gmina Krzymów - Gmina Krzywcza Gmina Krzywiń Gmina Krzyżanowice - Gmina Ksawerów Gmina Książ Wielki Gmina Kunice Gmina Kunów @@ -432,19 +360,15 @@ Gmina Kwilcz Gmina Łabowa Gmina Łabunie - Gmina Łączna - Gmina Lądek Gmina Łambinowice Gmina Lanckorona - Gmina Łańcut - Gmina Łapanów Gmina Łapsze Niżne Gmina Łasin Gmina Łaskarzew Gmina Lasowice Wielkie Gmina Łaszczów + Gmina Laszki Gmina Latowicz - Gmina Łaziska Gmina Łazy Gmina Łęczyca Gmina Łęczyce @@ -454,14 +378,11 @@ Gmina Lelów Gmina Leśna Gmina Leśna Podlaska - Gmina Leśniowice Gmina Lesznowola Gmina Leżajsk Gmina Lichnowy Gmina Limanowa Gmina Linia - Gmina Liniewo - Gmina Lipiany Gmina Lipinki Gmina Lipnik Gmina Lipowa @@ -469,51 +390,43 @@ Gmina Liszki Gmina Liw Gmina Łobez - Gmina Łochów Gmina Łodygowice Gmina Łomazy - Gmina Łomianki - Gmina Łoniów Gmina Łopiennik Górny Gmina Łopuszno - Gmina Łosice Gmina Lubań Gmina Lubartów Gmina Lubasz - Gmina Lubawka Gmina Lubenia Gmina Łubianka Gmina Lubicz - Gmina Lubień Gmina Lubiewo Gmina Lubin Gmina Łubniany Gmina Lubochnia + Gmina Lubomia Gmina Luboń - Gmina Lubsza - Gmina Lubycza Królewska Gmina Łuków Gmina Łukowica Gmina Lutowiska - Gmina Lututów Gmina Luzino Gmina Łużna Gmina Łysomice - Gmina Maciejowice Gmina Magnuszew - Gmina Majdan Królewski Gmina Maków Podhalański + Gmina Mała Wieś Gmina Malbork Gmina Małdyty Gmina Małkinia Górna Gmina Marcinowice Gmina Margonin Gmina Marianowo - Gmina Markuszów - Gmina Męcinka + Gmina Markusy + Gmina Masłów Gmina Medyka Gmina Mełgiew Gmina Michałów + Gmina Michałowo Gmina Miedziana Góra Gmina Miedźna Gmina Miedźno @@ -522,10 +435,7 @@ Gmina Międzyrzec Podlaski Gmina Międzyzdroje Gmina Miejsce Piastowe - Gmina Miękinia Gmina Mielec - Gmina Mielno - Gmina Mieszkowice Gmina Milanów Gmina Milejów Gmina Milicz @@ -534,26 +444,21 @@ Gmina Miłosław Gmina Milówka Gmina Mińsk Mazowiecki - Gmina Mirów Gmina Mirsk Gmina Młynary - Gmina Modliborzyce Gmina Mogielnica Gmina Mogilany - Gmina Mogilno - Gmina Morawica Gmina Mordy Gmina Moryń Gmina Mrocza Gmina Mrozy - Gmina Mściwojów - Gmina Mstów Gmina Mszana Gmina Mszana Dolna Gmina Murów Gmina Mycielin - Gmina Mykanów + Gmina Mysłakowice Gmina Myślibórz + Gmina Nadarzyn Gmina Namysłów Gmina Nasielsk Gmina Nawojowa @@ -564,25 +469,23 @@ Gmina Niedrzwica Duża Gmina Niedźwiada Gmina Niedźwiedź - Gmina Nowa Karczma + Gmina Niegosławice + Gmina Niwiska Gmina Nowa Ruda Gmina Nowa Wieś Lęborska - Gmina Nowe Gmina Nowe Miasto Gmina Nowe Miasto Nad Wartą - Gmina Nowogród + Gmina Nowogród Bobrzański Gmina Nowosolna Gmina Nowy Kawęczyn - Gmina Nowy Korczyn Gmina Nowy Staw Gmina Nowy Targ Gmina Nowy Tomyśl - Gmina Nozdrzec Gmina Nur Gmina Obrazów Gmina Ochotnica Dolna Gmina Ogrodzieniec - Gmina Olszanica + Gmina Olecko Gmina Olsztynek Gmina Olszyna Gmina Opatowiec @@ -592,15 +495,11 @@ Gmina Osiek Jasielski Gmina Osiek Mały Gmina Osielsko - Gmina Osina - Gmina Osjaków - Gmina Ostroróg Gmina Ostrów Gmina Ostrówek Gmina Ostrów Lubelski Gmina Ostrów Mazowiecka Gmina Ostrów Wielkopolski - Gmina Otmuchów Gmina Otyń Gmina Ożarów Gmina Ożarowice @@ -608,32 +507,27 @@ Gmina Ozorków Gmina Pabianice Gmina Pacanów - Gmina Pacyna Gmina Paczków Gmina Padew Narodowa + Gmina Pajęczno Gmina Pakosław Gmina Pakosławice Gmina Pałecznica Gmina Panki Gmina Parchowo Gmina Parczew - Gmina Pasłęk - Gmina Pątnów + Gmina Pawłosiów Gmina Pawłowice Gmina Pawłowiczki - Gmina Pawonków Gmina Pęcław Gmina Pelplin - Gmina Pępowo Gmina Piaski Gmina Piątnica + Gmina Piecki Gmina Piekoszów - Gmina Pieniężno Gmina Pilchowice - Gmina Pińczów Gmina Pionki - Gmina Płaska - Gmina Platerówka + Gmina Piotrków Trybunalski Gmina Pleśna Gmina Pleszew Gmina Płońsk @@ -641,7 +535,6 @@ Gmina Poczesna Gmina Podedwórze Gmina Podegrodzie - Gmina Podgórzyn Gmina Pokój Gmina Połajewo Gmina Połaniec @@ -650,18 +543,16 @@ Gmina Police Gmina Polkowice Gmina Pomiechówek - Gmina Poniatowa Gmina Popielów Gmina Popów + Gmina Poraj Gmina Potęgowo - Gmina Potok Wielki Gmina Praszka + Gmina Prażmów Gmina Prochowice Gmina Promna Gmina Prószków - Gmina Prusice Gmina Pruszcz Gdański - Gmina Przechlewo Gmina Przecław Gmina Przedecz Gmina Przemęt @@ -671,9 +562,7 @@ Gmina Przodkowo Gmina Przykona Gmina Przyłęk - Gmina Przyrów Gmina Przystajń - Gmina Przytoczna Gmina Puchaczów Gmina Puck Gmina Puławy @@ -681,10 +570,10 @@ Gmina Puszcza Mariańska Gmina Pysznica Gmina Pyzdry - Gmina Raba Wyżna Gmina Rachanie Gmina Raciechowice - Gmina Radgoszcz + Gmina Racławice + Gmina Radecznica Gmina Radków Gmina Radłów Gmina Radomin @@ -692,29 +581,16 @@ Gmina Radomyśl Nad Sanem Gmina Radoszyce Gmina Radwanice - Gmina Radymno - Gmina Radziejów Gmina Radziłów - Gmina Rajgród - Gmina Raków - Gmina Rakszawa Gmina Rawa Mazowiecka - Gmina Regnów Gmina Reńska Wieś - Gmina Rogóźno - Gmina Rokitno - Gmina Ropa Gmina Rossosz Gmina Rozprza Gmina Ruciane-Nida Gmina Ruda-Huta Gmina Rudna Gmina Rudniki - Gmina Rudnik Nad Sanem - Gmina Rudziniec Gmina Rusiec - Gmina Rusinów - Gmina Rybczewice Gmina Rychliki Gmina Rychtal Gmina Ryczywół @@ -722,39 +598,32 @@ Gmina Rypin Gmina Rytro Gmina Rytwiany + Gmina Rząśnia Gmina Rzeczyca Gmina Rzepiennik Strzyżewski Gmina Rzepin - Gmina Rzezawa Gmina Rzgów Gmina Sadki Gmina Sadowne Gmina Samborzec Gmina Sanok - Gmina Sawin Gmina Ścinawa Gmina Sędziejowice - Gmina Sejny - Gmina Sękowa Gmina Sępopol Gmina Serokomla Gmina Sianów Gmina Sicienko Gmina Sieciechów Gmina Siedlce - Gmina Siedliszcze Gmina Siemiatycze - Gmina Siemień Gmina Siemyśl Gmina Siennica Gmina Siennica Różana Gmina Sienno Gmina Siepraw Gmina Sieradz - Gmina Sieraków Gmina Sierakowice Gmina Siewierz - Gmina Sitkówka-Nowiny Gmina Sitno Gmina Skarżysko Kościelne Gmina Skępe @@ -762,22 +631,16 @@ Gmina Skoczów Gmina Skoki Gmina Skołyszyn - Gmina Skrwilno Gmina Skrzyszów Gmina Skulsk - Gmina Skwierzyna Gmina Sława - Gmina Śliwice Gmina Słopnice - Gmina Słubice Gmina Słupca Gmina Słupia - Gmina Słupia (Konecka) - Gmina Śmigiel Gmina Sobienie-Jeziory - Gmina Sobolew Gmina Sobótka Gmina Sokółka + Gmina Sokoły Gmina Solina Gmina Sośnicowice Gmina Sośnie @@ -792,16 +655,11 @@ Gmina Stare Miasto Gmina Stare Pole Gmina Starogard Gdański - Gmina Stary Brus - Gmina Stary Dzierzgoń - Gmina Stary Targ Gmina Stawiszyn - Gmina Stepnica Gmina Stoczek Łukowski Gmina Stopnica Gmina Strawczyn Gmina Stryków - Gmina Stryszawa Gmina Stryszów Gmina Strzałkowo Gmina Strzelce Opolskie @@ -810,43 +668,38 @@ Gmina Strzyżewice Gmina Stupsk Gmina Subkowy - Gmina Suchań Gmina Suchedniów Gmina Suchożebry Gmina Suchy Las Gmina Sulechów Gmina Sulęcin - Gmina Sulejów Gmina Sulików Gmina Sulmierzyce Gmina Sułów Gmina Susiec - Gmina Świercze - Gmina Świerczów - Gmina Świerklany + Gmina Świerklaniec Gmina Świerzawa Gmina Świeszyno Gmina Świlcza Gmina Szadek Gmina Szaflary Gmina Szastarka - Gmina Szczawin Kościelny Gmina Szczebrzeszyn Gmina Szczekociny Gmina Szczerców + Gmina Szczutowo Gmina Szczytna Gmina Szczytniki - Gmina Szczytno + Gmina Szemud Gmina Szerzyny Gmina Szlichtyngowa - Gmina Szreńsk - Gmina Szudziałowo Gmina Szydłów Gmina Tarłów Gmina Tarnów Gmina Tarnowiec Gmina Tarnów Opolski Gmina Teresin + Gmina Terespol Gmina Tereszpol Gmina Tłuchowo Gmina Tłuszcz @@ -856,15 +709,12 @@ Gmina Toszek Gmina Trąbki Wielkie Gmina Trzebiatów - Gmina Trzebielino Gmina Trzebinia + Gmina Trzeszczany Gmina Trzyciąż - Gmina Trzydnik Duży Gmina Tuchów - Gmina Tułowice Gmina Turośń Kościelna Gmina Tuszów Narodowy - Gmina Tworóg Gmina Tyczyn Gmina Tymbark Gmina Tyrawa Wołoska @@ -873,21 +723,15 @@ Gmina Ulan-Majorat Gmina Ulanów Gmina Ułęż - Gmina Ulhówek Gmina Urszulin Gmina Urzędów - Gmina Uście Gorlickie Gmina Uścimów Gmina Wąchock - Gmina Wądroże Wielkie Gmina Wągrowiec - Gmina Walce Gmina Wąpielsk Gmina Wasilków - Gmina Wąsosz Gmina Wąwolnica Gmina Wejherowo - Gmina Werbkowice Gmina Wiązów Gmina Wiązowna Gmina Wicko @@ -895,21 +739,16 @@ Gmina Wielbark Gmina Wieleń Gmina Wielgie - Gmina Wielgomłyny Gmina Wieliszew Gmina Wielka Nieszawka Gmina Wieniawa Gmina Wieprz Gmina Wieruszów - Gmina Wierzbinek Gmina Wierzbno - Gmina Wierzchlas Gmina Wierzchosławice Gmina Wietrzychowice Gmina Wijewo - Gmina Wilczyce Gmina Wilczyn - Gmina Wilkołaz Gmina Wilków Gmina Wilkowice Gmina Winnica @@ -920,14 +759,12 @@ Gmina Witkowo Gmina Władysławów Gmina Wleń - Gmina Włocławek Gmina Włodawa Gmina Włoszczowa Gmina Wodzierady Gmina Wodzisław Gmina Wojcieszków Gmina Wojnicz - Gmina Wojsławice Gmina Wola Krzysztoporska Gmina Wolanów Gmina Wolbrom @@ -938,18 +775,15 @@ Gmina Wręczyca Wielka Gmina Wronki Gmina Wyrzysk - Gmina Wysokie + Gmina Zabierzów Gmina Żabno Gmina Żagań - Gmina Zagórów + Gmina Zagórz Gmina Zaklików Gmina Zakroczym Gmina Zakrzówek - Gmina Zalesie Gmina Zaleszany - Gmina Załuski Gmina Zamość - Gmina Żarnów Gmina Żarnowiec Gmina Żarów Gmina Zarszyn @@ -961,26 +795,20 @@ Gmina Zbójno Gmina Zbrosławice Gmina Zduńska Wola + Gmina Zduny Gmina Zdzieszowice - Gmina Zębowice Gmina Zebrzydowice - Gmina Żegocina Gmina Żelazków - Gmina Zembrzyce Gmina Zgierz Gmina Zgorzelec Gmina Ziębice Gmina Zielonki Gmina Zławieś Wielka - Gmina Złota - Gmina Złotniki Kujawskie Gmina Żmudź Gmina Żnin Gmina Żółkiewka Gmina Żołynia Gmina Żukowice - Gmina Żurawica - Gmina Żyraków Gmina Żyrzyn Gmina Żytno Gniezno @@ -989,19 +817,19 @@ Góra Góra Kalwaria Gorlice - Górzno Gorzów Śląski Gorzów Wielkopolski Gostynin Grajewo Grodzisk Mazowiecki + Gronowo Elbląskie Grudziądz - Grybów Gryfino Gryfów Śląski Hel Hrubieszów Inowrocław + Iwanowice Izbica Kujawska Jabłonowo Pomorskie Janowiec Wielkopolski @@ -1011,6 +839,7 @@ Jasło Jastrzębie-Zdrój Jawor + Jaworzno Jedlina-Zdrój Jelcz-Laskowice Jelenia Góra @@ -1031,9 +860,9 @@ Kępno Kętrzyn Kielce + Kiełczygłów Kłodawa Kłodzko - Kluczbork Knurów Kobyłka Koło @@ -1063,13 +892,11 @@ Krzeszowice Krzyż Wielkopolski Książ Wielkopolski + Kudowa-Zdrój Kujawsko-Pomorskie - Kutno Kuźnia Raciborska - Kwidzyn Łabiszyn Lądek-Zdrój - Łańcut Łapy Łask Łaskarzew @@ -1081,10 +908,10 @@ Legnica Leszno Lewin Brzeski - Lewin Brzeski 2 Leżajsk Limanowa Lipno + Lipsko Łódź Łódzkie Łowicz @@ -1101,8 +928,11 @@ Lwówek Śląski Malbork Małopolskie + Marciszów Marki + Masłowice Mazowieckie + Miastko Michałowice Miechów Międzyrzec Podlaski @@ -1110,7 +940,6 @@ Mielec Milanówek Mińsk Mazowiecki - Mniszków Mosina Mrągowo Mrągowski @@ -1120,17 +949,18 @@ Mysłowice Myszków Nakło Nad Notecią + Nasielsk Niemodlin Niepołomice Nisko Nowa Dęba Nowa Sarzyna - Nowa Sól Nowe Miasteczko Nowe Skalmierzyce Nowogard Nowogród Bobrzański Nowogrodziec + Nowosolna Nowy Dwór Mazowiecki Nowy Sącz Nowy Targ @@ -1144,8 +974,6 @@ Opoczno Opole Opole Lubelskie - Opolskie - Orzesze Osieczna Osiecznica Ostróda @@ -1163,16 +991,13 @@ Piekary Śląskie Pieńsk Piła - Pilzno Piotrków Trybunalski Pisz Płock Płońsk Pniewy - Pobiedziska Podkarpackie Podkowa Leśna - Podlaskie Połczyn-Zdrój Pomorskie Poniec @@ -1181,7 +1006,7 @@ Powiat augustowski Powiat będziński Powiat bełchatowski - Powiat białostocki + Powiat białobrzeski Powiat bialski Powiat bielski Powiat bieszczadzki @@ -1207,7 +1032,6 @@ Powiat człuchowski Powiat dąbrowski Powiat dębicki - Powiat drawski Powiat działdowski Powiat dzierżoniowski Powiat elbląski @@ -1222,11 +1046,10 @@ Powiat goleniowski Powiat golubsko-dobrzyński Powiat gorlicki - Powiat górowski Powiat gorzowski Powiat gostyński - Powiat grajewski Powiat grójecki + Powiat grudziądzki Powiat gryficki Powiat gryfiński Powiat hajnowski @@ -1241,7 +1064,6 @@ Powiat jędrzejowski Powiat jeleniogórski Powiat kaliski - Powiat kamiennogórski Powiat kamieński Powiat kartuski Powiat kazimierski @@ -1266,7 +1088,6 @@ Powiat krośnieński Powiat krotoszyński Powiat kutnowski - Powiat łańcucki Powiat łaski Powiat lęborski Powiat łęczycki @@ -1281,7 +1102,6 @@ Powiat lipski Powiat łobeski Powiat łódzki wschodni - Powiat łosicki Powiat łowicki Powiat lubaczowski Powiat lubański @@ -1302,11 +1122,9 @@ Powiat myślenicki Powiat myszkowski Powiat nakielski - Powiat namysłowski Powiat nidzicki Powiat niżański Powiat nowodworski - Powiat nowomiejski Powiat nowosądecki Powiat nowosolski Powiat nowotarski @@ -1342,6 +1160,7 @@ Powiat proszowicki Powiat prudnicki Powiat pruszkowski + Powiat przasnyski Powiat przemyski Powiat przeworski Powiat przysuski @@ -1364,7 +1183,6 @@ Powiat rzeszowski Powiat sandomierski Powiat sanocki - Powiat sejneński Powiat sępoleński Powiat siedlecki Powiat siemiatycki @@ -1392,7 +1210,6 @@ Powiat świdnicki Powiat świdwiński Powiat świebodziński - Powiat świecki Powiat szamotulski Powiat szczycieński Powiat sztumski @@ -1411,7 +1228,6 @@ Powiat wągrowiecki Powiat wałecki Powiat warszawski zachodni - Powiat węgorzewski Powiat węgrowski Powiat wejherowski Powiat wielicki @@ -1431,6 +1247,7 @@ Powiat wyszkowski Powiat ząbkowicki Powiat żagański + Powiat zambrowski Powiat zamojski Powiat żarski Powiat zawierciański @@ -1441,33 +1258,34 @@ Powiat złotoryjski Powiat złotowski Powiat żniński + Powiat żuromiński Powiat żyrardowski Powiat żywiecki Poznań + Prostki Proszowice Prudnik - Pruszcz Gdański Pruszków Przasnysz Przemyśl Przeworsk Przysucha Pszczyna + Pszów Puck Puławy - Pułtusk - Puszczykowo Pyskowice Rabka-Zdrój Raciąż Racibórz + Raciechowice Radom Radomsko - Radomyśl Wielki Radymno Radziejów Radzionków Radzyń Podlaski + Raków Rawa Mazowiecka Rawicz Reda @@ -1481,7 +1299,6 @@ Rymanów Rypin Rzeszów - Rzeszów projekt Sandomierz Sanok Sędziszów Małopolski @@ -1489,6 +1306,7 @@ Siedlce Siemianowice Śląskie Siemiatycze + Sieniawa Sieradz Skarżysko-Kamienna Skawina @@ -1507,15 +1325,17 @@ Środa Śląska Środa Wielkopolska Starachowice - Stargard Starogard Gdański Stary Sącz Staszów Stronie Śląskie + Strzegom Strzyżów + Suchy Las Sulejówek Sułkowice Sulmierzyce + Suwalski Swarzędz Świdnica Świdnik @@ -1538,10 +1358,8 @@ Terespol Tomaszów Lubelski Tomaszów Mazowiecki - Tomaszów Mazowiecki projekt Toruń Trzcianka - Trzcińsko-Zdrój Trzebnica Trzemeszno Tuliszków @@ -1554,7 +1372,7 @@ Ustrzyki Dolne Wadowice Wągrowiec - Wałcz + Wałbrzych Warmińsko-Mazurskie Warszawa Wąsosz @@ -1563,7 +1381,7 @@ Więcbork Wieliczka Wielkopolskie - Wieluń + Wizna Władysławowo Włocławek Włodawa @@ -1592,7 +1410,6 @@ Zielona Góra Zielonka Złotoryja - Złotów Żory Zwoleń Żyrardów @@ -1601,11 +1418,13 @@ andrychow augustow baranowsandomierski + bartoszyce bedzin belchatow belzyce bialapodlaska bialarawska + bialogard bialybor bialystok biecz @@ -1613,9 +1432,11 @@ bielskobiala bierawa bierutow + biskupice blachownia blaszki blonie + bochnia bogatynia boguchwala bogutypianki @@ -1638,7 +1459,6 @@ chelmza chocianow chodziez - chojnice chojnow chorzow ciechanow @@ -1652,9 +1472,7 @@ dabrowagornicza dabrowatarnowska debica - debno dobrzenwielki - dobrzenwielki2 dobrzynnadwisla dolnoslaskie dusznikizdroj @@ -1672,9 +1490,6 @@ glogowmalopolski glowno glubczyce - glubczyce2 - glucholazy - gminaabramow gminaadamowka gminaaleksandrowkujawski gminaaleksandrowlodzki @@ -1686,17 +1501,14 @@ gminabadkowo gminabaltow gminabaranow + gminabarciany gminabarcin - gminabarczewo gminabaruchowo - gminabatorz gminabedzino gminabelchatow - gminabesko gminabialaczow gminabialeblota - gminabialopole - gminabielsk + gminabielskpodlaski gminabircza gminablazowa gminabledow @@ -1706,6 +1518,7 @@ gminabobrowniki gminabodzentyn gminabogoria + gminabojanow gminabojanowo gminabojszowy gminaboleslawiec @@ -1714,14 +1527,10 @@ gminaborow gminaborowa gminaborzecin - gminaborzytuchom - gminabralin gminabranice gminabraniewo - gminabranszczyk gminabraszewice gminabrenna - gminabrok gminabrzegdolny gminabrzeziny gminabrzeznio @@ -1730,14 +1539,13 @@ gminabrzuze gminabrzyska gminabuczek + gminabuczkowice gminabudzow gminabudzyn - gminabukowinatatrzanska gminabukowsko gminabyczyna gminabystrasidzina - gminaceglow - gminacekcyn + gminabyton gminacekowkolonia gminacelestynow gminacewice @@ -1745,25 +1553,16 @@ gminachelm gminachelmiec gminachelmno - gminachlopice gminachmielnik - gminachociwel gminachocz gminachodel - gminachodow gminachojnice gminachojnow - gminachotcza - gminachrzastowice gminachrzypskowielkie gminachybie gminaciasna - gminaciechanow gminaciechocin - gminacieladz - gminacieszanow gminaciezkowice - gminacisek gminacisna gminacmolas gminacycow @@ -1771,26 +1570,19 @@ gminaczarna gminaczarnkow gminaczarnydunajec - gminaczastary gminaczechowicedziedzice gminaczernichow gminaczerniejewo - gminaczerniewice - gminaczernikowo gminaczerwionkaleszczyny - gminaczerwonak + gminaczerwonka gminaczluchow gminaczosnow - gminadabrowazielona - gminadabrowice gminadamaslawek gminadamnica gminadarlowo gminadebewielkie gminadebica gminadebno - gminadebowakloda - gminadebrzno gminadlutow gminadobczyce gminadobra @@ -1798,31 +1590,19 @@ gminadobrodzien gminadobron gminadobrzany - gminadobrzyca gminadobrzyniewoduze - gminadolsk gminadominowo gminadorohusk - gminadoruchow - gminadragacz - gminadrawsko - gminadruzbice gminadrzewica gminadubiecko - gminadubienka gminadukla gminadwikozy - gminadydnia gminadynow gminadziadowakloda gminadzialoszyce - gminadziemiany gminadzierzoniow - gminadzwola gminaelblag - gminaelk - gminafredropol - gminagarbatkaletnisko + gminafajslawice gminagarbow gminagarwolin gminagasawa @@ -1832,37 +1612,29 @@ gminagdow gminagielniow gminagieraltowice + gminaglinojeck gminaglogow - gminaglogowek gminagluchow - gminaglusk gminagluszyca gminagniew - gminagniewino gminagniewoszow gminagniezno gminagoczalkowicezdroj gminagodkowo gminagodow gminagodzieszewielkie - gminagodziszow gminagolancz - gminagolcza gminagoleszow gminagolina gminagolubdobrzyn - gminagoluchow - gminagomunice gminagoraj gminagorlice gminagorno - gminagorzyca gminagoscieradow gminagostyn gminagostynin gminagoszczyn gminagozd - gminagrabica gminagrabow gminagrabowiec gminagrabownadpilica @@ -1881,52 +1653,45 @@ gminagrudziadz gminagruta gminagrybow - gminagryfice - gminagrzmiaca gminahaczow gminahalinow gminahansk gminaharasiuki gminahazlach gminaherby - gminahorodlo gminahrubieszow gminahuszlew gminahyzne gminaimielno gminainowroclaw - gminairzadze gminaistebna - gminaiwanowice gminaiwierzyce gminaiwoniczzdroj gminaizabelin gminaizbica - gminaizbicko - gminajablon + gminajadow gminajaktorow - gminajakubow gminajanikowo - gminajanow gminajanowiec gminajanowpodlaski - gminajarczow + gminajaraczewo gminajarocin gminajasienicarosielna - gminajasliska gminajaslo gminajastkow gminajastrowie gminajastrzab gminajedlicze + gminajedlinsk + gminajedlnialetnisko gminajejkowice gminajemielnica + gminajemielno gminajerzmanowa gminajezewo gminajeziorawielkie gminajeziorzany gminajezowe - gminajoniec gminajordanow gminajozefow gminajozefownadwisla @@ -1934,18 +1699,14 @@ gminakakolewnica gminakamien gminakamienica - gminakamiennik + gminakamieniec gminakamionka gminakarczmiska gminakargowa - gminakarlino - gminakarniewo gminakaweczyn gminakazimierzbiskupi gminakepice - gminakesowo gminakielczyglow - gminakietrz gminakikol gminakiszkowo gminakleczew @@ -1960,30 +1721,22 @@ gminaklucze gminakluczewsko gminakobielewielkie - gminakobylanka gminakochanowice gminakock gminakodrab gminakolaczyce gminakolbaskowo - gminakolbiel gminakolczyglowy - gminakolobrzeg gminakoluszki gminakomancza - gminakomarowkapodlaska gminakomorniki gminakomprachcice gminakonarzyny gminakondratowice - gminakoneck gminakoniusza gminakonopiska gminakonskowola - gminakonstantynow gminakoprzywnica - gminakorfantow - gminakornik gminakorsze gminakorycin gminakorzenna @@ -1993,14 +1746,10 @@ gminakoscierzyna gminakosowlacki gminakostrzyn - gminakoszecin + gminakoszyce gminakotla gminakotun - gminakowiesy - gminakozieglowy gminakozlow - gminakramsk - gminakrasniczyn gminakrasnik gminakrasnobrod gminakrasnystaw @@ -2010,16 +1759,12 @@ gminakrosnice gminakrupskimlyn gminakruszwica - gminakrynice gminakrynki gminakrzanowice gminakrzemieniewo - gminakrzeszow gminakrzymow - gminakrzywcza gminakrzywin gminakrzyzanowice - gminaksawerow gminaksiazwielki gminakunice gminakunow @@ -2029,19 +1774,15 @@ gminakwilcz gminalabowa gminalabunie - gminalaczna - gminaladek gminalambinowice gminalanckorona - gminalancut - gminalapanow gminalapszenizne gminalasin gminalaskarzew gminalasowicewielkie gminalaszczow + gminalaszki gminalatowicz - gminalaziska gminalazy gminaleczyca gminaleczyce @@ -2051,14 +1792,11 @@ gminalelow gminalesna gminalesnapodlaska - gminalesniowice gminalesznowola gminalezajsk gminalichnowy gminalimanowa gminalinia - gminaliniewo - gminalipiany gminalipinki gminalipnik gminalipowa @@ -2066,51 +1804,43 @@ gminaliszki gminaliw gminalobez - gminalochow gminalodygowice gminalomazy - gminalomianki - gminaloniow gminalopiennikgorny gminalopuszno - gminalosice gminaluban gminalubartow gminalubasz - gminalubawka gminalubenia gminalubianka gminalubicz - gminalubien gminalubiewo gminalubin gminalubniany gminalubochnia + gminalubomia gminalubon - gminalubsza - gminalubyczakrolewska gminalukow gminalukowica gminalutowiska - gminalututow gminaluzino gminaluzna gminalysomice - gminamaciejowice gminamagnuszew - gminamajdankrolewski gminamakowpodhalanski + gminamalawies gminamalbork gminamaldyty gminamalkiniagorna gminamarcinowice gminamargonin gminamarianowo - gminamarkuszow - gminamecinka + gminamarkusy + gminamaslow gminamedyka gminamelgiew gminamichalow + gminamichalowo gminamiedzianagora gminamiedzna gminamiedzno @@ -2119,10 +1849,7 @@ gminamiedzyrzecpodlaski gminamiedzyzdroje gminamiejscepiastowe - gminamiekinia gminamielec - gminamielno - gminamieszkowice gminamilanow gminamilejow gminamilicz @@ -2131,26 +1858,21 @@ gminamiloslaw gminamilowka gminaminskmazowiecki - gminamirow gminamirsk gminamlynary - gminamodliborzyce gminamogielnica gminamogilany - gminamogilno - gminamorawica gminamordy gminamoryn gminamrocza gminamrozy - gminamsciwojow - gminamstow gminamszana gminamszanadolna gminamurow gminamycielin - gminamykanow + gminamyslakowice gminamysliborz + gminanadarzyn gminanamyslow gminanasielsk gminanawojowa @@ -2161,25 +1883,23 @@ gminaniedrzwicaduza gminaniedzwiada gminaniedzwiedz - gminanowakarczma + gminaniegoslawice + gminaniwiska gminanowaruda gminanowawiesleborska - gminanowe gminanowemiasto gminanowemiastonadwarta - gminanowogrod + gminanowogrodbobrzanski gminanowosolna gminanowykaweczyn - gminanowykorczyn gminanowystaw gminanowytarg gminanowytomysl - gminanozdrzec gminanur gminaobrazow gminaochotnicadolna gminaogrodzieniec - gminaolszanica + gminaolecko gminaolsztynek gminaolszyna gminaopatowiec @@ -2189,15 +1909,11 @@ gminaosiekjasielski gminaosiekmaly gminaosielsko - gminaosina - gminaosjakow - gminaostrorog gminaostrow gminaostrowek gminaostrowlubelski gminaostrowmazowiecka gminaostrowwielkopolski - gminaotmuchow gminaotyn gminaozarow gminaozarowice @@ -2205,32 +1921,27 @@ gminaozorkow gminapabianice gminapacanow - gminapacyna gminapaczkow gminapadewnarodowa + gminapajeczno gminapakoslaw gminapakoslawice gminapalecznica gminapanki gminaparchowo gminaparczew - gminapaslek - gminapatnow + gminapawlosiow gminapawlowice gminapawlowiczki - gminapawonkow gminapeclaw gminapelplin - gminapepowo gminapiaski gminapiatnica + gminapiecki gminapiekoszow - gminapieniezno gminapilchowice - gminapinczow gminapionki - gminaplaska - gminaplaterowka + gminapiotrkowtrybunalski gminaplesna gminapleszew gminaplonsk @@ -2238,7 +1949,6 @@ gminapoczesna gminapodedworze gminapodegrodzie - gminapodgorzyn gminapokoj gminapolajewo gminapolaniec @@ -2247,18 +1957,16 @@ gminapolice gminapolkowice gminapomiechowek - gminaponiatowa gminapopielow gminapopow + gminaporaj gminapotegowo - gminapotokwielki gminapraszka + gminaprazmow gminaprochowice gminapromna gminaproszkow - gminaprusice gminapruszczgdanski - gminaprzechlewo gminaprzeclaw gminaprzedecz gminaprzemet @@ -2268,9 +1976,7 @@ gminaprzodkowo gminaprzykona gminaprzylek - gminaprzyrow gminaprzystajn - gminaprzytoczna gminapuchaczow gminapuck gminapulawy @@ -2278,10 +1984,10 @@ gminapuszczamarianska gminapysznica gminapyzdry - gminarabawyzna gminarachanie gminaraciechowice - gminaradgoszcz + gminaraclawice + gminaradecznica gminaradkow gminaradlow gminaradomin @@ -2289,29 +1995,16 @@ gminaradomyslnadsanem gminaradoszyce gminaradwanice - gminaradymno - gminaradziejow gminaradzilow - gminarajgrod - gminarakow - gminarakszawa gminarawamazowiecka - gminaregnow gminarenskawies - gminarogozno - gminarokitno - gminaropa gminarossosz gminarozprza gminarucianenida gminarudahuta gminarudna gminarudniki - gminarudniknadsanem - gminarudziniec gminarusiec - gminarusinow - gminarybczewice gminarychliki gminarychtal gminaryczywol @@ -2319,39 +2012,32 @@ gminarypin gminarytro gminarytwiany + gminarzasnia gminarzeczyca gminarzepiennikstrzyzewski gminarzepin - gminarzezawa gminarzgow gminasadki gminasadowne gminasamborzec gminasanok - gminasawin gminascinawa gminasedziejowice - gminasejny - gminasekowa gminasepopol gminaserokomla gminasianow gminasicienko gminasieciechow gminasiedlce - gminasiedliszcze gminasiemiatycze - gminasiemien gminasiemysl gminasiennica gminasiennicarozana gminasienno gminasiepraw gminasieradz - gminasierakow gminasierakowice gminasiewierz - gminasitkowkanowiny gminasitno gminaskarzyskokoscielne gminaskepe @@ -2359,22 +2045,16 @@ gminaskoczow gminaskoki gminaskolyszyn - gminaskrwilno gminaskrzyszow gminaskulsk - gminaskwierzyna gminaslawa - gminasliwice gminaslopnice - gminaslubice gminaslupca gminaslupia - gminaslupiakonecka - gminasmigiel gminasobieniejeziory - gminasobolew gminasobotka gminasokolka + gminasokoly gminasolina gminasosnicowice gminasosnie @@ -2389,16 +2069,11 @@ gminastaremiasto gminastarepole gminastarogardgdanski - gminastarybrus - gminastarydzierzgon - gminastarytarg gminastawiszyn - gminastepnica gminastoczeklukowski gminastopnica gminastrawczyn gminastrykow - gminastryszawa gminastryszow gminastrzalkowo gminastrzelceopolskie @@ -2407,43 +2082,38 @@ gminastrzyzewice gminastupsk gminasubkowy - gminasuchan gminasuchedniow gminasuchozebry gminasuchylas gminasulechow gminasulecin - gminasulejow gminasulikow gminasulmierzyce gminasulow gminasusiec - gminaswiercze - gminaswierczow - gminaswierklany + gminaswierklaniec gminaswierzawa gminaswieszyno gminaswilcza gminaszadek gminaszaflary gminaszastarka - gminaszczawinkoscielny gminaszczebrzeszyn gminaszczekociny gminaszczercow + gminaszczutowo gminaszczytna gminaszczytniki - gminaszczytno + gminaszemud gminaszerzyny gminaszlichtyngowa - gminaszrensk - gminaszudzialowo gminaszydlow gminatarlow gminatarnow gminatarnowiec gminatarnowopolski gminateresin + gminaterespol gminatereszpol gminatluchowo gminatluszcz @@ -2453,15 +2123,12 @@ gminatoszek gminatrabkiwielkie gminatrzebiatow - gminatrzebielino gminatrzebinia + gminatrzeszczany gminatrzyciaz - gminatrzydnikduzy gminatuchow - gminatulowice gminaturosnkoscielna gminatuszownarodowy - gminatworog gminatyczyn gminatymbark gminatyrawawoloska @@ -2470,21 +2137,15 @@ gminaulanmajorat gminaulanow gminaulez - gminaulhowek gminaurszulin gminaurzedow - gminausciegorlickie gminauscimow gminawachock - gminawadrozewielkie gminawagrowiec - gminawalce gminawapielsk gminawasilkow - gminawasosz gminawawolnica gminawejherowo - gminawerbkowice gminawiazow gminawiazowna gminawicko @@ -2492,21 +2153,16 @@ gminawielbark gminawielen gminawielgie - gminawielgomlyny gminawieliszew gminawielkanieszawka gminawieniawa gminawieprz gminawieruszow - gminawierzbinek gminawierzbno - gminawierzchlas gminawierzchoslawice gminawietrzychowice gminawijewo - gminawilczyce gminawilczyn - gminawilkolaz gminawilkow gminawilkowice gminawinnica @@ -2517,14 +2173,12 @@ gminawitkowo gminawladyslawow gminawlen - gminawloclawek gminawlodawa gminawloszczowa gminawodzierady gminawodzislaw gminawojcieszkow gminawojnicz - gminawojslawice gminawolakrzysztoporska gminawolanow gminawolbrom @@ -2535,18 +2189,15 @@ gminawreczycawielka gminawronki gminawyrzysk - gminawysokie + gminazabierzow gminazabno gminazagan - gminazagorow + gminazagorz gminazaklikow gminazakroczym gminazakrzowek - gminazalesie gminazaleszany - gminazaluski gminazamosc - gminazarnow gminazarnowiec gminazarow gminazarszyn @@ -2558,26 +2209,20 @@ gminazbojno gminazbroslawice gminazdunskawola + gminazduny gminazdzieszowice - gminazebowice gminazebrzydowice - gminazegocina gminazelazkow - gminazembrzyce gminazgierz gminazgorzelec gminaziebice gminazielonki gminazlawieswielka - gminazlota - gminazlotnikikujawskie gminazmudz gminaznin gminazolkiewka gminazolynia gminazukowice - gminazurawica - gminazyrakow gminazyrzyn gminazytno gniezno @@ -2586,19 +2231,19 @@ gora gorakalwaria gorlice - gorzno gorzowslaski gorzowwielkopolski gostynin grajewo grodziskmazowiecki + gronowoelblaskie grudziadz - grybow gryfino gryfowslaski hel hrubieszow inowroclaw + iwanowice izbicakujawska jablonowopomorskie janowiecwielkopolski @@ -2608,6 +2253,7 @@ jaslo jastrzebiezdroj jawor + jaworzno jedlinazdroj jelczlaskowice jeleniagora @@ -2628,9 +2274,9 @@ kepno ketrzyn kielce + kielczyglow klodawa klodzko - kluczbork knurow kobylka kolo @@ -2660,13 +2306,11 @@ krzeszowice krzyzwielkopolski ksiazwielkopolski + kudowazdroj kujawskopomorskie - kutno kuzniaraciborska - kwidzyn labiszyn ladekzdroj - lancut lapy lask laskarzew @@ -2678,10 +2322,10 @@ legnica leszno lewinbrzeski - lewinbrzeski2 lezajsk limanowa lipno + lipsko lodz lodzkie lowicz @@ -2698,8 +2342,11 @@ lwowekslaski malbork malopolskie + marciszow marki + maslowice mazowieckie + miastko michalowice miechow miedzyrzecpodlaski @@ -2707,7 +2354,6 @@ mielec milanowek minskmazowiecki - mniszkow mosina mragowo mragowski @@ -2717,17 +2363,18 @@ myslowice myszkow naklonadnotecia + nasielsk niemodlin niepolomice nisko nowadeba nowasarzyna - nowasol nowemiasteczko noweskalmierzyce nowogard nowogrodbobrzanski nowogrodziec + nowosolna nowydwormazowiecki nowysacz nowytarg @@ -2741,8 +2388,6 @@ opoczno opole opolelubelskie - opolskie - orzesze osieczna osiecznica ostroda @@ -2760,16 +2405,13 @@ piekaryslaskie piensk pila - pilzno piotrkowtrybunalski pisz plock plonsk pniewy - pobiedziska podkarpackie podkowalesna - podlaskie polczynzdroj pomorskie poniec @@ -2778,7 +2420,7 @@ powiataugustowski powiatbedzinski powiatbelchatowski - powiatbialostocki + powiatbialobrzeski powiatbialski powiatbielski powiatbieszczadzki @@ -2804,7 +2446,6 @@ powiatczluchowski powiatdabrowski powiatdebicki - powiatdrawski powiatdzialdowski powiatdzierzoniowski powiatelblaski @@ -2819,11 +2460,10 @@ powiatgoleniowski powiatgolubskodobrzynski powiatgorlicki - powiatgorowski powiatgorzowski powiatgostynski - powiatgrajewski powiatgrojecki + powiatgrudziadzki powiatgryficki powiatgryfinski powiathajnowski @@ -2838,7 +2478,6 @@ powiatjedrzejowski powiatjeleniogorski powiatkaliski - powiatkamiennogorski powiatkamienski powiatkartuski powiatkazimierski @@ -2863,7 +2502,6 @@ powiatkrosnienski powiatkrotoszynski powiatkutnowski - powiatlancucki powiatlaski powiatleborski powiatleczycki @@ -2878,7 +2516,6 @@ powiatlipski powiatlobeski powiatlodzkiwschodni - powiatlosicki powiatlowicki powiatlubaczowski powiatlubanski @@ -2899,11 +2536,9 @@ powiatmyslenicki powiatmyszkowski powiatnakielski - powiatnamyslowski powiatnidzicki powiatnizanski powiatnowodworski - powiatnowomiejski powiatnowosadecki powiatnowosolski powiatnowotarski @@ -2939,6 +2574,7 @@ powiatproszowicki powiatprudnicki powiatpruszkowski + powiatprzasnyski powiatprzemyski powiatprzeworski powiatprzysuski @@ -2961,7 +2597,6 @@ powiatrzeszowski powiatsandomierski powiatsanocki - powiatsejnenski powiatsepolenski powiatsiedlecki powiatsiemiatycki @@ -2989,7 +2624,6 @@ powiatswidnicki powiatswidwinski powiatswiebodzinski - powiatswiecki powiatszamotulski powiatszczycienski powiatsztumski @@ -3008,7 +2642,6 @@ powiatwagrowiecki powiatwalecki powiatwarszawskizachodni - powiatwegorzewski powiatwegrowski powiatwejherowski powiatwielicki @@ -3028,6 +2661,7 @@ powiatwyszkowski powiatzabkowicki powiatzaganski + powiatzambrowski powiatzamojski powiatzarski powiatzawiercianski @@ -3038,33 +2672,34 @@ powiatzlotoryjski powiatzlotowski powiatzninski + powiatzurominski powiatzyrardowski powiatzywiecki poznan + prostki proszowice prudnik - pruszczgdanski pruszkow przasnysz przemysl przeworsk przysucha pszczyna + pszow puck pulawy - pultusk - puszczykowo pyskowice rabkazdroj raciaz raciborz + raciechowice radom radomsko - radomyslwielki radymno radziejow radzionkow radzynpodlaski + rakow rawamazowiecka rawicz reda @@ -3078,7 +2713,6 @@ rymanow rypin rzeszow - rzeszowprojekt sandomierz sanok sedziszowmalopolski @@ -3086,6 +2720,7 @@ siedlce siemianowiceslaskie siemiatycze + sieniawa sieradz skarzyskokamienna skawina @@ -3104,15 +2739,17 @@ srodaslaska srodawielkopolska starachowice - stargard starogardgdanski starysacz staszow stronieslaskie + strzegom strzyzow + suchylas sulejowek sulkowice sulmierzyce + suwalski swarzedz swidnica swidnik @@ -3135,10 +2772,8 @@ terespol tomaszowlubelski tomaszowmazowiecki - tomaszowmazowieckiprojekt torun trzcianka - trzcinskozdroj trzebnica trzemeszno tuliszkow @@ -3151,7 +2786,7 @@ ustrzykidolne wadowice wagrowiec - walcz + walbrzych warminskomazurskie warszawa wasosz @@ -3160,7 +2795,7 @@ wiecbork wieliczka wielkopolskie - wielun + wizna wladyslawowo wloclawek wlodawa @@ -3189,7 +2824,6 @@ zielonagora zielonka zlotoryja - zlotow zory zwolen zyrardow diff --git a/app/src/main/res/values/preferences_keys.xml b/app/src/main/res/values/preferences_keys.xml index 80a71bc71..f29080b33 100644 --- a/app/src/main/res/values/preferences_keys.xml +++ b/app/src/main/res/values/preferences_keys.xml @@ -31,7 +31,8 @@ homework_fullscreen subjects_without_grades optional_arithmetic_average - message_draft + message_send_is_draft + message_send_recipients last_sync_date notifications_piggyback notifications_piggyback_cancel_original diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 38997054f..e4542547d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -26,11 +26,15 @@ Student info Dashboard Notifications center + + Semester %1$d, %2$d/%3$d + + Sign in with the student or parent account - Enter the symbol from the register page for account: <b>%1$s</b> + Enter the symbol from the register page for account: <b>%1$s</b> Username Email Login, PESEL or e-mail @@ -55,7 +59,7 @@ Invalid symbol Student not found. Validate the symbol and the chosen variation of the UONET+ register Selected student is already logged in - The symbol can be found on the register page in Uczeń → Dostęp Mobilny → Wygeneruj kod dostępu.\n\nMake sure that you have set the appropriate register variant in the UONET+ register variant field on the first login screen + The symbol can be found on the register page in Uczeń → Dostęp Mobilny → Zarejestruj urządzenie mobilne.\n\nMake sure that you have set the appropriate register variant in the UONET+ register variant field on the previous screen Select students to log in to the application Other options In this mode, a lucky number does not work, a class grade stats, summary of attendance, excuse for absence, completed lessons, school information and preview of the list of registered devices @@ -67,21 +71,15 @@ Discord Send email Zgłoszenie: Problemy z logowaniem - Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\nDodatkowe informacje: %4$s\nIdentyfikator instalacji: %5$s\nOstatni błąd: %6$s\n\nNazwa szkoły i miejscowość: + Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\nDodatkowe informacje: %4$s\nOstatni błąd: %5$s\n\nNazwa szkoły i miejscowość: Make sure you select the correct UONET+ register variation! I forgot my password Recover your account Recover Student is already signed in Standard - Other search locations - No active students found - Enter a different symbol - - Enable notifications - Enable notifications so you don\'t miss message from teacher or new grade - Skip - Enable + + Account manager Log in @@ -90,6 +88,8 @@ Application support Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time Enable ads + + Grade Semester %d @@ -152,6 +152,8 @@ You received %1$d final grade You received %1$d final grades + + Lesson Room @@ -187,6 +189,8 @@ %d change %d changes + + Completed lessons Show completed lessons @@ -194,6 +198,8 @@ Topic Absence Resources + + Additional lessons Show additional lessons @@ -209,6 +215,8 @@ Start time End time End time must be greater than start time + + Attendance summary Absent for school reasons @@ -241,8 +249,12 @@ %d attendance %d attendance + + Total + + No exams this week Type @@ -259,6 +271,8 @@ %d exam %d exams + + Inbox Sent @@ -287,11 +301,9 @@ Message does not exist You need to choose at least 1 recipient The message content must be at least 3 characters - All mailboxes Only unread Only with attachments Read: %s - Read by: %1$d of %2$d people %1$d message %1$d messages @@ -311,7 +323,8 @@ %1$d selected Messages deleted - Choose mailbox + + No info about notes Points @@ -327,6 +340,7 @@ You received %1$d note You received %1$d notes + %d praise @@ -340,6 +354,7 @@ You received %1$d praise You received %1$d praises + %d neutral note @@ -353,6 +368,8 @@ You received %1$d neutral note You received %1$d neutral notes + + No info about homework Mark as done @@ -373,6 +390,8 @@ %d homework %d homework + + Lucky number Today\'s lucky number is @@ -380,9 +399,13 @@ Lucky number for today Today\'s lucky number is: %s Show history + + Lucky number history No info about lucky numbers + + Mobile devices No devices @@ -392,8 +415,12 @@ Token Symbol PIN + + School and teachers + + School No info about school @@ -404,10 +431,14 @@ Name of pedagogue Show on map Call + + Teachers No info about teachers No subject + + Conferences No info about conferences @@ -425,8 +456,7 @@ Present at conference Agenda - Place - Topic + School announcements No school announcements @@ -442,6 +472,8 @@ You have %1$d new school announcement You have %1$d new school announcements + + Add account Logout @@ -456,6 +488,8 @@ Contact Residence details Personal information + + App version Contributors @@ -478,12 +512,18 @@ Visit the website and help develop the application Licenses Licenses of libraries used in the application - Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\nIdentyfikator instalacji: %4$s\nTreść zgłoszenia: + Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\n\nTreść zgłoszenia: + + License + + Avatar See more on GitHub + + No info about student or student family Name @@ -506,13 +546,19 @@ Female Last name Guardian + + Nick Add nick Choose avatar color + + Share logs Refresh + + Lessons (Tomorrow) @@ -531,6 +577,7 @@ until %1$s No upcoming lessons An error occurred while loading the lessons + Homework No homework to do An error occurred while loading the homework @@ -539,9 +586,11 @@ %1$d more homework due %1$s + Last grades No new grades An error occurred while loading the grades + School announcements No current announcements An error occurred while loading the announcements @@ -549,6 +598,7 @@ %1$d more announcement %1$d more announcements + Exams No upcoming exams An error occurred while loading the exams @@ -556,6 +606,7 @@ %1$d more exam %1$d more exams + Conferences No upcoming conferences An error occurred while loading the conferences @@ -563,11 +614,16 @@ %1$d more conference %1$d more conferences + An error occurred while loading data None + + Check for updates Before reporting a bug, check first if an update with the bug fix is available + + Content Retry @@ -595,12 +651,16 @@ Undo Change Add to calendar + + No lessons Choose theme Light Dark System Theme + + App Default view @@ -616,6 +676,7 @@ Grades color scheme Subjects sorting Language + Notifications Other Show notifications @@ -635,6 +696,7 @@ Upcoming lesson notifications You must allow the Wulkanowy app to set alarms and reminders in your system settings to use this feature. Go to settings + Synchronization Automatic update Suspended on holidays @@ -645,10 +707,12 @@ Sync failed Sync in progress Last full sync: %s + Value of the plus Value of the minus Reply with message history Show arithmetic average when no weights provided + Support Privacy Policy Agreements @@ -668,11 +732,13 @@ I am over 18 years old Yes, personalized ads Yes, non-personalized ads + Advanced Appearance & Behavior Notifications Synchronization Advertisements + Grades Dashboard Tiles visibility @@ -681,6 +747,7 @@ Grades Calculated average Messages + Appearance & Behavior Languages, themes, subjects sorting App notifications, fix problems @@ -691,6 +758,8 @@ Advanced App version, contributors, social portals Displaying advertisements, project support + + New grades New homework @@ -705,6 +774,8 @@ Debug Timetable change New attendance + + Black Red @@ -712,11 +783,15 @@ Green Purple No color + + Download of updates has started… An update has just been downloaded. Restart Update failed! Wulkanowy may not function properly. Consider updating + + No internet connection An error occurred. Check your device clock diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml deleted file mode 100644 index 418b6d4c4..000000000 --- a/app/src/main/res/xml/data_extraction_rules.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml index 17fac4d1e..84ff05a04 100644 --- a/app/src/main/res/xml/network_security_config.xml +++ b/app/src/main/res/xml/network_security_config.xml @@ -1,5 +1,6 @@ + diff --git a/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsPresenter.kt b/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsPresenter.kt index 28c98e3c3..772d616d7 100644 --- a/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsPresenter.kt +++ b/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsPresenter.kt @@ -31,22 +31,13 @@ class AdsPresenter @Inject constructor( view?.showLoadingSupportAd(true) presenterScope.launch { runCatching { adsHelper.getSupportAd() } - .onFailure { - errorHandler.dispatch(it) + .onFailure(errorHandler::dispatch) + .onSuccess { it?.let { view?.showAd(it) } } - view?.run { - showLoadingSupportAd(false) - showWatchAdOncePerVisit(false) - } - } - .onSuccess { - it?.let { view?.showAd(it) } - - view?.run { - showLoadingSupportAd(false) - showWatchAdOncePerVisit(true) - } - } + view?.run { + showLoadingSupportAd(false) + showWatchAdOncePerVisit(true) + } } } diff --git a/app/src/play/java/io/github/wulkanowy/utils/AdsHelper.kt b/app/src/play/java/io/github/wulkanowy/utils/AdsHelper.kt index d5f65b46d..c536e2218 100644 --- a/app/src/play/java/io/github/wulkanowy/utils/AdsHelper.kt +++ b/app/src/play/java/io/github/wulkanowy/utils/AdsHelper.kt @@ -1,12 +1,8 @@ package io.github.wulkanowy.utils import android.content.Context -import android.net.ConnectivityManager -import android.net.NetworkCapabilities -import android.os.Build import android.os.Bundle import android.view.View -import androidx.core.content.getSystemService import com.google.ads.mediation.admob.AdMobAdapter import com.google.android.gms.ads.* import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd @@ -14,7 +10,6 @@ import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAdLoa import dagger.hilt.android.qualifiers.ApplicationContext import io.github.wulkanowy.BuildConfig import io.github.wulkanowy.data.repositories.PreferencesRepository -import java.net.UnknownHostException import javax.inject.Inject import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException @@ -33,10 +28,6 @@ class AdsHelper @Inject constructor( } suspend fun getSupportAd(): RewardedInterstitialAd? { - if (!context.isInternetConnected()) { - throw UnknownHostException() - } - val extra = Bundle().apply { putString("npa", "1") } val adRequest = AdRequest.Builder() .apply { @@ -93,18 +84,4 @@ class AdsHelper @Inject constructor( } } -@Suppress("DEPRECATION") -private fun Context.isInternetConnected(): Boolean { - val connectivityManager = getSystemService() ?: return false - - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - val currentNetwork = connectivityManager.activeNetwork - val networkCapabilities = connectivityManager.getNetworkCapabilities(currentNetwork) - - networkCapabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) == true - } else { - connectivityManager.activeNetworkInfo?.isConnected == true - } -} - data class AdBanner(val view: View) diff --git a/app/src/play/java/io/github/wulkanowy/utils/AnalyticsHelper.kt b/app/src/play/java/io/github/wulkanowy/utils/AnalyticsHelper.kt index 3215fa20c..b65325790 100644 --- a/app/src/play/java/io/github/wulkanowy/utils/AnalyticsHelper.kt +++ b/app/src/play/java/io/github/wulkanowy/utils/AnalyticsHelper.kt @@ -4,37 +4,25 @@ import android.app.Activity import android.content.Context import android.os.Bundle import com.google.firebase.analytics.FirebaseAnalytics -import com.google.firebase.crashlytics.FirebaseCrashlytics import dagger.hilt.android.qualifiers.ApplicationContext -import io.github.wulkanowy.data.repositories.PreferencesRepository import javax.inject.Inject import javax.inject.Singleton @Singleton class AnalyticsHelper @Inject constructor( - @ApplicationContext private val context: Context, - preferencesRepository: PreferencesRepository, - appInfo: AppInfo, + @ApplicationContext private val context: Context ) { private val analytics by lazy { FirebaseAnalytics.getInstance(context) } - private val crashlytics by lazy { FirebaseCrashlytics.getInstance() } - - init { - if (!appInfo.isDebug) { - crashlytics.setUserId(preferencesRepository.installationId) - } - } - fun logEvent(name: String, vararg params: Pair) { Bundle().apply { - params.forEach { (key, value) -> - if (value == null) return@forEach - when (value) { - is String -> putString(key, value) - is Int -> putInt(key, value) - is Boolean -> putBoolean(key, value) + params.forEach { + if (it.second == null) return@forEach + when (it.second) { + is String, is String? -> putString(it.first, it.second.toString()) + is Int, is Int? -> putInt(it.first, it.second as Int) + is Boolean, is Boolean? -> putBoolean(it.first, it.second as Boolean) } } analytics.logEvent(name, this) diff --git a/app/src/play/java/io/github/wulkanowy/utils/CrashlyticsUtils.kt b/app/src/play/java/io/github/wulkanowy/utils/CrashlyticsUtils.kt index f980bc4bb..410fddf16 100644 --- a/app/src/play/java/io/github/wulkanowy/utils/CrashlyticsUtils.kt +++ b/app/src/play/java/io/github/wulkanowy/utils/CrashlyticsUtils.kt @@ -23,6 +23,9 @@ class CrashLogExceptionTree : FormatterPriorityTree(Log.ERROR, ExceptionFilter) override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { if (skipLog(priority, tag, message, t)) return + crashlytics.setCustomKey("priority", priority) + crashlytics.setCustomKey("tag", tag.orEmpty()) + crashlytics.setCustomKey("message", message) if (t != null) { crashlytics.recordException(t) } else { diff --git a/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt b/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt index 84a0cb405..ff0a53135 100644 --- a/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt +++ b/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt @@ -27,9 +27,7 @@ fun getMailboxEntity() = Mailbox( globalKey = "v4", fullName = "", userName = "", - email = "test", - symbol = "powiatwulkanowy", - schoolId = "123456", + userLoginId = 0, studentName = "", schoolNameShort = "", type = MailboxType.UNKNOWN, diff --git a/app/src/test/java/io/github/wulkanowy/data/db/migrations/AbstractMigrationTest.kt b/app/src/test/java/io/github/wulkanowy/data/db/migrations/AbstractMigrationTest.kt index 18249ba8b..cc31d8933 100644 --- a/app/src/test/java/io/github/wulkanowy/data/db/migrations/AbstractMigrationTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/db/migrations/AbstractMigrationTest.kt @@ -3,7 +3,6 @@ package io.github.wulkanowy.data.db.migrations import android.content.Context import androidx.preference.PreferenceManager import androidx.room.Room -import androidx.room.migration.Migration import androidx.room.testing.MigrationTestHelper import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory import androidx.test.core.app.ApplicationProvider @@ -17,7 +16,7 @@ abstract class AbstractMigrationTest { val dbName = "migration-test" - private val context: Context get() = ApplicationProvider.getApplicationContext() + val context: Context get() = ApplicationProvider.getApplicationContext() @get:Rule val helper: MigrationTestHelper = MigrationTestHelper( @@ -26,10 +25,6 @@ abstract class AbstractMigrationTest { FrameworkSQLiteOpenHelperFactory() ) - fun runMigrationsAndValidate(migration: Migration) { - helper.runMigrationsAndValidate(dbName, migration.endVersion, true, migration).close() - } - fun getMigratedRoomDatabase(): AppDatabase { val database = Room.databaseBuilder( ApplicationProvider.getApplicationContext(), diff --git a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration12Test.kt b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration12Test.kt index f614c8ca9..a02904733 100644 --- a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration12Test.kt +++ b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration12Test.kt @@ -33,7 +33,7 @@ class Migration12Test : AbstractMigrationTest() { close() } - runMigrationsAndValidate(Migration12()) + helper.runMigrationsAndValidate(dbName, 12, true, Migration12()) val db = getMigratedRoomDatabase() val students = runBlocking { db.studentDao.loadAll() } @@ -49,7 +49,6 @@ class Migration12Test : AbstractMigrationTest() { assertEquals(2, studentId) assertEquals(6, classId) } - db.close() } @Test @@ -63,7 +62,7 @@ class Migration12Test : AbstractMigrationTest() { close() } - runMigrationsAndValidate(Migration12()) + helper.runMigrationsAndValidate(dbName, 12, true, Migration12()) val db = getMigratedRoomDatabase() val students = runBlocking { db.studentDao.loadAll() } @@ -74,7 +73,6 @@ class Migration12Test : AbstractMigrationTest() { assertEquals(2, studentId) assertEquals(1, classId) } - db.close() } @Test @@ -90,7 +88,7 @@ class Migration12Test : AbstractMigrationTest() { close() } - runMigrationsAndValidate(Migration12()) + helper.runMigrationsAndValidate(dbName, 12, true, Migration12()) val db = getMigratedRoomDatabase() val students = runBlocking { db.studentDao.loadAll() } @@ -109,7 +107,6 @@ class Migration12Test : AbstractMigrationTest() { assertEquals(studentId, 3) assertEquals(true, isCurrent) } - db.close() } private fun createStudent(db: SupportSQLiteDatabase, studentId: Int, isCurrent: Boolean) { diff --git a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration13Test.kt b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration13Test.kt index b0c03fb11..bdfb4137d 100644 --- a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration13Test.kt +++ b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration13Test.kt @@ -57,8 +57,6 @@ class Migration13Test : AbstractMigrationTest() { assertEquals("C", className) assertEquals("Publiczna szkoła Wulkanowego-fejka nr 2 w fakelog.cf", schoolName) } - - db.close() } @Test @@ -87,8 +85,6 @@ class Migration13Test : AbstractMigrationTest() { assertEquals("", className) assertEquals("Publiczna szkoła Wulkanowego-fejka nr 1 w fakelog.cf", schoolName) } - - db.close() } @Test @@ -152,7 +148,6 @@ class Migration13Test : AbstractMigrationTest() { assertFalse(semesters[2].second) assertTrue(semesters[3].second) } - db.close() } private fun getSemesters(db: SupportSQLiteDatabase, query: String): List> { diff --git a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration27Test.kt b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration27Test.kt index 19eda9ba8..8e744f27a 100644 --- a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration27Test.kt +++ b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration27Test.kt @@ -27,7 +27,7 @@ class Migration27Test : AbstractMigrationTest() { close() } - runMigrationsAndValidate(Migration27()) + helper.runMigrationsAndValidate(dbName, 27, true, Migration27()) val db = getMigratedRoomDatabase() val students = runBlocking { db.studentDao.loadAll() } @@ -39,8 +39,6 @@ class Migration27Test : AbstractMigrationTest() { assertEquals(123, userLoginId) assertEquals("Student Jan", userName) } - - db.close() } @Test @@ -51,7 +49,7 @@ class Migration27Test : AbstractMigrationTest() { close() } - runMigrationsAndValidate(Migration27()) + helper.runMigrationsAndValidate(dbName, 27, true, Migration27()) val db = getMigratedRoomDatabase() val students = runBlocking { db.studentDao.loadAll() } @@ -63,8 +61,6 @@ class Migration27Test : AbstractMigrationTest() { assertEquals(2, userLoginId) assertEquals("Unit Jan", userName) } - - db.close() } @Test @@ -77,7 +73,7 @@ class Migration27Test : AbstractMigrationTest() { close() } - runMigrationsAndValidate(Migration27()) + helper.runMigrationsAndValidate(dbName, 27, true, Migration27()) val db = getMigratedRoomDatabase() val students = runBlocking { db.studentDao.loadAll() } @@ -94,8 +90,6 @@ class Migration27Test : AbstractMigrationTest() { assertEquals(333, userLoginId) assertEquals("Unit Tomasz", userName) } - - db.close() } private fun createStudent(db: SupportSQLiteDatabase, id: Long, userLoginId: Int, studentName: String) { diff --git a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration35Test.kt b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration35Test.kt index 79c24f2e6..883cdb81c 100644 --- a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration35Test.kt +++ b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration35Test.kt @@ -29,7 +29,7 @@ class Migration35Test : AbstractMigrationTest() { close() } - runMigrationsAndValidate(Migration35(AppInfo())) + helper.runMigrationsAndValidate(dbName, 35, true, Migration35(AppInfo())) val db = getMigratedRoomDatabase() val students = runBlocking { db.studentDao.loadAll() } @@ -38,8 +38,6 @@ class Migration35Test : AbstractMigrationTest() { assertTrue { students[0].avatarColor in AppInfo().defaultColorsForAvatar } assertTrue { students[1].avatarColor in AppInfo().defaultColorsForAvatar } - - db.close() } private fun createStudent(db: SupportSQLiteDatabase, id: Long) { diff --git a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration54Test.kt b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration54Test.kt deleted file mode 100644 index 1855e0d50..000000000 --- a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration54Test.kt +++ /dev/null @@ -1,130 +0,0 @@ -package io.github.wulkanowy.data.db.migrations - -import android.content.ContentValues -import android.database.sqlite.SQLiteDatabase -import android.os.Build -import androidx.sqlite.db.SupportSQLiteDatabase -import dagger.hilt.android.testing.HiltAndroidTest -import dagger.hilt.android.testing.HiltTestApplication -import io.github.wulkanowy.sdk.Sdk -import io.github.wulkanowy.sdk.Sdk.ScrapperLoginType.* -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.runTest -import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -import org.robolectric.annotation.Config -import kotlin.random.Random -import kotlin.test.assertEquals - -@HiltAndroidTest -@RunWith(RobolectricTestRunner::class) -@OptIn(ExperimentalCoroutinesApi::class) -@Config(sdk = [Build.VERSION_CODES.O_MR1], application = HiltTestApplication::class) -class Migration54Test : AbstractMigrationTest() { - - @Test - fun `don't touch unrelated students`() = runTest { - with(helper.createDatabase(dbName, 53)) { - createStudent(1, STANDARD, "vulcan.net.pl", "rzeszow", "Jan Michniewicz") - createStudent(2, ADFSLight, "umt.tarnow.pl", "tarnow", "Joanna Marcinkiewicz") - close() - } - - runMigrationsAndValidate(Migration54()) - val db = getMigratedRoomDatabase() - val students = db.studentDao.loadAll() - - assertEquals(2, students.size) - with(students[0]) { - assertEquals(STANDARD.name, loginType) - assertEquals("https://vulcan.net.pl", scrapperBaseUrl) - assertEquals("rzeszow", symbol) - } - with(students[1]) { - assertEquals(ADFSLight.name, loginType) - assertEquals("https://umt.tarnow.pl", scrapperBaseUrl) - assertEquals("tarnow", symbol) - } - db.close() - } - - @Test - fun `remove tomaszow mazowiecki students`() = runTest { - with(helper.createDatabase(dbName, 53)) { - createStudent(1, STANDARD, "vulcan.net.pl", "rzeszow", "Jan Michniewicz") - createStudent(2, STANDARD, "vulcan.net.pl", "tomaszowmazowiecki", "Joanna Stec") - createStudent(3, STANDARD, "vulcan.net.pl", "tomaszowmazowiecki", "Kacper Morawiecki") - close() - } - - runMigrationsAndValidate(Migration54()) - val db = getMigratedRoomDatabase() - val students = db.studentDao.loadAll() - assertEquals(1, students.size) - with(students[0]) { - assertEquals("rzeszow", symbol) - } - db.close() - } - - @Test - fun `migrate resman students`() = runTest { - with(helper.createDatabase(dbName, 53)) { - createStudent(1, ADFSLight, "resman.pl", "rzeszow", "Joanna Stec") - createStudent(2, ADFSLight, "resman.pl", "rzeszow", "Kacper Morawiecki") - createStudent(3, STANDARD, "vulcan.net.pl", "rzeszow", "Jan Michniewicz") - close() - } - runMigrationsAndValidate(Migration54()) - val db = getMigratedRoomDatabase() - val students = db.studentDao.loadAll() - assertEquals(3, students.size) - with(students[0]) { - assertEquals(ADFSLightScoped.name, loginType) - assertEquals("https://vulcan.net.pl", scrapperBaseUrl) - assertEquals("rzeszowprojekt", symbol) - } - with(students[1]) { - assertEquals(ADFSLightScoped.name, loginType) - assertEquals("https://vulcan.net.pl", scrapperBaseUrl) - assertEquals("rzeszowprojekt", symbol) - } - db.close() - } - - private fun SupportSQLiteDatabase.createStudent( - id: Long, - loginType: Sdk.ScrapperLoginType, - host: String, - symbol: String, - studentName: String, - ) { - insert("Students", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply { - put("scrapper_base_url", "https://$host") - put("mobile_base_url", "") - put("login_type", loginType.name) - put("login_mode", "SCRAPPER") - put("certificate_key", "") - put("private_key", "") - put("is_parent", false) - put("email", "jan@fakelog.cf") - put("password", "******") - put("symbol", symbol) - put("student_id", Random.nextInt()) - put("user_login_id", id) - put("user_name", studentName) - put("student_name", studentName) - put("school_id", "123") - put("school_short", "") - put("school_name", "") - put("class_name", "") - put("class_id", Random.nextInt()) - put("is_current", false) - put("registration_date", "0") - put("id", id) - put("nick", "") - put("avatar_color", "") - }) - } -} diff --git a/app/src/test/java/io/github/wulkanowy/data/mappers/AttendanceMapperKtTest.kt b/app/src/test/java/io/github/wulkanowy/data/mappers/AttendanceMapperKtTest.kt deleted file mode 100644 index a35e5d303..000000000 --- a/app/src/test/java/io/github/wulkanowy/data/mappers/AttendanceMapperKtTest.kt +++ /dev/null @@ -1,143 +0,0 @@ -package io.github.wulkanowy.data.mappers - -import io.github.wulkanowy.data.db.entities.Semester -import io.github.wulkanowy.data.db.entities.Timetable -import io.github.wulkanowy.sdk.pojo.Attendance -import io.github.wulkanowy.sdk.scrapper.attendance.SentExcuse -import org.junit.Test -import java.time.Instant -import java.time.LocalDate -import kotlin.test.assertEquals - -class AttendanceMapperTest { - - @Test - fun `map attendance when fallback is not necessary`() { - val attendance = listOf( - getSdkAttendance(1, LocalDate.of(2022, 11, 17), "Oryginalna 1"), - getSdkAttendance(2, LocalDate.of(2022, 11, 17), "Oryginalna 2"), - ) - val lessons = listOf( - getEntityTimetable(1, LocalDate.of(2022, 11, 17), "Pierwsza"), - getEntityTimetable(2, LocalDate.of(2022, 11, 17), "Druga"), - ) - - val result = attendance.mapToEntities(getEntitySemester(), lessons) - assertEquals("Oryginalna 1", result[0].subject) - assertEquals("Oryginalna 2", result[1].subject) - } - - @Test - fun `map attendance when fallback is not always necessary`() { - val attendance = listOf( - getSdkAttendance(1, LocalDate.of(2022, 11, 17), "Oryginalna 1"), - getSdkAttendance(2, LocalDate.of(2022, 11, 17), ""), - ) - val lessons = listOf( - getEntityTimetable(1, LocalDate.of(2022, 11, 17), "Pierwsza"), - getEntityTimetable(2, LocalDate.of(2022, 11, 17), "Druga"), - ) - - val result = attendance.mapToEntities(getEntitySemester(), lessons) - assertEquals("Oryginalna 1", result[0].subject) - assertEquals("Druga", result[1].subject) - } - - @Test - fun `map attendance when fallback is sometimes empty`() { - val attendance = listOf( - getSdkAttendance(1, LocalDate.of(2022, 11, 17), "Oryginalna 1"), - getSdkAttendance(2, LocalDate.of(2022, 11, 17), ""), - ) - val lessons = listOf( - getEntityTimetable(1, LocalDate.of(2022, 11, 17), "Pierwsza"), - ) - - val result = attendance.mapToEntities(getEntitySemester(), lessons) - assertEquals("Oryginalna 1", result[0].subject) - assertEquals("", result[1].subject) - } - - @Test - fun `map attendance when fallback is empty`() { - val attendance = listOf( - getSdkAttendance(1, LocalDate.of(2022, 11, 17), ""), - getSdkAttendance(2, LocalDate.of(2022, 11, 17), ""), - ) - val lessons = listOf( - getEntityTimetable(1, LocalDate.of(2022, 11, 18), "Pierwsza"), - getEntityTimetable(2, LocalDate.of(2022, 10, 17), "Druga"), - ) - - val result = attendance.mapToEntities(getEntitySemester(), lessons) - assertEquals("", result[0].subject) - assertEquals("", result[1].subject) - } - - @Test - fun `map attendance with all subject fallback`() { - val attendance = listOf( - getSdkAttendance(1, LocalDate.of(2022, 11, 17)), - getSdkAttendance(2, LocalDate.of(2022, 11, 17)), - ) - val lessons = listOf( - getEntityTimetable(1, LocalDate.of(2022, 11, 17), "Pierwsza"), - getEntityTimetable(2, LocalDate.of(2022, 11, 17), "Druga"), - ) - - val result = attendance.mapToEntities(getEntitySemester(), lessons) - assertEquals("Pierwsza", result[0].subject) - assertEquals("Druga", result[1].subject) - } - - private fun getSdkAttendance(number: Int, date: LocalDate, subject: String = "") = Attendance( - number = number, - name = "ABSENCE", - subject = subject, - date = date, - timeId = 1, - categoryId = 1, - deleted = false, - excuseStatus = SentExcuse.Status.WAITING, - excusable = false, - absence = false, - excused = false, - exemption = false, - lateness = false, - presence = false, - ) - - private fun getEntityTimetable(number: Int, date: LocalDate, subject: String = "") = Timetable( - number = number, - start = Instant.now(), - end = Instant.now(), - date = date, - subject = subject, - subjectOld = "", - group = "", - room = "", - roomOld = "", - teacher = "", - teacherOld = "", - info = "", - changes = false, - canceled = false, - studentId = 0, - diaryId = 0, - isStudentPlan = false, - ) - - private fun getEntitySemester() = Semester( - studentId = 0, - diaryId = 0, - kindergartenDiaryId = 0, - diaryName = "", - schoolYear = 0, - semesterId = 0, - semesterName = 0, - start = LocalDate.now(), - end = LocalDate.now(), - classId = 0, - unitId = 0 - ) -} diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/AttendanceRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/AttendanceRepositoryTest.kt index 896491ef0..7d22f7265 100644 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/AttendanceRepositoryTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/AttendanceRepositoryTest.kt @@ -2,7 +2,6 @@ package io.github.wulkanowy.data.repositories import io.github.wulkanowy.data.dataOrNull import io.github.wulkanowy.data.db.dao.AttendanceDao -import io.github.wulkanowy.data.db.dao.TimetableDao import io.github.wulkanowy.data.errorOrNull import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.toFirstResult @@ -30,9 +29,6 @@ class AttendanceRepositoryTest { @MockK private lateinit var attendanceDb: AttendanceDao - @MockK - private lateinit var timetableDb: TimetableDao - @MockK(relaxUnitFun = true) private lateinit var refreshHelper: AutoRefreshHelper @@ -55,9 +51,8 @@ class AttendanceRepositoryTest { fun setUp() { MockKAnnotations.init(this) every { refreshHelper.shouldBeRefreshed(any()) } returns false - coEvery { timetableDb.load(any(), any(), any(), any()) } returns emptyList() - attendanceRepository = AttendanceRepository(attendanceDb, timetableDb, sdk, refreshHelper) + attendanceRepository = AttendanceRepository(attendanceDb, sdk, refreshHelper) } @Test @@ -65,8 +60,8 @@ class AttendanceRepositoryTest { // prepare coEvery { sdk.getAttendance(startDate, endDate, 1) } returns remoteList coEvery { attendanceDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf( - flowOf(remoteList.mapToEntities(semester, emptyList())), - flowOf(remoteList.mapToEntities(semester, emptyList())) + flowOf(remoteList.mapToEntities(semester)), + flowOf(remoteList.mapToEntities(semester)) ) coEvery { attendanceDb.insertAll(any()) } returns listOf(1, 2, 3) coEvery { attendanceDb.deleteAll(any()) } just Runs @@ -88,9 +83,9 @@ class AttendanceRepositoryTest { // prepare coEvery { sdk.getAttendance(startDate, endDate, 1) } returns remoteList coEvery { attendanceDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf( - flowOf(remoteList.dropLast(1).mapToEntities(semester, emptyList())), - flowOf(remoteList.dropLast(1).mapToEntities(semester, emptyList())), // after fetch end before save result - flowOf(remoteList.mapToEntities(semester, emptyList())) + flowOf(remoteList.dropLast(1).mapToEntities(semester)), + flowOf(remoteList.dropLast(1).mapToEntities(semester)), // after fetch end before save result + flowOf(remoteList.mapToEntities(semester)) ) coEvery { attendanceDb.insertAll(any()) } returns listOf(1, 2, 3) coEvery { attendanceDb.deleteAll(any()) } just Runs @@ -105,7 +100,7 @@ class AttendanceRepositoryTest { coVerify { attendanceDb.loadAll(1, 1, startDate, endDate) } coVerify { attendanceDb.insertAll(match { - it.size == 1 && it[0] == remoteList.mapToEntities(semester, emptyList())[1] + it.size == 1 && it[0] == remoteList.mapToEntities(semester)[1] }) } coVerify { attendanceDb.deleteAll(match { it.isEmpty() }) } @@ -116,9 +111,9 @@ class AttendanceRepositoryTest { // prepare coEvery { sdk.getAttendance(startDate, endDate, 1) } returns remoteList.dropLast(1) coEvery { attendanceDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf( - flowOf(remoteList.mapToEntities(semester, emptyList())), - flowOf(remoteList.mapToEntities(semester, emptyList())), // after fetch end before save result - flowOf(remoteList.dropLast(1).mapToEntities(semester, emptyList())) + flowOf(remoteList.mapToEntities(semester)), + flowOf(remoteList.mapToEntities(semester)), // after fetch end before save result + flowOf(remoteList.dropLast(1).mapToEntities(semester)) ) coEvery { attendanceDb.insertAll(any()) } returns listOf(1, 2, 3) coEvery { attendanceDb.deleteAll(any()) } just Runs @@ -134,7 +129,7 @@ class AttendanceRepositoryTest { coVerify { attendanceDb.insertAll(match { it.isEmpty() }) } coVerify { attendanceDb.deleteAll(match { - it.size == 1 && it[0] == remoteList.mapToEntities(semester, emptyList())[1] + it.size == 1 && it[0] == remoteList.mapToEntities(semester)[1] }) } } 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 9a2c22fd6..24306bfeb 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 @@ -3,7 +3,6 @@ package io.github.wulkanowy.data.repositories import android.content.Context import io.github.wulkanowy.data.dataOrNull import io.github.wulkanowy.data.db.SharedPrefProvider -import io.github.wulkanowy.data.db.dao.MailboxDao import io.github.wulkanowy.data.db.dao.MessageAttachmentDao import io.github.wulkanowy.data.db.dao.MessagesDao import io.github.wulkanowy.data.db.entities.Message @@ -11,7 +10,6 @@ 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.domain.messages.GetMailboxByStudentUseCase import io.github.wulkanowy.getMailboxEntity import io.github.wulkanowy.getStudentEntity import io.github.wulkanowy.sdk.Sdk @@ -57,12 +55,6 @@ class MessageRepositoryTest { @MockK private lateinit var sharedPrefProvider: SharedPrefProvider - @MockK - private lateinit var mailboxDao: MailboxDao - - @MockK - private lateinit var getMailboxByStudentUseCase: GetMailboxByStudentUseCase - private val student = getStudentEntity() private val mailbox = getMailboxEntity() @@ -82,33 +74,26 @@ class MessageRepositoryTest { refreshHelper = refreshHelper, sharedPrefProvider = sharedPrefProvider, json = Json, - mailboxDao = mailboxDao, - getMailboxByStudentUseCase = getMailboxByStudentUseCase, ) } @Test fun `get messages when fetched completely new message without notify`() = runBlocking { - coEvery { mailboxDao.loadAll(any()) } returns listOf(mailbox) - every { messageDb.loadAll(mailbox.globalKey, any()) } returns flowOf(emptyList()) + every { messageDb.loadAll(any(), any()) } returns flowOf(emptyList()) coEvery { sdk.getMessages(Folder.RECEIVED, any()) } returns listOf( - getMessageDto().copy( - unreadBy = 5, - readBy = 10, - ) + getMessageDto() ) coEvery { messageDb.deleteAll(any()) } just Runs coEvery { messageDb.insertAll(any()) } returns listOf() - val res = repository.getMessages( + repository.getMessages( student = student, mailbox = mailbox, folder = MessageFolder.RECEIVED, forceRefresh = true, notify = false, - ).toFirstResult() + ).toFirstResult().dataOrNull.orEmpty() - assertEquals(null, res.errorOrNull) coVerify(exactly = 1) { messageDb.deleteAll(withArg { checkEquals(emptyList()) }) } coVerify { messageDb.insertAll(withArg { @@ -156,7 +141,7 @@ class MessageRepositoryTest { messageDb.loadMessageWithAttachment("v4") } returnsMany listOf(flowOf(mWa), flowOf(mWaWithContent)) coEvery { - sdk.getMessageDetails("v4", any()) + sdk.getMessageDetails("v4") } returns mockk { every { sender } returns "" every { recipients } returns listOf("") @@ -202,16 +187,13 @@ class MessageRepositoryTest { ) = Message( messageGlobalKey = "v4", mailboxKey = "", - email = "", correspondents = "", messageId = messageId, subject = "", date = Instant.EPOCH, folderId = 1, unread = unread, - readBy = 1, - unreadBy = 1, - hasAttachments = false, + hasAttachments = false ).apply { this.content = content } @@ -227,8 +209,6 @@ class MessageRepositoryTest { dateZoned = Instant.EPOCH.atZone(ZoneOffset.UTC), folderId = 1, unread = true, - readBy = 1, - unreadBy = 1, hasAttachments = false, ) } diff --git a/app/src/test/java/io/github/wulkanowy/domain/GetMailboxByStudentUseCaseTest.kt b/app/src/test/java/io/github/wulkanowy/domain/GetMailboxByStudentUseCaseTest.kt deleted file mode 100644 index 6db16d2f5..000000000 --- a/app/src/test/java/io/github/wulkanowy/domain/GetMailboxByStudentUseCaseTest.kt +++ /dev/null @@ -1,225 +0,0 @@ -package io.github.wulkanowy.domain - -import io.github.wulkanowy.data.db.dao.MailboxDao -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.domain.messages.GetMailboxByStudentUseCase -import io.github.wulkanowy.sdk.Sdk -import io.mockk.MockKAnnotations -import io.mockk.Runs -import io.mockk.coEvery -import io.mockk.impl.annotations.MockK -import io.mockk.just -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Test -import java.time.Instant -import kotlin.test.assertEquals -import kotlin.test.assertNull - -@OptIn(ExperimentalCoroutinesApi::class) -class GetMailboxByStudentUseCaseTest { - - @MockK - private lateinit var mailboxDao: MailboxDao - - private lateinit var systemUnderTest: GetMailboxByStudentUseCase - - @Before - fun setUp() { - MockKAnnotations.init(this) - - coEvery { mailboxDao.deleteAll(any()) } just Runs - coEvery { mailboxDao.insertAll(any()) } returns emptyList() - coEvery { mailboxDao.loadAll(any()) } returns emptyList() - - systemUnderTest = GetMailboxByStudentUseCase(mailboxDao = mailboxDao) - } - - @Test - fun `get mailbox that doesn't exist`() = runTest { - val student = getStudentEntity( - userName = "Stanisław Kowalski", - studentName = "Jan Kowalski", - ) - coEvery { mailboxDao.loadAll(any()) } returns emptyList() - - assertNull(systemUnderTest(student)) - } - - @Test - fun `get mailbox for user with additional spaces`() = runTest { - val student = getStudentEntity( - userName = " Stanisław Kowalski ", - studentName = " Jan Kowalski ", - ) - val expectedMailbox = getMailboxEntity("Jan Kowalski ") - coEvery { mailboxDao.loadAll(any()) } returns listOf( - expectedMailbox, - ) - - val selectedMailbox = systemUnderTest(student) - assertEquals(expectedMailbox, selectedMailbox) - } - - @Test - fun `get mailbox for user with reversed name`() = runTest { - val student = getStudentEntity( - userName = "Kowalski Jan", - studentName = "Jan Kowalski", - ) - val expectedMailbox = getMailboxEntity("Kowalski Jan") - coEvery { mailboxDao.loadAll(any()) } returns listOf(expectedMailbox) - - assertEquals(expectedMailbox, systemUnderTest(student)) - } - - @Test - fun `get mailbox for unique non-authorized student`() = runTest { - val student = getStudentEntity( - userName = "Stanisław Kowalski", - studentName = "J** K*******", - ) - val expectedMailbox = getMailboxEntity("Jan Kowalski") - coEvery { mailboxDao.loadAll(any()) } returns listOf( - expectedMailbox, - ) - - assertEquals(expectedMailbox, systemUnderTest(student)) - } - - @Test - fun `get mailbox for unique non-authorized student but with spaces`() = runTest { - val student = getStudentEntity( - userName = "Stanisław Kowalski", - studentName = "J** K*******", - ) - val expectedMailbox = getMailboxEntity("Jan Kowalski") - coEvery { mailboxDao.loadAll(any()) } returns listOf( - expectedMailbox, - ) - - assertEquals(expectedMailbox, systemUnderTest(student)) - } - - @Test - fun `get mailbox for not-unique non-authorized student`() = runTest { - val student = getStudentEntity( - userName = "Stanisław Kowalski", - studentName = "J** K*******", - ) - coEvery { mailboxDao.loadAll(any()) } returns listOf( - getMailboxEntity("Jan Kowalski"), - getMailboxEntity("Jan Kurowski"), - ) - - assertNull(systemUnderTest(student)) - } - - @Test - fun `get mailbox for student with uppercase name`() = runTest { - val student = getStudentEntity( - userName = "Mochoń Julia", - studentName = "KLAUDIA MOCHOŃ", - ) - val expectedMailbox = getMailboxEntity("Klaudia Mochoń") - coEvery { mailboxDao.loadAll(any()) } returns listOf( - expectedMailbox, - ) - - assertEquals(expectedMailbox, systemUnderTest(student)) - } - - @Test - fun `get mailbox for student with second name`() = runTest { - val student = getStudentEntity( - userName = "Fistaszek Karolina", - studentName = "Julia Fistaszek", - ) - val expectedMailbox = getMailboxEntity("Julia Maria Fistaszek") - coEvery { mailboxDao.loadAll(any()) } returns listOf( - expectedMailbox, - ) - - assertEquals(expectedMailbox, systemUnderTest(student)) - } - - @Test - fun `get mailbox for student with second name and uppercase`() = runTest { - val student = getStudentEntity( - userName = "BEDNAREK KAMIL", - studentName = "ALEKSANDRA BEDNAREK", - ) - val expectedMailbox = getMailboxEntity("Aleksandra Anna Bednarek") - coEvery { mailboxDao.loadAll(any()) } returns listOf( - expectedMailbox, - ) - - assertEquals(expectedMailbox, systemUnderTest(student)) - } - - @Test - fun `get mailbox for student with mailboxes from two different schools`() = runTest { - val student = getStudentEntity( - userName = "Kamil Bednarek", - studentName = "Kamil Bednarek", - schoolShortName = "CKZiU", - ) - val mailbox1 = getMailboxEntity( - studentName = "Kamil Bednarek", - schoolShortName = "ZSTiO", - ) - val mailbox2 = getMailboxEntity( - studentName = "Kamil Bednarek", - schoolShortName = "CKZiU", - ) - coEvery { mailboxDao.loadAll(any()) } returns listOf(mailbox1, mailbox2) - - assertEquals(mailbox2, systemUnderTest(student)) - } - - private fun getMailboxEntity( - studentName: String, - schoolShortName: String = "test", - ) = Mailbox( - globalKey = "", - fullName = "", - userName = "", - email = "", - schoolId = "", - symbol = "", - studentName = studentName, - schoolNameShort = schoolShortName, - type = MailboxType.STUDENT, - ) - - private fun getStudentEntity( - studentName: String, - userName: String, - schoolShortName: String = "test", - ) = Student( - scrapperBaseUrl = "http://fakelog.cf", - email = "jan@fakelog.cf", - certificateKey = "", - classId = 0, - className = "", - isCurrent = false, - isParent = false, - loginMode = Sdk.Mode.API.name, - loginType = Sdk.ScrapperLoginType.STANDARD.name, - mobileBaseUrl = "", - password = "", - privateKey = "", - registrationDate = Instant.now(), - schoolName = "", - schoolShortName = schoolShortName, - schoolSymbol = "", - studentId = 1, - studentName = studentName, - symbol = "", - userLoginId = 1, - userName = userName, - ) -} diff --git a/app/src/test/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenterTest.kt b/app/src/test/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenterTest.kt index bf2d9f2cc..9bcfb8b6c 100644 --- a/app/src/test/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenterTest.kt +++ b/app/src/test/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenterTest.kt @@ -1,9 +1,9 @@ package io.github.wulkanowy.ui.modules.login.form import io.github.wulkanowy.MainCoroutineRule -import io.github.wulkanowy.data.pojos.RegisterUser +import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.data.repositories.StudentRepository -import io.github.wulkanowy.sdk.scrapper.Scrapper import io.github.wulkanowy.ui.modules.login.LoginErrorHandler import io.github.wulkanowy.utils.AnalyticsHelper import io.mockk.* @@ -12,6 +12,7 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import java.io.IOException +import java.time.Instant class LoginFormPresenterTest { @@ -32,15 +33,6 @@ class LoginFormPresenterTest { private lateinit var presenter: LoginFormPresenter - private val registerUser = RegisterUser( - email = "", - password = "", - login = "", - baseUrl = "", - loginType = Scrapper.LoginType.AUTO, - symbols = listOf(), - ) - @Before fun setUp() { MockKAnnotations.init(this) @@ -112,9 +104,32 @@ class LoginFormPresenterTest { @Test fun loginTest() { - coEvery { - repository.getUserSubjectsFromScrapper(any(), any(), any(), any()) - } returns registerUser + val studentTest = Student( + email = "test@", + password = "123", + scrapperBaseUrl = "https://fakelog.cf/?email", + loginType = "AUTO", + studentName = "", + schoolSymbol = "", + schoolName = "", + studentId = 0, + classId = 1, + isCurrent = false, + symbol = "", + registrationDate = Instant.now(), + className = "", + mobileBaseUrl = "", + privateKey = "", + certificateKey = "", + loginMode = "", + userLoginId = 0, + schoolShortName = "", + isParent = false, + userName = "" + ) + coEvery { repository.getStudentsScrapper(any(), any(), any(), any()) } returns listOf( + StudentWithSemesters(studentTest, emptyList()) + ) every { loginFormView.formUsernameValue } returns "@" every { loginFormView.formPassValue } returns "123456" @@ -131,9 +146,7 @@ class LoginFormPresenterTest { @Test fun loginEmptyTest() { - coEvery { - repository.getUserSubjectsFromScrapper(any(), any(), any(), any()) - } returns registerUser + coEvery { repository.getStudentsScrapper(any(), any(), any(), any()) } returns listOf() every { loginFormView.formUsernameValue } returns "@" every { loginFormView.formPassValue } returns "123456" every { loginFormView.formHostValue } returns "https://fakelog.cf/?email" @@ -149,9 +162,7 @@ class LoginFormPresenterTest { @Test fun loginEmptyTwiceTest() { - coEvery { - repository.getUserSubjectsFromScrapper(any(), any(), any(), any()) - } returns registerUser + coEvery { repository.getStudentsScrapper(any(), any(), any(), any()) } returns listOf() every { loginFormView.formUsernameValue } returns "@" every { loginFormView.formPassValue } returns "123456" every { loginFormView.formHostValue } returns "https://fakelog.cf/?email" @@ -169,14 +180,7 @@ class LoginFormPresenterTest { @Test fun loginErrorTest() { val testException = IOException("test") - coEvery { - repository.getUserSubjectsFromScrapper( - any(), - any(), - any(), - any() - ) - } throws testException + coEvery { repository.getStudentsScrapper(any(), any(), any(), any()) } throws testException every { loginFormView.formUsernameValue } returns "@" every { loginFormView.formPassValue } returns "123456" every { loginFormView.formHostValue } returns "https://fakelog.cf/?email" diff --git a/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt b/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt index cf426a50b..e52ec3ae2 100644 --- a/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt +++ b/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt @@ -1,22 +1,18 @@ package io.github.wulkanowy.ui.modules.login.studentselect import io.github.wulkanowy.MainCoroutineRule -import io.github.wulkanowy.data.pojos.RegisterStudent -import io.github.wulkanowy.data.pojos.RegisterSymbol -import io.github.wulkanowy.data.pojos.RegisterUnit -import io.github.wulkanowy.data.pojos.RegisterUser +import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.data.repositories.StudentRepository -import io.github.wulkanowy.sdk.scrapper.Scrapper import io.github.wulkanowy.services.sync.SyncManager -import io.github.wulkanowy.ui.modules.login.LoginData import io.github.wulkanowy.ui.modules.login.LoginErrorHandler import io.github.wulkanowy.utils.AnalyticsHelper -import io.github.wulkanowy.utils.AppInfo import io.mockk.* import io.mockk.impl.annotations.MockK import org.junit.Before import org.junit.Rule import org.junit.Test +import java.time.Instant class LoginStudentSelectPresenterTest { @@ -26,7 +22,7 @@ class LoginStudentSelectPresenterTest { @MockK(relaxed = true) lateinit var errorHandler: LoginErrorHandler - @MockK + @MockK(relaxed = true) lateinit var loginStudentSelectView: LoginStudentSelectView @MockK @@ -38,55 +34,33 @@ class LoginStudentSelectPresenterTest { @MockK(relaxed = true) lateinit var syncManager: SyncManager - private val appInfo = AppInfo() - private lateinit var presenter: LoginStudentSelectPresenter - private val loginData = LoginData( - login = "", - password = "", - baseUrl = "", - symbol = null, - ) - - private val subject = RegisterStudent( - studentId = 0, - studentName = "", - studentSecondName = "", - studentSurname = "", - className = "", - classId = 0, - isParent = false, - semesters = listOf(), - ) - - private val school = RegisterUnit( - userLoginId = 0, - schoolId = "", - schoolName = "", - schoolShortName = "", - parentIds = listOf(), - studentIds = listOf(), - employeeIds = listOf(), - error = null, - students = listOf(subject) - ) - - private val symbol = RegisterSymbol( - symbol = "", - error = null, - userName = "", - schools = listOf(school), - ) - - private val registerUser = RegisterUser( - email = "", - password = "", - login = "", - baseUrl = "", - loginType = Scrapper.LoginType.AUTO, - symbols = listOf(symbol), - ) + private val testStudent by lazy { + Student( + email = "test", + password = "test123", + scrapperBaseUrl = "https://fakelog.cf", + loginType = "AUTO", + symbol = "", + isCurrent = false, + studentId = 0, + schoolName = "", + schoolSymbol = "", + classId = 1, + studentName = "", + registrationDate = Instant.now(), + className = "", + loginMode = "", + certificateKey = "", + privateKey = "", + mobileBaseUrl = "", + schoolShortName = "", + userLoginId = 1, + isParent = false, + userName = "" + ) + } private val testException by lazy { RuntimeException("Problem") } @@ -95,62 +69,46 @@ class LoginStudentSelectPresenterTest { MockKAnnotations.init(this) clearMocks(studentRepository, loginStudentSelectView) - - coEvery { studentRepository.getSavedStudents(false) } returns emptyList() - every { loginStudentSelectView.initView() } just Runs - every { loginStudentSelectView.symbols } returns emptyMap() - + every { loginStudentSelectView.showContact(any()) } just Runs every { loginStudentSelectView.enableSignIn(any()) } just Runs every { loginStudentSelectView.showProgress(any()) } just Runs every { loginStudentSelectView.showContent(any()) } just Runs - presenter = LoginStudentSelectPresenter( - studentRepository = studentRepository, - loginErrorHandler = errorHandler, - syncManager = syncManager, - analytics = analytics, - appInfo = appInfo, - ) + presenter = LoginStudentSelectPresenter(studentRepository, errorHandler, syncManager, analytics) + presenter.onAttachView(loginStudentSelectView, emptyList()) } @Test fun initViewTest() { - presenter.onAttachView(loginStudentSelectView, loginData, registerUser) verify { loginStudentSelectView.initView() } } @Test fun onSelectedStudentTest() { - val itemsSlot = slot>() - every { loginStudentSelectView.updateData(capture(itemsSlot)) } just Runs - presenter.onAttachView(loginStudentSelectView, loginData, registerUser) + coEvery { + studentRepository.saveStudents(listOf(StudentWithSemesters(testStudent, emptyList()))) + } just Runs - coEvery { studentRepository.saveStudents(any()) } just Runs + every { loginStudentSelectView.openMainView() } just Runs - every { loginStudentSelectView.navigateToNext() } just Runs - - itemsSlot.captured.filterIsInstance().first().let { - it.onClick(it) - } + presenter.onItemSelected(StudentWithSemesters(testStudent, emptyList()), false) presenter.onSignIn() verify { loginStudentSelectView.showContent(false) } verify { loginStudentSelectView.showProgress(true) } - verify { loginStudentSelectView.navigateToNext() } + verify { loginStudentSelectView.openMainView() } } @Test fun onSelectedStudentErrorTest() { - val itemsSlot = slot>() - every { loginStudentSelectView.updateData(capture(itemsSlot)) } just Runs - presenter.onAttachView(loginStudentSelectView, loginData, registerUser) + coEvery { + studentRepository.saveStudents(listOf(StudentWithSemesters(testStudent, emptyList()))) + } throws testException - coEvery { studentRepository.saveStudents(any()) } throws testException + coEvery { studentRepository.logoutStudent(testStudent) } just Runs - itemsSlot.captured.filterIsInstance().first().let { - it.onClick(it) - } + presenter.onItemSelected(StudentWithSemesters(testStudent, emptyList()), false) presenter.onSignIn() verify { loginStudentSelectView.showContent(false) } diff --git a/app/src/test/java/io/github/wulkanowy/utils/SemesterExtensionKtTest.kt b/app/src/test/java/io/github/wulkanowy/utils/SemesterExtensionKtTest.kt deleted file mode 100644 index b7d3ecc94..000000000 --- a/app/src/test/java/io/github/wulkanowy/utils/SemesterExtensionKtTest.kt +++ /dev/null @@ -1,72 +0,0 @@ -package io.github.wulkanowy.utils - -import io.github.wulkanowy.data.db.entities.Semester -import io.github.wulkanowy.getSemesterEntity -import org.junit.Test -import java.time.LocalDate -import kotlin.test.assertEquals - -class SemesterExtensionKtTest { - - @Test(expected = IllegalArgumentException::class) - fun `get current semester when current is doubled`() { - val semesters = listOf( - getSemesterEntity(1, 1, LocalDate.now(), LocalDate.now()), - getSemesterEntity(1, 1, LocalDate.now(), LocalDate.now()) - ) - - semesters.getCurrentOrLast() - } - - @Test(expected = RuntimeException::class) - fun `get current semester when there is empty list`() { - val semesters = listOf() - - semesters.getCurrentOrLast() - } - - @Test - fun `get current kindergarten semester when there is no any current`() { - val semesters = listOf( - createSemesterEntity( - kindergartenDiaryId = 281, - schoolYear = 2020, - semesterId = 0, - start = LocalDate.of(2020, 9, 1), - end = LocalDate.of(2021, 8, 31), - ), - createSemesterEntity( - kindergartenDiaryId = 342, - schoolYear = 2021, - semesterId = 0, - start = LocalDate.of(2021, 9, 1), - end = LocalDate.of(2022, 8, 31), - ), - ) - - val res = semesters.getCurrentOrLast() - - assertEquals(2021, res.schoolYear) - } - - private fun createSemesterEntity( - diaryId: Int = 0, - kindergartenDiaryId: Int = 0, - semesterId: Int = 0, - schoolYear: Int = 0, - start: LocalDate = LocalDate.now(), - end: LocalDate = LocalDate.now().plusMonths(6), - ) = Semester( - studentId = 1, - diaryId = diaryId, - kindergartenDiaryId = kindergartenDiaryId, - semesterId = semesterId, - diaryName = "$semesterId", - schoolYear = schoolYear, - classId = 0, - semesterName = semesterId, - unitId = 1, - start = start, - end = end - ) -} diff --git a/build.gradle b/build.gradle index 87e201acb..98c9dfb84 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,8 @@ buildscript { ext { - kotlin_version = '1.7.21' - about_libraries = '10.5.2' - hilt_version = "2.44.2" + kotlin_version = '1.7.10' + about_libraries = '10.4.0' + hilt_version = "2.43.2" } repositories { mavenCentral() @@ -13,14 +13,14 @@ buildscript { dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" - classpath 'com.android.tools.build:gradle:7.3.1' + classpath 'com.android.tools.build:gradle:7.2.2' classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" - classpath 'com.google.gms:google-services:4.3.14' - classpath 'com.huawei.agconnect:agcp:1.7.3.302' - classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2' + classpath 'com.google.gms:google-services:4.3.13' + classpath 'com.huawei.agconnect:agcp:1.7.1.300' + classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.1' classpath "com.github.triplet.gradle:play-publisher:3.6.0" classpath "ru.cian:huawei-publish-gradle-plugin:1.3.4" - classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.5.0.2730" + classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513" classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0" classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$about_libraries" } @@ -31,7 +31,6 @@ allprojects { mavenCentral() google() maven { url "https://jitpack.io" } - maven { url "https://s01.oss.sonatype.org/content/repositories/snapshots/" } maven { url "https://developer.huawei.com/repo/" } } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927a4..7454180f2 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f42e62f37..d7e66b5c6 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists