forked from github/wulkanowy-mirror
Compare commits
209 Commits
Author | SHA1 | Date | |
---|---|---|---|
4bce35f810 | |||
2d83218f61 | |||
d3e276d6fc | |||
51a1097bb4 | |||
db4f172fb8 | |||
4d49e956b8 | |||
b8296ac02f | |||
d6385e8cdd | |||
885319a885 | |||
fded5007c1 | |||
66ff14f719 | |||
1257dc63d3 | |||
50b6d380b6 | |||
62b7d42a73 | |||
21fe209246 | |||
02cd4e4e06 | |||
86fe2b61cb | |||
4113bd9b53 | |||
d924902dac | |||
b269360ecb | |||
ffd5addadb | |||
c5e2b18695 | |||
515a3973b7 | |||
7bee10d5ce | |||
22a4f509dc | |||
3925a6261b | |||
49b383fbe5 | |||
4a484dc2ce | |||
a14c4b489b | |||
e91cd18804 | |||
4c24363599 | |||
e20c232f8f | |||
1f11eea9b5 | |||
42f9a00e8c | |||
ad487e680c | |||
3f431022a5 | |||
cd037f0ce0 | |||
37f7f21a03 | |||
c653039590 | |||
95a90a7a79 | |||
4dc80595ac | |||
8114a2376e | |||
a523850216 | |||
354f51dd70 | |||
b271c12ebc | |||
8ca41b5ba3 | |||
edbe45332a | |||
1bbd249275 | |||
5148ff291b | |||
a1dc00af42 | |||
f1db993fee | |||
4f0519552e | |||
3625c5c518 | |||
afbfb9761f | |||
a5c636853a | |||
d5d45ed1ba | |||
d3f869c6c2 | |||
46c29c438e | |||
73a7255d3a | |||
c7af85e0e1 | |||
afc16e3d17 | |||
59f6f5c212 | |||
86f8763e69 | |||
157becb017 | |||
83ca9a7060 | |||
1033be4503 | |||
e67066f3ae | |||
bc22808b0e | |||
e05abb3539 | |||
6153c7b97d | |||
e574e5e2ec | |||
e6571a1dfc | |||
d566de0282 | |||
558db061f5 | |||
190f40ede8 | |||
4b795d6ef5 | |||
d139bd5b14 | |||
bf34cb0c1e | |||
eed091aad2 | |||
535206056d | |||
f2cb3b4f9e | |||
54372e0a55 | |||
5c17c38d1d | |||
f68a8e4215 | |||
70c2cb7dbf | |||
7f6fd60821 | |||
62c04fb205 | |||
10c36f19bf | |||
37d756b8fe | |||
de1bc4809f | |||
3d6ec93cde | |||
c293c76398 | |||
09e07a1713 | |||
71f1a55437 | |||
d9e22af5ef | |||
bc0689a30d | |||
9d47127921 | |||
08a3bd77bd | |||
9fe1151a04 | |||
793952cb44 | |||
d64a21b50c | |||
274f9dde07 | |||
5a884a4c56 | |||
c55fd98179 | |||
ffc0cd840b | |||
96067946d0 | |||
9339e7d916 | |||
b4117aa62e | |||
dc3a941e24 | |||
b67ecbba4b | |||
1175740ba2 | |||
378ed0100f | |||
cf87339ac4 | |||
c23a90f104 | |||
d337be0f40 | |||
cf7c6f78ea | |||
efa68f5044 | |||
b9be85d99c | |||
dfc4553fc6 | |||
08c9539abe | |||
fd18583df2 | |||
7c4f1c7b22 | |||
bdb6c962ea | |||
f1c217b087 | |||
4b6277abf5 | |||
344e0d55ff | |||
89a6a98bbf | |||
fcc7dc0913 | |||
1b74bffc06 | |||
0f11f14c3e | |||
e70fe6f097 | |||
b70649f136 | |||
7b13684137 | |||
c4689fcbb3 | |||
d8f644c5b4 | |||
c808bf2e61 | |||
0fb55bd6c6 | |||
c5dfea788c | |||
120e5c9171 | |||
a97039a727 | |||
e9ba65f8f6 | |||
a264abf814 | |||
0a2eb07844 | |||
bfab265ccf | |||
cd59166efb | |||
06ed5f6079 | |||
6b70583573 | |||
c3cbaa6ac2 | |||
f61d820d6f | |||
03ad5527f8 | |||
cce736410b | |||
8c515bd03f | |||
8dcb3ed45d | |||
4f3f24ac10 | |||
d074e5c9b3 | |||
d2d1d1dba7 | |||
891e241d1a | |||
5c4a3d578b | |||
fcf0adfd80 | |||
c42a47ac48 | |||
fa48b033af | |||
808927a58a | |||
dc717c9fb5 | |||
a2804d813a | |||
847ab6149a | |||
dc74d2877b | |||
6534176685 | |||
9542b9f231 | |||
dbba61a99f | |||
c2496a15b8 | |||
facf84d9a8 | |||
459c8330f9 | |||
0c8e2632a2 | |||
b17e9deca0 | |||
c296e72c30 | |||
637125e1fc | |||
445bfda801 | |||
ebde42328a | |||
a0bf14b576 | |||
2e7caabde3 | |||
bb052fd4c9 | |||
28ef8c6761 | |||
15e8e096ed | |||
6007de017f | |||
775b5122ef | |||
fed00122d7 | |||
426bee882c | |||
d37de197fc | |||
447ece3696 | |||
a73f39e59c | |||
f912aac140 | |||
3caabd3e0e | |||
88576271e2 | |||
b088551005 | |||
130e11a629 | |||
d5e0ae7b37 | |||
e6f56a74a4 | |||
1bc59cfa7f | |||
41bae262a5 | |||
ae65228805 | |||
391ee6e621 | |||
0a87df3d82 | |||
cb4ae21903 | |||
679cf2554d | |||
d473d53879 | |||
6531061b48 | |||
3347e8fba8 | |||
84067126a1 | |||
da9bebe923 |
21
.github/workflows/deploy-store.yml
vendored
21
.github/workflows/deploy-store.yml
vendored
@ -1,4 +1,4 @@
|
|||||||
name: Deploy to app stores
|
name: Deploy release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
@ -7,16 +7,17 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
deploy-google-play:
|
deploy-google-play:
|
||||||
name: Deploy to google play
|
name: Google Play
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
environment: google-play
|
environment: google-play
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
java-version: 11
|
java-version: 11
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
@ -37,20 +38,22 @@ jobs:
|
|||||||
ANDROID_PUBLISHER_CREDENTIALS: ${{ secrets.ANDROID_PUBLISHER_CREDENTIALS }}
|
ANDROID_PUBLISHER_CREDENTIALS: ${{ secrets.ANDROID_PUBLISHER_CREDENTIALS }}
|
||||||
ADMOB_PROJECT_ID: ${{ secrets.ADMOB_PROJECT_ID }}
|
ADMOB_PROJECT_ID: ${{ secrets.ADMOB_PROJECT_ID }}
|
||||||
SINGLE_SUPPORT_AD_ID: ${{ secrets.SINGLE_SUPPORT_AD_ID }}
|
SINGLE_SUPPORT_AD_ID: ${{ secrets.SINGLE_SUPPORT_AD_ID }}
|
||||||
|
DASHBOARD_TILE_AD_ID: ${{ secrets.DASHBOARD_TILE_AD_ID }}
|
||||||
SET_BUILD_TIMESTAMP: ${{ secrets.SET_BUILD_TIMESTAMP }}
|
SET_BUILD_TIMESTAMP: ${{ secrets.SET_BUILD_TIMESTAMP }}
|
||||||
run: ./gradlew publishPlayReleaseApps -PenableFirebase --stacktrace;
|
run: ./gradlew publishPlayReleaseApps -PenableFirebase --stacktrace;
|
||||||
|
|
||||||
deploy-app-gallery:
|
deploy-app-gallery:
|
||||||
name: Deploy to AppGallery
|
name: AppGallery
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
environment: app-gallery
|
environment: app-gallery
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
java-version: 11
|
java-version: 11
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
|
20
.github/workflows/deploy-test.yml
vendored
20
.github/workflows/deploy-test.yml
vendored
@ -1,4 +1,4 @@
|
|||||||
name: Deploy to app tests
|
name: Deploy DEV
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@ -18,11 +18,12 @@ jobs:
|
|||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
environment: app-center
|
environment: app-center
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
java-version: 11
|
java-version: 11
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
@ -66,7 +67,7 @@ jobs:
|
|||||||
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
|
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
|
||||||
run: ./gradlew assembleFdroidDebug --stacktrace
|
run: ./gradlew assembleFdroidDebug --stacktrace
|
||||||
- name: Upload apk to github artifacts
|
- name: Upload apk to github artifacts
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: wulkanowyDEV-${{ env.RUN_NUMBER }}.apk
|
name: wulkanowyDEV-${{ env.RUN_NUMBER }}.apk
|
||||||
path: app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk
|
path: app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk
|
||||||
@ -87,11 +88,12 @@ jobs:
|
|||||||
environment: app-distribution
|
environment: app-distribution
|
||||||
if: github.event_name != 'pull_request_target'
|
if: github.event_name != 'pull_request_target'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
java-version: 11
|
java-version: 11
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
@ -131,7 +133,7 @@ jobs:
|
|||||||
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
|
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
|
||||||
run: ./gradlew assemblePlayDebug -PenableFirebase --stacktrace
|
run: ./gradlew assemblePlayDebug -PenableFirebase --stacktrace
|
||||||
- name: Upload apk to github artifacts
|
- name: Upload apk to github artifacts
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: wulkanowyDEV-${{ env.RUN_NUMBER }}-dev.apk
|
name: wulkanowyDEV-${{ env.RUN_NUMBER }}-dev.apk
|
||||||
path: app/build/outputs/apk/play/debug/app-play-debug.apk
|
path: app/build/outputs/apk/play/debug/app-play-debug.apk
|
||||||
|
66
.github/workflows/test.yml
vendored
66
.github/workflows/test.yml
vendored
@ -8,18 +8,20 @@ on:
|
|||||||
branches: [ master, develop ]
|
branches: [ master, develop ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
unit-tests:
|
|
||||||
name: Unit tests
|
tests-fdroid:
|
||||||
|
name: F-Droid
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
- uses: fkirc/skip-duplicate-actions@master
|
- uses: fkirc/skip-duplicate-actions@master
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: gradle/wrapper-validation-action@v1
|
- uses: gradle/wrapper-validation-action@v1
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
java-version: 11
|
java-version: 11
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
@ -29,6 +31,58 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
./gradlew testFdroidDebugUnitTest --stacktrace
|
./gradlew testFdroidDebugUnitTest --stacktrace
|
||||||
./gradlew jacocoTestReport --stacktrace
|
./gradlew jacocoTestReport --stacktrace
|
||||||
- uses: codecov/codecov-action@v1
|
- uses: codecov/codecov-action@v3
|
||||||
|
with:
|
||||||
|
flags: unit
|
||||||
|
|
||||||
|
tests-play:
|
||||||
|
name: Play
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- uses: fkirc/skip-duplicate-actions@master
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: gradle/wrapper-validation-action@v1
|
||||||
|
- uses: actions/setup-java@v2
|
||||||
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
|
java-version: 11
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
./gradlew testPlayDebugUnitTest --stacktrace
|
||||||
|
./gradlew jacocoTestReport --stacktrace
|
||||||
|
- uses: codecov/codecov-action@v3
|
||||||
|
with:
|
||||||
|
flags: unit
|
||||||
|
|
||||||
|
tests-hms:
|
||||||
|
name: HMS
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- uses: fkirc/skip-duplicate-actions@master
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: gradle/wrapper-validation-action@v1
|
||||||
|
- uses: actions/setup-java@v2
|
||||||
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
|
java-version: 11
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
./gradlew testHmsDebugUnitTest --stacktrace
|
||||||
|
./gradlew jacocoTestReport --stacktrace
|
||||||
|
- uses: codecov/codecov-action@v3
|
||||||
with:
|
with:
|
||||||
flags: unit
|
flags: unit
|
||||||
|
11
README.cs.md
11
README.cs.md
@ -1,10 +1,4 @@
|
|||||||
[English version of README](README.en.md)
|
Česká verze / [Deutsche Version](README.de.md) / [English version](README.en.md) / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md)
|
||||||
|
|
||||||
[Deutsche Version von README](README.de.md)
|
|
||||||
|
|
||||||
[Polska wersja README](README.md)
|
|
||||||
|
|
||||||
[Slovenská verzia README](README.sk.md)
|
|
||||||
|
|
||||||
# Wulkanowy
|
# Wulkanowy
|
||||||
|
|
||||||
@ -13,6 +7,7 @@
|
|||||||
[](https://discord.gg/vccAQBr)
|
[](https://discord.gg/vccAQBr)
|
||||||
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
[](https://github.com/wulkanowy/wulkanowy/releases)
|
[](https://github.com/wulkanowy/wulkanowy/releases)
|
||||||
|
[](https://translate.wulkanowy.net.pl)
|
||||||
|
|
||||||
Neoficiální klient deníku VULCAN UONET+ pro žáka a rodiče
|
Neoficiální klient deníku VULCAN UONET+ pro žáka a rodiče
|
||||||
|
|
||||||
@ -57,7 +52,7 @@ Aktuální verzi si můžete stáhnout z Google Play, F-Droid nebo Huawei AppGal
|
|||||||
|
|
||||||
Můžete si také stáhnout [vývojovou verzi](https://wulkanowy.github.io/#download), která zahrnuje nové funkce připravované pro příští vydání
|
Můžete si také stáhnout [vývojovou verzi](https://wulkanowy.github.io/#download), která zahrnuje nové funkce připravované pro příští vydání
|
||||||
|
|
||||||
## Postaveno s
|
## Postaveno s pomocí
|
||||||
|
|
||||||
|
|
||||||
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
|
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
[Polska wersja README](README.md)
|
[Česká verze](README.cs.md) / Deutsche Version / [English version](README.en.md) / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md)
|
||||||
|
|
||||||
[English version of README](README.en.md)
|
|
||||||
|
|
||||||
# Wulkanowy
|
# Wulkanowy
|
||||||
|
|
||||||
@ -9,6 +7,7 @@
|
|||||||
[](https://discord.gg/vccAQBr)
|
[](https://discord.gg/vccAQBr)
|
||||||
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
[](https://github.com/wulkanowy/wulkanowy/releases)
|
[](https://github.com/wulkanowy/wulkanowy/releases)
|
||||||
|
[](https://translate.wulkanowy.net.pl)
|
||||||
|
|
||||||
Inoffizieller Android VULCAN UONET+ Registrierungsclient für Schüler und ihre Eltern
|
Inoffizieller Android VULCAN UONET+ Registrierungsclient für Schüler und ihre Eltern
|
||||||
|
|
||||||
@ -51,7 +50,7 @@ Die aktuelle Version können Sie von der Google Play, F-Droid oder Huawei AppGal
|
|||||||
alt="Explore it on AppGallery"
|
alt="Explore it on AppGallery"
|
||||||
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
|
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
|
||||||
|
|
||||||
Sie können auch ein [Entwicklungsversion herunterladen](https://wulkanowy.github.io/#download) das beinhaltet neue Funktionen, die für die nächste Version vorbereitet werden
|
Sie können auch eine [Entwicklungsversion herunterladen](https://wulkanowy.github.io/#download) die beinhaltet neue Funktionen, die für die nächste Version vorbereitet werden
|
||||||
|
|
||||||
## Gebaut mit
|
## Gebaut mit
|
||||||
|
|
||||||
|
@ -1,10 +1,4 @@
|
|||||||
[Polska wersja README](README.md)
|
[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / English version / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md)
|
||||||
|
|
||||||
[Deutsche Version von README](README.de.md)
|
|
||||||
|
|
||||||
[Česká verze README](README.cs.md)
|
|
||||||
|
|
||||||
[Slovenská verzia README](README.sk.md)
|
|
||||||
|
|
||||||
# Wulkanowy
|
# Wulkanowy
|
||||||
|
|
||||||
@ -13,6 +7,7 @@
|
|||||||
[](https://discord.gg/vccAQBr)
|
[](https://discord.gg/vccAQBr)
|
||||||
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
[](https://github.com/wulkanowy/wulkanowy/releases)
|
[](https://github.com/wulkanowy/wulkanowy/releases)
|
||||||
|
[](https://translate.wulkanowy.net.pl)
|
||||||
|
|
||||||
Unofficial android VULCAN UONET+ register client for both students and their parents
|
Unofficial android VULCAN UONET+ register client for both students and their parents
|
||||||
|
|
||||||
|
@ -1,10 +1,4 @@
|
|||||||
[English version of README](README.en.md)
|
[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / [English version](README.en.md) / Polska wersja / [Slovenská verzia](README.sk.md)
|
||||||
|
|
||||||
[Deutsche Version von README](README.de.md)
|
|
||||||
|
|
||||||
[Česká verze README](README.cs.md)
|
|
||||||
|
|
||||||
[Slovenská verzia README](README.sk.md)
|
|
||||||
|
|
||||||
# Wulkanowy
|
# Wulkanowy
|
||||||
|
|
||||||
@ -13,6 +7,7 @@
|
|||||||
[](https://discord.gg/vccAQBr)
|
[](https://discord.gg/vccAQBr)
|
||||||
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
[](https://github.com/wulkanowy/wulkanowy/releases)
|
[](https://github.com/wulkanowy/wulkanowy/releases)
|
||||||
|
[](https://translate.wulkanowy.net.pl)
|
||||||
|
|
||||||
Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
|
Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
|
||||||
|
|
||||||
|
11
README.sk.md
11
README.sk.md
@ -1,10 +1,4 @@
|
|||||||
[English version of README](README.en.md)
|
[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / [English version](README.en.md) / [Polska wersja](README.md) / Slovenská verzia
|
||||||
|
|
||||||
[Deutsche Version von README](README.de.md)
|
|
||||||
|
|
||||||
[Polska wersja README](README.md)
|
|
||||||
|
|
||||||
[Česká verze README](README.cs.md)
|
|
||||||
|
|
||||||
# Wulkanowy
|
# Wulkanowy
|
||||||
|
|
||||||
@ -13,6 +7,7 @@
|
|||||||
[](https://discord.gg/vccAQBr)
|
[](https://discord.gg/vccAQBr)
|
||||||
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
[](https://github.com/wulkanowy/wulkanowy/releases)
|
[](https://github.com/wulkanowy/wulkanowy/releases)
|
||||||
|
[](https://translate.wulkanowy.net.pl)
|
||||||
|
|
||||||
Neoficiálny klient denníka VULCAN UONET+ pre žiaka a rodičov
|
Neoficiálny klient denníka VULCAN UONET+ pre žiaka a rodičov
|
||||||
|
|
||||||
@ -57,7 +52,7 @@ Aktuálnu verziu si môžete stiahnuť z Google Play, F-Droid alebo Huawei AppGa
|
|||||||
|
|
||||||
Môžete si tiež stiahnuť [vývojovú verziu](https://wulkanowy.github.io/#download), ktorá zahrňuje nové funkcie pripravované pre budúce vydanie
|
Môžete si tiež stiahnuť [vývojovú verziu](https://wulkanowy.github.io/#download), ktorá zahrňuje nové funkcie pripravované pre budúce vydanie
|
||||||
|
|
||||||
## Postavené s
|
## Postavené s pomocou
|
||||||
|
|
||||||
|
|
||||||
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
|
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
|
||||||
|
@ -15,33 +15,35 @@ apply from: 'sonarqube.gradle'
|
|||||||
apply from: 'hooks.gradle'
|
apply from: 'hooks.gradle'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 31
|
namespace 'io.github.wulkanowy'
|
||||||
|
compileSdkVersion 32
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "io.github.wulkanowy"
|
applicationId "io.github.wulkanowy"
|
||||||
testApplicationId "io.github.tests.wulkanowy"
|
testApplicationId "io.github.tests.wulkanowy"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 31
|
targetSdkVersion 32
|
||||||
versionCode 104
|
versionCode 115
|
||||||
versionName "1.6.0"
|
versionName "1.8.0"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
resValue "string", "app_name", "Wulkanowy"
|
resValue "string", "app_name", "Wulkanowy"
|
||||||
|
|
||||||
manifestPlaceholders = [
|
manifestPlaceholders = [
|
||||||
firebase_enabled: project.hasProperty("enableFirebase"),
|
firebase_enabled: project.hasProperty("enableFirebase"),
|
||||||
admob_project_id: ""
|
admob_project_id: ""
|
||||||
]
|
]
|
||||||
javaCompileOptions {
|
javaCompileOptions {
|
||||||
annotationProcessorOptions {
|
annotationProcessorOptions {
|
||||||
arguments += [
|
arguments += [
|
||||||
"room.schemaLocation": "$projectDir/schemas".toString(),
|
"room.schemaLocation": "$projectDir/schemas".toString(),
|
||||||
"room.incremental" : "true"
|
"room.incremental" : "true"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "null"
|
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "null"
|
||||||
|
buildConfigField "String", "DASHBOARD_TILE_AD_ID", "null"
|
||||||
|
|
||||||
if (System.env.SET_BUILD_TIMESTAMP) {
|
if (System.env.SET_BUILD_TIMESTAMP) {
|
||||||
buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis())
|
buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis())
|
||||||
@ -94,10 +96,12 @@ android {
|
|||||||
play {
|
play {
|
||||||
dimension "platform"
|
dimension "platform"
|
||||||
manifestPlaceholders = [
|
manifestPlaceholders = [
|
||||||
install_channel : "Google Play",
|
install_channel : "Google Play",
|
||||||
admob_project_id: System.getenv("ADMOB_PROJECT_ID") ?: "ca-app-pub-3940256099942544~3347511713"
|
admob_project_id: System.getenv("ADMOB_PROJECT_ID") ?: "ca-app-pub-3940256099942544~3347511713"
|
||||||
]
|
]
|
||||||
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "\"${System.getenv("SINGLE_SUPPORT_AD_ID") ?: "ca-app-pub-3940256099942544/5354046379"}\""
|
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "\"${System.getenv("SINGLE_SUPPORT_AD_ID") ?: "ca-app-pub-3940256099942544/5354046379"}\""
|
||||||
|
buildConfigField "String", "DASHBOARD_TILE_AD_ID", "\"${System.getenv("DASHBOARD_TILE_AD_ID") ?: "ca-app-pub-3940256099942544/6300978111"}\""
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fdroid {
|
fdroid {
|
||||||
@ -122,6 +126,8 @@ android {
|
|||||||
|
|
||||||
testOptions.unitTests {
|
testOptions.unitTests {
|
||||||
includeAndroidResources = true
|
includeAndroidResources = true
|
||||||
|
// workaround HMS test errors https://github.com/robolectric/robolectric/issues/2750
|
||||||
|
all { jvmArgs '-noverify' }
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
@ -132,12 +138,14 @@ android {
|
|||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "11"
|
jvmTarget = "11"
|
||||||
freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn", "-Xjvm-default=all"]
|
freeCompilerArgs += ["-opt-in=kotlin.RequiresOptIn", "-Xjvm-default=all"]
|
||||||
}
|
}
|
||||||
|
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
exclude 'META-INF/library_release.kotlin_module'
|
resources {
|
||||||
exclude 'META-INF/library-core_release.kotlin_module'
|
excludes += ['META-INF/library_release.kotlin_module',
|
||||||
|
'META-INF/library-core_release.kotlin_module']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
aboutLibraries {
|
aboutLibraries {
|
||||||
@ -154,7 +162,7 @@ play {
|
|||||||
track = 'production'
|
track = 'production'
|
||||||
releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS
|
releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS
|
||||||
userFraction = 0.25d
|
userFraction = 0.25d
|
||||||
updatePriority = 1
|
updatePriority = 4
|
||||||
enabled.set(false)
|
enabled.set(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,42 +179,42 @@ huaweiPublish {
|
|||||||
ext {
|
ext {
|
||||||
work_manager = "2.7.1"
|
work_manager = "2.7.1"
|
||||||
android_hilt = "1.0.0"
|
android_hilt = "1.0.0"
|
||||||
room = "2.4.2"
|
room = "2.4.3"
|
||||||
chucker = "3.5.2"
|
chucker = "3.5.2"
|
||||||
mockk = "1.12.2"
|
mockk = "1.13.2"
|
||||||
coroutines = "1.6.0"
|
coroutines = "1.6.4"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "io.github.wulkanowy:sdk:1.6.0"
|
implementation "io.github.wulkanowy:sdk:1.8.0"
|
||||||
|
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2"
|
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
|
||||||
|
|
||||||
implementation "androidx.core:core-ktx:1.7.0"
|
implementation "androidx.core:core-ktx:1.8.0"
|
||||||
implementation 'androidx.core:core-splashscreen:1.0.0-beta02'
|
implementation 'androidx.core:core-splashscreen:1.0.0'
|
||||||
implementation "androidx.activity:activity-ktx:1.4.0"
|
implementation "androidx.activity:activity-ktx:1.5.1"
|
||||||
implementation "androidx.appcompat:appcompat:1.4.1"
|
implementation "androidx.appcompat:appcompat:1.5.1"
|
||||||
implementation "androidx.fragment:fragment-ktx:1.4.1"
|
implementation "androidx.fragment:fragment-ktx:1.5.4"
|
||||||
implementation "androidx.annotation:annotation:1.3.0"
|
implementation "androidx.annotation:annotation:1.5.0"
|
||||||
|
|
||||||
implementation "androidx.preference:preference-ktx:1.2.0"
|
implementation "androidx.preference:preference-ktx:1.2.0"
|
||||||
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
||||||
implementation "androidx.viewpager2:viewpager2:1.1.0-beta01"
|
implementation "androidx.viewpager2:viewpager2:1.1.0-beta01"
|
||||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||||
implementation "androidx.constraintlayout:constraintlayout:2.1.3"
|
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
|
||||||
implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
|
implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
|
||||||
implementation "com.google.android.material:material:1.5.0"
|
implementation "com.google.android.material:material:1.7.0"
|
||||||
implementation "com.github.wulkanowy:material-chips-input:2.3.1"
|
implementation "com.github.wulkanowy:material-chips-input:2.3.1"
|
||||||
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
|
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
|
||||||
implementation 'com.github.lopspower:CircularImageView:4.2.0'
|
implementation 'com.github.lopspower:CircularImageView:4.3.0'
|
||||||
|
|
||||||
implementation "androidx.work:work-runtime-ktx:$work_manager"
|
implementation "androidx.work:work-runtime-ktx:$work_manager"
|
||||||
playImplementation "androidx.work:work-gcm:$work_manager"
|
playImplementation "androidx.work:work-gcm:$work_manager"
|
||||||
|
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1"
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
|
||||||
|
|
||||||
implementation "androidx.room:room-runtime:$room"
|
implementation "androidx.room:room-runtime:$room"
|
||||||
implementation "androidx.room:room-ktx:$room"
|
implementation "androidx.room:room-ktx:$room"
|
||||||
@ -222,27 +230,27 @@ dependencies {
|
|||||||
|
|
||||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||||
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0"
|
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0"
|
||||||
implementation "com.squareup.okhttp3:logging-interceptor:4.9.3"
|
implementation "com.squareup.okhttp3:logging-interceptor:4.10.0"
|
||||||
|
|
||||||
implementation "com.jakewharton.timber:timber:5.0.1"
|
implementation "com.jakewharton.timber:timber:5.0.1"
|
||||||
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
||||||
implementation 'com.github.bastienpaulfr:Treessence:1.0.5'
|
implementation 'com.github.bastienpaulfr:Treessence:1.0.5'
|
||||||
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
||||||
implementation "io.coil-kt:coil:1.4.0"
|
implementation "io.coil-kt:coil:2.2.2"
|
||||||
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
|
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
|
||||||
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
|
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
|
||||||
implementation 'com.fredporciuncula:flow-preferences:1.6.0'
|
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
|
||||||
|
|
||||||
playImplementation platform('com.google.firebase:firebase-bom:29.3.0')
|
playImplementation platform('com.google.firebase:firebase-bom:31.0.3')
|
||||||
playImplementation 'com.google.firebase:firebase-analytics-ktx'
|
playImplementation 'com.google.firebase:firebase-analytics-ktx'
|
||||||
playImplementation 'com.google.firebase:firebase-messaging:'
|
playImplementation 'com.google.firebase:firebase-messaging:'
|
||||||
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
||||||
playImplementation 'com.google.android.play:core:1.10.3'
|
playImplementation 'com.google.android.play:core:1.10.3'
|
||||||
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
||||||
playImplementation 'com.google.android.gms:play-services-ads:20.6.0'
|
playImplementation 'com.google.android.gms:play-services-ads:21.3.0'
|
||||||
|
|
||||||
hmsImplementation 'com.huawei.hms:hianalytics:6.4.1.300'
|
hmsImplementation 'com.huawei.hms:hianalytics:6.8.0.300'
|
||||||
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.5.200'
|
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.3.300'
|
||||||
|
|
||||||
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
||||||
|
|
||||||
@ -255,10 +263,10 @@ dependencies {
|
|||||||
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines"
|
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines"
|
||||||
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
|
|
||||||
testImplementation 'org.robolectric:robolectric:4.7.3'
|
testImplementation 'org.robolectric:robolectric:4.9'
|
||||||
testImplementation "androidx.test:runner:1.4.0"
|
testImplementation "androidx.test:runner:1.5.1"
|
||||||
testImplementation "androidx.test.ext:junit:1.1.3"
|
testImplementation "androidx.test.ext:junit:1.1.4"
|
||||||
testImplementation "androidx.test:core:1.4.0"
|
testImplementation "androidx.test:core:1.5.0"
|
||||||
testImplementation "androidx.room:room-testing:$room"
|
testImplementation "androidx.room:room-testing:$room"
|
||||||
testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
|
testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
|
||||||
kaptTest "com.google.dagger:hilt-android-compiler:$hilt_version"
|
kaptTest "com.google.dagger:hilt-android-compiler:$hilt_version"
|
||||||
|
2445
app/schemas/io.github.wulkanowy.data.db.AppDatabase/49.json
Normal file
2445
app/schemas/io.github.wulkanowy.data.db.AppDatabase/49.json
Normal file
File diff suppressed because it is too large
Load Diff
2445
app/schemas/io.github.wulkanowy.data.db.AppDatabase/50.json
Normal file
2445
app/schemas/io.github.wulkanowy.data.db.AppDatabase/50.json
Normal file
File diff suppressed because it is too large
Load Diff
2409
app/schemas/io.github.wulkanowy.data.db.AppDatabase/51.json
Normal file
2409
app/schemas/io.github.wulkanowy.data.db.AppDatabase/51.json
Normal file
File diff suppressed because it is too large
Load Diff
2421
app/schemas/io.github.wulkanowy.data.db.AppDatabase/52.json
Normal file
2421
app/schemas/io.github.wulkanowy.data.db.AppDatabase/52.json
Normal file
File diff suppressed because it is too large
Load Diff
2439
app/schemas/io.github.wulkanowy.data.db.AppDatabase/53.json
Normal file
2439
app/schemas/io.github.wulkanowy.data.db.AppDatabase/53.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,33 +1,92 @@
|
|||||||
{
|
{
|
||||||
"agcgw":{
|
"agcgw": {
|
||||||
"backurl":"connect-dre.dbankcloud.cn",
|
"backurl": "connect-dre.hispace.hicloud.com",
|
||||||
"url":"connect-dre.hispace.hicloud.com"
|
"url": "connect-dre.dbankcloud.cn",
|
||||||
},
|
"websocketbackurl": "connect-ws-dre.hispace.dbankcloud.com",
|
||||||
"client":{
|
"websocketurl": "connect-ws-dre.hispace.dbankcloud.cn"
|
||||||
"cp_id":"890048000024105546",
|
},
|
||||||
"product_id":"",
|
"agcgw_all": {
|
||||||
"client_id":"",
|
"CN": "connect-drcn.dbankcloud.cn",
|
||||||
"client_secret":"",
|
"CN_back": "connect-drcn.hispace.hicloud.com",
|
||||||
"app_id":"101440411",
|
"DE": "connect-dre.dbankcloud.cn",
|
||||||
"package_name":"io.github.wulkanowy.dev",
|
"DE_back": "connect-dre.hispace.hicloud.com",
|
||||||
"api_key":""
|
"RU": "connect-drru.hispace.dbankcloud.ru",
|
||||||
},
|
"RU_back": "connect-drru.hispace.dbankcloud.cn",
|
||||||
"service":{
|
"SG": "connect-dra.dbankcloud.cn",
|
||||||
"analytics":{
|
"SG_back": "connect-dra.hispace.hicloud.com"
|
||||||
"collector_url":"datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
|
},
|
||||||
"resource_id":"p1",
|
"websocketgw_all": {
|
||||||
"channel_id":""
|
"CN": "connect-ws-drcn.hispace.dbankcloud.cn",
|
||||||
},
|
"CN_back": "connect-ws-drcn.hispace.dbankcloud.com",
|
||||||
|
"DE": "connect-ws-dre.hispace.dbankcloud.cn",
|
||||||
|
"DE_back": "connect-ws-dre.hispace.dbankcloud.com",
|
||||||
|
"RU": "connect-ws-drru.hispace.dbankcloud.ru",
|
||||||
|
"RU_back": "connect-ws-drru.hispace.dbankcloud.cn",
|
||||||
|
"SG": "connect-ws-dra.hispace.dbankcloud.cn",
|
||||||
|
"SG_back": "connect-ws-dra.hispace.dbankcloud.com"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"cp_id": "890048000024105546",
|
||||||
|
"product_id": "736430079244736562",
|
||||||
|
"client_id": "514530959291319360",
|
||||||
|
"client_secret": "C42522DBF17D3D4BBE9D9C1783A54484B7E6844B388B7A67502D36A633A4186B",
|
||||||
|
"project_id": "736430079244736562",
|
||||||
|
"app_id": "106552551",
|
||||||
|
"api_key": "CgB6e3x9BUNiq+r8ebCHNojjjYsMT4pJSjjNDOkm9owtBb6rVI6LjnASoZBRxbjjhObcrV5gANo99fI/eKZDTbWS",
|
||||||
|
"package_name": "io.github.wulkanowy.dev"
|
||||||
|
},
|
||||||
|
"oauth_client": {
|
||||||
|
"client_id": "106552551",
|
||||||
|
"client_type": 1
|
||||||
|
},
|
||||||
|
"app_info": {
|
||||||
|
"app_id": "106552551",
|
||||||
|
"package_name": "io.github.wulkanowy.dev"
|
||||||
|
},
|
||||||
|
"service": {
|
||||||
|
"analytics": {
|
||||||
|
"collector_url": "datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
|
||||||
|
"collector_url_ru": "datacollector-drru.dt.dbankcloud.ru,datacollector-drru.dt.hicloud.com",
|
||||||
|
"collector_url_sg": "datacollector-dra.dt.hicloud.com,datacollector-dra.dt.dbankcloud.cn",
|
||||||
|
"collector_url_de": "datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
|
||||||
|
"collector_url_cn": "datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn",
|
||||||
|
"resource_id": "p1",
|
||||||
|
"channel_id": ""
|
||||||
|
},
|
||||||
"search":{
|
"search":{
|
||||||
"url":"https://search-dre.cloud.huawei.com"
|
"url":"https://search-dre.cloud.huawei.com"
|
||||||
},
|
},
|
||||||
"cloudstorage":{
|
"cloudstorage": {
|
||||||
"storage_url":"https://ops-dre.agcstorage.link"
|
"storage_url_sg_back": "https://agc-storage-dra.cloud.huawei.asia",
|
||||||
},
|
"storage_url_ru_back": "https://agc-storage-drru.cloud.huawei.ru",
|
||||||
"ml":{
|
"storage_url_ru": "https://agc-storage-drru.cloud.huawei.ru",
|
||||||
"mlservice_url":"ml-api-dre.ai.dbankcloud.com,ml-api-dre.ai.dbankcloud.cn"
|
"storage_url_de_back": "https://agc-storage-dre.cloud.huawei.eu",
|
||||||
}
|
"storage_url_de": "https://ops-dre.agcstorage.link",
|
||||||
},
|
"storage_url": "https://agc-storage-drcn.platform.dbankcloud.cn",
|
||||||
"region":"DE",
|
"storage_url_sg": "https://ops-dra.agcstorage.link",
|
||||||
"configuration_version":"1.0"
|
"storage_url_cn_back": "https://agc-storage-drcn.cloud.huawei.com.cn",
|
||||||
|
"storage_url_cn": "https://agc-storage-drcn.platform.dbankcloud.cn"
|
||||||
|
},
|
||||||
|
"ml": {
|
||||||
|
"mlservice_url": "ml-api-dre.ai.dbankcloud.com,ml-api-dre.ai.dbankcloud.cn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"region": "DE",
|
||||||
|
"configuration_version": "3.0",
|
||||||
|
"appInfos": [
|
||||||
|
{
|
||||||
|
"package_name": "io.github.wulkanowy.dev",
|
||||||
|
"client": {
|
||||||
|
"app_id": "106552551"
|
||||||
|
},
|
||||||
|
"app_info": {
|
||||||
|
"package_name": "io.github.wulkanowy.dev",
|
||||||
|
"app_id": "106552551"
|
||||||
|
},
|
||||||
|
"oauth_client": {
|
||||||
|
"client_type": 1,
|
||||||
|
"client_id": "106552551"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
28
app/src/fdroid/java/io/github/wulkanowy/utils/AdsHelper.kt
Normal file
28
app/src/fdroid/java/io/github/wulkanowy/utils/AdsHelper.kt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package io.github.wulkanowy.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
class AdsHelper @Inject constructor(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
|
private val preferencesRepository: PreferencesRepository
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun initialize() {
|
||||||
|
preferencesRepository.isAdsEnabled = false
|
||||||
|
preferencesRepository.isAgreeToProcessData = false
|
||||||
|
preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("RedundantSuspendModifier", "UNUSED_PARAMETER")
|
||||||
|
suspend fun getDashboardTileAdBanner(width: Int): AdBanner {
|
||||||
|
throw IllegalStateException("Can't get ad banner (F-droid)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class AdBanner(val view: View)
|
@ -8,15 +8,7 @@ import javax.inject.Singleton
|
|||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
class AnalyticsHelper @Inject constructor() {
|
class AnalyticsHelper @Inject constructor() {
|
||||||
|
|
||||||
fun logEvent(name: String, vararg params: Pair<String, Any?>) {
|
fun logEvent(name: String, vararg params: Pair<String, Any?>) = Unit
|
||||||
// do nothing
|
fun setCurrentScreen(activity: Activity, name: String?) = Unit
|
||||||
}
|
fun popCurrentScreen(name: String?) = Unit
|
||||||
|
|
||||||
fun setCurrentScreen(activity: Activity, name: String?) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
fun popCurrentScreen(name: String?) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
28
app/src/hms/java/io/github/wulkanowy/utils/AdsHelper.kt
Normal file
28
app/src/hms/java/io/github/wulkanowy/utils/AdsHelper.kt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package io.github.wulkanowy.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
class AdsHelper @Inject constructor(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
|
private val preferencesRepository: PreferencesRepository
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun initialize() {
|
||||||
|
preferencesRepository.isAdsEnabled = false
|
||||||
|
preferencesRepository.isAgreeToProcessData = false
|
||||||
|
preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("RedundantSuspendModifier", "UNUSED_PARAMETER")
|
||||||
|
suspend fun getDashboardTileAdBanner(width: Int): AdBanner {
|
||||||
|
throw IllegalStateException("Can't get ad banner (HMS)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class AdBanner(val view: View)
|
@ -3,26 +3,38 @@ package io.github.wulkanowy.utils
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import com.huawei.agconnect.crash.AGConnectCrash
|
||||||
import com.huawei.hms.analytics.HiAnalytics
|
import com.huawei.hms.analytics.HiAnalytics
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class AnalyticsHelper @Inject constructor(
|
class AnalyticsHelper @Inject constructor(
|
||||||
@ApplicationContext private val context: Context
|
@ApplicationContext private val context: Context,
|
||||||
|
preferencesRepository: PreferencesRepository,
|
||||||
|
appInfo: AppInfo,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val analytics by lazy { HiAnalytics.getInstance(context) }
|
private val analytics by lazy { HiAnalytics.getInstance(context) }
|
||||||
|
|
||||||
|
private val connectCrash by lazy { AGConnectCrash.getInstance() }
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (!appInfo.isDebug) {
|
||||||
|
connectCrash.setUserId(preferencesRepository.installationId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun logEvent(name: String, vararg params: Pair<String, Any?>) {
|
fun logEvent(name: String, vararg params: Pair<String, Any?>) {
|
||||||
Bundle().apply {
|
Bundle().apply {
|
||||||
params.forEach {
|
params.forEach { (key, value) ->
|
||||||
if (it.second == null) return@forEach
|
if (value == null) return@forEach
|
||||||
when (it.second) {
|
when (value) {
|
||||||
is String, is String? -> putString(it.first, it.second as String)
|
is String -> putString(key, value)
|
||||||
is Int, is Int? -> putInt(it.first, it.second as Int)
|
is Int -> putInt(key, value)
|
||||||
is Boolean, is Boolean? -> putBoolean(it.first, it.second as Boolean)
|
is Boolean -> putBoolean(key, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
analytics.onEvent(name, this)
|
analytics.onEvent(name, this)
|
||||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.utils
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.huawei.agconnect.crash.AGConnectCrash
|
import com.huawei.agconnect.crash.AGConnectCrash
|
||||||
import fr.bipi.tressence.base.FormatterPriorityTree
|
import fr.bipi.tressence.base.FormatterPriorityTree
|
||||||
|
import fr.bipi.tressence.common.StackTraceRecorder
|
||||||
|
|
||||||
class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) {
|
class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) {
|
||||||
|
|
||||||
@ -22,16 +23,10 @@ class CrashLogExceptionTree : FormatterPriorityTree(Log.ERROR, ExceptionFilter)
|
|||||||
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
||||||
if (skipLog(priority, tag, message, t)) return
|
if (skipLog(priority, tag, message, t)) return
|
||||||
|
|
||||||
// Disabled due to a bug in the Huawei library
|
|
||||||
|
|
||||||
/*connectCrash.setCustomKey("priority", priority)
|
|
||||||
connectCrash.setCustomKey("tag", tag.orEmpty())
|
|
||||||
connectCrash.setCustomKey("message", message)
|
|
||||||
|
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
connectCrash.recordException(t)
|
connectCrash.recordException(t)
|
||||||
} else {
|
} else {
|
||||||
connectCrash.recordException(StackTraceRecorder(format(priority, tag, message)))
|
connectCrash.recordException(StackTraceRecorder(format(priority, tag, message)))
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import javax.inject.Inject
|
|||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
|
@Suppress("UNUSED_PARAMETER", "unused")
|
||||||
class InAppReviewHelper @Inject constructor(
|
class InAppReviewHelper @Inject constructor(
|
||||||
@ApplicationContext private val context: Context
|
@ApplicationContext private val context: Context
|
||||||
) {
|
) {
|
||||||
@ -14,4 +15,4 @@ class InAppReviewHelper @Inject constructor(
|
|||||||
fun showInAppReview(activity: MainActivity) {
|
fun showInAppReview(activity: MainActivity) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="io.github.wulkanowy"
|
|
||||||
android:installLocation="internalOnly">
|
android:installLocation="internalOnly">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
@ -31,10 +31,14 @@ class WulkanowyApp : Application(), Configuration.Provider {
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var analyticsHelper: AnalyticsHelper
|
lateinit var analyticsHelper: AnalyticsHelper
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var adsHelper: AdsHelper
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
initializeAppLanguage()
|
initializeAppLanguage()
|
||||||
themeManager.applyDefaultTheme()
|
themeManager.applyDefaultTheme()
|
||||||
|
adsHelper.initialize()
|
||||||
initLogging()
|
initLogging()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@ import io.github.wulkanowy.data.db.SharedPrefProvider
|
|||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.AppInfo
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
@ -110,7 +109,6 @@ internal class DataModule {
|
|||||||
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences =
|
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences =
|
||||||
PreferenceManager.getDefaultSharedPreferences(context)
|
PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideFlowSharedPref(sharedPreferences: SharedPreferences) =
|
fun provideFlowSharedPref(sharedPreferences: SharedPreferences) =
|
||||||
@ -197,7 +195,7 @@ internal class DataModule {
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideReportingUnitDao(database: AppDatabase) = database.reportingUnitDao
|
fun provideMailboxesDao(database: AppDatabase) = database.mailboxDao
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -30,7 +30,7 @@ import javax.inject.Singleton
|
|||||||
Subject::class,
|
Subject::class,
|
||||||
LuckyNumber::class,
|
LuckyNumber::class,
|
||||||
CompletedLesson::class,
|
CompletedLesson::class,
|
||||||
ReportingUnit::class,
|
Mailbox::class,
|
||||||
Recipient::class,
|
Recipient::class,
|
||||||
MobileDevice::class,
|
MobileDevice::class,
|
||||||
Teacher::class,
|
Teacher::class,
|
||||||
@ -47,6 +47,7 @@ import javax.inject.Singleton
|
|||||||
AutoMigration(from = 44, to = 45),
|
AutoMigration(from = 44, to = 45),
|
||||||
AutoMigration(from = 46, to = 47),
|
AutoMigration(from = 46, to = 47),
|
||||||
AutoMigration(from = 47, to = 48),
|
AutoMigration(from = 47, to = 48),
|
||||||
|
AutoMigration(from = 51, to = 52),
|
||||||
],
|
],
|
||||||
version = AppDatabase.VERSION_SCHEMA,
|
version = AppDatabase.VERSION_SCHEMA,
|
||||||
exportSchema = true
|
exportSchema = true
|
||||||
@ -55,7 +56,7 @@ import javax.inject.Singleton
|
|||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val VERSION_SCHEMA = 48
|
const val VERSION_SCHEMA = 53
|
||||||
|
|
||||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
||||||
Migration2(),
|
Migration2(),
|
||||||
@ -102,6 +103,10 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
Migration43(),
|
Migration43(),
|
||||||
Migration44(),
|
Migration44(),
|
||||||
Migration46(),
|
Migration46(),
|
||||||
|
Migration49(),
|
||||||
|
Migration50(),
|
||||||
|
Migration51(),
|
||||||
|
Migration53(),
|
||||||
)
|
)
|
||||||
|
|
||||||
fun newInstance(
|
fun newInstance(
|
||||||
@ -152,7 +157,7 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
|
|
||||||
abstract val completedLessonsDao: CompletedLessonsDao
|
abstract val completedLessonsDao: CompletedLessonsDao
|
||||||
|
|
||||||
abstract val reportingUnitDao: ReportingUnitDao
|
abstract val mailboxDao: MailboxDao
|
||||||
|
|
||||||
abstract val recipientDao: RecipientDao
|
abstract val recipientDao: RecipientDao
|
||||||
|
|
||||||
|
@ -2,11 +2,12 @@ package io.github.wulkanowy.data.db.dao
|
|||||||
|
|
||||||
import androidx.room.Delete
|
import androidx.room.Delete
|
||||||
import androidx.room.Insert
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
import androidx.room.Update
|
import androidx.room.Update
|
||||||
|
|
||||||
interface BaseDao<T> {
|
interface BaseDao<T> {
|
||||||
|
|
||||||
@Insert
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
suspend fun insertAll(items: List<T>): List<Long>
|
suspend fun insertAll(items: List<T>): List<Long>
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package io.github.wulkanowy.data.db.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Dao
|
||||||
|
interface MailboxDao : BaseDao<Mailbox> {
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Mailboxes WHERE email = :email")
|
||||||
|
suspend fun loadAll(email: String): List<Mailbox>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Mailboxes WHERE email = :email AND symbol = :symbol AND schoolId = :schoolId")
|
||||||
|
fun loadAll(email: String, symbol: String, schoolId: String): Flow<List<Mailbox>>
|
||||||
|
}
|
@ -11,9 +11,12 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
interface MessagesDao : BaseDao<Message> {
|
interface MessagesDao : BaseDao<Message> {
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND message_id = :messageId")
|
@Query("SELECT * FROM Messages WHERE message_global_key = :messageGlobalKey")
|
||||||
fun loadMessageWithAttachment(studentId: Int, messageId: Int): Flow<MessageWithAttachment?>
|
fun loadMessageWithAttachment(messageGlobalKey: String): Flow<MessageWithAttachment?>
|
||||||
|
|
||||||
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder ORDER BY date DESC")
|
@Query("SELECT * FROM Messages WHERE mailbox_key = :mailboxKey AND folder_id = :folder ORDER BY date DESC")
|
||||||
fun loadAll(studentId: Int, folder: Int): Flow<List<Message>>
|
fun loadAll(mailboxKey: String, folder: Int): Flow<List<Message>>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Messages WHERE email = :email AND folder_id = :folder ORDER BY date DESC")
|
||||||
|
fun loadAll(folder: Int, email: String): Flow<List<Message>>
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,6 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
@Dao
|
@Dao
|
||||||
interface MobileDeviceDao : BaseDao<MobileDevice> {
|
interface MobileDeviceDao : BaseDao<MobileDevice> {
|
||||||
|
|
||||||
@Query("SELECT * FROM MobileDevices WHERE student_id = :userLoginId ORDER BY date DESC")
|
@Query("SELECT * FROM MobileDevices WHERE user_login_id = :userLoginId ORDER BY date DESC")
|
||||||
fun loadAll(userLoginId: Int): Flow<List<MobileDevice>>
|
fun loadAll(userLoginId: Int): Flow<List<MobileDevice>>
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.data.db.dao
|
|||||||
|
|
||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
|
import io.github.wulkanowy.data.db.entities.MailboxType
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -9,6 +10,6 @@ import javax.inject.Singleton
|
|||||||
@Dao
|
@Dao
|
||||||
interface RecipientDao : BaseDao<Recipient> {
|
interface RecipientDao : BaseDao<Recipient> {
|
||||||
|
|
||||||
@Query("SELECT * FROM Recipients WHERE student_id = :studentId AND unit_id = :unitId AND role = :role")
|
@Query("SELECT * FROM Recipients WHERE type = :type AND studentMailboxGlobalKey = :studentMailboxGlobalKey")
|
||||||
suspend fun loadAll(studentId: Int, unitId: Int, role: Int): List<Recipient>
|
suspend fun loadAll(type: MailboxType, studentMailboxGlobalKey: String): List<Recipient>
|
||||||
}
|
}
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
package io.github.wulkanowy.data.db.dao
|
|
||||||
|
|
||||||
import androidx.room.Dao
|
|
||||||
import androidx.room.Query
|
|
||||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Dao
|
|
||||||
interface ReportingUnitDao : BaseDao<ReportingUnit> {
|
|
||||||
|
|
||||||
@Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId")
|
|
||||||
suspend fun load(studentId: Int): List<ReportingUnit>
|
|
||||||
|
|
||||||
@Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId AND real_id = :unitId")
|
|
||||||
suspend fun loadOne(studentId: Int, unitId: Int): ReportingUnit?
|
|
||||||
}
|
|
@ -10,6 +10,6 @@ import javax.inject.Singleton
|
|||||||
@Singleton
|
@Singleton
|
||||||
interface SchoolAnnouncementDao : BaseDao<SchoolAnnouncement> {
|
interface SchoolAnnouncementDao : BaseDao<SchoolAnnouncement> {
|
||||||
|
|
||||||
@Query("SELECT * FROM SchoolAnnouncements WHERE student_id = :studentId ORDER BY date DESC")
|
@Query("SELECT * FROM SchoolAnnouncements WHERE user_login_id = :userLoginId ORDER BY date DESC")
|
||||||
fun loadAll(studentId: Int): Flow<List<SchoolAnnouncement>>
|
fun loadAll(userLoginId: Int): Flow<List<SchoolAnnouncement>>
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package io.github.wulkanowy.data.db.entities
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
@Entity(tableName = "Mailboxes")
|
||||||
|
data class Mailbox(
|
||||||
|
|
||||||
|
@PrimaryKey
|
||||||
|
val globalKey: String,
|
||||||
|
|
||||||
|
val email: String,
|
||||||
|
val symbol: String,
|
||||||
|
val schoolId: String,
|
||||||
|
|
||||||
|
val fullName: String,
|
||||||
|
val userName: String,
|
||||||
|
val studentName: String,
|
||||||
|
val schoolNameShort: String,
|
||||||
|
val type: MailboxType,
|
||||||
|
) : java.io.Serializable, Parcelable
|
||||||
|
|
||||||
|
enum class MailboxType {
|
||||||
|
STUDENT,
|
||||||
|
PARENT,
|
||||||
|
GUARDIAN,
|
||||||
|
EMPLOYEE,
|
||||||
|
UNKNOWN,
|
||||||
|
}
|
@ -9,23 +9,19 @@ import java.time.Instant
|
|||||||
@Entity(tableName = "Messages")
|
@Entity(tableName = "Messages")
|
||||||
data class Message(
|
data class Message(
|
||||||
|
|
||||||
@ColumnInfo(name = "student_id")
|
@ColumnInfo(name = "email")
|
||||||
val studentId: Long,
|
val email: String,
|
||||||
|
|
||||||
@ColumnInfo(name = "real_id")
|
@ColumnInfo(name = "message_global_key")
|
||||||
val realId: Int,
|
val messageGlobalKey: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "mailbox_key")
|
||||||
|
val mailboxKey: String,
|
||||||
|
|
||||||
@ColumnInfo(name = "message_id")
|
@ColumnInfo(name = "message_id")
|
||||||
val messageId: Int,
|
val messageId: Int,
|
||||||
|
|
||||||
@ColumnInfo(name = "sender_name")
|
val correspondents: String,
|
||||||
val sender: String,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "sender_id")
|
|
||||||
val senderId: Int,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "recipient_name")
|
|
||||||
val recipient: String,
|
|
||||||
|
|
||||||
val subject: String,
|
val subject: String,
|
||||||
|
|
||||||
@ -36,7 +32,11 @@ data class Message(
|
|||||||
|
|
||||||
var unread: Boolean,
|
var unread: Boolean,
|
||||||
|
|
||||||
val removed: Boolean,
|
@ColumnInfo(name = "read_by")
|
||||||
|
val readBy: Int?,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "unread_by")
|
||||||
|
val unreadBy: Int?,
|
||||||
|
|
||||||
@ColumnInfo(name = "has_attachments")
|
@ColumnInfo(name = "has_attachments")
|
||||||
val hasAttachments: Boolean
|
val hasAttachments: Boolean
|
||||||
@ -48,11 +48,7 @@ data class Message(
|
|||||||
@ColumnInfo(name = "is_notified")
|
@ColumnInfo(name = "is_notified")
|
||||||
var isNotified: Boolean = true
|
var isNotified: Boolean = true
|
||||||
|
|
||||||
@ColumnInfo(name = "unread_by")
|
|
||||||
var unreadBy: Int = 0
|
|
||||||
|
|
||||||
@ColumnInfo(name = "read_by")
|
|
||||||
var readBy: Int = 0
|
|
||||||
|
|
||||||
var content: String = ""
|
var content: String = ""
|
||||||
|
var sender: String? = null
|
||||||
|
var recipients: String? = null
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,8 @@ data class MessageAttachment(
|
|||||||
@ColumnInfo(name = "real_id")
|
@ColumnInfo(name = "real_id")
|
||||||
val realId: Int,
|
val realId: Int,
|
||||||
|
|
||||||
@ColumnInfo(name = "message_id")
|
@ColumnInfo(name = "message_global_key")
|
||||||
val messageId: Int,
|
val messageGlobalKey: String,
|
||||||
|
|
||||||
@ColumnInfo(name = "one_drive_id")
|
|
||||||
val oneDriveId: String,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "url")
|
@ColumnInfo(name = "url")
|
||||||
val url: String,
|
val url: String,
|
||||||
|
@ -7,6 +7,6 @@ data class MessageWithAttachment(
|
|||||||
@Embedded
|
@Embedded
|
||||||
val message: Message,
|
val message: Message,
|
||||||
|
|
||||||
@Relation(parentColumn = "message_id", entityColumn = "message_id")
|
@Relation(parentColumn = "message_global_key", entityColumn = "message_global_key")
|
||||||
val attachments: List<MessageAttachment>
|
val attachments: List<MessageAttachment>
|
||||||
)
|
)
|
||||||
|
@ -9,7 +9,7 @@ import java.time.Instant
|
|||||||
@Entity(tableName = "MobileDevices")
|
@Entity(tableName = "MobileDevices")
|
||||||
data class MobileDevice(
|
data class MobileDevice(
|
||||||
|
|
||||||
@ColumnInfo(name = "student_id")
|
@ColumnInfo(name = "user_login_id")
|
||||||
val userLoginId: Int,
|
val userLoginId: Int,
|
||||||
|
|
||||||
@ColumnInfo(name = "device_id")
|
@ColumnInfo(name = "device_id")
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.data.db.entities
|
package io.github.wulkanowy.data.db.entities
|
||||||
|
|
||||||
import androidx.room.ColumnInfo
|
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
@ -8,32 +7,16 @@ import java.io.Serializable
|
|||||||
@kotlinx.serialization.Serializable
|
@kotlinx.serialization.Serializable
|
||||||
@Entity(tableName = "Recipients")
|
@Entity(tableName = "Recipients")
|
||||||
data class Recipient(
|
data class Recipient(
|
||||||
|
val mailboxGlobalKey: String,
|
||||||
@ColumnInfo(name = "student_id")
|
val studentMailboxGlobalKey: String,
|
||||||
val studentId: Int,
|
val fullName: String,
|
||||||
|
val userName: String,
|
||||||
@ColumnInfo(name = "real_id")
|
val schoolShortName: String,
|
||||||
val realId: String,
|
val type: MailboxType,
|
||||||
|
|
||||||
val name: String,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "real_name")
|
|
||||||
val realName: String,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "login_id")
|
|
||||||
val loginId: Int,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "unit_id")
|
|
||||||
val unitId: Int,
|
|
||||||
|
|
||||||
val role: Int,
|
|
||||||
|
|
||||||
val hash: String
|
|
||||||
|
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
var id: Long = 0
|
var id: Long = 0
|
||||||
|
|
||||||
override fun toString() = name
|
override fun toString() = userName
|
||||||
}
|
}
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
package io.github.wulkanowy.data.db.entities
|
|
||||||
|
|
||||||
import androidx.room.ColumnInfo
|
|
||||||
import androidx.room.Entity
|
|
||||||
import androidx.room.PrimaryKey
|
|
||||||
import java.io.Serializable
|
|
||||||
|
|
||||||
@Entity(tableName = "ReportingUnits")
|
|
||||||
data class ReportingUnit(
|
|
||||||
|
|
||||||
@ColumnInfo(name = "student_id")
|
|
||||||
val studentId: Int,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "real_id")
|
|
||||||
val unitId: Int,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "short")
|
|
||||||
val shortName: String,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "sender_id")
|
|
||||||
val senderId: Int,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "sender_name")
|
|
||||||
val senderName: String,
|
|
||||||
|
|
||||||
val roles: List<Int>
|
|
||||||
|
|
||||||
) : Serializable {
|
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
|
||||||
var id: Long = 0
|
|
||||||
}
|
|
@ -9,8 +9,8 @@ import java.time.LocalDate
|
|||||||
@Entity(tableName = "SchoolAnnouncements")
|
@Entity(tableName = "SchoolAnnouncements")
|
||||||
data class SchoolAnnouncement(
|
data class SchoolAnnouncement(
|
||||||
|
|
||||||
@ColumnInfo(name = "student_id")
|
@ColumnInfo(name = "user_login_id")
|
||||||
val studentId: Int,
|
val userLoginId: Int,
|
||||||
|
|
||||||
val date: LocalDate,
|
val date: LocalDate,
|
||||||
|
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration49 : Migration(48, 49) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS SchoolAnnouncements")
|
||||||
|
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `SchoolAnnouncements` (
|
||||||
|
`user_login_id` INTEGER NOT NULL,
|
||||||
|
`date` INTEGER NOT NULL,
|
||||||
|
`subject` TEXT NOT NULL,
|
||||||
|
`content` TEXT NOT NULL,
|
||||||
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
`is_notified` INTEGER NOT NULL)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration50 : Migration(49, 50) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS MobileDevices")
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `MobileDevices` (
|
||||||
|
`user_login_id` INTEGER NOT NULL,
|
||||||
|
`device_id` INTEGER NOT NULL,
|
||||||
|
`name` TEXT NOT NULL,
|
||||||
|
`date` INTEGER NOT NULL,
|
||||||
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration51 : Migration(50, 51) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
createMailboxTable(database)
|
||||||
|
recreateMessagesTable(database)
|
||||||
|
recreateMessageAttachmentsTable(database)
|
||||||
|
recreateRecipientsTable(database)
|
||||||
|
deleteReportingUnitTable(database)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createMailboxTable(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS Mailboxes")
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `Mailboxes` (
|
||||||
|
`globalKey` TEXT NOT NULL,
|
||||||
|
`fullName` TEXT NOT NULL,
|
||||||
|
`userName` TEXT NOT NULL,
|
||||||
|
`userLoginId` INTEGER NOT NULL,
|
||||||
|
`studentName` TEXT NOT NULL,
|
||||||
|
`schoolNameShort` TEXT NOT NULL,
|
||||||
|
`type` TEXT NOT NULL,
|
||||||
|
PRIMARY KEY(`globalKey`)
|
||||||
|
)""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun recreateMessagesTable(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS Messages")
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `Messages` (
|
||||||
|
`message_global_key` TEXT NOT NULL,
|
||||||
|
`mailbox_key` TEXT NOT NULL,
|
||||||
|
`message_id` INTEGER NOT NULL,
|
||||||
|
`correspondents` TEXT NOT NULL,
|
||||||
|
`subject` TEXT NOT NULL,
|
||||||
|
`date` INTEGER NOT NULL,
|
||||||
|
`folder_id` INTEGER NOT NULL,
|
||||||
|
`unread` INTEGER NOT NULL,
|
||||||
|
`has_attachments` INTEGER NOT NULL,
|
||||||
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
`is_notified` INTEGER NOT NULL,
|
||||||
|
`content` TEXT NOT NULL,
|
||||||
|
`sender` TEXT, `recipients` TEXT
|
||||||
|
)""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun recreateMessageAttachmentsTable(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS MessageAttachments")
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `MessageAttachments` (
|
||||||
|
`real_id` INTEGER NOT NULL,
|
||||||
|
`message_global_key` TEXT NOT NULL,
|
||||||
|
`url` TEXT NOT NULL,
|
||||||
|
`filename` TEXT NOT NULL,
|
||||||
|
PRIMARY KEY(`real_id`)
|
||||||
|
)""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun recreateRecipientsTable(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS Recipients")
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `Recipients` (
|
||||||
|
`mailboxGlobalKey` TEXT NOT NULL,
|
||||||
|
`studentMailboxGlobalKey` TEXT NOT NULL,
|
||||||
|
`fullName` TEXT NOT NULL,
|
||||||
|
`userName` TEXT NOT NULL,
|
||||||
|
`schoolShortName` TEXT NOT NULL,
|
||||||
|
`type` TEXT NOT NULL,
|
||||||
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
|
||||||
|
)""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteReportingUnitTable(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS ReportingUnits")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration53 : Migration(52, 53) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
createMailboxTable(database)
|
||||||
|
recreateMessagesTable(database)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createMailboxTable(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS Mailboxes")
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `Mailboxes` (
|
||||||
|
`globalKey` TEXT NOT NULL,
|
||||||
|
`email` TEXT NOT NULL,
|
||||||
|
`symbol` TEXT NOT NULL,
|
||||||
|
`schoolId` TEXT NOT NULL,
|
||||||
|
`fullName` TEXT NOT NULL,
|
||||||
|
`userName` TEXT NOT NULL,
|
||||||
|
`studentName` TEXT NOT NULL,
|
||||||
|
`schoolNameShort` TEXT NOT NULL,
|
||||||
|
`type` TEXT NOT NULL,
|
||||||
|
PRIMARY KEY(`globalKey`)
|
||||||
|
)""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun recreateMessagesTable(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS Messages")
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `Messages` (
|
||||||
|
`email` TEXT NOT NULL,
|
||||||
|
`message_global_key` TEXT NOT NULL,
|
||||||
|
`mailbox_key` TEXT NOT NULL,
|
||||||
|
`message_id` INTEGER NOT NULL,
|
||||||
|
`correspondents` TEXT NOT NULL,
|
||||||
|
`subject` TEXT NOT NULL,
|
||||||
|
`date` INTEGER NOT NULL,
|
||||||
|
`folder_id` INTEGER NOT NULL,
|
||||||
|
`unread` INTEGER NOT NULL,
|
||||||
|
`read_by` INTEGER,
|
||||||
|
`unread_by` INTEGER,
|
||||||
|
`has_attachments` INTEGER NOT NULL,
|
||||||
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
`is_notified` INTEGER NOT NULL,
|
||||||
|
`content` TEXT NOT NULL,
|
||||||
|
`sender` TEXT,
|
||||||
|
`recipients` TEXT
|
||||||
|
)""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -2,9 +2,10 @@ package io.github.wulkanowy.data.enums
|
|||||||
|
|
||||||
enum class GradeSortingMode(val value: String) {
|
enum class GradeSortingMode(val value: String) {
|
||||||
ALPHABETIC("alphabetic"),
|
ALPHABETIC("alphabetic"),
|
||||||
DATE("date");
|
DATE("date"),
|
||||||
|
AVERAGE("average");
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getByValue(value: String) = values().find { it.value == value } ?: ALPHABETIC
|
fun getByValue(value: String) = values().find { it.value == value } ?: ALPHABETIC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import io.github.wulkanowy.sdk.pojo.DirectorInformation as SdkDirectorInformatio
|
|||||||
|
|
||||||
fun List<SdkDirectorInformation>.mapToEntities(student: Student) = map {
|
fun List<SdkDirectorInformation>.mapToEntities(student: Student) = map {
|
||||||
SchoolAnnouncement(
|
SchoolAnnouncement(
|
||||||
studentId = student.userLoginId,
|
userLoginId = student.userLoginId,
|
||||||
date = it.date,
|
date = it.date,
|
||||||
subject = it.subject,
|
subject = it.subject,
|
||||||
content = it.content,
|
content = it.content,
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package io.github.wulkanowy.data.mappers
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
import io.github.wulkanowy.data.db.entities.MailboxType
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.sdk.pojo.Mailbox as SdkMailbox
|
||||||
|
|
||||||
|
fun List<SdkMailbox>.mapToEntities(student: Student) = map {
|
||||||
|
Mailbox(
|
||||||
|
globalKey = it.globalKey,
|
||||||
|
fullName = it.fullName,
|
||||||
|
userName = it.userName,
|
||||||
|
studentName = it.studentName,
|
||||||
|
schoolNameShort = it.schoolNameShort,
|
||||||
|
type = MailboxType.valueOf(it.type.name),
|
||||||
|
email = student.email,
|
||||||
|
symbol = student.symbol,
|
||||||
|
schoolId = student.schoolSymbol,
|
||||||
|
)
|
||||||
|
}
|
@ -1,40 +1,36 @@
|
|||||||
package io.github.wulkanowy.data.mappers
|
package io.github.wulkanowy.data.mappers
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.*
|
||||||
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
import io.github.wulkanowy.sdk.pojo.MailboxType
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import java.time.Instant
|
|
||||||
import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
|
import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
|
||||||
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
|
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
|
||||||
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
|
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
|
||||||
|
|
||||||
fun List<SdkMessage>.mapToEntities(student: Student) = map {
|
fun List<SdkMessage>.mapToEntities(student: Student, mailbox: Mailbox?, allMailboxes: List<Mailbox>) = map {
|
||||||
Message(
|
Message(
|
||||||
studentId = student.id,
|
messageGlobalKey = it.globalKey,
|
||||||
realId = it.id ?: 0,
|
mailboxKey = mailbox?.globalKey ?: allMailboxes.find { box ->
|
||||||
messageId = it.messageId ?: 0,
|
box.fullName == it.mailbox
|
||||||
sender = it.sender?.name.orEmpty(),
|
}?.globalKey!!,
|
||||||
senderId = it.sender?.loginId ?: 0,
|
email = student.email,
|
||||||
recipient = it.recipients.singleOrNull()?.name ?: "Wielu adresatów",
|
messageId = it.id,
|
||||||
|
correspondents = it.correspondents,
|
||||||
subject = it.subject.trim(),
|
subject = it.subject.trim(),
|
||||||
date = it.dateZoned?.toInstant() ?: Instant.now(),
|
date = it.dateZoned.toInstant(),
|
||||||
folderId = it.folderId,
|
folderId = it.folderId,
|
||||||
unread = it.unread ?: false,
|
unread = it.unread,
|
||||||
removed = it.removed,
|
unreadBy = it.unreadBy,
|
||||||
hasAttachments = it.hasAttachments
|
readBy = it.readBy,
|
||||||
|
hasAttachments = it.hasAttachments,
|
||||||
).apply {
|
).apply {
|
||||||
content = it.content.orEmpty()
|
content = it.content.orEmpty()
|
||||||
unreadBy = it.unreadBy ?: 0
|
|
||||||
readBy = it.readBy ?: 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun List<SdkMessageAttachment>.mapToEntities() = map {
|
fun List<SdkMessageAttachment>.mapToEntities(messageGlobalKey: String) = map {
|
||||||
MessageAttachment(
|
MessageAttachment(
|
||||||
realId = it.id,
|
messageGlobalKey = messageGlobalKey,
|
||||||
messageId = it.messageId,
|
realId = it.url.hashCode(),
|
||||||
oneDriveId = it.oneDriveId,
|
|
||||||
url = it.url,
|
url = it.url,
|
||||||
filename = it.filename
|
filename = it.filename
|
||||||
)
|
)
|
||||||
@ -42,12 +38,11 @@ fun List<SdkMessageAttachment>.mapToEntities() = map {
|
|||||||
|
|
||||||
fun List<Recipient>.mapFromEntities() = map {
|
fun List<Recipient>.mapFromEntities() = map {
|
||||||
SdkRecipient(
|
SdkRecipient(
|
||||||
id = it.realId,
|
fullName = it.fullName,
|
||||||
name = it.realName,
|
userName = it.userName,
|
||||||
loginId = it.loginId,
|
studentName = it.userName,
|
||||||
reportingUnitId = it.unitId,
|
mailboxGlobalKey = it.mailboxGlobalKey,
|
||||||
role = it.role,
|
schoolNameShort = it.schoolShortName,
|
||||||
hash = it.hash,
|
type = MailboxType.valueOf(it.type.name),
|
||||||
shortName = it.name
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package io.github.wulkanowy.data.mappers
|
package io.github.wulkanowy.data.mappers
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.MobileDevice
|
import io.github.wulkanowy.data.db.entities.MobileDevice
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.pojos.MobileDeviceToken
|
import io.github.wulkanowy.data.pojos.MobileDeviceToken
|
||||||
import io.github.wulkanowy.sdk.pojo.Device as SdkDevice
|
import io.github.wulkanowy.sdk.pojo.Device as SdkDevice
|
||||||
import io.github.wulkanowy.sdk.pojo.Token as SdkToken
|
import io.github.wulkanowy.sdk.pojo.Token as SdkToken
|
||||||
|
|
||||||
fun List<SdkDevice>.mapToEntities(semester: Semester) = map {
|
fun List<SdkDevice>.mapToEntities(student: Student) = map {
|
||||||
MobileDevice(
|
MobileDevice(
|
||||||
userLoginId = semester.studentId,
|
userLoginId = student.userLoginId,
|
||||||
date = it.createDateZoned.toInstant(),
|
date = it.createDateZoned.toInstant(),
|
||||||
deviceId = it.id,
|
deviceId = it.id,
|
||||||
name = it.name
|
name = it.name
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
package io.github.wulkanowy.data.mappers
|
package io.github.wulkanowy.data.mappers
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.MailboxType
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
|
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
|
||||||
|
|
||||||
fun List<SdkRecipient>.mapToEntities(userLoginId: Int) = map {
|
fun List<SdkRecipient>.mapToEntities(studentMailboxGlobalKey: String) = map {
|
||||||
Recipient(
|
Recipient(
|
||||||
studentId = userLoginId,
|
mailboxGlobalKey = it.mailboxGlobalKey,
|
||||||
realId = it.id,
|
fullName = it.fullName,
|
||||||
realName = it.name,
|
userName = it.userName,
|
||||||
name = it.shortName,
|
studentMailboxGlobalKey = studentMailboxGlobalKey,
|
||||||
hash = it.hash,
|
schoolShortName = it.schoolNameShort,
|
||||||
loginId = it.loginId,
|
type = MailboxType.valueOf(it.type.name),
|
||||||
role = it.role,
|
|
||||||
unitId = it.reportingUnitId ?: 0
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
package io.github.wulkanowy.data.mappers
|
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import io.github.wulkanowy.sdk.pojo.ReportingUnit as SdkReportingUnit
|
|
||||||
|
|
||||||
fun List<SdkReportingUnit>.mapToEntities(student: Student) = map {
|
|
||||||
ReportingUnit(
|
|
||||||
studentId = student.id.toInt(),
|
|
||||||
unitId = it.id,
|
|
||||||
roles = it.roles,
|
|
||||||
senderId = it.senderId,
|
|
||||||
senderName = it.senderName,
|
|
||||||
shortName = it.short
|
|
||||||
)
|
|
||||||
}
|
|
@ -5,29 +5,32 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
|||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.Resource
|
import io.github.wulkanowy.data.Resource
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
|
import io.github.wulkanowy.data.db.dao.MailboxDao
|
||||||
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
||||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||||
import io.github.wulkanowy.data.db.entities.*
|
import io.github.wulkanowy.data.db.entities.*
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder
|
import io.github.wulkanowy.data.enums.MessageFolder
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
|
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
|
||||||
|
import io.github.wulkanowy.data.enums.MessageFolder.TRASHED
|
||||||
import io.github.wulkanowy.data.mappers.mapFromEntities
|
import io.github.wulkanowy.data.mappers.mapFromEntities
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
import io.github.wulkanowy.data.networkBoundResource
|
import io.github.wulkanowy.data.networkBoundResource
|
||||||
import io.github.wulkanowy.data.pojos.MessageDraft
|
import io.github.wulkanowy.data.pojos.MessageDraft
|
||||||
|
import io.github.wulkanowy.data.toFirstResult
|
||||||
|
import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.sdk.pojo.Folder
|
import io.github.wulkanowy.sdk.pojo.Folder
|
||||||
import io.github.wulkanowy.sdk.pojo.SentMessage
|
|
||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
import io.github.wulkanowy.utils.getRefreshKey
|
import io.github.wulkanowy.utils.getRefreshKey
|
||||||
import io.github.wulkanowy.utils.init
|
import io.github.wulkanowy.utils.init
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.time.LocalDateTime.now
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -40,16 +43,18 @@ class MessageRepository @Inject constructor(
|
|||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
private val sharedPrefProvider: SharedPrefProvider,
|
private val sharedPrefProvider: SharedPrefProvider,
|
||||||
private val json: Json,
|
private val json: Json,
|
||||||
|
private val mailboxDao: MailboxDao,
|
||||||
|
private val getMailboxByStudentUseCase: GetMailboxByStudentUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val saveFetchResultMutex = Mutex()
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private val cacheKey = "message"
|
private val messagesCacheKey = "message"
|
||||||
|
private val mailboxCacheKey = "mailboxes"
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
fun getMessages(
|
fun getMessages(
|
||||||
student: Student,
|
student: Student,
|
||||||
semester: Semester,
|
mailbox: Mailbox?,
|
||||||
folder: MessageFolder,
|
folder: MessageFolder,
|
||||||
forceRefresh: Boolean,
|
forceRefresh: Boolean,
|
||||||
notify: Boolean = false,
|
notify: Boolean = false,
|
||||||
@ -58,46 +63,33 @@ class MessageRepository @Inject constructor(
|
|||||||
isResultEmpty = { it.isEmpty() },
|
isResultEmpty = { it.isEmpty() },
|
||||||
shouldFetch = {
|
shouldFetch = {
|
||||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
val isExpired = refreshHelper.shouldBeRefreshed(
|
||||||
key = getRefreshKey(cacheKey, student, folder)
|
key = getRefreshKey(messagesCacheKey, mailbox, folder)
|
||||||
)
|
)
|
||||||
it.isEmpty() || forceRefresh || isExpired
|
it.isEmpty() || forceRefresh || isExpired
|
||||||
},
|
},
|
||||||
query = { messagesDb.loadAll(student.id.toInt(), folder.id) },
|
query = {
|
||||||
|
if (mailbox == null) {
|
||||||
|
messagesDb.loadAll(folder.id, student.email)
|
||||||
|
} else messagesDb.loadAll(mailbox.globalKey, folder.id)
|
||||||
|
},
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).getMessages(Folder.valueOf(folder.name), now().minusMonths(3), now())
|
sdk.init(student).getMessages(
|
||||||
.mapToEntities(student)
|
folder = Folder.valueOf(folder.name),
|
||||||
|
mailboxKey = mailbox?.globalKey,
|
||||||
|
).mapToEntities(student, mailbox, mailboxDao.loadAll(student.email))
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
messagesDb.deleteAll(old uniqueSubtract new)
|
messagesDb.deleteAll(old uniqueSubtract new)
|
||||||
messagesDb.insertAll((new uniqueSubtract old).onEach {
|
messagesDb.insertAll((new uniqueSubtract old).onEach {
|
||||||
it.isNotified = !notify
|
it.isNotified = !notify
|
||||||
})
|
})
|
||||||
messagesDb.updateAll(getMessagesWithReadByChange(old, new, !notify))
|
|
||||||
|
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student, folder))
|
refreshHelper.updateLastRefreshTimestamp(
|
||||||
|
getRefreshKey(messagesCacheKey, mailbox, 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(
|
fun getMessage(
|
||||||
student: Student,
|
student: Student,
|
||||||
message: Message,
|
message: Message,
|
||||||
@ -106,34 +98,38 @@ class MessageRepository @Inject constructor(
|
|||||||
isResultEmpty = { it?.message?.content.isNullOrBlank() },
|
isResultEmpty = { it?.message?.content.isNullOrBlank() },
|
||||||
shouldFetch = {
|
shouldFetch = {
|
||||||
checkNotNull(it) { "This message no longer exist!" }
|
checkNotNull(it) { "This message no longer exist!" }
|
||||||
Timber.d("Message content in db empty: ${it.message.content.isEmpty()}")
|
Timber.d("Message content in db empty: ${it.message.content.isBlank()}")
|
||||||
it.message.unread || it.message.content.isEmpty()
|
it.message.unread || it.message.content.isBlank()
|
||||||
|
},
|
||||||
|
query = {
|
||||||
|
messagesDb.loadMessageWithAttachment(message.messageGlobalKey)
|
||||||
},
|
},
|
||||||
query = { messagesDb.loadMessageWithAttachment(student.id.toInt(), message.messageId) },
|
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).getMessageDetails(
|
sdk.init(student).getMessageDetails(it!!.message.messageGlobalKey, markAsRead)
|
||||||
messageId = it!!.message.messageId,
|
|
||||||
folderId = message.folderId,
|
|
||||||
read = markAsRead,
|
|
||||||
id = message.realId
|
|
||||||
).let { details ->
|
|
||||||
details.content to details.attachments.mapToEntities()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, (downloadedMessage, attachments) ->
|
saveFetchResult = { old, new ->
|
||||||
checkNotNull(old) { "Fetched message no longer exist!" }
|
checkNotNull(old) { "Fetched message no longer exist!" }
|
||||||
messagesDb.updateAll(listOf(old.message.apply {
|
messagesDb.updateAll(
|
||||||
id = old.message.id
|
listOf(old.message.apply {
|
||||||
unread = !markAsRead
|
id = message.id
|
||||||
content = content.ifBlank { downloadedMessage }
|
unread = !markAsRead
|
||||||
}))
|
sender = new.sender
|
||||||
messageAttachmentDao.insertAttachments(attachments)
|
recipients = new.recipients.singleOrNull() ?: "Wielu adresatów"
|
||||||
|
content = content.ifBlank { new.content }
|
||||||
|
})
|
||||||
|
)
|
||||||
|
messageAttachmentDao.insertAttachments(
|
||||||
|
items = new.attachments.mapToEntities(message.messageGlobalKey),
|
||||||
|
)
|
||||||
|
|
||||||
Timber.d("Message ${message.messageId} with blank content: ${old.message.content.isBlank()}, marked as read")
|
Timber.d("Message ${message.messageId} with blank content: ${old.message.content.isBlank()}, marked as read")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getMessagesFromDatabase(student: Student): Flow<List<Message>> {
|
fun getMessagesFromDatabase(student: Student, mailbox: Mailbox?): Flow<List<Message>> {
|
||||||
return messagesDb.loadAll(student.id.toInt(), RECEIVED.id)
|
return if (mailbox == null) {
|
||||||
|
messagesDb.loadAll(RECEIVED.id, student.email)
|
||||||
|
} else messagesDb.loadAll(mailbox.globalKey, RECEIVED.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateMessages(messages: List<Message>) {
|
suspend fun updateMessages(messages: List<Message>) {
|
||||||
@ -145,38 +141,82 @@ class MessageRepository @Inject constructor(
|
|||||||
subject: String,
|
subject: String,
|
||||||
content: String,
|
content: String,
|
||||||
recipients: List<Recipient>,
|
recipients: List<Recipient>,
|
||||||
): SentMessage = sdk.init(student).sendMessage(
|
mailboxId: String,
|
||||||
subject = subject,
|
) {
|
||||||
content = content,
|
sdk.init(student).sendMessage(
|
||||||
recipients = recipients.mapFromEntities()
|
subject = subject,
|
||||||
)
|
content = content,
|
||||||
|
recipients = recipients.mapFromEntities(),
|
||||||
|
mailboxId = mailboxId,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun deleteMessages(student: Student, messages: List<Message>) {
|
suspend fun deleteMessages(student: Student, mailbox: Mailbox?, messages: List<Message>) {
|
||||||
val folderId = messages.first().folderId
|
val firstMessage = messages.first()
|
||||||
val isDeleted = sdk.init(student)
|
sdk.init(student).deleteMessages(
|
||||||
.deleteMessages(messages = messages.map { it.messageId }, folderId = folderId)
|
messages = messages.map { it.messageGlobalKey },
|
||||||
|
removeForever = firstMessage.folderId == TRASHED.id,
|
||||||
|
)
|
||||||
|
|
||||||
if (folderId != MessageFolder.TRASHED.id && isDeleted) {
|
if (firstMessage.folderId != TRASHED.id) {
|
||||||
val deletedMessages = messages.map {
|
val deletedMessages = messages.map {
|
||||||
it.copy(folderId = MessageFolder.TRASHED.id)
|
it.copy(folderId = TRASHED.id)
|
||||||
.apply {
|
.apply {
|
||||||
id = it.id
|
id = it.id
|
||||||
content = it.content
|
content = it.content
|
||||||
|
sender = it.sender
|
||||||
|
recipients = it.recipients
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
messagesDb.updateAll(deletedMessages)
|
messagesDb.updateAll(deletedMessages)
|
||||||
} else messagesDb.deleteAll(messages)
|
} else messagesDb.deleteAll(messages)
|
||||||
|
|
||||||
|
getMessages(
|
||||||
|
student = student,
|
||||||
|
mailbox = mailbox,
|
||||||
|
folder = TRASHED,
|
||||||
|
forceRefresh = true,
|
||||||
|
).first()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun deleteMessage(student: Student, message: Message) =
|
suspend fun deleteMessage(student: Student, mailbox: Mailbox, message: Message) {
|
||||||
deleteMessages(student, listOf(message))
|
deleteMessages(student, mailbox, listOf(message))
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getMailboxes(student: Student, forceRefresh: Boolean) = networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
|
isResultEmpty = { it.isEmpty() },
|
||||||
|
shouldFetch = {
|
||||||
|
val isExpired = refreshHelper.shouldBeRefreshed(
|
||||||
|
key = getRefreshKey(mailboxCacheKey, student),
|
||||||
|
)
|
||||||
|
it.isEmpty() || isExpired || forceRefresh
|
||||||
|
},
|
||||||
|
query = { mailboxDao.loadAll(student.email, student.symbol, student.schoolSymbol) },
|
||||||
|
fetch = { sdk.init(student).getMailboxes().mapToEntities(student) },
|
||||||
|
saveFetchResult = { old, new ->
|
||||||
|
mailboxDao.deleteAll(old uniqueSubtract new)
|
||||||
|
mailboxDao.insertAll(new uniqueSubtract old)
|
||||||
|
|
||||||
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(mailboxCacheKey, student))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
suspend fun getMailboxByStudent(student: Student): Mailbox? {
|
||||||
|
val mailbox = getMailboxByStudentUseCase(student)
|
||||||
|
|
||||||
|
return if (mailbox == null) {
|
||||||
|
getMailboxes(student, forceRefresh = true).toFirstResult()
|
||||||
|
getMailboxByStudentUseCase(student)
|
||||||
|
} else mailbox
|
||||||
|
}
|
||||||
|
|
||||||
var draftMessage: MessageDraft?
|
var draftMessage: MessageDraft?
|
||||||
get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_send_draft))
|
get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_draft))
|
||||||
?.let { json.decodeFromString(it) }
|
?.let { json.decodeFromString(it) }
|
||||||
set(value) = sharedPrefProvider.putString(
|
set(value) = sharedPrefProvider.putString(
|
||||||
context.getString(R.string.pref_key_message_send_draft),
|
context.getString(R.string.pref_key_message_draft),
|
||||||
value?.let { json.encodeToString(it) }
|
value?.let { json.encodeToString(it) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -39,12 +39,12 @@ class MobileDeviceRepository @Inject constructor(
|
|||||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
|
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
|
||||||
it.isEmpty() || forceRefresh || isExpired
|
it.isEmpty() || forceRefresh || isExpired
|
||||||
},
|
},
|
||||||
query = { mobileDb.loadAll(student.userLoginId.takeIf { it != 0 } ?: student.studentId) },
|
query = { mobileDb.loadAll(student.userLoginId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student)
|
sdk.init(student)
|
||||||
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
|
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
|
||||||
.getRegisteredDevices()
|
.getRegisteredDevices()
|
||||||
.mapToEntities(semester)
|
.mapToEntities(student)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
mobileDb.deleteAll(old uniqueSubtract new)
|
mobileDb.deleteAll(old uniqueSubtract new)
|
||||||
|
@ -10,17 +10,16 @@ import io.github.wulkanowy.R
|
|||||||
import io.github.wulkanowy.data.enums.*
|
import io.github.wulkanowy.data.enums.*
|
||||||
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||||
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
|
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class PreferencesRepository @Inject constructor(
|
class PreferencesRepository @Inject constructor(
|
||||||
@ApplicationContext val context: Context,
|
@ApplicationContext val context: Context,
|
||||||
@ -222,19 +221,31 @@ class PreferencesRepository @Inject constructor(
|
|||||||
get() = selectedDashboardTilesPreference.asFlow()
|
get() = selectedDashboardTilesPreference.asFlow()
|
||||||
.map { set ->
|
.map { set ->
|
||||||
set.map { DashboardItem.Tile.valueOf(it) }
|
set.map { DashboardItem.Tile.valueOf(it) }
|
||||||
.plus(DashboardItem.Tile.ACCOUNT)
|
.plus(
|
||||||
.plus(DashboardItem.Tile.ADMIN_MESSAGE)
|
listOfNotNull(
|
||||||
|
DashboardItem.Tile.ACCOUNT,
|
||||||
|
DashboardItem.Tile.ADMIN_MESSAGE,
|
||||||
|
DashboardItem.Tile.ADS.takeIf { isAdsEnabled }
|
||||||
|
)
|
||||||
|
)
|
||||||
.toSet()
|
.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectedDashboardTiles: Set<DashboardItem.Tile>
|
var selectedDashboardTiles: Set<DashboardItem.Tile>
|
||||||
get() = selectedDashboardTilesPreference.get()
|
get() = selectedDashboardTilesPreference.get()
|
||||||
.map { DashboardItem.Tile.valueOf(it) }
|
.map { DashboardItem.Tile.valueOf(it) }
|
||||||
.plus(DashboardItem.Tile.ACCOUNT)
|
.plus(
|
||||||
.plus(DashboardItem.Tile.ADMIN_MESSAGE)
|
listOfNotNull(
|
||||||
|
DashboardItem.Tile.ACCOUNT,
|
||||||
|
DashboardItem.Tile.ADMIN_MESSAGE,
|
||||||
|
DashboardItem.Tile.ADS.takeIf { isAdsEnabled }
|
||||||
|
)
|
||||||
|
)
|
||||||
.toSet()
|
.toSet()
|
||||||
set(value) {
|
set(value) {
|
||||||
val filteredValue = value.filterNot { it == DashboardItem.Tile.ACCOUNT }
|
val filteredValue = value.filterNot {
|
||||||
|
it == DashboardItem.Tile.ACCOUNT || it == DashboardItem.Tile.ADMIN_MESSAGE
|
||||||
|
}
|
||||||
.map { it.name }
|
.map { it.name }
|
||||||
.toSet()
|
.toSet()
|
||||||
|
|
||||||
@ -271,7 +282,48 @@ class PreferencesRepository @Inject constructor(
|
|||||||
|
|
||||||
var isAppReviewDone: Boolean
|
var isAppReviewDone: Boolean
|
||||||
get() = sharedPref.getBoolean(PREF_KEY_IN_APP_REVIEW_DONE, false)
|
get() = sharedPref.getBoolean(PREF_KEY_IN_APP_REVIEW_DONE, false)
|
||||||
set(value) = sharedPref.edit().putBoolean(PREF_KEY_IN_APP_REVIEW_DONE, value).apply()
|
set(value) = sharedPref.edit { putBoolean(PREF_KEY_IN_APP_REVIEW_DONE, value) }
|
||||||
|
|
||||||
|
var isAppSupportShown: Boolean
|
||||||
|
get() = sharedPref.getBoolean(PREF_KEY_APP_SUPPORT_SHOWN, false)
|
||||||
|
set(value) = sharedPref.edit { putBoolean(PREF_KEY_APP_SUPPORT_SHOWN, value) }
|
||||||
|
|
||||||
|
var isAgreeToProcessData: Boolean
|
||||||
|
get() = getBoolean(
|
||||||
|
R.string.pref_key_ads_consent_data_processing,
|
||||||
|
R.bool.pref_default_ads_consent_data_processing
|
||||||
|
)
|
||||||
|
set(value) = sharedPref.edit {
|
||||||
|
putBoolean(context.getString(R.string.pref_key_ads_consent_data_processing), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
var isPersonalizedAdsEnabled: Boolean
|
||||||
|
get() = sharedPref.getBoolean(PREF_KEY_PERSONALIZED_ADS_ENABLED, false)
|
||||||
|
set(value) = sharedPref.edit { putBoolean(PREF_KEY_PERSONALIZED_ADS_ENABLED, value) }
|
||||||
|
|
||||||
|
val isAdsEnabledFlow = flowSharedPref.getBoolean(
|
||||||
|
context.getString(R.string.pref_key_ads_enabled),
|
||||||
|
context.resources.getBoolean(R.bool.pref_default_ads_enabled)
|
||||||
|
).asFlow()
|
||||||
|
|
||||||
|
var isAdsEnabled: Boolean
|
||||||
|
get() = getBoolean(
|
||||||
|
R.string.pref_key_ads_enabled,
|
||||||
|
R.bool.pref_default_ads_enabled
|
||||||
|
)
|
||||||
|
set(value) = sharedPref.edit {
|
||||||
|
putBoolean(context.getString(R.string.pref_key_ads_enabled), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
var installationId: String
|
||||||
|
get() = sharedPref.getString(PREF_KEY_INSTALLATION_ID, null).orEmpty()
|
||||||
|
private set(value) = sharedPref.edit { putString(PREF_KEY_INSTALLATION_ID, value) }
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (installationId.isEmpty()) {
|
||||||
|
installationId = UUID.randomUUID().toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun getLong(id: Int, default: Int) = getLong(context.getString(id), default)
|
private fun getLong(id: Int, default: Int) = getLong(context.getString(id), default)
|
||||||
|
|
||||||
@ -288,19 +340,14 @@ class PreferencesRepository @Inject constructor(
|
|||||||
private fun getBoolean(id: String, default: Int) =
|
private fun getBoolean(id: String, default: Int) =
|
||||||
sharedPref.getBoolean(id, context.resources.getBoolean(default))
|
sharedPref.getBoolean(id, context.resources.getBoolean(default))
|
||||||
|
|
||||||
private fun getBoolean(id: Int, default: Boolean) =
|
|
||||||
sharedPref.getBoolean(context.getString(id), default)
|
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
private const val PREF_KEY_INSTALLATION_ID = "installation_id"
|
||||||
private const val PREF_KEY_DASHBOARD_ITEMS_POSITION = "dashboard_items_position"
|
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_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_DATE = "in_app_review_date"
|
||||||
|
|
||||||
private const val PREF_KEY_IN_APP_REVIEW_DONE = "in_app_review_done"
|
private const val PREF_KEY_IN_APP_REVIEW_DONE = "in_app_review_done"
|
||||||
|
private const val PREF_KEY_APP_SUPPORT_SHOWN = "app_support_shown"
|
||||||
|
private const val PREF_KEY_PERSONALIZED_ADS_ENABLED = "personalized_ads_enabled"
|
||||||
private const val PREF_KEY_ADMIN_DISMISSED_MESSAGE_IDS = "admin_message_dismissed_ids"
|
private const val PREF_KEY_ADMIN_DISMISSED_MESSAGE_IDS = "admin_message_dismissed_ids"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
package io.github.wulkanowy.data.repositories
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.dao.RecipientDao
|
import io.github.wulkanowy.data.db.dao.RecipientDao
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.*
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
|
||||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
@ -23,9 +20,10 @@ class RecipientRepository @Inject constructor(
|
|||||||
|
|
||||||
private val cacheKey = "recipient"
|
private val cacheKey = "recipient"
|
||||||
|
|
||||||
suspend fun refreshRecipients(student: Student, unit: ReportingUnit, role: Int) {
|
suspend fun refreshRecipients(student: Student, mailbox: Mailbox, type: MailboxType) {
|
||||||
val new = sdk.init(student).getRecipients(unit.unitId, role).mapToEntities(unit.studentId)
|
val new = sdk.init(student).getRecipients(mailbox.globalKey)
|
||||||
val old = recipientDb.loadAll(unit.studentId, unit.unitId, role)
|
.mapToEntities(mailbox.globalKey)
|
||||||
|
val old = recipientDb.loadAll(type, mailbox.globalKey)
|
||||||
|
|
||||||
recipientDb.deleteAll(old uniqueSubtract new)
|
recipientDb.deleteAll(old uniqueSubtract new)
|
||||||
recipientDb.insertAll(new uniqueSubtract old)
|
recipientDb.insertAll(new uniqueSubtract old)
|
||||||
@ -33,18 +31,33 @@ class RecipientRepository @Inject constructor(
|
|||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getRecipients(student: Student, unit: ReportingUnit, role: Int): List<Recipient> {
|
suspend fun getRecipients(
|
||||||
val cached = recipientDb.loadAll(unit.studentId, unit.unitId, role)
|
student: Student,
|
||||||
|
mailbox: Mailbox?,
|
||||||
|
type: MailboxType,
|
||||||
|
): List<Recipient> {
|
||||||
|
mailbox ?: return emptyList()
|
||||||
|
|
||||||
|
val cached = recipientDb.loadAll(type, mailbox.globalKey)
|
||||||
|
|
||||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
|
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
|
||||||
return if (cached.isEmpty() || isExpired) {
|
return if (cached.isEmpty() || isExpired) {
|
||||||
refreshRecipients(student, unit, role)
|
refreshRecipients(student, mailbox, type)
|
||||||
recipientDb.loadAll(unit.studentId, unit.unitId, role)
|
recipientDb.loadAll(type, mailbox.globalKey)
|
||||||
} else cached
|
} else cached
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getMessageRecipients(student: Student, message: Message): List<Recipient> {
|
suspend fun getMessageSender(
|
||||||
return sdk.init(student).getMessageRecipients(message.messageId, message.senderId)
|
student: Student,
|
||||||
.mapToEntities(student.studentId)
|
mailbox: Mailbox?,
|
||||||
|
message: Message,
|
||||||
|
): List<Recipient> {
|
||||||
|
mailbox ?: return emptyList()
|
||||||
|
|
||||||
|
return sdk.init(student)
|
||||||
|
.getMessageReplayDetails(message.messageGlobalKey)
|
||||||
|
.sender
|
||||||
|
.let(::listOf)
|
||||||
|
.mapToEntities(mailbox.globalKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
package io.github.wulkanowy.data.repositories
|
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.dao.ReportingUnitDao
|
|
||||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
|
||||||
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.init
|
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
class ReportingUnitRepository @Inject constructor(
|
|
||||||
private val reportingUnitDb: ReportingUnitDao,
|
|
||||||
private val sdk: Sdk
|
|
||||||
) {
|
|
||||||
|
|
||||||
suspend fun refreshReportingUnits(student: Student) {
|
|
||||||
val new = sdk.init(student).getReportingUnits().mapToEntities(student)
|
|
||||||
val old = reportingUnitDb.load(student.id.toInt())
|
|
||||||
|
|
||||||
reportingUnitDb.deleteAll(old.uniqueSubtract(new))
|
|
||||||
reportingUnitDb.insertAll(new.uniqueSubtract(old))
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getReportingUnits(student: Student): List<ReportingUnit> {
|
|
||||||
return reportingUnitDb.load(student.id.toInt()).ifEmpty {
|
|
||||||
refreshReportingUnits(student)
|
|
||||||
|
|
||||||
reportingUnitDb.load(student.id.toInt())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getReportingUnit(student: Student, unitId: Int): ReportingUnit? {
|
|
||||||
return reportingUnitDb.loadOne(student.id.toInt(), unitId) ?: run {
|
|
||||||
refreshReportingUnits(student)
|
|
||||||
|
|
||||||
return reportingUnitDb.loadOne(student.id.toInt(), unitId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -28,7 +28,8 @@ class SchoolAnnouncementRepository @Inject constructor(
|
|||||||
|
|
||||||
fun getSchoolAnnouncements(
|
fun getSchoolAnnouncements(
|
||||||
student: Student,
|
student: Student,
|
||||||
forceRefresh: Boolean, notify: Boolean = false
|
forceRefresh: Boolean,
|
||||||
|
notify: Boolean = false
|
||||||
) = networkBoundResource(
|
) = networkBoundResource(
|
||||||
mutex = saveFetchResultMutex,
|
mutex = saveFetchResultMutex,
|
||||||
isResultEmpty = { it.isEmpty() },
|
isResultEmpty = { it.isEmpty() },
|
||||||
@ -37,7 +38,7 @@ class SchoolAnnouncementRepository @Inject constructor(
|
|||||||
it.isEmpty() || forceRefresh || isExpired
|
it.isEmpty() || forceRefresh || isExpired
|
||||||
},
|
},
|
||||||
query = {
|
query = {
|
||||||
schoolAnnouncementDb.loadAll(student.studentId)
|
schoolAnnouncementDb.loadAll(student.userLoginId)
|
||||||
},
|
},
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student)
|
sdk.init(student)
|
||||||
@ -56,7 +57,7 @@ class SchoolAnnouncementRepository @Inject constructor(
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun getSchoolAnnouncementFromDatabase(student: Student): Flow<List<SchoolAnnouncement>> {
|
fun getSchoolAnnouncementFromDatabase(student: Student): Flow<List<SchoolAnnouncement>> {
|
||||||
return schoolAnnouncementDb.loadAll(student.studentId)
|
return schoolAnnouncementDb.loadAll(student.userLoginId)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateSchoolAnnouncement(schoolAnnouncement: List<SchoolAnnouncement>) =
|
suspend fun updateSchoolAnnouncement(schoolAnnouncement: List<SchoolAnnouncement>) =
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
package io.github.wulkanowy.domain.messages
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.dao.MailboxDao
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class GetMailboxByStudentUseCase @Inject constructor(
|
||||||
|
private val mailboxDao: MailboxDao,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend operator fun invoke(student: Student): Mailbox? {
|
||||||
|
return mailboxDao.loadAll(student.email)
|
||||||
|
.filterByStudent(student)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<Mailbox>.filterByStudent(student: Student): Mailbox? {
|
||||||
|
val normalizedStudentName = student.studentName.normalizeStudentName()
|
||||||
|
|
||||||
|
return find {
|
||||||
|
it.studentName.normalizeStudentName() == normalizedStudentName
|
||||||
|
} ?: singleOrNull {
|
||||||
|
it.studentName.getFirstAndLastPart() == normalizedStudentName.getFirstAndLastPart()
|
||||||
|
} ?: singleOrNull {
|
||||||
|
it.studentName.getUnauthorizedVersion() == normalizedStudentName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.normalizeStudentName(): String {
|
||||||
|
return trim().split(" ")
|
||||||
|
.filter { it.isNotBlank() }
|
||||||
|
.joinToString(" ") { part ->
|
||||||
|
part.lowercase().replaceFirstChar { it.uppercase() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.getFirstAndLastPart(): String {
|
||||||
|
val parts = normalizeStudentName().split(" ")
|
||||||
|
|
||||||
|
val endParts = parts.filterIndexed { i, _ ->
|
||||||
|
i == 0 || parts.size - 1 == i
|
||||||
|
}
|
||||||
|
return endParts.joinToString(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.getUnauthorizedVersion(): String {
|
||||||
|
return normalizeStudentName().split(" ")
|
||||||
|
.joinToString(" ") {
|
||||||
|
it.first() + "*".repeat(it.length - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,79 +15,41 @@ import javax.inject.Singleton
|
|||||||
@Singleton
|
@Singleton
|
||||||
class ShortcutsHelper @Inject constructor(@ApplicationContext private val context: Context) {
|
class ShortcutsHelper @Inject constructor(@ApplicationContext private val context: Context) {
|
||||||
|
|
||||||
// Destination cannot be used here as shortcuts
|
fun initializeShortcuts() {
|
||||||
// require their intents to only use primitive types (see PersistableBundle.isValidType).
|
|
||||||
|
|
||||||
private val destinations = mapOf(
|
|
||||||
"grade" to Destination.Grade,
|
|
||||||
"attendance" to Destination.Attendance,
|
|
||||||
"exam" to Destination.Exam,
|
|
||||||
"timetable" to Destination.Timetable()
|
|
||||||
)
|
|
||||||
|
|
||||||
init {
|
|
||||||
initializeShortcuts()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getDestination(intent: Intent) =
|
|
||||||
destinations[intent.getStringExtra(EXTRA_SHORTCUT_DESTINATION_ID)]
|
|
||||||
|
|
||||||
private fun initializeShortcuts() {
|
|
||||||
val shortcutsInfo = listOf(
|
val shortcutsInfo = listOf(
|
||||||
ShortcutInfoCompat.Builder(context, "grade_shortcut")
|
ShortcutInfoCompat.Builder(context, "grade_shortcut")
|
||||||
.setShortLabel(context.getString(R.string.grade_title))
|
.setShortLabel(context.getString(R.string.grade_title))
|
||||||
.setLongLabel(context.getString(R.string.grade_title))
|
.setLongLabel(context.getString(R.string.grade_title))
|
||||||
.setIcon(IconCompat.createWithResource(context, R.drawable.ic_shortcut_grade))
|
.setIcon(IconCompat.createWithResource(context, R.drawable.ic_shortcut_grade))
|
||||||
.setIntent(SplashActivity.getStartIntent(context)
|
.setIntent(SplashActivity.getStartIntent(context, Destination.Grade)
|
||||||
.apply {
|
.apply { action = Intent.ACTION_VIEW })
|
||||||
action = Intent.ACTION_VIEW
|
|
||||||
putExtra(EXTRA_SHORTCUT_DESTINATION_ID, "grade")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.build(),
|
.build(),
|
||||||
|
|
||||||
ShortcutInfoCompat.Builder(context, "attendance_shortcut")
|
ShortcutInfoCompat.Builder(context, "attendance_shortcut")
|
||||||
.setShortLabel(context.getString(R.string.attendance_title))
|
.setShortLabel(context.getString(R.string.attendance_title))
|
||||||
.setLongLabel(context.getString(R.string.attendance_title))
|
.setLongLabel(context.getString(R.string.attendance_title))
|
||||||
.setIcon(IconCompat.createWithResource(context, R.drawable.ic_shortcut_attendance))
|
.setIcon(IconCompat.createWithResource(context, R.drawable.ic_shortcut_attendance))
|
||||||
.setIntent(SplashActivity.getStartIntent(context)
|
.setIntent(SplashActivity.getStartIntent(context, Destination.Attendance)
|
||||||
.apply {
|
.apply { action = Intent.ACTION_VIEW })
|
||||||
action = Intent.ACTION_VIEW
|
|
||||||
putExtra(EXTRA_SHORTCUT_DESTINATION_ID, "attendance")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.build(),
|
.build(),
|
||||||
|
|
||||||
ShortcutInfoCompat.Builder(context, "exam_shortcut")
|
ShortcutInfoCompat.Builder(context, "exam_shortcut")
|
||||||
.setShortLabel(context.getString(R.string.exam_title))
|
.setShortLabel(context.getString(R.string.exam_title))
|
||||||
.setLongLabel(context.getString(R.string.exam_title))
|
.setLongLabel(context.getString(R.string.exam_title))
|
||||||
.setIcon(IconCompat.createWithResource(context, R.drawable.ic_shortcut_exam))
|
.setIcon(IconCompat.createWithResource(context, R.drawable.ic_shortcut_exam))
|
||||||
.setIntent(SplashActivity.getStartIntent(context)
|
.setIntent(SplashActivity.getStartIntent(context, Destination.Exam)
|
||||||
.apply {
|
.apply { action = Intent.ACTION_VIEW })
|
||||||
action = Intent.ACTION_VIEW
|
|
||||||
putExtra(EXTRA_SHORTCUT_DESTINATION_ID, "exam")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.build(),
|
.build(),
|
||||||
|
|
||||||
ShortcutInfoCompat.Builder(context, "timetable_shortcut")
|
ShortcutInfoCompat.Builder(context, "timetable_shortcut")
|
||||||
.setShortLabel(context.getString(R.string.timetable_title))
|
.setShortLabel(context.getString(R.string.timetable_title))
|
||||||
.setLongLabel(context.getString(R.string.timetable_title))
|
.setLongLabel(context.getString(R.string.timetable_title))
|
||||||
.setIcon(IconCompat.createWithResource(context, R.drawable.ic_shortcut_timetable))
|
.setIcon(IconCompat.createWithResource(context, R.drawable.ic_shortcut_timetable))
|
||||||
.setIntent(SplashActivity.getStartIntent(context)
|
.setIntent(SplashActivity.getStartIntent(context, Destination.Timetable())
|
||||||
.apply {
|
.apply { action = Intent.ACTION_VIEW })
|
||||||
action = Intent.ACTION_VIEW
|
|
||||||
putExtra(EXTRA_SHORTCUT_DESTINATION_ID, "timetable")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
|
|
||||||
shortcutsInfo.forEach { ShortcutManagerCompat.pushDynamicShortcut(context, it) }
|
shortcutsInfo.forEach { ShortcutManagerCompat.pushDynamicShortcut(context, it) }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private companion object {
|
|
||||||
|
|
||||||
private const val EXTRA_SHORTCUT_DESTINATION_ID = "shortcut_destination_id"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -8,7 +8,6 @@ import io.github.wulkanowy.data.db.entities.Student
|
|||||||
import io.github.wulkanowy.data.pojos.GroupNotificationData
|
import io.github.wulkanowy.data.pojos.GroupNotificationData
|
||||||
import io.github.wulkanowy.data.pojos.NotificationData
|
import io.github.wulkanowy.data.pojos.NotificationData
|
||||||
import io.github.wulkanowy.ui.modules.Destination
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
import io.github.wulkanowy.ui.modules.splash.SplashActivity
|
|
||||||
import io.github.wulkanowy.utils.descriptionRes
|
import io.github.wulkanowy.utils.descriptionRes
|
||||||
import io.github.wulkanowy.utils.getPlural
|
import io.github.wulkanowy.utils.getPlural
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
@ -22,8 +21,9 @@ class NewAttendanceNotification @Inject constructor(
|
|||||||
suspend fun notify(items: List<Attendance>, student: Student) {
|
suspend fun notify(items: List<Attendance>, student: Student) {
|
||||||
val lines = items.filterNot { it.presence || it.name == "UNKNOWN" }
|
val lines = items.filterNot { it.presence || it.name == "UNKNOWN" }
|
||||||
.map {
|
.map {
|
||||||
|
val lesson = it.subject.ifBlank { "Lekcja ${it.number}" }
|
||||||
val description = context.getString(it.descriptionRes)
|
val description = context.getString(it.descriptionRes)
|
||||||
"${it.date.toFormattedString("dd.MM")} - ${it.subject}: $description"
|
"${it.date.toFormattedString("dd.MM")} - $lesson: $description"
|
||||||
}
|
}
|
||||||
.ifEmpty { return }
|
.ifEmpty { return }
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ import io.github.wulkanowy.data.db.entities.Student
|
|||||||
import io.github.wulkanowy.data.pojos.GroupNotificationData
|
import io.github.wulkanowy.data.pojos.GroupNotificationData
|
||||||
import io.github.wulkanowy.data.pojos.NotificationData
|
import io.github.wulkanowy.data.pojos.NotificationData
|
||||||
import io.github.wulkanowy.ui.modules.Destination
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
import io.github.wulkanowy.ui.modules.splash.SplashActivity
|
|
||||||
import io.github.wulkanowy.utils.getPlural
|
import io.github.wulkanowy.utils.getPlural
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -21,7 +20,7 @@ class NewMessageNotification @Inject constructor(
|
|||||||
val notificationDataList = items.map {
|
val notificationDataList = items.map {
|
||||||
NotificationData(
|
NotificationData(
|
||||||
title = context.getPlural(R.plurals.message_new_items, 1),
|
title = context.getPlural(R.plurals.message_new_items, 1),
|
||||||
content = "${it.sender}: ${it.subject}",
|
content = "${it.correspondents}: ${it.subject}",
|
||||||
destination = Destination.Message,
|
destination = Destination.Message,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -15,15 +15,16 @@ class MessageWork @Inject constructor(
|
|||||||
) : Work {
|
) : Work {
|
||||||
|
|
||||||
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
|
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
|
||||||
|
val mailbox = messageRepository.getMailboxByStudent(student)
|
||||||
messageRepository.getMessages(
|
messageRepository.getMessages(
|
||||||
student = student,
|
student = student,
|
||||||
semester = semester,
|
mailbox = mailbox,
|
||||||
folder = RECEIVED,
|
folder = RECEIVED,
|
||||||
forceRefresh = true,
|
forceRefresh = true,
|
||||||
notify = notify
|
notify = notify
|
||||||
).waitForResult()
|
).waitForResult()
|
||||||
|
|
||||||
messageRepository.getMessagesFromDatabase(student).first()
|
messageRepository.getMessagesFromDatabase(student, mailbox).first()
|
||||||
.filter { !it.isNotified && it.unread }.let {
|
.filter { !it.isNotified && it.unread }.let {
|
||||||
if (it.isNotEmpty()) newMessageNotification.notify(it, student)
|
if (it.isNotEmpty()) newMessageNotification.notify(it, student)
|
||||||
messageRepository.updateMessages(it.onEach { message -> message.isNotified = true })
|
messageRepository.updateMessages(it.onEach { message -> message.isNotified = true })
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
package io.github.wulkanowy.services.sync.works
|
package io.github.wulkanowy.services.sync.works
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.dataOrNull
|
||||||
|
import io.github.wulkanowy.data.db.entities.MailboxType
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||||
import io.github.wulkanowy.data.repositories.RecipientRepository
|
import io.github.wulkanowy.data.repositories.RecipientRepository
|
||||||
import io.github.wulkanowy.data.repositories.ReportingUnitRepository
|
import io.github.wulkanowy.data.toFirstResult
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class RecipientWork @Inject constructor(
|
class RecipientWork @Inject constructor(
|
||||||
private val reportingUnitRepository: ReportingUnitRepository,
|
private val messageRepository: MessageRepository,
|
||||||
private val recipientRepository: RecipientRepository
|
private val recipientRepository: RecipientRepository
|
||||||
) : Work {
|
) : Work {
|
||||||
|
|
||||||
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
|
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
|
||||||
reportingUnitRepository.refreshReportingUnits(student)
|
val mailboxes = messageRepository.getMailboxes(student, forceRefresh = true).toFirstResult()
|
||||||
|
mailboxes.dataOrNull?.forEach {
|
||||||
reportingUnitRepository.getReportingUnits(student).let { units ->
|
recipientRepository.refreshRecipients(student, it, MailboxType.EMPLOYEE)
|
||||||
units.map {
|
|
||||||
recipientRepository.refreshRecipients(student, it, 2)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import io.github.wulkanowy.data.repositories.SchoolAnnouncementRepository
|
|||||||
import io.github.wulkanowy.data.waitForResult
|
import io.github.wulkanowy.data.waitForResult
|
||||||
import io.github.wulkanowy.services.sync.notifications.NewSchoolAnnouncementNotification
|
import io.github.wulkanowy.services.sync.notifications.NewSchoolAnnouncementNotification
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
|
import java.time.LocalDate
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class SchoolAnnouncementWork @Inject constructor(
|
class SchoolAnnouncementWork @Inject constructor(
|
||||||
@ -20,10 +21,13 @@ class SchoolAnnouncementWork @Inject constructor(
|
|||||||
notify = notify,
|
notify = notify,
|
||||||
).waitForResult()
|
).waitForResult()
|
||||||
|
|
||||||
|
schoolAnnouncementRepository.getSchoolAnnouncementFromDatabase(student)
|
||||||
schoolAnnouncementRepository.getSchoolAnnouncementFromDatabase(student).first()
|
.first()
|
||||||
.filter { !it.isNotified }.let {
|
.filter { !it.isNotified && it.date >= LocalDate.now() }
|
||||||
if (it.isNotEmpty()) newSchoolAnnouncementNotification.notify(it, student)
|
.let {
|
||||||
|
if (it.isNotEmpty()) {
|
||||||
|
newSchoolAnnouncementNotification.notify(it, student)
|
||||||
|
}
|
||||||
|
|
||||||
schoolAnnouncementRepository.updateSchoolAnnouncement(it.onEach { schoolAnnouncement ->
|
schoolAnnouncementRepository.updateSchoolAnnouncement(it.onEach { schoolAnnouncement ->
|
||||||
schoolAnnouncement.isNotified = true
|
schoolAnnouncement.isNotified = true
|
||||||
|
@ -4,7 +4,6 @@ import android.app.Dialog
|
|||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import android.widget.Toast.LENGTH_LONG
|
import android.widget.Toast.LENGTH_LONG
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
@ -15,6 +14,7 @@ import androidx.fragment.app.DialogFragment
|
|||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.databinding.DialogErrorBinding
|
import io.github.wulkanowy.databinding.DialogErrorBinding
|
||||||
import io.github.wulkanowy.utils.*
|
import io.github.wulkanowy.utils.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -25,6 +25,9 @@ class ErrorDialog : DialogFragment() {
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var appInfo: AppInfo
|
lateinit var appInfo: AppInfo
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var preferencesRepository: PreferencesRepository
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val ARGUMENT_KEY = "error"
|
private const val ARGUMENT_KEY = "error"
|
||||||
|
|
||||||
@ -36,7 +39,7 @@ class ErrorDialog : DialogFragment() {
|
|||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
val error = requireArguments().getSerializable(ARGUMENT_KEY) as Throwable
|
val error = requireArguments().getSerializable(ARGUMENT_KEY) as Throwable
|
||||||
|
|
||||||
val binding = DialogErrorBinding.inflate(LayoutInflater.from(context))
|
val binding = DialogErrorBinding.inflate(layoutInflater)
|
||||||
binding.bindErrorDetails(error)
|
binding.bindErrorDetails(error)
|
||||||
|
|
||||||
return getAlertDialog(binding, error).apply {
|
return getAlertDialog(binding, error).apply {
|
||||||
@ -99,7 +102,8 @@ class ErrorDialog : DialogFragment() {
|
|||||||
R.string.about_feedback_template,
|
R.string.about_feedback_template,
|
||||||
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
|
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
|
||||||
appInfo.systemVersion.toString(),
|
appInfo.systemVersion.toString(),
|
||||||
"${appInfo.versionName}-${appInfo.buildFlavor}"
|
"${appInfo.versionName}-${appInfo.buildFlavor}",
|
||||||
|
preferencesRepository.installationId,
|
||||||
) + "\n" + content,
|
) + "\n" + content,
|
||||||
onActivityNotFound = {
|
onActivityNotFound = {
|
||||||
requireContext().openInternetBrowser(
|
requireContext().openInternetBrowser(
|
||||||
|
@ -19,15 +19,15 @@ import kotlinx.serialization.Serializable
|
|||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
sealed class Destination private constructor() : java.io.Serializable {
|
sealed class Destination {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Type in children classes have to be as getter to avoid null in enums
|
Type in children classes have to be as getter to avoid null in enums
|
||||||
https://stackoverflow.com/questions/68866453/kotlin-enum-val-is-returning-null-despite-being-set-at-compile-time
|
https://stackoverflow.com/questions/68866453/kotlin-enum-val-is-returning-null-despite-being-set-at-compile-time
|
||||||
*/
|
*/
|
||||||
abstract val type: Type
|
abstract val destinationType: Type
|
||||||
|
|
||||||
abstract val fragment: Fragment
|
abstract val destinationFragment: Fragment
|
||||||
|
|
||||||
enum class Type(val defaultDestination: Destination) {
|
enum class Type(val defaultDestination: Destination) {
|
||||||
DASHBOARD(Dashboard),
|
DASHBOARD(Dashboard),
|
||||||
@ -47,26 +47,26 @@ sealed class Destination private constructor() : java.io.Serializable {
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
object Dashboard : Destination() {
|
object Dashboard : Destination() {
|
||||||
override val type get() = Type.DASHBOARD
|
override val destinationType get() = Type.DASHBOARD
|
||||||
override val fragment get() = DashboardFragment.newInstance()
|
override val destinationFragment get() = DashboardFragment.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
object Grade : Destination() {
|
object Grade : Destination() {
|
||||||
override val type get() = Type.GRADE
|
override val destinationType get() = Type.GRADE
|
||||||
override val fragment get() = GradeFragment.newInstance()
|
override val destinationFragment get() = GradeFragment.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
object Attendance : Destination() {
|
object Attendance : Destination() {
|
||||||
override val type get() = Type.ATTENDANCE
|
override val destinationType get() = Type.ATTENDANCE
|
||||||
override val fragment get() = AttendanceFragment.newInstance()
|
override val destinationFragment get() = AttendanceFragment.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
object Exam : Destination() {
|
object Exam : Destination() {
|
||||||
override val type get() = Type.EXAM
|
override val destinationType get() = Type.EXAM
|
||||||
override val fragment get() = ExamFragment.newInstance()
|
override val destinationFragment get() = ExamFragment.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -74,55 +74,55 @@ sealed class Destination private constructor() : java.io.Serializable {
|
|||||||
@Serializable(with = LocalDateSerializer::class)
|
@Serializable(with = LocalDateSerializer::class)
|
||||||
private val date: LocalDate? = null
|
private val date: LocalDate? = null
|
||||||
) : Destination() {
|
) : Destination() {
|
||||||
override val type get() = Type.TIMETABLE
|
override val destinationType get() = Type.TIMETABLE
|
||||||
override val fragment get() = TimetableFragment.newInstance(date)
|
override val destinationFragment get() = TimetableFragment.newInstance(date)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
object Homework : Destination() {
|
object Homework : Destination() {
|
||||||
override val type get() = Type.HOMEWORK
|
override val destinationType get() = Type.HOMEWORK
|
||||||
override val fragment get() = HomeworkFragment.newInstance()
|
override val destinationFragment get() = HomeworkFragment.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
object Note : Destination() {
|
object Note : Destination() {
|
||||||
override val type get() = Type.NOTE
|
override val destinationType get() = Type.NOTE
|
||||||
override val fragment get() = NoteFragment.newInstance()
|
override val destinationFragment get() = NoteFragment.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
object Conference : Destination() {
|
object Conference : Destination() {
|
||||||
override val type get() = Type.CONFERENCE
|
override val destinationType get() = Type.CONFERENCE
|
||||||
override val fragment get() = ConferenceFragment.newInstance()
|
override val destinationFragment get() = ConferenceFragment.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
object SchoolAnnouncement : Destination() {
|
object SchoolAnnouncement : Destination() {
|
||||||
override val type get() = Type.SCHOOL_ANNOUNCEMENT
|
override val destinationType get() = Type.SCHOOL_ANNOUNCEMENT
|
||||||
override val fragment get() = SchoolAnnouncementFragment.newInstance()
|
override val destinationFragment get() = SchoolAnnouncementFragment.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
object School : Destination() {
|
object School : Destination() {
|
||||||
override val type get() = Type.SCHOOL
|
override val destinationType get() = Type.SCHOOL
|
||||||
override val fragment get() = SchoolFragment.newInstance()
|
override val destinationFragment get() = SchoolFragment.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
object LuckyNumber : Destination() {
|
object LuckyNumber : Destination() {
|
||||||
override val type get() = Type.LUCKY_NUMBER
|
override val destinationType get() = Type.LUCKY_NUMBER
|
||||||
override val fragment get() = LuckyNumberFragment.newInstance()
|
override val destinationFragment get() = LuckyNumberFragment.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
object More : Destination() {
|
object More : Destination() {
|
||||||
override val type get() = Type.MORE
|
override val destinationType get() = Type.MORE
|
||||||
override val fragment get() = MoreFragment.newInstance()
|
override val destinationFragment get() = MoreFragment.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
object Message : Destination() {
|
object Message : Destination() {
|
||||||
override val type get() = Type.MESSAGE
|
override val destinationType get() = Type.MESSAGE
|
||||||
override val fragment get() = MessageFragment.newInstance()
|
override val destinationFragment get() = MessageFragment.newInstance()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import android.view.View
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.databinding.FragmentAboutBinding
|
import io.github.wulkanowy.databinding.FragmentAboutBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.modules.about.contributor.ContributorFragment
|
import io.github.wulkanowy.ui.modules.about.contributor.ContributorFragment
|
||||||
@ -30,6 +31,9 @@ class AboutFragment : BaseFragment<FragmentAboutBinding>(R.layout.fragment_about
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var appInfo: AppInfo
|
lateinit var appInfo: AppInfo
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var preferencesRepository: PreferencesRepository
|
||||||
|
|
||||||
override val versionRes: Triple<String, String, Drawable?>?
|
override val versionRes: Triple<String, String, Drawable?>?
|
||||||
get() = context?.run {
|
get() = context?.run {
|
||||||
val buildTimestamp =
|
val buildTimestamp =
|
||||||
@ -185,7 +189,8 @@ class AboutFragment : BaseFragment<FragmentAboutBinding>(R.layout.fragment_about
|
|||||||
R.string.about_feedback_template,
|
R.string.about_feedback_template,
|
||||||
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
|
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
|
||||||
appInfo.systemVersion.toString(),
|
appInfo.systemVersion.toString(),
|
||||||
"${appInfo.versionName}-${appInfo.buildFlavor}"
|
"${appInfo.versionName}-${appInfo.buildFlavor}",
|
||||||
|
preferencesRepository.installationId,
|
||||||
),
|
),
|
||||||
onActivityNotFound = {
|
onActivityNotFound = {
|
||||||
requireContext().openInternetBrowser(
|
requireContext().openInternetBrowser(
|
||||||
|
@ -23,8 +23,9 @@ class LicenseAdapter @Inject constructor() : RecyclerView.Adapter<LicenseAdapter
|
|||||||
val item = items[position]
|
val item = items[position]
|
||||||
|
|
||||||
with(holder.binding) {
|
with(holder.binding) {
|
||||||
licenseItemName.text = item.libraryName
|
licenseItemName.text = item.name
|
||||||
licenseItemSummary.text = item.licenses?.firstOrNull()?.licenseName?.takeIf { it.isNotBlank() } ?: item.libraryVersion
|
licenseItemSummary.text = item.licenses.firstOrNull()?.name?.takeIf { it.isNotBlank() }
|
||||||
|
?: item.artifactVersion
|
||||||
|
|
||||||
root.setOnClickListener { onClickListener(item) }
|
root.setOnClickListener { onClickListener(item) }
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.mikepenz.aboutlibraries.Libs
|
import com.mikepenz.aboutlibraries.Libs
|
||||||
import com.mikepenz.aboutlibraries.entity.Library
|
import com.mikepenz.aboutlibraries.entity.Library
|
||||||
|
import com.mikepenz.aboutlibraries.util.withContext
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.databinding.FragmentLicenseBinding
|
import io.github.wulkanowy.databinding.FragmentLicenseBinding
|
||||||
@ -28,7 +29,9 @@ class LicenseFragment : BaseFragment<FragmentLicenseBinding>(R.layout.fragment_l
|
|||||||
|
|
||||||
override val titleStringId get() = R.string.license_title
|
override val titleStringId get() = R.string.license_title
|
||||||
|
|
||||||
override val appLibraries by lazy { Libs(requireContext()).libraries }
|
override val appLibraries by lazy {
|
||||||
|
Libs.Builder().withContext(requireContext()).build().libraries
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance() = LicenseFragment()
|
fun newInstance() = LicenseFragment()
|
||||||
|
@ -22,7 +22,7 @@ class LicensePresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onItemSelected(library: Library) {
|
fun onItemSelected(library: Library) {
|
||||||
view?.run { library.licenses?.firstOrNull()?.licenseDescription?.let { openLicense(it) } }
|
view?.run { library.licenses.firstOrNull()?.licenseContent?.let { openLicense(it) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadData() {
|
private fun loadData() {
|
||||||
|
@ -35,9 +35,11 @@ class AttendanceAdapter @Inject constructor() :
|
|||||||
|
|
||||||
with(holder.binding) {
|
with(holder.binding) {
|
||||||
attendanceItemNumber.text = item.number.toString()
|
attendanceItemNumber.text = item.number.toString()
|
||||||
attendanceItemSubject.text = item.subject
|
attendanceItemSubject.text = item.subject.ifBlank {
|
||||||
|
root.context.getString(R.string.all_no_data)
|
||||||
|
}
|
||||||
attendanceItemDescription.setText(item.descriptionRes)
|
attendanceItemDescription.setText(item.descriptionRes)
|
||||||
attendanceItemAlert.visibility = item.run { if (absence && !excused) View.VISIBLE else View.INVISIBLE }
|
attendanceItemAlert.isVisible = item.let { it.absence && !it.excused }
|
||||||
attendanceItemNumber.visibility = View.GONE
|
attendanceItemNumber.visibility = View.GONE
|
||||||
attendanceItemExcuseInfo.visibility = View.GONE
|
attendanceItemExcuseInfo.visibility = View.GONE
|
||||||
attendanceItemExcuseCheckbox.visibility = View.GONE
|
attendanceItemExcuseCheckbox.visibility = View.GONE
|
||||||
@ -46,7 +48,7 @@ class AttendanceAdapter @Inject constructor() :
|
|||||||
onExcuseCheckboxSelect(item, checked)
|
onExcuseCheckboxSelect(item, checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
when (item.excuseStatus?.let { SentExcuseStatus.valueOf(it)}) {
|
when (item.excuseStatus?.let { SentExcuseStatus.valueOf(it) }) {
|
||||||
SentExcuseStatus.WAITING -> {
|
SentExcuseStatus.WAITING -> {
|
||||||
attendanceItemExcuseInfo.setImageResource(R.drawable.ic_excuse_waiting)
|
attendanceItemExcuseInfo.setImageResource(R.drawable.ic_excuse_waiting)
|
||||||
attendanceItemExcuseInfo.visibility = View.VISIBLE
|
attendanceItemExcuseInfo.visibility = View.VISIBLE
|
||||||
|
@ -91,15 +91,19 @@ class AttendancePresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onViewReselected() {
|
fun onViewReselected() {
|
||||||
Timber.i("Attendance view is reselected")
|
Timber.i("Attendance view is reselected")
|
||||||
view?.also { view ->
|
view?.let { view ->
|
||||||
if (view.currentStackSize == 1) {
|
if (view.currentStackSize == 1) {
|
||||||
baseDate.also {
|
baseDate = now().previousOrSameSchoolDay
|
||||||
if (currentDate != it) {
|
|
||||||
reloadView(it)
|
if (currentDate != baseDate) {
|
||||||
loadData()
|
reloadView(baseDate)
|
||||||
} else if (!view.isViewEmpty) view.resetView()
|
loadData()
|
||||||
|
} else if (!view.isViewEmpty) {
|
||||||
|
view.resetView()
|
||||||
}
|
}
|
||||||
} else view.popView()
|
} else {
|
||||||
|
view.popView()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ import io.github.wulkanowy.ui.base.BaseFragment
|
|||||||
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsFragment
|
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsFragment
|
||||||
import io.github.wulkanowy.ui.modules.attendance.summary.AttendanceSummaryFragment
|
import io.github.wulkanowy.ui.modules.attendance.summary.AttendanceSummaryFragment
|
||||||
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
|
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.dashboard.adapters.DashboardAdapter
|
||||||
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
||||||
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
||||||
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
||||||
@ -47,6 +48,14 @@ class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragme
|
|||||||
override var subtitleString =
|
override var subtitleString =
|
||||||
LocalDate.now().toFormattedString("EEEE, d MMMM yyyy").capitalise()
|
LocalDate.now().toFormattedString("EEEE, d MMMM yyyy").capitalise()
|
||||||
|
|
||||||
|
override val tileWidth: Int
|
||||||
|
get() {
|
||||||
|
val recyclerWidth = binding.dashboardRecycler.width
|
||||||
|
val margin = requireContext().dpToPx(24f).toInt()
|
||||||
|
|
||||||
|
return ((recyclerWidth - margin) / resources.displayMetrics.density).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun newInstance() = DashboardFragment()
|
fun newInstance() = DashboardFragment()
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
import io.github.wulkanowy.data.db.entities.*
|
||||||
import io.github.wulkanowy.data.db.entities.Conference
|
|
||||||
import io.github.wulkanowy.data.db.entities.Exam
|
|
||||||
import io.github.wulkanowy.data.db.entities.Grade
|
|
||||||
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import io.github.wulkanowy.data.enums.GradeColorTheme
|
import io.github.wulkanowy.data.enums.GradeColorTheme
|
||||||
import io.github.wulkanowy.data.pojos.TimetableFull
|
import io.github.wulkanowy.data.pojos.TimetableFull
|
||||||
|
import io.github.wulkanowy.utils.AdBanner
|
||||||
import io.github.wulkanowy.data.db.entities.Homework as EntitiesHomework
|
import io.github.wulkanowy.data.db.entities.Homework as EntitiesHomework
|
||||||
|
|
||||||
sealed class DashboardItem(val type: Type) {
|
sealed class DashboardItem(val type: Type) {
|
||||||
@ -106,17 +102,26 @@ sealed class DashboardItem(val type: Type) {
|
|||||||
override val isDataLoaded get() = conferences != null
|
override val isDataLoaded get() = conferences != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class Ads(
|
||||||
|
val adBanner: AdBanner? = null,
|
||||||
|
override val error: Throwable? = null,
|
||||||
|
override val isLoading: Boolean = false
|
||||||
|
) : DashboardItem(Type.ADS) {
|
||||||
|
|
||||||
|
override val isDataLoaded get() = adBanner != null
|
||||||
|
}
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
ADMIN_MESSAGE,
|
ADMIN_MESSAGE,
|
||||||
ACCOUNT,
|
ACCOUNT,
|
||||||
HORIZONTAL_GROUP,
|
HORIZONTAL_GROUP,
|
||||||
LESSONS,
|
LESSONS,
|
||||||
|
ADS,
|
||||||
GRADES,
|
GRADES,
|
||||||
HOMEWORK,
|
HOMEWORK,
|
||||||
ANNOUNCEMENTS,
|
ANNOUNCEMENTS,
|
||||||
EXAMS,
|
EXAMS,
|
||||||
CONFERENCES,
|
CONFERENCES,
|
||||||
ADS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Tile {
|
enum class Tile {
|
||||||
@ -126,12 +131,12 @@ sealed class DashboardItem(val type: Type) {
|
|||||||
MESSAGES,
|
MESSAGES,
|
||||||
ATTENDANCE,
|
ATTENDANCE,
|
||||||
LESSONS,
|
LESSONS,
|
||||||
|
ADS,
|
||||||
GRADES,
|
GRADES,
|
||||||
HOMEWORK,
|
HOMEWORK,
|
||||||
ANNOUNCEMENTS,
|
ANNOUNCEMENTS,
|
||||||
EXAMS,
|
EXAMS,
|
||||||
CONFERENCES,
|
CONFERENCES,
|
||||||
ADS
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,4 +153,4 @@ fun DashboardItem.Tile.toDashboardItemType() = when (this) {
|
|||||||
DashboardItem.Tile.EXAMS -> DashboardItem.Type.EXAMS
|
DashboardItem.Tile.EXAMS -> DashboardItem.Type.EXAMS
|
||||||
DashboardItem.Tile.CONFERENCES -> DashboardItem.Type.CONFERENCES
|
DashboardItem.Tile.CONFERENCES -> DashboardItem.Type.CONFERENCES
|
||||||
DashboardItem.Tile.ADS -> DashboardItem.Type.ADS
|
DashboardItem.Tile.ADS -> DashboardItem.Type.ADS
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@ package io.github.wulkanowy.ui.modules.dashboard
|
|||||||
|
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import java.util.Collections
|
import io.github.wulkanowy.ui.modules.dashboard.adapters.DashboardAdapter
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class DashboardItemMoveCallback(
|
class DashboardItemMoveCallback(
|
||||||
private val dashboardAdapter: DashboardAdapter,
|
private val dashboardAdapter: DashboardAdapter,
|
||||||
|
@ -8,6 +8,7 @@ import io.github.wulkanowy.data.enums.MessageFolder
|
|||||||
import io.github.wulkanowy.data.repositories.*
|
import io.github.wulkanowy.data.repositories.*
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
|
import io.github.wulkanowy.utils.AdsHelper
|
||||||
import io.github.wulkanowy.utils.calculatePercentage
|
import io.github.wulkanowy.utils.calculatePercentage
|
||||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
@ -31,7 +32,8 @@ class DashboardPresenter @Inject constructor(
|
|||||||
private val conferenceRepository: ConferenceRepository,
|
private val conferenceRepository: ConferenceRepository,
|
||||||
private val preferencesRepository: PreferencesRepository,
|
private val preferencesRepository: PreferencesRepository,
|
||||||
private val schoolAnnouncementRepository: SchoolAnnouncementRepository,
|
private val schoolAnnouncementRepository: SchoolAnnouncementRepository,
|
||||||
private val adminMessageRepository: AdminMessageRepository
|
private val adminMessageRepository: AdminMessageRepository,
|
||||||
|
private val adsHelper: AdsHelper
|
||||||
) : BasePresenter<DashboardView>(errorHandler, studentRepository) {
|
) : BasePresenter<DashboardView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
private val dashboardItemLoadedList = mutableListOf<DashboardItem>()
|
private val dashboardItemLoadedList = mutableListOf<DashboardItem>()
|
||||||
@ -55,7 +57,11 @@ class DashboardPresenter @Inject constructor(
|
|||||||
showContent(false)
|
showContent(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
preferencesRepository.selectedDashboardTilesFlow
|
merge(
|
||||||
|
preferencesRepository.selectedDashboardTilesFlow,
|
||||||
|
preferencesRepository.isAdsEnabledFlow
|
||||||
|
.map { preferencesRepository.selectedDashboardTiles }
|
||||||
|
)
|
||||||
.onEach { loadData(tilesToLoad = it) }
|
.onEach { loadData(tilesToLoad = it) }
|
||||||
.launch("dashboard_pref")
|
.launch("dashboard_pref")
|
||||||
}
|
}
|
||||||
@ -166,7 +172,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
DashboardItem.Type.CONFERENCES -> {
|
DashboardItem.Type.CONFERENCES -> {
|
||||||
loadConferences(student, forceRefresh)
|
loadConferences(student, forceRefresh)
|
||||||
}
|
}
|
||||||
DashboardItem.Type.ADS -> TODO()
|
DashboardItem.Type.ADS -> loadAds(forceRefresh)
|
||||||
DashboardItem.Type.ADMIN_MESSAGE -> loadAdminMessage(student, forceRefresh)
|
DashboardItem.Type.ADMIN_MESSAGE -> loadAdminMessage(student, forceRefresh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,6 +227,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) {
|
private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) {
|
||||||
flow {
|
flow {
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val semester = semesterRepository.getCurrentSemester(student)
|
||||||
|
val mailbox = messageRepository.getMailboxByStudent(student)
|
||||||
val selectedTiles = preferencesRepository.selectedDashboardTiles
|
val selectedTiles = preferencesRepository.selectedDashboardTiles
|
||||||
|
|
||||||
val flowSuccess = flowOf(Resource.Success(null))
|
val flowSuccess = flowOf(Resource.Success(null))
|
||||||
@ -232,7 +239,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
|
|
||||||
val messageFLow = messageRepository.getMessages(
|
val messageFLow = messageRepository.getMessages(
|
||||||
student = student,
|
student = student,
|
||||||
semester = semester,
|
mailbox = mailbox,
|
||||||
folder = MessageFolder.RECEIVED,
|
folder = MessageFolder.RECEIVED,
|
||||||
forceRefresh = forceRefresh
|
forceRefresh = forceRefresh
|
||||||
).takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowSuccess
|
).takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowSuccess
|
||||||
@ -595,6 +602,23 @@ class DashboardPresenter @Inject constructor(
|
|||||||
.launchWithUniqueRefreshJob("dashboard_admin_messages", forceRefresh)
|
.launchWithUniqueRefreshJob("dashboard_admin_messages", forceRefresh)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadAds(forceRefresh: Boolean) {
|
||||||
|
presenterScope.launch {
|
||||||
|
if (!forceRefresh) {
|
||||||
|
updateData(DashboardItem.Ads(), forceRefresh)
|
||||||
|
}
|
||||||
|
|
||||||
|
val dashboardAdItem =
|
||||||
|
runCatching {
|
||||||
|
DashboardItem.Ads(adsHelper.getDashboardTileAdBanner(view!!.tileWidth))
|
||||||
|
}
|
||||||
|
.onFailure { Timber.e(it) }
|
||||||
|
.getOrElse { DashboardItem.Ads(error = it) }
|
||||||
|
|
||||||
|
updateData(dashboardAdItem, forceRefresh)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateData(dashboardItem: DashboardItem, forceRefresh: Boolean) {
|
private fun updateData(dashboardItem: DashboardItem, forceRefresh: Boolean) {
|
||||||
val isForceRefreshError = forceRefresh && dashboardItem.error != null
|
val isForceRefreshError = forceRefresh && dashboardItem.error != null
|
||||||
val isFirstRunDataLoadedError =
|
val isFirstRunDataLoadedError =
|
||||||
@ -619,6 +643,18 @@ class DashboardPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dashboardItem is DashboardItem.Ads) {
|
||||||
|
if (!dashboardItem.isDataLoaded) {
|
||||||
|
dashboardItemsToLoad = dashboardItemsToLoad - DashboardItem.Type.ADS
|
||||||
|
dashboardTileLoadedList = dashboardTileLoadedList - DashboardItem.Tile.ADS
|
||||||
|
|
||||||
|
dashboardItemLoadedList.removeAll { it.type == DashboardItem.Type.ADS }
|
||||||
|
} else {
|
||||||
|
dashboardItemsToLoad = dashboardItemsToLoad + DashboardItem.Type.ADS
|
||||||
|
dashboardTileLoadedList = dashboardTileLoadedList + DashboardItem.Tile.ADS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (forceRefresh) {
|
if (forceRefresh) {
|
||||||
updateForceRefreshData(dashboardItem)
|
updateForceRefreshData(dashboardItem)
|
||||||
} else {
|
} else {
|
||||||
|
@ -4,6 +4,8 @@ import io.github.wulkanowy.ui.base.BaseView
|
|||||||
|
|
||||||
interface DashboardView : BaseView {
|
interface DashboardView : BaseView {
|
||||||
|
|
||||||
|
val tileWidth: Int
|
||||||
|
|
||||||
fun initView()
|
fun initView()
|
||||||
|
|
||||||
fun updateData(data: List<DashboardItem>)
|
fun updateData(data: List<DashboardItem>)
|
||||||
@ -27,4 +29,4 @@ interface DashboardView : BaseView {
|
|||||||
fun openNotificationsCenterView()
|
fun openNotificationsCenterView()
|
||||||
|
|
||||||
fun openInternetBrowser(url: String)
|
fun openInternetBrowser(url: String)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
@ -9,6 +9,7 @@ import android.os.Looper
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
import androidx.core.text.parseAsHtml
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.view.updateLayoutParams
|
import androidx.core.view.updateLayoutParams
|
||||||
import androidx.core.view.updateMarginsRelative
|
import androidx.core.view.updateMarginsRelative
|
||||||
@ -21,24 +22,15 @@ import io.github.wulkanowy.data.db.entities.Student
|
|||||||
import io.github.wulkanowy.data.db.entities.Timetable
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
||||||
import io.github.wulkanowy.data.enums.GradeColorTheme
|
import io.github.wulkanowy.data.enums.GradeColorTheme
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardAccountBinding
|
import io.github.wulkanowy.databinding.*
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardAdminMessageBinding
|
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardAnnouncementsBinding
|
import io.github.wulkanowy.utils.*
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardConferencesBinding
|
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardExamsBinding
|
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardGradesBinding
|
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardHomeworkBinding
|
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardHorizontalGroupBinding
|
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardLessonsBinding
|
|
||||||
import io.github.wulkanowy.utils.createNameInitialsDrawable
|
|
||||||
import io.github.wulkanowy.utils.dpToPx
|
|
||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
|
||||||
import io.github.wulkanowy.utils.left
|
|
||||||
import io.github.wulkanowy.utils.nickOrName
|
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.time.*
|
import java.time.Duration
|
||||||
import java.util.Timer
|
import java.time.Instant
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.concurrent.timer
|
import kotlin.concurrent.timer
|
||||||
|
|
||||||
@ -119,6 +111,9 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
DashboardItem.Type.ADMIN_MESSAGE.ordinal -> AdminMessageViewHolder(
|
DashboardItem.Type.ADMIN_MESSAGE.ordinal -> AdminMessageViewHolder(
|
||||||
ItemDashboardAdminMessageBinding.inflate(inflater, parent, false)
|
ItemDashboardAdminMessageBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
DashboardItem.Type.ADS.ordinal -> AdsViewHolder(
|
||||||
|
ItemDashboardAdsBinding.inflate(inflater, parent, false)
|
||||||
|
)
|
||||||
else -> throw IllegalArgumentException()
|
else -> throw IllegalArgumentException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,6 +129,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
is ExamsViewHolder -> bindExamsViewHolder(holder, position)
|
is ExamsViewHolder -> bindExamsViewHolder(holder, position)
|
||||||
is ConferencesViewHolder -> bindConferencesViewHolder(holder, position)
|
is ConferencesViewHolder -> bindConferencesViewHolder(holder, position)
|
||||||
is AdminMessageViewHolder -> bindAdminMessage(holder, position)
|
is AdminMessageViewHolder -> bindAdminMessage(holder, position)
|
||||||
|
is AdsViewHolder -> bindAdsViewHolder(holder, position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -563,7 +559,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
) {
|
) {
|
||||||
with(binding.dashboardLessonsItemDayHeader) {
|
with(binding.dashboardLessonsItemDayHeader) {
|
||||||
isVisible = header != null
|
isVisible = header != null
|
||||||
text = header?.content
|
text = header?.content?.parseAsHtml()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -745,6 +741,20 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun bindAdsViewHolder(adsViewHolder: AdsViewHolder, position: Int) {
|
||||||
|
val item = (items[position] as DashboardItem.Ads).adBanner ?: return
|
||||||
|
val binding = adsViewHolder.binding
|
||||||
|
|
||||||
|
binding.dashboardAdminMessageItemContent.removeAllViews()
|
||||||
|
binding.dashboardAdminMessageItemContent.addView(
|
||||||
|
item.view,
|
||||||
|
ViewGroup.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
class AccountViewHolder(val binding: ItemDashboardAccountBinding) :
|
class AccountViewHolder(val binding: ItemDashboardAccountBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
@ -787,6 +797,9 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
class AdminMessageViewHolder(val binding: ItemDashboardAdminMessageBinding) :
|
class AdminMessageViewHolder(val binding: ItemDashboardAdminMessageBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
|
class AdsViewHolder(val binding: ItemDashboardAdsBinding) :
|
||||||
|
RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
private class DiffCallback(
|
private class DiffCallback(
|
||||||
private val newList: List<DashboardItem>,
|
private val newList: List<DashboardItem>,
|
||||||
private val oldList: List<DashboardItem>
|
private val oldList: List<DashboardItem>
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -33,4 +33,4 @@ class DashboardAnnouncementsAdapter :
|
|||||||
|
|
||||||
class ViewHolder(val binding: SubitemDashboardAnnouncementsBinding) :
|
class ViewHolder(val binding: SubitemDashboardAnnouncementsBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -33,4 +33,4 @@ class DashboardConferencesAdapter :
|
|||||||
|
|
||||||
class ViewHolder(val binding: SubitemDashboardConferencesBinding) :
|
class ViewHolder(val binding: SubitemDashboardConferencesBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@ -56,4 +56,4 @@ class DashboardExamsAdapter :
|
|||||||
|
|
||||||
class ViewHolder(val binding: SubitemDashboardExamsBinding) :
|
class ViewHolder(val binding: SubitemDashboardExamsBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@ -53,4 +53,4 @@ class DashboardHomeworkAdapter : RecyclerView.Adapter<DashboardHomeworkAdapter.V
|
|||||||
|
|
||||||
class ViewHolder(val binding: SubitemDashboardHomeworkBinding) :
|
class ViewHolder(val binding: SubitemDashboardHomeworkBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
}
|
}
|
@ -17,16 +17,16 @@ val debugMessageItems = listOf(
|
|||||||
)
|
)
|
||||||
|
|
||||||
private fun generateMessage(sender: String, subject: String) = Message(
|
private fun generateMessage(sender: String, subject: String) = Message(
|
||||||
sender = sender,
|
|
||||||
subject = subject,
|
subject = subject,
|
||||||
studentId = 0,
|
messageId = 123,
|
||||||
realId = 0,
|
email = "",
|
||||||
messageId = 0,
|
|
||||||
senderId = 0,
|
|
||||||
recipient = "",
|
|
||||||
date = Instant.now(),
|
date = Instant.now(),
|
||||||
folderId = 0,
|
folderId = 0,
|
||||||
unread = true,
|
unread = true,
|
||||||
removed = false,
|
readBy = 2,
|
||||||
hasAttachments = false
|
unreadBy = 2,
|
||||||
|
hasAttachments = false,
|
||||||
|
messageGlobalKey = "",
|
||||||
|
correspondents = sender,
|
||||||
|
mailboxKey = "",
|
||||||
)
|
)
|
||||||
|
@ -19,6 +19,6 @@ val debugSchoolAnnouncementItems = listOf(
|
|||||||
private fun generateAnnouncement(subject: String, content: String) = SchoolAnnouncement(
|
private fun generateAnnouncement(subject: String, content: String) = SchoolAnnouncement(
|
||||||
subject = subject,
|
subject = subject,
|
||||||
content = content,
|
content = content,
|
||||||
studentId = 0,
|
userLoginId = 0,
|
||||||
date = LocalDate.now()
|
date = LocalDate.now()
|
||||||
)
|
)
|
||||||
|
@ -3,8 +3,7 @@ package io.github.wulkanowy.ui.modules.grade.details
|
|||||||
import io.github.wulkanowy.data.*
|
import io.github.wulkanowy.data.*
|
||||||
import io.github.wulkanowy.data.db.entities.Grade
|
import io.github.wulkanowy.data.db.entities.Grade
|
||||||
import io.github.wulkanowy.data.enums.GradeExpandMode
|
import io.github.wulkanowy.data.enums.GradeExpandMode
|
||||||
import io.github.wulkanowy.data.enums.GradeSortingMode.ALPHABETIC
|
import io.github.wulkanowy.data.enums.GradeSortingMode.*
|
||||||
import io.github.wulkanowy.data.enums.GradeSortingMode.DATE
|
|
||||||
import io.github.wulkanowy.data.repositories.GradeRepository
|
import io.github.wulkanowy.data.repositories.GradeRepository
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||||
@ -132,16 +131,17 @@ class GradeDetailsPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
.logResourceStatus("load grade details")
|
.logResourceStatus("load grade details")
|
||||||
.onResourceData {
|
.onResourceData {
|
||||||
|
val gradeItems = createGradeItems(it)
|
||||||
view?.run {
|
view?.run {
|
||||||
enableSwipe(true)
|
enableSwipe(true)
|
||||||
showProgress(false)
|
showProgress(false)
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
showContent(it.isNotEmpty())
|
showContent(gradeItems.isNotEmpty())
|
||||||
showEmpty(it.isEmpty())
|
showEmpty(gradeItems.isEmpty())
|
||||||
updateNewGradesAmount(it)
|
updateNewGradesAmount(it)
|
||||||
updateMarkAsDoneButton()
|
updateMarkAsDoneButton()
|
||||||
updateData(
|
updateData(
|
||||||
data = createGradeItems(it),
|
data = gradeItems,
|
||||||
expandMode = preferencesRepository.gradeExpandMode,
|
expandMode = preferencesRepository.gradeExpandMode,
|
||||||
preferencesRepository.gradeColorTheme
|
preferencesRepository.gradeColorTheme
|
||||||
)
|
)
|
||||||
@ -204,6 +204,7 @@ class GradeDetailsPresenter @Inject constructor(
|
|||||||
ALPHABETIC -> gradeSubjects.sortedBy { gradeDetailsWithAverage ->
|
ALPHABETIC -> gradeSubjects.sortedBy { gradeDetailsWithAverage ->
|
||||||
gradeDetailsWithAverage.subject.lowercase()
|
gradeDetailsWithAverage.subject.lowercase()
|
||||||
}
|
}
|
||||||
|
AVERAGE -> gradeSubjects.sortedByDescending { it.average }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.map { (subject, average, points, _, grades) ->
|
.map { (subject, average, points, _, grades) ->
|
||||||
|
@ -10,6 +10,7 @@ import io.github.wulkanowy.data.db.entities.GradeSummary
|
|||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.databinding.ItemGradeSummaryBinding
|
import io.github.wulkanowy.databinding.ItemGradeSummaryBinding
|
||||||
import io.github.wulkanowy.databinding.ScrollableHeaderGradeSummaryBinding
|
import io.github.wulkanowy.databinding.ScrollableHeaderGradeSummaryBinding
|
||||||
|
import io.github.wulkanowy.sdk.scrapper.grades.isGradeValid
|
||||||
import io.github.wulkanowy.utils.calcFinalAverage
|
import io.github.wulkanowy.utils.calcFinalAverage
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -61,7 +62,7 @@ class GradeSummaryAdapter @Inject constructor(
|
|||||||
if (items.isEmpty()) return
|
if (items.isEmpty()) return
|
||||||
|
|
||||||
val context = binding.root.context
|
val context = binding.root.context
|
||||||
val finalItemsCount = items.count { it.finalGrade.matches("[0-6][+-]?".toRegex()) }
|
val finalItemsCount = items.count { isGradeValid(it.finalGrade) }
|
||||||
val calculatedItemsCount = items.count { value -> value.average != 0.0 }
|
val calculatedItemsCount = items.count { value -> value.average != 0.0 }
|
||||||
val allItemsCount = items.count { !it.subject.equals("zachowanie", true) }
|
val allItemsCount = items.count { !it.subject.equals("zachowanie", true) }
|
||||||
val finalAverage = items.calcFinalAverage(
|
val finalAverage = items.calcFinalAverage(
|
||||||
|
@ -2,6 +2,9 @@ package io.github.wulkanowy.ui.modules.grade.summary
|
|||||||
|
|
||||||
import io.github.wulkanowy.data.*
|
import io.github.wulkanowy.data.*
|
||||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||||
|
import io.github.wulkanowy.data.enums.GradeSortingMode
|
||||||
|
import io.github.wulkanowy.data.enums.GradeSortingMode.*
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
@ -14,6 +17,7 @@ import javax.inject.Inject
|
|||||||
class GradeSummaryPresenter @Inject constructor(
|
class GradeSummaryPresenter @Inject constructor(
|
||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
|
private val preferencesRepository: PreferencesRepository,
|
||||||
private val averageProvider: GradeAverageProvider,
|
private val averageProvider: GradeAverageProvider,
|
||||||
private val analytics: AnalyticsHelper
|
private val analytics: AnalyticsHelper
|
||||||
) : BasePresenter<GradeSummaryView>(errorHandler, studentRepository) {
|
) : BasePresenter<GradeSummaryView>(errorHandler, studentRepository) {
|
||||||
@ -127,7 +131,17 @@ class GradeSummaryPresenter @Inject constructor(
|
|||||||
private fun createGradeSummaryItems(items: List<GradeSubject>): List<GradeSummary> {
|
private fun createGradeSummaryItems(items: List<GradeSubject>): List<GradeSummary> {
|
||||||
return items
|
return items
|
||||||
.filter { !checkEmpty(it) }
|
.filter { !checkEmpty(it) }
|
||||||
.sortedBy { it.subject }
|
.let { gradeSubjects ->
|
||||||
|
when (preferencesRepository.gradeSortingMode) {
|
||||||
|
DATE -> gradeSubjects.sortedByDescending { gradeDetailsWithAverage ->
|
||||||
|
gradeDetailsWithAverage.grades.maxByOrNull { it.date }?.date
|
||||||
|
}
|
||||||
|
ALPHABETIC -> gradeSubjects.sortedBy { gradeDetailsWithAverage ->
|
||||||
|
gradeDetailsWithAverage.subject.lowercase()
|
||||||
|
}
|
||||||
|
AVERAGE -> gradeSubjects.sortedByDescending { it.average }
|
||||||
|
}
|
||||||
|
}
|
||||||
.map { it.summary.copy(average = it.average) }
|
.map { it.summary.copy(average = it.average) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +93,7 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
|
|||||||
}
|
}
|
||||||
|
|
||||||
//https://developer.android.com/guide/playcore/in-app-updates#status_callback
|
//https://developer.android.com/guide/playcore/in-app-updates#status_callback
|
||||||
|
@Deprecated("Deprecated in Java")
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
@ -10,6 +10,7 @@ import androidx.core.widget.doOnTextChanged
|
|||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.databinding.FragmentLoginFormBinding
|
import io.github.wulkanowy.databinding.FragmentLoginFormBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
@ -32,6 +33,9 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var appInfo: AppInfo
|
lateinit var appInfo: AppInfo
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var preferencesRepository: PreferencesRepository
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance() = LoginFormFragment()
|
fun newInstance() = LoginFormFragment()
|
||||||
}
|
}
|
||||||
@ -260,8 +264,9 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
|
|||||||
R.string.login_email_text,
|
R.string.login_email_text,
|
||||||
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
|
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
|
||||||
appInfo.systemVersion.toString(),
|
appInfo.systemVersion.toString(),
|
||||||
appInfo.versionName,
|
"${appInfo.versionName}-${appInfo.buildFlavor}",
|
||||||
"$formHostValue/$formHostSymbol",
|
"$formHostValue/$formHostSymbol",
|
||||||
|
preferencesRepository.installationId,
|
||||||
lastError
|
lastError
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -172,7 +172,7 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
if ("@" in login && "||" !in login && "login" !in host && "email" !in host) {
|
if ("@" in login && "||" !in login && "login" !in host && "email" !in host) {
|
||||||
val emailHost = login.substringAfter("@")
|
val emailHost = login.substringAfter("@")
|
||||||
val emailDomain = URL(host).host
|
val emailDomain = URL(host).host
|
||||||
if (emailHost != emailDomain) {
|
if (!emailHost.equals(emailDomain, true)) {
|
||||||
view?.setErrorEmailInvalid(domain = emailDomain)
|
view?.setErrorEmailInvalid(domain = emailDomain)
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,7 @@ import android.os.Bundle
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
import android.webkit.JavascriptInterface
|
import android.webkit.*
|
||||||
import android.webkit.WebView
|
|
||||||
import android.webkit.WebViewClient
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.doOnTextChanged
|
import androidx.core.widget.doOnTextChanged
|
||||||
import com.yariksoffice.lingver.Lingver
|
import com.yariksoffice.lingver.Lingver
|
||||||
@ -206,10 +204,9 @@ class LoginRecoverFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onReceivedError(
|
override fun onReceivedError(
|
||||||
view: WebView,
|
view: WebView?,
|
||||||
errorCode: Int,
|
request: WebResourceRequest?,
|
||||||
description: String,
|
error: WebResourceError?
|
||||||
failingUrl: String
|
|
||||||
) {
|
) {
|
||||||
recoverWebViewSuccess = false
|
recoverWebViewSuccess = false
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.databinding.FragmentLoginStudentSelectBinding
|
import io.github.wulkanowy.databinding.FragmentLoginStudentSelectBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
@ -32,6 +33,9 @@ class LoginStudentSelectFragment :
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var appInfo: AppInfo
|
lateinit var appInfo: AppInfo
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var preferencesRepository: PreferencesRepository
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val ARG_STUDENTS = "STUDENTS"
|
const val ARG_STUDENTS = "STUDENTS"
|
||||||
|
|
||||||
@ -111,10 +115,12 @@ class LoginStudentSelectFragment :
|
|||||||
email = "wulkanowyinc@gmail.com",
|
email = "wulkanowyinc@gmail.com",
|
||||||
subject = requireContext().getString(R.string.login_email_subject),
|
subject = requireContext().getString(R.string.login_email_subject),
|
||||||
body = requireContext().getString(
|
body = requireContext().getString(
|
||||||
R.string.login_email_text, appInfo.systemModel,
|
R.string.login_email_text,
|
||||||
|
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
|
||||||
appInfo.systemVersion.toString(),
|
appInfo.systemVersion.toString(),
|
||||||
appInfo.versionName,
|
"${appInfo.versionName}-${appInfo.buildFlavor}",
|
||||||
"Select users to log in",
|
"Select users to log in",
|
||||||
|
preferencesRepository.installationId,
|
||||||
lastError
|
lastError
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -13,6 +13,7 @@ import androidx.core.widget.doOnTextChanged
|
|||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.databinding.FragmentLoginSymbolBinding
|
import io.github.wulkanowy.databinding.FragmentLoginSymbolBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
@ -34,6 +35,9 @@ class LoginSymbolFragment :
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var appInfo: AppInfo
|
lateinit var appInfo: AppInfo
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var preferencesRepository: PreferencesRepository
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val SAVED_LOGIN_DATA = "LOGIN_DATA"
|
private const val SAVED_LOGIN_DATA = "LOGIN_DATA"
|
||||||
|
|
||||||
@ -159,8 +163,9 @@ class LoginSymbolFragment :
|
|||||||
R.string.login_email_text,
|
R.string.login_email_text,
|
||||||
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
|
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
|
||||||
appInfo.systemVersion.toString(),
|
appInfo.systemVersion.toString(),
|
||||||
appInfo.versionName,
|
"${appInfo.versionName}-${appInfo.buildFlavor}",
|
||||||
"$host/${binding.loginSymbolName.text}",
|
"$host/${binding.loginSymbolName.text}",
|
||||||
|
preferencesRepository.installationId,
|
||||||
lastError
|
lastError
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -78,7 +78,7 @@ class LuckyNumberWidgetProvider : AppWidgetProvider() {
|
|||||||
.apply {
|
.apply {
|
||||||
setTextViewText(
|
setTextViewText(
|
||||||
R.id.luckyNumberWidgetNumber,
|
R.id.luckyNumberWidgetNumber,
|
||||||
luckyNumber.dataOrNull?.toString() ?: "#"
|
luckyNumber.dataOrNull?.luckyNumber?.toString() ?: "#"
|
||||||
)
|
)
|
||||||
setOnClickPendingIntent(R.id.luckyNumberWidgetContainer, appIntent)
|
setOnClickPendingIntent(R.id.luckyNumberWidgetContainer, appIntent)
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import androidx.fragment.app.DialogFragment
|
|||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.elevation.ElevationOverlayProvider
|
import com.google.android.material.elevation.ElevationOverlayProvider
|
||||||
import com.ncapdevi.fragnav.FragNavController
|
import com.ncapdevi.fragnav.FragNavController
|
||||||
import com.ncapdevi.fragnav.FragNavController.Companion.HIDE
|
import com.ncapdevi.fragnav.FragNavController.Companion.HIDE
|
||||||
@ -20,10 +21,13 @@ import io.github.wulkanowy.R
|
|||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.databinding.ActivityMainBinding
|
import io.github.wulkanowy.databinding.ActivityMainBinding
|
||||||
|
import io.github.wulkanowy.databinding.DialogAdsConsentBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
import io.github.wulkanowy.ui.modules.Destination
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
|
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
|
||||||
import io.github.wulkanowy.utils.*
|
import io.github.wulkanowy.utils.*
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -55,13 +59,13 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val EXTRA_START_DESTINATION = "start_destination"
|
private const val EXTRA_START_DESTINATION = "start_destination_json"
|
||||||
|
|
||||||
fun getStartIntent(
|
fun getStartIntent(
|
||||||
context: Context,
|
context: Context,
|
||||||
destination: Destination? = null,
|
destination: Destination? = null,
|
||||||
) = Intent(context, MainActivity::class.java).apply {
|
) = Intent(context, MainActivity::class.java).apply {
|
||||||
putExtra(EXTRA_START_DESTINATION, destination)
|
destination?.let { putExtra(EXTRA_START_DESTINATION, Json.encodeToString(it)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,9 +74,8 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
override val currentStackSize get() = navController.currentStack?.size
|
override val currentStackSize get() = navController.currentStack?.size
|
||||||
|
|
||||||
override val currentViewTitle
|
override val currentViewTitle
|
||||||
get() = (navController.currentFrag as? MainView.TitledView)?.titleStringId?.let {
|
get() = (navController.currentFrag as? MainView.TitledView)?.titleStringId
|
||||||
getString(it)
|
?.let { getString(it) }
|
||||||
}
|
|
||||||
|
|
||||||
override val currentViewSubtitle get() = (navController.currentFrag as? MainView.TitledView)?.subtitleString
|
override val currentViewSubtitle get() = (navController.currentFrag as? MainView.TitledView)?.subtitleString
|
||||||
|
|
||||||
@ -86,7 +89,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
messageContainer = binding.mainMessageContainer
|
messageContainer = binding.mainMessageContainer
|
||||||
updateHelper.messageContainer = binding.mainFragmentContainer
|
updateHelper.messageContainer = binding.mainFragmentContainer
|
||||||
|
|
||||||
val destination = (intent.getSerializableExtra(EXTRA_START_DESTINATION) as Destination?)
|
val destination = intent.getStringExtra(EXTRA_START_DESTINATION)
|
||||||
?.takeIf { savedInstanceState == null }
|
?.takeIf { savedInstanceState == null }
|
||||||
|
|
||||||
presenter.onAttachView(this, destination)
|
presenter.onAttachView(this, destination)
|
||||||
@ -99,6 +102,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
}
|
}
|
||||||
|
|
||||||
//https://developer.android.com/guide/playcore/in-app-updates#status_callback
|
//https://developer.android.com/guide/playcore/in-app-updates#status_callback
|
||||||
|
@Deprecated("Deprecated in Java")
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
@ -129,7 +133,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
fragmentHideStrategy = HIDE
|
fragmentHideStrategy = HIDE
|
||||||
rootFragments = rootDestinations.map { it.fragment }
|
rootFragments = rootDestinations.map { it.destinationFragment }
|
||||||
|
|
||||||
initialize(startMenuIndex, savedInstanceState)
|
initialize(startMenuIndex, savedInstanceState)
|
||||||
}
|
}
|
||||||
@ -230,7 +234,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun openMoreDestination(destination: Destination) {
|
override fun openMoreDestination(destination: Destination) {
|
||||||
pushView(destination.fragment)
|
pushView(destination.destinationFragment)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun notifyMenuViewReselected() {
|
override fun notifyMenuViewReselected() {
|
||||||
@ -286,6 +290,50 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
inAppReviewHelper.showInAppReview(this)
|
inAppReviewHelper.showInAppReview(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showAppSupport() {
|
||||||
|
MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.main_support_title)
|
||||||
|
.setMessage(R.string.main_support_description)
|
||||||
|
.setPositiveButton(R.string.main_support_positive) { _, _ -> presenter.onEnableAdsSelected() }
|
||||||
|
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||||
|
.setOnDismissListener { }
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showPrivacyPolicyDialog() {
|
||||||
|
val dialogAdsConsentBinding = DialogAdsConsentBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
val dialog = MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.pref_ads_consent_title)
|
||||||
|
.setMessage(R.string.pref_ads_consent_description)
|
||||||
|
.setView(dialogAdsConsentBinding.root)
|
||||||
|
.show()
|
||||||
|
|
||||||
|
dialogAdsConsentBinding.adsConsentOver.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
dialogAdsConsentBinding.adsConsentPersonalised.isEnabled = isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogAdsConsentBinding.adsConsentPersonalised.setOnClickListener {
|
||||||
|
presenter.onPrivacyAgree(true)
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogAdsConsentBinding.adsConsentNonPersonalised.setOnClickListener {
|
||||||
|
presenter.onPrivacyAgree(false)
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogAdsConsentBinding.adsConsentPrivacy.setOnClickListener { presenter.onPrivacySelected() }
|
||||||
|
dialogAdsConsentBinding.adsConsentCancel.setOnClickListener { dialog.cancel() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openPrivacyPolicy() {
|
||||||
|
openInternetBrowser(
|
||||||
|
"https://wulkanowy.github.io/polityka-prywatnosci.html",
|
||||||
|
::showMessage
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
navController.onSaveInstanceState(outState)
|
navController.onSaveInstanceState(outState)
|
||||||
|
@ -18,7 +18,12 @@ import io.github.wulkanowy.ui.modules.grade.GradeView
|
|||||||
import io.github.wulkanowy.ui.modules.message.MessageView
|
import io.github.wulkanowy.ui.modules.message.MessageView
|
||||||
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersView
|
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersView
|
||||||
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
|
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
|
||||||
|
import io.github.wulkanowy.utils.AdsHelper
|
||||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||||
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@ -27,9 +32,12 @@ import javax.inject.Inject
|
|||||||
class MainPresenter @Inject constructor(
|
class MainPresenter @Inject constructor(
|
||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val prefRepository: PreferencesRepository,
|
private val preferencesRepository: PreferencesRepository,
|
||||||
private val syncManager: SyncManager,
|
private val syncManager: SyncManager,
|
||||||
private val analytics: AnalyticsHelper,
|
private val analytics: AnalyticsHelper,
|
||||||
|
private val json: Json,
|
||||||
|
private val adsHelper: AdsHelper,
|
||||||
|
private val appInfo: AppInfo
|
||||||
) : BasePresenter<MainView>(errorHandler, studentRepository) {
|
) : BasePresenter<MainView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
private var studentsWitSemesters: List<StudentWithSemesters>? = null
|
private var studentsWitSemesters: List<StudentWithSemesters>? = null
|
||||||
@ -44,19 +52,21 @@ class MainPresenter @Inject constructor(
|
|||||||
|
|
||||||
private val Destination?.startMenuIndex
|
private val Destination?.startMenuIndex
|
||||||
get() = when {
|
get() = when {
|
||||||
this == null -> prefRepository.startMenuIndex
|
this == null -> preferencesRepository.startMenuIndex
|
||||||
type in rootDestinationTypeList -> {
|
destinationType in rootDestinationTypeList -> {
|
||||||
rootDestinationTypeList.indexOf(type)
|
rootDestinationTypeList.indexOf(destinationType)
|
||||||
}
|
}
|
||||||
else -> 4
|
else -> 4
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onAttachView(view: MainView, initDestination: Destination?) {
|
fun onAttachView(view: MainView, initDestinationJson: String?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
|
|
||||||
|
val initDestination: Destination? = initDestinationJson?.let { json.decodeFromString(it) }
|
||||||
|
|
||||||
val startMenuIndex = initDestination.startMenuIndex
|
val startMenuIndex = initDestination.startMenuIndex
|
||||||
val destinations = rootDestinationTypeList.map {
|
val destinations = rootDestinationTypeList.map {
|
||||||
if (it == initDestination?.type) initDestination else it.defaultDestination
|
if (it == initDestination?.destinationType) initDestination else it.defaultDestination
|
||||||
}
|
}
|
||||||
|
|
||||||
view.initView(startMenuIndex, destinations)
|
view.initView(startMenuIndex, destinations)
|
||||||
@ -66,6 +76,8 @@ class MainPresenter @Inject constructor(
|
|||||||
|
|
||||||
syncManager.startPeriodicSyncWorker()
|
syncManager.startPeriodicSyncWorker()
|
||||||
|
|
||||||
|
checkAppSupport()
|
||||||
|
|
||||||
analytics.logEvent("app_open", "destination" to initDestination.toString())
|
analytics.logEvent("app_open", "destination" to initDestination.toString())
|
||||||
Timber.i("Main view was initialized with $initDestination")
|
Timber.i("Main view was initialized with $initDestination")
|
||||||
}
|
}
|
||||||
@ -150,18 +162,52 @@ class MainPresenter @Inject constructor(
|
|||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkInAppReview() {
|
fun onEnableAdsSelected() {
|
||||||
prefRepository.inAppReviewCount++
|
view?.showPrivacyPolicyDialog()
|
||||||
|
}
|
||||||
|
|
||||||
if (prefRepository.inAppReviewDate == null) {
|
fun onPrivacyAgree(isPersonalizedAds: Boolean) {
|
||||||
prefRepository.inAppReviewDate = Instant.now()
|
preferencesRepository.isAgreeToProcessData = true
|
||||||
|
preferencesRepository.isPersonalizedAdsEnabled = isPersonalizedAds
|
||||||
|
|
||||||
|
adsHelper.initialize()
|
||||||
|
|
||||||
|
preferencesRepository.isAdsEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onPrivacySelected() {
|
||||||
|
view?.openPrivacyPolicy()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkInAppReview() {
|
||||||
|
preferencesRepository.inAppReviewCount++
|
||||||
|
|
||||||
|
if (preferencesRepository.inAppReviewDate == null) {
|
||||||
|
preferencesRepository.inAppReviewDate = Instant.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prefRepository.isAppReviewDone && prefRepository.inAppReviewCount >= 50 &&
|
if (!preferencesRepository.isAppReviewDone && preferencesRepository.inAppReviewCount >= 50 &&
|
||||||
Instant.now().minus(Duration.ofDays(14)).isAfter(prefRepository.inAppReviewDate)
|
Instant.now().minus(Duration.ofDays(14)).isAfter(preferencesRepository.inAppReviewDate)
|
||||||
) {
|
) {
|
||||||
view?.showInAppReview()
|
view?.showInAppReview()
|
||||||
prefRepository.isAppReviewDone = true
|
preferencesRepository.isAppReviewDone = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkAppSupport() {
|
||||||
|
if (!preferencesRepository.isAppSupportShown && !preferencesRepository.isAdsEnabled
|
||||||
|
&& appInfo.buildFlavor == "play"
|
||||||
|
) {
|
||||||
|
presenterScope.launch {
|
||||||
|
val student = runCatching { studentRepository.getCurrentStudent(false) }
|
||||||
|
.onFailure { Timber.e(it) }
|
||||||
|
.getOrElse { return@launch }
|
||||||
|
|
||||||
|
if (Instant.now().minus(Duration.ofDays(28)).isAfter(student.registrationDate)) {
|
||||||
|
view?.showAppSupport()
|
||||||
|
preferencesRepository.isAppSupportShown = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,12 @@ interface MainView : BaseView {
|
|||||||
|
|
||||||
fun showInAppReview()
|
fun showInAppReview()
|
||||||
|
|
||||||
|
fun showAppSupport()
|
||||||
|
|
||||||
|
fun showPrivacyPolicyDialog()
|
||||||
|
|
||||||
|
fun openPrivacyPolicy()
|
||||||
|
|
||||||
fun openMoreDestination(destination: Destination)
|
fun openMoreDestination(destination: Destination)
|
||||||
|
|
||||||
interface MainChildView {
|
interface MainChildView {
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.message.mailboxchooser
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.recyclerview.widget.DiffUtil.ItemCallback
|
||||||
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
import io.github.wulkanowy.data.db.entities.MailboxType
|
||||||
|
import io.github.wulkanowy.databinding.ItemMailboxChooserBinding
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class MailboxChooserAdapter @Inject constructor() :
|
||||||
|
ListAdapter<MailboxChooserItem, MailboxChooserAdapter.ItemViewHolder>(Differ) {
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
|
||||||
|
ItemMailboxChooserBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context), parent, false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
|
||||||
|
holder.bind(getItem(position))
|
||||||
|
}
|
||||||
|
|
||||||
|
class ItemViewHolder(
|
||||||
|
private val binding: ItemMailboxChooserBinding,
|
||||||
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
|
fun bind(item: MailboxChooserItem) {
|
||||||
|
with(binding) {
|
||||||
|
mailboxItemName.text = item.mailbox?.getFirstLine()
|
||||||
|
?: root.resources.getString(R.string.message_chip_all_mailboxes)
|
||||||
|
mailboxItemSchool.text = item.mailbox?.getSecondLine()
|
||||||
|
mailboxItemSchool.isVisible = !item.isAll
|
||||||
|
|
||||||
|
root.setOnClickListener { item.onClickListener(item.mailbox) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Mailbox.getFirstLine() = buildString {
|
||||||
|
if (studentName.isNotBlank() && studentName != userName) {
|
||||||
|
append(studentName)
|
||||||
|
append(" - ")
|
||||||
|
}
|
||||||
|
append(userName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Mailbox.getSecondLine() = buildString {
|
||||||
|
append(schoolNameShort)
|
||||||
|
append(" - ")
|
||||||
|
append(getMailboxType(type))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMailboxType(type: MailboxType): String = when (type) {
|
||||||
|
MailboxType.STUDENT -> R.string.message_mailbox_type_student
|
||||||
|
MailboxType.PARENT -> R.string.message_mailbox_type_parent
|
||||||
|
MailboxType.GUARDIAN -> R.string.message_mailbox_type_guardian
|
||||||
|
MailboxType.EMPLOYEE -> R.string.message_mailbox_type_employee
|
||||||
|
MailboxType.UNKNOWN -> null
|
||||||
|
}.let { it?.let { it1 -> binding.root.resources.getString(it1) }.orEmpty() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private object Differ : ItemCallback<MailboxChooserItem>() {
|
||||||
|
override fun areItemsTheSame(
|
||||||
|
oldItem: MailboxChooserItem,
|
||||||
|
newItem: MailboxChooserItem
|
||||||
|
): Boolean {
|
||||||
|
return oldItem.mailbox?.globalKey == newItem.mailbox?.globalKey
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(
|
||||||
|
oldItem: MailboxChooserItem,
|
||||||
|
newItem: MailboxChooserItem
|
||||||
|
): Boolean {
|
||||||
|
return oldItem == newItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.message.mailboxchooser
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.fragment.app.setFragmentResult
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
import io.github.wulkanowy.databinding.DialogMailboxChooserBinding
|
||||||
|
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class MailboxChooserDialog : BaseDialogFragment<DialogMailboxChooserBinding>(), MailboxChooserView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: MailboxChooserPresenter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var mailboxAdapter: MailboxChooserAdapter
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val LISTENER_KEY = "mailbox_selected"
|
||||||
|
const val MAILBOX_KEY = "selected_mailbox"
|
||||||
|
const val REQUIRED_KEY = "is_mailbox_required"
|
||||||
|
|
||||||
|
fun newInstance(mailboxes: List<Mailbox>, isMailboxRequired: Boolean, folder: String) =
|
||||||
|
MailboxChooserDialog().apply {
|
||||||
|
arguments = bundleOf(
|
||||||
|
MAILBOX_KEY to mailboxes.toTypedArray(),
|
||||||
|
REQUIRED_KEY to isMailboxRequired,
|
||||||
|
LISTENER_KEY to folder,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setStyle(STYLE_NO_TITLE, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
) = DialogMailboxChooserBinding.inflate(inflater).apply { binding = this }.root
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
presenter.onAttachView(
|
||||||
|
view = this,
|
||||||
|
requireMailbox = requireArguments().getBoolean(REQUIRED_KEY, false),
|
||||||
|
mailboxes = requireArguments().getParcelableArray(MAILBOX_KEY).orEmpty()
|
||||||
|
.toList() as List<Mailbox>,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initView() {
|
||||||
|
binding.accountQuickDialogRecycler.adapter = mailboxAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun submitData(items: List<MailboxChooserItem>) {
|
||||||
|
mailboxAdapter.submitList(items)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMailboxSelected(item: Mailbox?) {
|
||||||
|
setFragmentResult(
|
||||||
|
requestKey = requireArguments().getString(LISTENER_KEY).orEmpty(),
|
||||||
|
result = bundleOf(MAILBOX_KEY to item),
|
||||||
|
)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user