diff --git a/.circleci/config.yml b/.circleci/config.yml index b07c9638..cad32112 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,7 +7,7 @@ references: container_config: &container_config docker: - - image: circleci/android:api-28 + - image: circleci/android@sha256:5cdc8626cc6f13efe5ed982cdcdb432b0472f8740fed8743a6461e025ad6cdfc working_directory: *workspace_root environment: environment: @@ -35,7 +35,7 @@ jobs: command: ./gradlew dependencies --no-daemon --stacktrace --console=plain -PdisablePreDex || true - run: name: Initial build - command: ./gradlew build -x test -x lint -x fabricGenerateResourcesRelease -x packageRelease --no-daemon --stacktrace --console=plain -PdisablePreDex + command: ./gradlew build -x test -x lint -x fabricGenerateResourcesFdroidRelease -x fabricGenerateResourcesPlayRelease -x packageRelease --no-daemon --stacktrace --console=plain -PdisablePreDex - run: name: Run FOSSA command: fossa --no-ansi || true @@ -56,7 +56,7 @@ jobs: <<: *general_cache_key - run: name: Run lint - command: ./gradlew lint -x fabricGenerateResourcesRelease --no-daemon --stacktrace --console=plain -PdisablePreDex + command: ./gradlew lint -x fabricGenerateResourcesFdroidRelease -x fabricGenerateResourcesPlayRelease --no-daemon --stacktrace --console=plain -PdisablePreDex - store_artifacts: path: ./app/build/reports/ destination: lint_reports/app/ @@ -75,7 +75,7 @@ jobs: <<: *general_cache_key - run: name: Run app tests - command: ./gradlew :app:test :app:jacocoTestReport -x fabricGenerateResourcesRelease --no-daemon --stacktrace --console=plain -PdisablePreDex + command: ./gradlew :app:test :app:jacocoTestReport -x fabricGenerateResourcesFdroidRelease -x fabricGenerateResourcesPlayRelease --no-daemon --stacktrace --console=plain -PdisablePreDex - run: name: Upload unit code coverage to codecov command: bash <(curl -s https://codecov.io/bash) -F app @@ -93,6 +93,9 @@ jobs: <<: *container_config steps: - *attach_workspace + - run: + name: Accept licenses + command: yes | sdkmanager --licenses && yes | sdkmanager --update - run: name: Setup emulator command: sdkmanager "system-images;android-19;default;armeabi-v7a" && echo "no" | avdmanager create avd -n test -k "system-images;android-19;default;armeabi-v7a" @@ -113,7 +116,7 @@ jobs: adb shell input keyevent 82 - run: name: Run instrumented tests - command: ./gradlew clean createDebugCoverageReport jacocoTestReport --no-daemon --stacktrace --console=plain -PdisablePreDex + command: ./gradlew clean createPlayDebugCoverageReport jacocoTestReport --no-daemon --stacktrace --console=plain -PdisablePreDex - run: name: Collect logs from emulator command: adb logcat -d > ./app/build/reports/logcat_emulator.txt @@ -159,7 +162,7 @@ jobs: openssl aes-256-cbc -d -in ./app/upload-key-encrypted.jks -k $ENCRYPT_KEY >> ./app/upload-key.jks - run: name: Publish release - command: ./gradlew publish --no-daemon --stacktrace --console=plain -PenableCrashlytics -PdisablePreDex + command: ./gradlew publishPlayRelease --no-daemon --stacktrace --console=plain -PenableCrashlytics -PdisablePreDex workflows: version: 2 diff --git a/.gitignore b/.gitignore index 6bc531b6..63783326 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,4 @@ app/key.p12 app/upload-key.jks *.log .idea/assetWizardSettings.xml +.idea/uiDesigner.xml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0d1bcd5d..a84ac839 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,7 +12,7 @@ build: script: - ./gradlew --no-daemon --stacktrace dependencies || true - ./gradlew --no-daemon --stacktrace assembleDebug - - mv app/build/outputs/apk/debug/app-debug.apk . + - mv app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk . artifacts: name: "${CI_PROJECT_NAME}_${CI_BUILD_REF_NAME}-${CI_BUILD_ID}" paths: @@ -26,7 +26,7 @@ tests: - .gradle policy: pull script: - - ./gradlew --no-daemon --stacktrace -x fabricGenerateResourcesRelease test + - ./gradlew --no-daemon --stacktrace -x fabricGenerateResourcesFdroidRelease -x fabricGenerateResourcesPlayRelease test artifacts: paths: - app/build/reports/tests @@ -39,7 +39,7 @@ lint: - .gradle policy: pull script: - - ./gradlew --no-daemon --stacktrace -x fabricGenerateResourcesRelease lint + - ./gradlew --no-daemon --stacktrace -x fabricGenerateResourcesFdroidRelease -x fabricGenerateResourcesPlayRelease lint artifacts: paths: - app/build/reports diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100644 index 7f68460d..00000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 10824e32..4c40f615 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,9 +12,8 @@ cache: - $HOME/.gradle/wrapper/ #branches: -# only: -# - master -# - 0.8.x +# only: +# - develop android: licenses: @@ -48,20 +47,20 @@ before_script: script: - ./gradlew dependencies --stacktrace --daemon - fossa --no-ansi || true - - ./gradlew lint -x fabricGenerateResourcesRelease --stacktrace --daemon - - ./gradlew test -x fabricGenerateResourcesRelease --stacktrace --daemon - - ./gradlew createDebugCoverageReport --stacktrace --daemon + #- ./gradlew lintPlayRelease -x fabricGenerateResourcesPlayRelease --stacktrace --daemon + - ./gradlew testPlayDebugUnitTest -x fabricGenerateResourcesPlay --stacktrace --daemon + - ./gradlew createPlayDebugCoverageReport --stacktrace --daemon - ./gradlew jacocoTestReport --stacktrace --daemon - if [ -z ${SONAR_HOST+x} ]; then echo "sonar scan skipped"; else git fetch --unshallow; - ./gradlew sonarqube -x test -x lint -x fabricGenerateResourcesRelease -Dsonar.host.url=$SONAR_HOST -Dsonar.organization=$SONAR_ORG -Dsonar.login=$SONAR_KEY -Dsonar.branch.name=${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} --stacktrace --daemon; + ./gradlew sonarqube -x test -x lint -x fabricGenerateResourcesPlayRelease -x fabricGenerateResourcesFdroidRelease -Dsonar.host.url=$SONAR_HOST -Dsonar.organization=$SONAR_ORG -Dsonar.login=$SONAR_KEY -Dsonar.branch.name=${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} --stacktrace --daemon; fi - | if [ $TRAVIS_TAG ]; then gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/google-services.json.gpg; gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/key.p12.gpg; gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg; - ./gradlew publish -PenableCrashlytics --stacktrace; + ./gradlew publishPlayRelease -PenableCrashlytics --stacktrace; fi after_success: diff --git a/README.md b/README.md index 97a4172c..07f06d7f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # Wulkanowy -[![CircleCI](https://img.shields.io/circleci/project/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://circleci.com/gh/wulkanowy/wulkanowy) [![Travis](https://img.shields.io/travis/com/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://travis-ci.com/wulkanowy/wulkanowy) [![Bitrise](https://img.shields.io/bitrise/daeff1893f3c8128/master.svg?token=Hjm1ACamk86JDeVVJHOeqQ&style=flat-square)](https://www.bitrise.io/app/daeff1893f3c8128) [![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy) @@ -8,6 +7,8 @@ [![Sonarcloud](https://sonarcloud.io/api/project_badges/measure?project=io.github.wulkanowy%3Aapp&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=io.github.wulkanowy%3Aapp) [![FOSSA Status](https://app.fossa.com/api/projects/custom%2B5644%2Fgithub.com%2Fwulkanowy%2Fwulkanowy.svg?type=shield)](https://app.fossa.com/projects/custom%2B5644%2Fgithub.com%2Fwulkanowy%2Fwulkanowy?ref=badge_shield) [![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)](https://f-droid.org/packages/io.github.wulkanowy/) +[![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github)](https://github.com/wulkanowy/wulkanowy/releases) [Pobierz wersję beta z Google Play](https://play.google.com/store/apps/details?id=io.github.wulkanowy&utm_source=vcs) diff --git a/app/build.gradle b/app/build.gradle index 7982e49c..e88f74c6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,8 +16,8 @@ android { testApplicationId "io.github.tests.wulkanowy" minSdkVersion 15 targetSdkVersion 28 - versionCode 37 - versionName "0.8.4" + versionCode 38 + versionName "0.9.0" multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true @@ -63,6 +63,18 @@ android { } } + flavorDimensions "platform" + productFlavors { + play { + dimension "platform" + } + + fdroid { + buildConfigField "boolean", "CRASHLYTICS_ENABLED", "false" + dimension "platform" + } + } + lintOptions { disable 'HardwareIds' } @@ -85,7 +97,7 @@ play { } dependencies { - implementation 'io.github.wulkanowy:api:0.8.4' + implementation 'io.github.wulkanowy:api:0.9.0' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "androidx.legacy:legacy-support-v4:1.0.0" @@ -94,20 +106,20 @@ dependencies { implementation "androidx.cardview:cardview:1.0.0" implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation "com.google.android.material:material:1.1.0-alpha05" + implementation "com.google.android.material:material:1.1.0-alpha07" implementation 'com.github.wulkanowy:MaterialChipsInput:b72fd0ee6f' implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0' implementation "androidx.work:work-runtime:2.0.1" implementation "androidx.work:work-rxjava2:2.0.1" - implementation "androidx.room:room-runtime:2.1.0-alpha07" - implementation "androidx.room:room-rxjava2:2.1.0-alpha07" - kapt "androidx.room:room-compiler:2.1.0-alpha07" + implementation "androidx.room:room-runtime:2.1.0-rc01" + implementation "androidx.room:room-rxjava2:2.1.0-rc01" + kapt "androidx.room:room-compiler:2.1.0-rc01" - implementation "com.google.dagger:dagger-android-support:2.22.1" - kapt "com.google.dagger:dagger-compiler:2.22.1" - kapt "com.google.dagger:dagger-android-processor:2.22.1" + implementation "com.google.dagger:dagger-android-support:2.23.1" + kapt "com.google.dagger:dagger-compiler:2.23.1" + kapt "com.google.dagger:dagger-android-processor:2.23.1" implementation 'com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0' kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.4.0' @@ -116,21 +128,21 @@ dependencies { implementation "com.aurelhubert:ahbottomnavigation:2.3.4" implementation 'com.ncapdevi:frag-nav:3.2.0' - implementation 'com.github.pwittchen:reactivenetwork-rx2:3.0.2' + implementation 'com.github.pwittchen:reactivenetwork-rx2:3.0.3' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' - implementation "io.reactivex.rxjava2:rxjava:2.2.8" + implementation "io.reactivex.rxjava2:rxjava:2.2.9" implementation 'com.google.code.gson:gson:2.8.5' implementation "com.jakewharton.threetenabp:threetenabp:1.2.0" implementation "com.jakewharton.timber:timber:4.7.1" implementation "at.favre.lib:slf4j-timber:1.0.1" - implementation "com.squareup.okhttp3:logging-interceptor:3.12.1" + implementation "com.squareup.okhttp3:logging-interceptor:3.12.3" implementation "com.mikepenz:aboutlibraries:6.2.3" implementation 'com.takisoft.preferencex:preferencex:1.0.0' - implementation 'com.google.firebase:firebase-core:16.0.8' - implementation 'com.crashlytics.sdk.android:crashlytics:2.9.9' + playImplementation 'com.google.firebase:firebase-core:16.0.9' + playImplementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' releaseImplementation 'fr.o80.chucker:library-no-op:2.0.4' @@ -139,16 +151,22 @@ dependencies { testImplementation "junit:junit:4.12" testImplementation "io.mockk:mockk:1.9.2" - testImplementation "org.mockito:mockito-inline:2.27.0" - testImplementation 'org.threeten:threetenbp:1.3.8' + testImplementation 'org.threeten:threetenbp:1.4.0' + testImplementation "org.mockito:mockito-core:2.28.2" + testImplementation("org.mockito:mockito-inline:2.28.2") { + exclude group: 'org.mockito', module: 'mockito-core' + } - androidTestImplementation 'androidx.test:core:1.1.0' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.ext:junit:1.1.0' + androidTestImplementation 'androidx.test:core:1.2.0' + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation "io.mockk:mockk-android:1.9.2" - androidTestImplementation 'org.mockito:mockito-android:2.27.0' - androidTestImplementation "androidx.room:room-testing:2.1.0-alpha07" + androidTestImplementation "androidx.room:room-testing:2.1.0-rc01" androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" + androidTestImplementation "org.mockito:mockito-core:2.28.2" + androidTestImplementation('org.mockito:mockito-android:2.28.2') { + exclude group: 'org.mockito', module: 'mockito-core' + } } apply plugin: 'com.google.gms.google-services' diff --git a/app/jacoco.gradle b/app/jacoco.gradle index f22c3359..44cd3f62 100644 --- a/app/jacoco.gradle +++ b/app/jacoco.gradle @@ -35,11 +35,14 @@ task jacocoTestReport(type: JacocoReport) { dir: "$buildDir/intermediates/classes/debug", excludes: excludes ) + fileTree( - dir: "$buildDir/tmp/kotlin-classes/debug", + dir: "$buildDir/tmp/kotlin-classes/playDebug", excludes: excludes )) - sourceDirectories.setFrom(files("$project.projectDir/src/main/java")) + sourceDirectories.setFrom(files([ + "src/main/java", + "src/play/java" + ])) executionData.setFrom(fileTree( dir: project.projectDir, includes: ["**/*.exec", "**/*.ec"] diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/14.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/14.json new file mode 100644 index 00000000..82b76492 --- /dev/null +++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/14.json @@ -0,0 +1,1386 @@ +{ + "formatVersion": 1, + "database": { + "version": 14, + "identityHash": "b22945c41e7841ff2e6b16af346dde0c", + "entities": [ + { + "tableName": "Students", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `endpoint` TEXT NOT NULL, `loginType` TEXT NOT NULL, `email` TEXT NOT NULL, `password` TEXT NOT NULL, `symbol` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_name` TEXT NOT NULL, `class_name` TEXT NOT NULL, `class_id` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `registration_date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "endpoint", + "columnName": "endpoint", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginType", + "columnName": "loginType", + "affinity": "TEXT", + "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": "studentName", + "columnName": "student_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolSymbol", + "columnName": "school_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolName", + "columnName": "school_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "className", + "columnName": "class_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isCurrent", + "columnName": "is_current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "registrationDate", + "columnName": "registration_date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_Students_email_symbol_student_id_school_id_class_id", + "unique": true, + "columnNames": [ + "email", + "symbol", + "student_id", + "school_id", + "class_id" + ], + "createSql": "CREATE UNIQUE INDEX `index_Students_email_symbol_student_id_school_id_class_id` ON `${TABLE_NAME}` (`email`, `symbol`, `student_id`, `school_id`, `class_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Semesters", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryName", + "columnName": "diary_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolYear", + "columnName": "school_year", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterName", + "columnName": "semester_name", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isCurrent", + "columnName": "is_current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "unit_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_Semesters_student_id_diary_id_semester_id", + "unique": true, + "columnNames": [ + "student_id", + "diary_id", + "semester_id" + ], + "createSql": "CREATE UNIQUE INDEX `index_Semesters_student_id_diary_id_semester_id` ON `${TABLE_NAME}` (`student_id`, `diary_id`, `semester_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Exams", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `group` TEXT NOT NULL, `type` TEXT NOT NULL, `description` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryDate", + "columnName": "entry_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "group", + "columnName": "group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Timetable", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `number` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `subjectOld` TEXT NOT NULL, `group` TEXT NOT NULL, `room` TEXT NOT NULL, `roomOld` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacherOld` TEXT NOT NULL, `info` TEXT NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subjectOld", + "columnName": "subjectOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "group", + "columnName": "group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "room", + "columnName": "room", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roomOld", + "columnName": "roomOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherOld", + "columnName": "teacherOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "info", + "columnName": "info", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "changes", + "columnName": "changes", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "canceled", + "columnName": "canceled", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Attendance", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `excused` INTEGER NOT NULL, `deleted` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "presence", + "columnName": "presence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "exemption", + "columnName": "exemption", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lateness", + "columnName": "lateness", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excused", + "columnName": "excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deleted", + "columnName": "deleted", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "AttendanceSummary", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `subject_id` INTEGER NOT NULL, `month` INTEGER NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `absence_excused` INTEGER NOT NULL, `absence_for_school_reasons` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `lateness_excused` INTEGER NOT NULL, `exemption` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subjectId", + "columnName": "subject_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "month", + "columnName": "month", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "presence", + "columnName": "presence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absenceExcused", + "columnName": "absence_excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absenceForSchoolReasons", + "columnName": "absence_for_school_reasons", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lateness", + "columnName": "lateness", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "latenessExcused", + "columnName": "lateness_excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "exemption", + "columnName": "exemption", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Grades", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `entry` TEXT NOT NULL, `value` INTEGER NOT NULL, `modifier` REAL NOT NULL, `comment` TEXT NOT NULL, `color` TEXT NOT NULL, `grade_symbol` TEXT NOT NULL, `description` TEXT NOT NULL, `weight` TEXT NOT NULL, `weightValue` REAL NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRead", + "columnName": "is_read", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "entry", + "columnName": "entry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "modifier", + "columnName": "modifier", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "comment", + "columnName": "comment", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "gradeSymbol", + "columnName": "grade_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "weight", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weightValue", + "columnName": "weightValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesSummary", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `position` INTEGER NOT NULL, `subject` TEXT NOT NULL, `predicted_grade` TEXT NOT NULL, `final_grade` TEXT NOT NULL, `proposed_points` TEXT NOT NULL, `final_points` TEXT NOT NULL, `points_sum` TEXT NOT NULL, `average` REAL NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "predictedGrade", + "columnName": "predicted_grade", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "finalGrade", + "columnName": "final_grade", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "proposedPoints", + "columnName": "proposed_points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "finalPoints", + "columnName": "final_points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pointsSum", + "columnName": "points_sum", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "average", + "columnName": "average", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesStatistics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `grade` INTEGER NOT NULL, `amount` INTEGER NOT NULL, `is_semester` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "grade", + "columnName": "grade", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semester", + "columnName": "is_semester", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `content` TEXT, `student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `recipient_name` TEXT NOT NULL, `subject` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `unread_by` INTEGER NOT NULL, `read_by` INTEGER NOT NULL, `removed` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sender", + "columnName": "sender_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "sender_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "recipient", + "columnName": "recipient_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "folderId", + "columnName": "folder_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unread", + "columnName": "unread", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unreadBy", + "columnName": "unread_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "readBy", + "columnName": "read_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "removed", + "columnName": "removed", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Notes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `category` TEXT NOT NULL, `content` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRead", + "columnName": "is_read", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Homework", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryDate", + "columnName": "entry_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Subjects", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "LuckyNumbers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "luckyNumber", + "columnName": "lucky_number", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "CompletedLesson", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `topic` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `substitution` TEXT NOT NULL, `absence` TEXT NOT NULL, `resources` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "topic", + "columnName": "topic", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "substitution", + "columnName": "substitution", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "resources", + "columnName": "resources", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "ReportingUnits", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `short` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `roles` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shortName", + "columnName": "short", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "sender_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "senderName", + "columnName": "sender_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roles", + "columnName": "roles", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Recipients", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` TEXT NOT NULL, `name` TEXT NOT NULL, `real_name` TEXT NOT NULL, `login_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `role` INTEGER NOT NULL, `hash` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "realName", + "columnName": "real_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginId", + "columnName": "login_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "unit_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "role", + "columnName": "role", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hash", + "columnName": "hash", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + } + ], + "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, 'b22945c41e7841ff2e6b16af346dde0c')" + ] + } +} \ No newline at end of file diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/15.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/15.json new file mode 100644 index 00000000..6f2d1d1d --- /dev/null +++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/15.json @@ -0,0 +1,1430 @@ +{ + "formatVersion": 1, + "database": { + "version": 15, + "identityHash": "84b300bf53c7dd70b60a29a842275bb2", + "entities": [ + { + "tableName": "Students", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `endpoint` TEXT NOT NULL, `loginType` TEXT NOT NULL, `email` TEXT NOT NULL, `password` TEXT NOT NULL, `symbol` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_name` TEXT NOT NULL, `class_name` TEXT NOT NULL, `class_id` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `registration_date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "endpoint", + "columnName": "endpoint", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginType", + "columnName": "loginType", + "affinity": "TEXT", + "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": "studentName", + "columnName": "student_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolSymbol", + "columnName": "school_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolName", + "columnName": "school_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "className", + "columnName": "class_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isCurrent", + "columnName": "is_current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "registrationDate", + "columnName": "registration_date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_Students_email_symbol_student_id_school_id_class_id", + "unique": true, + "columnNames": [ + "email", + "symbol", + "student_id", + "school_id", + "class_id" + ], + "createSql": "CREATE UNIQUE INDEX `index_Students_email_symbol_student_id_school_id_class_id` ON `${TABLE_NAME}` (`email`, `symbol`, `student_id`, `school_id`, `class_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Semesters", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryName", + "columnName": "diary_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolYear", + "columnName": "school_year", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterName", + "columnName": "semester_name", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isCurrent", + "columnName": "is_current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "unit_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_Semesters_student_id_diary_id_semester_id", + "unique": true, + "columnNames": [ + "student_id", + "diary_id", + "semester_id" + ], + "createSql": "CREATE UNIQUE INDEX `index_Semesters_student_id_diary_id_semester_id` ON `${TABLE_NAME}` (`student_id`, `diary_id`, `semester_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Exams", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `group` TEXT NOT NULL, `type` TEXT NOT NULL, `description` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryDate", + "columnName": "entry_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "group", + "columnName": "group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Timetable", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `number` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `subjectOld` TEXT NOT NULL, `group` TEXT NOT NULL, `room` TEXT NOT NULL, `roomOld` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacherOld` TEXT NOT NULL, `info` TEXT NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subjectOld", + "columnName": "subjectOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "group", + "columnName": "group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "room", + "columnName": "room", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roomOld", + "columnName": "roomOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherOld", + "columnName": "teacherOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "info", + "columnName": "info", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "changes", + "columnName": "changes", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "canceled", + "columnName": "canceled", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Attendance", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `excused` INTEGER NOT NULL, `deleted` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "presence", + "columnName": "presence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "exemption", + "columnName": "exemption", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lateness", + "columnName": "lateness", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excused", + "columnName": "excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deleted", + "columnName": "deleted", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "AttendanceSummary", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `subject_id` INTEGER NOT NULL, `month` INTEGER NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `absence_excused` INTEGER NOT NULL, `absence_for_school_reasons` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `lateness_excused` INTEGER NOT NULL, `exemption` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subjectId", + "columnName": "subject_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "month", + "columnName": "month", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "presence", + "columnName": "presence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absenceExcused", + "columnName": "absence_excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absenceForSchoolReasons", + "columnName": "absence_for_school_reasons", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lateness", + "columnName": "lateness", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "latenessExcused", + "columnName": "lateness_excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "exemption", + "columnName": "exemption", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Grades", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `entry` TEXT NOT NULL, `value` INTEGER NOT NULL, `modifier` REAL NOT NULL, `comment` TEXT NOT NULL, `color` TEXT NOT NULL, `grade_symbol` TEXT NOT NULL, `description` TEXT NOT NULL, `weight` TEXT NOT NULL, `weightValue` REAL NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRead", + "columnName": "is_read", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "entry", + "columnName": "entry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "modifier", + "columnName": "modifier", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "comment", + "columnName": "comment", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "gradeSymbol", + "columnName": "grade_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "weight", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weightValue", + "columnName": "weightValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesSummary", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `position` INTEGER NOT NULL, `subject` TEXT NOT NULL, `predicted_grade` TEXT NOT NULL, `final_grade` TEXT NOT NULL, `proposed_points` TEXT NOT NULL, `final_points` TEXT NOT NULL, `points_sum` TEXT NOT NULL, `average` REAL NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "predictedGrade", + "columnName": "predicted_grade", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "finalGrade", + "columnName": "final_grade", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "proposedPoints", + "columnName": "proposed_points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "finalPoints", + "columnName": "final_points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pointsSum", + "columnName": "points_sum", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "average", + "columnName": "average", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesStatistics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `grade` INTEGER NOT NULL, `amount` INTEGER NOT NULL, `is_semester` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "grade", + "columnName": "grade", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semester", + "columnName": "is_semester", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `content` TEXT, `student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `recipient_name` TEXT NOT NULL, `subject` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `unread_by` INTEGER NOT NULL, `read_by` INTEGER NOT NULL, `removed` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sender", + "columnName": "sender_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "sender_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "recipient", + "columnName": "recipient_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "folderId", + "columnName": "folder_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unread", + "columnName": "unread", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unreadBy", + "columnName": "unread_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "readBy", + "columnName": "read_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "removed", + "columnName": "removed", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Notes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `category` TEXT NOT NULL, `content` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRead", + "columnName": "is_read", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Homework", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryDate", + "columnName": "entry_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Subjects", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "LuckyNumbers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "luckyNumber", + "columnName": "lucky_number", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "CompletedLesson", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `topic` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `substitution` TEXT NOT NULL, `absence` TEXT NOT NULL, `resources` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "topic", + "columnName": "topic", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "substitution", + "columnName": "substitution", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "resources", + "columnName": "resources", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "ReportingUnits", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `short` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `roles` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shortName", + "columnName": "short", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "sender_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "senderName", + "columnName": "sender_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roles", + "columnName": "roles", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Recipients", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` TEXT NOT NULL, `name` TEXT NOT NULL, `real_name` TEXT NOT NULL, `login_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `role` INTEGER NOT NULL, `hash` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "realName", + "columnName": "real_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginId", + "columnName": "login_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "unit_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "role", + "columnName": "role", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hash", + "columnName": "hash", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "MobileDevices", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deviceId", + "columnName": "device_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + } + ], + "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, '84b300bf53c7dd70b60a29a842275bb2')" + ] + } +} \ No newline at end of file diff --git a/app/sonarqube.gradle b/app/sonarqube.gradle index 52fd2dd8..3dad1034 100644 --- a/app/sonarqube.gradle +++ b/app/sonarqube.gradle @@ -29,5 +29,6 @@ sonarqube { property "sonar.java.coveragePlugin", "jacoco" property "sonar.android.lint.report", "build/reports/lint-results.xml" property "sonar.jacoco.reportPaths", fileTree(dir: project.projectDir, includes: ['**/*.exec', '**/*.ec']) + property "sonar.coverage.jacoco.xmlReportPaths", "build/reports/jacocoTestReport/jacocoTestReport.xml" } } diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/db/migrations/AbstractMigrationTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/db/migrations/AbstractMigrationTest.kt index 507105f6..f720663b 100644 --- a/app/src/androidTest/java/io/github/wulkanowy/data/db/migrations/AbstractMigrationTest.kt +++ b/app/src/androidTest/java/io/github/wulkanowy/data/db/migrations/AbstractMigrationTest.kt @@ -22,7 +22,12 @@ abstract class AbstractMigrationTest { fun getMigratedRoomDatabase(): AppDatabase { val database = Room.databaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java, dbName) - .addMigrations(Migration12(), Migration13()) + .addMigrations( + Migration12(), + Migration13(), + Migration14(), + Migration15() + ) .build() // close the database and release any stream resources when the test finishes helper.closeWhenFinished(database) diff --git a/app/src/fdroid/java/io/github/wulkanowy/utils/CrashlyticsUtils.kt b/app/src/fdroid/java/io/github/wulkanowy/utils/CrashlyticsUtils.kt new file mode 100644 index 00000000..33ef5a58 --- /dev/null +++ b/app/src/fdroid/java/io/github/wulkanowy/utils/CrashlyticsUtils.kt @@ -0,0 +1,17 @@ +@file:Suppress("UNUSED_PARAMETER") + +package io.github.wulkanowy.utils + +import android.content.Context +import timber.log.Timber + +class CrashlyticsTree : Timber.Tree() { + + override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { + // do nothing + } +} + +fun initCrashlytics(context: Context) { + // do nothing +} diff --git a/app/src/fdroid/java/io/github/wulkanowy/utils/FirebaseAnalyticsHelper.kt b/app/src/fdroid/java/io/github/wulkanowy/utils/FirebaseAnalyticsHelper.kt new file mode 100644 index 00000000..0b1274f1 --- /dev/null +++ b/app/src/fdroid/java/io/github/wulkanowy/utils/FirebaseAnalyticsHelper.kt @@ -0,0 +1,13 @@ +package io.github.wulkanowy.utils + +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class FirebaseAnalyticsHelper @Inject constructor() { + + @Suppress("UNUSED_PARAMETER") + fun logEvent(name: String, vararg params: Pair) { + // do nothing + } +} diff --git a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt index a58a9804..35a0e8da 100644 --- a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt +++ b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt @@ -4,21 +4,18 @@ import android.content.Context import androidx.multidex.MultiDex import androidx.work.Configuration import androidx.work.WorkManager -import com.crashlytics.android.Crashlytics -import com.crashlytics.android.core.CrashlyticsCore import com.jakewharton.threetenabp.AndroidThreeTen import dagger.android.AndroidInjector import dagger.android.support.DaggerApplication import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.utils.Log -import io.fabric.sdk.android.Fabric -import io.github.wulkanowy.BuildConfig.CRASHLYTICS_ENABLED import io.github.wulkanowy.BuildConfig.DEBUG import io.github.wulkanowy.di.DaggerAppComponent import io.github.wulkanowy.services.sync.SyncWorkerFactory import io.github.wulkanowy.utils.ActivityLifecycleLogger import io.github.wulkanowy.utils.CrashlyticsTree import io.github.wulkanowy.utils.DebugLogTree +import io.github.wulkanowy.utils.initCrashlytics import io.reactivex.exceptions.UndeliverableException import io.reactivex.plugins.RxJavaPlugins import timber.log.Timber @@ -41,7 +38,7 @@ class WulkanowyApp : DaggerApplication() { WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(workerFactory).build()) RxJavaPlugins.setErrorHandler(::onError) - initCrashlytics() + initCrashlytics(applicationContext) initLogging() } @@ -55,12 +52,6 @@ class WulkanowyApp : DaggerApplication() { registerActivityLifecycleCallbacks(ActivityLifecycleLogger()) } - private fun initCrashlytics() { - Fabric.with(Fabric.Builder(this).kits( - Crashlytics.Builder().core(CrashlyticsCore.Builder().disabled(!CRASHLYTICS_ENABLED).build()).build() - ).debuggable(DEBUG).build()) - } - private fun onError(error: Throwable) { if (error is UndeliverableException && error.cause is IOException || error.cause is InterruptedException) { Timber.e(error.cause, "An undeliverable error occurred") diff --git a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt index c832368a..97da6bb8 100644 --- a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt +++ b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt @@ -132,4 +132,8 @@ internal class RepositoryModule { @Singleton @Provides fun provideRecipientDao(database: AppDatabase) = database.recipientDao + + @Singleton + @Provides + fun provideMobileDevicesDao(database: AppDatabase) = database.mobileDeviceDao } 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 d867583e..a97a3042 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 @@ -16,6 +16,7 @@ import io.github.wulkanowy.data.db.dao.GradeSummaryDao import io.github.wulkanowy.data.db.dao.HomeworkDao import io.github.wulkanowy.data.db.dao.LuckyNumberDao import io.github.wulkanowy.data.db.dao.MessagesDao +import io.github.wulkanowy.data.db.dao.MobileDeviceDao import io.github.wulkanowy.data.db.dao.NoteDao import io.github.wulkanowy.data.db.dao.RecipientDao import io.github.wulkanowy.data.db.dao.ReportingUnitDao @@ -33,6 +34,7 @@ import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.db.entities.Homework import io.github.wulkanowy.data.db.entities.LuckyNumber import io.github.wulkanowy.data.db.entities.Message +import io.github.wulkanowy.data.db.entities.MobileDevice import io.github.wulkanowy.data.db.entities.Note import io.github.wulkanowy.data.db.entities.Recipient import io.github.wulkanowy.data.db.entities.ReportingUnit @@ -44,6 +46,8 @@ import io.github.wulkanowy.data.db.migrations.Migration10 import io.github.wulkanowy.data.db.migrations.Migration11 import io.github.wulkanowy.data.db.migrations.Migration12 import io.github.wulkanowy.data.db.migrations.Migration13 +import io.github.wulkanowy.data.db.migrations.Migration14 +import io.github.wulkanowy.data.db.migrations.Migration15 import io.github.wulkanowy.data.db.migrations.Migration2 import io.github.wulkanowy.data.db.migrations.Migration3 import io.github.wulkanowy.data.db.migrations.Migration4 @@ -73,7 +77,8 @@ import javax.inject.Singleton LuckyNumber::class, CompletedLesson::class, ReportingUnit::class, - Recipient::class + Recipient::class, + MobileDevice::class ], version = AppDatabase.VERSION_SCHEMA, exportSchema = true @@ -82,7 +87,7 @@ import javax.inject.Singleton abstract class AppDatabase : RoomDatabase() { companion object { - const val VERSION_SCHEMA = 13 + const val VERSION_SCHEMA = 15 fun newInstance(context: Context): AppDatabase { return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database") @@ -101,7 +106,9 @@ abstract class AppDatabase : RoomDatabase() { Migration10(), Migration11(), Migration12(), - Migration13() + Migration13(), + Migration14(), + Migration15() ) .build() } @@ -140,4 +147,6 @@ abstract class AppDatabase : RoomDatabase() { abstract val reportingUnitDao: ReportingUnitDao abstract val recipientDao: RecipientDao + + abstract val mobileDeviceDao: MobileDeviceDao } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/MobileDeviceDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/MobileDeviceDao.kt new file mode 100644 index 00000000..d6b97f6a --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/MobileDeviceDao.kt @@ -0,0 +1,21 @@ +package io.github.wulkanowy.data.db.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import io.github.wulkanowy.data.db.entities.MobileDevice +import io.reactivex.Maybe + +@Dao +interface MobileDeviceDao { + + @Insert + fun insertAll(devices: List) + + @Delete + fun deleteAll(devices: List) + + @Query("SELECT * FROM MobileDevices WHERE student_id = :studentId ORDER BY date DESC") + fun loadAll(studentId: Int): Maybe> +} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/GradeSummary.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/GradeSummary.kt index e6ac4926..6e29112b 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/entities/GradeSummary.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/GradeSummary.kt @@ -13,11 +13,26 @@ data class GradeSummary( @ColumnInfo(name = "student_id") val studentId: Int, + val position: Int, + val subject: String, + @ColumnInfo(name = "predicted_grade") val predictedGrade: String, - val finalGrade: String + @ColumnInfo(name = "final_grade") + val finalGrade: String, + + @ColumnInfo(name = "proposed_points") + val proposedPoints: String, + + @ColumnInfo(name = "final_points") + val finalPoints: String, + + @ColumnInfo(name = "points_sum") + val pointsSum: String, + + val average: Double ) { @PrimaryKey(autoGenerate = true) var id: Long = 0 diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/MobileDevice.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/MobileDevice.kt new file mode 100644 index 00000000..f67ed599 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/MobileDevice.kt @@ -0,0 +1,25 @@ +package io.github.wulkanowy.data.db.entities + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import org.threeten.bp.LocalDateTime +import java.io.Serializable + +@Entity(tableName = "MobileDevices") +data class MobileDevice( + + @ColumnInfo(name = "student_id") + val studentId: Int, + + @ColumnInfo(name = "device_id") + val deviceId: Int, + + val name: String, + + val date: LocalDateTime +) : Serializable { + + @PrimaryKey(autoGenerate = true) + var id: Long = 0 +} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration14.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration14.kt new file mode 100644 index 00000000..4dac0d30 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration14.kt @@ -0,0 +1,26 @@ +package io.github.wulkanowy.data.db.migrations + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +class Migration14 : Migration(13, 14) { + + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("DROP TABLE IF EXISTS GradesSummary") + database.execSQL(""" + CREATE TABLE IF NOT EXISTS GradesSummary ( + id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + semester_id INTEGER NOT NULL, + student_id INTEGER NOT NULL, + position INTEGER NOT NULL, + subject TEXT NOT NULL, + predicted_grade TEXT NOT NULL, + final_grade TEXT NOT NULL, + proposed_points TEXT NOT NULL, + final_points TEXT NOT NULL, + points_sum TEXT NOT NULL, + average REAL NOT NULL + ) + """) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration15.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration15.kt new file mode 100644 index 00000000..5be49a95 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration15.kt @@ -0,0 +1,19 @@ +package io.github.wulkanowy.data.db.migrations + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +class Migration15 : Migration(14, 15) { + + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL(""" + CREATE TABLE IF NOT EXISTS MobileDevices ( + id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + student_id INTEGER NOT NULL, + device_id INTEGER NOT NULL, + name TEXT NOT NULL, + date INTEGER NOT NULL + ) + """) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/pojos/MobileDeviceToken.kt b/app/src/main/java/io/github/wulkanowy/data/pojos/MobileDeviceToken.kt new file mode 100644 index 00000000..40101821 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/pojos/MobileDeviceToken.kt @@ -0,0 +1,12 @@ +package io.github.wulkanowy.data.pojos + +data class MobileDeviceToken( + + val token: String, + + val symbol: String, + + val pin: String, + + val qr: String +) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt index d395decf..3335cfb0 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt @@ -18,9 +18,14 @@ class GradeSummaryRemote @Inject constructor(private val api: Api) { GradeSummary( semesterId = semester.semesterId, studentId = semester.studentId, + position = it.order, subject = it.name, predictedGrade = it.predicted, - finalGrade = it.final + finalGrade = it.final, + pointsSum = it.pointsSum, + proposedPoints = it.proposedPoints, + finalPoints = it.finalPoints, + average = it.average ) } } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceLocal.kt new file mode 100644 index 00000000..8f0efa5b --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceLocal.kt @@ -0,0 +1,25 @@ +package io.github.wulkanowy.data.repositories.mobiledevice + +import io.github.wulkanowy.data.db.dao.MobileDeviceDao +import io.github.wulkanowy.data.db.entities.MobileDevice +import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student +import io.reactivex.Maybe +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class MobileDeviceLocal @Inject constructor(private val mobileDb: MobileDeviceDao) { + + fun saveDevices(devices: List) { + mobileDb.insertAll(devices) + } + + fun deleteDevices(devices: List) { + mobileDb.deleteAll(devices) + } + + fun getDevices(semester: Semester): Maybe> { + return mobileDb.loadAll(semester.studentId).filter { it.isNotEmpty() } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRemote.kt new file mode 100644 index 00000000..86fdce97 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRemote.kt @@ -0,0 +1,47 @@ +package io.github.wulkanowy.data.repositories.mobiledevice + +import io.github.wulkanowy.api.Api +import io.github.wulkanowy.data.db.entities.MobileDevice +import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.pojos.MobileDeviceToken +import io.github.wulkanowy.utils.toLocalDateTime +import io.reactivex.Single +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class MobileDeviceRemote @Inject constructor(private val api: Api) { + + fun getDevices(semester: Semester): Single> { + return Single.just(api.apply { diaryId = semester.diaryId }) + .flatMap { api.getRegisteredDevices() } + .map { devices -> + devices.map { + MobileDevice( + studentId = semester.studentId, + date = it.date.toLocalDateTime(), + deviceId = it.id, + name = it.name + ) + } + } + } + + fun unregisterDevice(semester: Semester, device: MobileDevice): Single { + return Single.just(api.apply { diaryId = semester.diaryId }) + .flatMap { api.unregisterDevice(device.deviceId) } + } + + fun getToken(semester: Semester): Single { + return Single.just(api.apply { diaryId = semester.diaryId }) + .flatMap { api.getToken() } + .map { + MobileDeviceToken( + token = it.token, + symbol = it.symbol, + pin = it.pin, + qr = it.qrCodeImage + ) + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRepository.kt new file mode 100644 index 00000000..3643a701 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRepository.kt @@ -0,0 +1,44 @@ +package io.github.wulkanowy.data.repositories.mobiledevice + +import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork +import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings +import io.github.wulkanowy.data.db.entities.MobileDevice +import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.pojos.MobileDeviceToken +import io.github.wulkanowy.utils.uniqueSubtract +import io.reactivex.Single +import java.net.UnknownHostException +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class MobileDeviceRepository @Inject constructor( + private val settings: InternetObservingSettings, + private val local: MobileDeviceLocal, + private val remote: MobileDeviceRemote +) { + + fun getDevices(semester: Semester, forceRefresh: Boolean = false): Single> { + return local.getDevices(semester).filter { !forceRefresh } + .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) + .flatMap { + if (it) remote.getDevices(semester) + else Single.error(UnknownHostException()) + }.flatMap { new -> + local.getDevices(semester).toSingle(emptyList()) + .doOnSuccess { old -> + local.deleteDevices(old uniqueSubtract new) + local.saveDevices(new uniqueSubtract old) + } + } + ).flatMap { local.getDevices(semester).toSingle(emptyList()) } + } + + fun unregisterDevice(semester: Semester, device: MobileDevice): Single { + return remote.unregisterDevice(semester, device) + } + + fun getToken(semester: Semester): Single { + return remote.getToken(semester) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/preferences/PreferencesRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/preferences/PreferencesRepository.kt index 91717ed7..bde84162 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/preferences/PreferencesRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/preferences/PreferencesRepository.kt @@ -40,7 +40,7 @@ class PreferencesRepository @Inject constructor( val servicesOnlyWifiKey: String = context.getString(R.string.pref_key_services_wifi_only) val isServicesOnlyWifi: Boolean - get() = sharedPref.getBoolean(servicesOnlyWifiKey, true) + get() = sharedPref.getBoolean(servicesOnlyWifiKey, false) val isNotificationsEnable: Boolean get() = sharedPref.getBoolean(context.getString(R.string.pref_key_notifications_enable), true) diff --git a/app/src/main/java/io/github/wulkanowy/di/AppModule.kt b/app/src/main/java/io/github/wulkanowy/di/AppModule.kt index da1d8f7a..9ea2bf10 100644 --- a/app/src/main/java/io/github/wulkanowy/di/AppModule.kt +++ b/app/src/main/java/io/github/wulkanowy/di/AppModule.kt @@ -2,7 +2,6 @@ package io.github.wulkanowy.di import android.appwidget.AppWidgetManager import android.content.Context -import com.google.firebase.analytics.FirebaseAnalytics import dagger.Module import dagger.Provides import eu.davidea.flexibleadapter.FlexibleAdapter @@ -27,10 +26,6 @@ internal class AppModule { @Provides fun provideFlexibleAdapter() = FlexibleAdapter>(null, null, true) - @Singleton - @Provides - fun provideFirebaseAnalytics(context: Context) = FirebaseAnalytics.getInstance(context) - @Singleton @Provides fun provideAppWidgetManager(context: Context): AppWidgetManager = AppWidgetManager.getInstance(context) diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.kt index d8b53607..0879aa3c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.kt @@ -1,8 +1,11 @@ package io.github.wulkanowy.ui.base +import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK +import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.os.Bundle import android.view.View import android.widget.Toast +import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate import androidx.fragment.app.Fragment @@ -12,10 +15,12 @@ import dagger.android.AndroidInjection import dagger.android.DispatchingAndroidInjector import dagger.android.support.HasSupportFragmentInjector import io.github.wulkanowy.R +import io.github.wulkanowy.ui.modules.login.LoginActivity import io.github.wulkanowy.utils.FragmentLifecycleLogger import javax.inject.Inject -abstract class BaseActivity : AppCompatActivity(), BaseView, HasSupportFragmentInjector { +abstract class BaseActivity> : AppCompatActivity(), BaseView, + HasSupportFragmentInjector { @Inject lateinit var supportFragmentInjector: DispatchingAndroidInjector @@ -28,6 +33,8 @@ abstract class BaseActivity : AppCompatActivity(), BaseView, HasSupportFragmentI protected var messageContainer: View? = null + abstract var presenter: T + public override fun onCreate(savedInstanceState: Bundle?) { AndroidInjection.inject(this) themeManager.applyTheme(this) @@ -51,9 +58,24 @@ abstract class BaseActivity : AppCompatActivity(), BaseView, HasSupportFragmentI else Toast.makeText(this, text, Toast.LENGTH_LONG).show() } + override fun showExpiredDialog() { + AlertDialog.Builder(this) + .setTitle(R.string.main_session_expired) + .setMessage(R.string.main_session_relogin) + .setPositiveButton(R.string.main_log_in) { _, _ -> presenter.onExpiredLoginSelected() } + .setNegativeButton(android.R.string.cancel) { _, _ -> } + .show() + } + + override fun openClearLoginView() { + startActivity(LoginActivity.getStartIntent(this) + .apply { addFlags(FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK) }) + } + override fun onDestroy() { super.onDestroy() invalidateOptionsMenu() + presenter.onDetachView() } override fun supportFragmentInjector() = supportFragmentInjector diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt index 4beb0ac4..4b2ad053 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt @@ -18,7 +18,7 @@ abstract class BaseFragment : DaggerFragment(), BaseView { } .show() } else { - (activity as? BaseActivity)?.showError(text, error) + (activity as? BaseActivity<*>)?.showError(text, error) } } @@ -26,7 +26,15 @@ abstract class BaseFragment : DaggerFragment(), BaseView { if (messageContainer != null) { Snackbar.make(messageContainer!!, text, LENGTH_LONG).show() } else { - (activity as? BaseActivity)?.showMessage(text) + (activity as? BaseActivity<*>)?.showMessage(text) } } + + override fun showExpiredDialog() { + (activity as? BaseActivity<*>)?.showExpiredDialog() + } + + override fun openClearLoginView() { + (activity as? BaseActivity<*>)?.openClearLoginView() + } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BasePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BasePresenter.kt index c5a31958..9f0b4047 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BasePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BasePresenter.kt @@ -1,8 +1,16 @@ package io.github.wulkanowy.ui.base +import io.github.wulkanowy.data.repositories.student.StudentRepository +import io.github.wulkanowy.utils.SchedulersProvider +import io.reactivex.Completable import io.reactivex.disposables.CompositeDisposable +import timber.log.Timber -open class BasePresenter(private val errorHandler: ErrorHandler) { +open class BasePresenter( + protected val errorHandler: ErrorHandler, + protected val studentRepository: StudentRepository, + protected val schedulers: SchedulersProvider +) { val disposable = CompositeDisposable() @@ -10,7 +18,33 @@ open class BasePresenter(private val errorHandler: ErrorHandler) { open fun onAttachView(view: T) { this.view = view - errorHandler.showErrorMessage = { text, error -> view.showError(text, error) } + errorHandler.apply { + showErrorMessage = view::showError + onSessionExpired = view::showExpiredDialog + onNoCurrentStudent = view::openClearLoginView + } + } + + fun onExpiredLoginSelected() { + Timber.i("Attempt to switch the student after the session expires") + disposable.add(studentRepository.getCurrentStudent(false) + .flatMapCompletable { studentRepository.logoutStudent(it) } + .andThen(studentRepository.getSavedStudents(false)) + .flatMapCompletable { + if (it.isNotEmpty()) { + Timber.i("Switching current student") + studentRepository.switchStudent(it[0]) + } else Completable.complete() + } + .subscribeOn(schedulers.backgroundThread) + .observeOn(schedulers.mainThread) + .subscribe({ + Timber.i("Switch student result: Open login view") + view?.openClearLoginView() + }, { + Timber.i("Switch student result: An exception occurred") + errorHandler.dispatch(it) + })) } open fun onDetachView() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseView.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BaseView.kt index d2470fd1..7681263b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseView.kt @@ -5,4 +5,8 @@ interface BaseView { fun showError(text: String, error: Throwable) fun showMessage(text: String) + + fun showExpiredDialog() + + fun openClearLoginView() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/ErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/ui/base/ErrorHandler.kt index 83cbf0ef..16e9a048 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/ErrorHandler.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/ErrorHandler.kt @@ -5,7 +5,10 @@ import com.readystatesoftware.chuck.api.ChuckCollector import io.github.wulkanowy.R import io.github.wulkanowy.api.interceptor.FeatureDisabledException import io.github.wulkanowy.api.interceptor.ServiceUnavailableException +import io.github.wulkanowy.api.login.BadCredentialsException import io.github.wulkanowy.api.login.NotLoggedInException +import io.github.wulkanowy.data.exceptions.NoCurrentStudentException +import io.github.wulkanowy.utils.security.ScramblerException import timber.log.Timber import java.net.SocketTimeoutException import java.net.UnknownHostException @@ -15,6 +18,10 @@ open class ErrorHandler @Inject constructor(protected val resources: Resources, var showErrorMessage: (String, Throwable) -> Unit = { _, _ -> } + var onSessionExpired: () -> Unit = {} + + var onNoCurrentStudent: () -> Unit = {} + fun dispatch(error: Throwable) { chuckCollector.onError(error.javaClass.simpleName, error) Timber.e(error, "An exception occurred while the Wulkanowy was running") @@ -22,17 +29,23 @@ open class ErrorHandler @Inject constructor(protected val resources: Resources, } protected open fun proceed(error: Throwable) { - showErrorMessage((when (error) { - is UnknownHostException -> resources.getString(R.string.error_no_internet) - is SocketTimeoutException -> resources.getString(R.string.error_timeout) - is NotLoggedInException -> resources.getString(R.string.error_login_failed) - is ServiceUnavailableException -> resources.getString(R.string.error_service_unavailable) - is FeatureDisabledException -> resources.getString(R.string.error_feature_disabled) - else -> resources.getString(R.string.error_unknown) - }), error) + resources.run { + when (error) { + is UnknownHostException -> showErrorMessage(getString(R.string.error_no_internet), error) + is SocketTimeoutException -> showErrorMessage(getString(R.string.error_timeout), error) + is NotLoggedInException -> showErrorMessage(getString(R.string.error_login_failed), error) + is ServiceUnavailableException -> showErrorMessage(getString(R.string.error_service_unavailable), error) + is FeatureDisabledException -> showErrorMessage(getString(R.string.error_feature_disabled), error) + is ScramblerException, is BadCredentialsException -> onSessionExpired() + is NoCurrentStudentException -> onNoCurrentStudent() + else -> showErrorMessage(getString(R.string.error_unknown), error) + } + } } open fun clear() { showErrorMessage = { _, _ -> } + onSessionExpired = {} + onNoCurrentStudent = {} } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/session/BaseSessionFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/base/session/BaseSessionFragment.kt deleted file mode 100644 index 110729d4..00000000 --- a/app/src/main/java/io/github/wulkanowy/ui/base/session/BaseSessionFragment.kt +++ /dev/null @@ -1,21 +0,0 @@ -package io.github.wulkanowy.ui.base.session - -import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK -import android.content.Intent.FLAG_ACTIVITY_NEW_TASK -import io.github.wulkanowy.ui.base.BaseFragment -import io.github.wulkanowy.ui.modules.login.LoginActivity -import io.github.wulkanowy.ui.modules.main.MainActivity - -open class BaseSessionFragment : BaseFragment(), BaseSessionView { - - override fun showExpiredDialog() { - (activity as? MainActivity)?.showExpiredDialog() - } - - override fun openLoginView() { - activity?.also { - startActivity(LoginActivity.getStartIntent(it) - .apply { addFlags(FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK) }) - } - } -} diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/session/BaseSessionPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/base/session/BaseSessionPresenter.kt deleted file mode 100644 index 2c9f50ea..00000000 --- a/app/src/main/java/io/github/wulkanowy/ui/base/session/BaseSessionPresenter.kt +++ /dev/null @@ -1,15 +0,0 @@ -package io.github.wulkanowy.ui.base.session - -import io.github.wulkanowy.ui.base.BasePresenter - -open class BaseSessionPresenter(private val errorHandler: SessionErrorHandler) : - BasePresenter(errorHandler) { - - override fun onAttachView(view: T) { - super.onAttachView(view) - errorHandler.apply { - onDecryptionFail = { view.showExpiredDialog() } - onNoCurrentStudent = { view.openLoginView() } - } - } -} diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/session/BaseSessionView.kt b/app/src/main/java/io/github/wulkanowy/ui/base/session/BaseSessionView.kt deleted file mode 100644 index 619c2863..00000000 --- a/app/src/main/java/io/github/wulkanowy/ui/base/session/BaseSessionView.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.github.wulkanowy.ui.base.session - -import io.github.wulkanowy.ui.base.BaseView - -interface BaseSessionView : BaseView { - - fun showExpiredDialog() - - fun openLoginView() -} diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/session/SessionErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/ui/base/session/SessionErrorHandler.kt deleted file mode 100644 index 017eabba..00000000 --- a/app/src/main/java/io/github/wulkanowy/ui/base/session/SessionErrorHandler.kt +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.wulkanowy.ui.base.session - -import android.content.res.Resources -import com.readystatesoftware.chuck.api.ChuckCollector -import io.github.wulkanowy.data.exceptions.NoCurrentStudentException -import io.github.wulkanowy.ui.base.ErrorHandler -import io.github.wulkanowy.utils.security.ScramblerException -import javax.inject.Inject - -open class SessionErrorHandler @Inject constructor( - resources: Resources, - chuckCollector: ChuckCollector -) : ErrorHandler(resources, chuckCollector) { - - var onDecryptionFail: () -> Unit = {} - - var onNoCurrentStudent: () -> Unit = {} - - override fun proceed(error: Throwable) { - when (error) { - is ScramblerException -> onDecryptionFail() - is NoCurrentStudentException -> onNoCurrentStudent() - else -> super.proceed(error) - } - } - - override fun clear() { - super.clear() - onDecryptionFail = {} - onNoCurrentStudent = {} - } -} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutPresenter.kt index 0b6db107..736bf0ce 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutPresenter.kt @@ -4,16 +4,20 @@ import com.mikepenz.aboutlibraries.Libs import com.mikepenz.aboutlibraries.Libs.SpecialButton.SPECIAL1 import com.mikepenz.aboutlibraries.Libs.SpecialButton.SPECIAL2 import com.mikepenz.aboutlibraries.Libs.SpecialButton.SPECIAL3 +import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper +import io.github.wulkanowy.utils.SchedulersProvider import timber.log.Timber import javax.inject.Inject class AboutPresenter @Inject constructor( + schedulers: SchedulersProvider, errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val analytics: FirebaseAnalyticsHelper -) : BasePresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { override fun onAttachView(view: AboutView) { super.onAttachView(view) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountDialog.kt index 1eaa07c1..f23a1eb5 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountDialog.kt @@ -1,7 +1,5 @@ package io.github.wulkanowy.ui.modules.account -import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK -import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -14,6 +12,7 @@ import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R +import io.github.wulkanowy.ui.base.BaseActivity import io.github.wulkanowy.ui.modules.login.LoginActivity import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.dialog_account.* @@ -73,16 +72,17 @@ class AccountDialog : DaggerAppCompatDialogFragment(), AccountView { } override fun openLoginView() { - activity?.also { + activity?.let { startActivity(LoginActivity.getStartIntent(it)) } } + override fun showExpiredDialog() { + (activity as? BaseActivity<*>)?.showExpiredDialog() + } + override fun openClearLoginView() { - activity?.also { - startActivity(LoginActivity.getStartIntent(it) - .apply { addFlags(FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK) }) - } + (activity as? BaseActivity<*>)?.openClearLoginView() } override fun showConfirmDialog() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt index a16c544a..e9b4b81e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt @@ -11,11 +11,11 @@ import timber.log.Timber import javax.inject.Inject class AccountPresenter @Inject constructor( - private val errorHandler: ErrorHandler, - private val studentRepository: StudentRepository, - private val syncManager: SyncManager, - private val schedulers: SchedulersProvider -) : BasePresenter(errorHandler) { + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, + private val syncManager: SyncManager +) : BasePresenter(errorHandler, studentRepository, schedulers) { override fun onAttachView(view: AccountView) { super.onAttachView(view) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountView.kt index 74662cf4..ede5023b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountView.kt @@ -14,8 +14,6 @@ interface AccountView : BaseView { fun openLoginView() - fun openClearLoginView() - fun recreateMainView() } 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 e5d8150d..f3131098 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 @@ -13,7 +13,7 @@ import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Attendance -import io.github.wulkanowy.ui.base.session.BaseSessionFragment +import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.attendance.summary.AttendanceSummaryFragment import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView @@ -21,7 +21,7 @@ import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_attendance.* import javax.inject.Inject -class AttendanceFragment : BaseSessionFragment(), AttendanceView, MainView.MainChildView, MainView.TitledView { +class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MainChildView, MainView.TitledView { @Inject lateinit var presenter: AttendancePresenter diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt index ec3d57e3..5e7333e1 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt @@ -1,20 +1,14 @@ package io.github.wulkanowy.ui.modules.attendance -import com.google.firebase.analytics.FirebaseAnalytics.Param.START_DATE import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.data.repositories.attendance.AttendanceRepository import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.data.repositories.student.StudentRepository -import io.github.wulkanowy.ui.base.session.BaseSessionPresenter -import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper -import io.github.wulkanowy.utils.SchedulersProvider -import io.github.wulkanowy.utils.isHolidays -import io.github.wulkanowy.utils.nextSchoolDay -import io.github.wulkanowy.utils.previousOrSameSchoolDay -import io.github.wulkanowy.utils.previousSchoolDay -import io.github.wulkanowy.utils.toFormattedString +import io.github.wulkanowy.utils.* import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate.now import org.threeten.bp.LocalDate.ofEpochDay @@ -23,14 +17,14 @@ import java.util.concurrent.TimeUnit.MILLISECONDS import javax.inject.Inject class AttendancePresenter @Inject constructor( - private val errorHandler: SessionErrorHandler, - private val schedulers: SchedulersProvider, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val attendanceRepository: AttendanceRepository, - private val studentRepository: StudentRepository, private val semesterRepository: SemesterRepository, private val prefRepository: PreferencesRepository, private val analytics: FirebaseAnalyticsHelper -) : BaseSessionPresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { lateinit var currentDate: LocalDate private set @@ -115,7 +109,7 @@ class AttendancePresenter @Inject constructor( showEmpty(it.isEmpty()) showContent(it.isNotEmpty()) } - analytics.logEvent("load_attendance", "items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd")) + analytics.logEvent("load_attendance", "items" to it.size, "force_refresh" to forceRefresh) }) { Timber.i("Loading attendance result: An exception occurred") view?.run { showEmpty(isViewEmpty) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceView.kt index ef3b874b..04fe94a4 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceView.kt @@ -1,9 +1,9 @@ package io.github.wulkanowy.ui.modules.attendance import io.github.wulkanowy.data.db.entities.Attendance -import io.github.wulkanowy.ui.base.session.BaseSessionView +import io.github.wulkanowy.ui.base.BaseView -interface AttendanceView : BaseSessionView { +interface AttendanceView : BaseView { val isViewEmpty: Boolean diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryFragment.kt index b8d2c952..1845bdda 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryFragment.kt @@ -13,13 +13,13 @@ import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R -import io.github.wulkanowy.ui.base.session.BaseSessionFragment +import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.setOnItemSelectedListener import kotlinx.android.synthetic.main.fragment_attendance_summary.* import javax.inject.Inject -class AttendanceSummaryFragment : BaseSessionFragment(), AttendanceSummaryView, MainView.TitledView { +class AttendanceSummaryFragment : BaseFragment(), AttendanceSummaryView, MainView.TitledView { @Inject lateinit var presenter: AttendanceSummaryPresenter diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryPresenter.kt index 09ad8980..dc6fe5b3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryPresenter.kt @@ -6,8 +6,8 @@ import io.github.wulkanowy.data.repositories.attendancesummary.AttendanceSummary import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.data.repositories.subject.SubjectRepository -import io.github.wulkanowy.ui.base.session.BaseSessionPresenter -import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import io.github.wulkanowy.utils.calculatePercentage @@ -19,14 +19,14 @@ import java.util.concurrent.TimeUnit.MILLISECONDS import javax.inject.Inject class AttendanceSummaryPresenter @Inject constructor( - private val errorHandler: SessionErrorHandler, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val attendanceSummaryRepository: AttendanceSummaryRepository, private val subjectRepository: SubjectRepository, - private val studentRepository: StudentRepository, private val semesterRepository: SemesterRepository, - private val schedulers: SchedulersProvider, private val analytics: FirebaseAnalyticsHelper -) : BaseSessionPresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { private var subjects = emptyList() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryView.kt index e4c36db7..50f03e20 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryView.kt @@ -1,8 +1,8 @@ package io.github.wulkanowy.ui.modules.attendance.summary -import io.github.wulkanowy.ui.base.session.BaseSessionView +import io.github.wulkanowy.ui.base.BaseView -interface AttendanceSummaryView : BaseSessionView { +interface AttendanceSummaryView : BaseView { val isViewEmpty: Boolean diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt index 8f9576f2..47f6d587 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt @@ -13,14 +13,14 @@ import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Exam -import io.github.wulkanowy.ui.base.session.BaseSessionFragment +import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_exam.* import javax.inject.Inject -class ExamFragment : BaseSessionFragment(), ExamView, MainView.MainChildView, MainView.TitledView { +class ExamFragment : BaseFragment(), ExamView, MainView.MainChildView, MainView.TitledView { @Inject lateinit var presenter: ExamPresenter diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamPresenter.kt index a18f7b2a..4045a956 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamPresenter.kt @@ -1,13 +1,12 @@ package io.github.wulkanowy.ui.modules.exam -import com.google.firebase.analytics.FirebaseAnalytics.Param.START_DATE import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.data.db.entities.Exam import io.github.wulkanowy.data.repositories.exam.ExamRepository import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.data.repositories.student.StudentRepository -import io.github.wulkanowy.ui.base.session.BaseSessionPresenter -import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import io.github.wulkanowy.utils.friday @@ -23,13 +22,13 @@ import java.util.concurrent.TimeUnit.MILLISECONDS import javax.inject.Inject class ExamPresenter @Inject constructor( - private val errorHandler: SessionErrorHandler, - private val schedulers: SchedulersProvider, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val examRepository: ExamRepository, - private val studentRepository: StudentRepository, private val semesterRepository: SemesterRepository, private val analytics: FirebaseAnalyticsHelper -) : BaseSessionPresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { lateinit var currentDate: LocalDate private set @@ -102,7 +101,7 @@ class ExamPresenter @Inject constructor( showEmpty(it.isEmpty()) showContent(it.isNotEmpty()) } - analytics.logEvent("load_exam", "items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd")) + analytics.logEvent("load_exam", "items" to it.size, "force_refresh" to forceRefresh) }) { Timber.i("Loading exam result: An exception occurred") view?.run { showEmpty(isViewEmpty) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamView.kt index 2ced3f2d..888cb05e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamView.kt @@ -1,9 +1,9 @@ package io.github.wulkanowy.ui.modules.exam import io.github.wulkanowy.data.db.entities.Exam -import io.github.wulkanowy.ui.base.session.BaseSessionView +import io.github.wulkanowy.ui.base.BaseView -interface ExamView : BaseSessionView { +interface ExamView : BaseView { val isViewEmpty: Boolean diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt index a76f3d5a..cff60268 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt @@ -3,16 +3,20 @@ package io.github.wulkanowy.ui.modules.grade import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.repositories.grade.GradeRepository +import io.github.wulkanowy.data.repositories.gradessummary.GradeSummaryRepository import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository import io.github.wulkanowy.utils.calcAverage import io.github.wulkanowy.utils.changeModifier +import io.reactivex.Maybe import io.reactivex.Single import javax.inject.Inject class GradeAverageProvider @Inject constructor( private val preferencesRepository: PreferencesRepository, - private val gradeRepository: GradeRepository + private val gradeRepository: GradeRepository, + private val gradeSummaryRepository: GradeSummaryRepository ) { + fun getGradeAverage(student: Student, semesters: List, selectedSemesterId: Int, forceRefresh: Boolean): Single> { return when (preferencesRepository.gradeAverageMode) { "all_year" -> getAllYearAverage(student, semesters, selectedSemesterId, forceRefresh) @@ -27,16 +31,19 @@ class GradeAverageProvider @Inject constructor( val plusModifier = preferencesRepository.gradePlusModifier val minusModifier = preferencesRepository.gradeMinusModifier - return gradeRepository.getGrades(student, selectedSemester, forceRefresh) - .flatMap { firstGrades -> - if (selectedSemester == firstSemester) Single.just(firstGrades) - else gradeRepository.getGrades(student, firstSemester) - .map { secondGrades -> secondGrades + firstGrades } - }.map { grades -> - grades.map { it.changeModifier(plusModifier, minusModifier) } - .groupBy { it.subject } - .mapValues { it.value.calcAverage() } - } + return getAverageFromGradeSummary(selectedSemester, forceRefresh) + .switchIfEmpty(gradeRepository.getGrades(student, selectedSemester, forceRefresh) + .flatMap { firstGrades -> + if (selectedSemester == firstSemester) Single.just(firstGrades) + else { + gradeRepository.getGrades(student, firstSemester) + .map { secondGrades -> secondGrades + firstGrades } + } + }.map { grades -> + grades.map { it.changeModifier(plusModifier, minusModifier) } + .groupBy { it.subject } + .mapValues { it.value.calcAverage() } + }) } private fun getOnlyOneSemesterAverage(student: Student, semesters: List, semesterId: Int, forceRefresh: Boolean): Single> { @@ -44,11 +51,22 @@ class GradeAverageProvider @Inject constructor( val plusModifier = preferencesRepository.gradePlusModifier val minusModifier = preferencesRepository.gradeMinusModifier - return gradeRepository.getGrades(student, selectedSemester, forceRefresh) - .map { grades -> - grades.map { it.changeModifier(plusModifier, minusModifier) } - .groupBy { it.subject } - .mapValues { it.value.calcAverage() } + return getAverageFromGradeSummary(selectedSemester, forceRefresh) + .switchIfEmpty(gradeRepository.getGrades(student, selectedSemester, forceRefresh) + .map { grades -> + grades.map { it.changeModifier(plusModifier, minusModifier) } + .groupBy { it.subject } + .mapValues { it.value.calcAverage() } + }) + } + + private fun getAverageFromGradeSummary(selectedSemester: Semester, forceRefresh: Boolean): Maybe> { + return gradeSummaryRepository.getGradesSummary(selectedSemester, forceRefresh) + .toMaybe() + .flatMap { + if (it.any { summary -> summary.average != .0 }) { + Maybe.just(it.map { summary -> summary.subject to summary.average }.toMap()) + } else Maybe.empty() } } } 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 182258d1..eb5e3669 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 @@ -11,8 +11,8 @@ import android.view.View.VISIBLE import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import io.github.wulkanowy.R +import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter -import io.github.wulkanowy.ui.base.session.BaseSessionFragment import io.github.wulkanowy.ui.modules.grade.details.GradeDetailsFragment import io.github.wulkanowy.ui.modules.grade.statistics.GradeStatisticsFragment import io.github.wulkanowy.ui.modules.grade.summary.GradeSummaryFragment @@ -21,7 +21,7 @@ import io.github.wulkanowy.utils.setOnSelectPageListener import kotlinx.android.synthetic.main.fragment_grade.* import javax.inject.Inject -class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView, MainView.TitledView { +class GradeFragment : BaseFragment(), GradeView, MainView.MainChildView, MainView.TitledView { @Inject lateinit var presenter: GradePresenter diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt index 6a8d4d58..2ee69480 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt @@ -3,20 +3,20 @@ package io.github.wulkanowy.ui.modules.grade import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.data.repositories.student.StudentRepository -import io.github.wulkanowy.ui.base.session.BaseSessionPresenter -import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import timber.log.Timber import javax.inject.Inject class GradePresenter @Inject constructor( - private val errorHandler: SessionErrorHandler, - private val schedulers: SchedulersProvider, - private val studentRepository: StudentRepository, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val semesterRepository: SemesterRepository, private val analytics: FirebaseAnalyticsHelper -) : BaseSessionPresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { var selectedIndex = 0 private set diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeView.kt index 9fdd46b1..a37e6d67 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeView.kt @@ -1,8 +1,8 @@ package io.github.wulkanowy.ui.modules.grade -import io.github.wulkanowy.ui.base.session.BaseSessionView +import io.github.wulkanowy.ui.base.BaseView -interface GradeView : BaseSessionView { +interface GradeView : BaseView { val currentPageIndex: Int diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt index 65cd9262..d50fd057 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 @@ -17,7 +17,7 @@ import eu.davidea.flexibleadapter.items.IExpandable import eu.davidea.flexibleadapter.items.IFlexible import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Grade -import io.github.wulkanowy.ui.base.session.BaseSessionFragment +import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.grade.GradeFragment import io.github.wulkanowy.ui.modules.grade.GradeView import io.github.wulkanowy.ui.modules.main.MainActivity @@ -25,7 +25,7 @@ import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_grade_details.* import javax.inject.Inject -class GradeDetailsFragment : BaseSessionFragment(), GradeDetailsView, GradeView.GradeChildView { +class GradeDetailsFragment : BaseFragment(), GradeDetailsView, GradeView.GradeChildView { @Inject lateinit var presenter: GradeDetailsPresenter 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 12e60687..184527e2 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 @@ -6,8 +6,8 @@ import io.github.wulkanowy.data.repositories.grade.GradeRepository import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.data.repositories.student.StudentRepository -import io.github.wulkanowy.ui.base.session.BaseSessionPresenter -import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider @@ -16,15 +16,15 @@ import timber.log.Timber import javax.inject.Inject class GradeDetailsPresenter @Inject constructor( - private val errorHandler: SessionErrorHandler, - private val schedulers: SchedulersProvider, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val gradeRepository: GradeRepository, - private val studentRepository: StudentRepository, private val semesterRepository: SemesterRepository, private val preferencesRepository: PreferencesRepository, private val averageProvider: GradeAverageProvider, private val analytics: FirebaseAnalyticsHelper -) : BaseSessionPresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { private var currentSemesterId = 0 diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsView.kt index 1fb98216..88b83bda 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsView.kt @@ -4,9 +4,9 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import eu.davidea.flexibleadapter.items.IExpandable import eu.davidea.flexibleadapter.items.IFlexible import io.github.wulkanowy.data.db.entities.Grade -import io.github.wulkanowy.ui.base.session.BaseSessionView +import io.github.wulkanowy.ui.base.BaseView -interface GradeDetailsView : BaseSessionView { +interface GradeDetailsView : BaseView { val isViewEmpty: Boolean diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsFragment.kt index f27a13c8..a1cea6df 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 @@ -16,7 +16,7 @@ import com.github.mikephil.charting.data.PieEntry import com.github.mikephil.charting.formatter.ValueFormatter import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.GradeStatistics -import io.github.wulkanowy.ui.base.session.BaseSessionFragment +import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.grade.GradeFragment import io.github.wulkanowy.ui.modules.grade.GradeView import io.github.wulkanowy.utils.getThemeAttrColor @@ -24,7 +24,7 @@ import io.github.wulkanowy.utils.setOnItemSelectedListener import kotlinx.android.synthetic.main.fragment_grade_statistics.* import javax.inject.Inject -class GradeStatisticsFragment : BaseSessionFragment(), GradeStatisticsView, GradeView.GradeChildView { +class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.GradeChildView { @Inject lateinit var presenter: GradeStatisticsPresenter diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsPresenter.kt index 5dd485cd..55ea611f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsPresenter.kt @@ -6,23 +6,23 @@ import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.data.repositories.subject.SubjectRepository -import io.github.wulkanowy.ui.base.session.BaseSessionPresenter -import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import timber.log.Timber import javax.inject.Inject class GradeStatisticsPresenter @Inject constructor( - private val errorHandler: SessionErrorHandler, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val gradeStatisticsRepository: GradeStatisticsRepository, private val subjectRepository: SubjectRepository, - private val studentRepository: StudentRepository, private val semesterRepository: SemesterRepository, private val preferencesRepository: PreferencesRepository, - private val schedulers: SchedulersProvider, private val analytics: FirebaseAnalyticsHelper -) : BaseSessionPresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { private var subjects = emptyList() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsView.kt index dbdde459..edb2552e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsView.kt @@ -1,9 +1,9 @@ package io.github.wulkanowy.ui.modules.grade.statistics import io.github.wulkanowy.data.db.entities.GradeStatistics -import io.github.wulkanowy.ui.base.session.BaseSessionView +import io.github.wulkanowy.ui.base.BaseView -interface GradeStatisticsView : BaseSessionView { +interface GradeStatisticsView : BaseView { val isViewEmpty: Boolean diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt index f174f96c..7699a641 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt @@ -11,13 +11,13 @@ import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R -import io.github.wulkanowy.ui.base.session.BaseSessionFragment +import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.grade.GradeFragment import io.github.wulkanowy.ui.modules.grade.GradeView import kotlinx.android.synthetic.main.fragment_grade_summary.* import javax.inject.Inject -class GradeSummaryFragment : BaseSessionFragment(), GradeSummaryView, GradeView.GradeChildView { +class GradeSummaryFragment : BaseFragment(), GradeSummaryView, GradeView.GradeChildView { @Inject lateinit var presenter: GradeSummaryPresenter diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryItem.kt index 5737a832..95c32d17 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryItem.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryItem.kt @@ -1,19 +1,21 @@ package io.github.wulkanowy.ui.modules.grade.summary +import android.annotation.SuppressLint import android.view.View +import android.view.View.GONE +import android.view.View.VISIBLE import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.viewholders.FlexibleViewHolder import io.github.wulkanowy.R +import io.github.wulkanowy.data.db.entities.GradeSummary import kotlinx.android.extensions.LayoutContainer import kotlinx.android.synthetic.main.item_grade_summary.* class GradeSummaryItem( - private val title: String, - private val average: String, - private val predictedGrade: String, - private val finalGrade: String + val summary: GradeSummary, + private val average: String ) : AbstractFlexibleItem() { override fun getLayoutRes() = R.layout.item_grade_summary @@ -22,12 +24,16 @@ class GradeSummaryItem( return ViewHolder(view, adapter) } + @SuppressLint("SetTextI18n") override fun bindViewHolder(adapter: FlexibleAdapter>, holder: ViewHolder, position: Int, payloads: MutableList?) { holder.run { - gradeSummaryItemTitle.text = title + gradeSummaryItemTitle.text = summary.subject + gradeSummaryItemPoints.text = summary.pointsSum gradeSummaryItemAverage.text = average - gradeSummaryItemPredicted.text = predictedGrade - gradeSummaryItemFinal.text = finalGrade + gradeSummaryItemPredicted.text = "${summary.predictedGrade} ${summary.proposedPoints}".trim() + gradeSummaryItemFinal.text = "${summary.finalGrade} ${summary.finalPoints}".trim() + + gradeSummaryItemPointsContainer.visibility = if (summary.pointsSum.isBlank()) GONE else VISIBLE } } @@ -38,18 +44,16 @@ class GradeSummaryItem( other as GradeSummaryItem if (average != other.average) return false - if (title != other.title) return false - if (predictedGrade != other.predictedGrade) return false - if (finalGrade != other.finalGrade) return false + if (summary != other.summary) return false + if (summary.id != other.summary.id) return false return true } override fun hashCode(): Int { - var result = title.hashCode() + var result = summary.hashCode() + result = 31 * result + summary.id.hashCode() result = 31 * result + average.hashCode() - result = 31 * result + predictedGrade.hashCode() - result = 31 * result + finalGrade.hashCode() return result } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt index bab64632..3f8fd0ed 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt @@ -4,8 +4,8 @@ import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.repositories.gradessummary.GradeSummaryRepository import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.data.repositories.student.StudentRepository -import io.github.wulkanowy.ui.base.session.BaseSessionPresenter -import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider @@ -16,14 +16,14 @@ import java.util.Locale.FRANCE import javax.inject.Inject class GradeSummaryPresenter @Inject constructor( - private val errorHandler: SessionErrorHandler, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val gradeSummaryRepository: GradeSummaryRepository, - private val studentRepository: StudentRepository, private val semesterRepository: SemesterRepository, private val averageProvider: GradeAverageProvider, - private val schedulers: SchedulersProvider, private val analytics: FirebaseAnalyticsHelper -) : BaseSessionPresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { override fun onAttachView(view: GradeSummaryView) { super.onAttachView(view) @@ -96,10 +96,8 @@ class GradeSummaryPresenter @Inject constructor( gradesSummary.filter { !checkEmpty(it, filteredAverages) } .map { GradeSummaryItem( - title = it.subject, - average = formatAverage(filteredAverages.getOrElse(it.subject) { 0.0 }, ""), - predictedGrade = it.predictedGrade, - finalGrade = it.finalGrade + summary = it, + average = formatAverage(filteredAverages.getOrElse(it.subject) { 0.0 }, "") ) }.let { it to GradeSummaryScrollableHeader( diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryView.kt index 5f7c7b16..9e9c6e58 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryView.kt @@ -1,8 +1,8 @@ package io.github.wulkanowy.ui.modules.grade.summary -import io.github.wulkanowy.ui.base.session.BaseSessionView +import io.github.wulkanowy.ui.base.BaseView -interface GradeSummaryView : BaseSessionView { +interface GradeSummaryView : BaseView { val isViewEmpty: Boolean diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt index 7325e3ec..01fdc909 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt @@ -10,14 +10,14 @@ import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Homework -import io.github.wulkanowy.ui.base.session.BaseSessionFragment +import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_homework.* import javax.inject.Inject -class HomeworkFragment : BaseSessionFragment(), HomeworkView, MainView.TitledView { +class HomeworkFragment : BaseFragment(), HomeworkView, MainView.TitledView { @Inject lateinit var presenter: HomeworkPresenter diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt index de85d8d1..682e87d4 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt @@ -1,13 +1,12 @@ package io.github.wulkanowy.ui.modules.homework -import com.google.firebase.analytics.FirebaseAnalytics.Param.START_DATE import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.data.db.entities.Homework import io.github.wulkanowy.data.repositories.homework.HomeworkRepository import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.data.repositories.student.StudentRepository -import io.github.wulkanowy.ui.base.session.BaseSessionPresenter -import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import io.github.wulkanowy.utils.friday @@ -21,13 +20,13 @@ import java.util.concurrent.TimeUnit import javax.inject.Inject class HomeworkPresenter @Inject constructor( - private val errorHandler: SessionErrorHandler, - private val schedulers: SchedulersProvider, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val homeworkRepository: HomeworkRepository, - private val studentRepository: StudentRepository, private val semesterRepository: SemesterRepository, private val analytics: FirebaseAnalyticsHelper -) : BaseSessionPresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { lateinit var currentDate: LocalDate private set @@ -89,7 +88,7 @@ class HomeworkPresenter @Inject constructor( showEmpty(it.isEmpty()) showContent(it.isNotEmpty()) } - analytics.logEvent("load_homework", "items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd")) + analytics.logEvent("load_homework", "items" to it.size, "force_refresh" to forceRefresh) }) { Timber.i("Loading homework result: An exception occurred") view?.run { showEmpty(isViewEmpty()) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkView.kt index 546d0526..977a5b73 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkView.kt @@ -1,9 +1,9 @@ package io.github.wulkanowy.ui.modules.homework import io.github.wulkanowy.data.db.entities.Homework -import io.github.wulkanowy.ui.base.session.BaseSessionView +import io.github.wulkanowy.ui.base.BaseView -interface HomeworkView : BaseSessionView { +interface HomeworkView : BaseView { fun initView() 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 da054bb5..5e707b8a 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 @@ -14,10 +14,10 @@ import io.github.wulkanowy.utils.setOnSelectPageListener import kotlinx.android.synthetic.main.activity_login.* import javax.inject.Inject -class LoginActivity : BaseActivity(), LoginView { +class LoginActivity : BaseActivity(), LoginView { @Inject - lateinit var presenter: LoginPresenter + override lateinit var presenter: LoginPresenter @Inject lateinit var loginAdapter: BaseFragmentPagerAdapter @@ -81,9 +81,4 @@ class LoginActivity : BaseActivity(), LoginView { fun onSymbolFragmentAccountLogged(students: List) { presenter.onSymbolViewAccountLogged(students) } - - public override fun onDestroy() { - presenter.onDetachView() - super.onDestroy() - } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginPresenter.kt index 00242a7d..87827152 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginPresenter.kt @@ -1,12 +1,18 @@ package io.github.wulkanowy.ui.modules.login import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler +import io.github.wulkanowy.utils.SchedulersProvider import timber.log.Timber import javax.inject.Inject -class LoginPresenter @Inject constructor(errorHandler: ErrorHandler) : BasePresenter(errorHandler) { +class LoginPresenter @Inject constructor( + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository +) : BasePresenter(errorHandler, studentRepository, schedulers) { override fun onAttachView(view: LoginView) { super.onAttachView(view) 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 3ab47c29..0fbfb329 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 @@ -1,6 +1,5 @@ package io.github.wulkanowy.ui.modules.login.form -import com.google.firebase.analytics.FirebaseAnalytics.Param.SUCCESS import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.modules.login.LoginErrorHandler @@ -11,12 +10,12 @@ import javax.inject.Inject import javax.inject.Named class LoginFormPresenter @Inject constructor( - private val schedulers: SchedulersProvider, - private val errorHandler: LoginErrorHandler, - private val studentRepository: StudentRepository, + schedulers: SchedulersProvider, + studentRepository: StudentRepository, + private val loginErrorHandler: LoginErrorHandler, private val analytics: FirebaseAnalyticsHelper, @param:Named("isDebug") private val isDebug: Boolean -) : BasePresenter(errorHandler) { +) : BasePresenter(loginErrorHandler, studentRepository, schedulers) { override fun onAttachView(view: LoginFormView) { super.onAttachView(view) @@ -24,7 +23,7 @@ class LoginFormPresenter @Inject constructor( initView() if (isDebug) showVersion() else showPrivacyPolicy() - errorHandler.onBadCredentials = { + loginErrorHandler.onBadCredentials = { setErrorPassIncorrect() showSoftKeyboard() Timber.i("Entered wrong username or password") @@ -78,12 +77,12 @@ class LoginFormPresenter @Inject constructor( } .subscribe({ Timber.i("Login result: Success") - analytics.logEvent("registration_form", SUCCESS to true, "students" to it.size, "endpoint" to endpoint, "error" to "No error") + analytics.logEvent("registration_form", "success" to true, "students" to it.size, "endpoint" to endpoint, "error" to "No error") view?.notifyParentAccountLogged(it) }, { Timber.i("Login result: An exception occurred") - analytics.logEvent("registration_form", SUCCESS to false, "students" to -1, "endpoint" to endpoint, "error" to it.localizedMessage) - errorHandler.dispatch(it) + analytics.logEvent("registration_form", "success" to false, "students" to -1, "endpoint" to endpoint, "error" to it.localizedMessage.ifEmpty { "No message" }) + loginErrorHandler.dispatch(it) })) } 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 21dde7b8..0636e163 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,6 +1,5 @@ package io.github.wulkanowy.ui.modules.login.studentselect -import com.google.firebase.analytics.FirebaseAnalytics.Param.SUCCESS import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.repositories.student.StudentRepository @@ -13,22 +12,22 @@ import java.io.Serializable import javax.inject.Inject class LoginStudentSelectPresenter @Inject constructor( - private val errorHandler: LoginErrorHandler, - private val studentRepository: StudentRepository, - private val schedulers: SchedulersProvider, + schedulers: SchedulersProvider, + studentRepository: StudentRepository, + private val loginErrorHandler: LoginErrorHandler, private val analytics: FirebaseAnalyticsHelper -) : BasePresenter(errorHandler) { +) : BasePresenter(loginErrorHandler, studentRepository, schedulers) { var students = emptyList() - var selectedStudents = mutableListOf() + private var selectedStudents = mutableListOf() fun onAttachView(view: LoginStudentSelectView, students: Serializable?) { super.onAttachView(view) view.run { initView() enableSignIn(false) - errorHandler.onStudentDuplicate = { + loginErrorHandler.onStudentDuplicate = { showMessage(it) Timber.i("The student already registered in the app was selected") } @@ -78,13 +77,13 @@ class LoginStudentSelectPresenter @Inject constructor( Timber.i("Registration started") } .subscribe({ - students.forEach { analytics.logEvent("registration_student_select", SUCCESS to true, "endpoint" to it.endpoint, "symbol" to it.symbol, "error" to "No error") } + students.forEach { analytics.logEvent("registration_student_select", "success" to true, "endpoint" to it.endpoint, "symbol" to it.symbol, "error" to "No error") } Timber.i("Registration result: Success") view?.openMainView() }, { error -> - students.forEach { analytics.logEvent("registration_student_select", SUCCESS to false, "endpoint" to it.endpoint, "symbol" to it.symbol, "error" to error.localizedMessage) } + students.forEach { analytics.logEvent("registration_student_select", "success" to false, "endpoint" to it.endpoint, "symbol" to it.symbol, "error" to error.localizedMessage.ifEmpty { "No message" }) } Timber.i("Registration result: An exception occurred ") - errorHandler.dispatch(error) + loginErrorHandler.dispatch(error) view?.apply { showProgress(false) showContent(true) 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 0adb9e16..8776526e 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,6 +1,5 @@ package io.github.wulkanowy.ui.modules.login.symbol -import com.google.firebase.analytics.FirebaseAnalytics.Param.SUCCESS import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.modules.login.LoginErrorHandler @@ -12,11 +11,11 @@ import java.io.Serializable import javax.inject.Inject class LoginSymbolPresenter @Inject constructor( - private val studentRepository: StudentRepository, - private val errorHandler: LoginErrorHandler, - private val schedulers: SchedulersProvider, + studentRepository: StudentRepository, + schedulers: SchedulersProvider, + private val loginErrorHandler: LoginErrorHandler, private val analytics: FirebaseAnalyticsHelper -) : BasePresenter(errorHandler) { +) : BasePresenter(loginErrorHandler, studentRepository, schedulers) { var loginData: Triple? = null @@ -59,7 +58,7 @@ class LoginSymbolPresenter @Inject constructor( } } .subscribe({ - analytics.logEvent("registration_symbol", SUCCESS to true, "students" to it.size, "endpoint" to loginData?.third, "symbol" to symbol, "error" to "No error") + analytics.logEvent("registration_symbol", "success" to true, "students" to it.size, "endpoint" to loginData?.third, "symbol" to symbol, "error" to "No error") view?.apply { if (it.isEmpty()) { Timber.i("Login with symbol result: Empty student list") @@ -71,8 +70,8 @@ class LoginSymbolPresenter @Inject constructor( } }, { Timber.i("Login with symbol result: An exception occurred") - analytics.logEvent("registration_symbol", SUCCESS to false, "students" to -1, "endpoint" to loginData?.third, "symbol" to symbol, "error" to it.localizedMessage) - errorHandler.dispatch(it) + analytics.logEvent("registration_symbol", "success" to false, "students" to -1, "endpoint" to loginData?.third, "symbol" to symbol, "error" to it.localizedMessage.ifEmpty { "No message" }) + loginErrorHandler.dispatch(it) })) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt index cff6175c..00204a87 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt @@ -6,12 +6,12 @@ import android.view.View import android.view.ViewGroup import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.LuckyNumber -import io.github.wulkanowy.ui.base.session.BaseSessionFragment +import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainView import kotlinx.android.synthetic.main.fragment_lucky_number.* import javax.inject.Inject -class LuckyNumberFragment : BaseSessionFragment(), LuckyNumberView, MainView.TitledView { +class LuckyNumberFragment : BaseFragment(), LuckyNumberView, MainView.TitledView { @Inject lateinit var presenter: LuckyNumberPresenter diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt index 8ef638db..ee7260e6 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt @@ -4,20 +4,20 @@ import io.github.wulkanowy.data.repositories.luckynumber.LuckyNumberRepository import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.ui.base.BasePresenter -import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import timber.log.Timber import javax.inject.Inject class LuckyNumberPresenter @Inject constructor( - private val errorHandler: SessionErrorHandler, - private val schedulers: SchedulersProvider, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val luckyNumberRepository: LuckyNumberRepository, - private val studentRepository: StudentRepository, private val semesterRepository: SemesterRepository, private val analytics: FirebaseAnalyticsHelper -) : BasePresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { override fun onAttachView(view: LuckyNumberView) { super.onAttachView(view) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberView.kt index 5c19142c..9ead2b1f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberView.kt @@ -1,9 +1,9 @@ package io.github.wulkanowy.ui.modules.luckynumber import io.github.wulkanowy.data.db.entities.LuckyNumber -import io.github.wulkanowy.ui.base.session.BaseSessionView +import io.github.wulkanowy.ui.base.BaseView -interface LuckyNumberView : BaseSessionView { +interface LuckyNumberView : BaseView { fun initView() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigureActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigureActivity.kt index 7e3eeb56..3dd0e5df 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigureActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigureActivity.kt @@ -16,13 +16,14 @@ import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.activity_widget_configure.* import javax.inject.Inject -class LuckyNumberWidgetConfigureActivity : BaseActivity(), LuckyNumberWidgetConfigureView { +class LuckyNumberWidgetConfigureActivity : BaseActivity(), + LuckyNumberWidgetConfigureView { @Inject lateinit var configureAdapter: FlexibleAdapter> @Inject - lateinit var presenter: LuckyNumberWidgetConfigurePresenter + override lateinit var presenter: LuckyNumberWidgetConfigurePresenter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -69,9 +70,4 @@ class LuckyNumberWidgetConfigureActivity : BaseActivity(), LuckyNumberWidgetConf override fun openLoginView() { startActivity(LoginActivity.getStartIntent(this)) } - - override fun onDestroy() { - super.onDestroy() - presenter.onDetachView() - } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigurePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigurePresenter.kt index 4fd81e96..2ed0fa6f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigurePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigurePresenter.kt @@ -11,11 +11,11 @@ import io.github.wulkanowy.utils.SchedulersProvider import javax.inject.Inject class LuckyNumberWidgetConfigurePresenter @Inject constructor( - private val errorHandler: ErrorHandler, - private val schedulers: SchedulersProvider, - private val studentRepository: StudentRepository, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val sharedPref: SharedPrefHelper -) : BasePresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { private var appWidgetId: Int? = null 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 5ca41b71..779f0a49 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 @@ -7,7 +7,6 @@ import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.os.Bundle import android.view.Menu import android.view.MenuItem -import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment @@ -22,7 +21,6 @@ import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment import io.github.wulkanowy.ui.modules.exam.ExamFragment import io.github.wulkanowy.ui.modules.grade.GradeFragment import io.github.wulkanowy.ui.modules.homework.HomeworkFragment -import io.github.wulkanowy.ui.modules.login.LoginActivity import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment import io.github.wulkanowy.ui.modules.message.MessageFragment import io.github.wulkanowy.ui.modules.more.MoreFragment @@ -34,10 +32,10 @@ import io.github.wulkanowy.utils.setOnViewChangeListener import kotlinx.android.synthetic.main.activity_main.* import javax.inject.Inject -class MainActivity : BaseActivity(), MainView { +class MainActivity : BaseActivity(), MainView { @Inject - lateinit var presenter: MainPresenter + override lateinit var presenter: MainPresenter @Inject lateinit var navController: FragNavController @@ -154,15 +152,6 @@ class MainActivity : BaseActivity(), MainView { navController.showDialogFragment(AccountDialog.newInstance()) } - fun showExpiredDialog() { - AlertDialog.Builder(this) - .setTitle(R.string.main_session_expired) - .setMessage(R.string.main_session_relogin) - .setPositiveButton(R.string.main_log_in) { _, _ -> presenter.onLoginSelected() } - .setNegativeButton(android.R.string.cancel) { _, _ -> } - .show() - } - override fun notifyMenuViewReselected() { (navController.currentStack?.getOrNull(0) as? MainView.MainChildView)?.onFragmentReselected() } @@ -183,19 +172,9 @@ class MainActivity : BaseActivity(), MainView { presenter.onBackPressed { super.onBackPressed() } } - override fun openLoginView() { - startActivity(LoginActivity.getStartIntent(this) - .apply { addFlags(FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK) }) - } - override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) navController.onSaveInstanceState(outState) intent.removeExtra(EXTRA_START_MENU) } - - override fun onDestroy() { - super.onDestroy() - presenter.onDetachView() - } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainModule.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainModule.kt index de4405b7..cc69005e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainModule.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainModule.kt @@ -19,6 +19,9 @@ import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment import io.github.wulkanowy.ui.modules.message.MessageFragment import io.github.wulkanowy.ui.modules.message.MessageModule import io.github.wulkanowy.ui.modules.message.preview.MessagePreviewFragment +import io.github.wulkanowy.ui.modules.mobiledevice.token.MobileDeviceTokenDialog +import io.github.wulkanowy.ui.modules.mobiledevice.MobileDeviceFragment +import io.github.wulkanowy.ui.modules.mobiledevice.MobileDeviceModule import io.github.wulkanowy.ui.modules.more.MoreFragment import io.github.wulkanowy.ui.modules.note.NoteFragment import io.github.wulkanowy.ui.modules.settings.SettingsFragment @@ -97,4 +100,12 @@ abstract class MainModule { @PerFragment @ContributesAndroidInjector abstract fun bindAccountDialog(): AccountDialog + + @PerFragment + @ContributesAndroidInjector(modules = [MobileDeviceModule::class]) + abstract fun bindMobileDevices(): MobileDeviceFragment + + @PerFragment + @ContributesAndroidInjector + abstract fun bindMobileDeviceDialog(): MobileDeviceTokenDialog } 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 12f2bb04..a74226bf 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 @@ -1,7 +1,5 @@ package io.github.wulkanowy.ui.modules.main -import com.google.firebase.analytics.FirebaseAnalytics.Event.APP_OPEN -import com.google.firebase.analytics.FirebaseAnalytics.Param.DESTINATION import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.services.sync.SyncManager @@ -9,18 +7,17 @@ import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider -import io.reactivex.Completable import timber.log.Timber import javax.inject.Inject class MainPresenter @Inject constructor( - private val errorHandler: ErrorHandler, - private val studentRepository: StudentRepository, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val prefRepository: PreferencesRepository, private val syncManager: SyncManager, - private val schedulers: SchedulersProvider, private val analytics: FirebaseAnalyticsHelper -) : BasePresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { fun onAttachView(view: MainView, initMenu: MainView.MenuView?) { super.onAttachView(view) @@ -34,7 +31,7 @@ class MainPresenter @Inject constructor( } syncManager.startSyncWorker() - analytics.logEvent(APP_OPEN, DESTINATION to initMenu?.name) + analytics.logEvent("app_open", "destination" to initMenu?.name) } fun onViewChange() { @@ -80,28 +77,6 @@ class MainPresenter @Inject constructor( } == true } - fun onLoginSelected() { - Timber.i("Attempt to switch the student after the session expires") - disposable.add(studentRepository.getCurrentStudent(false) - .flatMapCompletable { studentRepository.logoutStudent(it) } - .andThen(studentRepository.getSavedStudents(false)) - .flatMapCompletable { - if (it.isNotEmpty()) { - Timber.i("Switching current student") - studentRepository.switchStudent(it[0]) - } else Completable.complete() - } - .subscribeOn(schedulers.backgroundThread) - .observeOn(schedulers.mainThread) - .subscribe({ - Timber.i("Switch student result: Open login view") - view?.openLoginView() - }, { - Timber.i("Switch student result: An exception occurred") - errorHandler.dispatch(it) - })) - } - private fun getProperViewIndexes(initMenu: MainView.MenuView?): Pair { return when { initMenu?.id in 0..3 -> initMenu!!.id to -1 diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainView.kt index a786a3c3..6aef573e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainView.kt @@ -28,8 +28,6 @@ interface MainView : BaseView { fun popView() - fun openLoginView() - interface MainChildView { fun onFragmentReselected() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessagePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessagePresenter.kt index 888df040..0f5598b2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessagePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessagePresenter.kt @@ -1,6 +1,7 @@ package io.github.wulkanowy.ui.modules.message import io.github.wulkanowy.data.db.entities.Message +import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.SchedulersProvider @@ -10,9 +11,10 @@ import java.util.concurrent.TimeUnit.MILLISECONDS import javax.inject.Inject class MessagePresenter @Inject constructor( + schedulers: SchedulersProvider, errorHandler: ErrorHandler, - private val schedulers: SchedulersProvider -) : BasePresenter(errorHandler) { + studentRepository: StudentRepository +) : BasePresenter(errorHandler, studentRepository, schedulers) { override fun onAttachView(view: MessageView) { super.onAttachView(view) 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 057d81dc..93ef502f 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 @@ -12,7 +12,7 @@ import android.view.View.VISIBLE import android.view.ViewGroup import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Message -import io.github.wulkanowy.ui.base.session.BaseSessionFragment +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.MessageFragment @@ -20,8 +20,7 @@ import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity import kotlinx.android.synthetic.main.fragment_message_preview.* import javax.inject.Inject -@SuppressLint("SetTextI18n") -class MessagePreviewFragment : BaseSessionFragment(), MessagePreviewView, MainView.TitledView { +class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.TitledView { @Inject lateinit var presenter: MessagePreviewPresenter @@ -87,10 +86,12 @@ class MessagePreviewFragment : BaseSessionFragment(), MessagePreviewView, MainVi messagePreviewSubject.text = subject } + @SuppressLint("SetTextI18n") override fun setRecipient(recipient: String) { messagePreviewAuthor.text = "${getString(R.string.message_to)} $recipient" } + @SuppressLint("SetTextI18n") override fun setSender(sender: String) { messagePreviewAuthor.text = "${getString(R.string.message_from)} $sender" } 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 31641d75..a230c0b3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt @@ -1,11 +1,10 @@ package io.github.wulkanowy.ui.modules.message.preview -import com.google.firebase.analytics.FirebaseAnalytics.Param.START_DATE import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.repositories.message.MessageRepository import io.github.wulkanowy.data.repositories.student.StudentRepository -import io.github.wulkanowy.ui.base.session.BaseSessionPresenter -import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import io.github.wulkanowy.utils.toFormattedString @@ -13,12 +12,12 @@ import timber.log.Timber import javax.inject.Inject class MessagePreviewPresenter @Inject constructor( - private val errorHandler: SessionErrorHandler, - private val schedulers: SchedulersProvider, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val messageRepository: MessageRepository, - private val studentRepository: StudentRepository, private val analytics: FirebaseAnalyticsHelper -) : BaseSessionPresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { var messageId = 0L @@ -53,7 +52,7 @@ class MessagePreviewPresenter @Inject constructor( else setSender(it.sender) } } - analytics.logEvent("load_message_preview", START_DATE to message.date.toFormattedString("yyyy.MM.dd"), "length" to message.content?.length) + analytics.logEvent("load_message_preview", "length" to message.content?.length) }) { Timber.i("Loading message $id preview result: An exception occurred ") view?.showMessageError() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt index 8bc528a3..373dee11 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt @@ -1,9 +1,9 @@ package io.github.wulkanowy.ui.modules.message.preview import io.github.wulkanowy.data.db.entities.Message -import io.github.wulkanowy.ui.base.session.BaseSessionView +import io.github.wulkanowy.ui.base.BaseView -interface MessagePreviewView : BaseSessionView { +interface MessagePreviewView : BaseView { val noSubjectString: String 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 3a44ea86..5c6e74b0 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,13 +19,14 @@ import io.github.wulkanowy.utils.showSoftInput import kotlinx.android.synthetic.main.activity_send_message.* import javax.inject.Inject -class SendMessageActivity : BaseActivity(), SendMessageView { +class SendMessageActivity : BaseActivity(), SendMessageView { @Inject - lateinit var presenter: SendMessagePresenter + override lateinit var presenter: SendMessagePresenter companion object { private const val EXTRA_MESSAGE = "EXTRA_MESSAGE" + private const val EXTRA_REPLY = "EXTRA_REPLY" fun getStartIntent(context: Context) = Intent(context, SendMessageActivity::class.java) @@ -126,9 +127,4 @@ class SendMessageActivity : BaseActivity(), SendMessageView { override fun popView() { onBackPressed() } - - override fun onDestroy() { - presenter.onDetachView() - super.onDestroy() - } } 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 8dedaba0..4808fafc 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 @@ -19,16 +19,16 @@ import timber.log.Timber import javax.inject.Inject class SendMessagePresenter @Inject constructor( - private val errorHandler: ErrorHandler, - private val schedulers: SchedulersProvider, - private val studentRepository: StudentRepository, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val semesterRepository: SemesterRepository, private val messageRepository: MessageRepository, private val reportingUnitRepository: ReportingUnitRepository, private val recipientRepository: RecipientRepository, private val preferencesRepository: PreferencesRepository, private val analytics: FirebaseAnalyticsHelper -) : BasePresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { fun onAttachView(view: SendMessageView, message: Message?, reply: Boolean?) { super.onAttachView(view) 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 3859853f..326cd6a7 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 @@ -13,7 +13,7 @@ import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R import io.github.wulkanowy.data.repositories.message.MessageFolder -import io.github.wulkanowy.ui.base.session.BaseSessionFragment +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.MessageItem @@ -22,7 +22,7 @@ import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_message_tab.* import javax.inject.Inject -class MessageTabFragment : BaseSessionFragment(), MessageTabView { +class MessageTabFragment : BaseFragment(), MessageTabView { @Inject lateinit var presenter: MessageTabPresenter 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 2173c951..af576293 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 @@ -5,8 +5,8 @@ import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.repositories.message.MessageFolder import io.github.wulkanowy.data.repositories.message.MessageRepository import io.github.wulkanowy.data.repositories.student.StudentRepository -import io.github.wulkanowy.ui.base.session.BaseSessionPresenter -import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.ui.modules.message.MessageItem import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider @@ -14,12 +14,12 @@ import timber.log.Timber import javax.inject.Inject class MessageTabPresenter @Inject constructor( - private val errorHandler: SessionErrorHandler, - private val schedulers: SchedulersProvider, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val messageRepository: MessageRepository, - private val studentRepository: StudentRepository, private val analytics: FirebaseAnalyticsHelper -) : BaseSessionPresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { lateinit var folder: MessageFolder 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 01a188e7..967863de 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,10 +1,10 @@ package io.github.wulkanowy.ui.modules.message.tab import eu.davidea.flexibleadapter.items.AbstractFlexibleItem -import io.github.wulkanowy.ui.base.session.BaseSessionView +import io.github.wulkanowy.ui.base.BaseView import io.github.wulkanowy.ui.modules.message.MessageItem -interface MessageTabView : BaseSessionView { +interface MessageTabView : BaseView { val noSubjectString: String diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceAdapter.kt new file mode 100644 index 00000000..518246b6 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceAdapter.kt @@ -0,0 +1,10 @@ +package io.github.wulkanowy.ui.modules.mobiledevice + +import eu.davidea.flexibleadapter.FlexibleAdapter +import eu.davidea.flexibleadapter.items.IFlexible +import io.github.wulkanowy.data.db.entities.MobileDevice + +class MobileDeviceAdapter> : FlexibleAdapter(null, null, true) { + + var onDeviceUnregisterListener: (MobileDevice, position: Int) -> Unit = { _, _ -> } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceFragment.kt new file mode 100644 index 00000000..98780e17 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceFragment.kt @@ -0,0 +1,114 @@ +package io.github.wulkanowy.ui.modules.mobiledevice + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.View.GONE +import android.view.View.VISIBLE +import android.view.ViewGroup +import eu.davidea.flexibleadapter.common.FlexibleItemDecoration +import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager +import eu.davidea.flexibleadapter.helpers.EmptyViewHelper +import eu.davidea.flexibleadapter.helpers.UndoHelper +import eu.davidea.flexibleadapter.items.AbstractFlexibleItem +import io.github.wulkanowy.R +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.mobiledevice.token.MobileDeviceTokenDialog +import kotlinx.android.synthetic.main.fragment_mobile_device.* +import javax.inject.Inject + +class MobileDeviceFragment : BaseFragment(), MobileDeviceView, MainView.TitledView { + + @Inject + lateinit var presenter: MobileDevicePresenter + + @Inject + lateinit var devicesAdapter: MobileDeviceAdapter> + + companion object { + fun newInstance() = MobileDeviceFragment() + } + + override val titleStringId: Int + get() = R.string.mobile_devices_title + + override val isViewEmpty: Boolean + get() = devicesAdapter.isEmpty + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_mobile_device, container, false) + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + messageContainer = mobileDevicesRecycler + presenter.onAttachView(this) + } + + override fun initView() { + mobileDevicesRecycler.run { + layoutManager = SmoothScrollLinearLayoutManager(context) + adapter = devicesAdapter + addItemDecoration(FlexibleItemDecoration(context) + .withDefaultDivider() + .withDrawDividerOnLastItem(false) + ) + } + EmptyViewHelper.create(devicesAdapter, mobileDevicesEmpty) + mobileDevicesSwipe.setOnRefreshListener { presenter.onSwipeRefresh() } + mobileDeviceAddButton.setOnClickListener { presenter.onRegisterDevice() } + devicesAdapter.run { + isPermanentDelete = false + onDeviceUnregisterListener = { device, position -> + val onActionListener = object : UndoHelper.OnActionListener { + override fun onActionConfirmed(action: Int, event: Int) { + presenter.onUnregister(device) + } + + override fun onActionCanceled(action: Int, positions: MutableList?) { + devicesAdapter.restoreDeletedItems() + } + } + UndoHelper(devicesAdapter, onActionListener) + .withConsecutive(false) + .withAction(UndoHelper.Action.REMOVE) + .start(listOf(position), mobileDevicesRecycler, R.string.mobile_device_removed, R.string.all_undo, 3000) + } + } + } + + override fun updateData(data: List) { + devicesAdapter.updateDataSet(data) + } + + override fun clearData() { + devicesAdapter.clear() + } + + override fun hideRefresh() { + mobileDevicesSwipe.isRefreshing = false + } + + override fun showProgress(show: Boolean) { + mobileDevicesProgress.visibility = if (show) VISIBLE else GONE + } + + override fun enableSwipe(enable: Boolean) { + mobileDevicesSwipe.isEnabled = enable + } + + override fun showContent(show: Boolean) { + mobileDevicesRecycler.visibility = if (show) VISIBLE else GONE + } + + override fun showTokenDialog() { + (activity as? MainActivity)?.showDialogFragment(MobileDeviceTokenDialog.newInstance()) + } + + override fun onDestroyView() { + presenter.onDetachView() + super.onDestroyView() + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceItem.kt new file mode 100644 index 00000000..436c2d0e --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceItem.kt @@ -0,0 +1,53 @@ +package io.github.wulkanowy.ui.modules.mobiledevice + +import android.view.View +import eu.davidea.flexibleadapter.FlexibleAdapter +import eu.davidea.flexibleadapter.items.AbstractFlexibleItem +import eu.davidea.flexibleadapter.items.IFlexible +import eu.davidea.viewholders.FlexibleViewHolder +import io.github.wulkanowy.R +import io.github.wulkanowy.data.db.entities.MobileDevice +import io.github.wulkanowy.utils.toFormattedString +import kotlinx.android.extensions.LayoutContainer +import kotlinx.android.synthetic.main.item_mobile_device.* + +class MobileDeviceItem(val device: MobileDevice) : AbstractFlexibleItem() { + + override fun getLayoutRes() = R.layout.item_mobile_device + + override fun createViewHolder(view: View, adapter: FlexibleAdapter>): ViewHolder { + return ViewHolder(view, adapter) + } + + override fun bindViewHolder(adapter: FlexibleAdapter>, holder: ViewHolder, position: Int, payloads: MutableList?) { + holder.apply { + mobileDeviceItemDate.text = device.date.toFormattedString("dd.MM.yyyy HH:mm:ss") + mobileDeviceItemName.text = device.name + mobileDeviceItemUnregister.setOnClickListener { + (adapter as MobileDeviceAdapter).onDeviceUnregisterListener(device, holder.flexibleAdapterPosition) + } + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as MobileDeviceItem + + if (device.id != other.device.id) return false + return true + } + + override fun hashCode(): Int { + var result = device.hashCode() + result = 31 * result + device.id.toInt() + return result + } + + class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer { + + override val containerView: View + get() = contentView + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceModule.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceModule.kt new file mode 100644 index 00000000..59bbaa9f --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceModule.kt @@ -0,0 +1,12 @@ +package io.github.wulkanowy.ui.modules.mobiledevice + +import dagger.Module +import dagger.Provides +import eu.davidea.flexibleadapter.items.AbstractFlexibleItem + +@Module +class MobileDeviceModule { + + @Provides + fun provideMobileDeviceFlexibleAdapter() = MobileDeviceAdapter>() +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDevicePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDevicePresenter.kt new file mode 100644 index 00000000..47203c8a --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDevicePresenter.kt @@ -0,0 +1,94 @@ +package io.github.wulkanowy.ui.modules.mobiledevice + +import io.github.wulkanowy.data.db.entities.MobileDevice +import io.github.wulkanowy.data.repositories.mobiledevice.MobileDeviceRepository +import io.github.wulkanowy.data.repositories.semester.SemesterRepository +import io.github.wulkanowy.data.repositories.student.StudentRepository +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler +import io.github.wulkanowy.utils.FirebaseAnalyticsHelper +import io.github.wulkanowy.utils.SchedulersProvider +import timber.log.Timber +import javax.inject.Inject + +class MobileDevicePresenter @Inject constructor( + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, + private val semesterRepository: SemesterRepository, + private val mobileDeviceRepository: MobileDeviceRepository, + private val analytics: FirebaseAnalyticsHelper +) : BasePresenter(errorHandler, studentRepository, schedulers) { + + override fun onAttachView(view: MobileDeviceView) { + super.onAttachView(view) + view.initView() + Timber.i("Mobile device view was initialized") + loadData() + } + + fun onSwipeRefresh() { + loadData(true) + } + + private fun loadData(forceRefresh: Boolean = false) { + Timber.i("Loading mobile devices data started") + disposable.add(studentRepository.getCurrentStudent() + .flatMap { semesterRepository.getCurrentSemester(it) } + .flatMap { mobileDeviceRepository.getDevices(it, forceRefresh) } + .map { items -> items.map { MobileDeviceItem(it) } } + .subscribeOn(schedulers.backgroundThread) + .observeOn(schedulers.mainThread) + .doFinally { + view?.run { + hideRefresh() + showProgress(false) + enableSwipe(true) + } + }.subscribe({ + Timber.i("Loading mobile devices result: Success") + view?.run { + updateData(it) + showContent(it.isNotEmpty()) + } + analytics.logEvent("load_devices", "items" to it.size, "force_refresh" to forceRefresh) + }) { + Timber.i("Loading mobile devices result: An exception occurred") + errorHandler.dispatch(it) + }) + } + + fun onRegisterDevice() { + view?.showTokenDialog() + } + + fun onUnregister(device: MobileDevice) { + Timber.i("Unregister device started") + disposable.add(studentRepository.getCurrentStudent() + .flatMap { semesterRepository.getCurrentSemester(it) } + .flatMap { semester -> + mobileDeviceRepository.unregisterDevice(semester, device) + .flatMap { mobileDeviceRepository.getDevices(semester, it) } + } + .map { items -> items.map { MobileDeviceItem(it) } } + .subscribeOn(schedulers.backgroundThread) + .observeOn(schedulers.mainThread) + .doFinally { + view?.run { + showProgress(false) + enableSwipe(true) + } + } + .subscribe({ + Timber.i("Unregister device result: Success") + view?.run { + updateData(it) + showContent(it.isNotEmpty()) + } + }) { + Timber.i("Unregister device result: An exception occurred") + errorHandler.dispatch(it) + } + ) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceView.kt new file mode 100644 index 00000000..ef35cd75 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDeviceView.kt @@ -0,0 +1,24 @@ +package io.github.wulkanowy.ui.modules.mobiledevice + +import io.github.wulkanowy.ui.base.BaseView + +interface MobileDeviceView : BaseView { + + val isViewEmpty: Boolean + + fun initView() + + fun updateData(data: List) + + fun hideRefresh() + + fun clearData() + + fun showProgress(show: Boolean) + + fun enableSwipe(enable: Boolean) + + fun showContent(show: Boolean) + + fun showTokenDialog() +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenDialog.kt new file mode 100644 index 00000000..a4110128 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenDialog.kt @@ -0,0 +1,89 @@ +package io.github.wulkanowy.ui.modules.mobiledevice.token + +import android.graphics.BitmapFactory +import android.os.Bundle +import android.util.Base64 +import android.view.LayoutInflater +import android.view.View +import android.view.View.GONE +import android.view.View.VISIBLE +import android.view.ViewGroup +import android.widget.Toast +import dagger.android.support.DaggerDialogFragment +import io.github.wulkanowy.R +import io.github.wulkanowy.data.pojos.MobileDeviceToken +import io.github.wulkanowy.data.repositories.mobiledevice.MobileDeviceRemote +import io.github.wulkanowy.ui.base.BaseActivity +import kotlinx.android.synthetic.main.dialog_mobile_device.* +import javax.inject.Inject + +class MobileDeviceTokenDialog : DaggerDialogFragment(), MobileDeviceTokenVIew { + + @Inject + lateinit var presenter: MobileDeviceTokenPresenter + + companion object { + fun newInstance(): MobileDeviceTokenDialog = MobileDeviceTokenDialog() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(STYLE_NO_TITLE, 0) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.dialog_mobile_device, container, false) + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + presenter.onAttachView(this) + } + + override fun initView() { + mobileDeviceDialogClose.setOnClickListener { dismiss() } + } + + override fun updateData(token: MobileDeviceToken) { + mobileDeviceDialogToken.text = token.token + mobileDeviceDialogSymbol.text = token.symbol + mobileDeviceDialogPin.text = token.pin + + mobileDeviceQr.setImageBitmap(Base64.decode(token.qr, Base64.DEFAULT).let { + BitmapFactory.decodeByteArray(it, 0, it.size) + }) + } + + override fun hideLoading() { + mobileDeviceDialogProgress.visibility = GONE + } + + override fun showContent() { + mobileDeviceDialogContent.visibility = VISIBLE + } + + override fun closeDialog() { + dismiss() + } + + override fun showError(text: String, error: Throwable) { + showMessage(text) + } + + override fun showMessage(text: String) { + Toast.makeText(context, text, Toast.LENGTH_LONG).show() + } + + override fun showExpiredDialog() { + (activity as? BaseActivity<*>)?.showExpiredDialog() + } + + override fun openClearLoginView() { + (activity as? BaseActivity<*>)?.openClearLoginView() + } + + override fun onDestroyView() { + presenter.onDetachView() + super.onDestroyView() + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenPresenter.kt new file mode 100644 index 00000000..a778cbed --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenPresenter.kt @@ -0,0 +1,51 @@ +package io.github.wulkanowy.ui.modules.mobiledevice.token + +import io.github.wulkanowy.data.repositories.mobiledevice.MobileDeviceRepository +import io.github.wulkanowy.data.repositories.semester.SemesterRepository +import io.github.wulkanowy.data.repositories.student.StudentRepository +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler +import io.github.wulkanowy.utils.FirebaseAnalyticsHelper +import io.github.wulkanowy.utils.SchedulersProvider +import timber.log.Timber +import javax.inject.Inject + +class MobileDeviceTokenPresenter @Inject constructor( + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, + private val semesterRepository: SemesterRepository, + private val mobileDeviceRepository: MobileDeviceRepository, + private val analytics: FirebaseAnalyticsHelper +) : BasePresenter(errorHandler, studentRepository, schedulers) { + + override fun onAttachView(view: MobileDeviceTokenVIew) { + super.onAttachView(view) + view.initView() + Timber.i("Mobile device view was initialized") + loadData() + } + + private fun loadData() { + Timber.i("Mobile device registration data started") + disposable.add(studentRepository.getCurrentStudent() + .flatMap { semesterRepository.getCurrentSemester(it) } + .flatMap { mobileDeviceRepository.getToken(it) } + .subscribeOn(schedulers.backgroundThread) + .observeOn(schedulers.mainThread) + .doFinally { view?.hideLoading() } + .subscribe({ + Timber.i("Mobile device registration result: Success") + view?.run { + updateData(it) + showContent() + } + analytics.logEvent("device_register", "symbol" to it.token.substring(0, 3)) + }) { + Timber.i("Mobile device registration result: An exception occurred") + view?.closeDialog() + errorHandler.dispatch(it) + } + ) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenVIew.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenVIew.kt new file mode 100644 index 00000000..950f8bcf --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenVIew.kt @@ -0,0 +1,17 @@ +package io.github.wulkanowy.ui.modules.mobiledevice.token + +import io.github.wulkanowy.data.pojos.MobileDeviceToken +import io.github.wulkanowy.ui.base.BaseView + +interface MobileDeviceTokenVIew : BaseView { + + fun initView() + + fun hideLoading() + + fun showContent() + + fun closeDialog() + + fun updateData(token: MobileDeviceToken) +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreFragment.kt index 4823dedf..8b50a1c8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreFragment.kt @@ -17,6 +17,7 @@ import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.modules.message.MessageFragment +import io.github.wulkanowy.ui.modules.mobiledevice.MobileDeviceFragment import io.github.wulkanowy.ui.modules.note.NoteFragment import io.github.wulkanowy.ui.modules.settings.SettingsFragment import io.github.wulkanowy.utils.setOnItemClickListener @@ -69,6 +70,14 @@ class MoreFragment : BaseFragment(), MoreView, MainView.TitledView, MainView.Mai } } + override val mobileDevicesRes: Pair? + get() { + return context?.run { + getString(R.string.mobile_devices_title) to + ContextCompat.getDrawable(this, R.drawable.ic_menu_main_mobile_devices_24dp) + } + } + override val settingsRes: Pair? get() { return context?.run { @@ -127,6 +136,10 @@ class MoreFragment : BaseFragment(), MoreView, MainView.TitledView, MainView.Mai (activity as? MainActivity)?.pushView(LuckyNumberFragment.newInstance()) } + override fun openMobileDevicesView() { + (activity as? MainActivity)?.pushView(MobileDeviceFragment.newInstance()) + } + override fun openSettingsView() { (activity as? MainActivity)?.pushView(SettingsFragment.newInstance()) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/more/MorePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/more/MorePresenter.kt index a7626ec0..f9fd5bbf 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/more/MorePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/more/MorePresenter.kt @@ -1,12 +1,18 @@ package io.github.wulkanowy.ui.modules.more import eu.davidea.flexibleadapter.items.AbstractFlexibleItem +import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler +import io.github.wulkanowy.utils.SchedulersProvider import timber.log.Timber import javax.inject.Inject -class MorePresenter @Inject constructor(errorHandler: ErrorHandler) : BasePresenter(errorHandler) { +class MorePresenter @Inject constructor( + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository +) : BasePresenter(errorHandler, studentRepository, schedulers) { override fun onAttachView(view: MoreView) { super.onAttachView(view) @@ -24,6 +30,7 @@ class MorePresenter @Inject constructor(errorHandler: ErrorHandler) : BasePresen homeworkRes?.first -> openHomeworkView() noteRes?.first -> openNoteView() luckyNumberRes?.first -> openLuckyNumberView() + mobileDevicesRes?.first -> openMobileDevicesView() settingsRes?.first -> openSettingsView() aboutRes?.first -> openAboutView() } @@ -44,6 +51,7 @@ class MorePresenter @Inject constructor(errorHandler: ErrorHandler) : BasePresen homeworkRes?.let { MoreItem(it.first, it.second) }, noteRes?.let { MoreItem(it.first, it.second) }, luckyNumberRes?.let { MoreItem(it.first, it.second) }, + mobileDevicesRes?.let { MoreItem(it.first, it.second) }, settingsRes?.let { MoreItem(it.first, it.second) }, aboutRes?.let { MoreItem(it.first, it.second) }) ) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreView.kt index 333edc5d..9c1abb90 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreView.kt @@ -13,6 +13,8 @@ interface MoreView : BaseView { val luckyNumberRes: Pair? + val mobileDevicesRes: Pair? + val settingsRes: Pair? val aboutRes: Pair? @@ -34,4 +36,6 @@ interface MoreView : BaseView { fun openNoteView() fun openLuckyNumberView() + + fun openMobileDevicesView() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt index fc773e10..6117ae24 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt @@ -12,14 +12,14 @@ import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Note -import io.github.wulkanowy.ui.base.session.BaseSessionFragment +import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_note.* import javax.inject.Inject -class NoteFragment : BaseSessionFragment(), NoteView, MainView.TitledView { +class NoteFragment : BaseFragment(), NoteView, MainView.TitledView { @Inject lateinit var presenter: NotePresenter diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NotePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NotePresenter.kt index 136a4413..df98ab88 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NotePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NotePresenter.kt @@ -5,21 +5,21 @@ import io.github.wulkanowy.data.db.entities.Note import io.github.wulkanowy.data.repositories.note.NoteRepository import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.data.repositories.student.StudentRepository -import io.github.wulkanowy.ui.base.session.BaseSessionPresenter -import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import timber.log.Timber import javax.inject.Inject class NotePresenter @Inject constructor( - private val errorHandler: SessionErrorHandler, - private val schedulers: SchedulersProvider, - private val studentRepository: StudentRepository, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val noteRepository: NoteRepository, private val semesterRepository: SemesterRepository, private val analytics: FirebaseAnalyticsHelper -) : BaseSessionPresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { override fun onAttachView(view: NoteView) { super.onAttachView(view) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteView.kt index 38e6c94f..9a2c12eb 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteView.kt @@ -2,9 +2,9 @@ package io.github.wulkanowy.ui.modules.note import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.data.db.entities.Note -import io.github.wulkanowy.ui.base.session.BaseSessionView +import io.github.wulkanowy.ui.base.BaseView -interface NoteView : BaseSessionView { +interface NoteView : BaseView { val isViewEmpty: Boolean diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt index 2baad0eb..d0550bd4 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt @@ -55,11 +55,19 @@ class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedP } override fun showError(text: String, error: Throwable) { - (activity as? BaseActivity)?.showError(text, error) + (activity as? BaseActivity<*>)?.showError(text, error) } override fun showMessage(text: String) { - (activity as? BaseActivity)?.showMessage(text) + (activity as? BaseActivity<*>)?.showMessage(text) + } + + override fun showExpiredDialog() { + (activity as? BaseActivity<*>)?.showExpiredDialog() + } + + override fun openClearLoginView() { + (activity as? BaseActivity<*>)?.openClearLoginView() } override fun onResume() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt index c25198d5..a2edc414 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt @@ -2,22 +2,26 @@ package io.github.wulkanowy.ui.modules.settings import com.readystatesoftware.chuck.api.ChuckCollector import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository +import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.services.sync.SyncManager import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper +import io.github.wulkanowy.utils.SchedulersProvider import io.github.wulkanowy.utils.isHolidays import org.threeten.bp.LocalDate.now import timber.log.Timber import javax.inject.Inject class SettingsPresenter @Inject constructor( + schedulers: SchedulersProvider, errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val preferencesRepository: PreferencesRepository, private val analytics: FirebaseAnalyticsHelper, private val syncManager: SyncManager, private val chuckCollector: ChuckCollector -) : BasePresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { override fun onAttachView(view: SettingsView) { super.onAttachView(view) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/splash/SplashActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/splash/SplashActivity.kt index 2bd62533..3e0106d1 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/splash/SplashActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/splash/SplashActivity.kt @@ -8,10 +8,10 @@ import io.github.wulkanowy.ui.modules.login.LoginActivity import io.github.wulkanowy.ui.modules.main.MainActivity import javax.inject.Inject -class SplashActivity : BaseActivity(), SplashView { +class SplashActivity : BaseActivity(), SplashView { @Inject - lateinit var presenter: SplashPresenter + override lateinit var presenter: SplashPresenter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -31,9 +31,4 @@ class SplashActivity : BaseActivity(), SplashView { override fun showError(text: String, error: Throwable) { Toast.makeText(this, text, LENGTH_LONG).show() } - - override fun onDestroy() { - presenter.onDetachView() - super.onDestroy() - } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/splash/SplashPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/splash/SplashPresenter.kt index e6a9d7b3..44b53c5f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/splash/SplashPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/splash/SplashPresenter.kt @@ -7,10 +7,10 @@ import io.github.wulkanowy.utils.SchedulersProvider import javax.inject.Inject class SplashPresenter @Inject constructor( - private val studentRepository: StudentRepository, - private val errorHandler: ErrorHandler, - private val schedulers: SchedulersProvider -) : BasePresenter(errorHandler) { + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository +) : BasePresenter(errorHandler, studentRepository, schedulers) { override fun onAttachView(view: SplashView) { super.onAttachView(view) 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 26eaef27..e60be74c 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 @@ -13,7 +13,7 @@ import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Timetable -import io.github.wulkanowy.ui.base.session.BaseSessionFragment +import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.modules.timetable.completed.CompletedLessonsFragment @@ -21,7 +21,7 @@ import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_timetable.* import javax.inject.Inject -class TimetableFragment : BaseSessionFragment(), TimetableView, MainView.MainChildView, MainView.TitledView { +class TimetableFragment : BaseFragment(), TimetableView, MainView.MainChildView, MainView.TitledView { @Inject lateinit var presenter: TimetablePresenter diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt index 5b837f07..bead4228 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt @@ -1,12 +1,11 @@ package io.github.wulkanowy.ui.modules.timetable -import com.google.firebase.analytics.FirebaseAnalytics.Param.START_DATE import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.data.repositories.timetable.TimetableRepository -import io.github.wulkanowy.ui.base.session.BaseSessionPresenter -import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import io.github.wulkanowy.utils.isHolidays @@ -22,13 +21,13 @@ import java.util.concurrent.TimeUnit.MILLISECONDS import javax.inject.Inject class TimetablePresenter @Inject constructor( - private val errorHandler: SessionErrorHandler, - private val schedulers: SchedulersProvider, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val timetableRepository: TimetableRepository, - private val studentRepository: StudentRepository, private val semesterRepository: SemesterRepository, private val analytics: FirebaseAnalyticsHelper -) : BaseSessionPresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { lateinit var currentDate: LocalDate private set @@ -109,7 +108,7 @@ class TimetablePresenter @Inject constructor( showEmpty(it.isEmpty()) showContent(it.isNotEmpty()) } - analytics.logEvent("load_timetable", "items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd")) + analytics.logEvent("load_timetable", "items" to it.size, "force_refresh" to forceRefresh) }) { Timber.i("Loading timetable result: An exception occurred") view?.run { showEmpty(isViewEmpty) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableView.kt index c08961c3..80a2f9b8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableView.kt @@ -1,9 +1,9 @@ package io.github.wulkanowy.ui.modules.timetable import io.github.wulkanowy.data.db.entities.Timetable -import io.github.wulkanowy.ui.base.session.BaseSessionView +import io.github.wulkanowy.ui.base.BaseView -interface TimetableView : BaseSessionView { +interface TimetableView : BaseView { val roomString: String diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsErrorHandler.kt index 50d55685..ed11607c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsErrorHandler.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsErrorHandler.kt @@ -3,13 +3,13 @@ package io.github.wulkanowy.ui.modules.timetable.completed import android.content.res.Resources import com.readystatesoftware.chuck.api.ChuckCollector import io.github.wulkanowy.api.interceptor.FeatureDisabledException -import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.ui.base.ErrorHandler import javax.inject.Inject class CompletedLessonsErrorHandler @Inject constructor( resources: Resources, chuckCollector: ChuckCollector -) : SessionErrorHandler(resources, chuckCollector) { +) : ErrorHandler(resources, chuckCollector) { var onFeatureDisabled: () -> Unit = {} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt index bb328c41..f56652d5 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt @@ -10,14 +10,14 @@ import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.CompletedLesson -import io.github.wulkanowy.ui.base.session.BaseSessionFragment +import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_timetable_completed.* import javax.inject.Inject -class CompletedLessonsFragment : BaseSessionFragment(), CompletedLessonsView, MainView.TitledView { +class CompletedLessonsFragment : BaseFragment(), CompletedLessonsView, MainView.TitledView { @Inject lateinit var presenter: CompletedLessonsPresenter diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsPresenter.kt index 6a14acda..0db5210f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsPresenter.kt @@ -1,11 +1,10 @@ package io.github.wulkanowy.ui.modules.timetable.completed -import com.google.firebase.analytics.FirebaseAnalytics.Param.START_DATE import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.data.repositories.completedlessons.CompletedLessonsRepository import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.data.repositories.student.StudentRepository -import io.github.wulkanowy.ui.base.session.BaseSessionPresenter +import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import io.github.wulkanowy.utils.isHolidays @@ -21,13 +20,13 @@ import java.util.concurrent.TimeUnit import javax.inject.Inject class CompletedLessonsPresenter @Inject constructor( - private val schedulers: SchedulersProvider, - private val errorHandler: CompletedLessonsErrorHandler, - private val studentRepository: StudentRepository, + schedulers: SchedulersProvider, + studentRepository: StudentRepository, + private val completedLessonsErrorHandler: CompletedLessonsErrorHandler, private val semesterRepository: SemesterRepository, private val completedLessonsRepository: CompletedLessonsRepository, private val analytics: FirebaseAnalyticsHelper -) : BaseSessionPresenter(errorHandler) { +) : BasePresenter(completedLessonsErrorHandler, studentRepository, schedulers) { lateinit var currentDate: LocalDate private set @@ -38,7 +37,7 @@ class CompletedLessonsPresenter @Inject constructor( view.initView() loadData(ofEpochDay(date ?: now().nextOrSameSchoolDay.toEpochDay())) reloadView() - errorHandler.onFeatureDisabled = { + completedLessonsErrorHandler.onFeatureDisabled = { this.view?.showFeatureDisabled() Timber.i("Completed lessons feature disabled by school") } @@ -93,11 +92,11 @@ class CompletedLessonsPresenter @Inject constructor( showEmpty(it.isEmpty()) showContent(it.isNotEmpty()) } - analytics.logEvent("load_completed_lessons", "items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd")) + analytics.logEvent("load_completed_lessons", "items" to it.size, "force_refresh" to forceRefresh) }) { Timber.i("Loading completed lessons result: An exception occurred") view?.run { showEmpty(isViewEmpty) } - errorHandler.dispatch(it) + completedLessonsErrorHandler.dispatch(it) }) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsView.kt index 9607cc47..a8bef66f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsView.kt @@ -1,9 +1,9 @@ package io.github.wulkanowy.ui.modules.timetable.completed import io.github.wulkanowy.data.db.entities.CompletedLesson -import io.github.wulkanowy.ui.base.session.BaseSessionView +import io.github.wulkanowy.ui.base.BaseView -interface CompletedLessonsView : BaseSessionView { +interface CompletedLessonsView : BaseView { val isViewEmpty: Boolean diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigureActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigureActivity.kt index 468567f1..79dd59bf 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigureActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigureActivity.kt @@ -18,13 +18,14 @@ import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.activity_widget_configure.* import javax.inject.Inject -class TimetableWidgetConfigureActivity : BaseActivity(), TimetableWidgetConfigureView { +class TimetableWidgetConfigureActivity : BaseActivity(), + TimetableWidgetConfigureView { @Inject lateinit var configureAdapter: FlexibleAdapter> @Inject - lateinit var presenter: TimetableWidgetConfigurePresenter + override lateinit var presenter: TimetableWidgetConfigurePresenter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -71,9 +72,4 @@ class TimetableWidgetConfigureActivity : BaseActivity(), TimetableWidgetConfigur override fun openLoginView() { startActivity(LoginActivity.getStartIntent(this)) } - - override fun onDestroy() { - super.onDestroy() - presenter.onDetachView() - } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigurePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigurePresenter.kt index 5a7bdd7c..60fd03aa 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigurePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigurePresenter.kt @@ -11,11 +11,11 @@ import io.github.wulkanowy.utils.SchedulersProvider import javax.inject.Inject class TimetableWidgetConfigurePresenter @Inject constructor( - private val errorHandler: ErrorHandler, - private val schedulers: SchedulersProvider, - private val studentRepository: StudentRepository, + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, private val sharedPref: SharedPrefHelper -) : BasePresenter(errorHandler) { +) : BasePresenter(errorHandler, studentRepository, schedulers) { private var appWidgetId: Int? = null diff --git a/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.kt b/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.kt index 5a6cc2bf..f9db0465 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.kt @@ -7,7 +7,6 @@ import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager -import com.crashlytics.android.Crashlytics import timber.log.Timber import javax.inject.Inject import javax.inject.Singleton @@ -19,17 +18,6 @@ class DebugLogTree : Timber.DebugTree() { } } -class CrashlyticsTree : Timber.Tree() { - - override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { - Crashlytics.setInt("priority", priority) - Crashlytics.setString("tag", tag) - - if (t == null) Crashlytics.log(message) - else Crashlytics.logException(t) - } -} - class ActivityLifecycleLogger : Application.ActivityLifecycleCallbacks { override fun onActivityPaused(activity: Activity?) { 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 c151c07f..7fe143d8 100644 --- a/app/src/main/play/release-notes/pl-PL/default.txt +++ b/app/src/main/play/release-notes/pl-PL/default.txt @@ -1,6 +1,14 @@ -Wersja 0.8.4 +Wersja 0.9.0 + +Dodaliśmy: +- zarządzanie dostępem mobilnym do dziennika +- wyświetlanie sumy punktów (jeśli dziennik obsługuje) +- wyświetlanie informacji o wygasłej sesji, gdy zostanie zmienione hasło Naprawiliśmy: -- synchronizację w tle dla użytkowników używających danych pakietowych +- wykrywanie uczniów przy logowaniu, jeśli symbol zawiera cyfry +- błędne wyświetlanie średniej +- synchronizację w tle na danych komórkowych przy domyślnych ustawieniach +- rzadkie błędy podczas ładowania szczęśliwego numerka Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases diff --git a/app/src/main/res/drawable/ic_all_add_24dp.xml b/app/src/main/res/drawable/ic_all_add_24dp.xml new file mode 100644 index 00000000..e3979cd7 --- /dev/null +++ b/app/src/main/res/drawable/ic_all_add_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_main_mobile_devices_24dp.xml b/app/src/main/res/drawable/ic_menu_main_mobile_devices_24dp.xml new file mode 100644 index 00000000..150ced43 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_main_mobile_devices_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_message_delete_24dp.xml b/app/src/main/res/drawable/ic_message_delete_24dp.xml index 3760de23..4a577483 100644 --- a/app/src/main/res/drawable/ic_message_delete_24dp.xml +++ b/app/src/main/res/drawable/ic_message_delete_24dp.xml @@ -1,10 +1,9 @@ diff --git a/app/src/main/res/layout/dialog_mobile_device.xml b/app/src/main/res/layout/dialog_mobile_device.xml new file mode 100644 index 00000000..c514205a --- /dev/null +++ b/app/src/main/res/layout/dialog_mobile_device.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + +