1
0
Fork 1

Compare commits

..

No commits in common. "1.1.2" and "0.23.1" have entirely different histories.

506 changed files with 6384 additions and 26154 deletions

View file

@ -1,202 +0,0 @@
name: Test and deploy
on:
push:
branches: [ develop ]
tags: [ '*' ]
pull_request:
branches: [ develop ]
workflow_dispatch:
jobs:
unit-tests:
name: Unit tests
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: Unit tests
run: |
./gradlew --build-cache -Pcoverage testFdroidDebugUnitTest --stacktrace
./gradlew --build-cache -Pcoverage jacocoTestReport --stacktrace
- uses: codecov/codecov-action@v1
with:
flags: unit
deploy-google-play:
name: Deploy to google play
runs-on: ubuntu-latest
timeout-minutes: 10
environment: google-play
needs: [ unit-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*') }}
- 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;
deploy-appcenter:
name: Deploy to App Center
runs-on: ubuntu-latest
timeout-minutes: 10
environment: app-center
if: github.ref != 'refs/heads/develop'
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*') }}
- name: Set run number with offset
env:
BUILD_NUMBER_OFFSET: ${{ secrets.BUILD_NUMBER_OFFSET }}
run: echo "RUN_NUMBER=$((GITHUB_RUN_NUMBER+BUILD_NUMBER_OFFSET))" >> $GITHUB_ENV
- name: Prepare build configuration
run: |
sed -i -e "s#applicationIdSuffix \".dev\"#applicationIdSuffix \".${GITHUB_HEAD_REF//[-.\/]/_}\"#" app/build.gradle
sed -i -e "s#.dev\"#.${GITHUB_HEAD_REF//[-.\/]/_}\"#" app/src/debug/google-services.json
sed -i -e "s#.dev\"#.${GITHUB_HEAD_REF//[-.\/]/_}\"#" app/src/debug/agconnect-services.json
sed -i -e '/versionNameSuffix/d' app/build.gradle
- name: Add signing config
run: |
cat >> app/build.gradle <<EOF
android.signingConfigs.debug {
storeFile file("bitrise.jks")
storePassword System.getenv("BITRISE_KEYSTORE_PASSWORD")
keyAlias System.getenv("BITRISE_KEY_ALIAS")
keyPassword System.getenv("BITRISE_KEY_PASSWORD")
}
EOF
- name: Decrypt keys
env:
BITRISE_ENCRYPT_KEY: ${{ secrets.BITRISE_ENCRYPT_KEY }}
run: |
gpg --yes --batch --passphrase=$BITRISE_ENCRYPT_KEY ./app/bitrise.jks.gpg
- name: Bump version
uses: chkfung/android-version-actions@v1.1
with:
gradlePath: app/build.gradle
versionCode: ${{ env.RUN_NUMBER }}
versionName: ${{ env.RUN_NUMBER }}-${{ github.head_ref }}
- name: Build apk
env:
BITRISE_KEYSTORE_PASSWORD: ${{ secrets.BITRISE_KEYSTORE_PASSWORD }}
BITRISE_KEY_ALIAS: ${{ secrets.BITRISE_KEY_ALIAS }}
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
run: ./gradlew assembleFdroidDebug --stacktrace
- name: Upload apk to github artifacts
uses: actions/upload-artifact@v2
with:
name: wulkanowyDEV-${{ env.RUN_NUMBER }}.apk
path: app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk
- name: Deploy to app center
uses: wzieba/AppCenter-Github-Action@v1
with:
appName: wulkanowy/wulkanowy
token: ${{ secrets.APP_CENTER_TOKEN }}
group: Testers
file: app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk
notifyTesters: true
debug: true
deploy-app-distribution:
name: Deploy to AppDistribution
runs-on: ubuntu-latest
timeout-minutes: 10
environment: app-distribution
if: github.ref == 'refs/heads/develop'
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*') }}
- name: Set run number with offset
env:
BUILD_NUMBER_OFFSET: ${{ secrets.BUILD_NUMBER_OFFSET }}
run: echo "RUN_NUMBER=$((GITHUB_RUN_NUMBER+BUILD_NUMBER_OFFSET))" >> $GITHUB_ENV
- name: Add signing config
run: |
cat >> app/build.gradle <<EOF
android.signingConfigs.debug {
storeFile file("bitrise.jks")
storePassword System.getenv("BITRISE_KEYSTORE_PASSWORD")
keyAlias System.getenv("BITRISE_KEY_ALIAS")
keyPassword System.getenv("BITRISE_KEY_PASSWORD")
}
EOF
- name: Decrypt keys
env:
BITRISE_ENCRYPT_KEY: ${{ secrets.BITRISE_ENCRYPT_KEY }}
BITRISE_SERVICES_ENCRYPT_KEY: ${{ secrets.BITRISE_SERVICES_ENCRYPT_KEY }}
run: |
gpg --yes --batch --passphrase=$BITRISE_SERVICES_ENCRYPT_KEY ./app/src/debug/google-services.json.gpg
gpg --yes --batch --passphrase=$BITRISE_ENCRYPT_KEY ./app/bitrise.jks.gpg
- name: Bump version
uses: chkfung/android-version-actions@v1.1
with:
gradlePath: app/build.gradle
versionCode: ${{ env.RUN_NUMBER }}
versionName: ${{ env.RUN_NUMBER }}
- name: Build apk
env:
BITRISE_KEYSTORE_PASSWORD: ${{ secrets.BITRISE_KEYSTORE_PASSWORD }}
BITRISE_KEY_ALIAS: ${{ secrets.BITRISE_KEY_ALIAS }}
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
run: ./gradlew assemblePlayDebug -PenableFirebase --stacktrace
- name: Upload apk to github artifacts
uses: actions/upload-artifact@v2
with:
name: wulkanowyDEV-${{ env.RUN_NUMBER }}-dev.apk
path: app/build/outputs/apk/play/debug/app-play-debug.apk
- name: Deploy to app distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{ secrets.FIREBASE_APP_ID }}
token: ${{ secrets.FIREBASE_TOKEN }}
groups: discord
file: app/build/outputs/apk/play/debug/app-play-debug.apk

1
.gitignore vendored
View file

@ -19,7 +19,6 @@ out/
# Gradle files
.gradle/
build/
.build-cache
# Local configuration file (sdk path, etc)
local.properties

View file

