Compare commits

..

No commits in common. "0.25.0" and "0.21.1" have entirely different histories.

458 changed files with 5476 additions and 21449 deletions

View file

@ -1,142 +0,0 @@
name: Test and deploy
on:
push:
branches: [ develop ]
tags: [ '*' ]
pull_request:
branches: [ develop ]
workflow_dispatch:
jobs:
build:
name: Pre-build
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: fkirc/skip-duplicate-actions@master
- uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
- name: Build
run: ./gradlew --build-cache compileFdroidDebugUnitTestKotlin preFdroidDebugAndroidTestBuild dexBuilderFdroidDebugAndroidTest packageFdroidDebug packageFdroidDebugAndroidTest
- name: Prepare build cache
run: tar -cf prebuild.tar .build-cache .gradle app/build
- uses: actions/upload-artifact@v2
with:
name: prebuild.tar
path: prebuild.tar
unit-tests:
name: Unit tests
runs-on: ubuntu-latest
timeout-minutes: 10
needs: [ build ]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
- uses: actions/download-artifact@v2
with:
name: prebuild.tar
- name: Extract build cache
run: tar -xf prebuild.tar
- name: Unit tests
run: |
./gradlew --build-cache -Pcoverage testFdroidDebugUnitTest --stacktrace
./gradlew --build-cache -Pcoverage jacocoTestReport --stacktrace
- uses: codecov/codecov-action@v1
with:
flags: unit
instrumentation-tests:
name: Instrumentation tests
runs-on: macOS-latest
timeout-minutes: 15
needs: [ build ]
strategy:
fail-fast: true
matrix:
api-level: [21, 29]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
- uses: actions/download-artifact@v2
with:
name: prebuild.tar
- name: Extract build cache
run: tar -xf prebuild.tar
- name: Instrumentation tests
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api-level }}
arch: x86
script: |
./gradlew --build-cache -Pcoverage connectedFdroidDebugAndroidTest --stacktrace
./gradlew --build-cache -Pcoverage jacocoTestReport --stacktrace
- uses: codecov/codecov-action@v1
with:
flags: instrumented,api-${{ matrix.api-level }}
deploy-google-play:
name: Deploy to google play
runs-on: ubuntu-latest
timeout-minutes: 10
environment: google-play
needs: [ build, unit-tests, instrumentation-tests ]
if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
- uses: actions/download-artifact@v2
with:
name: prebuild.tar
- name: Extract build cache
run: tar -xf prebuild.tar
- name: Decrypt keys
env:
ENCRYPT_KEY: ${{ secrets.ENCRYPT_KEY }}
SERVICES_ENCRYPT_KEY: ${{ secrets.SERVICES_ENCRYPT_KEY }}
run: |
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
- name: Upload apk to google play
env:
PLAY_KEY_ALIAS: ${{ secrets.PLAY_KEY_ALIAS }}
PLAY_KEY_PASSWORD: ${{ secrets.PLAY_KEY_PASSWORD }}
PLAY_SERVICE_ACCOUNT_EMAIL: ${{ secrets.PLAY_SERVICE_ACCOUNT_EMAIL }}
PLAY_STORE_PASSWORD: ${{ secrets.PLAY_STORE_PASSWORD }}
run: ./gradlew publishPlayRelease -PenableFirebase --stacktrace;

4
.gitignore vendored
View file

@ -19,7 +19,6 @@ out/
# Gradle files # Gradle files
.gradle/ .gradle/
build/ build/
.build-cache
# Local configuration file (sdk path, etc) # Local configuration file (sdk path, etc)
local.properties local.properties
@ -114,6 +113,3 @@ Thumbs.db
!/gradle/wrapper/gradle-wrapper.jar !/gradle/wrapper/gradle-wrapper.jar
.idea/jarRepositories.xml .idea/jarRepositories.xml
app/src/release/agconnect-services.json

View file

@ -18,9 +18,18 @@
</option> </option>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" /> <option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" /> <option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
<option name="CONTINUATION_INDENT_IN_PARAMETER_LISTS" value="false" />
<option name="CONTINUATION_INDENT_IN_ARGUMENT_LISTS" value="false" />
<option name="CONTINUATION_INDENT_FOR_EXPRESSION_BODIES" value="false" />
<option name="CONTINUATION_INDENT_FOR_CHAINED_CALLS" value="false" />
<option name="CONTINUATION_INDENT_IN_SUPERTYPE_LISTS" value="false" />
<option name="CONTINUATION_INDENT_IN_IF_CONDITIONS" value="false" />
<option name="CONTINUATION_INDENT_IN_ELVIS" value="false" />
<option name="WRAP_ELVIS_EXPRESSIONS" value="0" /> <option name="WRAP_ELVIS_EXPRESSIONS" value="0" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings> </JetCodeStyleSettings>
<MarkdownNavigatorCodeStyleSettings>
<option name="RIGHT_MARGIN" value="72" />
</MarkdownNavigatorCodeStyleSettings>
<codeStyleSettings language="XML"> <codeStyleSettings language="XML">
<indentOptions> <indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" /> <option name="CONTINUATION_INDENT_SIZE" value="4" />
@ -134,11 +143,13 @@
</arrangement> </arrangement>
</codeStyleSettings> </codeStyleSettings>
<codeStyleSettings language="kotlin"> <codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" /> <option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> <option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" /> <option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" /> <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<indentOptions> <indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" /> <option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions> </indentOptions>

View file

@ -3,8 +3,8 @@ jdk: oraclejdk8
env: env:
global: global:
- ANDROID_API_LEVEL=30 - ANDROID_API_LEVEL=29
- ANDROID_BUILD_TOOLS_VERSION=30.0.2 - ANDROID_BUILD_TOOLS_VERSION=29.0.3
cache: cache:
directories: directories:
@ -14,7 +14,7 @@ cache:
branches: branches:
only: only:
- develop - develop
- 0.24.0 - 0.21.1
android: android:
licenses: licenses:
@ -37,10 +37,6 @@ android:
- android-22 - android-22
- sys-img-armeabi-v7a-android-22 - sys-img-armeabi-v7a-android-22
before_install:
- yes | sdkmanager "platforms;android-30"
- yes | sdkmanager "build-tools;30.0.2"
before_script: before_script:
# Launch emulator before the execution # Launch emulator before the execution
- echo no | android create avd --force -n test -t android-22 --abi armeabi-v7a - echo no | android create avd --force -n test -t android-22 --abi armeabi-v7a
@ -58,7 +54,6 @@ script:
- | - |
if [ $TRAVIS_TAG ]; then if [ $TRAVIS_TAG ]; then
gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/google-services.json.gpg; gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/google-services.json.gpg;
gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/agconnect-services.json.gpg;
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/key.p12.gpg; gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/key.p12.gpg;
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg; gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg;
./gradlew publishPlayRelease -PenableFirebase --stacktrace; ./gradlew publishPlayRelease -PenableFirebase --stacktrace;

View file

