Compare commits
No commits in common. "1.2.1" and "1.1.3" 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ć
|
||||
|
||||
|
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
|
74
.github/workflows/deploy-store.yml
vendored
|
@ -1,74 +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/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-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/key.p12.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_KEY_ALIAS: ${{ secrets.PLAY_KEY_ALIAS }}
|
||||
PLAY_KEY_PASSWORD: ${{ secrets.PLAY_KEY_PASSWORD }}
|
||||
PLAY_STORE_PASSWORD: ${{ secrets.PLAY_STORE_PASSWORD }}
|
||||
run: ./gradlew assembleHmsRelease --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:
|
||||
push:
|
||||
branches: [ master, develop ]
|
||||
branches: [ develop ]
|
||||
tags: [ '*' ]
|
||||
pull_request:
|
||||
branches: [ master, develop ]
|
||||
branches: [ develop ]
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
unit-tests:
|
||||
|
@ -27,8 +29,174 @@ jobs:
|
|||
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||
- name: Unit tests
|
||||
run: |
|
||||
./gradlew testFdroidDebugUnitTest --stacktrace
|
||||
./gradlew jacocoTestReport --stacktrace
|
||||
./gradlew --build-cache -Pcoverage testFdroidDebugUnitTest --stacktrace
|
||||
./gradlew --build-cache -Pcoverage jacocoTestReport --stacktrace
|
||||
- uses: codecov/codecov-action@v1
|
||||
with:
|
||||
flags: unit
|
||||
|
||||
deploy-google-play:
|
||||
name: Deploy to google play
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
environment: google-play
|
||||
needs: [ unit-tests ]
|
||||
if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||
- name: Decrypt keys
|
||||
env:
|
||||
ENCRYPT_KEY: ${{ secrets.ENCRYPT_KEY }}
|
||||
SERVICES_ENCRYPT_KEY: ${{ secrets.SERVICES_ENCRYPT_KEY }}
|
||||
run: |
|
||||
gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/google-services.json.gpg
|
||||
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/key.p12.gpg
|
||||
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg
|
||||
- name: Upload apk to google play
|
||||
env:
|
||||
PLAY_KEY_ALIAS: ${{ secrets.PLAY_KEY_ALIAS }}
|
||||
PLAY_KEY_PASSWORD: ${{ secrets.PLAY_KEY_PASSWORD }}
|
||||
PLAY_SERVICE_ACCOUNT_EMAIL: ${{ secrets.PLAY_SERVICE_ACCOUNT_EMAIL }}
|
||||
PLAY_STORE_PASSWORD: ${{ secrets.PLAY_STORE_PASSWORD }}
|
||||
run: ./gradlew publishPlayRelease -PenableFirebase --stacktrace;
|
||||
|
||||
deploy-appcenter:
|
||||
name: Deploy to App Center
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
environment: app-center
|
||||
if: github.ref != 'refs/heads/develop'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||
- name: Set run number with offset
|
||||
env:
|
||||
BUILD_NUMBER_OFFSET: ${{ secrets.BUILD_NUMBER_OFFSET }}
|
||||
run: echo "RUN_NUMBER=$((GITHUB_RUN_NUMBER+BUILD_NUMBER_OFFSET))" >> $GITHUB_ENV
|
||||
- name: Prepare build configuration
|
||||
run: |
|
||||
sed -i -e "s#applicationIdSuffix \".dev\"#applicationIdSuffix \".${GITHUB_HEAD_REF//[-.\/]/_}\"#" app/build.gradle
|
||||
sed -i -e "s#.dev\"#.${GITHUB_HEAD_REF//[-.\/]/_}\"#" app/src/debug/google-services.json
|
||||
sed -i -e "s#.dev\"#.${GITHUB_HEAD_REF//[-.\/]/_}\"#" app/src/debug/agconnect-services.json
|
||||
sed -i -e '/versionNameSuffix/d' app/build.gradle
|
||||
- name: Add signing config
|
||||
run: |
|
||||
cat >> app/build.gradle <<EOF
|
||||
android.signingConfigs.debug {
|
||||
storeFile file("bitrise.jks")
|
||||
storePassword System.getenv("BITRISE_KEYSTORE_PASSWORD")
|
||||
keyAlias System.getenv("BITRISE_KEY_ALIAS")
|
||||
keyPassword System.getenv("BITRISE_KEY_PASSWORD")
|
||||
}
|
||||
EOF
|
||||
- name: Decrypt keys
|
||||
env:
|
||||
BITRISE_ENCRYPT_KEY: ${{ secrets.BITRISE_ENCRYPT_KEY }}
|
||||
run: |
|
||||
gpg --yes --batch --passphrase=$BITRISE_ENCRYPT_KEY ./app/bitrise.jks.gpg
|
||||
- name: Bump version
|
||||
uses: chkfung/android-version-actions@v1.1
|
||||
with:
|
||||
gradlePath: app/build.gradle
|
||||
versionCode: ${{ env.RUN_NUMBER }}
|
||||
versionName: ${{ env.RUN_NUMBER }}-${{ github.head_ref }}
|
||||
- name: Build apk
|
||||
env:
|
||||
BITRISE_KEYSTORE_PASSWORD: ${{ secrets.BITRISE_KEYSTORE_PASSWORD }}
|
||||
BITRISE_KEY_ALIAS: ${{ secrets.BITRISE_KEY_ALIAS }}
|
||||
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
|
||||
run: ./gradlew assembleFdroidDebug --stacktrace
|
||||
- name: Upload apk to github artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: wulkanowyDEV-${{ env.RUN_NUMBER }}.apk
|
||||
path: app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk
|
||||
- name: Deploy to app center
|
||||
uses: wzieba/AppCenter-Github-Action@v1
|
||||
with:
|
||||
appName: wulkanowy/wulkanowy
|
||||
token: ${{ secrets.APP_CENTER_TOKEN }}
|
||||
group: Testers
|
||||
file: app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk
|
||||
notifyTesters: true
|
||||
debug: true
|
||||
|
||||
deploy-app-distribution:
|
||||
name: Deploy to AppDistribution
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
environment: app-distribution
|
||||
if: github.ref == 'refs/heads/develop'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||
- name: Set run number with offset
|
||||
env:
|
||||
BUILD_NUMBER_OFFSET: ${{ secrets.BUILD_NUMBER_OFFSET }}
|
||||
run: echo "RUN_NUMBER=$((GITHUB_RUN_NUMBER+BUILD_NUMBER_OFFSET))" >> $GITHUB_ENV
|
||||
- name: Add signing config
|
||||
run: |
|
||||
cat >> app/build.gradle <<EOF
|
||||
android.signingConfigs.debug {
|
||||
storeFile file("bitrise.jks")
|
||||
storePassword System.getenv("BITRISE_KEYSTORE_PASSWORD")
|
||||
keyAlias System.getenv("BITRISE_KEY_ALIAS")
|
||||
keyPassword System.getenv("BITRISE_KEY_PASSWORD")
|
||||
}
|
||||
EOF
|
||||
- name: Decrypt keys
|
||||
env:
|
||||
BITRISE_ENCRYPT_KEY: ${{ secrets.BITRISE_ENCRYPT_KEY }}
|
||||
BITRISE_SERVICES_ENCRYPT_KEY: ${{ secrets.BITRISE_SERVICES_ENCRYPT_KEY }}
|
||||
run: |
|
||||
gpg --yes --batch --passphrase=$BITRISE_SERVICES_ENCRYPT_KEY ./app/src/debug/google-services.json.gpg
|
||||
gpg --yes --batch --passphrase=$BITRISE_ENCRYPT_KEY ./app/bitrise.jks.gpg
|
||||
- name: Bump version
|
||||
uses: chkfung/android-version-actions@v1.1
|
||||
with:
|
||||
gradlePath: app/build.gradle
|
||||
versionCode: ${{ env.RUN_NUMBER }}
|
||||
versionName: ${{ env.RUN_NUMBER }}
|
||||
- name: Build apk
|
||||
env:
|
||||
BITRISE_KEYSTORE_PASSWORD: ${{ secrets.BITRISE_KEYSTORE_PASSWORD }}
|
||||
BITRISE_KEY_ALIAS: ${{ secrets.BITRISE_KEY_ALIAS }}
|
||||
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
|
||||
run: ./gradlew assemblePlayDebug -PenableFirebase --stacktrace
|
||||
- name: Upload apk to github artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: wulkanowyDEV-${{ env.RUN_NUMBER }}-dev.apk
|
||||
path: app/build/outputs/apk/play/debug/app-play-debug.apk
|
||||
- name: Deploy to app distribution
|
||||
uses: wzieba/Firebase-Distribution-Github-Action@v1
|
||||
with:
|
||||
appId: ${{ secrets.FIREBASE_APP_ID }}
|
||||
token: ${{ secrets.FIREBASE_TOKEN }}
|
||||
groups: discord
|
||||
file: app/build/outputs/apk/play/debug/app-play-debug.apk
|
||||
|
|
2
.gitignore
vendored
|
@ -117,5 +117,3 @@ Thumbs.db
|
|||
|
||||
|
||||
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" />
|
||||
</value>
|
||||
</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_FOR_MEMBERS" value="2147483647" />
|
||||
<option name="WRAP_ELVIS_EXPRESSIONS" value="0" />
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# Wulkanowy
|
||||
|
||||
[](https://github.com/wulkanowy/wulkanowy/actions)
|
||||
[](https://github.com/wulkanowy/wulkanowy/actions)
|
||||
[](https://codecov.io/gh/wulkanowy/wulkanowy)
|
||||
[](https://discord.gg/vccAQBr)
|
||||
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# Wulkanowy
|
||||
|
||||
[](https://github.com/wulkanowy/wulkanowy/actions)
|
||||
[](https://github.com/wulkanowy/wulkanowy/actions)
|
||||
[](https://codecov.io/gh/wulkanowy/wulkanowy)
|
||||
[](https://discord.gg/vccAQBr)
|
||||
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||
|
|
BIN
app/bitrise.jks
Normal file
116
app/build.gradle
|
@ -1,13 +1,11 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'dagger.hilt.android.plugin'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
apply plugin: 'com.github.triplet.play'
|
||||
apply plugin: 'ru.cian.huawei-publish'
|
||||
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'com.huawei.agconnect'
|
||||
apply from: 'jacoco.gradle'
|
||||
apply from: 'sonarqube.gradle'
|
||||
|
@ -15,14 +13,16 @@ apply from: 'hooks.gradle'
|
|||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion '30.0.3'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "io.github.wulkanowy"
|
||||
testApplicationId "io.github.tests.wulkanowy"
|
||||
minSdkVersion 21
|
||||
minSdkVersion 17
|
||||
targetSdkVersion 30
|
||||
versionCode 94
|
||||
versionName "1.2.1"
|
||||
versionCode 89
|
||||
versionName "1.1.3"
|
||||
multiDexEnabled true
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
|
||||
|
@ -67,6 +67,7 @@ android {
|
|||
resValue "string", "app_name", "Wulkanowy DEV " + defaultConfig.versionCode
|
||||
applicationIdSuffix ".dev"
|
||||
versionNameSuffix "-dev"
|
||||
testCoverageEnabled = project.hasProperty('coverage')
|
||||
ext.enableCrashlytics = project.hasProperty("enableFirebase")
|
||||
}
|
||||
}
|
||||
|
@ -76,6 +77,7 @@ android {
|
|||
productFlavors {
|
||||
hms {
|
||||
dimension "platform"
|
||||
minSdkVersion 19
|
||||
manifestPlaceholders = [
|
||||
install_channel: "AppGallery"
|
||||
]
|
||||
|
@ -97,7 +99,11 @@ android {
|
|||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
viewBinding = true
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
disable 'HardwareIds'
|
||||
}
|
||||
|
||||
testOptions.unitTests {
|
||||
|
@ -106,12 +112,13 @@ android {
|
|||
|
||||
compileOptions {
|
||||
coreLibraryDesugaringEnabled true
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = "11"
|
||||
useIR = true
|
||||
jvmTarget = "1.8"
|
||||
freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn", "-Xjvm-default=all"]
|
||||
}
|
||||
|
||||
|
@ -125,10 +132,6 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
kapt {
|
||||
correctErrorTypes true
|
||||
}
|
||||
|
||||
play {
|
||||
serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") ?: "jan@fakelog.cf"
|
||||
serviceAccountCredentials = file('key.p12')
|
||||
|
@ -137,49 +140,41 @@ play {
|
|||
updatePriority = 3
|
||||
}
|
||||
|
||||
huaweiPublish {
|
||||
instances {
|
||||
hmsRelease {
|
||||
credentialsPath = "$rootDir/app/src/release/agconnect-credentials.json"
|
||||
buildFormat = "apk"
|
||||
deployType = "draft"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ext {
|
||||
work_manager = "2.5.0"
|
||||
android_hilt = "1.0.0"
|
||||
room = "2.3.0"
|
||||
chucker = "3.5.2"
|
||||
mockk = "1.12.0"
|
||||
moshi = "1.12.0"
|
||||
work_hilt = "1.0.0-beta01"
|
||||
room = "2.3.0-rc01"
|
||||
chucker = "3.4.0"
|
||||
mockk = "1.11.0"
|
||||
moshi = "1.11.0"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "io.github.wulkanowy:sdk:1.2.1"
|
||||
implementation "io.github.wulkanowy:sdk:1.1.3"
|
||||
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3'
|
||||
|
||||
implementation "androidx.core:core-ktx:1.6.0"
|
||||
implementation "androidx.activity:activity-ktx:1.3.1"
|
||||
implementation "androidx.appcompat:appcompat:1.3.1"
|
||||
implementation "androidx.appcompat:appcompat-resources:1.3.1"
|
||||
implementation "androidx.fragment:fragment-ktx:1.3.6"
|
||||
implementation "androidx.core:core-ktx:1.3.2"
|
||||
implementation "androidx.activity:activity-ktx:1.2.2"
|
||||
implementation "androidx.appcompat:appcompat:1.2.0"
|
||||
implementation "androidx.appcompat:appcompat-resources:1.2.0"
|
||||
implementation "androidx.fragment:fragment-ktx:1.3.2"
|
||||
implementation "androidx.annotation:annotation:1.2.0"
|
||||
implementation "androidx.multidex:multidex:2.0.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.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.1.0"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
|
||||
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.2.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"
|
||||
playImplementation "androidx.work:work-gcm:$work_manager"
|
||||
|
@ -192,56 +187,55 @@ dependencies {
|
|||
|
||||
implementation "com.google.dagger:hilt-android:$hilt_version"
|
||||
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
|
||||
kapt "androidx.hilt:hilt-compiler:$android_hilt"
|
||||
implementation "androidx.hilt:hilt-work:$android_hilt"
|
||||
implementation "androidx.hilt:hilt-work:$work_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.squareup.moshi:moshi:$moshi"
|
||||
implementation "com.squareup.moshi:moshi-adapters:$moshi"
|
||||
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi"
|
||||
|
||||
implementation "com.jakewharton.timber:timber:5.0.1"
|
||||
implementation "com.jakewharton.timber:timber:4.7.1"
|
||||
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
||||
implementation 'com.github.bastienpaulfr:Treessence:1.0.4'
|
||||
implementation "fr.bipi.treessence:treessence:0.3.2"
|
||||
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
||||
implementation "io.coil-kt:coil:1.3.2"
|
||||
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
|
||||
implementation "io.coil-kt:coil:1.1.1"
|
||||
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
|
||||
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
|
||||
implementation 'com.fredporciuncula:flow-preferences:1.5.0'
|
||||
|
||||
playImplementation platform('com.google.firebase:firebase-bom:28.4.0')
|
||||
playImplementation platform('com.google.firebase:firebase-bom:26.7.0')
|
||||
playImplementation 'com.google.firebase:firebase-analytics-ktx'
|
||||
playImplementation 'com.google.firebase:firebase-messaging:'
|
||||
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
||||
playImplementation 'com.google.android.play:core:1.10.1'
|
||||
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
||||
|
||||
hmsImplementation 'com.huawei.hms:hianalytics:6.2.0.301'
|
||||
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.0.300'
|
||||
hmsImplementation 'com.huawei.hms:hianalytics:5.2.0.301'
|
||||
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.5.1.200'
|
||||
|
||||
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
||||
|
||||
debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker"
|
||||
debugImplementation 'com.github.amitshekhariitbhu.Android-Debug-Database:debug-db:v1.0.6'
|
||||
debugImplementation "com.amitshekhar.android:debug-db:1.0.6"
|
||||
|
||||
testImplementation "junit:junit:4.13.2"
|
||||
testImplementation "io.mockk:mockk:$mockk"
|
||||
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.2'
|
||||
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2'
|
||||
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||
|
||||
testImplementation 'org.robolectric:robolectric:4.6.1'
|
||||
testImplementation "androidx.test:runner:1.4.0"
|
||||
testImplementation "androidx.test.ext:junit:1.1.3"
|
||||
testImplementation "androidx.test:core:1.4.0"
|
||||
testImplementation 'org.robolectric:robolectric:4.5.1'
|
||||
testImplementation "androidx.test:runner:1.3.0"
|
||||
testImplementation "androidx.test.ext:junit:1.1.2"
|
||||
testImplementation "androidx.test:core:1.3.0"
|
||||
testImplementation "androidx.room:room-testing:$room"
|
||||
testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
|
||||
kaptTest "com.google.dagger:hilt-android-compiler:$hilt_version"
|
||||
|
||||
androidTestImplementation "androidx.test:core:1.4.0"
|
||||
androidTestImplementation "androidx.test:runner:1.4.0"
|
||||
androidTestImplementation "androidx.test.ext:junit:1.1.3"
|
||||
androidTestImplementation "androidx.test:core:1.3.0"
|
||||
androidTestImplementation "androidx.test:runner:1.3.0"
|
||||
androidTestImplementation "androidx.test.ext:junit:1.1.2"
|
||||
androidTestImplementation "io.mockk:mockk-android:$mockk"
|
||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
apply plugin: "jacoco"
|
||||
|
||||
jacoco {
|
||||
toolVersion "0.8.7"
|
||||
reportsDirectory.set(file("$buildDir/reports"))
|
||||
toolVersion "0.8.5"
|
||||
reportsDir = file("$buildDir/reports")
|
||||
}
|
||||
|
||||
tasks.withType(Test) {
|
||||
|
@ -16,8 +16,8 @@ task jacocoTestReport(type: JacocoReport) {
|
|||
description = "Generate Jacoco coverage reports"
|
||||
|
||||
reports {
|
||||
xml.required.set(true)
|
||||
html.required.set(true)
|
||||
xml.enabled = true
|
||||
html.enabled = true
|
||||
}
|
||||
|
||||
def excludes = ['**/R.class',
|
||||
|
|
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 com.huawei.agconnect.crash.AGConnectCrash
|
||||
import fr.bipi.tressence.base.FormatterPriorityTree
|
||||
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
|
||||
import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
|
||||
import java.io.InterruptedIOException
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
|
||||
class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) {
|
||||
|
||||
|
@ -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() }
|
||||
|
||||
override fun skipLog(priority: Int, tag: String?, message: String, t: Throwable?): Boolean {
|
||||
return when (t) {
|
||||
is FeatureDisabledException,
|
||||
is FeatureNotAvailableException,
|
||||
is UnknownHostException,
|
||||
is SocketTimeoutException,
|
||||
is InterruptedIOException -> true
|
||||
else -> super.skipLog(priority, tag, message, t)
|
||||
}
|
||||
}
|
||||
|
||||
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
||||
if (skipLog(priority, tag, message, t)) return
|
||||
|
||||
|
|
|
@ -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.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.VIBRATE" />
|
||||
|
||||
|
@ -168,7 +167,7 @@
|
|||
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||
android:resource="@drawable/ic_stat_all" />
|
||||
android:resource="@drawable/ic_stat_push" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_channel_id"
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
"githubUsername": "Luncenok"
|
||||
},
|
||||
{
|
||||
"displayName": "Daniel Olczyk",
|
||||
"displayName": "MRmlik12",
|
||||
"githubUsername": "MRmlik12"
|
||||
},
|
||||
{
|
||||
|
@ -46,9 +46,5 @@
|
|||
{
|
||||
"displayName": "Kamil Studziński",
|
||||
"githubUsername": "studzinskik"
|
||||
},
|
||||
{
|
||||
"displayName": "Tomasz F.",
|
||||
"githubUsername": "Pengwius"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -2,12 +2,14 @@ package io.github.wulkanowy
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.util.Log.DEBUG
|
||||
import android.util.Log.INFO
|
||||
import android.util.Log.VERBOSE
|
||||
import android.webkit.WebView
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.hilt.work.HiltWorkerFactory
|
||||
import androidx.multidex.MultiDex
|
||||
import androidx.work.Configuration
|
||||
import com.yariksoffice.lingver.Lingver
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
|
@ -41,6 +43,11 @@ class WulkanowyApp : Application(), Configuration.Provider {
|
|||
@Inject
|
||||
lateinit var analyticsHelper: AnalyticsHelper
|
||||
|
||||
override fun attachBaseContext(base: Context?) {
|
||||
super.attachBaseContext(base)
|
||||
MultiDex.install(this)
|
||||
}
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageWarning")
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
@ -84,7 +91,7 @@ class WulkanowyApp : Application(), Configuration.Provider {
|
|||
//https://stackoverflow.com/questions/40398528/android-webview-language-changes-abruptly-on-android-7-0-and-above
|
||||
try {
|
||||
WebView(this).destroy()
|
||||
} catch (e: Throwable) {
|
||||
} catch (e: Exception) {
|
||||
//Ignore exceptions
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,6 @@ import androidx.preference.PreferenceManager
|
|||
import com.chuckerteam.chucker.api.ChuckerCollector
|
||||
import com.chuckerteam.chucker.api.ChuckerInterceptor
|
||||
import com.chuckerteam.chucker.api.RetentionManager
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
@ -20,7 +18,6 @@ import io.github.wulkanowy.data.db.SharedPrefProvider
|
|||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import timber.log.Timber
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -80,16 +77,6 @@ internal class RepositoryModule {
|
|||
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideFlowSharedPref(sharedPreferences: SharedPreferences) =
|
||||
FlowSharedPreferences(sharedPreferences)
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideMoshi() = Moshi.Builder().build()
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideStudentDao(database: AppDatabase) = database.studentDao
|
||||
|
@ -194,12 +181,4 @@ internal class RepositoryModule {
|
|||
@Singleton
|
||||
@Provides
|
||||
fun provideStudentInfoDao(database: AppDatabase) = database.studentInfoDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideTimetableHeaderDao(database: AppDatabase) = database.timetableHeaderDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideSchoolAnnouncementDao(database: AppDatabase) = database.schoolAnnouncementDao
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import io.github.wulkanowy.data.db.dao.AttendanceDao
|
|||
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
|
||||
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
|
||||
import io.github.wulkanowy.data.db.dao.ConferenceDao
|
||||
import io.github.wulkanowy.data.db.dao.SchoolAnnouncementDao
|
||||
import io.github.wulkanowy.data.db.dao.ExamDao
|
||||
import io.github.wulkanowy.data.db.dao.GradeDao
|
||||
import io.github.wulkanowy.data.db.dao.GradePartialStatisticsDao
|
||||
|
@ -33,12 +32,10 @@ import io.github.wulkanowy.data.db.dao.SubjectDao
|
|||
import io.github.wulkanowy.data.db.dao.TeacherDao
|
||||
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
|
||||
import io.github.wulkanowy.data.db.dao.TimetableDao
|
||||
import io.github.wulkanowy.data.db.dao.TimetableHeaderDao
|
||||
import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.github.wulkanowy.data.db.entities.AttendanceSummary
|
||||
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
||||
import io.github.wulkanowy.data.db.entities.Conference
|
||||
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
|
||||
|
@ -61,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.Timetable
|
||||
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.Migration11
|
||||
import io.github.wulkanowy.data.db.migrations.Migration12
|
||||
|
@ -90,10 +86,6 @@ import io.github.wulkanowy.data.db.migrations.Migration32
|
|||
import io.github.wulkanowy.data.db.migrations.Migration33
|
||||
import io.github.wulkanowy.data.db.migrations.Migration34
|
||||
import io.github.wulkanowy.data.db.migrations.Migration35
|
||||
import io.github.wulkanowy.data.db.migrations.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.Migration5
|
||||
import io.github.wulkanowy.data.db.migrations.Migration6
|
||||
|
@ -132,8 +124,6 @@ import javax.inject.Singleton
|
|||
Conference::class,
|
||||
TimetableAdditional::class,
|
||||
StudentInfo::class,
|
||||
TimetableHeader::class,
|
||||
SchoolAnnouncement::class,
|
||||
],
|
||||
version = AppDatabase.VERSION_SCHEMA,
|
||||
exportSchema = true
|
||||
|
@ -142,7 +132,7 @@ import javax.inject.Singleton
|
|||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
companion object {
|
||||
const val VERSION_SCHEMA = 39
|
||||
const val VERSION_SCHEMA = 35
|
||||
|
||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
||||
Migration2(),
|
||||
|
@ -178,11 +168,7 @@ abstract class AppDatabase : RoomDatabase() {
|
|||
Migration32(),
|
||||
Migration33(),
|
||||
Migration34(),
|
||||
Migration35(appInfo),
|
||||
Migration36(),
|
||||
Migration37(),
|
||||
Migration38(),
|
||||
Migration39(),
|
||||
Migration35(appInfo)
|
||||
)
|
||||
|
||||
fun newInstance(
|
||||
|
@ -248,8 +234,4 @@ abstract class AppDatabase : RoomDatabase() {
|
|||
abstract val timetableAdditionalDao: TimetableAdditionalDao
|
||||
|
||||
abstract val studentInfoDao: StudentInfoDao
|
||||
|
||||
abstract val timetableHeaderDao: TimetableHeaderDao
|
||||
|
||||
abstract val schoolAnnouncementDao: SchoolAnnouncementDao
|
||||
}
|
||||
|
|
|
@ -20,15 +20,9 @@ class SharedPrefProvider @Inject constructor(
|
|||
|
||||
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 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) {
|
||||
fun putString(key: String, value: String, sync: Boolean = false) {
|
||||
sharedPref.edit(sync) { putString(key, value) }
|
||||
}
|
||||
|
||||
|
|
|
@ -4,13 +4,12 @@ import androidx.room.Dao
|
|||
import androidx.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.Conference
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import java.time.LocalDateTime
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Dao
|
||||
@Singleton
|
||||
interface ConferenceDao : BaseDao<Conference> {
|
||||
|
||||
@Query("SELECT * FROM Conferences WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :startDate")
|
||||
fun loadAll(diaryId: Int, studentId: Int, startDate: LocalDateTime): Flow<List<Conference>>
|
||||
@Query("SELECT * FROM Conferences WHERE diary_id = :diaryId AND student_id = :studentId")
|
||||
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.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>>
|
||||
}
|
|
@ -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>>
|
||||
}
|
|
@ -32,7 +32,4 @@ data class Conference(
|
|||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
|
||||
@ColumnInfo(name = "is_notified")
|
||||
var isNotified: Boolean = true
|
||||
}
|
||||
|
|
|
@ -36,7 +36,4 @@ data class Exam(
|
|||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
|
||||
@ColumnInfo(name = "is_notified")
|
||||
var isNotified: Boolean = true
|
||||
}
|
||||
|
|
|
@ -37,7 +37,4 @@ data class Homework(
|
|||
|
||||
@ColumnInfo(name = "is_done")
|
||||
var isDone: Boolean = false
|
||||
|
||||
@ColumnInfo(name = "is_notified")
|
||||
var isNotified: Boolean = true
|
||||
}
|
||||
|
|
|
@ -3,10 +3,8 @@ package io.github.wulkanowy.data.db.entities
|
|||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.squareup.moshi.JsonClass
|
||||
import java.io.Serializable
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
@Entity(tableName = "Recipients")
|
||||
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
|
||||
}
|
|
@ -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,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.Timetable
|
||||
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.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 {
|
||||
Timetable(
|
||||
studentId = semester.studentId,
|
||||
|
@ -49,13 +39,3 @@ fun List<SdkTimetableAdditional>.mapToEntities(semester: Semester) = map {
|
|||
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,11 +0,0 @@
|
|||
package io.github.wulkanowy.data.pojos
|
||||
|
||||
import com.squareup.moshi.JsonClass
|
||||
import io.github.wulkanowy.ui.modules.message.send.RecipientChipItem
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MessageDraft(
|
||||
val recipients: List<RecipientChipItem>,
|
||||
val subject: String,
|
||||
val content: String,
|
||||
)
|
|
@ -1,36 +0,0 @@
|
|||
package io.github.wulkanowy.data.pojos
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.PluralsRes
|
||||
import androidx.annotation.StringRes
|
||||
import io.github.wulkanowy.services.sync.notifications.NotificationType
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
|
||||
sealed interface Notification {
|
||||
val type: NotificationType
|
||||
val startMenu: MainView.Section
|
||||
val icon: Int
|
||||
val titleStringRes: Int
|
||||
val contentStringRes: Int
|
||||
}
|
||||
|
||||
data class MultipleNotifications(
|
||||
override val type: NotificationType,
|
||||
override val startMenu: MainView.Section,
|
||||
@DrawableRes override val icon: Int,
|
||||
@PluralsRes override val titleStringRes: Int,
|
||||
@PluralsRes override val contentStringRes: Int,
|
||||
|
||||
@PluralsRes val summaryStringRes: Int,
|
||||
val lines: List<String>,
|
||||
) : Notification
|
||||
|
||||
data class OneNotification(
|
||||
override val type: NotificationType,
|
||||
override val startMenu: MainView.Section,
|
||||
@DrawableRes override val icon: Int,
|
||||
@StringRes override val titleStringRes: Int,
|
||||
@StringRes override val contentStringRes: Int,
|
||||
|
||||
val contentValues: List<String>,
|
||||
) : Notification
|
|
@ -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>,
|
||||
)
|
|
@ -15,7 +15,6 @@ class AppCreatorRepository @Inject constructor(
|
|||
private val dispatchers: DispatchersProvider
|
||||
) {
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
suspend fun getAppCreators() = withContext(dispatchers.backgroundThread) {
|
||||
val moshi = Moshi.Builder().build()
|
||||
val type = Types.newParameterizedType(List::class.java, Contributor::class.java)
|
||||
|
|
|
@ -25,17 +25,9 @@ class AttendanceSummaryRepository @Inject constructor(
|
|||
|
||||
private val cacheKey = "attendance_summary"
|
||||
|
||||
fun getAttendanceSummary(
|
||||
student: Student,
|
||||
semester: Semester,
|
||||
subjectId: Int,
|
||||
forceRefresh: Boolean
|
||||
) = networkBoundResource(
|
||||
fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int, forceRefresh: Boolean) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
shouldFetch = {
|
||||
it.isEmpty() || forceRefresh
|
||||
|| refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||
},
|
||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
|
||||
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId) },
|
||||
fetch = {
|
||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.github.wulkanowy.data.repositories
|
||||
|
||||
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.Student
|
||||
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.networkBoundResource
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneOffset
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -30,44 +25,19 @@ class ConferenceRepository @Inject constructor(
|
|||
|
||||
private val cacheKey = "conference"
|
||||
|
||||
fun getConferences(
|
||||
student: Student,
|
||||
semester: Semester,
|
||||
forceRefresh: Boolean,
|
||||
notify: Boolean = false,
|
||||
startDate: LocalDateTime = LocalDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC)
|
||||
) = networkBoundResource(
|
||||
fun getConferences(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
shouldFetch = {
|
||||
it.isEmpty() || forceRefresh
|
||||
|| refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||
},
|
||||
query = {
|
||||
conferenceDb.loadAll(semester.diaryId, student.studentId, startDate)
|
||||
},
|
||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
|
||||
query = { conferenceDb.loadAll(semester.diaryId, student.studentId) },
|
||||
fetch = {
|
||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getConferences()
|
||||
.mapToEntities(semester)
|
||||
.filter { it.date >= startDate }
|
||||
},
|
||||
saveFetchResult = { old, new ->
|
||||
val conferencesToSave = (new uniqueSubtract old).onEach {
|
||||
if (notify) it.isNotified = false
|
||||
}
|
||||
|
||||
conferenceDb.deleteAll(old uniqueSubtract new)
|
||||
conferenceDb.insertAll(conferencesToSave)
|
||||
conferenceDb.insertAll(new uniqueSubtract old)
|
||||
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
|
||||
|
||||
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.Student
|
||||
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.startExamsDay
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import java.time.LocalDate
|
||||
import javax.inject.Inject
|
||||
|
@ -30,54 +28,20 @@ class ExamRepository @Inject constructor(
|
|||
|
||||
private val cacheKey = "exam"
|
||||
|
||||
fun getExams(
|
||||
student: Student,
|
||||
semester: Semester,
|
||||
start: LocalDate,
|
||||
end: LocalDate,
|
||||
forceRefresh: Boolean,
|
||||
notify: Boolean = false
|
||||
) = networkBoundResource(
|
||||
fun getExams(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
shouldFetch = {
|
||||
val isShouldBeRefreshed = refreshHelper.isShouldBeRefreshed(
|
||||
key = getRefreshKey(cacheKey, semester, start, end)
|
||||
)
|
||||
it.isEmpty() || forceRefresh || isShouldBeRefreshed
|
||||
},
|
||||
query = {
|
||||
examDb.loadAll(
|
||||
diaryId = semester.diaryId,
|
||||
studentId = semester.studentId,
|
||||
from = start.startExamsDay,
|
||||
end = start.endExamsDay
|
||||
)
|
||||
},
|
||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
||||
query = { examDb.loadAll(semester.diaryId, semester.studentId, start.startExamsDay, start.endExamsDay) },
|
||||
fetch = {
|
||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getExams(start.startExamsDay, start.endExamsDay, semester.semesterId)
|
||||
.mapToEntities(semester)
|
||||
},
|
||||
saveFetchResult = { old, new ->
|
||||
val examsToSave = (new uniqueSubtract old).onEach {
|
||||
if (notify) it.isNotified = false
|
||||
}
|
||||
|
||||
examDb.deleteAll(old uniqueSubtract new)
|
||||
examDb.insertAll(examsToSave)
|
||||
examDb.insertAll(new uniqueSubtract old)
|
||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, 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,10 @@ class GradeRepository @Inject constructor(
|
|||
|
||||
private val cacheKey = "grade"
|
||||
|
||||
fun getGrades(
|
||||
student: Student,
|
||||
semester: Semester,
|
||||
forceRefresh: Boolean,
|
||||
notify: Boolean = false
|
||||
) = networkBoundResource(
|
||||
fun getGrades(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
shouldFetch = { (details, summaries) ->
|
||||
val isShouldBeRefreshed =
|
||||
refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||
val isShouldBeRefreshed = refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||
details.isEmpty() || summaries.isEmpty() || forceRefresh || isShouldBeRefreshed
|
||||
},
|
||||
query = {
|
||||
|
@ -65,14 +59,8 @@ class GradeRepository @Inject constructor(
|
|||
}
|
||||
)
|
||||
|
||||
private suspend fun refreshGradeDetails(
|
||||
student: Student,
|
||||
oldGrades: List<Grade>,
|
||||
newDetails: List<Grade>,
|
||||
notify: Boolean
|
||||
) {
|
||||
val notifyBreakDate =
|
||||
oldGrades.maxByOrNull { it.date }?.date ?: student.registrationDate.toLocalDate()
|
||||
private suspend fun refreshGradeDetails(student: Student, oldGrades: List<Grade>, newDetails: List<Grade>, notify: Boolean) {
|
||||
val notifyBreakDate = oldGrades.maxByOrNull { it.date }?.date ?: student.registrationDate.toLocalDate()
|
||||
gradeDb.deleteAll(oldGrades uniqueSubtract newDetails)
|
||||
gradeDb.insertAll((newDetails uniqueSubtract oldGrades).onEach {
|
||||
if (it.date >= notifyBreakDate) it.apply {
|
||||
|
@ -82,15 +70,10 @@ class GradeRepository @Inject constructor(
|
|||
})
|
||||
}
|
||||
|
||||
private suspend fun refreshGradeSummaries(
|
||||
oldSummaries: List<GradeSummary>,
|
||||
newSummary: List<GradeSummary>,
|
||||
notify: Boolean
|
||||
) {
|
||||
private suspend fun refreshGradeSummaries(oldSummaries: List<GradeSummary>, newSummary: List<GradeSummary>, notify: Boolean) {
|
||||
gradeSummaryDb.deleteAll(oldSummaries uniqueSubtract newSummary)
|
||||
gradeSummaryDb.insertAll((newSummary uniqueSubtract oldSummaries).onEach { summary ->
|
||||
val oldSummary =
|
||||
oldSummaries.find { oldSummary -> oldSummary.subject == summary.subject }
|
||||
val oldSummary = oldSummaries.find { oldSummary -> oldSummary.subject == summary.subject }
|
||||
summary.isPredictedGradeNotified = when {
|
||||
summary.predictedGrade.isEmpty() -> true
|
||||
notify && oldSummary?.predictedGrade != summary.predictedGrade -> false
|
||||
|
@ -121,16 +104,22 @@ class GradeRepository @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun getGradesFromDatabase(semester: Semester): Flow<List<Grade>> {
|
||||
return gradeDb.loadAll(semester.semesterId, semester.studentId)
|
||||
fun getNotNotifiedGrades(semester: Semester): Flow<List<Grade>> {
|
||||
return gradeDb.loadAll(semester.semesterId, semester.studentId).map {
|
||||
it.filter { grade -> !grade.isNotified }
|
||||
}
|
||||
}
|
||||
|
||||
fun getGradesPredictedFromDatabase(semester: Semester): Flow<List<GradeSummary>> {
|
||||
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)
|
||||
fun getNotNotifiedPredictedGrades(semester: Semester): Flow<List<GradeSummary>> {
|
||||
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).map {
|
||||
it.filter { gradeSummary -> !gradeSummary.isPredictedGradeNotified }
|
||||
}
|
||||
}
|
||||
|
||||
fun getGradesFinalFromDatabase(semester: Semester): Flow<List<GradeSummary>> {
|
||||
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)
|
||||
fun getNotNotifiedFinalGrades(semester: Semester): Flow<List<GradeSummary>> {
|
||||
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).map {
|
||||
it.filter { gradeSummary -> !gradeSummary.isFinalGradeNotified }
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateGrade(grade: Grade) {
|
||||
|
|
|
@ -29,38 +29,18 @@ class HomeworkRepository @Inject constructor(
|
|||
|
||||
private val cacheKey = "homework"
|
||||
|
||||
fun getHomework(
|
||||
student: Student, semester: Semester,
|
||||
start: LocalDate, end: LocalDate,
|
||||
forceRefresh: Boolean, notify: Boolean = false
|
||||
) = networkBoundResource(
|
||||
fun getHomework(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
shouldFetch = {
|
||||
val isShouldBeRefreshed = refreshHelper.isShouldBeRefreshed(
|
||||
key = getRefreshKey(cacheKey, semester, start, end)
|
||||
)
|
||||
it.isEmpty() || forceRefresh || isShouldBeRefreshed
|
||||
},
|
||||
query = {
|
||||
homeworkDb.loadAll(
|
||||
semesterId = semester.semesterId,
|
||||
studentId = semester.studentId,
|
||||
from = start.monday,
|
||||
end = end.sunday
|
||||
)
|
||||
},
|
||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
||||
query = { homeworkDb.loadAll(semester.semesterId, semester.studentId, start.monday, end.sunday) },
|
||||
fetch = {
|
||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getHomework(start.monday, end.sunday)
|
||||
.mapToEntities(semester)
|
||||
},
|
||||
saveFetchResult = { old, new ->
|
||||
val homeWorkToSave = (new uniqueSubtract old).onEach {
|
||||
if (notify) it.isNotified = false
|
||||
}
|
||||
|
||||
homeworkDb.deleteAll(old uniqueSubtract new)
|
||||
homeworkDb.insertAll(homeWorkToSave)
|
||||
homeworkDb.insertAll(new uniqueSubtract old)
|
||||
|
||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
|
||||
}
|
||||
|
@ -71,9 +51,4 @@ class HomeworkRepository @Inject constructor(
|
|||
isDone = !isDone
|
||||
}))
|
||||
}
|
||||
|
||||
fun getHomeworkFromDatabase(semester: Semester, start: LocalDate, end: LocalDate) =
|
||||
homeworkDb.loadAll(semester.semesterId, semester.studentId, start.monday, end.sunday)
|
||||
|
||||
suspend fun updateHomework(homework: List<Homework>) = homeworkDb.updateAll(homework)
|
||||
}
|
||||
|
|
|
@ -1,15 +1,8 @@
|
|||
package io.github.wulkanowy.data.repositories
|
||||
|
||||
import android.content.Context
|
||||
import com.squareup.moshi.Moshi
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
|
@ -17,8 +10,6 @@ import io.github.wulkanowy.data.enums.MessageFolder
|
|||
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
|
||||
import io.github.wulkanowy.data.mappers.mapFromEntities
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.pojos.MessageDraft
|
||||
import io.github.wulkanowy.data.pojos.MessageDraftJsonAdapter
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.sdk.pojo.Folder
|
||||
import io.github.wulkanowy.sdk.pojo.SentMessage
|
||||
|
@ -28,6 +19,7 @@ import io.github.wulkanowy.utils.init
|
|||
import io.github.wulkanowy.utils.networkBoundResource
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import timber.log.Timber
|
||||
import java.time.LocalDateTime.now
|
||||
|
@ -39,10 +31,7 @@ class MessageRepository @Inject constructor(
|
|||
private val messagesDb: MessagesDao,
|
||||
private val messageAttachmentDao: MessageAttachmentDao,
|
||||
private val sdk: Sdk,
|
||||
@ApplicationContext private val context: Context,
|
||||
private val refreshHelper: AutoRefreshHelper,
|
||||
private val sharedPrefProvider: SharedPrefProvider,
|
||||
private val moshi: Moshi,
|
||||
) {
|
||||
|
||||
private val saveFetchResultMutex = Mutex()
|
||||
|
@ -50,54 +39,22 @@ class MessageRepository @Inject constructor(
|
|||
private val cacheKey = "message"
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun getMessages(
|
||||
student: Student, semester: Semester,
|
||||
folder: MessageFolder, forceRefresh: Boolean, notify: Boolean = false
|
||||
): Flow<Resource<List<Message>>> = networkBoundResource(
|
||||
fun getMessages(student: Student, semester: Semester, folder: MessageFolder, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
shouldFetch = {
|
||||
it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(
|
||||
getRefreshKey(cacheKey, student, folder)
|
||||
)
|
||||
},
|
||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, student, folder)) },
|
||||
query = { messagesDb.loadAll(student.id.toInt(), folder.id) },
|
||||
fetch = {
|
||||
sdk.init(student).getMessages(Folder.valueOf(folder.name), now().minusMonths(3), now())
|
||||
.mapToEntities(student)
|
||||
},
|
||||
fetch = { sdk.init(student).getMessages(Folder.valueOf(folder.name), now().minusMonths(3), now()).mapToEntities(student) },
|
||||
saveFetchResult = { old, new ->
|
||||
messagesDb.deleteAll(old uniqueSubtract new)
|
||||
messagesDb.insertAll((new uniqueSubtract old).onEach {
|
||||
it.isNotified = !notify
|
||||
})
|
||||
messagesDb.updateAll(getMessagesWithReadByChange(old, new, !notify))
|
||||
|
||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student, folder))
|
||||
}
|
||||
)
|
||||
|
||||
private fun getMessagesWithReadByChange(
|
||||
old: List<Message>, new: List<Message>,
|
||||
setNotified: Boolean
|
||||
): List<Message> {
|
||||
val oldMeta = old.map { Triple(it, it.readBy, it.unreadBy) }
|
||||
val newMeta = new.map { Triple(it, it.readBy, it.unreadBy) }
|
||||
|
||||
val updatedItems = newMeta uniqueSubtract oldMeta
|
||||
|
||||
return updatedItems.map {
|
||||
val oldItem = old.find { item -> item.messageId == it.first.messageId }
|
||||
it.first.apply {
|
||||
id = oldItem?.id ?: 0
|
||||
isNotified = oldItem?.isNotified ?: setNotified
|
||||
content = oldItem?.content.orEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getMessage(
|
||||
student: Student, message: Message, markAsRead: Boolean = false
|
||||
): Flow<Resource<MessageWithAttachment?>> = networkBoundResource(
|
||||
fun getMessage(student: Student, message: Message, markAsRead: Boolean = false) = networkBoundResource(
|
||||
shouldFetch = {
|
||||
checkNotNull(it, { "This message no longer exist!" })
|
||||
Timber.d("Message content in db empty: ${it.message.content.isEmpty()}")
|
||||
|
@ -105,20 +62,14 @@ class MessageRepository @Inject constructor(
|
|||
},
|
||||
query = { messagesDb.loadMessageWithAttachment(student.id.toInt(), message.messageId) },
|
||||
fetch = {
|
||||
sdk.init(student).getMessageDetails(
|
||||
messageId = it!!.message.messageId,
|
||||
folderId = message.folderId,
|
||||
read = markAsRead,
|
||||
id = message.realId
|
||||
).let { details ->
|
||||
sdk.init(student).getMessageDetails(it!!.message.messageId, message.folderId, markAsRead, message.realId).let { details ->
|
||||
details.content to details.attachments.mapToEntities()
|
||||
}
|
||||
},
|
||||
saveFetchResult = { old, (downloadedMessage, attachments) ->
|
||||
checkNotNull(old, { "Fetched message no longer exist!" })
|
||||
messagesDb.updateAll(listOf(old.message.apply {
|
||||
messagesDb.updateAll(listOf(old.message.copy(unread = !markAsRead).apply {
|
||||
id = old.message.id
|
||||
unread = !markAsRead
|
||||
content = content.ifBlank { downloadedMessage }
|
||||
}))
|
||||
messageAttachmentDao.insertAttachments(attachments)
|
||||
|
@ -126,42 +77,30 @@ class MessageRepository @Inject constructor(
|
|||
}
|
||||
)
|
||||
|
||||
fun getMessagesFromDatabase(student: Student): Flow<List<Message>> {
|
||||
return messagesDb.loadAll(student.id.toInt(), RECEIVED.id)
|
||||
fun getNotNotifiedMessages(student: Student): Flow<List<Message>> {
|
||||
return messagesDb.loadAll(student.id.toInt(), RECEIVED.id).map { it.filter { message -> !message.isNotified && message.unread } }
|
||||
}
|
||||
|
||||
suspend fun updateMessages(messages: List<Message>) {
|
||||
return messagesDb.updateAll(messages)
|
||||
}
|
||||
|
||||
suspend fun sendMessage(
|
||||
student: Student, subject: String, content: String,
|
||||
recipients: List<Recipient>
|
||||
): SentMessage = sdk.init(student).sendMessage(
|
||||
subject = subject,
|
||||
content = content,
|
||||
recipients = recipients.mapFromEntities()
|
||||
)
|
||||
|
||||
suspend fun deleteMessage(student: Student, message: Message) {
|
||||
val isDeleted = sdk.init(student).deleteMessages(
|
||||
messages = listOf(message.messageId), message.folderId
|
||||
suspend fun sendMessage(student: Student, subject: String, content: String, recipients: List<Recipient>): SentMessage {
|
||||
return sdk.init(student).sendMessage(
|
||||
subject = subject,
|
||||
content = content,
|
||||
recipients = recipients.mapFromEntities()
|
||||
)
|
||||
|
||||
if (message.folderId != MessageFolder.TRASHED.id && isDeleted) {
|
||||
val deletedMessage = message.copy(folderId = MessageFolder.TRASHED.id).apply {
|
||||
id = message.id
|
||||
content = message.content
|
||||
}
|
||||
messagesDb.updateAll(listOf(deletedMessage))
|
||||
} else messagesDb.deleteAll(listOf(message))
|
||||
}
|
||||
|
||||
var draftMessage: MessageDraft?
|
||||
get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_send_draft))
|
||||
?.let { MessageDraftJsonAdapter(moshi).fromJson(it) }
|
||||
set(value) = sharedPrefProvider.putString(
|
||||
context.getString(R.string.pref_key_message_send_draft),
|
||||
value?.let { MessageDraftJsonAdapter(moshi).toJson(it) }
|
||||
)
|
||||
suspend fun deleteMessage(student: Student, message: Message) {
|
||||
val isDeleted = sdk.init(student).deleteMessages(listOf(message.messageId), message.folderId)
|
||||
|
||||
if (message.folderId != MessageFolder.TRASHED.id) {
|
||||
if (isDeleted) messagesDb.updateAll(listOf(message.copy(folderId = MessageFolder.TRASHED.id).apply {
|
||||
id = message.id
|
||||
content = message.content
|
||||
}))
|
||||
} else messagesDb.deleteAll(listOf(message))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,8 +50,8 @@ class NoteRepository @Inject constructor(
|
|||
}
|
||||
)
|
||||
|
||||
fun getNotesFromDatabase(student: Student): Flow<List<Note>> {
|
||||
return noteDb.loadAll(student.studentId)
|
||||
fun getNotNotifiedNotes(student: Student): Flow<List<Note>> {
|
||||
return noteDb.loadAll(student.studentId).map { it.filter { note -> !note.isNotified } }
|
||||
}
|
||||
|
||||
suspend fun updateNote(note: Note) {
|
||||
|
|
|
@ -3,41 +3,18 @@ package io.github.wulkanowy.data.repositories
|
|||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
|
||||
import com.fredporciuncula.flow.preferences.Preference
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.adapter
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.sdk.toLocalDate
|
||||
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeSortingMode
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Singleton
|
||||
class PreferencesRepository @Inject constructor(
|
||||
private val sharedPref: SharedPreferences,
|
||||
private val flowSharedPref: FlowSharedPreferences,
|
||||
@ApplicationContext val context: Context,
|
||||
moshi: Moshi
|
||||
@ApplicationContext val context: Context
|
||||
) {
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private val dashboardItemsPositionAdapter: JsonAdapter<Map<DashboardItem.Type, Int>> =
|
||||
moshi.adapter()
|
||||
|
||||
val startMenuIndex: Int
|
||||
get() = getString(R.string.pref_key_start_menu, R.string.pref_default_startup).toInt()
|
||||
|
||||
|
@ -169,78 +146,9 @@ class PreferencesRepository @Inject constructor(
|
|||
R.bool.pref_default_subjects_without_grades
|
||||
)
|
||||
|
||||
val isOptionalArithmeticAverage: Boolean
|
||||
get() = getBoolean(
|
||||
R.string.pref_key_optional_arithmetic_average,
|
||||
R.bool.pref_default_optional_arithmetic_average
|
||||
)
|
||||
|
||||
var lasSyncDate: LocalDateTime
|
||||
get() = getLong(
|
||||
R.string.pref_key_last_sync_date,
|
||||
R.string.pref_default_last_sync_date
|
||||
).toLocalDateTime()
|
||||
set(value) = sharedPref.edit().putLong("last_sync_date", value.toTimestamp()).apply()
|
||||
|
||||
var dashboardItemsPosition: Map<DashboardItem.Type, Int>?
|
||||
get() {
|
||||
val json = sharedPref.getString(PREF_KEY_DASHBOARD_ITEMS_POSITION, null) ?: return null
|
||||
|
||||
return dashboardItemsPositionAdapter.fromJson(json)
|
||||
}
|
||||
set(value) = sharedPref.edit {
|
||||
putString(
|
||||
PREF_KEY_DASHBOARD_ITEMS_POSITION,
|
||||
dashboardItemsPositionAdapter.toJson(value)
|
||||
)
|
||||
}
|
||||
|
||||
val selectedDashboardTilesFlow: Flow<Set<DashboardItem.Tile>>
|
||||
get() = selectedDashboardTilesPreference.asFlow()
|
||||
.map { set ->
|
||||
set.map { DashboardItem.Tile.valueOf(it) }
|
||||
.plus(DashboardItem.Tile.ACCOUNT)
|
||||
.toSet()
|
||||
}
|
||||
|
||||
var selectedDashboardTiles: Set<DashboardItem.Tile>
|
||||
get() = selectedDashboardTilesPreference.get()
|
||||
.map { DashboardItem.Tile.valueOf(it) }
|
||||
.plus(DashboardItem.Tile.ACCOUNT)
|
||||
.toSet()
|
||||
set(value) {
|
||||
val filteredValue = value.filterNot { it == DashboardItem.Tile.ACCOUNT }
|
||||
.map { it.name }
|
||||
.toSet()
|
||||
|
||||
selectedDashboardTilesPreference.set(filteredValue)
|
||||
}
|
||||
|
||||
private val selectedDashboardTilesPreference: Preference<Set<String>>
|
||||
get() {
|
||||
val defaultSet =
|
||||
context.resources.getStringArray(R.array.pref_default_dashboard_tiles).toSet()
|
||||
val prefKey = context.getString(R.string.pref_key_dashboard_tiles)
|
||||
|
||||
return flowSharedPref.getStringSet(prefKey, defaultSet)
|
||||
}
|
||||
|
||||
var inAppReviewCount: Int
|
||||
get() = sharedPref.getInt(PREF_KEY_IN_APP_REVIEW_COUNT, 0)
|
||||
set(value) = sharedPref.edit().putInt(PREF_KEY_IN_APP_REVIEW_COUNT, value).apply()
|
||||
|
||||
var inAppReviewDate: LocalDate?
|
||||
get() = sharedPref.getLong(PREF_KEY_IN_APP_REVIEW_DATE, 0).takeIf { it != 0L }?.toLocalDate()
|
||||
set(value) = sharedPref.edit().putLong(PREF_KEY_IN_APP_REVIEW_DATE, value!!.toTimestamp()).apply()
|
||||
|
||||
var isAppReviewDone: Boolean
|
||||
get() = sharedPref.getBoolean(PREF_KEY_IN_APP_REVIEW_DONE, false)
|
||||
set(value) = sharedPref.edit().putBoolean(PREF_KEY_IN_APP_REVIEW_DONE, value).apply()
|
||||
|
||||
private fun getLong(id: Int, default: Int) = getLong(context.getString(id), default)
|
||||
|
||||
private fun getLong(id: String, default: Int) =
|
||||
sharedPref.getLong(id, context.resources.getString(default).toLong())
|
||||
var isKitkatDialogDisabled: Boolean
|
||||
get() = sharedPref.getBoolean("kitkat_dialog_disabled", false)
|
||||
set(value) = sharedPref.edit { putBoolean("kitkat_dialog_disabled", value) }
|
||||
|
||||
private fun getString(id: Int, default: Int) = getString(context.getString(id), default)
|
||||
|
||||
|
@ -251,15 +159,4 @@ class PreferencesRepository @Inject constructor(
|
|||
|
||||
private fun getBoolean(id: String, default: Int) =
|
||||
sharedPref.getBoolean(id, context.resources.getBoolean(default))
|
||||
|
||||
private companion object {
|
||||
|
||||
private const val PREF_KEY_DASHBOARD_ITEMS_POSITION = "dashboard_items_position"
|
||||
|
||||
private const val PREF_KEY_IN_APP_REVIEW_COUNT = "in_app_review_count"
|
||||
|
||||
private const val PREF_KEY_IN_APP_REVIEW_DATE = "in_app_review_date"
|
||||
|
||||
private const val PREF_KEY_IN_APP_REVIEW_DONE = "in_app_review_done"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
package io.github.wulkanowy.data.repositories
|
||||
|
||||
import io.github.wulkanowy.data.db.dao.SchoolAnnouncementDao
|
||||
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||
import io.github.wulkanowy.utils.getRefreshKey
|
||||
import io.github.wulkanowy.utils.init
|
||||
import io.github.wulkanowy.utils.networkBoundResource
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class SchoolAnnouncementRepository @Inject constructor(
|
||||
private val schoolAnnouncementDb: SchoolAnnouncementDao,
|
||||
private val sdk: Sdk,
|
||||
private val refreshHelper: AutoRefreshHelper,
|
||||
) {
|
||||
|
||||
private val saveFetchResultMutex = Mutex()
|
||||
|
||||
private val cacheKey = "school_announcement"
|
||||
|
||||
fun getSchoolAnnouncements(
|
||||
student: Student,
|
||||
forceRefresh: Boolean,
|
||||
notify: Boolean = false
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
shouldFetch = {
|
||||
it.isEmpty() || forceRefresh
|
||||
|| refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, student))
|
||||
},
|
||||
query = {
|
||||
schoolAnnouncementDb.loadAll(
|
||||
student.studentId)
|
||||
},
|
||||
fetch = {
|
||||
sdk.init(student)
|
||||
.getDirectorInformation()
|
||||
.mapToEntities(student)
|
||||
},
|
||||
saveFetchResult = { old, new ->
|
||||
val schoolAnnouncementsToSave = (new uniqueSubtract old).onEach {
|
||||
if (notify) it.isNotified = false
|
||||
}
|
||||
|
||||
schoolAnnouncementDb.deleteAll(old uniqueSubtract new)
|
||||
schoolAnnouncementDb.insertAll(schoolAnnouncementsToSave)
|
||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
|
||||
}
|
||||
)
|
||||
fun getSchoolAnnouncementFromDatabase(student: Student): Flow<List<SchoolAnnouncement>> {
|
||||
return schoolAnnouncementDb.loadAll(student.studentId)
|
||||
}
|
||||
|
||||
suspend fun updateSchoolAnnouncement(schoolAnnouncement: List<SchoolAnnouncement>) = schoolAnnouncementDb.updateAll(schoolAnnouncement)
|
||||
}
|
|
@ -22,11 +22,7 @@ class SemesterRepository @Inject constructor(
|
|||
private val dispatchers: DispatchersProvider
|
||||
) {
|
||||
|
||||
suspend fun getSemesters(
|
||||
student: Student,
|
||||
forceRefresh: Boolean = false,
|
||||
refreshOnNoCurrent: Boolean = false
|
||||
) = withContext(dispatchers.backgroundThread) {
|
||||
suspend fun getSemesters(student: Student, forceRefresh: Boolean = false, refreshOnNoCurrent: Boolean = false) = withContext(dispatchers.backgroundThread) {
|
||||
val semesters = semesterDb.loadAll(student.studentId, student.classId)
|
||||
|
||||
if (isShouldFetch(student, semesters, forceRefresh, refreshOnNoCurrent)) {
|
||||
|
@ -35,21 +31,14 @@ class SemesterRepository @Inject constructor(
|
|||
} else semesters
|
||||
}
|
||||
|
||||
private fun isShouldFetch(
|
||||
student: Student,
|
||||
semesters: List<Semester>,
|
||||
forceRefresh: Boolean,
|
||||
refreshOnNoCurrent: Boolean
|
||||
): Boolean {
|
||||
private fun isShouldFetch(student: Student, semesters: List<Semester>, forceRefresh: Boolean, refreshOnNoCurrent: Boolean): Boolean {
|
||||
val isNoSemesters = semesters.isEmpty()
|
||||
|
||||
val isRefreshOnModeChangeRequired =
|
||||
if (Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
|
||||
semesters.firstOrNull { it.isCurrent }?.diaryId == 0
|
||||
} else false
|
||||
val isRefreshOnModeChangeRequired = if (Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
|
||||
semesters.firstOrNull { it.isCurrent }?.diaryId == 0
|
||||
} else false
|
||||
|
||||
val isRefreshOnNoCurrentAppropriate =
|
||||
refreshOnNoCurrent && !semesters.any { semester -> semester.isCurrent }
|
||||
val isRefreshOnNoCurrentAppropriate = refreshOnNoCurrent && !semesters.any { semester -> semester.isCurrent }
|
||||
|
||||
return forceRefresh || isNoSemesters || isRefreshOnModeChangeRequired || isRefreshOnNoCurrentAppropriate
|
||||
}
|
||||
|
@ -63,8 +52,7 @@ class SemesterRepository @Inject constructor(
|
|||
semesterDb.insertSemesters(new.uniqueSubtract(old))
|
||||
}
|
||||
|
||||
suspend fun getCurrentSemester(student: Student, forceRefresh: Boolean = false) =
|
||||
withContext(dispatchers.backgroundThread) {
|
||||
getSemesters(student, forceRefresh).getCurrentOrLast()
|
||||
}
|
||||
suspend fun getCurrentSemester(student: Student, forceRefresh: Boolean = false) = withContext(dispatchers.backgroundThread) {
|
||||
getSemesters(student, forceRefresh).getCurrentOrLast()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,14 +2,11 @@ package io.github.wulkanowy.data.repositories
|
|||
|
||||
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
|
||||
import io.github.wulkanowy.data.db.dao.TimetableDao
|
||||
import io.github.wulkanowy.data.db.dao.TimetableHeaderDao
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.pojos.TimetableFull
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
|
||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||
|
@ -19,8 +16,8 @@ import io.github.wulkanowy.utils.monday
|
|||
import io.github.wulkanowy.utils.networkBoundResource
|
||||
import io.github.wulkanowy.utils.sunday
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import java.time.LocalDate
|
||||
import javax.inject.Inject
|
||||
|
@ -30,7 +27,6 @@ import javax.inject.Singleton
|
|||
class TimetableRepository @Inject constructor(
|
||||
private val timetableDb: TimetableDao,
|
||||
private val timetableAdditionalDb: TimetableAdditionalDao,
|
||||
private val timetableHeaderDb: TimetableHeaderDao,
|
||||
private val sdk: Sdk,
|
||||
private val schedulerHelper: TimetableNotificationSchedulerHelper,
|
||||
private val refreshHelper: AutoRefreshHelper,
|
||||
|
@ -40,111 +36,53 @@ class TimetableRepository @Inject constructor(
|
|||
|
||||
private val cacheKey = "timetable"
|
||||
|
||||
fun getTimetable(
|
||||
student: Student, semester: Semester, start: LocalDate, end: LocalDate,
|
||||
forceRefresh: Boolean, refreshAdditional: Boolean = false
|
||||
) = networkBoundResource(
|
||||
fun getTimetable(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean, refreshAdditional: Boolean = false) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
shouldFetch = { (timetable, additional, headers) ->
|
||||
val refreshKey = getRefreshKey(cacheKey, semester, start, end)
|
||||
val isShouldRefresh = refreshHelper.isShouldBeRefreshed(refreshKey)
|
||||
val isRefreshAdditional = additional.isEmpty() && refreshAdditional
|
||||
|
||||
val isNoData = timetable.isEmpty() || isRefreshAdditional || headers.isEmpty()
|
||||
|
||||
isNoData || forceRefresh || isShouldRefresh
|
||||
shouldFetch = { (timetable, additional) -> timetable.isEmpty() || (additional.isEmpty() && refreshAdditional) || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
||||
query = {
|
||||
timetableDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)
|
||||
.map { schedulerHelper.scheduleNotifications(it, student); it }
|
||||
.combine(timetableAdditionalDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)) { timetable, additional ->
|
||||
timetable to additional
|
||||
}
|
||||
},
|
||||
query = { getFullTimetableFromDatabase(student, semester, start, end) },
|
||||
fetch = {
|
||||
val timetableFull = sdk.init(student)
|
||||
.switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getTimetableFull(start.monday, end.sunday)
|
||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getTimetable(start.monday, end.sunday)
|
||||
.let { (normal, additional) -> normal.mapToEntities(semester) to additional.mapToEntities(semester) }
|
||||
|
||||
timetableFull.mapToEntities(semester)
|
||||
},
|
||||
saveFetchResult = { timetableOld, timetableNew ->
|
||||
refreshTimetable(student, timetableOld.lessons, timetableNew.lessons)
|
||||
refreshAdditional(timetableOld.additional, timetableNew.additional)
|
||||
refreshDayHeaders(timetableOld.headers, timetableNew.headers)
|
||||
saveFetchResult = { (oldTimetable, oldAdditional), (newTimetable, newAdditional) ->
|
||||
refreshTimetable(student, oldTimetable, newTimetable)
|
||||
refreshAdditional(oldAdditional, newAdditional)
|
||||
|
||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
|
||||
},
|
||||
filterResult = { (timetable, additional, headers) ->
|
||||
TimetableFull(
|
||||
lessons = timetable.filter { it.date in start..end },
|
||||
additional = additional.filter { it.date in start..end },
|
||||
headers = headers.filter { it.date in start..end }
|
||||
)
|
||||
filterResult = { (timetable, additional) ->
|
||||
timetable.filter { item ->
|
||||
item.date in start..end
|
||||
} to additional.filter { item ->
|
||||
item.date in start..end
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
private fun getFullTimetableFromDatabase(
|
||||
student: Student, semester: Semester,
|
||||
start: LocalDate, end: LocalDate
|
||||
): Flow<TimetableFull> {
|
||||
val timetableFlow = timetableDb.loadAll(
|
||||
diaryId = semester.diaryId,
|
||||
studentId = semester.studentId,
|
||||
from = start.monday,
|
||||
end = end.sunday
|
||||
)
|
||||
val headersFlow = timetableHeaderDb.loadAll(
|
||||
diaryId = semester.diaryId,
|
||||
studentId = semester.studentId,
|
||||
from = start.monday,
|
||||
end = end.sunday
|
||||
)
|
||||
val additionalFlow = timetableAdditionalDb.loadAll(
|
||||
diaryId = semester.diaryId,
|
||||
studentId = semester.studentId,
|
||||
from = start.monday,
|
||||
end = end.sunday
|
||||
)
|
||||
return combine(timetableFlow, headersFlow, additionalFlow) { lessons, headers, additional ->
|
||||
schedulerHelper.scheduleNotifications(lessons, student)
|
||||
|
||||
TimetableFull(
|
||||
lessons = lessons,
|
||||
headers = headers,
|
||||
additional = additional
|
||||
)
|
||||
}
|
||||
private suspend fun refreshTimetable(student: Student, old: List<Timetable>, new: List<Timetable>) {
|
||||
timetableDb.deleteAll(old.uniqueSubtract(new).also { schedulerHelper.cancelScheduled(it) })
|
||||
timetableDb.insertAll(new.uniqueSubtract(old).also { schedulerHelper.scheduleNotifications(it, student) }.map { item ->
|
||||
item.also { new ->
|
||||
old.singleOrNull { new.start == it.start }?.let { old ->
|
||||
return@map new.copy(
|
||||
room = if (new.room.isEmpty()) old.room else new.room,
|
||||
teacher = if (new.teacher.isEmpty() && !new.changes && !old.changes) old.teacher else new.teacher
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private suspend fun refreshTimetable(
|
||||
student: Student,
|
||||
lessonsOld: List<Timetable>, lessonsNew: List<Timetable>
|
||||
) {
|
||||
val lessonsToRemove = lessonsOld uniqueSubtract lessonsNew
|
||||
val lessonsToAdd = (lessonsNew uniqueSubtract lessonsOld).map { new ->
|
||||
val matchingOld = lessonsOld.singleOrNull { new.start == it.start }
|
||||
if (matchingOld != null) {
|
||||
val useOldTeacher = new.teacher.isEmpty() && !new.changes && !matchingOld.changes
|
||||
new.copy(
|
||||
room = if (new.room.isEmpty()) matchingOld.room else new.room,
|
||||
teacher = if (useOldTeacher) matchingOld.teacher
|
||||
else new.teacher
|
||||
)
|
||||
} else new
|
||||
}
|
||||
|
||||
timetableDb.deleteAll(lessonsToRemove)
|
||||
timetableDb.insertAll(lessonsToAdd)
|
||||
|
||||
schedulerHelper.cancelScheduled(lessonsToRemove, student)
|
||||
schedulerHelper.scheduleNotifications(lessonsToAdd, student)
|
||||
}
|
||||
|
||||
private suspend fun refreshAdditional(
|
||||
old: List<TimetableAdditional>,
|
||||
new: List<TimetableAdditional>
|
||||
) {
|
||||
timetableAdditionalDb.deleteAll(old uniqueSubtract new)
|
||||
timetableAdditionalDb.insertAll(new uniqueSubtract old)
|
||||
}
|
||||
|
||||
private suspend fun refreshDayHeaders(old: List<TimetableHeader>, new: List<TimetableHeader>) {
|
||||
timetableHeaderDb.deleteAll(old uniqueSubtract new)
|
||||
timetableHeaderDb.insertAll(new uniqueSubtract old)
|
||||
private suspend fun refreshAdditional(old: List<TimetableAdditional>, new: List<TimetableAdditional>) {
|
||||
timetableAdditionalDb.deleteAll(old.uniqueSubtract(new))
|
||||
timetableAdditionalDb.insertAll(new.uniqueSubtract(old))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,19 +15,14 @@ import dagger.multibindings.IntoSet
|
|||
import io.github.wulkanowy.services.sync.channels.Channel
|
||||
import io.github.wulkanowy.services.sync.channels.DebugChannel
|
||||
import io.github.wulkanowy.services.sync.channels.LuckyNumberChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewConferencesChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewExamChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewGradesChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewHomeworkChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewMessagesChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewNotesChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewSchoolAnnouncementsChannel
|
||||
import io.github.wulkanowy.services.sync.channels.PushChannel
|
||||
import io.github.wulkanowy.services.sync.channels.UpcomingLessonsChannel
|
||||
import io.github.wulkanowy.services.sync.works.AttendanceSummaryWork
|
||||
import io.github.wulkanowy.services.sync.works.AttendanceWork
|
||||
import io.github.wulkanowy.services.sync.works.CompletedLessonWork
|
||||
import io.github.wulkanowy.services.sync.works.ConferenceWork
|
||||
import io.github.wulkanowy.services.sync.works.ExamWork
|
||||
import io.github.wulkanowy.services.sync.works.GradeStatisticsWork
|
||||
import io.github.wulkanowy.services.sync.works.GradeWork
|
||||
|
@ -36,7 +31,6 @@ import io.github.wulkanowy.services.sync.works.LuckyNumberWork
|
|||
import io.github.wulkanowy.services.sync.works.MessageWork
|
||||
import io.github.wulkanowy.services.sync.works.NoteWork
|
||||
import io.github.wulkanowy.services.sync.works.RecipientWork
|
||||
import io.github.wulkanowy.services.sync.works.SchoolAnnouncementWork
|
||||
import io.github.wulkanowy.services.sync.works.TeacherWork
|
||||
import io.github.wulkanowy.services.sync.works.TimetableWork
|
||||
import io.github.wulkanowy.services.sync.works.Work
|
||||
|
@ -50,18 +44,15 @@ abstract class ServicesModule {
|
|||
companion object {
|
||||
|
||||
@Provides
|
||||
fun provideWorkManager(@ApplicationContext context: Context) =
|
||||
WorkManager.getInstance(context)
|
||||
fun provideWorkManager(@ApplicationContext context: Context) = WorkManager.getInstance(context)
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideNotificationManager(@ApplicationContext context: Context) =
|
||||
NotificationManagerCompat.from(context)
|
||||
fun provideNotificationManager(@ApplicationContext context: Context) = NotificationManagerCompat.from(context)
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideAlarmManager(@ApplicationContext context: Context): AlarmManager =
|
||||
context.getSystemService()!!
|
||||
fun provideAlarmManager(@ApplicationContext context: Context): AlarmManager = context.getSystemService()!!
|
||||
}
|
||||
|
||||
@Binds
|
||||
|
@ -76,10 +67,6 @@ abstract class ServicesModule {
|
|||
@IntoSet
|
||||
abstract fun provideAttendanceWork(work: AttendanceWork): Work
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun provideConferenceWork(work: ConferenceWork): Work
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun provideExamWork(work: ExamWork): Work
|
||||
|
@ -120,10 +107,6 @@ abstract class ServicesModule {
|
|||
@IntoSet
|
||||
abstract fun provideGradeStatistics(work: GradeStatisticsWork): Work
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun provideSchoolAnnouncementWork(work: SchoolAnnouncementWork): Work
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun provideDebugChannel(channel: DebugChannel): Channel
|
||||
|
@ -132,18 +115,6 @@ abstract class ServicesModule {
|
|||
@IntoSet
|
||||
abstract fun provideLuckyNumberChannel(channel: LuckyNumberChannel): Channel
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun provideNewConferenceChannel(channel: NewConferencesChannel): Channel
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun provideNewExamChannel(channel: NewExamChannel): Channel
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun provideNewHomeworkChannel(channel: NewHomeworkChannel): Channel
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun provideNewGradesChannel(channel: NewGradesChannel): Channel
|
||||
|
@ -156,10 +127,6 @@ abstract class ServicesModule {
|
|||
@IntoSet
|
||||
abstract fun provideNewNotesChannel(channel: NewNotesChannel): Channel
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun provideNewSchoolAnnouncementChannel(channel: NewSchoolAnnouncementsChannel): Channel
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun providePushChannel(channel: PushChannel): Channel
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.github.wulkanowy.services.alarm
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.PendingIntent
|
||||
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
||||
import android.content.Context
|
||||
|
@ -19,7 +20,6 @@ import io.github.wulkanowy.ui.modules.main.MainView
|
|||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.getCompatColor
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
@ -50,7 +50,7 @@ class TimetableNotificationReceiver : HiltBroadcastReceiver() {
|
|||
const val LESSON_END = "end_timestamp"
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
@SuppressLint("CheckResult")
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
super.onReceive(context, intent)
|
||||
Timber.d("Receiving intent... ${intent.toUri(0)}")
|
||||
|
|
|
@ -51,8 +51,7 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
|
|||
lesson: Timetable
|
||||
) = day.getOrNull(index - 1)?.end ?: lesson.start.minusMinutes(30)
|
||||
|
||||
suspend fun cancelScheduled(lessons: List<Timetable>, student: Student) {
|
||||
val studentId = student.studentId
|
||||
suspend fun cancelScheduled(lessons: List<Timetable>, studentId: Int = 1) {
|
||||
withContext(dispatchersProvider.backgroundThread) {
|
||||
lessons.sortedBy { it.start }.forEachIndexed { index, lesson ->
|
||||
val upcomingTime = getUpcomingLessonTime(index, lessons, lesson)
|
||||
|
@ -79,7 +78,7 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
|
|||
|
||||
suspend fun scheduleNotifications(lessons: List<Timetable>, student: Student) {
|
||||
if (!preferencesRepository.isUpcomingLessonsNotificationsEnable) {
|
||||
return cancelScheduled(lessons, student)
|
||||
return cancelScheduled(lessons, student.studentId)
|
||||
}
|
||||
|
||||
withContext(dispatchersProvider.backgroundThread) {
|
||||
|
@ -90,7 +89,7 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
|
|||
val canceled = day.filter { it.canceled }
|
||||
val active = day.filter { !it.canceled }
|
||||
|
||||
cancelScheduled(canceled, student)
|
||||
cancelScheduled(canceled)
|
||||
active.forEachIndexed { index, lesson ->
|
||||
val intent = createIntent(student, lesson, active.getOrNull(index + 1))
|
||||
|
||||
|
|
|
@ -22,8 +22,6 @@ import io.github.wulkanowy.services.sync.works.Work
|
|||
import io.github.wulkanowy.utils.getCompatColor
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import timber.log.Timber
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
import kotlin.random.Random
|
||||
|
||||
@HiltWorker
|
||||
|
@ -50,7 +48,6 @@ class SyncWorker @AssistedInject constructor(
|
|||
Timber.i("${work::class.java.simpleName} is starting")
|
||||
work.doWork(student, semester)
|
||||
Timber.i("${work::class.java.simpleName} result: Success")
|
||||
preferencesRepository.lasSyncDate = LocalDateTime.now(ZoneId.systemDefault())
|
||||
null
|
||||
} catch (e: Throwable) {
|
||||
Timber.w("${work::class.java.simpleName} result: An exception ${e.message} occurred")
|
||||
|
@ -84,7 +81,7 @@ class SyncWorker @AssistedInject constructor(
|
|||
Random.nextInt(Int.MAX_VALUE),
|
||||
NotificationCompat.Builder(applicationContext, DebugChannel.CHANNEL_ID)
|
||||
.setContentTitle("Debug notification")
|
||||
.setSmallIcon(R.drawable.ic_stat_all)
|
||||
.setSmallIcon(R.drawable.ic_stat_push)
|
||||
.setAutoCancel(true)
|
||||
.setColor(applicationContext.getCompatColor(R.color.colorPrimary))
|
||||
.setStyle(BigTextStyle().bigText("${SyncWorker::class.java.simpleName} result: $result"))
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
package io.github.wulkanowy.services.sync.channels
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import javax.inject.Inject
|
||||
|
||||
@TargetApi(26)
|
||||
class NewConferencesChannel @Inject constructor(
|
||||
private val notificationManager: NotificationManagerCompat,
|
||||
@ApplicationContext private val context: Context
|
||||
) : Channel {
|
||||
|
||||
companion object {
|
||||
const val CHANNEL_ID = "new_conferences_channel"
|
||||
}
|
||||
|
||||
override fun create() {
|
||||
notificationManager.createNotificationChannel(
|
||||
NotificationChannel(CHANNEL_ID, context.getString(R.string.channel_new_conference), NotificationManager.IMPORTANCE_HIGH)
|
||||
.apply {
|
||||
enableLights(true)
|
||||
enableVibration(true)
|
||||
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package io.github.wulkanowy.services.sync.channels
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import javax.inject.Inject
|
||||
|
||||
@TargetApi(26)
|
||||
class NewExamChannel @Inject constructor(
|
||||
private val notificationManager: NotificationManagerCompat,
|
||||
@ApplicationContext private val context: Context
|
||||
) : Channel {
|
||||
|
||||
companion object {
|
||||
const val CHANNEL_ID = "new_exam_channel"
|
||||
}
|
||||
|
||||
override fun create() {
|
||||
notificationManager.createNotificationChannel(
|
||||
NotificationChannel(CHANNEL_ID, context.getString(R.string.channel_new_exam), NotificationManager.IMPORTANCE_HIGH)
|
||||
.apply {
|
||||
enableLights(true)
|
||||
enableVibration(true)
|
||||
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package io.github.wulkanowy.services.sync.channels
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import javax.inject.Inject
|
||||
|
||||
@TargetApi(26)
|
||||
class NewHomeworkChannel @Inject constructor(
|
||||
private val notificationManager: NotificationManagerCompat,
|
||||
@ApplicationContext private val context: Context
|
||||
) : Channel {
|
||||
|
||||
companion object {
|
||||
const val CHANNEL_ID = "new_homework_channel"
|
||||
}
|
||||
|
||||
override fun create() {
|
||||
notificationManager.createNotificationChannel(
|
||||
NotificationChannel(CHANNEL_ID, context.getString(R.string.channel_new_homework), NotificationManager.IMPORTANCE_HIGH)
|
||||
.apply {
|
||||
enableLights(true)
|
||||
enableVibration(true)
|
||||
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package io.github.wulkanowy.services.sync.channels
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import javax.inject.Inject
|
||||
|
||||
@TargetApi(26)
|
||||
class NewSchoolAnnouncementsChannel @Inject constructor(
|
||||
private val notificationManager: NotificationManagerCompat,
|
||||
@ApplicationContext private val context: Context
|
||||
) : Channel {
|
||||
|
||||
companion object {
|
||||
const val CHANNEL_ID = "new_school_announcements_channel"
|
||||
}
|
||||
|
||||
override fun create() {
|
||||
notificationManager.createNotificationChannel(
|
||||
NotificationChannel(CHANNEL_ID, context.getString(R.string.channel_new_school_announcement), NotificationManager.IMPORTANCE_HIGH)
|
||||
.apply {
|
||||
enableLights(true)
|
||||
enableVibration(true)
|
||||
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
package io.github.wulkanowy.services.sync.notifications
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.annotation.PluralsRes
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.pojos.MultipleNotifications
|
||||
import io.github.wulkanowy.data.pojos.Notification
|
||||
import io.github.wulkanowy.data.pojos.OneNotification
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
import io.github.wulkanowy.utils.getCompatBitmap
|
||||
import io.github.wulkanowy.utils.getCompatColor
|
||||
import io.github.wulkanowy.utils.nickOrName
|
||||
import kotlin.random.Random
|
||||
|
||||
abstract class BaseNotification(
|
||||
private val context: Context,
|
||||
private val notificationManager: NotificationManagerCompat,
|
||||
) {
|
||||
|
||||
protected fun sendNotification(notification: Notification, student: Student) =
|
||||
when (notification) {
|
||||
is OneNotification -> sendOneNotification(notification, student)
|
||||
is MultipleNotifications -> sendMultipleNotifications(notification, student)
|
||||
}
|
||||
|
||||
private fun sendOneNotification(notification: OneNotification, student: Student?) {
|
||||
notificationManager.notify(
|
||||
Random.nextInt(Int.MAX_VALUE),
|
||||
getNotificationBuilder(notification).apply {
|
||||
val content = context.getString(
|
||||
notification.contentStringRes,
|
||||
*notification.contentValues.toTypedArray()
|
||||
)
|
||||
setContentTitle(context.getString(notification.titleStringRes))
|
||||
setContentText(content)
|
||||
setStyle(
|
||||
NotificationCompat.BigTextStyle()
|
||||
.setSummaryText(student?.nickOrName)
|
||||
.bigText(content)
|
||||
)
|
||||
}.build()
|
||||
)
|
||||
}
|
||||
|
||||
private fun sendMultipleNotifications(notification: MultipleNotifications, student: Student) {
|
||||
val group = notification.type.group + student.id
|
||||
val groupId = student.id * 100 + notification.type.ordinal
|
||||
|
||||
notification.lines.forEach { item ->
|
||||
notificationManager.notify(
|
||||
Random.nextInt(Int.MAX_VALUE),
|
||||
getNotificationBuilder(notification).apply {
|
||||
setContentTitle(getQuantityString(notification.titleStringRes, 1))
|
||||
setContentText(item)
|
||||
setStyle(
|
||||
NotificationCompat.BigTextStyle()
|
||||
.setSummaryText(student.nickOrName)
|
||||
.bigText(item)
|
||||
)
|
||||
setGroup(group)
|
||||
}.build()
|
||||
)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return
|
||||
|
||||
notificationManager.notify(
|
||||
groupId.toInt(),
|
||||
getNotificationBuilder(notification).apply {
|
||||
setSmallIcon(notification.icon)
|
||||
setGroup(group)
|
||||
setStyle(NotificationCompat.InboxStyle().setSummaryText(student.nickOrName))
|
||||
setGroupSummary(true)
|
||||
}.build()
|
||||
)
|
||||
}
|
||||
|
||||
private fun getNotificationBuilder(notification: Notification) = NotificationCompat
|
||||
.Builder(context, notification.type.channel)
|
||||
.setLargeIcon(context.getCompatBitmap(notification.icon, R.color.colorPrimary))
|
||||
.setSmallIcon(R.drawable.ic_stat_all)
|
||||
.setAutoCancel(true)
|
||||
.setDefaults(NotificationCompat.DEFAULT_ALL)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setColor(context.getCompatColor(R.color.colorPrimary))
|
||||
.setContentIntent(
|
||||
PendingIntent.getActivity(
|
||||
context, notification.startMenu.id,
|
||||
MainActivity.getStartIntent(context, notification.startMenu, true),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
)
|
||||
|
||||
private fun getQuantityString(@PluralsRes id: Int, value: Int): String {
|
||||
return context.resources.getQuantityString(id, value, value)
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package io.github.wulkanowy.services.sync.notifications
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Conference
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.pojos.MultipleNotifications
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import java.time.LocalDateTime
|
||||
import javax.inject.Inject
|
||||
|
||||
class NewConferenceNotification @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
notificationManager: NotificationManagerCompat,
|
||||
) : BaseNotification(context, notificationManager) {
|
||||
|
||||
fun notify(items: List<Conference>, student: Student) {
|
||||
val today = LocalDateTime.now()
|
||||
val lines = items.filter { !it.date.isBefore(today) }.map {
|
||||
"${it.date.toFormattedString("dd.MM")} - ${it.title}: ${it.subject}"
|
||||
}.ifEmpty { return }
|
||||
|
||||
val notification = MultipleNotifications(
|
||||
type = NotificationType.NEW_CONFERENCE,
|
||||
icon = R.drawable.ic_more_conferences,
|
||||
titleStringRes = R.plurals.conference_notify_new_item_title,
|
||||
contentStringRes = R.plurals.conference_notify_new_items,
|
||||
summaryStringRes = R.plurals.conference_number_item,
|
||||
startMenu = MainView.Section.CONFERENCE,
|
||||
lines = lines
|
||||
)
|
||||
|
||||
sendNotification(notification, student)
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package io.github.wulkanowy.services.sync.notifications
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.pojos.MultipleNotifications
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import java.time.LocalDate
|
||||
import javax.inject.Inject
|
||||
|
||||
class NewExamNotification @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
notificationManager: NotificationManagerCompat,
|
||||
) : BaseNotification(context, notificationManager) {
|
||||
|
||||
fun notify(items: List<Exam>, student: Student) {
|
||||
val today = LocalDate.now()
|
||||
val lines = items.filter { !it.date.isBefore(today) }.map {
|
||||
"${it.date.toFormattedString("dd.MM")} - ${it.subject}: ${it.description}"
|
||||
}.ifEmpty { return }
|
||||
|
||||
val notification = MultipleNotifications(
|
||||
type = NotificationType.NEW_EXAM,
|
||||
icon = R.drawable.ic_main_exam,
|
||||
titleStringRes = R.plurals.exam_notify_new_item_title,
|
||||
contentStringRes = R.plurals.exam_notify_new_item_content,
|
||||
summaryStringRes = R.plurals.exam_number_item,
|
||||
startMenu = MainView.Section.EXAM,
|
||||
lines = lines
|
||||
)
|
||||
|
||||
sendNotification(notification, student)
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
package io.github.wulkanowy.services.sync.notifications
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.pojos.MultipleNotifications
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import javax.inject.Inject
|
||||
|
||||
class NewGradeNotification @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
notificationManager: NotificationManagerCompat,
|
||||
) : BaseNotification(context, notificationManager) {
|
||||
|
||||
fun notifyDetails(items: List<Grade>, student: Student) {
|
||||
val notification = MultipleNotifications(
|
||||
type = NotificationType.NEW_GRADE_DETAILS,
|
||||
icon = R.drawable.ic_stat_grade,
|
||||
titleStringRes = R.plurals.grade_new_items,
|
||||
contentStringRes = R.plurals.grade_notify_new_items,
|
||||
summaryStringRes = R.plurals.grade_number_item,
|
||||
startMenu = MainView.Section.GRADE,
|
||||
lines = items.map {
|
||||
"${it.subject}: ${it.entry}"
|
||||
}
|
||||
)
|
||||
|
||||
sendNotification(notification, student)
|
||||
}
|
||||
|
||||
fun notifyPredicted(items: List<GradeSummary>, student: Student) {
|
||||
val notification = MultipleNotifications(
|
||||
type = NotificationType.NEW_GRADE_PREDICTED,
|
||||
icon = R.drawable.ic_stat_grade,
|
||||
titleStringRes = R.plurals.grade_new_items_predicted,
|
||||
contentStringRes = R.plurals.grade_notify_new_items_predicted,
|
||||
summaryStringRes = R.plurals.grade_number_item,
|
||||
startMenu = MainView.Section.GRADE,
|
||||
lines = items.map {
|
||||
"${it.subject}: ${it.predictedGrade}"
|
||||
}
|
||||
)
|
||||
|
||||
sendNotification(notification, student)
|
||||
}
|
||||
|
||||
fun notifyFinal(items: List<GradeSummary>, student: Student) {
|
||||
val notification = MultipleNotifications(
|
||||
type = NotificationType.NEW_GRADE_FINAL,
|
||||
icon = R.drawable.ic_stat_grade,
|
||||
titleStringRes = R.plurals.grade_new_items_final,
|
||||
contentStringRes = R.plurals.grade_notify_new_items_final,
|
||||
summaryStringRes = R.plurals.grade_number_item,
|
||||
startMenu = MainView.Section.GRADE,
|
||||
lines = items.map {
|
||||
"${it.subject}: ${it.finalGrade}"
|
||||
}
|
||||
)
|
||||
|
||||
sendNotification(notification, student)
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package io.github.wulkanowy.services.sync.notifications
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Homework
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.pojos.MultipleNotifications
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import java.time.LocalDate
|
||||
import javax.inject.Inject
|
||||
|
||||
class NewHomeworkNotification @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
notificationManager: NotificationManagerCompat,
|
||||
) : BaseNotification(context, notificationManager) {
|
||||
|
||||
fun notify(items: List<Homework>, student: Student) {
|
||||
val today = LocalDate.now()
|
||||
val lines = items.filter { !it.date.isBefore(today) }.map {
|
||||
"${it.date.toFormattedString("dd.MM")} - ${it.subject}: ${it.content}"
|
||||
}.ifEmpty { return }
|
||||
|
||||
val notification = MultipleNotifications(
|
||||
type = NotificationType.NEW_HOMEWORK,
|
||||
icon = R.drawable.ic_more_homework,
|
||||
titleStringRes = R.plurals.homework_notify_new_item_title,
|
||||
contentStringRes = R.plurals.homework_notify_new_item_content,
|
||||
summaryStringRes = R.plurals.homework_number_item,
|
||||
startMenu = MainView.Section.HOMEWORK,
|
||||
lines = lines
|
||||
)
|
||||
|
||||
sendNotification(notification, student)
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package io.github.wulkanowy.services.sync.notifications
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.pojos.OneNotification
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import javax.inject.Inject
|
||||
|
||||
class NewLuckyNumberNotification @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
notificationManager: NotificationManagerCompat,
|
||||
) : BaseNotification(context, notificationManager) {
|
||||
|
||||
fun notify(item: LuckyNumber, student: Student) {
|
||||
val notification = OneNotification(
|
||||
type = NotificationType.NEW_LUCKY_NUMBER,
|
||||
icon = R.drawable.ic_stat_luckynumber,
|
||||
titleStringRes = R.string.lucky_number_notify_new_item_title,
|
||||
contentStringRes = R.string.lucky_number_notify_new_item,
|
||||
startMenu = MainView.Section.LUCKY_NUMBER,
|
||||
contentValues = listOf(item.luckyNumber.toString())
|
||||
)
|
||||
|
||||
sendNotification(notification, student)
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package io.github.wulkanowy.services.sync.notifications
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.pojos.MultipleNotifications
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import javax.inject.Inject
|
||||
|
||||
class NewMessageNotification @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
notificationManager: NotificationManagerCompat,
|
||||
) : BaseNotification(context, notificationManager) {
|
||||
|
||||
fun notify(items: List<Message>, student: Student) {
|
||||
val notification = MultipleNotifications(
|
||||
type = NotificationType.NEW_MESSAGE,
|
||||
icon = R.drawable.ic_stat_message,
|
||||
titleStringRes = R.plurals.message_new_items,
|
||||
contentStringRes = R.plurals.message_notify_new_items,
|
||||
summaryStringRes = R.plurals.message_number_item,
|
||||
startMenu = MainView.Section.MESSAGE,
|
||||
lines = items.map {
|
||||
"${it.sender}: ${it.subject}"
|
||||
}
|
||||
)
|
||||
|
||||
sendNotification(notification, student)
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package io.github.wulkanowy.services.sync.notifications
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Note
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.pojos.MultipleNotifications
|
||||
import io.github.wulkanowy.sdk.scrapper.notes.NoteCategory
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import javax.inject.Inject
|
||||
|
||||
class NewNoteNotification @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
notificationManager: NotificationManagerCompat,
|
||||
) : BaseNotification(context, notificationManager) {
|
||||
|
||||
fun notify(items: List<Note>, student: Student) {
|
||||
val notification = MultipleNotifications(
|
||||
type = NotificationType.NEW_NOTE,
|
||||
icon = R.drawable.ic_stat_note,
|
||||
titleStringRes = when (NoteCategory.getByValue(items.first().categoryType)) {
|
||||
NoteCategory.POSITIVE -> R.plurals.praise_new_items
|
||||
NoteCategory.NEUTRAL -> R.plurals.neutral_note_new_items
|
||||
else -> R.plurals.note_new_items
|
||||
},
|
||||
contentStringRes = when (NoteCategory.getByValue(items.first().categoryType)) {
|
||||
NoteCategory.POSITIVE -> R.plurals.praise_notify_new_items
|
||||
NoteCategory.NEUTRAL -> R.plurals.neutral_note_notify_new_items
|
||||
else -> R.plurals.note_notify_new_items
|
||||
},
|
||||
summaryStringRes = when (NoteCategory.getByValue(items.first().categoryType)) {
|
||||
NoteCategory.POSITIVE -> R.plurals.praise_number_item
|
||||
NoteCategory.NEUTRAL -> R.plurals.neutral_note_number_item
|
||||
else -> R.plurals.note_number_item
|
||||
},
|
||||
startMenu = MainView.Section.NOTE,
|
||||
lines = items.map {
|
||||
"${it.teacher}: ${it.category}"
|
||||
}
|
||||
)
|
||||
|
||||
sendNotification(notification, student)
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package io.github.wulkanowy.services.sync.notifications
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.pojos.MultipleNotifications
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import javax.inject.Inject
|
||||
|
||||
class NewSchoolAnnouncementNotification @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
notificationManager: NotificationManagerCompat,
|
||||
) : BaseNotification(context, notificationManager) {
|
||||
|
||||
fun notify(items: List<SchoolAnnouncement>, student: Student) {
|
||||
val notification = MultipleNotifications(
|
||||
type = NotificationType.NEW_ANNOUNCEMENT,
|
||||
icon = R.drawable.ic_all_about,
|
||||
titleStringRes = R.plurals.school_announcement_notify_new_item_title,
|
||||
contentStringRes = R.plurals.school_announcement_notify_new_items,
|
||||
summaryStringRes = R.plurals.school_announcement_number_item,
|
||||
startMenu = MainView.Section.SCHOOL_ANNOUNCEMENT,
|
||||
lines = items.map {
|
||||
"${it.subject}: ${it.content}"
|
||||
}
|
||||
)
|
||||
|
||||
sendNotification(notification, student)
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package io.github.wulkanowy.services.sync.notifications
|
||||
|
||||
import io.github.wulkanowy.services.sync.channels.LuckyNumberChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewConferencesChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewExamChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewGradesChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewHomeworkChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewMessagesChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewNotesChannel
|
||||
import io.github.wulkanowy.services.sync.channels.NewSchoolAnnouncementsChannel
|
||||
|
||||
enum class NotificationType(val group: String, val channel: String) {
|
||||
NEW_CONFERENCE("new_conferences_group", NewConferencesChannel.CHANNEL_ID),
|
||||
NEW_EXAM("new_exam_group", NewExamChannel.CHANNEL_ID),
|
||||
NEW_GRADE_DETAILS("new_grade_details_group", NewGradesChannel.CHANNEL_ID),
|
||||
NEW_GRADE_PREDICTED("new_grade_predicted_group", NewGradesChannel.CHANNEL_ID),
|
||||
NEW_GRADE_FINAL("new_grade_final_group", NewGradesChannel.CHANNEL_ID),
|
||||
NEW_HOMEWORK("new_homework_group", NewHomeworkChannel.CHANNEL_ID),
|
||||
NEW_LUCKY_NUMBER("lucky_number_group", LuckyNumberChannel.CHANNEL_ID),
|
||||
NEW_MESSAGE("new_message_group", NewMessagesChannel.CHANNEL_ID),
|
||||
NEW_NOTE("new_notes_group", NewNotesChannel.CHANNEL_ID),
|
||||
NEW_ANNOUNCEMENT("new_school_announcements_group", NewSchoolAnnouncementsChannel.CHANNEL_ID),
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package io.github.wulkanowy.services.sync.works
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.ConferenceRepository
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.services.sync.notifications.NewConferenceNotification
|
||||
import io.github.wulkanowy.utils.waitForResult
|
||||
import kotlinx.coroutines.flow.first
|
||||
import javax.inject.Inject
|
||||
|
||||
class ConferenceWork @Inject constructor(
|
||||
private val conferenceRepository: ConferenceRepository,
|
||||
private val preferencesRepository: PreferencesRepository,
|
||||
private val newConferenceNotification: NewConferenceNotification,
|
||||
) : Work {
|
||||
|
||||
override suspend fun doWork(student: Student, semester: Semester) {
|
||||
conferenceRepository.getConferences(
|
||||
student = student,
|
||||
semester = semester,
|
||||
forceRefresh = true,
|
||||
notify = preferencesRepository.isNotificationsEnable
|
||||
).waitForResult()
|
||||
|
||||
conferenceRepository.getConferenceFromDatabase(semester).first()
|
||||
.filter { !it.isNotified }.let {
|
||||
if (it.isNotEmpty()) newConferenceNotification.notify(it, student)
|
||||
|
||||
conferenceRepository.updateConference(it.onEach { conference ->
|
||||
conference.isNotified = true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|