@ -18,9 +18,18 @@
</option>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" 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="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<MarkdownNavigatorCodeStyleSettings>
<option name="RIGHT_MARGIN" value="72" />
</MarkdownNavigatorCodeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
@ -134,11 +143,13 @@
</arrangement>
</codeStyleSettings>
<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_CODE" value="1" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
<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>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>

View file

@ -14,7 +14,7 @@ cache:
branches:
only:
- develop
- 0.24.0
- 0.23.1
android:
licenses:

View file

@ -1,8 +1,7 @@
[Polska wersja README](README.md)
# 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)
[![Travis](https://img.shields.io/travis/com/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://travis-ci.com/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)
[![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/)
@ -12,7 +11,7 @@ Unofficial android VULCAN UONET+ register client for both students and their par
## Features
* logging in using the email and password
* logging in using the email and password OR using token and pin
* functions from the register website:
* grades
* grade statistics
@ -25,19 +24,15 @@ Unofficial android VULCAN UONET+ register client for both students and their par
* homework
* notes
* lucky number
* additional lessons
* school conferences
* student and school information
* calculation of the average independently of school's preferences
* notifications, e.g. about a new grade
* support for multiple accounts with the ability to rename students
* dark and black (AMOLED) theme
* offline mode
* no ads
## Download
You can download the current version from the Google Play, F-Droid or Huawei AppGallery store
You can download the current beta version from the Google Play, F-Droid or Huawei AppGallery store
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
alt="Get it on Google Play"
@ -55,8 +50,7 @@ You can also download a [development version](https://wulkanowy.github.io/#downl
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
* [Kotlin Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html)
* [Hilt](https://dagger.dev/hilt/)
* [Dagger 2](https://github.com/google/dagger)
* [Room](https://developer.android.com/topic/libraries/architecture/room)
* [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager)
@ -64,9 +58,6 @@ You can also download a [development version](https://wulkanowy.github.io/#downl
Please contribute to the project either by creating a PR or submitting an issue on GitHub.
For people interested in translating the application into different languages, we provide Crowdin
https://crowdin.com/project/wulkanowy2
## License
This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details

View file

@ -1,8 +1,7 @@
[English version of README](README.en.md)
# 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)
[![Travis](https://img.shields.io/travis/com/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://travis-ci.com/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)
[![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/)
@ -12,7 +11,7 @@ Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
## Funkcje
* logowanie za pomocą e-maila i hasła
* logowanie za pomocą e-maila i hasła LUB tokena i pinu
* funkcje ze strony internetowej dziennika:
* oceny
* statystyki ocen
@ -25,19 +24,15 @@ Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
* zadania domowe
* uwagi
* szczęśliwy numerek
* dodatkowe lekcje
* zebrania w szkole
* informacje o uczniu i szkole
* obliczanie średniej niezależnie od preferencji szkoły
* powiadomienia np. o nowej ocenie
* obsługa wielu kont wraz z możliwością zmiany nazwy ucznia
* ciemny i czarny (AMOLED) motyw
* tryb offilne
* brak reklam
## Pobierz
Aktualną wersję możesz pobrać ze sklepu Google Play, F-Droid lub Huawei AppGallery
Aktualną wersję beta możesz pobrać ze sklepu Google Play, F-Droid lub Huawei AppGallery
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
alt="Pobierz z Google Play"
@ -55,9 +50,8 @@ Możesz także pobrać [wersję rozwojową](https://wulkanowy.github.io/#downloa
## Zbudowana za pomocą
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
* [Kotlin Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html)
* [Hilt](https://dagger.dev/hilt/)
* [Wulkanowy SDK](https://github.com/wulkanowy/SDK)
* [Dagger 2](https://github.com/google/dagger)
* [Room](https://developer.android.com/topic/libraries/architecture/room)
* [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager)
@ -65,9 +59,6 @@ Możesz także pobrać [wersję rozwojową](https://wulkanowy.github.io/#downloa
Wnieś swój wkład w projekt, tworząc PR lub wysyłając issue na GitHub.
Dla osób zainteresowanych tłumaczeniem aplikacji na różne języki udostępniamy Crowdina
https://crowdin.com/project/wulkanowy2
## Licencja
Ten projekt udostępniany jest na licencji Apache License 2.0 - szczegóły w pliku [LICENSE](LICENSE)

Binary file not shown.

Binary file not shown.

View file

@ -5,30 +5,25 @@ apply plugin: 'dagger.hilt.android.plugin'
apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'com.github.triplet.play'
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.huawei.agconnect'
apply from: 'jacoco.gradle'
apply from: 'sonarqube.gradle'
apply from: 'hooks.gradle'
android {
compileSdkVersion 30
buildToolsVersion '30.0.3'
buildToolsVersion '30.0.2'
defaultConfig {
applicationId "io.github.wulkanowy"
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 17
targetSdkVersion 30
versionCode 88
versionName "1.1.2"
versionCode 77
versionName "0.23.1"
multiDexEnabled true
resValue "string", "app_name", "Wulkanowy"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
resValue "string", "app_name", "Wulkanowy"
buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis())
manifestPlaceholders = [
firebase_enabled: project.hasProperty("enableFirebase")
]
@ -43,8 +38,7 @@ android {
}
sourceSets {
// https://github.com/robolectric/robolectric/issues/3928#issuecomment-395309991
debug.assets.srcDirs += files("$projectDir/schemas".toString())
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
}
signingConfigs {
@ -106,10 +100,6 @@ android {
disable 'HardwareIds'
}
testOptions.unitTests {
includeAndroidResources = true
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
@ -117,7 +107,6 @@ android {
}
kotlinOptions {
useIR = true
jvmTarget = "1.8"
freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn", "-Xjvm-default=all"]
}
@ -136,32 +125,35 @@ play {
serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") ?: "jan@fakelog.cf"
serviceAccountCredentials = file('key.p12')
defaultToAppBundles = false
track = 'production'
updatePriority = 5
track = 'alpha'
updatePriority = 3
}
ext {
work_manager = "2.5.0"
work_hilt = "1.0.0-beta01"
room = "2.3.0-beta03"
work_manager = "2.4.0"
room = "2.2.5"
chucker = "3.4.0"
mockk = "1.10.6"
mockk = "1.10.3-jdk8"
moshi = "1.11.0"
}
dependencies {
implementation "io.github.wulkanowy:sdk:1.1.2"
configurations.all {
resolutionStrategy.force "androidx.constraintlayout:constraintlayout:1.1.3"
}
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
dependencies {
implementation "io.github.wulkanowy:sdk:0.23.1"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2'
implementation "androidx.core:core-ktx:1.3.2"
implementation "androidx.activity:activity-ktx:1.2.1"
implementation "androidx.activity:activity-ktx:1.1.0"
implementation "androidx.appcompat:appcompat:1.2.0"
implementation "androidx.appcompat:appcompat-resources:1.2.0"
implementation "androidx.fragment:fragment-ktx:1.3.1"
implementation "androidx.fragment:fragment-ktx:1.2.5"
implementation "androidx.annotation:annotation:1.1.0"
implementation "androidx.multidex:multidex:2.0.1"
@ -169,17 +161,17 @@ dependencies {
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation "androidx.viewpager:viewpager:1.0.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 "com.google.android.material:material:1.3.0"
implementation "com.github.wulkanowy:material-chips-input:2.2.0"
implementation "com.google.android.material:material:1.2.1"
implementation "com.github.wulkanowy:material-chips-input:2.1.1"
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
implementation 'com.mikhaellopez:circularimageview:4.2.0'
implementation "me.zhanghai.android.materialprogressbar:library:1.6.1"
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.3.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
implementation "androidx.room:room-runtime:$room"
implementation "androidx.room:room-ktx:$room"
@ -187,12 +179,12 @@ dependencies {
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
implementation "androidx.hilt:hilt-work:$work_hilt"
kapt "androidx.hilt:hilt-compiler:$work_hilt"
implementation 'androidx.hilt:hilt-work:1.0.0-alpha02'
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha02'
implementation "com.aurelhubert:ahbottomnavigation:2.3.4"
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-adapters:$moshi"
@ -202,43 +194,37 @@ dependencies {
implementation "fr.bipi.treessence:treessence:0.3.2"
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
implementation "io.coil-kt:coil:1.1.1"
implementation "io.coil-kt:coil:1.1.0"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
playImplementation platform('com.google.firebase:firebase-bom:26.7.0')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx'
playImplementation "com.google.firebase:firebase-inappmessaging-ktx"
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
playImplementation 'com.google.firebase:firebase-analytics:18.0.0'
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.1.2'
playImplementation "com.google.firebase:firebase-inappmessaging-ktx:19.1.2"
playImplementation 'com.google.firebase:firebase-messaging:21.0.0'
playImplementation 'com.google.firebase:firebase-crashlytics:17.3.0'
playImplementation 'com.google.android.play:core-ktx:1.8.1'
playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
hmsImplementation 'com.huawei.hms:hianalytics:5.2.0.300'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.5.0.300'
hmsImplementation 'com.huawei.hms:hianalytics:5.0.5.301'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.4.2.301'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker"
debugImplementation "com.amitshekhar.android:debug-db:1.0.6"
testImplementation "junit:junit:4.13.2"
testImplementation "junit:junit:4.13.1"
testImplementation "io.mockk:mockk:$mockk"
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2'
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
testImplementation 'org.robolectric:robolectric:4.5.1'
testImplementation "androidx.test:runner:1.3.0"
testImplementation "androidx.test.ext:junit:1.1.2"
testImplementation "androidx.test:core:1.3.0"
testImplementation "androidx.room:room-testing:$room"
testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
kaptTest "com.google.dagger:hilt-android-compiler:$hilt_version"
androidTestImplementation "androidx.test:core:1.3.0"
androidTestImplementation "androidx.test:runner:1.3.0"
androidTestImplementation "androidx.test.ext:junit:1.1.2"
androidTestImplementation "io.mockk:mockk-android:$mockk"
androidTestImplementation "androidx.room:room-testing:$room"
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
}
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.huawei.agconnect'

View file

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

View file

@ -1,21 +1,33 @@
# General
# Optimizations
-optimizationpasses 5
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-dontobfuscate
-allowaccessmodification
-repackageclasses ''
-verbose
#Config for wulkanowy
#Keep all wulkanowy files
-keep class io.github.wulkanowy.** {*;}
#Config for firebase crashlitycs
#Config for anallitycs
-keepattributes *Annotation*
-keepattributes SourceFile,LineNumberTable
-keep class com.crashlytics.** {*;}
-keep public class * extends java.lang.Exception
-dontwarn com.crashlytics.**
#Config for Okio and OkHttp
-dontwarn javax.annotation.**
#Config for OkHttp
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
-dontwarn org.codehaus.mojo.animal_sniffer.*
-dontwarn okhttp3.internal.platform.ConscryptPlatform
-dontwarn javax.annotation.**
#Config for MPAndroidChart
@ -24,3 +36,10 @@
#Config for Material Components
-keep class com.google.android.material.tabs.** { *; }
#Config for About Libraries
-keep class .R
-keep class **.R$* {
<fields>;
}

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

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
import android.content.Context
import androidx.preference.PreferenceManager
import androidx.room.Room
import androidx.room.testing.MigrationTestHelper
@ -9,7 +8,6 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.platform.app.InstrumentationRegistry
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.utils.AppInfo
import org.junit.Rule
abstract class AbstractMigrationTest {
@ -24,17 +22,12 @@ abstract class AbstractMigrationTest {
)
fun getMigratedRoomDatabase(): AppDatabase {
val context = ApplicationProvider.getApplicationContext<Context>()
val database = Room.databaseBuilder(
ApplicationProvider.getApplicationContext(),
AppDatabase::class.java,
dbName
).addMigrations(
*AppDatabase.getMigrations(
SharedPrefProvider(PreferenceManager.getDefaultSharedPreferences(context)),
AppInfo()
val database = Room.databaseBuilder(ApplicationProvider.getApplicationContext(),
AppDatabase::class.java, dbName)
.addMigrations(*AppDatabase.getMigrations(SharedPrefProvider(PreferenceManager
.getDefaultSharedPreferences(ApplicationProvider.getApplicationContext())))
)
).build()
.build()
// close the database and release any stream resources when the test finishes
helper.closeWhenFinished(database)
return database

View file

@ -2,20 +2,14 @@ package io.github.wulkanowy.data.db.migrations
import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase.CONFLICT_FAIL
import android.os.Build
import androidx.sqlite.db.SupportSQLiteDatabase
import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.HiltTestApplication
import androidx.test.ext.junit.runners.AndroidJUnit4
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import kotlin.test.assertEquals
@HiltAndroidTest
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [Build.VERSION_CODES.O_MR1], application = HiltTestApplication::class)
@RunWith(AndroidJUnit4::class)
class Migration12Test : AbstractMigrationTest() {
@Test

View file

@ -2,26 +2,17 @@ package io.github.wulkanowy.data.db.migrations
import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase
import android.os.Build
import androidx.sqlite.db.SupportSQLiteDatabase
import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.HiltTestApplication
import io.github.wulkanowy.data.db.Converters
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import java.time.LocalDate.of
import kotlin.test.assertFalse
import kotlin.test.assertTrue
@HiltAndroidTest
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [Build.VERSION_CODES.O_MR1], application = HiltTestApplication::class)
class Migration13Test : AbstractMigrationTest() {
@Test

View file

@ -2,21 +2,12 @@ package io.github.wulkanowy.data.db.migrations
import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase
import android.os.Build
import androidx.sqlite.db.SupportSQLiteDatabase
import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.HiltTestApplication
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import kotlin.random.Random
@HiltAndroidTest
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [Build.VERSION_CODES.O_MR1], application = HiltTestApplication::class)
class Migration27Test : AbstractMigrationTest() {
@Test

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,110 @@
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.GradePartialStatistics
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
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.gradePartialStatisticsDao, testDb.gradePointsStatisticsDao, testDb.gradeSemesterStatisticsDao)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun saveAndRead_subject() {
val list = listOf(
getGradeStatistics("Matematyka", 2, 1),
getGradeStatistics("Fizyka", 1, 2)
)
runBlocking { gradeStatisticsLocal.saveGradePartialStatistics(list) }
val stats = runBlocking { gradeStatisticsLocal.getGradePartialStatistics(getSemester()).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.saveGradePartialStatistics(list) }
val stats = runBlocking { gradeStatisticsLocal.getGradePartialStatistics(getSemester()).first() }
assertEquals(2, stats.size)
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.saveGradePointsStatistics(list) }
val stats = runBlocking { gradeStatisticsLocal.getGradePointsStatistics(getSemester()).first() }
with(stats[0]) {
assertEquals(subject, "Matematyka")
assertEquals(others, 5.0)
assertEquals(student, 5.0)
}
}
@Test
fun saveAndRead_subjectEmpty() {
runBlocking { gradeStatisticsLocal.saveGradePointsStatistics(listOf()) }
val stats = runBlocking { gradeStatisticsLocal.getGradePointsStatistics(getSemester()).first() }
assertEquals(emptyList(), stats)
}
@Test
fun saveAndRead_allEmpty() {
runBlocking { gradeStatisticsLocal.saveGradePointsStatistics(listOf()) }
val stats = runBlocking { gradeStatisticsLocal.getGradePointsStatistics(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): GradePartialStatistics {
return GradePartialStatistics(studentId, semesterId, subject, "", "", listOf(5), listOf(5))
}
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,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

@ -9,29 +9,6 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<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
android:name=".WulkanowyApp"
android:allowBackup="false"
@ -56,7 +33,7 @@
android:name=".ui.modules.login.LoginActivity"
android:configChanges="orientation|screenSize"
android:label="@string/login_title"
android:theme="@style/WulkanowyTheme.Login"
android:theme="@style/WulkanowyTheme.NoActionBar"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".ui.modules.main.MainActivity"
@ -68,7 +45,7 @@
android:name=".ui.modules.message.send.SendMessageActivity"
android:configChanges="orientation|screenSize"
android:label="@string/send_message_title"
android:theme="@style/WulkanowyTheme.MessageSend"
android:theme="@style/WulkanowyTheme.NoActionBar"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".ui.modules.timetablewidget.TimetableWidgetConfigureActivity"
@ -135,7 +112,8 @@
<meta-data
android:name="install_channel"
android:value="${install_channel}" />
android:value="${install_channel}">
</meta-data>
<!-- 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 -->

View file

@ -34,17 +34,5 @@
{
"displayName": "Mateusz Idziejczak",
"githubUsername": "Luncenok"
},
{
"displayName": "MRmlik12",
"githubUsername": "MRmlik12"
},
{
"displayName": "Damian Czupryn",
"githubUsername": "Daxxxis"
},
{
"displayName": "Kamil Studziński",
"githubUsername": "studzinskik"
}
]

View file

@ -1,23 +1,18 @@
package io.github.wulkanowy
import android.annotation.SuppressLint
import android.app.Application
import android.content.Context
import android.util.Log.DEBUG
import android.util.Log.INFO
import android.util.Log.VERBOSE
import android.webkit.WebView
import androidx.fragment.app.FragmentManager
import androidx.hilt.work.HiltWorkerFactory
import androidx.multidex.MultiDex
import androidx.work.Configuration
import com.yariksoffice.lingver.Lingver
import dagger.hilt.android.HiltAndroidApp
import fr.bipi.tressence.file.FileLoggerTree
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.ui.base.ThemeManager
import io.github.wulkanowy.utils.ActivityLifecycleLogger
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.CrashLogExceptionTree
import io.github.wulkanowy.utils.CrashLogTree
@ -37,37 +32,28 @@ class WulkanowyApp : Application(), Configuration.Provider {
@Inject
lateinit var appInfo: AppInfo
@Inject
lateinit var preferencesRepository: PreferencesRepository
@Inject
lateinit var analyticsHelper: AnalyticsHelper
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
MultiDex.install(this)
}
@SuppressLint("UnsafeOptInUsageWarning")
override fun onCreate() {
super.onCreate()
FragmentManager.enableNewStateManager(false)
initializeAppLanguage()
Lingver.init(this)
themeManager.applyDefaultTheme()
initLogging()
fixWebViewLocale()
}
private fun initLogging() {
if (appInfo.isDebug) {
Timber.plant(DebugLogTree())
Timber.plant(
FileLoggerTree.Builder()
.withFileName("wulkanowy.%g.log")
.withDirName(applicationContext.filesDir.absolutePath)
.withFileLimit(10)
.withMinPriority(DEBUG)
.build()
Timber.plant(FileLoggerTree.Builder()
.withFileName("wulkanowy.%g.log")
.withDirName(applicationContext.filesDir.absolutePath)
.withFileLimit(10)
.withMinPriority(DEBUG)
.build()
)
} else {
Timber.plant(CrashLogExceptionTree())
@ -76,26 +62,6 @@ class WulkanowyApp : Application(), Configuration.Provider {
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
try {
WebView(this).destroy()
} catch (e: Exception) {
//Ignore exceptions
}
}
override fun getWorkManagerConfiguration() = Configuration.Builder()
.setWorkerFactory(workerFactory)
.setMinimumLoggingLevel(if (appInfo.isDebug) VERBOSE else INFO)

View file

@ -15,9 +15,8 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import io.github.wulkanowy.data.db.AppDatabase
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.utils.AppInfo
import timber.log.Timber
import javax.inject.Singleton
@ -34,21 +33,17 @@ internal class RepositoryModule {
setSimpleHttpLogger { Timber.d(it) }
// for debug only
addInterceptor(
ChuckerInterceptor.Builder(context)
.collector(chuckerCollector)
.alwaysReadResponseBody(true)
.build(), network = true
)
addInterceptor(ChuckerInterceptor(
context = context,
collector = chuckerCollector,
alwaysReadResponseBody = true
), true)
}
}
@Singleton
@Provides
fun provideChuckerCollector(
@ApplicationContext context: Context,
prefRepository: PreferencesRepository
): ChuckerCollector {
fun provideChuckerCollector(@ApplicationContext context: Context, prefRepository: PreferencesRepository): ChuckerCollector {
return ChuckerCollector(
context = context,
showNotification = prefRepository.isDebugNotificationEnable,
@ -58,11 +53,7 @@ internal class RepositoryModule {
@Singleton
@Provides
fun provideDatabase(
@ApplicationContext context: Context,
sharedPrefProvider: SharedPrefProvider,
appInfo: AppInfo
) = AppDatabase.newInstance(context, sharedPrefProvider, appInfo)
fun provideDatabase(@ApplicationContext context: Context, sharedPrefProvider: SharedPrefProvider) = AppDatabase.newInstance(context, sharedPrefProvider)
@Singleton
@Provides
@ -74,8 +65,7 @@ internal class RepositoryModule {
@Singleton
@Provides
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences =
PreferenceManager.getDefaultSharedPreferences(context)
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
@Singleton
@Provides
@ -99,8 +89,7 @@ internal class RepositoryModule {
@Singleton
@Provides
fun provideGradeSemesterStatisticsDao(database: AppDatabase) =
database.gradeSemesterStatisticsDao
fun provideGradeSemesterStatisticsDao(database: AppDatabase) = database.gradeSemesterStatisticsDao
@Singleton
@Provides
@ -173,12 +162,4 @@ internal class RepositoryModule {
@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

@ -6,6 +6,7 @@ import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.RoomDatabase.JournalMode.TRUNCATE
import androidx.room.TypeConverters
import androidx.room.migration.Migration
import io.github.wulkanowy.data.db.dao.AttendanceDao
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
@ -27,10 +28,8 @@ import io.github.wulkanowy.data.db.dao.ReportingUnitDao
import io.github.wulkanowy.data.db.dao.SchoolDao
import io.github.wulkanowy.data.db.dao.SemesterDao
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.TeacherDao
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
import io.github.wulkanowy.data.db.dao.TimetableDao
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.AttendanceSummary
@ -53,11 +52,9 @@ import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.School
import io.github.wulkanowy.data.db.entities.Semester
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.Teacher
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.Migration11
import io.github.wulkanowy.data.db.migrations.Migration12
@ -80,19 +77,12 @@ 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.Migration30
import io.github.wulkanowy.data.db.migrations.Migration31
import io.github.wulkanowy.data.db.migrations.Migration32
import io.github.wulkanowy.data.db.migrations.Migration33
import io.github.wulkanowy.data.db.migrations.Migration34
import io.github.wulkanowy.data.db.migrations.Migration35
import io.github.wulkanowy.data.db.migrations.Migration4
import io.github.wulkanowy.data.db.migrations.Migration5
import io.github.wulkanowy.data.db.migrations.Migration6
import io.github.wulkanowy.data.db.migrations.Migration7
import io.github.wulkanowy.data.db.migrations.Migration8
import io.github.wulkanowy.data.db.migrations.Migration9
import io.github.wulkanowy.utils.AppInfo
import javax.inject.Singleton
@Singleton
@ -122,8 +112,6 @@ import javax.inject.Singleton
Teacher::class,
School::class,
Conference::class,
TimetableAdditional::class,
StudentInfo::class,
],
version = AppDatabase.VERSION_SCHEMA,
exportSchema = true
@ -132,55 +120,49 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() {
companion object {
const val VERSION_SCHEMA = 35
const val VERSION_SCHEMA = 29
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
Migration2(),
Migration3(),
Migration4(),
Migration5(),
Migration6(),
Migration7(),
Migration8(),
Migration9(),
Migration10(),
Migration11(),
Migration12(),
Migration13(),
Migration14(),
Migration15(),
Migration16(),
Migration17(),
Migration18(),
Migration19(sharedPrefProvider),
Migration20(),
Migration21(),
Migration22(),
Migration23(),
Migration24(),
Migration25(),
Migration26(),
Migration27(),
Migration28(),
Migration29(),
Migration30(),
Migration31(),
Migration32(),
Migration33(),
Migration34(),
Migration35(appInfo)
)
fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> {
return arrayOf(
Migration2(),
Migration3(),
Migration4(),
Migration5(),
Migration6(),
Migration7(),
Migration8(),
Migration9(),
Migration10(),
Migration11(),
Migration12(),
Migration13(),
Migration14(),
Migration15(),
Migration16(),
Migration17(),
Migration18(),
Migration19(sharedPrefProvider),
Migration20(),
Migration21(),
Migration22(),
Migration23(),
Migration24(),
Migration25(),
Migration26(),
Migration27(),
Migration28(),
Migration29()
)
}
fun newInstance(
context: Context,
sharedPrefProvider: SharedPrefProvider,
appInfo: AppInfo
) = Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
.setJournalMode(TRUNCATE)
.fallbackToDestructiveMigrationFrom(VERSION_SCHEMA + 1)
.fallbackToDestructiveMigrationOnDowngrade()
.addMigrations(*getMigrations(sharedPrefProvider, appInfo))
.build()
fun newInstance(context: Context, sharedPrefProvider: SharedPrefProvider): AppDatabase {
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
.setJournalMode(TRUNCATE)
.fallbackToDestructiveMigrationFrom(VERSION_SCHEMA + 1)
.fallbackToDestructiveMigrationOnDowngrade()
.addMigrations(*getMigrations(sharedPrefProvider))
.build()
}
}
abstract val studentDao: StudentDao
@ -230,8 +212,4 @@ abstract class AppDatabase : RoomDatabase() {
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
@Singleton
class SharedPrefProvider @Inject constructor(
private val sharedPref: SharedPreferences
) {
class SharedPrefProvider @Inject constructor(private val sharedPref: SharedPreferences) {
companion object {
const val APP_VERSION_CODE_KEY = "app_version_code"

View file

@ -12,5 +12,5 @@ import javax.inject.Singleton
interface CompletedLessonsDao : BaseDao<CompletedLesson> {
@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

@ -13,7 +13,4 @@ interface LuckyNumberDao : BaseDao<LuckyNumber> {
@Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date = :date")
fun load(studentId: Int, date: LocalDate): Flow<LuckyNumber?>
@Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date >= :start AND date <= :end")
fun getAll(studentId: Int, start: LocalDate, end: LocalDate): Flow<List<LuckyNumber>>
}

View file

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

View file

@ -9,6 +9,6 @@ import javax.inject.Singleton
@Dao
interface RecipientDao : BaseDao<Recipient> {
@Query("SELECT * FROM Recipients WHERE student_id = :userLoginId AND unit_id = :unitId AND role = :role")
suspend fun loadAll(userLoginId: Int, unitId: Int, role: Int): List<Recipient>
@Query("SELECT * FROM Recipients WHERE student_id = :studentId AND role = :role AND unit_id = :unitId")
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.Query
import androidx.room.Transaction
import androidx.room.Update
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import javax.inject.Singleton
@ -22,14 +20,11 @@ interface StudentDao {
@Delete
suspend fun delete(student: Student)
@Update(entity = Student::class)
suspend fun update(studentNickAndAvatar: StudentNickAndAvatar)
@Query("SELECT * FROM Students WHERE is_current = 1")
suspend fun loadCurrent(): Student?
@Query("SELECT * FROM Students WHERE id = :id")
suspend fun loadById(id: Long): Student?
suspend fun loadById(id: Int): Student?
@Query("SELECT * FROM Students")
suspend fun loadAll(): List<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

@ -10,7 +10,7 @@ import java.time.LocalDateTime
data class Message(
@ColumnInfo(name = "student_id")
val studentId: Long,
val studentId: Int,
@ColumnInfo(name = "real_id")
val realId: Int,

View file

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

View file

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

View file

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

View file

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

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,20 +0,0 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
@Entity
data class StudentNickAndAvatar(
val nick: String,
@ColumnInfo(name = "avatar_color")
var avatarColor: Long
) : 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,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,45 +0,0 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration33 : Migration(32, 33) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS StudentInfo")
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,
first_guardian_kinship TEXT,
first_guardian_address TEXT,
first_guardian_phones TEXT,
first_guardian_email TEXT,
second_guardian_full_name TEXT,
second_guardian_kinship TEXT,
second_guardian_address TEXT,
second_guardian_phones TEXT,
second_guardian_email TEXT)
"""
)
}
}

View file

@ -1,13 +0,0 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration34 : Migration(33, 34) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DELETE FROM ReportingUnits")
database.execSQL("DELETE FROM Recipients")
}
}

View file

@ -1,24 +0,0 @@
package io.github.wulkanowy.data.db.migrations
import androidx.core.database.getLongOrNull
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import io.github.wulkanowy.utils.AppInfo
class Migration35(private val appInfo: AppInfo) : Migration(34, 35) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN `avatar_color` INTEGER NOT NULL DEFAULT 0")
val studentsCursor = database.query("SELECT * FROM Students")
while (studentsCursor.moveToNext()) {
val studentId = studentsCursor.getLongOrNull(0)
database.execSQL(
"""UPDATE Students
SET avatar_color = ${appInfo.defaultColorsForAvatar.random()}
WHERE id = $studentId"""
)
}
}
}

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,79 +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.sdk.pojo.GradePointsStatistics as SdkGradePointsStatistics
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSemester as SdkGradeStatisticsSemester
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSubject as SdkGradeStatisticsSubject
@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 = GradeStatisticsItem.DataType.PARTIAL,
average = it.classAverage,
partial = it,
points = null,
semester = null
)
}
fun List<GradeSemesterStatistics>.mapSemesterToStatisticItems() = filterNot { it.amounts.isEmpty() }.map {
GradeStatisticsItem(
type = GradeStatisticsItem.DataType.SEMESTER,
partial = null,
points = null,
average = "",
semester = it
)
}
fun List<GradePointsStatistics>.mapPointsToStatisticsItems() = map {
GradeStatisticsItem(
type = GradeStatisticsItem.DataType.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 java.time.LocalDateTime
import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
fun List<SdkMessage>.mapToEntities(student: Student) = map {
Message(
studentId = student.id,
realId = it.id ?: 0,
messageId = it.messageId ?: 0,
sender = it.sender?.name.orEmpty(),
senderId = it.sender?.loginId ?: 0,
recipient = it.recipients.singleOrNull()?.name ?: "Wielu adresatów",
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 = guardianFirst?.mapToEntity(),
secondGuardian = guardianSecond?.mapToEntity()
)
fun SdkStudentGuardian.mapToEntity() = StudentGuardian(
fullName = fullName,
kinship = kinship,
address = address,
phones = phones,
email = email
)

View file

@ -5,7 +5,7 @@ import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import java.time.LocalDateTime
import io.github.wulkanowy.sdk.pojo.Student as SdkStudent
fun List<SdkStudent>.mapToEntities(password: String = "", colors: List<Long>) = map {
fun List<SdkStudent>.mapToEntities(password: String = "") = map {
StudentWithSemesters(
student = Student(
email = it.email,
@ -28,10 +28,8 @@ fun List<SdkStudent>.mapToEntities(password: String = "", colors: List<Long>) =
mobileBaseUrl = it.mobileBaseUrl,
privateKey = it.privateKey,
certificateKey = it.certificateKey,
loginMode = it.loginMode.name,
).apply {
avatarColor = colors.random()
},
loginMode = it.loginMode.name
),
semesters = it.semesters.mapToEntities(it.studentId)
)
}

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

@ -3,10 +3,11 @@ 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.GradeSemesterStatistics
import io.github.wulkanowy.ui.modules.grade.statistics.ViewType
data class GradeStatisticsItem(
val type: DataType,
val type: ViewType,
val average: String,
@ -15,11 +16,4 @@ data class GradeStatisticsItem(
val semester: GradeSemesterStatistics?,
val points: GradePointsStatistics?
) {
enum class DataType {
SEMESTER,
PARTIAL,
POINTS,
}
}
)

View file

@ -1,61 +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 kotlinx.coroutines.sync.Mutex
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 saveFetchResultMutex = Mutex()
private val cacheKey = "attendance"
fun getAttendance(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
mutex = saveFetchResultMutex,
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,43 +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 kotlinx.coroutines.sync.Mutex
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 saveFetchResultMutex = Mutex()
private val cacheKey = "attendance_summary"
fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int, forceRefresh: Boolean) = networkBoundResource(
mutex = saveFetchResultMutex,
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,47 +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 kotlinx.coroutines.sync.Mutex
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 saveFetchResultMutex = Mutex()
private val cacheKey = "completed"
fun getCompletedLessons(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
mutex = saveFetchResultMutex,
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,43 +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 kotlinx.coroutines.sync.Mutex
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 saveFetchResultMutex = Mutex()
private val cacheKey = "conference"
fun getConferences(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
mutex = saveFetchResultMutex,
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,47 +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 kotlinx.coroutines.sync.Mutex
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 saveFetchResultMutex = Mutex()
private val cacheKey = "exam"
fun getExams(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
mutex = saveFetchResultMutex,
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,136 +0,0 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.GradeDao
import io.github.wulkanowy.data.db.dao.GradeSummaryDao
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.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 kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.sync.Mutex
import java.time.LocalDateTime
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class GradeRepository @Inject constructor(
private val gradeDb: GradeDao,
private val gradeSummaryDb: GradeSummaryDao,
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "grade"
fun getGrades(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = { (details, summaries) ->
val isShouldBeRefreshed = refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester))
details.isEmpty() || summaries.isEmpty() || forceRefresh || isShouldBeRefreshed
},
query = {
val detailsFlow = gradeDb.loadAll(semester.semesterId, semester.studentId)
val summaryFlow = gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)
detailsFlow.combine(summaryFlow) { details, summaries -> details to summaries }
},
fetch = {
val (details, summary) = sdk.init(student)
.switchDiary(semester.diaryId, semester.schoolYear)
.getGrades(semester.semesterId)
details.mapToEntities(semester) to summary.mapToEntities(semester)
},
saveFetchResult = { (oldDetails, oldSummary), (newDetails, newSummary) ->
refreshGradeDetails(student, oldDetails, newDetails, notify)
refreshGradeSummaries(oldSummary, newSummary, notify)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
}
)
private suspend fun refreshGradeDetails(student: Student, oldGrades: List<Grade>, newDetails: List<Grade>, notify: Boolean) {
val notifyBreakDate = oldGrades.maxByOrNull { it.date }?.date ?: student.registrationDate.toLocalDate()
gradeDb.deleteAll(oldGrades uniqueSubtract newDetails)
gradeDb.insertAll((newDetails uniqueSubtract oldGrades).onEach {
if (it.date >= notifyBreakDate) it.apply {
isRead = false
if (notify) isNotified = false
}
})
}
private suspend fun refreshGradeSummaries(oldSummaries: List<GradeSummary>, newSummary: List<GradeSummary>, notify: Boolean) {
gradeSummaryDb.deleteAll(oldSummaries uniqueSubtract newSummary)
gradeSummaryDb.insertAll((newSummary uniqueSubtract oldSummaries).onEach { summary ->
val oldSummary = oldSummaries.find { oldSummary -> oldSummary.subject == summary.subject }
summary.isPredictedGradeNotified = when {
summary.predictedGrade.isEmpty() -> true
notify && oldSummary?.predictedGrade != summary.predictedGrade -> false
else -> true
}
summary.isFinalGradeNotified = when {
summary.finalGrade.isEmpty() -> true
notify && oldSummary?.finalGrade != summary.finalGrade -> false
else -> true
}
summary.predictedGradeLastChange = when {
oldSummary == null -> LocalDateTime.now()
summary.predictedGrade != oldSummary.predictedGrade -> LocalDateTime.now()
else -> oldSummary.predictedGradeLastChange
}
summary.finalGradeLastChange = when {
oldSummary == null -> LocalDateTime.now()
summary.finalGrade != oldSummary.finalGrade -> LocalDateTime.now()
else -> oldSummary.finalGradeLastChange
}
})
}
fun getUnreadGrades(semester: Semester): Flow<List<Grade>> {
return gradeDb.loadAll(semester.semesterId, semester.studentId).map {
it.filter { grade -> !grade.isRead }
}
}
fun getNotNotifiedGrades(semester: Semester): Flow<List<Grade>> {
return gradeDb.loadAll(semester.semesterId, semester.studentId).map {
it.filter { grade -> !grade.isNotified }
}
}
fun getNotNotifiedPredictedGrades(semester: Semester): Flow<List<GradeSummary>> {
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).map {
it.filter { gradeSummary -> !gradeSummary.isPredictedGradeNotified }
}
}
fun getNotNotifiedFinalGrades(semester: Semester): Flow<List<GradeSummary>> {
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).map {
it.filter { gradeSummary -> !gradeSummary.isFinalGradeNotified }
}
}
suspend fun updateGrade(grade: Grade) {
return gradeDb.updateAll(listOf(grade))
}
suspend fun updateGrades(grades: List<Grade>) {
return gradeDb.updateAll(grades)
}
suspend fun updateGradesSummary(gradesSummary: List<GradeSummary>) {
return gradeSummaryDb.updateAll(gradesSummary)
}
}

View file

@ -1,54 +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 kotlinx.coroutines.sync.Mutex
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 saveFetchResultMutex = Mutex()
private val cacheKey = "homework"
fun getHomework(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
mutex = saveFetchResultMutex,
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
}))
}
}

View file

@ -1,49 +0,0 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.LuckyNumberDao
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntity
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.sync.Mutex
import java.time.LocalDate
import java.time.LocalDate.now
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class LuckyNumberRepository @Inject constructor(
private val luckyNumberDb: LuckyNumberDao,
private val sdk: Sdk
) {
private val saveFetchResultMutex = Mutex()
fun getLuckyNumber(student: Student, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = { it == null || forceRefresh },
query = { luckyNumberDb.load(student.studentId, now()) },
fetch = { sdk.init(student).getLuckyNumber(student.schoolShortName)?.mapToEntity(student) },
saveFetchResult = { old, new ->
if (new != old) {
old?.let { luckyNumberDb.deleteAll(listOfNotNull(it)) }
luckyNumberDb.insertAll(listOfNotNull((new?.apply {
if (notify) isNotified = false
})))
}
}
)
fun getLuckyNumberHistory(student: Student, start: LocalDate, end: LocalDate) =
luckyNumberDb.getAll(student.studentId, start, end)
suspend fun getNotNotifiedLuckyNumber(student: Student) = luckyNumberDb.load(student.studentId, now()).map {
if (it?.isNotified == false) it else null
}.first()
suspend fun updateLuckyNumber(luckyNumber: LuckyNumber?) = luckyNumberDb.updateAll(listOfNotNull(luckyNumber))
}

View file

@ -1,106 +0,0 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
import io.github.wulkanowy.data.db.dao.MessagesDao
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.enums.MessageFolder
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
import io.github.wulkanowy.data.mappers.mapFromEntities
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Folder
import io.github.wulkanowy.sdk.pojo.SentMessage
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.sync.Mutex
import timber.log.Timber
import java.time.LocalDateTime.now
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class MessageRepository @Inject constructor(
private val messagesDb: MessagesDao,
private val messageAttachmentDao: MessageAttachmentDao,
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "message"
@Suppress("UNUSED_PARAMETER")
fun getMessages(student: Student, semester: Semester, folder: MessageFolder, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, student, folder)) },
query = { messagesDb.loadAll(student.id.toInt(), folder.id) },
fetch = { sdk.init(student).getMessages(Folder.valueOf(folder.name), now().minusMonths(3), now()).mapToEntities(student) },
saveFetchResult = { old, new ->
messagesDb.deleteAll(old uniqueSubtract new)
messagesDb.insertAll((new uniqueSubtract old).onEach {
it.isNotified = !notify
})
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student, folder))
}
)
fun getMessage(student: Student, message: Message, markAsRead: Boolean = false) = networkBoundResource(
shouldFetch = {
checkNotNull(it, { "This message no longer exist!" })
Timber.d("Message content in db empty: ${it.message.content.isEmpty()}")
it.message.unread || it.message.content.isEmpty()
},
query = { messagesDb.loadMessageWithAttachment(student.id.toInt(), message.messageId) },
fetch = {
sdk.init(student).getMessageDetails(it!!.message.messageId, message.folderId, markAsRead, message.realId).let { details ->
details.content to details.attachments.mapToEntities()
}
},
saveFetchResult = { old, (downloadedMessage, attachments) ->
checkNotNull(old, { "Fetched message no longer exist!" })
messagesDb.updateAll(listOf(old.message.copy(unread = !markAsRead).apply {
id = old.message.id
content = content.ifBlank { downloadedMessage }
}))
messageAttachmentDao.insertAttachments(attachments)
Timber.d("Message ${message.messageId} with blank content: ${old.message.content.isBlank()}, marked as read")
}
)
fun getNotNotifiedMessages(student: Student): Flow<List<Message>> {
return messagesDb.loadAll(student.id.toInt(), RECEIVED.id).map { it.filter { message -> !message.isNotified && message.unread } }
}
suspend fun updateMessages(messages: List<Message>) {
return messagesDb.updateAll(messages)
}
suspend fun sendMessage(student: Student, subject: String, content: String, recipients: List<Recipient>): SentMessage {
return sdk.init(student).sendMessage(
subject = subject,
content = content,
recipients = recipients.mapFromEntities()
)
}
suspend fun deleteMessage(student: Student, message: Message) {
val isDeleted = sdk.init(student).deleteMessages(listOf(message.messageId), message.folderId)
if (message.folderId != MessageFolder.TRASHED.id) {
if (isDeleted) messagesDb.updateAll(listOf(message.copy(folderId = MessageFolder.TRASHED.id).apply {
id = message.id
content = message.content
}))
} else messagesDb.deleteAll(listOf(message))
}
}

View file

@ -1,60 +0,0 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.MobileDeviceDao
import io.github.wulkanowy.data.db.entities.MobileDevice
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.mappers.mapToMobileDeviceToken
import io.github.wulkanowy.data.pojos.MobileDeviceToken
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 kotlinx.coroutines.sync.Mutex
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class MobileDeviceRepository @Inject constructor(
private val mobileDb: MobileDeviceDao,
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "devices"
fun getDevices(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, student)) },
query = { mobileDb.loadAll(student.userLoginId.takeIf { it != 0 } ?: student.studentId) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getRegisteredDevices()
.mapToEntities(semester)
},
saveFetchResult = { old, new ->
mobileDb.deleteAll(old uniqueSubtract new)
mobileDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
}
)
suspend fun unregisterDevice(student: Student, semester: Semester, device: MobileDevice) {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.unregisterDevice(device.deviceId)
mobileDb.deleteAll(listOf(device))
}
suspend fun getToken(student: Student, semester: Semester): MobileDeviceToken {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getToken()
.mapToMobileDeviceToken()
}
}

View file

@ -1,64 +0,0 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.NoteDao
import io.github.wulkanowy.data.db.entities.Note
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 kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class NoteRepository @Inject constructor(
private val noteDb: NoteDao,
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "note"
fun getNotes(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
query = { noteDb.loadAll(student.studentId) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getNotes(semester.semesterId)
.mapToEntities(semester)
},
saveFetchResult = { old, new ->
noteDb.deleteAll(old uniqueSubtract new)
noteDb.insertAll((new uniqueSubtract old).onEach {
if (it.date >= student.registrationDate.toLocalDate()) it.apply {
isRead = false
if (notify) isNotified = false
}
})
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
}
)
fun getNotNotifiedNotes(student: Student): Flow<List<Note>> {
return noteDb.loadAll(student.studentId).map { it.filter { note -> !note.isNotified } }
}
suspend fun updateNote(note: Note) {
noteDb.updateAll(listOf(note))
}
suspend fun updateNotes(notes: List<Note>) {
noteDb.updateAll(notes)
}
}

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