@ -1,8 +1,7 @@
[Polska wersja README](README.md) [Polska wersja README](README.md)
# Wulkanowy # Wulkanowy
[![Travis](https://img.shields.io/travis/com/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://travis-ci.com/wulkanowy/wulkanowy)
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Test%20and%20deploy/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
[![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy) [![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy)
[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr) [![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr)
[![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/) [![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/)
@ -33,7 +32,7 @@ Unofficial android VULCAN UONET+ register client for both students and their par
## Download ## Download
You can download the current beta version from the Google Play, F-Droid or Huawei AppGallery store You can download the current beta version from the Google Play or the F-Droid store
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" [<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
alt="Get it on Google Play" alt="Get it on Google Play"
@ -41,9 +40,6 @@ You can download the current beta version from the Google Play, F-Droid or Huawe
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" [<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Get it on F-Droid" alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/io.github.wulkanowy/) height="80">](https://f-droid.org/packages/io.github.wulkanowy/)
[<img src="appgallery_badge.png"
alt="Explore it on AppGallery"
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
You can also download a [development version](https://wulkanowy.github.io/#download) that includes new features being prepared for the next release You can also download a [development version](https://wulkanowy.github.io/#download) that includes new features being prepared for the next release
@ -51,8 +47,7 @@ You can also download a [development version](https://wulkanowy.github.io/#downl
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk) * [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
* [Kotlin Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) * [Dagger 2](https://github.com/google/dagger)
* [Hilt](https://dagger.dev/hilt/)
* [Room](https://developer.android.com/topic/libraries/architecture/room) * [Room](https://developer.android.com/topic/libraries/architecture/room)
* [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager) * [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager)

View file

@ -1,8 +1,7 @@
[English version of README](README.en.md) [English version of README](README.en.md)
# Wulkanowy # Wulkanowy
[![Travis](https://img.shields.io/travis/com/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://travis-ci.com/wulkanowy/wulkanowy)
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Test%20and%20deploy/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
[![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy) [![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy)
[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr) [![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr)
[![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/) [![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/)
@ -33,7 +32,7 @@ Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
## Pobierz ## Pobierz
Aktualną wersję beta możesz pobrać ze sklepu Google Play, F-Droid lub Huawei AppGallery Aktualną wersję beta możesz pobrać ze sklepu Google Play lub F-Droid
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" [<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
alt="Pobierz z Google Play" alt="Pobierz z Google Play"
@ -41,9 +40,6 @@ Aktualną wersję beta możesz pobrać ze sklepu Google Play, F-Droid lub Huawei
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" [<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Pobierz z F-Droid" alt="Pobierz z F-Droid"
height="80">](https://f-droid.org/packages/io.github.wulkanowy/) height="80">](https://f-droid.org/packages/io.github.wulkanowy/)
[<img src="appgallery_badge.png"
alt="Odkrywaj w AppGallery"
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
Możesz także pobrać [wersję rozwojową](https://wulkanowy.github.io/#download), która zawiera nowe funkcje przygotowywane do następnego wydania Możesz także pobrać [wersję rozwojową](https://wulkanowy.github.io/#download), która zawiera nowe funkcje przygotowywane do następnego wydania
@ -51,9 +47,8 @@ Możesz także pobrać [wersję rozwojową](https://wulkanowy.github.io/#downloa
## Zbudowana za pomocą ## Zbudowana za pomocą
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk) * [Wulkanowy SDK](https://github.com/wulkanowy/SDK)
* [Kotlin Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) * [Dagger 2](https://github.com/google/dagger)
* [Hilt](https://dagger.dev/hilt/)
* [Room](https://developer.android.com/topic/libraries/architecture/room) * [Room](https://developer.android.com/topic/libraries/architecture/room)
* [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager) * [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager)

View file

@ -10,23 +10,20 @@ apply from: 'sonarqube.gradle'
apply from: 'hooks.gradle' apply from: 'hooks.gradle'
android { android {
compileSdkVersion 30 compileSdkVersion 29
buildToolsVersion '30.0.3' buildToolsVersion '29.0.3'
defaultConfig { defaultConfig {
applicationId "io.github.wulkanowy" applicationId "io.github.wulkanowy"
testApplicationId "io.github.tests.wulkanowy" testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 17 minSdkVersion 17
targetSdkVersion 30 targetSdkVersion 29
versionCode 82 versionCode 71
versionName "0.25.0" versionName "0.21.1"
multiDexEnabled true multiDexEnabled true
resValue "string", "app_name", "Wulkanowy"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
resValue "string", "app_name", "Wulkanowy"
buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis())
manifestPlaceholders = [ manifestPlaceholders = [
firebase_enabled: project.hasProperty("enableFirebase") firebase_enabled: project.hasProperty("enableFirebase")
] ]
@ -72,26 +69,12 @@ android {
flavorDimensions "platform" flavorDimensions "platform"
productFlavors { productFlavors {
hms {
dimension "platform"
minSdkVersion 19
manifestPlaceholders = [
install_channel: "AppGallery"
]
}
play { play {
dimension "platform" dimension "platform"
manifestPlaceholders = [
install_channel: "Google Play"
]
} }
fdroid { fdroid {
dimension "platform" dimension "platform"
manifestPlaceholders = [
install_channel: "F-Droid"
]
} }
} }
@ -129,27 +112,29 @@ play {
serviceAccountCredentials = file('key.p12') serviceAccountCredentials = file('key.p12')
defaultToAppBundles = false defaultToAppBundles = false
track = 'alpha' track = 'alpha'
updatePriority = 3
} }
ext { ext {
work_manager = "2.5.0" work_manager = "2.4.0"
work_hilt = "1.0.0-alpha03" room = "2.2.5"
room = "2.3.0-beta01" chucker = "3.2.0"
chucker = "3.4.0" mockk = "1.10.0"
mockk = "1.10.5" moshi = "1.9.3"
moshi = "1.11.0" }
configurations.all {
resolutionStrategy.force "androidx.constraintlayout:constraintlayout:1.1.3"
} }
dependencies { dependencies {
implementation "io.github.wulkanowy:sdk:0.25.0" implementation "io.github.wulkanowy:sdk:0.21.1"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
implementation "androidx.core:core-ktx:1.3.2" implementation "androidx.core:core-ktx:1.3.1"
implementation "androidx.activity:activity-ktx:1.1.0" implementation "androidx.activity:activity-ktx:1.1.0"
implementation "androidx.appcompat:appcompat:1.2.0" implementation "androidx.appcompat:appcompat:1.2.0"
implementation "androidx.appcompat:appcompat-resources:1.2.0" implementation "androidx.appcompat:appcompat-resources:1.2.0"
@ -161,14 +146,15 @@ dependencies {
implementation "androidx.recyclerview:recyclerview:1.1.0" implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation "androidx.viewpager:viewpager:1.0.0" implementation "androidx.viewpager:viewpager:1.0.0"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "androidx.constraintlayout:constraintlayout:2.0.4" implementation "androidx.constraintlayout:constraintlayout:2.0.1"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0" implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
implementation "com.google.android.material:material:1.3.0-rc01" implementation "com.google.android.material:material:1.2.1"
implementation "com.github.wulkanowy:material-chips-input:2.1.1" implementation "com.github.wulkanowy:material-chips-input:2.1.1"
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0" implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
implementation "me.zhanghai.android.materialprogressbar:library:1.6.1"
implementation "androidx.work:work-runtime-ktx:$work_manager" implementation "androidx.work:work-runtime-ktx:$work_manager"
playImplementation "androidx.work:work-gcm:$work_manager" implementation "androidx.work:work-gcm:$work_manager"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0" implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
@ -178,12 +164,12 @@ dependencies {
implementation "com.google.dagger:hilt-android:$hilt_version" implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version" kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
implementation "androidx.hilt:hilt-work:$work_hilt" implementation 'androidx.hilt:hilt-work:1.0.0-alpha02'
kapt "androidx.hilt:hilt-compiler:$work_hilt" kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha02'
implementation "com.aurelhubert:ahbottomnavigation:2.3.4" implementation "com.aurelhubert:ahbottomnavigation:2.3.4"
implementation "com.ncapdevi:frag-nav:3.3.0" implementation "com.ncapdevi:frag-nav:3.3.0"
implementation "com.github.YarikSOffice:lingver:1.3.0" implementation "com.github.YarikSOffice:lingver:1.2.2"
implementation "com.squareup.moshi:moshi:$moshi" implementation "com.squareup.moshi:moshi:$moshi"
implementation "com.squareup.moshi:moshi-adapters:$moshi" implementation "com.squareup.moshi:moshi-adapters:$moshi"
@ -193,31 +179,25 @@ dependencies {
implementation "fr.bipi.treessence:treessence:0.3.2" implementation "fr.bipi.treessence:treessence:0.3.2"
implementation "com.mikepenz:aboutlibraries-core:$about_libraries" implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
implementation 'com.wdullaer:materialdatetimepicker:4.2.3' implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
implementation "io.coil-kt:coil:1.1.1" implementation "io.coil-kt:coil:1.0.0-rc2"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0" implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.3.1' implementation 'me.xdrop:fuzzywuzzy:1.3.1'
playImplementation platform('com.google.firebase:firebase-bom:26.4.0') playImplementation 'com.google.firebase:firebase-analytics:17.5.0'
playImplementation 'com.google.firebase:firebase-analytics-ktx' playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.1.1'
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx' playImplementation "com.google.firebase:firebase-inappmessaging-ktx:19.1.1"
playImplementation "com.google.firebase:firebase-inappmessaging-ktx" playImplementation 'com.google.firebase:firebase-messaging:20.2.4'
playImplementation 'com.google.firebase:firebase-messaging:' playImplementation 'com.google.firebase:firebase-crashlytics:17.2.1'
playImplementation 'com.google.firebase:firebase-crashlytics:'
playImplementation 'com.google.android.play:core-ktx:1.8.1'
playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava' playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
hmsImplementation 'com.huawei.hms:hianalytics:5.1.0.301'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.5.0.200'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker" releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker" debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker"
debugImplementation "com.amitshekhar.android:debug-db:1.0.6" debugImplementation "com.amitshekhar.android:debug-db:1.0.6"
testImplementation "junit:junit:4.13.1" testImplementation "junit:junit:4.13"
testImplementation "io.mockk:mockk:$mockk" testImplementation "io.mockk:mockk:$mockk"
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2' testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.9'
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
androidTestImplementation "androidx.test:core:1.3.0" androidTestImplementation "androidx.test:core:1.3.0"
androidTestImplementation "androidx.test:runner:1.3.0" androidTestImplementation "androidx.test:runner:1.3.0"
@ -228,4 +208,3 @@ dependencies {
} }
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.huawei.agconnect'

View file

@ -7,7 +7,6 @@ jacoco {
tasks.withType(Test) { tasks.withType(Test) {
jacoco.includeNoLocationClasses = true jacoco.includeNoLocationClasses = true
jacoco.excludes = ['jdk.internal.*']
} }
task jacocoTestReport(type: JacocoReport) { task jacocoTestReport(type: JacocoReport) {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
package io.github.wulkanowy.data
import io.github.wulkanowy.utils.DispatchersProvider
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
class TestDispatchersProvider : DispatchersProvider() {
override val backgroundThread: CoroutineDispatcher
get() = Dispatchers.Unconfined
}

View file

@ -1,6 +1,5 @@
package io.github.wulkanowy.data.db.migrations package io.github.wulkanowy.data.db.migrations
import android.content.Context
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.room.Room import androidx.room.Room
import androidx.room.testing.MigrationTestHelper import androidx.room.testing.MigrationTestHelper
@ -23,11 +22,10 @@ abstract class AbstractMigrationTest {
) )
fun getMigratedRoomDatabase(): AppDatabase { fun getMigratedRoomDatabase(): AppDatabase {
val context = ApplicationProvider.getApplicationContext<Context>()
val database = Room.databaseBuilder(ApplicationProvider.getApplicationContext(), val database = Room.databaseBuilder(ApplicationProvider.getApplicationContext(),
AppDatabase::class.java, dbName) AppDatabase::class.java, dbName)
.addMigrations(*AppDatabase.getMigrations(SharedPrefProvider(PreferenceManager .addMigrations(*AppDatabase.getMigrations(SharedPrefProvider(PreferenceManager
.getDefaultSharedPreferences(context))) .getDefaultSharedPreferences(ApplicationProvider.getApplicationContext())))
) )
.build() .build()
// close the database and release any stream resources when the test finishes // close the database and release any stream resources when the test finishes

View file

@ -0,0 +1,45 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import java.time.LocalDate.now
import java.time.LocalDateTime
fun getStudent(): Student {
return Student(
email = "test",
password = "test123",
schoolSymbol = "23",
scrapperBaseUrl = "fakelog.cf",
loginType = "AUTO",
isCurrent = true,
userName = "",
studentName = "",
schoolShortName = "",
schoolName = "",
studentId = 0,
classId = 1,
symbol = "",
registrationDate = LocalDateTime.now(),
className = "",
loginMode = "API",
certificateKey = "",
privateKey = "",
mobileBaseUrl = "",
userLoginId = 0,
isParent = false
)
}
fun getSemester() = Semester(
semesterId = 1,
studentId = 1,
classId = 1,
diaryId = 2,
diaryName = "",
end = now(),
schoolYear = 2019,
semesterName = 1,
start = now(),
unitId = 1
)

View file

@ -0,0 +1,83 @@
package io.github.wulkanowy.data.repositories.attendance
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.time.LocalDate
import java.time.LocalDate.now
import java.time.LocalDate.of
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class AttendanceLocalTest {
private lateinit var attendanceLocal: AttendanceLocal
private lateinit var testDb: AppDatabase
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java).build()
attendanceLocal = AttendanceLocal(testDb.attendanceDao)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun saveAndReadTest() {
val list = listOf(
getAttendanceEntity(
of(2018, 9, 10),
SentExcuseStatus.ACCEPTED
),
getAttendanceEntity(
of(2018, 9, 14),
SentExcuseStatus.WAITING
),
getAttendanceEntity(
of(2018, 9, 17),
SentExcuseStatus.ACCEPTED
)
)
runBlocking { attendanceLocal.saveAttendance(list) }
val semester = Semester(1, 2, "", 1, 3, 2019, now(), now(), 1, 1)
val attendance = runBlocking { attendanceLocal.getAttendance(semester, of(2018, 9, 10), of(2018, 9, 14)).first() }
assertEquals(2, attendance.size)
assertEquals(attendance[0].date, of(2018, 9, 10))
assertEquals(attendance[1].date, of(2018, 9, 14))
}
private fun getAttendanceEntity(
date: LocalDate,
excuseStatus: SentExcuseStatus
) = Attendance(
studentId = 1,
diaryId = 2,
timeId = 3,
date = date,
number = 0,
subject = "",
name = "",
presence = false,
absence = false,
exemption = false,
lateness = false,
excused = false,
deleted = false,
excusable = false,
excuseStatus = excuseStatus.name
)
}

View file

@ -0,0 +1,59 @@
package io.github.wulkanowy.data.repositories.completedlessons
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.time.LocalDate
import java.time.LocalDate.now
import java.time.LocalDate.of
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class CompletedLessonsLocalTest {
private lateinit var completedLessonsLocal: CompletedLessonsLocal
private lateinit var testDb: AppDatabase
@Before
fun createDb() {
testDb = Room
.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
completedLessonsLocal = CompletedLessonsLocal(testDb.completedLessonsDao)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun saveAndReadTest() {
val list = listOf(
getCompletedLesson(of(2018, 9, 10), 1),
getCompletedLesson(of(2018, 9, 14), 2),
getCompletedLesson(of(2018, 9, 17), 3)
)
runBlocking { completedLessonsLocal.saveCompletedLessons(list) }
val semester = Semester(1, 2, "", 1, 3, 2019, now(), now(), 1, 1)
val completed = runBlocking { completedLessonsLocal.getCompletedLessons(semester, of(2018, 9, 10), of(2018, 9, 14)).first() }
assertEquals(2, completed.size)
assertEquals(completed[0].date, of(2018, 9, 10))
assertEquals(completed[1].date, of(2018, 9, 14))
}
private fun getCompletedLesson(date: LocalDate, number: Int): CompletedLesson {
return CompletedLesson(1, 2, date, number, "", "", "", "", "", "", "")
}
}

View file

@ -0,0 +1,52 @@
package io.github.wulkanowy.data.repositories.exam
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.time.LocalDate.now
import java.time.LocalDate.of
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class ExamLocalTest {
private lateinit var examLocal: ExamLocal
private lateinit var testDb: AppDatabase
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java).build()
examLocal = ExamLocal(testDb.examsDao)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun saveAndReadTest() {
val list = listOf(
Exam(1, 2, of(2018, 9, 10), now(), "", "", "", "", "", ""),
Exam(1, 2, of(2018, 9, 14), now(), "", "", "", "", "", ""),
Exam(1, 2, of(2018, 9, 17), now(), "", "", "", "", "", "")
)
runBlocking { examLocal.saveExams(list) }
val semester = Semester(1, 2, "", 1, 3, 2019, now(), now(), 1, 1)
val exams = runBlocking { examLocal.getExams(semester, of(2018, 9, 10), of(2018, 9, 14)).first() }
assertEquals(2, exams.size)
assertEquals(exams[0].date, of(2018, 9, 10))
assertEquals(exams[1].date, of(2018, 9, 14))
}
}

View file

@ -0,0 +1,55 @@
package io.github.wulkanowy.data.repositories.grade
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.time.LocalDate
import java.time.LocalDate.now
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class GradeLocalTest {
private lateinit var gradeLocal: GradeLocal
private lateinit var testDb: AppDatabase
@Before
fun createDb() {
testDb = Room
.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
gradeLocal = GradeLocal(testDb.gradeDao, testDb.gradeSummaryDao)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun saveAndReadTest() {
val list = listOf(
createGradeLocal(5, 3.0, LocalDate.of(2018, 9, 10), "", 1),
createGradeLocal(4, 4.0, LocalDate.of(2019, 2, 27), "", 2),
createGradeLocal(3, 5.0, LocalDate.of(2019, 2, 28), "", 2)
)
runBlocking { gradeLocal.saveGrades(list) }
val semester = Semester(1, 2, "", 2019, 2, 1, now(), now(), 1, 1)
val grades = runBlocking { gradeLocal.getGradesDetails(semester).first() }
assertEquals(2, grades.size)
assertEquals(grades[0].date, LocalDate.of(2019, 2, 27))
assertEquals(grades[1].date, LocalDate.of(2019, 2, 28))
}
}

View file

@ -0,0 +1,221 @@
package io.github.wulkanowy.data.repositories.grade
import android.os.Build.VERSION_CODES.P
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.every
import io.mockk.impl.annotations.MockK
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.time.LocalDate.of
import java.time.LocalDateTime
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
@SdkSuppress(minSdkVersion = P)
@RunWith(AndroidJUnit4::class)
class GradeRepositoryTest {
@MockK
private lateinit var semesterMock: Semester
private lateinit var studentMock: Student
@MockK
private lateinit var gradeRemote: GradeRemote
private lateinit var gradeLocal: GradeLocal
private lateinit var testDb: AppDatabase
@Before
fun initApi() {
MockKAnnotations.init(this)
testDb = Room.inMemoryDatabaseBuilder(getApplicationContext(), AppDatabase::class.java).build()
gradeLocal = GradeLocal(testDb.gradeDao, testDb.gradeSummaryDao)
studentMock = getStudentMock()
every { semesterMock.studentId } returns 1
every { semesterMock.diaryId } returns 1
every { semesterMock.schoolYear } returns 2019
every { semesterMock.semesterId } returns 1
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun markOlderThanRegisterDateAsRead() {
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (listOf(
createGradeLocal(5, 4.0, of(2019, 2, 25), "Ocena pojawiła się"),
createGradeLocal(5, 4.0, of(2019, 2, 26), "przed zalogowanie w aplikacji"),
createGradeLocal(5, 4.0, of(2019, 2, 27), "Ocena z dnia logowania"),
createGradeLocal(5, 4.0, of(2019, 2, 28), "Ocena jeszcze nowsza")
) to emptyList())
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!.first.sortedByDescending { it.date }
}
assertFalse { grades[0].isRead }
assertFalse { grades[1].isRead }
assertTrue { grades[2].isRead }
assertTrue { grades[3].isRead }
}
@Test
fun mitigateOldGradesNotifications() {
val list = listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Jedna ocena"),
createGradeLocal(4, 4.0, of(2019, 2, 26), "Druga"),
createGradeLocal(3, 5.0, of(2019, 2, 27), "Trzecia")
)
runBlocking { gradeLocal.saveGrades(list) }
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (listOf(
createGradeLocal(5, 2.0, of(2019, 2, 25), "Ocena ma datę, jest inna, ale nie zostanie powiadomiona"),
createGradeLocal(4, 3.0, of(2019, 2, 26), "starszą niż ostatnia lokalnie"),
createGradeLocal(3, 4.0, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie"),
createGradeLocal(2, 5.0, of(2019, 2, 28), "Ta jest już w ogóle nowa")
) to emptyList())
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!.first.sortedByDescending { it.date }
}
assertFalse { grades[0].isRead }
assertFalse { grades[1].isRead }
assertTrue { grades[2].isRead }
assertTrue { grades[3].isRead }
}
@Test
fun subtractLocaleDuplicateGrades() {
val list = listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
)
runBlocking { gradeLocal.saveGrades(list) }
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
) to emptyList())
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!
}
assertEquals(2, grades.first.size)
}
@Test
fun subtractRemoteDuplicateGrades() {
val list = listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
)
runBlocking { gradeLocal.saveGrades(list) }
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
) to emptyList())
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!
}
assertEquals(3, grades.first.size)
}
@Test
fun emptyLocal() {
runBlocking { gradeLocal.saveGrades(listOf()) }
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
) to emptyList())
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!
}
assertEquals(3, grades.first.size)
}
@Test
fun emptyRemote() {
val list = listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
)
runBlocking { gradeLocal.saveGrades(list) }
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (emptyList<Grade>() to emptyList())
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!
}
assertEquals(0, grades.first.size)
}
private fun getStudentMock() = Student(
scrapperBaseUrl = "http://fakelog.cf",
email = "jan@fakelog.cf",
certificateKey = "",
classId = 0,
className = "",
isCurrent = false,
isParent = false,
loginMode = Sdk.Mode.SCRAPPER.name,
loginType = "STANDARD",
mobileBaseUrl = "",
password = "",
privateKey = "",
registrationDate = LocalDateTime.of(2019, 2, 27, 12, 0),
schoolName = "",
schoolShortName = "test",
schoolSymbol = "",
studentId = 0,
studentName = "",
symbol = "",
userLoginId = 0,
userName = ""
)
}

View file

@ -0,0 +1,41 @@
package io.github.wulkanowy.data.repositories.grade
import java.time.LocalDate
import io.github.wulkanowy.sdk.pojo.Grade as GradeRemote
import io.github.wulkanowy.data.db.entities.Grade as GradeLocal
fun createGradeLocal(value: Int, weight: Double, date: LocalDate, desc: String, semesterId: Int = 1): GradeLocal {
return GradeLocal(
semesterId = semesterId,
studentId = 1,
modifier = .0,
teacher = "",
subject = "",
date = date,
color = "",
comment = "",
description = desc,
entry = "",
gradeSymbol = "",
value = value.toDouble(),
weight = "",
weightValue = weight
)
}
fun createGradeApi(value: Int, weight: Double, date: LocalDate, desc: String): GradeRemote {
return GradeRemote(
subject = "",
color = "",
comment = "",
date = date,
description = desc,
entry = "",
modifier = .0,
symbol = "",
teacher = "",
value = value.toDouble(),
weight = weight.toString(),
weightValue = weight
)
}

View file

@ -0,0 +1,112 @@
package io.github.wulkanowy.data.repositories.gradestatistics
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeStatistics
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.time.LocalDate.now
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class GradeStatisticsLocalTest {
private lateinit var gradeStatisticsLocal: GradeStatisticsLocal
private lateinit var testDb: AppDatabase
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
gradeStatisticsLocal = GradeStatisticsLocal(testDb.gradeStatistics, testDb.gradePointsStatistics)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun saveAndRead_subject() {
val list = listOf(
getGradeStatistics("Matematyka", 2, 1),
getGradeStatistics("Fizyka", 1, 2)
)
runBlocking { gradeStatisticsLocal.saveGradesStatistics(list) }
val stats = runBlocking { gradeStatisticsLocal.getGradesStatistics(getSemester(), false).first() }
assertEquals(1, stats.size)
assertEquals(stats[0].subject, "Matematyka")
}
@Test
fun saveAndRead_all() {
val list = listOf(
getGradeStatistics("Matematyka", 2, 1),
getGradeStatistics("Chemia", 2, 1),
getGradeStatistics("Fizyka", 1, 2)
)
runBlocking { gradeStatisticsLocal.saveGradesStatistics(list) }
val stats = runBlocking { gradeStatisticsLocal.getGradesStatistics(getSemester(), false).first() }
assertEquals(2, stats.size)
// assertEquals(3, stats.size)
// assertEquals(stats[0].subject, "Wszystkie") // now in main repo
assertEquals(stats[0].subject, "Matematyka")
assertEquals(stats[1].subject, "Chemia")
}
@Test
fun saveAndRead_points() {
val list = listOf(
getGradePointsStatistics("Matematyka", 2, 1),
getGradePointsStatistics("Chemia", 2, 1),
getGradePointsStatistics("Fizyka", 1, 2)
)
runBlocking { gradeStatisticsLocal.saveGradesPointsStatistics(list) }
val stats = runBlocking { gradeStatisticsLocal.getGradesPointsStatistics(getSemester()).first() }
with(stats[0]) {
assertEquals(subject, "Matematyka")
assertEquals(others, 5.0)
assertEquals(student, 5.0)
}
}
@Test
fun saveAndRead_subjectEmpty() {
runBlocking { gradeStatisticsLocal.saveGradesPointsStatistics(listOf()) }
val stats = runBlocking { gradeStatisticsLocal.getGradesPointsStatistics(getSemester()).first() }
assertEquals(emptyList(), stats)
}
@Test
fun saveAndRead_allEmpty() {
runBlocking { gradeStatisticsLocal.saveGradesPointsStatistics(listOf()) }
val stats = runBlocking { gradeStatisticsLocal.getGradesPointsStatistics(getSemester()).first() }
assertEquals(emptyList(), stats)
}
private fun getSemester(): Semester {
return Semester(2, 2, "", 2019, 1, 2, now(), now(), 1, 1)
}
private fun getGradeStatistics(subject: String, studentId: Int, semesterId: Int): GradeStatistics {
return GradeStatistics(studentId, semesterId, subject, 5, 5, false)
}
private fun getGradePointsStatistics(subject: String, studentId: Int, semesterId: Int): GradePointsStatistics {
return GradePointsStatistics(studentId, semesterId, subject, 5.0, 5.0)
}
}

View file

@ -0,0 +1,51 @@
package io.github.wulkanowy.data.repositories.luckynumber
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Student
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.time.LocalDate
import java.time.LocalDateTime.now
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class LuckyNumberLocalTest {
private lateinit var luckyNumberLocal: LuckyNumberLocal
private lateinit var testDb: AppDatabase
@Before
fun createDb() {
testDb = Room
.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
luckyNumberLocal = LuckyNumberLocal(testDb.luckyNumberDao)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun saveAndReadTest() {
val number = LuckyNumber(1, LocalDate.of(2019, 1, 20), 14)
runBlocking { luckyNumberLocal.saveLuckyNumber(number) }
val student = Student("", "", "", "", "", "", false, "", "", "", 1, 1, "", "", "", "", "", "", 1, false, now())
val luckyNumber = runBlocking { luckyNumberLocal.getLuckyNumber(student, LocalDate.of(2019, 1, 20)).first() }
assertEquals(1, luckyNumber?.studentId)
assertEquals(LocalDate.of(2019, 1, 20), luckyNumber?.date)
assertEquals(14, luckyNumber?.luckyNumber)
}
}

View file

@ -0,0 +1,65 @@
package io.github.wulkanowy.data.repositories.recipient
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.Student
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.time.LocalDateTime
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class RecipientLocalTest {
private lateinit var recipientLocal: RecipientLocal
private lateinit var testDb: AppDatabase
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
recipientLocal = RecipientLocal(testDb.recipientDao)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun saveAndReadTest() {
val list = listOf(
Recipient(1, "2rPracownik", "Kowalski Jan", "Kowalski Jan [KJ] - Pracownik (Fake123456)", 3, 4, 2, "hash"),
Recipient(1, "3rPracownik", "Kowalska Karolina", "Kowalska Karolina [KK] - Pracownik (Fake123456)", 4, 4, 2, "hash"),
Recipient(1, "4rPracownik", "Krupa Stanisław", "Krupa Stanisław [KS] - Uczeń (Fake123456)", 5, 4, 1, "hash")
)
runBlocking { recipientLocal.saveRecipients(list) }
val student = Student("fakelog.cf", "AUTO", "", "", "", "", false, "", "", "", 1, 0, "", "", "", "", "", "", 1, true, LocalDateTime.now())
val recipients = runBlocking {
recipientLocal.getRecipients(
student = student,
role = 2,
unit = ReportingUnit(1, 4, "", 0, "", emptyList())
)
}
assertEquals(2, recipients.size)
assertEquals(1, recipients[0].studentId)
assertEquals("3rPracownik", recipients[1].realId)
assertEquals("Kowalski Jan", recipients[0].name)
assertEquals("Kowalska Karolina [KK] - Pracownik (Fake123456)", recipients[1].realName)
assertEquals(3, recipients[0].loginId)
assertEquals(4, recipients[1].unitId)
assertEquals(2, recipients[0].role)
assertEquals("hash", recipients[1].hash)
}
}

View file

@ -0,0 +1,46 @@
package io.github.wulkanowy.data.repositories.student
import android.content.Context
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.TestDispatchersProvider
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.repositories.getStudent
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class StudentLocalTest {
private lateinit var studentLocal: StudentLocal
private lateinit var testDb: AppDatabase
private val student = getStudent()
@Before
fun createDb() {
val context = ApplicationProvider.getApplicationContext<Context>()
testDb = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java)
.build()
studentLocal = StudentLocal(testDb.studentDao, TestDispatchersProvider(), context)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun saveAndReadTest() {
runBlocking { studentLocal.saveStudents(listOf(student)) }
val student = runBlocking { studentLocal.getCurrentStudent(true) }
assertEquals("23", student?.schoolSymbol)
}
}

View file

@ -0,0 +1,48 @@
package io.github.wulkanowy.data.repositories.timetable
import java.time.LocalDateTime
import java.time.LocalDateTime.now
import io.github.wulkanowy.data.db.entities.Timetable as TimetableLocal
import io.github.wulkanowy.sdk.pojo.Timetable as TimetableRemote
fun createTimetableLocal(start: LocalDateTime, number: Int, room: String = "", subject: String = "", teacher: String = "", changes: Boolean = false): TimetableLocal {
return TimetableLocal(
studentId = 1,
diaryId = 2,
number = number,
start = start,
end = now(),
date = start.toLocalDate(),
subject = subject,
subjectOld = "",
group = "",
room = room,
roomOld = "",
teacher = teacher,
teacherOld = "",
info = "",
isStudentPlan = true,
changes = changes,
canceled = false
)
}
fun createTimetableRemote(start: LocalDateTime, number: Int = 1, room: String = "", subject: String = "", teacher: String = "", changes: Boolean = false): TimetableRemote {
return TimetableRemote(
number = number,
start = start,
end = start.plusMinutes(45),
date = start.toLocalDate(),
subject = subject,
group = "",
room = room,
teacher = teacher,
info = "",
changes = changes,
canceled = false,
roomOld = "",
subjectOld = "",
teacherOld = "",
studentPlan = true
)
}

View file

@ -0,0 +1,59 @@
package io.github.wulkanowy.data.repositories.timetable
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.time.LocalDate
import java.time.LocalDateTime.of
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class TimetableLocalTest {
private lateinit var timetableDb: TimetableLocal
private lateinit var testDb: AppDatabase
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
timetableDb = TimetableLocal(testDb.timetableDao)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun saveAndReadTest() {
val list = listOf(
createTimetableLocal(of(2018, 9, 10, 0, 0, 0), 1),
createTimetableLocal(of(2018, 9, 14, 0, 0, 0), 1),
createTimetableLocal(of(2018, 9, 17, 0, 0, 0), 1)
)
runBlocking { timetableDb.saveTimetable(list) }
val semester = Semester(1, 2, "", 1, 1, 2019, LocalDate.now(), LocalDate.now(), 1, 1)
val exams = runBlocking {
timetableDb.getTimetable(
semester = semester,
startDate = LocalDate.of(2018, 9, 10),
endDate = LocalDate.of(2018, 9, 14)
).first()
}
assertEquals(2, exams.size)
assertEquals(exams[0].date, LocalDate.of(2018, 9, 10))
assertEquals(exams[1].date, LocalDate.of(2018, 9, 14))
}
}

View file

@ -0,0 +1,155 @@
package io.github.wulkanowy.data.repositories.timetable
import android.os.Build.VERSION_CODES.P
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.repositories.getSemester
import io.github.wulkanowy.data.repositories.getStudent
import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.impl.annotations.MockK
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.time.LocalDate
import java.time.LocalDateTime.of
import kotlin.test.assertEquals
@SdkSuppress(minSdkVersion = P)
@RunWith(AndroidJUnit4::class)
class TimetableRepositoryTest {
@MockK(relaxed = true)
private lateinit var timetableNotificationSchedulerHelper: TimetableNotificationSchedulerHelper
@MockK
private lateinit var timetableRemote: TimetableRemote
private lateinit var timetableLocal: TimetableLocal
private lateinit var testDb: AppDatabase
private val student = getStudent()
private val semester = getSemester()
@Before
fun initApi() {
MockKAnnotations.init(this)
testDb = Room.inMemoryDatabaseBuilder(getApplicationContext(), AppDatabase::class.java).build()
timetableLocal = TimetableLocal(testDb.timetableDao)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun copyRoomToCompletedFromPrevious() {
runBlocking {
timetableLocal.saveTimetable(listOf(
createTimetableLocal(of(2019, 3, 5, 8, 0), 1, "123", "Przyroda"),
createTimetableLocal(of(2019, 3, 5, 8, 50), 2, "321", "Religia"),
createTimetableLocal(of(2019, 3, 5, 9, 40), 3, "213", "W-F"),
createTimetableLocal(of(2019, 3, 5, 10, 30), 3, "213", "W-F", "Jan Kowalski")
))
}
coEvery { timetableRemote.getTimetable(student, semester, any(), any()) } returns listOf(
createTimetableLocal(of(2019, 3, 5, 8, 0), 1, "", "Przyroda"),
createTimetableLocal(of(2019, 3, 5, 8, 50), 2, "", "Religia"),
createTimetableLocal(of(2019, 3, 5, 9, 40), 3, "", "W-F"),
createTimetableLocal(of(2019, 3, 5, 10, 30), 4, "", "W-F")
)
val lessons = runBlocking {
TimetableRepository(timetableLocal, timetableRemote, timetableNotificationSchedulerHelper).getTimetable(
student = student,
semester = semester,
start = LocalDate.of(2019, 3, 5),
end = LocalDate.of(2019, 3, 5),
forceRefresh = true
).filter { it.status == Status.SUCCESS }.first().data.orEmpty()
}
assertEquals(4, lessons.size)
assertEquals("123", lessons[0].room)
assertEquals("321", lessons[1].room)
assertEquals("213", lessons[2].room)
}
@Test
fun copyTeacherToCompletedFromPrevious() {
val list = listOf(
createTimetableLocal(of(2019, 12, 23, 8, 0), 1, "123", "Matematyka", "Paweł Poniedziałkowski", false),
createTimetableLocal(of(2019, 12, 23, 8, 50), 2, "124", "Matematyka", "Paweł Poniedziałkowski", false),
createTimetableLocal(of(2019, 12, 23, 9, 40), 3, "125", "Język polski", "Joanna Wtorkowska", true),
createTimetableLocal(of(2019, 12, 23, 10, 40), 4, "126", "Język polski", "Joanna Wtorkowska", true),
createTimetableLocal(of(2019, 12, 24, 8, 0), 1, "123", "Język polski", "Joanna Wtorkowska", false),
createTimetableLocal(of(2019, 12, 24, 8, 50), 2, "124", "Język polski", "Joanna Wtorkowska", false),
createTimetableLocal(of(2019, 12, 24, 9, 40), 3, "125", "Język polski", "Joanna Środowska", true),
createTimetableLocal(of(2019, 12, 24, 10, 40), 4, "126", "Język polski", "Joanna Środowska", true),
createTimetableLocal(of(2019, 12, 25, 8, 0), 1, "123", "Matematyka", "", false),
createTimetableLocal(of(2019, 12, 25, 8, 50), 2, "124", "Matematyka", "", false),
createTimetableLocal(of(2019, 12, 25, 9, 40), 3, "125", "Matematyka", "", true),
createTimetableLocal(of(2019, 12, 25, 10, 40), 4, "126", "Matematyka", "", true)
)
runBlocking { timetableLocal.saveTimetable(list) }
coEvery { timetableRemote.getTimetable(student, semester, any(), any()) } returns listOf(
createTimetableLocal(of(2019, 12, 23, 8, 0), 1, "123", "Matematyka", "Paweł Poniedziałkowski", false),
createTimetableLocal(of(2019, 12, 23, 8, 50), 2, "124", "Matematyka", "Jakub Wtorkowski", true),
createTimetableLocal(of(2019, 12, 23, 9, 40), 3, "125", "Język polski", "Joanna Poniedziałkowska", false),
createTimetableLocal(of(2019, 12, 23, 10, 40), 4, "126", "Język polski", "Joanna Wtorkowska", true),
createTimetableLocal(of(2019, 12, 24, 8, 0), 1, "123", "Język polski", "", false),
createTimetableLocal(of(2019, 12, 24, 8, 50), 2, "124", "Język polski", "", true),
createTimetableLocal(of(2019, 12, 24, 9, 40), 3, "125", "Język polski", "", false),
createTimetableLocal(of(2019, 12, 24, 10, 40), 4, "126", "Język polski", "", true),
createTimetableLocal(of(2019, 12, 25, 8, 0), 1, "123", "Matematyka", "Paweł Środowski", false),
createTimetableLocal(of(2019, 12, 25, 8, 50), 2, "124", "Matematyka", "Paweł Czwartkowski", true),
createTimetableLocal(of(2019, 12, 25, 9, 40), 3, "125", "Matematyka", "Paweł Środowski", false),
createTimetableLocal(of(2019, 12, 25, 10, 40), 4, "126", "Matematyka", "Paweł Czwartkowski", true)
)
val lessons = runBlocking {
TimetableRepository(timetableLocal, timetableRemote, timetableNotificationSchedulerHelper).getTimetable(
student = student,
semester = semester,
start = LocalDate.of(2019, 12, 23),
end = LocalDate.of(2019, 12, 25),
forceRefresh = true
).filter { it.status == Status.SUCCESS }.first().data.orEmpty()
}
assertEquals(12, lessons.size)
assertEquals("Paweł Poniedziałkowski", lessons[0].teacher)
assertEquals("Jakub Wtorkowski", lessons[1].teacher)
assertEquals("Joanna Poniedziałkowska", lessons[2].teacher)
assertEquals("Joanna Wtorkowska", lessons[3].teacher)
assertEquals("Joanna Wtorkowska", lessons[4].teacher)
assertEquals("", lessons[5].teacher)
assertEquals("", lessons[6].teacher)
assertEquals("", lessons[7].teacher)
assertEquals("Paweł Środowski", lessons[8].teacher)
assertEquals("Paweł Czwartkowski", lessons[9].teacher)
assertEquals("Paweł Środowski", lessons[10].teacher)
assertEquals("Paweł Czwartkowski", lessons[11].teacher)
}
}

View file

@ -1,33 +0,0 @@
{
"agcgw":{
"backurl":"connect-dre.dbankcloud.cn",
"url":"connect-dre.hispace.hicloud.com"
},
"client":{
"cp_id":"890048000024105546",
"product_id":"",
"client_id":"",
"client_secret":"",
"app_id":"101440411",
"package_name":"io.github.wulkanowy.dev",
"api_key":""
},
"service":{
"analytics":{
"collector_url":"datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
"resource_id":"p1",
"channel_id":""
},
"search":{
"url":"https://search-dre.cloud.huawei.com"
},
"cloudstorage":{
"storage_url":"https://ops-dre.agcstorage.link"
},
"ml":{
"mlservice_url":"ml-api-dre.ai.dbankcloud.com,ml-api-dre.ai.dbankcloud.cn"
}
},
"region":"DE",
"configuration_version":"1.0"
}

View file

@ -1,19 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<group
android:scaleX="0.92"
android:scaleY="0.92"
android:translateX="0.96"
android:translateY="0.96">
<path
android:fillColor="#FFF"
android:pathData="M3.9512,2A2,2 0,0 0,2 4L2,18A2,2 0,0 0,4 20L10.0996,20C11.3596,21.24 13.09,22 15,22A7,7 0,0 0,15.7988 21.9551L15.7988,19.7832A4.85,4.85 0,0 1,15 19.8496C12.32,19.8496 10.1504,17.68 10.1504,15A4.85,4.85 0,0 1,15 10.1504C17.4677,10.1504 19.4978,11.9912 19.8047,14.375C20.566,14.3758 21.3108,14.5325 21.9922,14.834C21.9491,12.9905 21.2036,11.3226 20,10.0996L20,4A2,2 0,0 0,18 2L4,2A2,2 0,0 0,3.9512 2zM4,5L10,5L10,8L4,8L4,5zM12,5L18,5L18,8L12,8L12,5zM4,10L10.0996,10C9.2596,10.82 8.6291,11.85 8.2891,13L4,13L4,10zM14,12L14,15.6895L15.7988,16.7266L15.7988,14.9922L15.5,14.8203L15.5,12L14,12zM4,15L8,15C8,16.07 8.2399,17.09 8.6699,18L4,18L4,15z" />
<path
android:fillColor="#FFF"
android:pathData="m17.298,24v-8.1249h2.5c0.7143,0 1.3523,0.1618 1.9141,0.4855 0.5655,0.3199 1.0063,0.7775 1.3225,1.3728 0.3162,0.5915 0.4743,1.2649 0.4743,2.0201v0.3739c0,0.7552 -0.1562,1.4267 -0.4687,2.0145 -0.3088,0.5878 -0.7459,1.0435 -1.3114,1.3672C21.1633,23.8326 20.5253,23.9963 19.8148,24ZM18.9721,17.2311v5.4241h0.8091c0.6548,0 1.1551,-0.2139 1.5011,-0.6417 0.346,-0.4278 0.5227,-1.0398 0.5301,-1.8359v-0.4297c0,-0.8259 -0.1711,-1.4509 -0.5134,-1.875 -0.3423,-0.4278 -0.8426,-0.6417 -1.5011,-0.6417z" />
</group>
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 700 B

View file

@ -8,6 +8,6 @@ open class TimberTreeNoOp : Timber.Tree() {
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {} override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {}
} }
class CrashLogTree : TimberTreeNoOp() class CrashlyticsTree : TimberTreeNoOp()
class CrashLogExceptionTree : TimberTreeNoOp() class CrashlyticsExceptionTree : TimberTreeNoOp()

View file

@ -6,7 +6,7 @@ import javax.inject.Singleton
@Singleton @Singleton
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
class AnalyticsHelper @Inject constructor() { class FirebaseAnalyticsHelper @Inject constructor() {
fun logEvent(name: String, vararg params: Pair<String, Any?>) { fun logEvent(name: String, vararg params: Pair<String, Any?>) {
// do nothing // do nothing
@ -15,8 +15,4 @@ class AnalyticsHelper @Inject constructor() {
fun setCurrentScreen(activity: Activity, name: String?) { fun setCurrentScreen(activity: Activity, name: String?) {
// do nothing // do nothing
} }
fun popCurrentScreen(name: String?) {
// do nothing
}
} }

View file

@ -1,17 +0,0 @@
package io.github.wulkanowy.utils
import android.app.Activity
import android.view.View
import javax.inject.Inject
@Suppress("UNUSED_PARAMETER")
class UpdateHelper @Inject constructor() {
lateinit var messageContainer: View
fun checkAndInstallUpdates(activity: Activity) {}
fun onActivityResult(requestCode: Int, resultCode: Int) {}
fun onResume(activity: Activity) {}
}

View file

@ -1,39 +0,0 @@
package io.github.wulkanowy.utils
import android.app.Activity
import android.content.Context
import android.os.Bundle
import com.huawei.hms.analytics.HiAnalytics
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AnalyticsHelper @Inject constructor(
@ApplicationContext private val context: Context
) {
private val analytics by lazy { HiAnalytics.getInstance(context) }
fun logEvent(name: String, vararg params: Pair<String, Any?>) {
Bundle().apply {
params.forEach {
if (it.second == null) return@forEach
when (it.second) {
is String, is String? -> putString(it.first, it.second as String)
is Int, is Int? -> putInt(it.first, it.second as Int)
is Boolean, is Boolean? -> putBoolean(it.first, it.second as Boolean)
}
}
analytics.onEvent(name, this)
}
}
fun setCurrentScreen(activity: Activity, name: String?) {
analytics.pageStart(name, activity::class.simpleName)
}
fun popCurrentScreen(name: String?) {
analytics.pageEnd(name)
}
}

View file

@ -1,53 +0,0 @@
package io.github.wulkanowy.utils
import android.util.Log
import com.huawei.agconnect.crash.AGConnectCrash
import fr.bipi.tressence.base.FormatterPriorityTree
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
import java.io.InterruptedIOException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) {
private val connectCrash by lazy { AGConnectCrash.getInstance() }
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
if (skipLog(priority, tag, message, t)) return
connectCrash.log(format(priority, tag, message))
}
}
class CrashLogExceptionTree : FormatterPriorityTree(Log.ERROR) {
private val connectCrash by lazy { AGConnectCrash.getInstance() }
override fun skipLog(priority: Int, tag: String?, message: String, t: Throwable?): Boolean {
return when (t) {
is FeatureDisabledException,
is FeatureNotAvailableException,
is UnknownHostException,
is SocketTimeoutException,
is InterruptedIOException -> true
else -> super.skipLog(priority, tag, message, t)
}
}
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
if (skipLog(priority, tag, message, t)) return
// Disabled due to a bug in the Huawei library
/*connectCrash.setCustomKey("priority", priority)
connectCrash.setCustomKey("tag", tag.orEmpty())
connectCrash.setCustomKey("message", message)
if (t != null) {
connectCrash.recordException(t)
} else {
connectCrash.recordException(StackTraceRecorder(format(priority, tag, message)))
}*/
}
}

View file

@ -1,17 +0,0 @@
package io.github.wulkanowy.utils
import android.app.Activity
import android.view.View
import javax.inject.Inject
@Suppress("UNUSED_PARAMETER")
class UpdateHelper @Inject constructor() {
lateinit var messageContainer: View
fun checkAndInstallUpdates(activity: Activity) {}
fun onActivityResult(requestCode: Int, resultCode: Int) {}
fun onResume(activity: Activity) {}
}

View file

@ -9,29 +9,6 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="mailto" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="tel" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="geo" />
</intent>
</queries>
<application <application
android:name=".WulkanowyApp" android:name=".WulkanowyApp"
android:allowBackup="false" android:allowBackup="false"
@ -133,10 +110,6 @@
android:resource="@xml/provider_paths" /> android:resource="@xml/provider_paths" />
</provider> </provider>
<meta-data
android:name="install_channel"
android:value="${install_channel}" />
<!-- workaround for https://github.com/firebase/firebase-android-sdk/issues/473 enabled:false --> <!-- workaround for https://github.com/firebase/firebase-android-sdk/issues/473 enabled:false -->
<!-- https://firebase.googleblog.com/2017/03/take-control-of-your-firebase-init-on.html --> <!-- https://firebase.googleblog.com/2017/03/take-control-of-your-firebase-init-on.html -->
<provider <provider

View file

@ -33,6 +33,6 @@
}, },
{ {
"displayName": "Mateusz Idziejczak", "displayName": "Mateusz Idziejczak",
"githubUsername": "Luncenok" "githubUsername": "PanTajemnic"
} }
] ]

View file

@ -5,20 +5,17 @@ import android.content.Context
import android.util.Log.DEBUG import android.util.Log.DEBUG
import android.util.Log.INFO import android.util.Log.INFO
import android.util.Log.VERBOSE import android.util.Log.VERBOSE
import android.webkit.WebView
import androidx.hilt.work.HiltWorkerFactory import androidx.hilt.work.HiltWorkerFactory
import androidx.multidex.MultiDex import androidx.multidex.MultiDex
import androidx.work.Configuration import androidx.work.Configuration
import com.yariksoffice.lingver.Lingver import com.yariksoffice.lingver.Lingver
import dagger.hilt.android.HiltAndroidApp import dagger.hilt.android.HiltAndroidApp
import fr.bipi.tressence.file.FileLoggerTree import fr.bipi.tressence.file.FileLoggerTree
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.ui.base.ThemeManager import io.github.wulkanowy.ui.base.ThemeManager
import io.github.wulkanowy.utils.ActivityLifecycleLogger import io.github.wulkanowy.utils.ActivityLifecycleLogger
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.CrashLogExceptionTree import io.github.wulkanowy.utils.CrashlyticsExceptionTree
import io.github.wulkanowy.utils.CrashLogTree import io.github.wulkanowy.utils.CrashlyticsTree
import io.github.wulkanowy.utils.DebugLogTree import io.github.wulkanowy.utils.DebugLogTree
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -35,12 +32,6 @@ class WulkanowyApp : Application(), Configuration.Provider {
@Inject @Inject
lateinit var appInfo: AppInfo lateinit var appInfo: AppInfo
@Inject
lateinit var preferencesRepository: PreferencesRepository
@Inject
lateinit var analyticsHelper: AnalyticsHelper
override fun attachBaseContext(base: Context?) { override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base) super.attachBaseContext(base)
MultiDex.install(this) MultiDex.install(this)
@ -48,18 +39,16 @@ class WulkanowyApp : Application(), Configuration.Provider {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
Lingver.init(this)
initializeAppLanguage()
themeManager.applyDefaultTheme() themeManager.applyDefaultTheme()
initLogging() initLogging()
fixWebViewLocale()
} }
private fun initLogging() { private fun initLogging() {
if (appInfo.isDebug) { if (appInfo.isDebug) {
Timber.plant(DebugLogTree()) Timber.plant(DebugLogTree())
Timber.plant( Timber.plant(FileLoggerTree.Builder()
FileLoggerTree.Builder()
.withFileName("wulkanowy.%g.log") .withFileName("wulkanowy.%g.log")
.withDirName(applicationContext.filesDir.absolutePath) .withDirName(applicationContext.filesDir.absolutePath)
.withFileLimit(10) .withFileLimit(10)
@ -67,28 +56,12 @@ class WulkanowyApp : Application(), Configuration.Provider {
.build() .build()
) )
} else { } else {
Timber.plant(CrashLogExceptionTree()) Timber.plant(CrashlyticsExceptionTree())
Timber.plant(CrashLogTree()) Timber.plant(CrashlyticsTree())
} }
registerActivityLifecycleCallbacks(ActivityLifecycleLogger()) registerActivityLifecycleCallbacks(ActivityLifecycleLogger())
} }
private fun initializeAppLanguage() {
Lingver.init(this)
if (preferencesRepository.appLanguage == "system") {
Lingver.getInstance().setFollowSystemLocale(this)
analyticsHelper.logEvent("language", "startup" to appInfo.systemLanguage)
} else {
analyticsHelper.logEvent("language", "startup" to preferencesRepository.appLanguage)
}
}
private fun fixWebViewLocale() {
//https://stackoverflow.com/questions/40398528/android-webview-language-changes-abruptly-on-android-7-0-and-above
WebView(this).destroy()
}
override fun getWorkManagerConfiguration() = Configuration.Builder() override fun getWorkManagerConfiguration() = Configuration.Builder()
.setWorkerFactory(workerFactory) .setWorkerFactory(workerFactory)
.setMinimumLoggingLevel(if (appInfo.isDebug) VERBOSE else INFO) .setMinimumLoggingLevel(if (appInfo.isDebug) VERBOSE else INFO)

View file

@ -11,17 +11,17 @@ import com.chuckerteam.chucker.api.RetentionManager
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.components.ApplicationComponent
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.SharedPrefProvider import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import timber.log.Timber import timber.log.Timber
import javax.inject.Singleton import javax.inject.Singleton
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(ApplicationComponent::class)
internal class RepositoryModule { internal class RepositoryModule {
@Singleton @Singleton
@ -33,21 +33,13 @@ internal class RepositoryModule {
setSimpleHttpLogger { Timber.d(it) } setSimpleHttpLogger { Timber.d(it) }
// for debug only // for debug only
addInterceptor( addInterceptor(ChuckerInterceptor(context, chuckerCollector), true)
ChuckerInterceptor.Builder(context)
.collector(chuckerCollector)
.alwaysReadResponseBody(true)
.build(), network = true
)
} }
} }
@Singleton @Singleton
@Provides @Provides
fun provideChuckerCollector( fun provideChuckerCollector(@ApplicationContext context: Context, prefRepository: PreferencesRepository): ChuckerCollector {
@ApplicationContext context: Context,
prefRepository: PreferencesRepository
): ChuckerCollector {
return ChuckerCollector( return ChuckerCollector(
context = context, context = context,
showNotification = prefRepository.isDebugNotificationEnable, showNotification = prefRepository.isDebugNotificationEnable,
@ -57,10 +49,7 @@ internal class RepositoryModule {
@Singleton @Singleton
@Provides @Provides
fun provideDatabase( fun provideDatabase(@ApplicationContext context: Context, sharedPrefProvider: SharedPrefProvider) = AppDatabase.newInstance(context, sharedPrefProvider)
@ApplicationContext context: Context,
sharedPrefProvider: SharedPrefProvider,
) = AppDatabase.newInstance(context, sharedPrefProvider)
@Singleton @Singleton
@Provides @Provides
@ -72,8 +61,7 @@ internal class RepositoryModule {
@Singleton @Singleton
@Provides @Provides
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences = fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
PreferenceManager.getDefaultSharedPreferences(context)
@Singleton @Singleton
@Provides @Provides
@ -93,16 +81,11 @@ internal class RepositoryModule {
@Singleton @Singleton
@Provides @Provides
fun provideGradePartialStatisticsDao(database: AppDatabase) = database.gradePartialStatisticsDao fun provideGradeStatisticsDao(database: AppDatabase) = database.gradeStatistics
@Singleton @Singleton
@Provides @Provides
fun provideGradeSemesterStatisticsDao(database: AppDatabase) = fun provideGradePointsStatisticsDao(database: AppDatabase) = database.gradePointsStatistics
database.gradeSemesterStatisticsDao
@Singleton
@Provides
fun provideGradePointsStatisticsDao(database: AppDatabase) = database.gradePointsStatisticsDao
@Singleton @Singleton
@Provides @Provides
@ -167,16 +150,4 @@ internal class RepositoryModule {
@Singleton @Singleton
@Provides @Provides
fun provideSchoolInfoDao(database: AppDatabase) = database.schoolDao fun provideSchoolInfoDao(database: AppDatabase) = database.schoolDao
@Singleton
@Provides
fun provideConferenceDao(database: AppDatabase) = database.conferenceDao
@Singleton
@Provides
fun provideTimetableAdditionalDao(database: AppDatabase) = database.timetableAdditionalDao
@Singleton
@Provides
fun provideStudentInfoDao(database: AppDatabase) = database.studentInfoDao
} }

View file

@ -10,12 +10,10 @@ import androidx.room.migration.Migration
import io.github.wulkanowy.data.db.dao.AttendanceDao import io.github.wulkanowy.data.db.dao.AttendanceDao
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
import io.github.wulkanowy.data.db.dao.ConferenceDao
import io.github.wulkanowy.data.db.dao.ExamDao import io.github.wulkanowy.data.db.dao.ExamDao
import io.github.wulkanowy.data.db.dao.GradeDao import io.github.wulkanowy.data.db.dao.GradeDao
import io.github.wulkanowy.data.db.dao.GradePartialStatisticsDao
import io.github.wulkanowy.data.db.dao.GradePointsStatisticsDao import io.github.wulkanowy.data.db.dao.GradePointsStatisticsDao
import io.github.wulkanowy.data.db.dao.GradeSemesterStatisticsDao import io.github.wulkanowy.data.db.dao.GradeStatisticsDao
import io.github.wulkanowy.data.db.dao.GradeSummaryDao import io.github.wulkanowy.data.db.dao.GradeSummaryDao
import io.github.wulkanowy.data.db.dao.HomeworkDao import io.github.wulkanowy.data.db.dao.HomeworkDao
import io.github.wulkanowy.data.db.dao.LuckyNumberDao import io.github.wulkanowy.data.db.dao.LuckyNumberDao
@ -28,20 +26,16 @@ import io.github.wulkanowy.data.db.dao.ReportingUnitDao
import io.github.wulkanowy.data.db.dao.SchoolDao import io.github.wulkanowy.data.db.dao.SchoolDao
import io.github.wulkanowy.data.db.dao.SemesterDao import io.github.wulkanowy.data.db.dao.SemesterDao
import io.github.wulkanowy.data.db.dao.StudentDao import io.github.wulkanowy.data.db.dao.StudentDao
import io.github.wulkanowy.data.db.dao.StudentInfoDao
import io.github.wulkanowy.data.db.dao.SubjectDao import io.github.wulkanowy.data.db.dao.SubjectDao
import io.github.wulkanowy.data.db.dao.TeacherDao import io.github.wulkanowy.data.db.dao.TeacherDao
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
import io.github.wulkanowy.data.db.dao.TimetableDao import io.github.wulkanowy.data.db.dao.TimetableDao
import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.AttendanceSummary import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.CompletedLesson import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Conference
import io.github.wulkanowy.data.db.entities.Exam import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Grade import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import io.github.wulkanowy.data.db.entities.GradePointsStatistics import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics import io.github.wulkanowy.data.db.entities.GradeStatistics
import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.db.entities.Homework import io.github.wulkanowy.data.db.entities.Homework
import io.github.wulkanowy.data.db.entities.LuckyNumber import io.github.wulkanowy.data.db.entities.LuckyNumber
@ -54,11 +48,9 @@ import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.School import io.github.wulkanowy.data.db.entities.School
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentInfo
import io.github.wulkanowy.data.db.entities.Subject import io.github.wulkanowy.data.db.entities.Subject
import io.github.wulkanowy.data.db.entities.Teacher import io.github.wulkanowy.data.db.entities.Teacher
import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.db.entities.TimetableAdditional
import io.github.wulkanowy.data.db.migrations.Migration10 import io.github.wulkanowy.data.db.migrations.Migration10
import io.github.wulkanowy.data.db.migrations.Migration11 import io.github.wulkanowy.data.db.migrations.Migration11
import io.github.wulkanowy.data.db.migrations.Migration12 import io.github.wulkanowy.data.db.migrations.Migration12
@ -78,12 +70,7 @@ import io.github.wulkanowy.data.db.migrations.Migration24
import io.github.wulkanowy.data.db.migrations.Migration25 import io.github.wulkanowy.data.db.migrations.Migration25
import io.github.wulkanowy.data.db.migrations.Migration26 import io.github.wulkanowy.data.db.migrations.Migration26
import io.github.wulkanowy.data.db.migrations.Migration27 import io.github.wulkanowy.data.db.migrations.Migration27
import io.github.wulkanowy.data.db.migrations.Migration28
import io.github.wulkanowy.data.db.migrations.Migration29
import io.github.wulkanowy.data.db.migrations.Migration3 import io.github.wulkanowy.data.db.migrations.Migration3
import io.github.wulkanowy.data.db.migrations.Migration30
import io.github.wulkanowy.data.db.migrations.Migration31
import io.github.wulkanowy.data.db.migrations.Migration32
import io.github.wulkanowy.data.db.migrations.Migration4 import io.github.wulkanowy.data.db.migrations.Migration4
import io.github.wulkanowy.data.db.migrations.Migration5 import io.github.wulkanowy.data.db.migrations.Migration5
import io.github.wulkanowy.data.db.migrations.Migration6 import io.github.wulkanowy.data.db.migrations.Migration6
@ -103,9 +90,8 @@ import javax.inject.Singleton
AttendanceSummary::class, AttendanceSummary::class,
Grade::class, Grade::class,
GradeSummary::class, GradeSummary::class,
GradePartialStatistics::class, GradeStatistics::class,
GradePointsStatistics::class, GradePointsStatistics::class,
GradeSemesterStatistics::class,
Message::class, Message::class,
MessageAttachment::class, MessageAttachment::class,
Note::class, Note::class,
@ -117,10 +103,7 @@ import javax.inject.Singleton
Recipient::class, Recipient::class,
MobileDevice::class, MobileDevice::class,
Teacher::class, Teacher::class,
School::class, School::class
Conference::class,
TimetableAdditional::class,
StudentInfo::class,
], ],
version = AppDatabase.VERSION_SCHEMA, version = AppDatabase.VERSION_SCHEMA,
exportSchema = true exportSchema = true
@ -129,7 +112,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
companion object { companion object {
const val VERSION_SCHEMA = 32 const val VERSION_SCHEMA = 27
fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> { fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> {
return arrayOf( return arrayOf(
@ -159,11 +142,6 @@ abstract class AppDatabase : RoomDatabase() {
Migration25(), Migration25(),
Migration26(), Migration26(),
Migration27(), Migration27(),
Migration28(),
Migration29(),
Migration30(),
Migration31(),
Migration32()
) )
} }
@ -193,11 +171,9 @@ abstract class AppDatabase : RoomDatabase() {
abstract val gradeSummaryDao: GradeSummaryDao abstract val gradeSummaryDao: GradeSummaryDao
abstract val gradePartialStatisticsDao: GradePartialStatisticsDao abstract val gradeStatistics: GradeStatisticsDao
abstract val gradePointsStatisticsDao: GradePointsStatisticsDao abstract val gradePointsStatistics: GradePointsStatisticsDao
abstract val gradeSemesterStatisticsDao: GradeSemesterStatisticsDao
abstract val messagesDao: MessagesDao abstract val messagesDao: MessagesDao
@ -222,10 +198,4 @@ abstract class AppDatabase : RoomDatabase() {
abstract val teacherDao: TeacherDao abstract val teacherDao: TeacherDao
abstract val schoolDao: SchoolDao abstract val schoolDao: SchoolDao
abstract val conferenceDao: ConferenceDao
abstract val timetableAdditionalDao: TimetableAdditionalDao
abstract val studentInfoDao: StudentInfoDao
} }

View file

@ -6,9 +6,7 @@ import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class SharedPrefProvider @Inject constructor( class SharedPrefProvider @Inject constructor(private val sharedPref: SharedPreferences) {
private val sharedPref: SharedPreferences
) {
companion object { companion object {
const val APP_VERSION_CODE_KEY = "app_version_code" const val APP_VERSION_CODE_KEY = "app_version_code"

View file

@ -56,11 +56,11 @@ object PairAdapterFactory : JsonAdapter.Factory {
private fun deserializeGsonPair(reader: JsonReader): List<Pair<String, String>>? { private fun deserializeGsonPair(reader: JsonReader): List<Pair<String, String>>? {
val list = listAdapter.fromJson(reader) ?: return null val list = listAdapter.fromJson(reader) ?: return null
return list.map { require(list.size == 2 || list.isEmpty()) {
require(it.size == 2) {
"pair with more or less than two elements: $list" "pair with more or less than two elements: $list"
} }
return list.map {
it["first"].orEmpty() to it["second"].orEmpty() it["first"].orEmpty() to it["second"].orEmpty()
} }
} }

View file

@ -12,5 +12,5 @@ import javax.inject.Singleton
interface CompletedLessonsDao : BaseDao<CompletedLesson> { interface CompletedLessonsDao : BaseDao<CompletedLesson> {
@Query("SELECT * FROM CompletedLesson WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end") @Query("SELECT * FROM CompletedLesson WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(studentId: Int, diaryId: Int, from: LocalDate, end: LocalDate): Flow<List<CompletedLesson>> fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<CompletedLesson>>
} }

View file

@ -1,15 +0,0 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Conference
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Dao
@Singleton
interface ConferenceDao : BaseDao<Conference> {
@Query("SELECT * FROM Conferences WHERE diary_id = :diaryId AND student_id = :studentId")
fun loadAll(diaryId: Int, studentId: Int): Flow<List<Conference>>
}

View file

@ -1,13 +0,0 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import kotlinx.coroutines.flow.Flow
@Dao
interface GradePartialStatisticsDao : BaseDao<GradePartialStatistics> {
@Query("SELECT * FROM GradePartialStatistics WHERE student_id = :studentId AND semester_id = :semesterId")
fun loadAll(semesterId: Int, studentId: Int): Flow<List<GradePartialStatistics>>
}

View file

@ -1,13 +0,0 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
import kotlinx.coroutines.flow.Flow
@Dao
interface GradeSemesterStatisticsDao : BaseDao<GradeSemesterStatistics> {
@Query("SELECT * FROM GradeSemesterStatistics WHERE student_id = :studentId AND semester_id = :semesterId")
fun loadAll(semesterId: Int, studentId: Int): Flow<List<GradeSemesterStatistics>>
}

View file

@ -0,0 +1,18 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.GradeStatistics
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@Dao
interface GradeStatisticsDao : BaseDao<GradeStatistics> {
@Query("SELECT * FROM GradesStatistics WHERE student_id = :studentId AND semester_id = :semesterId AND subject = :subjectName AND is_semester = :isSemester")
fun loadSubject(semesterId: Int, studentId: Int, subjectName: String, isSemester: Boolean): Flow<List<GradeStatistics>>
@Query("SELECT * FROM GradesStatistics WHERE student_id = :studentId AND semester_id = :semesterId AND is_semester = :isSemester")
fun loadAll(semesterId: Int, studentId: Int, isSemester: Boolean): Flow<List<GradeStatistics>>
}

View file

@ -8,6 +8,6 @@ import kotlinx.coroutines.flow.Flow
@Dao @Dao
interface MobileDeviceDao : BaseDao<MobileDevice> { interface MobileDeviceDao : BaseDao<MobileDevice> {
@Query("SELECT * FROM MobileDevices WHERE student_id = :userLoginId ORDER BY date DESC") @Query("SELECT * FROM MobileDevices WHERE student_id = :studentId ORDER BY date DESC")
fun loadAll(userLoginId: Int): Flow<List<MobileDevice>> fun loadAll(studentId: Int): Flow<List<MobileDevice>>
} }

View file

@ -9,6 +9,6 @@ import javax.inject.Singleton
@Dao @Dao
interface RecipientDao : BaseDao<Recipient> { interface RecipientDao : BaseDao<Recipient> {
@Query("SELECT * FROM Recipients WHERE student_id = :userLoginId AND unit_id = :unitId AND role = :role") @Query("SELECT * FROM Recipients WHERE student_id = :studentId AND role = :role AND unit_id = :unitId")
suspend fun loadAll(userLoginId: Int, unitId: Int, role: Int): List<Recipient> suspend fun load(studentId: Int, role: Int, unitId: Int): List<Recipient>
} }

View file

@ -6,9 +6,7 @@ import androidx.room.Insert
import androidx.room.OnConflictStrategy.ABORT import androidx.room.OnConflictStrategy.ABORT
import androidx.room.Query import androidx.room.Query
import androidx.room.Transaction import androidx.room.Transaction
import androidx.room.Update
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentNick
import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import javax.inject.Singleton import javax.inject.Singleton
@ -22,9 +20,6 @@ interface StudentDao {
@Delete @Delete
suspend fun delete(student: Student) suspend fun delete(student: Student)
@Update(entity = Student::class)
suspend fun update(studentNick: StudentNick)
@Query("SELECT * FROM Students WHERE is_current = 1") @Query("SELECT * FROM Students WHERE is_current = 1")
suspend fun loadCurrent(): Student? suspend fun loadCurrent(): Student?

View file

@ -1,15 +0,0 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.StudentInfo
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@Dao
interface StudentInfoDao : BaseDao<StudentInfo> {
@Query("SELECT * FROM StudentInfo WHERE student_id = :studentId")
fun loadStudentInfo(studentId: Int): Flow<StudentInfo?>
}

View file

@ -1,16 +0,0 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.TimetableAdditional
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Singleton
@Dao
@Singleton
interface TimetableAdditionalDao : BaseDao<TimetableAdditional> {
@Query("SELECT * FROM TimetableAdditional WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<TimetableAdditional>>
}

View file

@ -1,35 +0,0 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
import java.time.LocalDateTime
@Entity(tableName = "Conferences")
data class Conference(
@ColumnInfo(name = "student_id")
val studentId: Int,
@ColumnInfo(name = "diary_id")
val diaryId: Int,
val title: String,
val subject: String,
val agenda: String,
@ColumnInfo(name = "present_on_conference")
val presentOnConference: String,
@ColumnInfo(name = "conference_id")
val conferenceId: Int,
val date: LocalDateTime
) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}

View file

@ -1,33 +0,0 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "GradePartialStatistics")
data class GradePartialStatistics(
@ColumnInfo(name = "student_id")
val studentId: Int,
@ColumnInfo(name = "semester_id")
val semesterId: Int,
val subject: String,
@ColumnInfo(name = "class_average")
val classAverage: String,
@ColumnInfo(name = "student_average")
val studentAverage: String,
@ColumnInfo(name = "class_amounts")
val classAmounts: List<Int>,
@ColumnInfo(name = "student_amounts")
val studentAmounts: List<Int>
) {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}

View file

@ -4,8 +4,8 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
@Entity(tableName = "GradeSemesterStatistics") @Entity(tableName = "GradesStatistics")
data class GradeSemesterStatistics( data class GradeStatistics(
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
val studentId: Int, val studentId: Int,
@ -15,14 +15,13 @@ data class GradeSemesterStatistics(
val subject: String, val subject: String,
val amounts: List<Int>, val grade: Int,
@ColumnInfo(name = "student_grade") val amount: Int,
val studentGrade: Int
@ColumnInfo(name = "is_semester")
val semester: Boolean
) { ) {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
var id: Long = 0 var id: Long = 0
@Transient
var average: String = ""
} }

View file

@ -10,7 +10,7 @@ import java.time.LocalDateTime
data class MobileDevice( data class MobileDevice(
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
val userLoginId: Int, val studentId: Int,
@ColumnInfo(name = "device_id") @ColumnInfo(name = "device_id")
val deviceId: Int, val deviceId: Int,

View file

@ -9,7 +9,7 @@ import java.io.Serializable
data class Recipient( data class Recipient(
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
val userLoginId: Int, val studentId: Int,
@ColumnInfo(name = "real_id") @ColumnInfo(name = "real_id")
val realId: String, val realId: String,

View file

@ -12,7 +12,7 @@ data class ReportingUnit(
val studentId: Int, val studentId: Int,
@ColumnInfo(name = "real_id") @ColumnInfo(name = "real_id")
val unitId: Int, val realId: Int,
@ColumnInfo(name = "short") @ColumnInfo(name = "short")
val shortName: String, val shortName: String,

View file

@ -7,13 +7,7 @@ import androidx.room.PrimaryKey
import java.io.Serializable import java.io.Serializable
import java.time.LocalDateTime import java.time.LocalDateTime
@Entity( @Entity(tableName = "Students", indices = [Index(value = ["email", "symbol", "student_id", "school_id", "class_id"], unique = true)])
tableName = "Students",
indices = [Index(
value = ["email", "symbol", "student_id", "school_id", "class_id"],
unique = true
)]
)
data class Student( data class Student(
@ColumnInfo(name = "scrapper_base_url") @ColumnInfo(name = "scrapper_base_url")
@ -58,7 +52,7 @@ data class Student(
@ColumnInfo(name = "school_id") @ColumnInfo(name = "school_id")
val schoolSymbol: String, val schoolSymbol: String,
@ColumnInfo(name = "school_short") @ColumnInfo(name ="school_short")
val schoolShortName: String, val schoolShortName: String,
@ColumnInfo(name = "school_name") @ColumnInfo(name = "school_name")
@ -79,6 +73,4 @@ data class Student(
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
var id: Long = 0 var id: Long = 0
var nick = ""
} }

View file

@ -1,85 +0,0 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.PrimaryKey
import io.github.wulkanowy.data.enums.Gender
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "StudentInfo")
data class StudentInfo(
@ColumnInfo(name = "student_id")
val studentId: Int,
@ColumnInfo(name = "full_name")
val fullName: String,
@ColumnInfo(name = "first_name")
val firstName: String,
@ColumnInfo(name = "second_name")
val secondName: String,
val surname: String,
@ColumnInfo(name = "birth_date")
val birthDate: LocalDate,
@ColumnInfo(name = "birth_place")
val birthPlace: String,
val gender: Gender,
@ColumnInfo(name = "has_polish_citizenship")
val hasPolishCitizenship: Boolean,
@ColumnInfo(name = "family_name")
val familyName: String,
@ColumnInfo(name = "parents_names")
val parentsNames: String,
val address: String,
@ColumnInfo(name = "registered_address")
val registeredAddress: String,
@ColumnInfo(name = "correspondence_address")
val correspondenceAddress: String,
@ColumnInfo(name = "phone_number")
val phoneNumber: String,
@ColumnInfo(name = "cell_phone_number")
val cellPhoneNumber: String,
val email: String,
@Embedded(prefix = "first_guardian_")
val firstGuardian: StudentGuardian,
@Embedded(prefix = "second_guardian_")
val secondGuardian: StudentGuardian
) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}
data class StudentGuardian(
@ColumnInfo(name = "full_name")
val fullName: String,
val kinship: String,
val address: String,
val phones: String,
val email: String
) : Serializable

View file

@ -1,16 +0,0 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
@Entity
data class StudentNick(
val nick: String
) : Serializable {
@PrimaryKey
var id: Long = 0
}

View file

@ -1,30 +0,0 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
import java.time.LocalDate
import java.time.LocalDateTime
@Entity(tableName = "TimetableAdditional")
data class TimetableAdditional(
@ColumnInfo(name = "student_id")
val studentId: Int,
@ColumnInfo(name = "diary_id")
val diaryId: Int,
val start: LocalDateTime,
val end: LocalDateTime,
val date: LocalDate,
val subject: String,
) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}

View file

@ -1,23 +0,0 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration28 : Migration(27, 28) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
CREATE TABLE IF NOT EXISTS Conferences (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,
diary_id INTEGER NOT NULL,
title TEXT NOT NULL,
subject TEXT NOT NULL,
agenda TEXT NOT NULL,
present_on_conference TEXT NOT NULL,
conference_id INTEGER NOT NULL,
date INTEGER NOT NULL
)
""")
}
}

View file

@ -1,33 +0,0 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration29 : Migration(28, 29) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS GradesStatistics")
database.execSQL("""
CREATE TABLE IF NOT EXISTS GradeSemesterStatistics (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,
semester_id INTEGER NOT NULL,
subject TEXT NOT NULL,
amounts TEXT NOT NULL,
student_grade INTEGER NOT NULL
)
""")
database.execSQL("""
CREATE TABLE IF NOT EXISTS GradePartialStatistics (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,
semester_id INTEGER NOT NULL,
subject TEXT NOT NULL,
class_average TEXT NOT NULL,
student_average TEXT NOT NULL,
class_amounts TEXT NOT NULL,
student_amounts TEXT NOT NULL
)
""")
}
}

View file

@ -1,21 +0,0 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration30 : Migration(29, 30) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
CREATE TABLE TimetableAdditional (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,
diary_id INTEGER NOT NULL,
start INTEGER NOT NULL,
`end` INTEGER NOT NULL,
date INTEGER NOT NULL,
subject TEXT NOT NULL
)
""")
}
}

View file

@ -1,42 +0,0 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration31 : Migration(30, 31) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"""CREATE TABLE IF NOT EXISTS StudentInfo (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,
full_name TEXT NOT NULL,
first_name TEXT NOT NULL,
second_name TEXT NOT NULL,
surname TEXT NOT NULL,
birth_date INTEGER NOT NULL,
birth_place TEXT NOT NULL,
gender TEXT NOT NULL,
has_polish_citizenship INTEGER NOT NULL,
family_name TEXT NOT NULL,
parents_names TEXT NOT NULL,
address TEXT NOT NULL,
registered_address TEXT NOT NULL,
correspondence_address TEXT NOT NULL,
phone_number TEXT NOT NULL,
cell_phone_number TEXT NOT NULL,
email TEXT NOT NULL,
first_guardian_full_name TEXT NOT NULL,
first_guardian_kinship TEXT NOT NULL,
first_guardian_address TEXT NOT NULL,
first_guardian_phones TEXT NOT NULL,
first_guardian_email TEXT NOT NULL,
second_guardian_full_name TEXT NOT NULL,
second_guardian_kinship TEXT NOT NULL,
second_guardian_address TEXT NOT NULL,
second_guardian_phones TEXT NOT NULL,
second_guardian_email TEXT NOT NULL)
"""
)
}
}

View file

@ -1,12 +0,0 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration32 : Migration(31, 32) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN nick TEXT NOT NULL DEFAULT \"\"")
}
}

View file

@ -1,3 +0,0 @@
package io.github.wulkanowy.data.enums
enum class Gender { MALE, FEMALE }

View file

@ -1,43 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.sdk.pojo.Attendance as SdkAttendance
import io.github.wulkanowy.sdk.pojo.AttendanceSummary as SdkAttendanceSummary
fun List<SdkAttendance>.mapToEntities(semester: Semester) = map {
Attendance(
studentId = semester.studentId,
diaryId = semester.diaryId,
date = it.date,
timeId = it.timeId,
number = it.number,
subject = it.subject,
name = it.name,
presence = it.presence,
absence = it.absence,
exemption = it.exemption,
lateness = it.lateness,
excused = it.excused,
deleted = it.deleted,
excusable = it.excusable,
excuseStatus = it.excuseStatus?.name
)
}
fun List<SdkAttendanceSummary>.mapToEntities(semester: Semester, subjectId: Int) = map {
AttendanceSummary(
studentId = semester.studentId,
diaryId = semester.diaryId,
subjectId = subjectId,
month = it.month,
presence = it.presence,
absence = it.absence,
absenceExcused = it.absenceExcused,
absenceForSchoolReasons = it.absenceForSchoolReasons,
lateness = it.lateness,
latenessExcused = it.latenessExcused,
exemption = it.exemption
)
}

View file

@ -1,21 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.sdk.pojo.CompletedLesson as SdkCompletedLesson
fun List<SdkCompletedLesson>.mapToEntities(semester: Semester) = map {
CompletedLesson(
studentId = semester.studentId,
diaryId = semester.diaryId,
date = it.date,
number = it.number,
subject = it.subject,
topic = it.topic,
teacher = it.teacher,
teacherSymbol = it.teacherSymbol,
substitution = it.substitution,
absence = it.absence,
resources = it.resources
)
}

View file

@ -1,18 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Conference
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.sdk.pojo.Conference as SdkConference
fun List<SdkConference>.mapToEntities(semester: Semester) = map {
Conference(
studentId = semester.studentId,
diaryId = semester.diaryId,
agenda = it.agenda,
conferenceId = it.id,
date = it.date,
presentOnConference = it.presentOnConference,
subject = it.subject,
title = it.title
)
}

View file

@ -1,20 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.sdk.pojo.Exam as SdkExam
fun List<SdkExam>.mapToEntities(semester: Semester) = map {
Exam(
studentId = semester.studentId,
diaryId = semester.diaryId,
date = it.date,
entryDate = it.entryDate,
subject = it.subject,
group = it.group,
type = it.type,
description = it.description,
teacher = it.teacher,
teacherSymbol = it.teacherSymbol
)
}

View file

@ -1,42 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.sdk.pojo.GradeSummary as SdkGradeSummary
import io.github.wulkanowy.sdk.pojo.Grade as SdkGrade
fun List<SdkGrade>.mapToEntities(semester: Semester) = map {
Grade(
studentId = semester.studentId,
semesterId = semester.semesterId,
subject = it.subject,
entry = it.entry,
value = it.value,
modifier = it.modifier,
comment = it.comment,
color = it.color,
gradeSymbol = it.symbol,
description = it.description,
weight = it.weight,
weightValue = it.weightValue,
date = it.date,
teacher = it.teacher
)
}
@JvmName("mapGradeSummaryToEntities")
fun List<SdkGradeSummary>.mapToEntities(semester: Semester) = map {
GradeSummary(
semesterId = semester.semesterId,
studentId = semester.studentId,
position = 0,
subject = it.name,
predictedGrade = it.predicted,
finalGrade = it.final,
pointsSum = it.pointsSum,
proposedPoints = it.proposedPoints,
finalPoints = it.finalPoints,
average = it.average
)
}

View file

@ -1,80 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
import io.github.wulkanowy.ui.modules.grade.statistics.ViewType
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSubject as SdkGradeStatisticsSubject
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSemester as SdkGradeStatisticsSemester
import io.github.wulkanowy.sdk.pojo.GradePointsStatistics as SdkGradePointsStatistics
@JvmName("mapToEntitiesSubject")
fun List<SdkGradeStatisticsSubject>.mapToEntities(semester: Semester) = map {
GradePartialStatistics(
semesterId = semester.semesterId,
studentId = semester.studentId,
subject = it.subject,
classAverage = it.classAverage,
studentAverage = it.studentAverage,
classAmounts = it.classItems
.sortedBy { item -> item.grade }
.map { item -> item.amount },
studentAmounts = it.studentItems.map { item -> item.amount }
)
}
@JvmName("mapToEntitiesSemester")
fun List<SdkGradeStatisticsSemester>.mapToEntities(semester: Semester) = map {
GradeSemesterStatistics(
semesterId = semester.semesterId,
studentId = semester.studentId,
subject = it.subject,
amounts = it.items
.sortedBy { item -> item.grade }
.map { item -> item.amount },
studentGrade = it.items.singleOrNull { item -> item.isStudentHere }?.grade ?: 0
)
}
@JvmName("mapToEntitiesPoints")
fun List<SdkGradePointsStatistics>.mapToEntities(semester: Semester) = map {
GradePointsStatistics(
semesterId = semester.semesterId,
studentId = semester.studentId,
subject = it.subject,
others = it.others,
student = it.student
)
}
fun List<GradePartialStatistics>.mapPartialToStatisticItems() = filterNot { it.classAmounts.isEmpty() }.map {
GradeStatisticsItem(
type = ViewType.PARTIAL,
average = it.classAverage,
partial = it,
points = null,
semester = null
)
}
fun List<GradeSemesterStatistics>.mapSemesterToStatisticItems() = filterNot { it.amounts.isEmpty() }.map {
GradeStatisticsItem(
type = ViewType.SEMESTER,
partial = null,
points = null,
average = "",
semester = it
)
}
fun List<GradePointsStatistics>.mapPointsToStatisticsItems() = map {
GradeStatisticsItem(
type = ViewType.POINTS,
partial = null,
semester = null,
average = "",
points = it
)
}

View file

@ -1,21 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.sdk.pojo.Homework as SdkHomework
import io.github.wulkanowy.data.db.entities.Homework
import io.github.wulkanowy.data.db.entities.Semester
fun List<SdkHomework>.mapToEntities(semester: Semester) = map {
Homework(
semesterId = semester.semesterId,
studentId = semester.studentId,
date = it.date,
entryDate = it.entryDate,
subject = it.subject,
content = it.content,
teacher = it.teacher,
teacherSymbol = it.teacherSymbol,
attachments = it.attachments.map { attachment ->
attachment.url to attachment.name
}
)
}

View file

@ -1,12 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Student
import java.time.LocalDate
import io.github.wulkanowy.sdk.pojo.LuckyNumber as SdkLuckyNumber
fun SdkLuckyNumber.mapToEntity(student: Student) = LuckyNumber(
studentId = student.studentId,
date = LocalDate.now(),
luckyNumber = number
)

View file

@ -1,53 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageAttachment
import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
import java.time.LocalDateTime
import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
fun List<SdkMessage>.mapToEntities(student: Student) = map {
Message(
studentId = student.id.toInt(),
realId = it.id ?: 0,
messageId = it.messageId ?: 0,
sender = it.sender?.name.orEmpty(),
senderId = it.sender?.loginId ?: 0,
recipient = it.recipients.singleOrNull()?.name ?: "Wielu adresatów",
subject = it.subject.trim(),
date = it.date ?: LocalDateTime.now(),
folderId = it.folderId,
unread = it.unread ?: false,
removed = it.removed,
hasAttachments = it.hasAttachments
).apply {
content = it.content.orEmpty()
unreadBy = it.unreadBy ?: 0
readBy = it.readBy ?: 0
}
}
fun List<SdkMessageAttachment>.mapToEntities() = map {
MessageAttachment(
realId = it.id,
messageId = it.messageId,
oneDriveId = it.oneDriveId,
url = it.url,
filename = it.filename
)
}
fun List<Recipient>.mapFromEntities() = map {
SdkRecipient(
id = it.realId,
name = it.realName,
loginId = it.loginId,
reportingUnitId = it.unitId,
role = it.role,
hash = it.hash,
shortName = it.name
)
}

View file

@ -1,23 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.MobileDevice
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.pojos.MobileDeviceToken
import io.github.wulkanowy.sdk.pojo.Token as SdkToken
import io.github.wulkanowy.sdk.pojo.Device as SdkDevice
fun List<SdkDevice>.mapToEntities(semester: Semester) = map {
MobileDevice(
userLoginId = semester.studentId,
date = it.createDate,
deviceId = it.id,
name = it.name
)
}
fun SdkToken.mapToMobileDeviceToken() = MobileDeviceToken(
token = token,
symbol = symbol,
pin = pin,
qr = qrCodeImage
)

View file

@ -1,19 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Note
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.sdk.pojo.Note as SdkNote
fun List<SdkNote>.mapToEntities(semester: Semester) = map {
Note(
studentId = semester.studentId,
date = it.date,
teacher = it.teacher,
teacherSymbol = it.teacherSymbol,
category = it.category,
categoryType = it.categoryType.id,
isPointsShow = it.showPoints,
points = it.points,
content = it.content
)
}

View file

@ -1,17 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
fun List<SdkRecipient>.mapToEntities(userLoginId: Int) = map {
Recipient(
userLoginId = userLoginId,
realId = it.id,
realName = it.name,
name = it.shortName,
hash = it.hash,
loginId = it.loginId,
role = it.role,
unitId = it.reportingUnitId ?: 0
)
}

View file

@ -1,16 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.pojo.ReportingUnit as SdkReportingUnit
fun List<SdkReportingUnit>.mapToEntities(student: Student) = map {
ReportingUnit(
studentId = student.studentId,
unitId = it.id,
roles = it.roles,
senderId = it.senderId,
senderName = it.senderName,
shortName = it.short
)
}

View file

@ -1,15 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.School
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.sdk.pojo.School as SdkSchool
fun SdkSchool.mapToEntity(semester: Semester) = School(
studentId = semester.studentId,
classId = semester.classId,
name = name,
address = address,
contact = contact,
headmaster = headmaster,
pedagogue = pedagogue
)

View file

@ -1,38 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.StudentGuardian
import io.github.wulkanowy.data.db.entities.StudentInfo
import io.github.wulkanowy.data.enums.Gender
import io.github.wulkanowy.sdk.pojo.StudentGuardian as SdkStudentGuardian
import io.github.wulkanowy.sdk.pojo.StudentInfo as SdkStudentInfo
fun SdkStudentInfo.mapToEntity(semester: Semester) = StudentInfo(
studentId = semester.studentId,
fullName = fullName,
firstName = firstName,
secondName = secondName,
surname = surname,
birthDate = birthDate,
birthPlace = birthPlace,
gender = Gender.valueOf(gender.name),
hasPolishCitizenship = hasPolishCitizenship,
familyName = familyName,
parentsNames = parentsNames,
address = address,
registeredAddress = registeredAddress,
correspondenceAddress = correspondenceAddress,
phoneNumber = phoneNumber,
cellPhoneNumber = phoneNumber,
email = email,
firstGuardian = guardians[0].mapToEntity(),
secondGuardian = guardians[1].mapToEntity()
)
fun SdkStudentGuardian.mapToEntity() = StudentGuardian(
fullName = fullName,
kinship = kinship,
address = address,
phones = phones,
email = email
)

View file

@ -1,14 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Subject
import io.github.wulkanowy.sdk.pojo.Subject as SdkSubject
fun List<SdkSubject>.mapToEntities(semester: Semester) = map {
Subject(
studentId = semester.studentId,
diaryId = semester.diaryId,
name = it.name,
realId = it.id
)
}

View file

@ -1,15 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Teacher
import io.github.wulkanowy.sdk.pojo.Teacher as SdkTeacher
fun List<SdkTeacher>.mapToEntities(semester: Semester) = map {
Teacher(
studentId = semester.studentId,
name = it.name,
subject = it.subject,
shortName = it.short,
classId = semester.classId
)
}

View file

@ -1,41 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.db.entities.TimetableAdditional
import io.github.wulkanowy.sdk.pojo.Timetable as SdkTimetable
import io.github.wulkanowy.sdk.pojo.TimetableAdditional as SdkTimetableAdditional
fun List<SdkTimetable>.mapToEntities(semester: Semester) = map {
Timetable(
studentId = semester.studentId,
diaryId = semester.diaryId,
number = it.number,
start = it.start,
end = it.end,
date = it.date,
subject = it.subject,
subjectOld = it.subjectOld,
group = it.group,
room = it.room,
roomOld = it.roomOld,
teacher = it.teacher,
teacherOld = it.teacherOld,
info = it.info,
isStudentPlan = it.studentPlan,
changes = it.changes,
canceled = it.canceled
)
}
@JvmName("mapToEntitiesTimetableAdditional")
fun List<SdkTimetableAdditional>.mapToEntities(semester: Semester) = map {
TimetableAdditional(
studentId = semester.studentId,
diaryId = semester.diaryId,
subject = it.subject,
date = it.date,
start = it.start,
end = it.end
)
}

View file

@ -1,19 +1,14 @@
package io.github.wulkanowy.data.pojos package io.github.wulkanowy.data.pojos
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import io.github.wulkanowy.data.db.entities.GradePointsStatistics import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics import io.github.wulkanowy.data.db.entities.GradeStatistics
import io.github.wulkanowy.ui.modules.grade.statistics.ViewType import io.github.wulkanowy.ui.modules.grade.statistics.ViewType
data class GradeStatisticsItem( data class GradeStatisticsItem(
val type: ViewType, val type: ViewType,
val average: String, val partial: List<GradeStatistics>,
val partial: GradePartialStatistics?,
val semester: GradeSemesterStatistics?,
val points: GradePointsStatistics? val points: GradePointsStatistics?
) )

View file

@ -1,57 +0,0 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.AttendanceDao
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Absent
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.uniqueSubtract
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AttendanceRepository @Inject constructor(
private val attendanceDb: AttendanceDao,
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
private val cacheKey = "attendance"
fun getAttendance(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getAttendance(start.monday, end.sunday, semester.semesterId)
.mapToEntities(semester)
},
saveFetchResult = { old, new ->
attendanceDb.deleteAll(old uniqueSubtract new)
attendanceDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
},
filterResult = { it.filter { item -> item.date in start..end } }
)
suspend fun excuseForAbsence(student: Student, semester: Semester, absenceList: List<Attendance>, reason: String? = null) {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).excuseForAbsence(absenceList.map { attendance ->
Absent(
date = LocalDateTime.of(attendance.date, LocalTime.of(0, 0)),
timeId = attendance.timeId
)
}, reason)
}
}

View file

@ -1,39 +0,0 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AttendanceSummaryRepository @Inject constructor(
private val attendanceDb: AttendanceSummaryDao,
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
private val cacheKey = "attendance_summary"
fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getAttendanceSummary(subjectId)
.mapToEntities(semester, subjectId)
},
saveFetchResult = { old, new ->
attendanceDb.deleteAll(old uniqueSubtract new)
attendanceDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
}
)
}

View file

@ -1,43 +0,0 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.uniqueSubtract
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class CompletedLessonsRepository @Inject constructor(
private val completedLessonsDb: CompletedLessonsDao,
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
private val cacheKey = "completed"
fun getCompletedLessons(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
query = { completedLessonsDb.loadAll(semester.studentId, semester.diaryId, start.monday, end.sunday) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getCompletedLessons(start.monday, end.sunday)
.mapToEntities(semester)
},
saveFetchResult = { old, new ->
completedLessonsDb.deleteAll(old uniqueSubtract new)
completedLessonsDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
},
filterResult = { it.filter { item -> item.date in start..end } }
)
}

View file

@ -1,39 +0,0 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.ConferenceDao
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ConferenceRepository @Inject constructor(
private val conferenceDb: ConferenceDao,
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
private val cacheKey = "conference"
fun getConferences(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
query = { conferenceDb.loadAll(semester.diaryId, student.studentId) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getConferences()
.mapToEntities(semester)
},
saveFetchResult = { old, new ->
conferenceDb.deleteAll(old uniqueSubtract new)
conferenceDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
}
)
}

View file

@ -1,43 +0,0 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.ExamDao
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.endExamsDay
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.startExamsDay
import io.github.wulkanowy.utils.uniqueSubtract
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ExamRepository @Inject constructor(
private val examDb: ExamDao,
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
private val cacheKey = "exam"
fun getExams(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
query = { examDb.loadAll(semester.diaryId, semester.studentId, start.startExamsDay, start.endExamsDay) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getExams(start.startExamsDay, start.endExamsDay, semester.semesterId)
.mapToEntities(semester)
},
saveFetchResult = { old, new ->
examDb.deleteAll(old uniqueSubtract new)
examDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
},
filterResult = { it.filter { item -> item.date in start..end } }
)
}

View file

@ -1,144 +0,0 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.GradePartialStatisticsDao
import io.github.wulkanowy.data.db.dao.GradePointsStatisticsDao
import io.github.wulkanowy.data.db.dao.GradeSemesterStatisticsDao
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapPartialToStatisticItems
import io.github.wulkanowy.data.mappers.mapPointsToStatisticsItems
import io.github.wulkanowy.data.mappers.mapSemesterToStatisticItems
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract
import java.util.Locale
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class GradeStatisticsRepository @Inject constructor(
private val gradePartialStatisticsDb: GradePartialStatisticsDao,
private val gradePointsStatisticsDb: GradePointsStatisticsDao,
private val gradeSemesterStatisticsDb: GradeSemesterStatisticsDao,
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
private val partialCacheKey = "grade_stats_partial"
private val semesterCacheKey = "grade_stats_semester"
private val pointsCacheKey = "grade_stats_points"
fun getGradesPartialStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(partialCacheKey, semester)) },
query = { gradePartialStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getGradesPartialStatistics(semester.semesterId)
.mapToEntities(semester)
},
saveFetchResult = { old, new ->
gradePartialStatisticsDb.deleteAll(old uniqueSubtract new)
gradePartialStatisticsDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(partialCacheKey, semester))
},
mapResult = { items ->
when (subjectName) {
"Wszystkie" -> {
val numerator = items.map {
it.classAverage.replace(",", ".").toDoubleOrNull() ?: .0
}.filterNot { it == .0 }
(items.reversed() + GradePartialStatistics(
studentId = semester.studentId,
semesterId = semester.semesterId,
subject = subjectName,
classAverage = if (numerator.isEmpty()) "" else numerator.average().let {
"%.2f".format(Locale.FRANCE, it)
},
studentAverage = "",
classAmounts = items.map { it.classAmounts }.sumGradeAmounts(),
studentAmounts = items.map { it.studentAmounts }.sumGradeAmounts()
)).reversed()
}
else -> items.filter { it.subject == subjectName }
}.mapPartialToStatisticItems()
}
)
fun getGradesSemesterStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(semesterCacheKey, semester)) },
query = { gradeSemesterStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getGradesSemesterStatistics(semester.semesterId)
.mapToEntities(semester)
},
saveFetchResult = { old, new ->
gradeSemesterStatisticsDb.deleteAll(old uniqueSubtract new)
gradeSemesterStatisticsDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(semesterCacheKey, semester))
},
mapResult = { items ->
val itemsWithAverage = items.map { item ->
item.copy().apply {
val denominator = item.amounts.sum()
average = if (denominator == 0) "" else (item.amounts.mapIndexed { gradeValue, amount ->
(gradeValue + 1) * amount
}.sum().toDouble() / denominator).let {
"%.2f".format(Locale.FRANCE, it)
}
}
}
when (subjectName) {
"Wszystkie" -> (itemsWithAverage.reversed() + GradeSemesterStatistics(
studentId = semester.studentId,
semesterId = semester.semesterId,
subject = subjectName,
amounts = itemsWithAverage.map { it.amounts }.sumGradeAmounts(),
studentGrade = 0
).apply {
average = itemsWithAverage.mapNotNull { it.average.replace(",", ".").toDoubleOrNull() }.average().let {
"%.2f".format(Locale.FRANCE, it)
}
}).reversed()
else -> itemsWithAverage.filter { it.subject == subjectName }
}.mapSemesterToStatisticItems()
}
)
fun getGradesPointsStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(pointsCacheKey, semester)) },
query = { gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getGradesPointsStatistics(semester.semesterId)
.mapToEntities(semester)
},
saveFetchResult = { old, new ->
gradePointsStatisticsDb.deleteAll(old uniqueSubtract new)
gradePointsStatisticsDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(pointsCacheKey, semester))
},
mapResult = { items ->
when (subjectName) {
"Wszystkie" -> items
else -> items.filter { it.subject == subjectName }
}.mapPointsToStatisticsItems()
}
)
private fun List<List<Int>>.sumGradeAmounts(): List<Int> {
val result = mutableListOf(0, 0, 0, 0, 0, 0)
forEach {
it.forEachIndexed { grade, amount ->
result[grade] += amount
}
}
return result
}
}

View file

@ -1,50 +0,0 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.HomeworkDao
import io.github.wulkanowy.data.db.entities.Homework
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.uniqueSubtract
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class HomeworkRepository @Inject constructor(
private val homeworkDb: HomeworkDao,
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
private val cacheKey = "homework"
fun getHomework(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
query = { homeworkDb.loadAll(semester.semesterId, semester.studentId, start.monday, end.sunday) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getHomework(start.monday, end.sunday)
.mapToEntities(semester)
},
saveFetchResult = { old, new ->
homeworkDb.deleteAll(old uniqueSubtract new)
homeworkDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
}
)
suspend fun toggleDone(homework: Homework) {
homeworkDb.updateAll(listOf(homework.apply {
isDone = !isDone
}))
}
}

Some files were not shown because too many files have changed in this diff Show more