Compare commits
No commits in common. "1.4.0" and "1.1.4" have entirely different histories.
|
@ -1,12 +1,3 @@
|
||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Utwórz raport błędu, aby pomóc nam ulepszyć Wulkanowego
|
|
||||||
title: ''
|
|
||||||
labels: ''
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Co powinno się dziać
|
## Co powinno się dziać
|
||||||
|
|
||||||
|
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
|
@ -1,20 +0,0 @@
|
||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Zaproponuj nowy pomysł dla Wulkanowego
|
|
||||||
title: ''
|
|
||||||
labels: ''
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
** Czy Twoja prośba o funkcję jest związana z problemem? Proszę opisz.**
|
|
||||||
Jasny i zwięzły opis problemu. Np. Zawsze jestem sfrustrowany, gdy [...]
|
|
||||||
|
|
||||||
** Opisz żądane rozwiązanie **
|
|
||||||
Jasny i zwięzły opis tego, co chcesz, aby się wydarzyło.
|
|
||||||
|
|
||||||
** Opisz alternatywy, które rozważałeś **
|
|
||||||
Jasny i zwięzły opis wszelkich rozważanych alternatywnych rozwiązań lub funkcji.
|
|
||||||
|
|
||||||
** Dodatkowy kontekst **
|
|
||||||
Dodaj inny kontekst lub zrzuty ekranu dotyczące żądania funkcji tutaj.
|
|
12
.github/dependabot.yml
vendored
|
@ -1,12 +0,0 @@
|
||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: gradle
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
open-pull-requests-limit: 10
|
|
||||||
target-branch: develop
|
|
||||||
ignore:
|
|
||||||
- dependency-name: io.github.wulkanowy:sdk
|
|
||||||
reviewers:
|
|
||||||
- Faierbel
|
|
72
.github/workflows/deploy-store.yml
vendored
|
@ -1,72 +0,0 @@
|
||||||
name: Deploy to app stores
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [ created ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
deploy-google-play:
|
|
||||||
name: Deploy to google play
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 10
|
|
||||||
environment: google-play
|
|
||||||
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/upload-key.jks.gpg
|
|
||||||
- name: Upload apk to google play
|
|
||||||
env:
|
|
||||||
PLAY_STORE_PASSWORD: ${{ secrets.PLAY_STORE_PASSWORD }}
|
|
||||||
PLAY_KEY_ALIAS: ${{ secrets.PLAY_KEY_ALIAS }}
|
|
||||||
PLAY_KEY_PASSWORD: ${{ secrets.PLAY_KEY_PASSWORD }}
|
|
||||||
ANDROID_PUBLISHER_CREDENTIALS: ${{ secrets.ANDROID_PUBLISHER_CREDENTIALS }}
|
|
||||||
run: ./gradlew publishPlayReleaseApps -PenableFirebase --stacktrace;
|
|
||||||
|
|
||||||
deploy-app-gallery:
|
|
||||||
name: Deploy to AppGallery
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 10
|
|
||||||
environment: app-gallery
|
|
||||||
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/agconnect-services.json.gpg
|
|
||||||
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg
|
|
||||||
- name: Prepare credentials
|
|
||||||
env:
|
|
||||||
AGC_CREDENTIALS: ${{ secrets.AGC_CREDENTIALS }}
|
|
||||||
run: echo $AGC_CREDENTIALS > ./app/src/release/agconnect-credentials.json
|
|
||||||
- name: Build and publish HMS version
|
|
||||||
env:
|
|
||||||
PLAY_STORE_PASSWORD: ${{ secrets.PLAY_STORE_PASSWORD }}
|
|
||||||
PLAY_KEY_ALIAS: ${{ secrets.PLAY_KEY_ALIAS }}
|
|
||||||
PLAY_KEY_PASSWORD: ${{ secrets.PLAY_KEY_PASSWORD }}
|
|
||||||
run: ./gradlew bundleHmsRelease --stacktrace && ./gradlew publishHuaweiAppGalleryHmsRelease --stacktrace
|
|
144
.github/workflows/deploy-test.yml
vendored
|
@ -1,144 +0,0 @@
|
||||||
name: Deploy to app tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
# branches: [ develop ]
|
|
||||||
branches: [ '!*' ]
|
|
||||||
pull_request_target:
|
|
||||||
# branches: [ develop ]
|
|
||||||
branches: [ '!*' ]
|
|
||||||
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
deploy-appcenter:
|
|
||||||
name: App Center
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 10
|
|
||||||
environment: app-center
|
|
||||||
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: App Distribution
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 10
|
|
||||||
environment: app-distribution
|
|
||||||
if: github.event_name != 'pull_request_target'
|
|
||||||
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
|
|
178
.github/workflows/test.yml
vendored
|
@ -1,11 +1,13 @@
|
||||||
name: Tests
|
name: Test and deploy
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master, develop ]
|
branches: [ develop ]
|
||||||
tags: [ '*' ]
|
tags: [ '*' ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master, develop ]
|
branches: [ develop ]
|
||||||
|
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
unit-tests:
|
unit-tests:
|
||||||
|
@ -27,8 +29,174 @@ jobs:
|
||||||
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||||
- name: Unit tests
|
- name: Unit tests
|
||||||
run: |
|
run: |
|
||||||
./gradlew testFdroidDebugUnitTest --stacktrace
|
./gradlew --build-cache -Pcoverage testFdroidDebugUnitTest --stacktrace
|
||||||
./gradlew jacocoTestReport --stacktrace
|
./gradlew --build-cache -Pcoverage jacocoTestReport --stacktrace
|
||||||
- uses: codecov/codecov-action@v1
|
- uses: codecov/codecov-action@v1
|
||||||
with:
|
with:
|
||||||
flags: unit
|
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
|
||||||
|
|
2
.gitignore
vendored
|
@ -117,5 +117,3 @@ Thumbs.db
|
||||||
|
|
||||||
|
|
||||||
app/src/release/agconnect-services.json
|
app/src/release/agconnect-services.json
|
||||||
app/src/release/agconnect-credentials.json
|
|
||||||
.idea/deploymentTargetDropDown.xml
|
|
||||||
|
|
9
.idea/codeStyles/Project.xml
generated
|
@ -7,6 +7,15 @@
|
||||||
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
|
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
|
||||||
</value>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
|
<option name="PACKAGES_IMPORT_LAYOUT">
|
||||||
|
<value>
|
||||||
|
<package name="" alias="false" withSubpackages="true" />
|
||||||
|
<package name="java" alias="false" withSubpackages="true" />
|
||||||
|
<package name="javax" alias="false" withSubpackages="true" />
|
||||||
|
<package name="kotlin" alias="false" withSubpackages="true" />
|
||||||
|
<package name="" alias="true" withSubpackages="true" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
|
||||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
|
||||||
<option name="WRAP_ELVIS_EXPRESSIONS" value="0" />
|
<option name="WRAP_ELVIS_EXPRESSIONS" value="0" />
|
||||||
|
|
2
LICENSE
|
@ -186,7 +186,7 @@
|
||||||
same "printed page" as the copyright notice for easier
|
same "printed page" as the copyright notice for easier
|
||||||
identification within third-party archives.
|
identification within third-party archives.
|
||||||
|
|
||||||
Copyright 2021 Wulkanowy
|
Copyright 2019 Wulkanowy
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
# Wulkanowy
|
# Wulkanowy
|
||||||
|
|
||||||
[](https://github.com/wulkanowy/wulkanowy/actions)
|
[](https://github.com/wulkanowy/wulkanowy/actions)
|
||||||
[](https://codecov.io/gh/wulkanowy/wulkanowy)
|
[](https://codecov.io/gh/wulkanowy/wulkanowy)
|
||||||
[](https://discord.gg/vccAQBr)
|
[](https://discord.gg/vccAQBr)
|
||||||
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
# Wulkanowy
|
# Wulkanowy
|
||||||
|
|
||||||
[](https://github.com/wulkanowy/wulkanowy/actions)
|
[](https://github.com/wulkanowy/wulkanowy/actions)
|
||||||
[](https://codecov.io/gh/wulkanowy/wulkanowy)
|
[](https://codecov.io/gh/wulkanowy/wulkanowy)
|
||||||
[](https://discord.gg/vccAQBr)
|
[](https://discord.gg/vccAQBr)
|
||||||
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
|
|
BIN
app/bitrise.jks
Normal file
179
app/build.gradle
|
@ -1,36 +1,36 @@
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlinx-serialization'
|
|
||||||
apply plugin: 'kotlin-parcelize'
|
|
||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
apply plugin: 'dagger.hilt.android.plugin'
|
apply plugin: 'dagger.hilt.android.plugin'
|
||||||
apply plugin: 'com.google.gms.google-services'
|
|
||||||
apply plugin: 'com.google.firebase.crashlytics'
|
apply plugin: 'com.google.firebase.crashlytics'
|
||||||
apply plugin: 'com.github.triplet.play'
|
apply plugin: 'com.github.triplet.play'
|
||||||
apply plugin: 'ru.cian.huawei-publish'
|
|
||||||
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
|
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
|
||||||
|
apply plugin: 'com.google.gms.google-services'
|
||||||
apply plugin: 'com.huawei.agconnect'
|
apply plugin: 'com.huawei.agconnect'
|
||||||
apply from: 'jacoco.gradle'
|
apply from: 'jacoco.gradle'
|
||||||
apply from: 'sonarqube.gradle'
|
apply from: 'sonarqube.gradle'
|
||||||
apply from: 'hooks.gradle'
|
apply from: 'hooks.gradle'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 31
|
compileSdkVersion 30
|
||||||
|
buildToolsVersion '30.0.3'
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "io.github.wulkanowy"
|
applicationId "io.github.wulkanowy"
|
||||||
testApplicationId "io.github.tests.wulkanowy"
|
testApplicationId "io.github.tests.wulkanowy"
|
||||||
minSdkVersion 21
|
minSdkVersion 17
|
||||||
targetSdkVersion 31
|
targetSdkVersion 30
|
||||||
versionCode 98
|
versionCode 90
|
||||||
versionName "1.4.0"
|
versionName "1.1.4"
|
||||||
|
multiDexEnabled true
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
vectorDrawables.useSupportLibrary = true
|
||||||
|
|
||||||
resValue "string", "app_name", "Wulkanowy"
|
resValue "string", "app_name", "Wulkanowy"
|
||||||
|
buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis())
|
||||||
|
|
||||||
manifestPlaceholders = [
|
manifestPlaceholders = [
|
||||||
firebase_enabled: project.hasProperty("enableFirebase"),
|
firebase_enabled: project.hasProperty("enableFirebase")
|
||||||
admob_project_id: ""
|
|
||||||
]
|
]
|
||||||
javaCompileOptions {
|
javaCompileOptions {
|
||||||
annotationProcessorOptions {
|
annotationProcessorOptions {
|
||||||
|
@ -40,14 +40,6 @@ android {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "null"
|
|
||||||
|
|
||||||
if (System.env.SET_BUILD_TIMESTAMP) {
|
|
||||||
buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis())
|
|
||||||
} else {
|
|
||||||
buildConfigField "long", "BUILD_TIMESTAMP", "1486235849000"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
|
@ -70,14 +62,13 @@ android {
|
||||||
shrinkResources true
|
shrinkResources true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
buildConfigField "String", "MESSAGES_BASE_URL", "\"https://messages.wulkanowy.net.pl\""
|
|
||||||
}
|
}
|
||||||
debug {
|
debug {
|
||||||
resValue "string", "app_name", "Wulkanowy DEV"
|
resValue "string", "app_name", "Wulkanowy DEV " + defaultConfig.versionCode
|
||||||
applicationIdSuffix ".dev"
|
applicationIdSuffix ".dev"
|
||||||
versionNameSuffix "-dev"
|
versionNameSuffix "-dev"
|
||||||
|
testCoverageEnabled = project.hasProperty('coverage')
|
||||||
ext.enableCrashlytics = project.hasProperty("enableFirebase")
|
ext.enableCrashlytics = project.hasProperty("enableFirebase")
|
||||||
buildConfigField "String", "MESSAGES_BASE_URL", "\"https://messages.wulkanowy.net.pl\""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,36 +77,33 @@ android {
|
||||||
productFlavors {
|
productFlavors {
|
||||||
hms {
|
hms {
|
||||||
dimension "platform"
|
dimension "platform"
|
||||||
manifestPlaceholders = [install_channel: "AppGallery"]
|
minSdkVersion 19
|
||||||
|
manifestPlaceholders = [
|
||||||
|
install_channel: "AppGallery"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
play {
|
play {
|
||||||
dimension "platform"
|
dimension "platform"
|
||||||
manifestPlaceholders = [
|
manifestPlaceholders = [
|
||||||
install_channel : "Google Play",
|
install_channel: "Google Play"
|
||||||
admob_project_id: System.getenv("ADMOB_PROJECT_ID") ?: "ca-app-pub-3940256099942544~3347511713"
|
|
||||||
]
|
]
|
||||||
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "\"${System.getenv("SINGLE_SUPPORT_AD_ID") ?: "ca-app-pub-3940256099942544/5354046379"}\""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fdroid {
|
fdroid {
|
||||||
dimension "platform"
|
dimension "platform"
|
||||||
manifestPlaceholders = [install_channel: "F-Droid"]
|
manifestPlaceholders = [
|
||||||
|
install_channel: "F-Droid"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
playConfigs {
|
|
||||||
play { enabled.set(true) }
|
|
||||||
}
|
|
||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding true
|
viewBinding = true
|
||||||
}
|
}
|
||||||
|
|
||||||
bundle {
|
lintOptions {
|
||||||
language {
|
disable 'HardwareIds'
|
||||||
enableSplit = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
testOptions.unitTests {
|
testOptions.unitTests {
|
||||||
|
@ -124,12 +112,13 @@ android {
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
coreLibraryDesugaringEnabled true
|
coreLibraryDesugaringEnabled true
|
||||||
sourceCompatibility JavaVersion.VERSION_11
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_11
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "11"
|
useIR = true
|
||||||
|
jvmTarget = "1.8"
|
||||||
freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn", "-Xjvm-default=all"]
|
freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn", "-Xjvm-default=all"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,66 +132,54 @@ android {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kapt {
|
|
||||||
correctErrorTypes true
|
|
||||||
}
|
|
||||||
|
|
||||||
play {
|
play {
|
||||||
|
serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") ?: "jan@fakelog.cf"
|
||||||
|
serviceAccountCredentials = file('key.p12')
|
||||||
defaultToAppBundles = false
|
defaultToAppBundles = false
|
||||||
track = 'beta'
|
track = 'production'
|
||||||
updatePriority = 1
|
updatePriority = 3
|
||||||
enabled.set(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
huaweiPublish {
|
|
||||||
instances {
|
|
||||||
hmsRelease {
|
|
||||||
credentialsPath = "$rootDir/app/src/release/agconnect-credentials.json"
|
|
||||||
buildFormat = "aab"
|
|
||||||
deployType = "draft"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
work_manager = "2.7.0"
|
work_manager = "2.5.0"
|
||||||
android_hilt = "1.0.0"
|
work_hilt = "1.0.0-beta01"
|
||||||
room = "2.3.0"
|
room = "2.3.0-rc01"
|
||||||
chucker = "3.5.2"
|
chucker = "3.4.0"
|
||||||
mockk = "1.12.0"
|
mockk = "1.11.0"
|
||||||
coroutines = "1.5.2"
|
moshi = "1.11.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "io.github.wulkanowy:sdk:1.4.0"
|
implementation "io.github.wulkanowy:sdk:1.1.3"
|
||||||
|
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3'
|
||||||
|
|
||||||
implementation "androidx.core:core-ktx:1.7.0"
|
implementation "androidx.core:core-ktx:1.3.2"
|
||||||
implementation 'androidx.core:core-splashscreen:1.0.0-alpha02'
|
implementation "androidx.activity:activity-ktx:1.2.2"
|
||||||
implementation "androidx.activity:activity-ktx:1.4.0"
|
implementation "androidx.appcompat:appcompat:1.2.0"
|
||||||
implementation "androidx.appcompat:appcompat:1.4.0-rc01"
|
implementation "androidx.appcompat:appcompat-resources:1.2.0"
|
||||||
implementation "androidx.fragment:fragment-ktx:1.4.0-rc01"
|
implementation "androidx.fragment:fragment-ktx:1.3.2"
|
||||||
implementation "androidx.annotation:annotation:1.3.0"
|
implementation "androidx.annotation:annotation:1.2.0"
|
||||||
|
implementation "androidx.multidex:multidex:2.0.1"
|
||||||
|
|
||||||
implementation "androidx.preference:preference-ktx:1.1.1"
|
implementation "androidx.preference:preference-ktx:1.1.1"
|
||||||
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
implementation "androidx.recyclerview:recyclerview:1.1.0"
|
||||||
implementation "androidx.viewpager:viewpager:1.0.0"
|
implementation "androidx.viewpager:viewpager:1.0.0"
|
||||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||||
implementation "androidx.constraintlayout:constraintlayout:2.1.1"
|
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
|
||||||
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
|
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
|
||||||
implementation "com.google.android.material:material:1.4.0"
|
implementation "com.google.android.material:material:1.3.0"
|
||||||
implementation "com.github.wulkanowy:material-chips-input:2.3.1"
|
implementation "com.github.wulkanowy:material-chips-input:2.2.0"
|
||||||
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
|
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
|
||||||
implementation 'com.github.lopspower:CircularImageView:4.2.0'
|
implementation 'com.mikhaellopez:circularimageview:4.2.0'
|
||||||
|
|
||||||
implementation "androidx.work:work-runtime-ktx:$work_manager"
|
implementation "androidx.work:work-runtime-ktx:$work_manager"
|
||||||
playImplementation "androidx.work:work-gcm:$work_manager"
|
playImplementation "androidx.work:work-gcm:$work_manager"
|
||||||
|
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0"
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"
|
||||||
|
|
||||||
implementation "androidx.room:room-runtime:$room"
|
implementation "androidx.room:room-runtime:$room"
|
||||||
implementation "androidx.room:room-ktx:$room"
|
implementation "androidx.room:room-ktx:$room"
|
||||||
|
@ -210,57 +187,55 @@ dependencies {
|
||||||
|
|
||||||
implementation "com.google.dagger:hilt-android:$hilt_version"
|
implementation "com.google.dagger:hilt-android:$hilt_version"
|
||||||
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
|
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
|
||||||
kapt "androidx.hilt:hilt-compiler:$android_hilt"
|
implementation "androidx.hilt:hilt-work:$work_hilt"
|
||||||
implementation "androidx.hilt:hilt-work:$android_hilt"
|
kapt "androidx.hilt:hilt-compiler:$work_hilt"
|
||||||
|
|
||||||
implementation 'com.github.ncapdevi:FragNav:3.3.0'
|
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.3.0"
|
||||||
|
|
||||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
implementation "com.squareup.moshi:moshi:$moshi"
|
||||||
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0"
|
implementation "com.squareup.moshi:moshi-adapters:$moshi"
|
||||||
implementation "com.squareup.okhttp3:logging-interceptor:4.9.2"
|
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi"
|
||||||
|
implementation "com.jakewharton.timber:timber:4.7.1"
|
||||||
implementation "com.jakewharton.timber:timber:5.0.1"
|
|
||||||
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
||||||
implementation 'com.github.bastienpaulfr:Treessence:1.0.5'
|
implementation "fr.bipi.treessence:treessence:0.3.2"
|
||||||
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
||||||
implementation "io.coil-kt:coil:1.4.0"
|
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
|
||||||
|
implementation "io.coil-kt:coil:1.1.1"
|
||||||
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
|
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
|
||||||
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
|
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
|
||||||
implementation 'com.fredporciuncula:flow-preferences:1.5.0'
|
|
||||||
|
|
||||||
playImplementation platform('com.google.firebase:firebase-bom:29.0.0')
|
playImplementation platform('com.google.firebase:firebase-bom:26.7.0')
|
||||||
playImplementation 'com.google.firebase:firebase-analytics-ktx'
|
playImplementation 'com.google.firebase:firebase-analytics-ktx'
|
||||||
playImplementation 'com.google.firebase:firebase-messaging:'
|
playImplementation 'com.google.firebase:firebase-messaging:'
|
||||||
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
||||||
playImplementation 'com.google.android.play:core:1.10.2'
|
|
||||||
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
||||||
playImplementation 'com.google.android.gms:play-services-ads:20.4.0'
|
|
||||||
|
|
||||||
hmsImplementation 'com.huawei.hms:hianalytics:6.3.0.303'
|
hmsImplementation 'com.huawei.hms:hianalytics:5.2.0.301'
|
||||||
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.1.300'
|
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.5.1.200'
|
||||||
|
|
||||||
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
||||||
|
|
||||||
debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker"
|
debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker"
|
||||||
debugImplementation 'com.github.amitshekhariitbhu.Android-Debug-Database:debug-db:1.0.6'
|
debugImplementation "com.amitshekhar.android:debug-db:1.0.6"
|
||||||
|
|
||||||
testImplementation "junit:junit:4.13.2"
|
testImplementation "junit:junit:4.13.2"
|
||||||
testImplementation "io.mockk:mockk:$mockk"
|
testImplementation "io.mockk:mockk:$mockk"
|
||||||
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines"
|
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2'
|
||||||
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
|
|
||||||
testImplementation 'org.robolectric:robolectric:4.7'
|
testImplementation 'org.robolectric:robolectric:4.5.1'
|
||||||
testImplementation "androidx.test:runner:1.4.0"
|
testImplementation "androidx.test:runner:1.3.0"
|
||||||
testImplementation "androidx.test.ext:junit:1.1.3"
|
testImplementation "androidx.test.ext:junit:1.1.2"
|
||||||
testImplementation "androidx.test:core:1.4.0"
|
testImplementation "androidx.test:core:1.3.0"
|
||||||
testImplementation "androidx.room:room-testing:$room"
|
testImplementation "androidx.room:room-testing:$room"
|
||||||
testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
|
testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
|
||||||
kaptTest "com.google.dagger:hilt-android-compiler:$hilt_version"
|
kaptTest "com.google.dagger:hilt-android-compiler:$hilt_version"
|
||||||
|
|
||||||
androidTestImplementation "androidx.test:core:1.4.0"
|
androidTestImplementation "androidx.test:core:1.3.0"
|
||||||
androidTestImplementation "androidx.test:runner:1.4.0"
|
androidTestImplementation "androidx.test:runner:1.3.0"
|
||||||
androidTestImplementation "androidx.test.ext:junit:1.1.3"
|
androidTestImplementation "androidx.test.ext:junit:1.1.2"
|
||||||
androidTestImplementation "io.mockk:mockk-android:$mockk"
|
androidTestImplementation "io.mockk:mockk-android:$mockk"
|
||||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
apply plugin: "jacoco"
|
apply plugin: "jacoco"
|
||||||
|
|
||||||
jacoco {
|
jacoco {
|
||||||
toolVersion "0.8.7"
|
toolVersion "0.8.5"
|
||||||
reportsDirectory.set(file("$buildDir/reports"))
|
reportsDir = file("$buildDir/reports")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(Test) {
|
tasks.withType(Test) {
|
||||||
|
@ -16,8 +16,8 @@ task jacocoTestReport(type: JacocoReport) {
|
||||||
description = "Generate Jacoco coverage reports"
|
description = "Generate Jacoco coverage reports"
|
||||||
|
|
||||||
reports {
|
reports {
|
||||||
xml.required.set(true)
|
xml.enabled = true
|
||||||
html.required.set(true)
|
html.enabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
def excludes = ['**/R.class',
|
def excludes = ['**/R.class',
|
||||||
|
|
BIN
app/key.p12.gpg
Normal file
BIN
app/src/debug/res/drawable-hdpi/ic_stat_grade.png
Normal file
After Width: | Height: | Size: 478 B |
BIN
app/src/debug/res/drawable-hdpi/ic_stat_luckynumber.png
Normal file
After Width: | Height: | Size: 652 B |
BIN
app/src/debug/res/drawable-hdpi/ic_stat_message.png
Normal file
After Width: | Height: | Size: 384 B |
BIN
app/src/debug/res/drawable-hdpi/ic_stat_note.png
Normal file
After Width: | Height: | Size: 460 B |
BIN
app/src/debug/res/drawable-hdpi/ic_stat_timetable.png
Normal file
After Width: | Height: | Size: 426 B |
BIN
app/src/debug/res/drawable-mdpi/ic_stat_grade.png
Normal file
After Width: | Height: | Size: 355 B |
BIN
app/src/debug/res/drawable-mdpi/ic_stat_luckynumber.png
Normal file
After Width: | Height: | Size: 451 B |
BIN
app/src/debug/res/drawable-mdpi/ic_stat_message.png
Normal file
After Width: | Height: | Size: 297 B |
BIN
app/src/debug/res/drawable-mdpi/ic_stat_note.png
Normal file
After Width: | Height: | Size: 339 B |
BIN
app/src/debug/res/drawable-mdpi/ic_stat_timetable.png
Normal file
After Width: | Height: | Size: 335 B |
BIN
app/src/debug/res/drawable-xhdpi/ic_stat_grade.png
Normal file
After Width: | Height: | Size: 588 B |
BIN
app/src/debug/res/drawable-xhdpi/ic_stat_luckynumber.png
Normal file
After Width: | Height: | Size: 897 B |
BIN
app/src/debug/res/drawable-xhdpi/ic_stat_message.png
Normal file
After Width: | Height: | Size: 508 B |
BIN
app/src/debug/res/drawable-xhdpi/ic_stat_note.png
Normal file
After Width: | Height: | Size: 586 B |
BIN
app/src/debug/res/drawable-xhdpi/ic_stat_timetable.png
Normal file
After Width: | Height: | Size: 519 B |
BIN
app/src/debug/res/drawable-xxhdpi/ic_stat_grade.png
Normal file
After Width: | Height: | Size: 781 B |
BIN
app/src/debug/res/drawable-xxhdpi/ic_stat_luckynumber.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
app/src/debug/res/drawable-xxhdpi/ic_stat_message.png
Normal file
After Width: | Height: | Size: 692 B |
BIN
app/src/debug/res/drawable-xxhdpi/ic_stat_note.png
Normal file
After Width: | Height: | Size: 805 B |
BIN
app/src/debug/res/drawable-xxhdpi/ic_stat_timetable.png
Normal file
After Width: | Height: | Size: 700 B |
|
@ -1,17 +0,0 @@
|
||||||
package io.github.wulkanowy.utils
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
|
||||||
import javax.inject.Singleton
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
class InAppReviewHelper @Inject constructor(
|
|
||||||
@ApplicationContext private val context: Context
|
|
||||||
) {
|
|
||||||
|
|
||||||
fun showInAppReview(activity: MainActivity) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,6 +3,11 @@ package io.github.wulkanowy.utils
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.huawei.agconnect.crash.AGConnectCrash
|
import com.huawei.agconnect.crash.AGConnectCrash
|
||||||
import fr.bipi.tressence.base.FormatterPriorityTree
|
import fr.bipi.tressence.base.FormatterPriorityTree
|
||||||
|
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
|
||||||
|
import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
|
||||||
|
import java.io.InterruptedIOException
|
||||||
|
import java.net.SocketTimeoutException
|
||||||
|
import java.net.UnknownHostException
|
||||||
|
|
||||||
class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) {
|
class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) {
|
||||||
|
|
||||||
|
@ -15,10 +20,21 @@ class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CrashLogExceptionTree : FormatterPriorityTree(Log.ERROR, ExceptionFilter) {
|
class CrashLogExceptionTree : FormatterPriorityTree(Log.ERROR) {
|
||||||
|
|
||||||
private val connectCrash by lazy { AGConnectCrash.getInstance() }
|
private val connectCrash by lazy { AGConnectCrash.getInstance() }
|
||||||
|
|
||||||
|
override fun skipLog(priority: Int, tag: String?, message: String, t: Throwable?): Boolean {
|
||||||
|
return when (t) {
|
||||||
|
is FeatureDisabledException,
|
||||||
|
is FeatureNotAvailableException,
|
||||||
|
is UnknownHostException,
|
||||||
|
is SocketTimeoutException,
|
||||||
|
is InterruptedIOException -> true
|
||||||
|
else -> super.skipLog(priority, tag, message, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
||||||
if (skipLog(priority, tag, message, t)) return
|
if (skipLog(priority, tag, message, t)) return
|
||||||
|
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
package io.github.wulkanowy.utils
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
class InAppReviewHelper @Inject constructor(
|
|
||||||
@ApplicationContext private val context: Context
|
|
||||||
) {
|
|
||||||
|
|
||||||
fun showInAppReview(activity: MainActivity) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
|
||||||
|
@ -38,14 +37,13 @@
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:networkSecurityConfig="@xml/network_security_config"
|
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="false"
|
android:supportsRtl="false"
|
||||||
android:theme="@style/WulkanowyTheme"
|
android:theme="@style/WulkanowyTheme"
|
||||||
|
android:usesCleartextTraffic="true"
|
||||||
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
|
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.modules.splash.SplashActivity"
|
android:name=".ui.modules.splash.SplashActivity"
|
||||||
android:exported="true"
|
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
android:theme="@style/WulkanowyTheme.SplashScreen"
|
android:theme="@style/WulkanowyTheme.SplashScreen"
|
||||||
tools:ignore="LockedOrientationActivity">
|
tools:ignore="LockedOrientationActivity">
|
||||||
|
@ -75,7 +73,6 @@
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.modules.timetablewidget.TimetableWidgetConfigureActivity"
|
android:name=".ui.modules.timetablewidget.TimetableWidgetConfigureActivity"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:exported="true"
|
|
||||||
android:noHistory="true"
|
android:noHistory="true"
|
||||||
android:theme="@style/WulkanowyTheme.WidgetAccountSwitcher">
|
android:theme="@style/WulkanowyTheme.WidgetAccountSwitcher">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
@ -85,7 +82,6 @@
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.modules.luckynumberwidget.LuckyNumberWidgetConfigureActivity"
|
android:name=".ui.modules.luckynumberwidget.LuckyNumberWidgetConfigureActivity"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:exported="true"
|
|
||||||
android:noHistory="true"
|
android:noHistory="true"
|
||||||
android:theme="@style/WulkanowyTheme.WidgetAccountSwitcher">
|
android:theme="@style/WulkanowyTheme.WidgetAccountSwitcher">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
@ -96,23 +92,6 @@
|
||||||
<service
|
<service
|
||||||
android:name=".services.widgets.TimetableWidgetService"
|
android:name=".services.widgets.TimetableWidgetService"
|
||||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||||
<service
|
|
||||||
android:name=".services.piggyback.VulcanNotificationListenerService"
|
|
||||||
android:exported="true"
|
|
||||||
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.service.notification.NotificationListenerService" />
|
|
||||||
</intent-filter>
|
|
||||||
</service>
|
|
||||||
<service
|
|
||||||
android:name=".services.messaging.AppMessagingService"
|
|
||||||
android:exported="false"
|
|
||||||
tools:ignore="MissingClass">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
|
||||||
</intent-filter>
|
|
||||||
</service>
|
|
||||||
|
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".ui.modules.timetablewidget.TimetableWidgetProvider"
|
android:name=".ui.modules.timetablewidget.TimetableWidgetProvider"
|
||||||
|
@ -127,7 +106,6 @@
|
||||||
</receiver>
|
</receiver>
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".ui.modules.luckynumberwidget.LuckyNumberWidgetProvider"
|
android:name=".ui.modules.luckynumberwidget.LuckyNumberWidgetProvider"
|
||||||
android:exported="true"
|
|
||||||
android:label="@string/lucky_number_title">
|
android:label="@string/lucky_number_title">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
|
@ -140,9 +118,11 @@
|
||||||
<receiver android:name=".services.alarm.TimetableNotificationReceiver" />
|
<receiver android:name=".services.alarm.TimetableNotificationReceiver" />
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.startup.InitializationProvider"
|
android:name="androidx.work.impl.WorkManagerInitializer"
|
||||||
android:authorities="${applicationId}.androidx-startup"
|
android:authorities="${applicationId}.workmanager-init"
|
||||||
|
android:exported="false"
|
||||||
tools:node="remove" />
|
tools:node="remove" />
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="${applicationId}.fileprovider"
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
@ -153,44 +133,44 @@
|
||||||
android:resource="@xml/provider_paths" />
|
android:resource="@xml/provider_paths" />
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="install_channel"
|
||||||
|
android:value="${install_channel}" />
|
||||||
|
|
||||||
<!-- workaround for https://github.com/firebase/firebase-android-sdk/issues/473 enabled:false -->
|
<!-- workaround for https://github.com/firebase/firebase-android-sdk/issues/473 enabled:false -->
|
||||||
<!-- https://firebase.googleblog.com/2017/03/take-control-of-your-firebase-init-on.html -->
|
<!-- https://firebase.googleblog.com/2017/03/take-control-of-your-firebase-init-on.html -->
|
||||||
<provider
|
<provider
|
||||||
android:name="com.google.firebase.provider.FirebaseInitProvider"
|
android:name="com.google.firebase.provider.FirebaseInitProvider"
|
||||||
android:authorities="${applicationId}.firebaseinitprovider"
|
android:authorities="${applicationId}.firebaseinitprovider"
|
||||||
android:enabled="${firebase_enabled}"
|
android:enabled="${firebase_enabled}"
|
||||||
android:exported="false"
|
android:exported="false" />
|
||||||
tools:ignore="MissingClass" />
|
|
||||||
|
|
||||||
<meta-data
|
|
||||||
android:name="install_channel"
|
|
||||||
android:value="${install_channel}" />
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="firebase_analytics_collection_enabled"
|
android:name="firebase_analytics_collection_enabled"
|
||||||
android:value="${firebase_enabled}" />
|
android:value="${firebase_enabled}" />
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="google_analytics_adid_collection_enabled"
|
android:name="google_analytics_adid_collection_enabled"
|
||||||
android:value="${firebase_enabled}" />
|
android:value="${firebase_enabled}" />
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="firebase_crashlytics_collection_enabled"
|
android:name="firebase_crashlytics_collection_enabled"
|
||||||
android:value="${firebase_enabled}" />
|
android:value="${firebase_enabled}" />
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="firebase_messaging_auto_init_enabled"
|
android:name="firebase_messaging_auto_init_enabled"
|
||||||
android:value="${firebase_enabled}" />
|
android:value="${firebase_enabled}" />
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="firebase_inapp_messaging_auto_data_collection_enabled"
|
android:name="firebase_inapp_messaging_auto_data_collection_enabled"
|
||||||
android:value="${firebase_enabled}" />
|
android:value="${firebase_enabled}" />
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.firebase.messaging.default_notification_icon"
|
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||||
android:resource="@drawable/ic_stat_all" />
|
android:resource="@drawable/ic_stat_push" />
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.firebase.messaging.default_notification_channel_id"
|
android:name="com.google.firebase.messaging.default_notification_channel_id"
|
||||||
android:value="push_channel" />
|
android:value="push_channel" />
|
||||||
<meta-data
|
|
||||||
android:name="com.google.android.gms.ads.APPLICATION_ID"
|
|
||||||
android:value="${admob_project_id}" />
|
|
||||||
<meta-data
|
|
||||||
android:name="com.google.android.gms.ads.DELAY_APP_MEASUREMENT_INIT"
|
|
||||||
android:value="true" />
|
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
"githubUsername": "Luncenok"
|
"githubUsername": "Luncenok"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"displayName": "Daniel Olczyk",
|
"displayName": "MRmlik12",
|
||||||
"githubUsername": "MRmlik12"
|
"githubUsername": "MRmlik12"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -46,9 +46,5 @@
|
||||||
{
|
{
|
||||||
"displayName": "Kamil Studziński",
|
"displayName": "Kamil Studziński",
|
||||||
"githubUsername": "studzinskik"
|
"githubUsername": "studzinskik"
|
||||||
},
|
|
||||||
{
|
|
||||||
"displayName": "Tomasz F.",
|
|
||||||
"githubUsername": "Pengwius"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
package io.github.wulkanowy
|
package io.github.wulkanowy
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import android.content.Context
|
||||||
import android.util.Log.DEBUG
|
import android.util.Log.DEBUG
|
||||||
import android.util.Log.INFO
|
import android.util.Log.INFO
|
||||||
import android.util.Log.VERBOSE
|
import android.util.Log.VERBOSE
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.hilt.work.HiltWorkerFactory
|
import androidx.hilt.work.HiltWorkerFactory
|
||||||
|
import androidx.multidex.MultiDex
|
||||||
import androidx.work.Configuration
|
import androidx.work.Configuration
|
||||||
import com.yariksoffice.lingver.Lingver
|
import com.yariksoffice.lingver.Lingver
|
||||||
import dagger.hilt.android.HiltAndroidApp
|
import dagger.hilt.android.HiltAndroidApp
|
||||||
|
@ -39,8 +43,15 @@ class WulkanowyApp : Application(), Configuration.Provider {
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var analyticsHelper: AnalyticsHelper
|
lateinit var analyticsHelper: AnalyticsHelper
|
||||||
|
|
||||||
|
override fun attachBaseContext(base: Context?) {
|
||||||
|
super.attachBaseContext(base)
|
||||||
|
MultiDex.install(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("UnsafeOptInUsageWarning")
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
FragmentManager.enableNewStateManager(false)
|
||||||
initializeAppLanguage()
|
initializeAppLanguage()
|
||||||
themeManager.applyDefaultTheme()
|
themeManager.applyDefaultTheme()
|
||||||
initLogging()
|
initLogging()
|
||||||
|
@ -80,7 +91,7 @@ class WulkanowyApp : Application(), Configuration.Provider {
|
||||||
//https://stackoverflow.com/questions/40398528/android-webview-language-changes-abruptly-on-android-7-0-and-above
|
//https://stackoverflow.com/questions/40398528/android-webview-language-changes-abruptly-on-android-7-0-and-above
|
||||||
try {
|
try {
|
||||||
WebView(this).destroy()
|
WebView(this).destroy()
|
||||||
} catch (e: Throwable) {
|
} catch (e: Exception) {
|
||||||
//Ignore exceptions
|
//Ignore exceptions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,100 +2,59 @@ package io.github.wulkanowy.data
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
import android.content.res.AssetManager
|
||||||
|
import android.content.res.Resources
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.chuckerteam.chucker.api.ChuckerCollector
|
import com.chuckerteam.chucker.api.ChuckerCollector
|
||||||
import com.chuckerteam.chucker.api.ChuckerInterceptor
|
import com.chuckerteam.chucker.api.ChuckerInterceptor
|
||||||
import com.chuckerteam.chucker.api.RetentionManager
|
import com.chuckerteam.chucker.api.RetentionManager
|
||||||
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
|
|
||||||
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
import io.github.wulkanowy.data.api.AdminMessageService
|
|
||||||
import io.github.wulkanowy.data.db.AppDatabase
|
import io.github.wulkanowy.data.db.AppDatabase
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.AppInfo
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
|
||||||
import retrofit2.Retrofit
|
|
||||||
import retrofit2.create
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
internal class DataModule {
|
internal class RepositoryModule {
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideSdk(chuckerInterceptor: ChuckerInterceptor) =
|
fun provideSdk(chuckerCollector: ChuckerCollector, @ApplicationContext context: Context): Sdk {
|
||||||
Sdk().apply {
|
return Sdk().apply {
|
||||||
androidVersion = android.os.Build.VERSION.RELEASE
|
androidVersion = android.os.Build.VERSION.RELEASE
|
||||||
buildTag = android.os.Build.MODEL
|
buildTag = android.os.Build.MODEL
|
||||||
setSimpleHttpLogger { Timber.d(it) }
|
setSimpleHttpLogger { Timber.d(it) }
|
||||||
|
|
||||||
// for debug only
|
// for debug only
|
||||||
addInterceptor(chuckerInterceptor, network = true)
|
addInterceptor(
|
||||||
|
ChuckerInterceptor.Builder(context)
|
||||||
|
.collector(chuckerCollector)
|
||||||
|
.alwaysReadResponseBody(true)
|
||||||
|
.build(), network = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideChuckerCollector(
|
fun provideChuckerCollector(
|
||||||
@ApplicationContext context: Context,
|
@ApplicationContext context: Context,
|
||||||
prefRepository: PreferencesRepository
|
prefRepository: PreferencesRepository
|
||||||
) = ChuckerCollector(
|
): ChuckerCollector {
|
||||||
context = context,
|
return ChuckerCollector(
|
||||||
showNotification = prefRepository.isDebugNotificationEnable,
|
context = context,
|
||||||
retentionPeriod = RetentionManager.Period.ONE_HOUR
|
showNotification = prefRepository.isDebugNotificationEnable,
|
||||||
)
|
retentionPeriod = RetentionManager.Period.ONE_HOUR
|
||||||
|
)
|
||||||
@Singleton
|
}
|
||||||
@Provides
|
|
||||||
fun provideChuckerInterceptor(
|
|
||||||
@ApplicationContext context: Context,
|
|
||||||
chuckerCollector: ChuckerCollector
|
|
||||||
) = ChuckerInterceptor.Builder(context)
|
|
||||||
.collector(chuckerCollector)
|
|
||||||
.alwaysReadResponseBody(true)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Provides
|
|
||||||
fun provideOkHttpClient(chuckerInterceptor: ChuckerInterceptor): OkHttpClient =
|
|
||||||
OkHttpClient.Builder()
|
|
||||||
.addNetworkInterceptor(chuckerInterceptor)
|
|
||||||
.addInterceptor(HttpLoggingInterceptor().apply {
|
|
||||||
level = HttpLoggingInterceptor.Level.BASIC
|
|
||||||
})
|
|
||||||
.connectTimeout(30, TimeUnit.SECONDS)
|
|
||||||
.readTimeout(30, TimeUnit.SECONDS)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
|
||||||
@Singleton
|
|
||||||
@Provides
|
|
||||||
fun provideRetrofit(
|
|
||||||
okHttpClient: OkHttpClient,
|
|
||||||
json: Json,
|
|
||||||
appInfo: AppInfo
|
|
||||||
): Retrofit = Retrofit.Builder()
|
|
||||||
.baseUrl(appInfo.messagesBaseUrl)
|
|
||||||
.client(okHttpClient)
|
|
||||||
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
|
|
||||||
.build()
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Provides
|
|
||||||
fun provideAdminMessageService(retrofit: Retrofit): AdminMessageService = retrofit.create()
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -105,23 +64,19 @@ internal class DataModule {
|
||||||
appInfo: AppInfo
|
appInfo: AppInfo
|
||||||
) = AppDatabase.newInstance(context, sharedPrefProvider, appInfo)
|
) = AppDatabase.newInstance(context, sharedPrefProvider, appInfo)
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideResources(@ApplicationContext context: Context): Resources = context.resources
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideAssets(@ApplicationContext context: Context): AssetManager = context.assets
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences =
|
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences =
|
||||||
PreferenceManager.getDefaultSharedPreferences(context)
|
PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
@Singleton
|
|
||||||
@Provides
|
|
||||||
fun provideFlowSharedPref(sharedPreferences: SharedPreferences) =
|
|
||||||
FlowSharedPreferences(sharedPreferences)
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Provides
|
|
||||||
fun provideJson() = Json {
|
|
||||||
ignoreUnknownKeys = true
|
|
||||||
}
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideStudentDao(database: AppDatabase) = database.studentDao
|
fun provideStudentDao(database: AppDatabase) = database.studentDao
|
||||||
|
@ -226,20 +181,4 @@ internal class DataModule {
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideStudentInfoDao(database: AppDatabase) = database.studentInfoDao
|
fun provideStudentInfoDao(database: AppDatabase) = database.studentInfoDao
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Provides
|
|
||||||
fun provideTimetableHeaderDao(database: AppDatabase) = database.timetableHeaderDao
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Provides
|
|
||||||
fun provideSchoolAnnouncementDao(database: AppDatabase) = database.schoolAnnouncementDao
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Provides
|
|
||||||
fun provideNotificationDao(database: AppDatabase) = database.notificationDao
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Provides
|
|
||||||
fun provideAdminMessageDao(database: AppDatabase) = database.adminMessagesDao
|
|
||||||
}
|
}
|
|
@ -1,12 +0,0 @@
|
||||||
package io.github.wulkanowy.data.api
|
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
|
||||||
import retrofit2.http.GET
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
interface AdminMessageService {
|
|
||||||
|
|
||||||
@GET("/v1.json")
|
|
||||||
suspend fun getAdminMessages(): List<AdminMessage>
|
|
||||||
}
|
|
|
@ -6,7 +6,6 @@ import androidx.room.Room
|
||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
import androidx.room.RoomDatabase.JournalMode.TRUNCATE
|
import androidx.room.RoomDatabase.JournalMode.TRUNCATE
|
||||||
import androidx.room.TypeConverters
|
import androidx.room.TypeConverters
|
||||||
import io.github.wulkanowy.data.db.dao.AdminMessageDao
|
|
||||||
import io.github.wulkanowy.data.db.dao.AttendanceDao
|
import io.github.wulkanowy.data.db.dao.AttendanceDao
|
||||||
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
|
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
|
||||||
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
|
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
|
||||||
|
@ -23,10 +22,8 @@ import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
||||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||||
import io.github.wulkanowy.data.db.dao.MobileDeviceDao
|
import io.github.wulkanowy.data.db.dao.MobileDeviceDao
|
||||||
import io.github.wulkanowy.data.db.dao.NoteDao
|
import io.github.wulkanowy.data.db.dao.NoteDao
|
||||||
import io.github.wulkanowy.data.db.dao.NotificationDao
|
|
||||||
import io.github.wulkanowy.data.db.dao.RecipientDao
|
import io.github.wulkanowy.data.db.dao.RecipientDao
|
||||||
import io.github.wulkanowy.data.db.dao.ReportingUnitDao
|
import io.github.wulkanowy.data.db.dao.ReportingUnitDao
|
||||||
import io.github.wulkanowy.data.db.dao.SchoolAnnouncementDao
|
|
||||||
import io.github.wulkanowy.data.db.dao.SchoolDao
|
import io.github.wulkanowy.data.db.dao.SchoolDao
|
||||||
import io.github.wulkanowy.data.db.dao.SemesterDao
|
import io.github.wulkanowy.data.db.dao.SemesterDao
|
||||||
import io.github.wulkanowy.data.db.dao.StudentDao
|
import io.github.wulkanowy.data.db.dao.StudentDao
|
||||||
|
@ -35,8 +32,6 @@ import io.github.wulkanowy.data.db.dao.SubjectDao
|
||||||
import io.github.wulkanowy.data.db.dao.TeacherDao
|
import io.github.wulkanowy.data.db.dao.TeacherDao
|
||||||
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
|
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
|
||||||
import io.github.wulkanowy.data.db.dao.TimetableDao
|
import io.github.wulkanowy.data.db.dao.TimetableDao
|
||||||
import io.github.wulkanowy.data.db.dao.TimetableHeaderDao
|
|
||||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
|
||||||
import io.github.wulkanowy.data.db.entities.Attendance
|
import io.github.wulkanowy.data.db.entities.Attendance
|
||||||
import io.github.wulkanowy.data.db.entities.AttendanceSummary
|
import io.github.wulkanowy.data.db.entities.AttendanceSummary
|
||||||
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
||||||
|
@ -53,11 +48,9 @@ import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
||||||
import io.github.wulkanowy.data.db.entities.MobileDevice
|
import io.github.wulkanowy.data.db.entities.MobileDevice
|
||||||
import io.github.wulkanowy.data.db.entities.Note
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
import io.github.wulkanowy.data.db.entities.Notification
|
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||||
import io.github.wulkanowy.data.db.entities.School
|
import io.github.wulkanowy.data.db.entities.School
|
||||||
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.db.entities.StudentInfo
|
import io.github.wulkanowy.data.db.entities.StudentInfo
|
||||||
|
@ -65,7 +58,6 @@ import io.github.wulkanowy.data.db.entities.Subject
|
||||||
import io.github.wulkanowy.data.db.entities.Teacher
|
import io.github.wulkanowy.data.db.entities.Teacher
|
||||||
import io.github.wulkanowy.data.db.entities.Timetable
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||||
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration10
|
import io.github.wulkanowy.data.db.migrations.Migration10
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration11
|
import io.github.wulkanowy.data.db.migrations.Migration11
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration12
|
import io.github.wulkanowy.data.db.migrations.Migration12
|
||||||
|
@ -94,15 +86,7 @@ import io.github.wulkanowy.data.db.migrations.Migration32
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration33
|
import io.github.wulkanowy.data.db.migrations.Migration33
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration34
|
import io.github.wulkanowy.data.db.migrations.Migration34
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration35
|
import io.github.wulkanowy.data.db.migrations.Migration35
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration36
|
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration37
|
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration38
|
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration39
|
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration4
|
import io.github.wulkanowy.data.db.migrations.Migration4
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration40
|
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration41
|
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration42
|
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration43
|
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration5
|
import io.github.wulkanowy.data.db.migrations.Migration5
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration6
|
import io.github.wulkanowy.data.db.migrations.Migration6
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration7
|
import io.github.wulkanowy.data.db.migrations.Migration7
|
||||||
|
@ -140,10 +124,6 @@ import javax.inject.Singleton
|
||||||
Conference::class,
|
Conference::class,
|
||||||
TimetableAdditional::class,
|
TimetableAdditional::class,
|
||||||
StudentInfo::class,
|
StudentInfo::class,
|
||||||
TimetableHeader::class,
|
|
||||||
SchoolAnnouncement::class,
|
|
||||||
Notification::class,
|
|
||||||
AdminMessage::class
|
|
||||||
],
|
],
|
||||||
version = AppDatabase.VERSION_SCHEMA,
|
version = AppDatabase.VERSION_SCHEMA,
|
||||||
exportSchema = true
|
exportSchema = true
|
||||||
|
@ -152,7 +132,7 @@ import javax.inject.Singleton
|
||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val VERSION_SCHEMA = 43
|
const val VERSION_SCHEMA = 35
|
||||||
|
|
||||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
||||||
Migration2(),
|
Migration2(),
|
||||||
|
@ -188,15 +168,7 @@ abstract class AppDatabase : RoomDatabase() {
|
||||||
Migration32(),
|
Migration32(),
|
||||||
Migration33(),
|
Migration33(),
|
||||||
Migration34(),
|
Migration34(),
|
||||||
Migration35(appInfo),
|
Migration35(appInfo)
|
||||||
Migration36(),
|
|
||||||
Migration37(),
|
|
||||||
Migration38(),
|
|
||||||
Migration39(),
|
|
||||||
Migration40(),
|
|
||||||
Migration41(sharedPrefProvider),
|
|
||||||
Migration42(),
|
|
||||||
Migration43()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
fun newInstance(
|
fun newInstance(
|
||||||
|
@ -262,12 +234,4 @@ abstract class AppDatabase : RoomDatabase() {
|
||||||
abstract val timetableAdditionalDao: TimetableAdditionalDao
|
abstract val timetableAdditionalDao: TimetableAdditionalDao
|
||||||
|
|
||||||
abstract val studentInfoDao: StudentInfoDao
|
abstract val studentInfoDao: StudentInfoDao
|
||||||
|
|
||||||
abstract val timetableHeaderDao: TimetableHeaderDao
|
|
||||||
|
|
||||||
abstract val schoolAnnouncementDao: SchoolAnnouncementDao
|
|
||||||
|
|
||||||
abstract val notificationDao: NotificationDao
|
|
||||||
|
|
||||||
abstract val adminMessagesDao: AdminMessageDao
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
package io.github.wulkanowy.data.db
|
package io.github.wulkanowy.data.db
|
||||||
|
|
||||||
import androidx.room.TypeConverter
|
import androidx.room.TypeConverter
|
||||||
import kotlinx.serialization.SerializationException
|
import com.squareup.moshi.Moshi
|
||||||
import kotlinx.serialization.decodeFromString
|
import com.squareup.moshi.Types
|
||||||
import kotlinx.serialization.encodeToString
|
import io.github.wulkanowy.data.db.adapters.PairAdapterFactory
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
@ -14,7 +13,15 @@ import java.util.Date
|
||||||
|
|
||||||
class Converters {
|
class Converters {
|
||||||
|
|
||||||
private val json = Json
|
private val moshi by lazy { Moshi.Builder().add(PairAdapterFactory).build() }
|
||||||
|
|
||||||
|
private val integerListAdapter by lazy {
|
||||||
|
moshi.adapter<List<Int>>(Types.newParameterizedType(List::class.java, Integer::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
|
private val stringListPairAdapter by lazy {
|
||||||
|
moshi.adapter<List<Pair<String, String>>>(Types.newParameterizedType(List::class.java, Pair::class.java, String::class.java, String::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
fun timestampToDate(value: Long?): LocalDate? = value?.run {
|
fun timestampToDate(value: Long?): LocalDate? = value?.run {
|
||||||
|
@ -44,25 +51,21 @@ class Converters {
|
||||||
|
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
fun intListToJson(list: List<Int>): String {
|
fun intListToJson(list: List<Int>): String {
|
||||||
return json.encodeToString(list)
|
return integerListAdapter.toJson(list)
|
||||||
}
|
}
|
||||||
|
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
fun jsonToIntList(value: String): List<Int> {
|
fun jsonToIntList(value: String): List<Int> {
|
||||||
return json.decodeFromString(value)
|
return integerListAdapter.fromJson(value).orEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
fun stringPairListToJson(list: List<Pair<String, String>>): String {
|
fun stringPairListToJson(list: List<Pair<String, String>>): String {
|
||||||
return json.encodeToString(list)
|
return stringListPairAdapter.toJson(list)
|
||||||
}
|
}
|
||||||
|
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
fun jsonToStringPairList(value: String): List<Pair<String, String>> {
|
fun jsonToStringPairList(value: String): List<Pair<String, String>> {
|
||||||
return try {
|
return stringListPairAdapter.fromJson(value).orEmpty()
|
||||||
json.decodeFromString(value)
|
|
||||||
} catch (e: SerializationException) {
|
|
||||||
emptyList() // handle errors from old gson Pair serialized data
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,18 +20,9 @@ class SharedPrefProvider @Inject constructor(
|
||||||
|
|
||||||
fun getLong(key: String, defaultValue: Long) = sharedPref.getLong(key, defaultValue)
|
fun getLong(key: String, defaultValue: Long) = sharedPref.getLong(key, defaultValue)
|
||||||
|
|
||||||
fun getString(key: String) = sharedPref.getString(key, null)
|
fun getString(key: String, defaultValue: String): String = sharedPref.getString(key, defaultValue) ?: defaultValue
|
||||||
|
|
||||||
fun getString(key: String, defaultValue: String): String =
|
fun putString(key: String, value: String, sync: Boolean = false) {
|
||||||
sharedPref.getString(key, defaultValue) ?: defaultValue
|
|
||||||
|
|
||||||
fun getBoolean(key: String, defaultValue: Boolean): Boolean =
|
|
||||||
sharedPref.getBoolean(key, defaultValue)
|
|
||||||
|
|
||||||
fun putBoolean(key: String, value: Boolean, sync: Boolean = false) =
|
|
||||||
sharedPref.edit(sync) { putBoolean(key, value) }
|
|
||||||
|
|
||||||
fun putString(key: String, value: String?, sync: Boolean = false) {
|
|
||||||
sharedPref.edit(sync) { putString(key, value) }
|
sharedPref.edit(sync) { putString(key, value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
package io.github.wulkanowy.data.db.adapters
|
||||||
|
|
||||||
|
import com.squareup.moshi.JsonAdapter
|
||||||
|
import com.squareup.moshi.JsonReader
|
||||||
|
import com.squareup.moshi.JsonWriter
|
||||||
|
import com.squareup.moshi.Moshi
|
||||||
|
import com.squareup.moshi.Types
|
||||||
|
import java.lang.reflect.ParameterizedType
|
||||||
|
import java.lang.reflect.Type
|
||||||
|
|
||||||
|
object PairAdapterFactory : JsonAdapter.Factory {
|
||||||
|
|
||||||
|
override fun create(type: Type, annotations: MutableSet<out Annotation>, moshi: Moshi): JsonAdapter<*>? {
|
||||||
|
if (type !is ParameterizedType || List::class.java != type.rawType) return null
|
||||||
|
if (type.actualTypeArguments[0] != Pair::class.java) return null
|
||||||
|
|
||||||
|
val listType = Types.newParameterizedType(List::class.java, Map::class.java, String::class.java)
|
||||||
|
val listAdapter = moshi.adapter<List<Map<String, String>>>(listType)
|
||||||
|
|
||||||
|
val mapType = Types.newParameterizedType(MutableMap::class.java, String::class.java, String::class.java)
|
||||||
|
val mapAdapter = moshi.adapter<Map<String, String>>(mapType)
|
||||||
|
|
||||||
|
return PairAdapter(listAdapter, mapAdapter)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PairAdapter(
|
||||||
|
private val listAdapter: JsonAdapter<List<Map<String, String>>>,
|
||||||
|
private val mapAdapter: JsonAdapter<Map<String, String>>,
|
||||||
|
) : JsonAdapter<List<Pair<String, String>>>() {
|
||||||
|
|
||||||
|
override fun toJson(writer: JsonWriter, value: List<Pair<String, String>>?) {
|
||||||
|
writer.beginArray()
|
||||||
|
value?.forEach {
|
||||||
|
writer.beginObject()
|
||||||
|
writer.name("first").value(it.first)
|
||||||
|
writer.name("second").value(it.second)
|
||||||
|
writer.endObject()
|
||||||
|
}
|
||||||
|
writer.endArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fromJson(reader: JsonReader): List<Pair<String, String>>? {
|
||||||
|
return if (reader.peek() == JsonReader.Token.BEGIN_OBJECT) deserializeMoshiMap(reader)
|
||||||
|
else deserializeGsonPair(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
// for compatibility with 0.21.0
|
||||||
|
private fun deserializeMoshiMap(reader: JsonReader): List<Pair<String, String>>? {
|
||||||
|
val map = mapAdapter.fromJson(reader) ?: return null
|
||||||
|
|
||||||
|
return map.entries.map {
|
||||||
|
it.key to it.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deserializeGsonPair(reader: JsonReader): List<Pair<String, String>>? {
|
||||||
|
val list = listAdapter.fromJson(reader) ?: return null
|
||||||
|
|
||||||
|
return list.map {
|
||||||
|
require(it.size == 2) {
|
||||||
|
"pair with more or less than two elements: $list"
|
||||||
|
}
|
||||||
|
|
||||||
|
it["first"].orEmpty() to it["second"].orEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,25 +0,0 @@
|
||||||
package io.github.wulkanowy.data.db.dao
|
|
||||||
|
|
||||||
import androidx.room.Dao
|
|
||||||
import androidx.room.Query
|
|
||||||
import androidx.room.Transaction
|
|
||||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Dao
|
|
||||||
abstract class AdminMessageDao : BaseDao<AdminMessage> {
|
|
||||||
|
|
||||||
@Query("SELECT * FROM AdminMessages")
|
|
||||||
abstract fun loadAll(): Flow<List<AdminMessage>>
|
|
||||||
|
|
||||||
@Transaction
|
|
||||||
open suspend fun removeOldAndSaveNew(
|
|
||||||
oldMessages: List<AdminMessage>,
|
|
||||||
newMessages: List<AdminMessage>
|
|
||||||
) {
|
|
||||||
deleteAll(oldMessages)
|
|
||||||
insertAll(newMessages)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,11 +11,6 @@ import javax.inject.Singleton
|
||||||
@Dao
|
@Dao
|
||||||
interface AttendanceDao : BaseDao<Attendance> {
|
interface AttendanceDao : BaseDao<Attendance> {
|
||||||
|
|
||||||
@Query("SELECT * FROM Attendance WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :start AND date <= :end")
|
@Query("SELECT * FROM Attendance WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
|
||||||
fun loadAll(
|
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<Attendance>>
|
||||||
diaryId: Int,
|
|
||||||
studentId: Int,
|
|
||||||
start: LocalDate,
|
|
||||||
end: LocalDate
|
|
||||||
): Flow<List<Attendance>>
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,12 @@ import androidx.room.Dao
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import io.github.wulkanowy.data.db.entities.Conference
|
import io.github.wulkanowy.data.db.entities.Conference
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import java.time.LocalDateTime
|
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
@Singleton
|
@Singleton
|
||||||
interface ConferenceDao : BaseDao<Conference> {
|
interface ConferenceDao : BaseDao<Conference> {
|
||||||
|
|
||||||
@Query("SELECT * FROM Conferences WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :startDate")
|
@Query("SELECT * FROM Conferences WHERE diary_id = :diaryId AND student_id = :studentId")
|
||||||
fun loadAll(diaryId: Int, studentId: Int, startDate: LocalDateTime): Flow<List<Conference>>
|
fun loadAll(diaryId: Int, studentId: Int): Flow<List<Conference>>
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.Notification
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Dao
|
|
||||||
interface NotificationDao : BaseDao<Notification> {
|
|
||||||
|
|
||||||
@Query("SELECT * FROM Notifications WHERE student_id = :studentId OR student_id = -1")
|
|
||||||
fun loadAll(studentId: Long): Flow<List<Notification>>
|
|
||||||
}
|
|
|
@ -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.SchoolAnnouncement
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Dao
|
|
||||||
@Singleton
|
|
||||||
interface SchoolAnnouncementDao : BaseDao<SchoolAnnouncement> {
|
|
||||||
|
|
||||||
@Query("SELECT * FROM SchoolAnnouncements WHERE student_id = :studentId")
|
|
||||||
fun loadAll(studentId: Int): Flow<List<SchoolAnnouncement>>
|
|
||||||
}
|
|
|
@ -14,39 +14,33 @@ import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Dao
|
@Dao
|
||||||
abstract class StudentDao {
|
interface StudentDao {
|
||||||
|
|
||||||
@Insert(onConflict = ABORT)
|
@Insert(onConflict = ABORT)
|
||||||
abstract suspend fun insertAll(student: List<Student>): List<Long>
|
suspend fun insertAll(student: List<Student>): List<Long>
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
abstract suspend fun delete(student: Student)
|
suspend fun delete(student: Student)
|
||||||
|
|
||||||
@Update(entity = Student::class)
|
@Update(entity = Student::class)
|
||||||
abstract suspend fun update(studentNickAndAvatar: StudentNickAndAvatar)
|
suspend fun update(studentNickAndAvatar: StudentNickAndAvatar)
|
||||||
|
|
||||||
@Query("SELECT * FROM Students WHERE is_current = 1")
|
@Query("SELECT * FROM Students WHERE is_current = 1")
|
||||||
abstract suspend fun loadCurrent(): Student?
|
suspend fun loadCurrent(): Student?
|
||||||
|
|
||||||
@Query("SELECT * FROM Students WHERE id = :id")
|
@Query("SELECT * FROM Students WHERE id = :id")
|
||||||
abstract suspend fun loadById(id: Long): Student?
|
suspend fun loadById(id: Long): Student?
|
||||||
|
|
||||||
@Query("SELECT * FROM Students")
|
@Query("SELECT * FROM Students")
|
||||||
abstract suspend fun loadAll(): List<Student>
|
suspend fun loadAll(): List<Student>
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
@Query("SELECT * FROM Students")
|
@Query("SELECT * FROM Students")
|
||||||
abstract suspend fun loadStudentsWithSemesters(): List<StudentWithSemesters>
|
suspend fun loadStudentsWithSemesters(): List<StudentWithSemesters>
|
||||||
|
|
||||||
@Query("UPDATE Students SET is_current = 1 WHERE id = :id")
|
@Query("UPDATE Students SET is_current = 1 WHERE id = :id")
|
||||||
abstract suspend fun updateCurrent(id: Long)
|
suspend fun updateCurrent(id: Long)
|
||||||
|
|
||||||
@Query("UPDATE Students SET is_current = 0")
|
@Query("UPDATE Students SET is_current = 0")
|
||||||
abstract suspend fun resetCurrent()
|
suspend fun resetCurrent()
|
||||||
|
|
||||||
@Transaction
|
|
||||||
open suspend fun switchCurrent(id: Long) {
|
|
||||||
resetCurrent()
|
|
||||||
updateCurrent(id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.TimetableHeader
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import java.time.LocalDate
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Dao
|
|
||||||
@Singleton
|
|
||||||
interface TimetableHeaderDao : BaseDao<TimetableHeader> {
|
|
||||||
|
|
||||||
@Query("SELECT * FROM TimetableHeaders 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<TimetableHeader>>
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
package io.github.wulkanowy.data.db.entities
|
|
||||||
|
|
||||||
import androidx.room.ColumnInfo
|
|
||||||
import androidx.room.Entity
|
|
||||||
import androidx.room.PrimaryKey
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@Entity(tableName = "AdminMessages")
|
|
||||||
data class AdminMessage(
|
|
||||||
|
|
||||||
@PrimaryKey
|
|
||||||
val id: Int,
|
|
||||||
|
|
||||||
val title: String,
|
|
||||||
|
|
||||||
val content: String,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "version_name")
|
|
||||||
val versionMin: Int? = null,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "version_max")
|
|
||||||
val versionMax: Int? = null,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "target_register_host")
|
|
||||||
val targetRegisterHost: String? = null,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "target_flavor")
|
|
||||||
val targetFlavor: String? = null,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "destination_url")
|
|
||||||
val destinationUrl: String? = null,
|
|
||||||
|
|
||||||
val priority: String,
|
|
||||||
|
|
||||||
val type: String
|
|
||||||
)
|
|
|
@ -47,7 +47,4 @@ data class Attendance(
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
var id: Long = 0
|
var id: Long = 0
|
||||||
|
|
||||||
@ColumnInfo(name = "is_notified")
|
|
||||||
var isNotified: Boolean = true
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,4 @@ data class Conference(
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
var id: Long = 0
|
var id: Long = 0
|
||||||
|
|
||||||
@ColumnInfo(name = "is_notified")
|
|
||||||
var isNotified: Boolean = true
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,4 @@ data class Exam(
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
var id: Long = 0
|
var id: Long = 0
|
||||||
|
|
||||||
@ColumnInfo(name = "is_notified")
|
|
||||||
var isNotified: Boolean = true
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,10 +37,4 @@ data class Homework(
|
||||||
|
|
||||||
@ColumnInfo(name = "is_done")
|
@ColumnInfo(name = "is_done")
|
||||||
var isDone: Boolean = false
|
var isDone: Boolean = false
|
||||||
|
|
||||||
@ColumnInfo(name = "is_notified")
|
|
||||||
var isNotified: Boolean = true
|
|
||||||
|
|
||||||
@ColumnInfo(name = "is_added_by_user")
|
|
||||||
var isAddedByUser: Boolean = false
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
package io.github.wulkanowy.data.db.entities
|
|
||||||
|
|
||||||
import androidx.room.ColumnInfo
|
|
||||||
import androidx.room.Entity
|
|
||||||
import androidx.room.PrimaryKey
|
|
||||||
import io.github.wulkanowy.services.sync.notifications.NotificationType
|
|
||||||
import java.time.LocalDateTime
|
|
||||||
|
|
||||||
@Entity(tableName = "Notifications")
|
|
||||||
data class Notification(
|
|
||||||
|
|
||||||
@ColumnInfo(name = "student_id")
|
|
||||||
val studentId: Long,
|
|
||||||
|
|
||||||
val title: String,
|
|
||||||
|
|
||||||
val content: String,
|
|
||||||
|
|
||||||
val type: NotificationType,
|
|
||||||
|
|
||||||
val date: LocalDateTime,
|
|
||||||
|
|
||||||
val data: String? = null
|
|
||||||
) {
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
|
||||||
var id: Long = 0
|
|
||||||
}
|
|
|
@ -5,7 +5,6 @@ import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
@kotlinx.serialization.Serializable
|
|
||||||
@Entity(tableName = "Recipients")
|
@Entity(tableName = "Recipients")
|
||||||
data class Recipient(
|
data class Recipient(
|
||||||
|
|
||||||
|
|
|
@ -1,27 +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
|
|
||||||
|
|
||||||
@Entity(tableName = "SchoolAnnouncements")
|
|
||||||
data class SchoolAnnouncement(
|
|
||||||
|
|
||||||
@ColumnInfo(name = "student_id")
|
|
||||||
val studentId: Int,
|
|
||||||
|
|
||||||
val date: LocalDate,
|
|
||||||
|
|
||||||
val subject: String,
|
|
||||||
|
|
||||||
val content: String
|
|
||||||
) : Serializable {
|
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
|
||||||
var id: Long = 0
|
|
||||||
|
|
||||||
@ColumnInfo(name = "is_notified")
|
|
||||||
var isNotified: Boolean = true
|
|
||||||
}
|
|
|
@ -50,7 +50,4 @@ data class Timetable(
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
var id: Long = 0
|
var id: Long = 0
|
||||||
|
|
||||||
@ColumnInfo(name = "is_notified")
|
|
||||||
var isNotified: Boolean = true
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +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
|
|
||||||
|
|
||||||
@Entity(tableName = "TimetableHeaders")
|
|
||||||
data class TimetableHeader(
|
|
||||||
|
|
||||||
@ColumnInfo(name = "student_id")
|
|
||||||
val studentId: Int,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "diary_id")
|
|
||||||
val diaryId: Int,
|
|
||||||
|
|
||||||
val date: LocalDate,
|
|
||||||
|
|
||||||
val content: String,
|
|
||||||
) : Serializable {
|
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
|
||||||
var id: Long = 0
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package io.github.wulkanowy.data.db.migrations
|
|
||||||
|
|
||||||
import androidx.room.migration.Migration
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
|
||||||
|
|
||||||
class Migration36 : Migration(35, 36) {
|
|
||||||
|
|
||||||
override fun migrate(database: SupportSQLiteDatabase) {
|
|
||||||
database.execSQL("ALTER TABLE Exams ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
|
|
||||||
database.execSQL("ALTER TABLE Homework ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package io.github.wulkanowy.data.db.migrations
|
|
||||||
|
|
||||||
import androidx.room.migration.Migration
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
|
||||||
|
|
||||||
class Migration37 : Migration(36, 37) {
|
|
||||||
|
|
||||||
override fun migrate(database: SupportSQLiteDatabase) {
|
|
||||||
database.execSQL(
|
|
||||||
"""
|
|
||||||
CREATE TABLE IF NOT EXISTS TimetableHeaders (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
||||||
student_id INTEGER NOT NULL,
|
|
||||||
diary_id INTEGER NOT NULL,
|
|
||||||
date INTEGER NOT NULL,
|
|
||||||
content TEXT NOT NULL
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package io.github.wulkanowy.data.db.migrations
|
|
||||||
|
|
||||||
import androidx.room.migration.Migration
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
|
||||||
|
|
||||||
class Migration38 : Migration(37, 38) {
|
|
||||||
|
|
||||||
override fun migrate(database: SupportSQLiteDatabase) {
|
|
||||||
database.execSQL("""
|
|
||||||
CREATE TABLE IF NOT EXISTS `SchoolAnnouncements` (
|
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
||||||
`student_id` INTEGER NOT NULL,
|
|
||||||
`date` INTEGER NOT NULL,
|
|
||||||
`subject` TEXT NOT NULL,
|
|
||||||
`content` TEXT NOT NULL
|
|
||||||
)
|
|
||||||
""")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package io.github.wulkanowy.data.db.migrations
|
|
||||||
|
|
||||||
import androidx.room.migration.Migration
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
|
||||||
|
|
||||||
class Migration39 : Migration(38, 39) {
|
|
||||||
|
|
||||||
override fun migrate(database: SupportSQLiteDatabase) {
|
|
||||||
database.execSQL("ALTER TABLE Conferences ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
|
|
||||||
database.execSQL("ALTER TABLE SchoolAnnouncements ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package io.github.wulkanowy.data.db.migrations
|
|
||||||
|
|
||||||
import androidx.room.migration.Migration
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
|
||||||
|
|
||||||
class Migration40 : Migration(39, 40) {
|
|
||||||
|
|
||||||
override fun migrate(database: SupportSQLiteDatabase) {
|
|
||||||
database.execSQL(
|
|
||||||
"""
|
|
||||||
CREATE TABLE IF NOT EXISTS `Notifications` (
|
|
||||||
`student_id` INTEGER NOT NULL,
|
|
||||||
`title` TEXT NOT NULL,
|
|
||||||
`content` TEXT NOT NULL,
|
|
||||||
`type` TEXT NOT NULL,
|
|
||||||
`date` INTEGER NOT NULL,
|
|
||||||
`data` TEXT,
|
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package io.github.wulkanowy.data.db.migrations
|
|
||||||
|
|
||||||
import androidx.room.migration.Migration
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
|
||||||
import io.github.wulkanowy.ui.modules.grade.GradeExpandMode
|
|
||||||
|
|
||||||
class Migration41(private val sharedPrefProvider: SharedPrefProvider) : Migration(40, 41) {
|
|
||||||
|
|
||||||
override fun migrate(database: SupportSQLiteDatabase) {
|
|
||||||
migrateSharedPreferences()
|
|
||||||
database.execSQL("ALTER TABLE Homework ADD COLUMN is_added_by_user INTEGER NOT NULL DEFAULT 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateSharedPreferences() {
|
|
||||||
if (sharedPrefProvider.getBoolean("pref_key_expand_grade", false)) {
|
|
||||||
sharedPrefProvider.putString("pref_key_expand_grade_mode", GradeExpandMode.ALWAYS_EXPANDED.value)
|
|
||||||
}
|
|
||||||
sharedPrefProvider.delete("pref_key_expand_grade")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
package io.github.wulkanowy.data.db.migrations
|
|
||||||
|
|
||||||
import androidx.room.migration.Migration
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
|
||||||
|
|
||||||
class Migration42 : Migration(41, 42) {
|
|
||||||
|
|
||||||
override fun migrate(database: SupportSQLiteDatabase) {
|
|
||||||
database.execSQL(
|
|
||||||
"""CREATE TABLE IF NOT EXISTS `AdminMessages` (
|
|
||||||
`id` INTEGER NOT NULL,
|
|
||||||
`title` TEXT NOT NULL,
|
|
||||||
`content` TEXT NOT NULL,
|
|
||||||
`version_name` INTEGER,
|
|
||||||
`version_max` INTEGER,
|
|
||||||
`target_register_host` TEXT,
|
|
||||||
`target_flavor` TEXT,
|
|
||||||
`destination_url` TEXT,
|
|
||||||
`priority` TEXT NOT NULL,
|
|
||||||
`type` TEXT NOT NULL,
|
|
||||||
PRIMARY KEY(`id`))"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package io.github.wulkanowy.data.db.migrations
|
|
||||||
|
|
||||||
import androidx.room.migration.Migration
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
|
||||||
|
|
||||||
class Migration43 : Migration(42, 43) {
|
|
||||||
|
|
||||||
override fun migrate(database: SupportSQLiteDatabase) {
|
|
||||||
database.execSQL("ALTER TABLE Timetable ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
|
|
||||||
database.execSQL("ALTER TABLE Attendance ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
package io.github.wulkanowy.data.mappers
|
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import io.github.wulkanowy.sdk.pojo.DirectorInformation as SdkDirectorInformation
|
|
||||||
|
|
||||||
fun List<SdkDirectorInformation>.mapToEntities(student: Student) = map {
|
|
||||||
SchoolAnnouncement(
|
|
||||||
studentId = student.studentId,
|
|
||||||
date = it.date,
|
|
||||||
subject = it.subject,
|
|
||||||
content = it.content,
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -3,19 +3,9 @@ package io.github.wulkanowy.data.mappers
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Timetable
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||||
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
|
||||||
import io.github.wulkanowy.data.pojos.TimetableFull
|
|
||||||
import io.github.wulkanowy.sdk.pojo.TimetableFull as SdkTimetableFull
|
|
||||||
import io.github.wulkanowy.sdk.pojo.TimetableDayHeader as SdkTimetableHeader
|
|
||||||
import io.github.wulkanowy.sdk.pojo.Timetable as SdkTimetable
|
import io.github.wulkanowy.sdk.pojo.Timetable as SdkTimetable
|
||||||
import io.github.wulkanowy.sdk.pojo.TimetableAdditional as SdkTimetableAdditional
|
import io.github.wulkanowy.sdk.pojo.TimetableAdditional as SdkTimetableAdditional
|
||||||
|
|
||||||
fun SdkTimetableFull.mapToEntities(semester: Semester) = TimetableFull(
|
|
||||||
lessons = lessons.mapToEntities(semester),
|
|
||||||
additional = additional.mapToEntities(semester),
|
|
||||||
headers = headers.mapToEntities(semester)
|
|
||||||
)
|
|
||||||
|
|
||||||
fun List<SdkTimetable>.mapToEntities(semester: Semester) = map {
|
fun List<SdkTimetable>.mapToEntities(semester: Semester) = map {
|
||||||
Timetable(
|
Timetable(
|
||||||
studentId = semester.studentId,
|
studentId = semester.studentId,
|
||||||
|
@ -49,13 +39,3 @@ fun List<SdkTimetableAdditional>.mapToEntities(semester: Semester) = map {
|
||||||
end = it.end
|
end = it.end
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("mapToEntitiesTimetableHeaders")
|
|
||||||
fun List<SdkTimetableHeader>.mapToEntities(semester: Semester) = map {
|
|
||||||
TimetableHeader(
|
|
||||||
studentId = semester.studentId,
|
|
||||||
diaryId = semester.diaryId,
|
|
||||||
date = it.date,
|
|
||||||
content = it.content
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package io.github.wulkanowy.data.pojos
|
package io.github.wulkanowy.data.pojos
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
@Serializable
|
@JsonClass(generateAdapter = true)
|
||||||
class Contributor(
|
class Contributor(
|
||||||
val displayName: String,
|
val displayName: String,
|
||||||
val githubUsername: String
|
val githubUsername: String
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
package io.github.wulkanowy.data.pojos
|
|
||||||
|
|
||||||
import io.github.wulkanowy.ui.modules.message.send.RecipientChipItem
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class MessageDraft(
|
|
||||||
val recipients: List<RecipientChipItem>,
|
|
||||||
val subject: String,
|
|
||||||
val content: String,
|
|
||||||
)
|
|
|
@ -1,19 +0,0 @@
|
||||||
package io.github.wulkanowy.data.pojos
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import io.github.wulkanowy.services.sync.notifications.NotificationType
|
|
||||||
|
|
||||||
data class NotificationData(
|
|
||||||
val intentToStart: Intent,
|
|
||||||
val title: String,
|
|
||||||
val content: String
|
|
||||||
)
|
|
||||||
|
|
||||||
data class GroupNotificationData(
|
|
||||||
val notificationDataList: List<NotificationData>,
|
|
||||||
val title: String,
|
|
||||||
val content: String,
|
|
||||||
val intentToStart: Intent,
|
|
||||||
val type: NotificationType
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
package io.github.wulkanowy.data.pojos
|
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.Timetable
|
|
||||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
|
||||||
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
|
||||||
|
|
||||||
data class TimetableFull(
|
|
||||||
val lessons: List<Timetable>,
|
|
||||||
val additional: List<TimetableAdditional>,
|
|
||||||
val headers: List<TimetableHeader>,
|
|
||||||
)
|
|
|
@ -1,52 +0,0 @@
|
||||||
package io.github.wulkanowy.data.repositories
|
|
||||||
|
|
||||||
import io.github.wulkanowy.data.api.AdminMessageService
|
|
||||||
import io.github.wulkanowy.data.db.dao.AdminMessageDao
|
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import io.github.wulkanowy.utils.AppInfo
|
|
||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
|
||||||
import io.github.wulkanowy.utils.networkBoundResource
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
class AdminMessageRepository @Inject constructor(
|
|
||||||
private val adminMessageService: AdminMessageService,
|
|
||||||
private val adminMessageDao: AdminMessageDao,
|
|
||||||
private val appInfo: AppInfo,
|
|
||||||
private val refreshHelper: AutoRefreshHelper,
|
|
||||||
) {
|
|
||||||
private val saveFetchResultMutex = Mutex()
|
|
||||||
|
|
||||||
private val cacheKey = "admin_messages"
|
|
||||||
|
|
||||||
suspend fun getAdminMessages(student: Student, forceRefresh: Boolean) = networkBoundResource(
|
|
||||||
mutex = saveFetchResultMutex,
|
|
||||||
query = { adminMessageDao.loadAll() },
|
|
||||||
fetch = { adminMessageService.getAdminMessages() },
|
|
||||||
shouldFetch = {
|
|
||||||
refreshHelper.shouldBeRefreshed(cacheKey) || forceRefresh
|
|
||||||
},
|
|
||||||
saveFetchResult = { oldItems, newItems ->
|
|
||||||
adminMessageDao.removeOldAndSaveNew(oldItems, newItems)
|
|
||||||
refreshHelper.updateLastRefreshTimestamp(cacheKey)
|
|
||||||
},
|
|
||||||
showSavedOnLoading = false,
|
|
||||||
mapResult = { adminMessages ->
|
|
||||||
adminMessages.filter { adminMessage ->
|
|
||||||
val isCorrectRegister = adminMessage.targetRegisterHost?.let {
|
|
||||||
student.scrapperBaseUrl.contains(it, true)
|
|
||||||
} ?: true
|
|
||||||
val isCorrectFlavor =
|
|
||||||
adminMessage.targetFlavor?.equals(appInfo.buildFlavor, true) ?: true
|
|
||||||
val isCorrectMaxVersion =
|
|
||||||
adminMessage.versionMax?.let { it >= appInfo.versionCode } ?: true
|
|
||||||
val isCorrectMinVersion =
|
|
||||||
adminMessage.versionMin?.let { it <= appInfo.versionCode } ?: true
|
|
||||||
|
|
||||||
isCorrectRegister && isCorrectFlavor && isCorrectMaxVersion && isCorrectMinVersion
|
|
||||||
}.maxByOrNull { it.id }
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,27 +1,24 @@
|
||||||
package io.github.wulkanowy.data.repositories
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.res.AssetManager
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import com.squareup.moshi.Moshi
|
||||||
|
import com.squareup.moshi.Types
|
||||||
import io.github.wulkanowy.data.pojos.Contributor
|
import io.github.wulkanowy.data.pojos.Contributor
|
||||||
import io.github.wulkanowy.utils.DispatchersProvider
|
import io.github.wulkanowy.utils.DispatchersProvider
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import kotlinx.serialization.json.decodeFromStream
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class AppCreatorRepository @Inject constructor(
|
class AppCreatorRepository @Inject constructor(
|
||||||
@ApplicationContext private val context: Context,
|
private val assets: AssetManager,
|
||||||
private val dispatchers: DispatchersProvider,
|
private val dispatchers: DispatchersProvider
|
||||||
private val json: Json,
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
suspend fun getAppCreators() = withContext(dispatchers.backgroundThread) {
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
val moshi = Moshi.Builder().build()
|
||||||
suspend fun getAppCreators() = withContext(dispatchers.io) {
|
val type = Types.newParameterizedType(List::class.java, Contributor::class.java)
|
||||||
val inputStream = context.assets.open("contributors.json").buffered()
|
val adapter = moshi.adapter<List<Contributor>>(type)
|
||||||
json.decodeFromStream<List<Contributor>>(inputStream)
|
adapter.fromJson(assets.open("contributors.json").bufferedReader().use { it.readText() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ import io.github.wulkanowy.utils.monday
|
||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
import io.github.wulkanowy.utils.sunday
|
import io.github.wulkanowy.utils.sunday
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
@ -33,24 +32,10 @@ class AttendanceRepository @Inject constructor(
|
||||||
|
|
||||||
private val cacheKey = "attendance"
|
private val cacheKey = "attendance"
|
||||||
|
|
||||||
fun getAttendance(
|
fun getAttendance(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
|
||||||
student: Student,
|
|
||||||
semester: Semester,
|
|
||||||
start: LocalDate,
|
|
||||||
end: LocalDate,
|
|
||||||
forceRefresh: Boolean,
|
|
||||||
notify: Boolean = false,
|
|
||||||
) = networkBoundResource(
|
|
||||||
mutex = saveFetchResultMutex,
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = {
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
||||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday) },
|
||||||
key = getRefreshKey(cacheKey, semester, start, end)
|
|
||||||
)
|
|
||||||
it.isEmpty() || forceRefresh || isExpired
|
|
||||||
},
|
|
||||||
query = {
|
|
||||||
attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)
|
|
||||||
},
|
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||||
.getAttendance(start.monday, end.sunday, semester.semesterId)
|
.getAttendance(start.monday, end.sunday, semester.semesterId)
|
||||||
|
@ -58,39 +43,19 @@ class AttendanceRepository @Inject constructor(
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
attendanceDb.deleteAll(old uniqueSubtract new)
|
attendanceDb.deleteAll(old uniqueSubtract new)
|
||||||
val attendanceToAdd = (new uniqueSubtract old).map { newAttendance ->
|
attendanceDb.insertAll(new uniqueSubtract old)
|
||||||
newAttendance.apply { if (notify) isNotified = false }
|
|
||||||
}
|
|
||||||
attendanceDb.insertAll(attendanceToAdd)
|
|
||||||
|
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
|
||||||
},
|
},
|
||||||
filterResult = { it.filter { item -> item.date in start..end } }
|
filterResult = { it.filter { item -> item.date in start..end } }
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getAttendanceFromDatabase(
|
suspend fun excuseForAbsence(student: Student, semester: Semester, absenceList: List<Attendance>, reason: String? = null) {
|
||||||
semester: Semester,
|
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).excuseForAbsence(absenceList.map { attendance ->
|
||||||
start: LocalDate,
|
|
||||||
end: LocalDate
|
|
||||||
): Flow<List<Attendance>> {
|
|
||||||
return attendanceDb.loadAll(semester.diaryId, semester.studentId, start, end)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun updateTimetable(timetable: List<Attendance>) {
|
|
||||||
return attendanceDb.updateAll(timetable)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun excuseForAbsence(
|
|
||||||
student: Student, semester: Semester,
|
|
||||||
absenceList: List<Attendance>, reason: String? = null
|
|
||||||
) {
|
|
||||||
val items = absenceList.map { attendance ->
|
|
||||||
Absent(
|
Absent(
|
||||||
date = LocalDateTime.of(attendance.date, LocalTime.of(0, 0)),
|
date = LocalDateTime.of(attendance.date, LocalTime.of(0, 0)),
|
||||||
timeId = attendance.timeId
|
timeId = attendance.timeId
|
||||||
)
|
)
|
||||||
}
|
}, reason)
|
||||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
|
||||||
.excuseForAbsence(items, reason)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,17 +25,9 @@ class AttendanceSummaryRepository @Inject constructor(
|
||||||
|
|
||||||
private val cacheKey = "attendance_summary"
|
private val cacheKey = "attendance_summary"
|
||||||
|
|
||||||
fun getAttendanceSummary(
|
fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int, forceRefresh: Boolean) = networkBoundResource(
|
||||||
student: Student,
|
|
||||||
semester: Semester,
|
|
||||||
subjectId: Int,
|
|
||||||
forceRefresh: Boolean,
|
|
||||||
) = networkBoundResource(
|
|
||||||
mutex = saveFetchResultMutex,
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = {
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
|
||||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
|
||||||
it.isEmpty() || forceRefresh || isExpired
|
|
||||||
},
|
|
||||||
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId) },
|
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||||
|
|
|
@ -28,28 +28,10 @@ class CompletedLessonsRepository @Inject constructor(
|
||||||
|
|
||||||
private val cacheKey = "completed"
|
private val cacheKey = "completed"
|
||||||
|
|
||||||
fun getCompletedLessons(
|
fun getCompletedLessons(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
|
||||||
student: Student,
|
|
||||||
semester: Semester,
|
|
||||||
start: LocalDate,
|
|
||||||
end: LocalDate,
|
|
||||||
forceRefresh: Boolean,
|
|
||||||
) = networkBoundResource(
|
|
||||||
mutex = saveFetchResultMutex,
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = {
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
||||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
query = { completedLessonsDb.loadAll(semester.studentId, semester.diaryId, start.monday, end.sunday) },
|
||||||
key = getRefreshKey(cacheKey, semester, start, end)
|
|
||||||
)
|
|
||||||
it.isEmpty() || forceRefresh || isExpired
|
|
||||||
},
|
|
||||||
query = {
|
|
||||||
completedLessonsDb.loadAll(
|
|
||||||
studentId = semester.studentId,
|
|
||||||
diaryId = semester.diaryId,
|
|
||||||
from = start.monday,
|
|
||||||
end = end.sunday
|
|
||||||
)
|
|
||||||
},
|
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||||
.getCompletedLessons(start.monday, end.sunday)
|
.getCompletedLessons(start.monday, end.sunday)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package io.github.wulkanowy.data.repositories
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.dao.ConferenceDao
|
import io.github.wulkanowy.data.db.dao.ConferenceDao
|
||||||
import io.github.wulkanowy.data.db.entities.Conference
|
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
|
@ -11,11 +10,7 @@ import io.github.wulkanowy.utils.getRefreshKey
|
||||||
import io.github.wulkanowy.utils.init
|
import io.github.wulkanowy.utils.init
|
||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import java.time.Instant
|
|
||||||
import java.time.LocalDateTime
|
|
||||||
import java.time.ZoneOffset
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@ -30,44 +25,19 @@ class ConferenceRepository @Inject constructor(
|
||||||
|
|
||||||
private val cacheKey = "conference"
|
private val cacheKey = "conference"
|
||||||
|
|
||||||
fun getConferences(
|
fun getConferences(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
|
||||||
student: Student,
|
|
||||||
semester: Semester,
|
|
||||||
forceRefresh: Boolean,
|
|
||||||
notify: Boolean = false,
|
|
||||||
startDate: LocalDateTime = LocalDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC),
|
|
||||||
) = networkBoundResource(
|
|
||||||
mutex = saveFetchResultMutex,
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = {
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
|
||||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
query = { conferenceDb.loadAll(semester.diaryId, student.studentId) },
|
||||||
it.isEmpty() || forceRefresh || isExpired
|
|
||||||
},
|
|
||||||
query = {
|
|
||||||
conferenceDb.loadAll(semester.diaryId, student.studentId, startDate)
|
|
||||||
},
|
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||||
.getConferences()
|
.getConferences()
|
||||||
.mapToEntities(semester)
|
.mapToEntities(semester)
|
||||||
.filter { it.date >= startDate }
|
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
val conferencesToSave = (new uniqueSubtract old).onEach {
|
|
||||||
if (notify) it.isNotified = false
|
|
||||||
}
|
|
||||||
|
|
||||||
conferenceDb.deleteAll(old uniqueSubtract new)
|
conferenceDb.deleteAll(old uniqueSubtract new)
|
||||||
conferenceDb.insertAll(conferencesToSave)
|
conferenceDb.insertAll(new uniqueSubtract old)
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getConferenceFromDatabase(semester: Semester): Flow<List<Conference>> =
|
|
||||||
conferenceDb.loadAll(
|
|
||||||
diaryId = semester.diaryId,
|
|
||||||
studentId = semester.studentId,
|
|
||||||
startDate = LocalDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC)
|
|
||||||
)
|
|
||||||
|
|
||||||
suspend fun updateConference(conference: List<Conference>) = conferenceDb.updateAll(conference)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package io.github.wulkanowy.data.repositories
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.dao.ExamDao
|
import io.github.wulkanowy.data.db.dao.ExamDao
|
||||||
import io.github.wulkanowy.data.db.entities.Exam
|
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
|
@ -13,7 +12,6 @@ import io.github.wulkanowy.utils.init
|
||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
import io.github.wulkanowy.utils.startExamsDay
|
import io.github.wulkanowy.utils.startExamsDay
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -30,54 +28,20 @@ class ExamRepository @Inject constructor(
|
||||||
|
|
||||||
private val cacheKey = "exam"
|
private val cacheKey = "exam"
|
||||||
|
|
||||||
fun getExams(
|
fun getExams(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
|
||||||
student: Student,
|
|
||||||
semester: Semester,
|
|
||||||
start: LocalDate,
|
|
||||||
end: LocalDate,
|
|
||||||
forceRefresh: Boolean,
|
|
||||||
notify: Boolean = false,
|
|
||||||
) = networkBoundResource(
|
|
||||||
mutex = saveFetchResultMutex,
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = {
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
||||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
query = { examDb.loadAll(semester.diaryId, semester.studentId, start.startExamsDay, start.endExamsDay) },
|
||||||
key = getRefreshKey(cacheKey, semester, start, end)
|
|
||||||
)
|
|
||||||
it.isEmpty() || forceRefresh || isExpired
|
|
||||||
},
|
|
||||||
query = {
|
|
||||||
examDb.loadAll(
|
|
||||||
diaryId = semester.diaryId,
|
|
||||||
studentId = semester.studentId,
|
|
||||||
from = start.startExamsDay,
|
|
||||||
end = start.endExamsDay
|
|
||||||
)
|
|
||||||
},
|
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||||
.getExams(start.startExamsDay, start.endExamsDay, semester.semesterId)
|
.getExams(start.startExamsDay, start.endExamsDay, semester.semesterId)
|
||||||
.mapToEntities(semester)
|
.mapToEntities(semester)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
val examsToSave = (new uniqueSubtract old).onEach {
|
|
||||||
if (notify) it.isNotified = false
|
|
||||||
}
|
|
||||||
|
|
||||||
examDb.deleteAll(old uniqueSubtract new)
|
examDb.deleteAll(old uniqueSubtract new)
|
||||||
examDb.insertAll(examsToSave)
|
examDb.insertAll(new uniqueSubtract old)
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
|
||||||
},
|
},
|
||||||
filterResult = { it.filter { item -> item.date in start..end } }
|
filterResult = { it.filter { item -> item.date in start..end } }
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getExamsFromDatabase(semester: Semester, start: LocalDate): Flow<List<Exam>> {
|
|
||||||
return examDb.loadAll(
|
|
||||||
diaryId = semester.diaryId,
|
|
||||||
studentId = semester.studentId,
|
|
||||||
from = start.startExamsDay,
|
|
||||||
end = start.endExamsDay
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun updateExam(exam: List<Exam>) = examDb.updateAll(exam)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,16 +33,11 @@ class GradeRepository @Inject constructor(
|
||||||
|
|
||||||
private val cacheKey = "grade"
|
private val cacheKey = "grade"
|
||||||
|
|
||||||
fun getGrades(
|
fun getGrades(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
|
||||||
student: Student,
|
|
||||||
semester: Semester,
|
|
||||||
forceRefresh: Boolean,
|
|
||||||
notify: Boolean = false,
|
|
||||||
) = networkBoundResource(
|
|
||||||
mutex = saveFetchResultMutex,
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { (details, summaries) ->
|
shouldFetch = { (details, summaries) ->
|
||||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
val isShouldBeRefreshed = refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||||
details.isEmpty() || summaries.isEmpty() || forceRefresh || isExpired
|
details.isEmpty() || summaries.isEmpty() || forceRefresh || isShouldBeRefreshed
|
||||||
},
|
},
|
||||||
query = {
|
query = {
|
||||||
val detailsFlow = gradeDb.loadAll(semester.semesterId, semester.studentId)
|
val detailsFlow = gradeDb.loadAll(semester.semesterId, semester.studentId)
|
||||||
|
@ -64,14 +59,8 @@ class GradeRepository @Inject constructor(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
private suspend fun refreshGradeDetails(
|
private suspend fun refreshGradeDetails(student: Student, oldGrades: List<Grade>, newDetails: List<Grade>, notify: Boolean) {
|
||||||
student: Student,
|
val notifyBreakDate = oldGrades.maxByOrNull { it.date }?.date ?: student.registrationDate.toLocalDate()
|
||||||
oldGrades: List<Grade>,
|
|
||||||
newDetails: List<Grade>,
|
|
||||||
notify: Boolean
|
|
||||||
) {
|
|
||||||
val notifyBreakDate = oldGrades.maxByOrNull {it.date }
|
|
||||||
?.date ?: student.registrationDate.toLocalDate()
|
|
||||||
gradeDb.deleteAll(oldGrades uniqueSubtract newDetails)
|
gradeDb.deleteAll(oldGrades uniqueSubtract newDetails)
|
||||||
gradeDb.insertAll((newDetails uniqueSubtract oldGrades).onEach {
|
gradeDb.insertAll((newDetails uniqueSubtract oldGrades).onEach {
|
||||||
if (it.date >= notifyBreakDate) it.apply {
|
if (it.date >= notifyBreakDate) it.apply {
|
||||||
|
@ -81,14 +70,10 @@ class GradeRepository @Inject constructor(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun refreshGradeSummaries(
|
private suspend fun refreshGradeSummaries(oldSummaries: List<GradeSummary>, newSummary: List<GradeSummary>, notify: Boolean) {
|
||||||
oldSummaries: List<GradeSummary>,
|
|
||||||
newSummary: List<GradeSummary>,
|
|
||||||
notify: Boolean
|
|
||||||
) {
|
|
||||||
gradeSummaryDb.deleteAll(oldSummaries uniqueSubtract newSummary)
|
gradeSummaryDb.deleteAll(oldSummaries uniqueSubtract newSummary)
|
||||||
gradeSummaryDb.insertAll((newSummary uniqueSubtract oldSummaries).onEach { summary ->
|
gradeSummaryDb.insertAll((newSummary uniqueSubtract oldSummaries).onEach { summary ->
|
||||||
val oldSummary = oldSummaries.find { old -> old.subject == summary.subject }
|
val oldSummary = oldSummaries.find { oldSummary -> oldSummary.subject == summary.subject }
|
||||||
summary.isPredictedGradeNotified = when {
|
summary.isPredictedGradeNotified = when {
|
||||||
summary.predictedGrade.isEmpty() -> true
|
summary.predictedGrade.isEmpty() -> true
|
||||||
notify && oldSummary?.predictedGrade != summary.predictedGrade -> false
|
notify && oldSummary?.predictedGrade != summary.predictedGrade -> false
|
||||||
|
@ -119,16 +104,22 @@ class GradeRepository @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getGradesFromDatabase(semester: Semester): Flow<List<Grade>> {
|
fun getNotNotifiedGrades(semester: Semester): Flow<List<Grade>> {
|
||||||
return gradeDb.loadAll(semester.semesterId, semester.studentId)
|
return gradeDb.loadAll(semester.semesterId, semester.studentId).map {
|
||||||
|
it.filter { grade -> !grade.isNotified }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getGradesPredictedFromDatabase(semester: Semester): Flow<List<GradeSummary>> {
|
fun getNotNotifiedPredictedGrades(semester: Semester): Flow<List<GradeSummary>> {
|
||||||
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)
|
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).map {
|
||||||
|
it.filter { gradeSummary -> !gradeSummary.isPredictedGradeNotified }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getGradesFinalFromDatabase(semester: Semester): Flow<List<GradeSummary>> {
|
fun getNotNotifiedFinalGrades(semester: Semester): Flow<List<GradeSummary>> {
|
||||||
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)
|
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).map {
|
||||||
|
it.filter { gradeSummary -> !gradeSummary.isFinalGradeNotified }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateGrade(grade: Grade) {
|
suspend fun updateGrade(grade: Grade) {
|
||||||
|
|
|
@ -39,19 +39,9 @@ class GradeStatisticsRepository @Inject constructor(
|
||||||
private val semesterCacheKey = "grade_stats_semester"
|
private val semesterCacheKey = "grade_stats_semester"
|
||||||
private val pointsCacheKey = "grade_stats_points"
|
private val pointsCacheKey = "grade_stats_points"
|
||||||
|
|
||||||
fun getGradesPartialStatistics(
|
fun getGradesPartialStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
|
||||||
student: Student,
|
|
||||||
semester: Semester,
|
|
||||||
subjectName: String,
|
|
||||||
forceRefresh: Boolean,
|
|
||||||
) = networkBoundResource(
|
|
||||||
mutex = partialMutex,
|
mutex = partialMutex,
|
||||||
shouldFetch = {
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(partialCacheKey, semester)) },
|
||||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
|
||||||
key = getRefreshKey(partialCacheKey, semester)
|
|
||||||
)
|
|
||||||
it.isEmpty() || forceRefresh || isExpired
|
|
||||||
},
|
|
||||||
query = { gradePartialStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
|
query = { gradePartialStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||||
|
@ -86,19 +76,9 @@ class GradeStatisticsRepository @Inject constructor(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getGradesSemesterStatistics(
|
fun getGradesSemesterStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
|
||||||
student: Student,
|
|
||||||
semester: Semester,
|
|
||||||
subjectName: String,
|
|
||||||
forceRefresh: Boolean,
|
|
||||||
) = networkBoundResource(
|
|
||||||
mutex = semesterMutex,
|
mutex = semesterMutex,
|
||||||
shouldFetch = {
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(semesterCacheKey, semester)) },
|
||||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
|
||||||
key = getRefreshKey(semesterCacheKey, semester)
|
|
||||||
)
|
|
||||||
it.isEmpty() || forceRefresh || isExpired
|
|
||||||
},
|
|
||||||
query = { gradeSemesterStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
|
query = { gradeSemesterStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||||
|
@ -114,12 +94,10 @@ class GradeStatisticsRepository @Inject constructor(
|
||||||
val itemsWithAverage = items.map { item ->
|
val itemsWithAverage = items.map { item ->
|
||||||
item.copy().apply {
|
item.copy().apply {
|
||||||
val denominator = item.amounts.sum()
|
val denominator = item.amounts.sum()
|
||||||
average = if (denominator == 0) "" else {
|
average = if (denominator == 0) "" else (item.amounts.mapIndexed { gradeValue, amount ->
|
||||||
(item.amounts.mapIndexed { gradeValue, amount ->
|
(gradeValue + 1) * amount
|
||||||
(gradeValue + 1) * amount
|
}.sum().toDouble() / denominator).let {
|
||||||
}.sum().toDouble() / denominator).let {
|
"%.2f".format(Locale.FRANCE, it)
|
||||||
"%.2f".format(Locale.FRANCE, it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,9 +109,7 @@ class GradeStatisticsRepository @Inject constructor(
|
||||||
amounts = itemsWithAverage.map { it.amounts }.sumGradeAmounts(),
|
amounts = itemsWithAverage.map { it.amounts }.sumGradeAmounts(),
|
||||||
studentGrade = 0
|
studentGrade = 0
|
||||||
).apply {
|
).apply {
|
||||||
average = itemsWithAverage.mapNotNull {
|
average = itemsWithAverage.mapNotNull { it.average.replace(",", ".").toDoubleOrNull() }.average().let {
|
||||||
it.average.replace(",", ".").toDoubleOrNull()
|
|
||||||
}.average().let {
|
|
||||||
"%.2f".format(Locale.FRANCE, it)
|
"%.2f".format(Locale.FRANCE, it)
|
||||||
}
|
}
|
||||||
}).reversed()
|
}).reversed()
|
||||||
|
@ -142,17 +118,9 @@ class GradeStatisticsRepository @Inject constructor(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getGradesPointsStatistics(
|
fun getGradesPointsStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
|
||||||
student: Student,
|
|
||||||
semester: Semester,
|
|
||||||
subjectName: String,
|
|
||||||
forceRefresh: Boolean,
|
|
||||||
) = networkBoundResource(
|
|
||||||
mutex = pointsMutex,
|
mutex = pointsMutex,
|
||||||
shouldFetch = {
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(pointsCacheKey, semester)) },
|
||||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(pointsCacheKey, semester))
|
|
||||||
it.isEmpty() || forceRefresh || isExpired
|
|
||||||
},
|
|
||||||
query = { gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
|
query = { gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||||
|
|