1
0

Compare commits

...

60 Commits
1.4.0 ... 1.4.4

Author SHA1 Message Date
4e12eb1552 Merge branch 'release/1.4.4' 2021-12-19 22:25:52 +01:00
c846cc999f Version 1.4.4 2021-12-19 22:25:47 +01:00
47d430292c Update template of login issue email (#1724)
* Update sdk

* Update template of login issue email
2021-12-19 22:08:39 +01:00
5e1ff2243f Fix exception in TimetableAdapter (#1721) 2021-12-12 23:09:34 +01:00
a35bef58f2 Bump gradle from 7.0.3 to 7.0.4 (#1718) 2021-12-12 14:06:15 +00:00
0005d84974 Bump hilt_version from 2.40.4 to 2.40.5 (#1719) 2021-12-12 14:05:53 +00:00
19558cb871 Bump firebase-bom from 29.0.1 to 29.0.2 (#1720) 2021-12-12 14:05:35 +00:00
45e884127f After deselecting fakelog, clear credentials from login form (#1713) 2021-12-12 15:04:31 +01:00
c87085a226 Fix invalid order of school announcements (#1689) 2021-12-11 17:35:55 +01:00
79b970256f More strongly typed data in preferences (#1697) 2021-12-11 16:14:46 +00:00
70f038f15f Remove useless group property from NotificationType (#1714) 2021-12-11 17:12:47 +01:00
9cabd7ef08 Deduplicate timetable time left string (#1710) 2021-12-11 16:42:33 +01:00
d89e4ccfdf Fix grade sorting by date (#1717) 2021-12-11 11:54:07 +01:00
1bcc4d199e When replying to a message use Re instead of RE (#1712) 2021-12-10 16:24:39 +01:00
2e85e88c5d Bump agcp from 1.6.2.200 to 1.6.2.300 (#1693) 2021-12-08 10:21:00 +00:00
6ab67fe25b Bump firebase-bom from 29.0.0 to 29.0.1 (#1696) 2021-12-08 10:04:29 +00:00
8563277a89 Bump robolectric from 4.7.2 to 4.7.3 (#1695) 2021-12-08 10:04:10 +00:00
e458cc90b0 Bump agconnect-crash from 1.6.2.200 to 1.6.2.300 (#1694) 2021-12-08 10:03:42 +00:00
651e3a21b9 Bump firebase-crashlytics-gradle from 2.8.0 to 2.8.1 (#1692) 2021-12-08 10:03:06 +00:00
f6b969cfb1 Bump hilt_version from 2.40.2 to 2.40.4 (#1691) 2021-12-08 10:02:43 +00:00
d2aa940d46 Convert from a stringly typed grade color to enum GradeColorTheme (#1672) 2021-11-27 10:11:17 +01:00
ab435a72ea Merge branch 'release/1.4.3' into develop 2021-11-26 22:29:13 +01:00
a56f4b8745 Merge branch 'release/1.4.3' 2021-11-26 22:29:09 +01:00
d003b0897c Version 1.4.3 2021-11-26 22:29:03 +01:00
581bb2de77 New Crowdin updates (#1669) 2021-11-26 20:22:54 +01:00
495e385228 Fix snackbar crash in grade statistics view (#1682) 2021-11-25 23:48:08 +01:00
10ba36ba44 Bump hianalytics from 6.3.0.303 to 6.3.2.300 (#1684) 2021-11-25 22:46:30 +00:00
eae396424f Bump hilt_version from 2.40.1 to 2.40.2 (#1683) 2021-11-25 22:46:17 +00:00
a7891bb266 Update viewpager2 library to fix duplicated menu bug (#1681) 2021-11-24 09:53:16 +01:00
6e82409dbc Bump play-services-ads from 20.4.0 to 20.5.0 (#1675) 2021-11-23 02:02:03 +00:00
984db18be3 Bump agcp from 1.6.1.300 to 1.6.2.200 (#1674) 2021-11-23 01:55:49 +00:00
c99bc96c08 Bump logging-interceptor from 4.9.2 to 4.9.3 (#1676) 2021-11-23 01:55:10 +00:00
3e7030abc2 Bump agconnect-crash from 1.6.1.300 to 1.6.2.200 (#1677) 2021-11-23 01:54:47 +00:00
6dad3b299b Bump robolectric from 4.7 to 4.7.2 (#1678) 2021-11-23 01:54:26 +00:00
5e997f5a3e Merge branch 'release/1.4.2' into develop 2021-11-21 13:31:56 +01:00
601d573283 Merge branch 'release/1.4.2' 2021-11-21 13:31:51 +01:00
6ae6ca7fbb Version 1.4.2 2021-11-21 13:31:45 +01:00
c3d38afc3d New Crowdin updates (#1658) 2021-11-21 13:23:43 +01:00
4e19964249 Make admin messages dissmisable (#1661) 2021-11-21 09:02:12 +01:00
a6c0efcb81 Fix empty student list in LoginStudentSelect view (#1668) 2021-11-21 07:47:23 +00:00
fcc71c0d5f Add ads limit (#1662) 2021-11-21 08:34:28 +01:00
a59d10b6c1 Disable personalized ads in single support advert (#1665) 2021-11-20 16:46:14 +01:00
a48e4eb4ee Probably fix snackbar crash in grade statistics view (#1663) 2021-11-20 16:42:21 +01:00
2a3668bb18 Fix nul login data in login symbol view (#1664) 2021-11-20 16:41:12 +01:00
804d0d9113 Add multiline to support ad preference (#1651) 2021-11-18 20:23:09 +01:00
88b893e6c0 Fix upcoming lesson notifications on Android 12 (#1650) 2021-11-18 20:22:15 +01:00
2874a7495e Add Czech and Slovak README (#1631) 2021-11-18 19:38:51 +01:00
40d8f7a93d German readme version (#1629) 2021-11-18 16:31:59 +01:00
84cd51205f Bump appcompat from 1.4.0-rc01 to 1.4.0 (#1654) 2021-11-18 01:02:12 +00:00
bac1832f27 Bump mockk from 1.12.0 to 1.12.1 (#1653) 2021-11-18 00:40:59 +00:00
8bf1e22407 Bump flow-preferences from 1.5.0 to 1.6.0 (#1657) 2021-11-18 00:40:38 +00:00
e9f43f925c Bump constraintlayout from 2.1.1 to 2.1.2 (#1656) 2021-11-18 00:37:26 +00:00
aa632edf5c Bump fragment-ktx from 1.4.0-rc01 to 1.4.0 (#1655) 2021-11-18 00:36:18 +00:00
57315d75c6 Bump work_manager from 2.7.0 to 2.7.1 (#1652) 2021-11-18 00:36:00 +00:00
4552bc85b0 Bump kotlin_version from 1.5.31 to 1.6.0 (#1635) 2021-11-18 01:34:55 +01:00
6b7795118c Merge branch 'release/1.4.1' into develop 2021-11-16 23:29:22 +01:00
1960782d8e Merge branch 'release/1.4.1' 2021-11-16 23:29:17 +01:00
8836be3766 Version 1.4.1 2021-11-16 23:29:12 +01:00
8697993149 Add missing env for google play build (#1647) 2021-11-16 23:28:03 +01:00
b88c7eb4e4 Merge branch 'release/1.4.0' into develop 2021-11-16 22:49:58 +01:00
72 changed files with 3283 additions and 438 deletions

View File

@ -35,6 +35,9 @@ jobs:
PLAY_KEY_ALIAS: ${{ secrets.PLAY_KEY_ALIAS }}
PLAY_KEY_PASSWORD: ${{ secrets.PLAY_KEY_PASSWORD }}
ANDROID_PUBLISHER_CREDENTIALS: ${{ secrets.ANDROID_PUBLISHER_CREDENTIALS }}
ADMOB_PROJECT_ID: ${{ secrets.ADMOB_PROJECT_ID }}
SINGLE_SUPPORT_AD_ID: ${{ secrets.SINGLE_SUPPORT_AD_ID }}
SET_BUILD_TIMESTAMP: ${{ secrets.SET_BUILD_TIMESTAMP }}
run: ./gradlew publishPlayReleaseApps -PenableFirebase --stacktrace;
deploy-app-gallery:
@ -69,4 +72,5 @@ jobs:
PLAY_STORE_PASSWORD: ${{ secrets.PLAY_STORE_PASSWORD }}
PLAY_KEY_ALIAS: ${{ secrets.PLAY_KEY_ALIAS }}
PLAY_KEY_PASSWORD: ${{ secrets.PLAY_KEY_PASSWORD }}
SET_BUILD_TIMESTAMP: ${{ secrets.SET_BUILD_TIMESTAMP }}
run: ./gradlew bundleHmsRelease --stacktrace && ./gradlew publishHuaweiAppGalleryHmsRelease --stacktrace

78
README.cs.md Normal file
View File

@ -0,0 +1,78 @@
[English version of README](README.en.md)
[Deutsche Version von README](README.de.md)
[Polska wersja README](README.md)
[Slovenská verzia README](README.sk.md)
# Wulkanowy
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
[![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy)
[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr)
[![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/)
[![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases)
Neoficiální klient deníku VULCAN UONET+ pro žáka a rodiče
## Funkce
* přihlášení pomocí emailu a hesla
* funkce z webové stránky deníku:
* známky
* statistiky známek
* frekvence
* procento frekvence
* zkoušky
* plán lekce
* dokončené lekce
* zprávy
* domácí úkoly
* poznámky
* šťastné číslo
* další lekce
* školní setkání
* informace o žáku a škole
* výpočet průměru nezávisle na preferencích školy
* upozornění, např. o nových známkách
* podpora více účtů s možností přejmenování žáků
* tmavý a černý (AMOLED) motiv
* offline režim
* žádné reklamy
## Stáhnout
Aktuální verzi si můžete stáhnout z Google Play, F-Droid nebo Huawei AppGallery
[<img src="https://play.google.com/intl/cs-CZ/badges/images/generic/cs_badge_web_generic.png"
alt="Nyní na Google Play"
height="80">](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Stáhnout s F-Droid"
height="80">](https://f-droid.org/packages/io.github.wulkanowy/)
[<img src="https://i.imgur.com/baTGiDP.png"
alt="Objevuj v AppGallery"
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
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
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
* [Kotlin Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html)
* [Hilt](https://dagger.dev/hilt/)
* [Room](https://developer.android.com/topic/libraries/architecture/room)
* [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager)
## Spolupráce
Přispějte do projektu vytvořením PR nebo odesláním issue na GitHub.
Pro zájemce o překlad aplikace do různých jazyků poskytujeme Crowdin:
https://crowdin.com/project/wulkanowy2
## Licence
Tento projekt je licencován pod licencí Apache License 2.0 - podrobnosti v souboru [LICENSE](LICENSE)

74
README.de.md Normal file
View File

@ -0,0 +1,74 @@
[Polska wersja README](README.md)
[English version of README](README.en.md)
# Wulkanowy
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
[![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy)
[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr)
[![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/)
[![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases)
Inoffizieller Android VULCAN UONET+ Registrierungsclient für Schüler und ihre Eltern
## Merkmale
* Einloggen mit E-Mail und Passwort
* Funktionen von der Registerwebsite:
* Noten
* Notenstatistik
* Anwesenheit
* Prozentsatz der Anwesenheit
* Prüfungen
* Stundenplan
* Unterricht abgeschlossen
* Nachrichten
* Hausaufgaben
* Anmerkungen
* Glückszahl
* Zusätzliche Lektionen
* Schulkonferenzen
* Schüler- und Schulinformationen
* Berechnung des Durchschnitts unabhängig von den Präferenzen der Schule
* Benachrichtigungen, z. B. über eine neue Note
* Unterstützung für mehrere Konten mit der Möglichkeit, den Namen des Schülers zu ändern
* dunkles und schwarzes (AMOLED) Thema
* Offline-Modus
* keine Werbung
## Herunterladen
Die aktuelle Version können Sie von der Google Play, F-Droid oder Huawei AppGallery store herunterladen
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
alt="Get it on Google Play"
height="80">](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/io.github.wulkanowy/)
[<img src="appgallery_badge.png"
alt="Explore it on AppGallery"
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
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
## Gebaut mit
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
* [Kotlin Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html)
* [Hilt](https://dagger.dev/hilt/)
* [Room](https://developer.android.com/topic/libraries/architecture/room)
* [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager)
## Beitragen
Bitte tragen Sie zum Projekt bei, indem Sie entweder eine PR erstellen oder ein Issue auf GitHub einreichen.
Für Personen, die daran interessiert sind, die Anwendung in verschiedene Sprachen zu übersetzen, bieten wir Crowdin
https://crowdin.com/project/wulkanowy2
## Lizenz
Dieses Projekt ist unter der Apache License 2.0 lizenziert - siehe die [LIZENZ](LICENSE) Datei für Details

View File

@ -1,5 +1,11 @@
[Polska wersja README](README.md)
[Deutsche Version von README](README.de.md)
[Česká verze README](README.cs.md)
[Slovenská verzia README](README.sk.md)
# Wulkanowy
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)

View File

@ -1,5 +1,11 @@
[English version of README](README.en.md)
[Deutsche Version von README](README.de.md)
[Česká verze README](README.cs.md)
[Slovenská verzia README](README.sk.md)
# Wulkanowy
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)

78
README.sk.md Normal file
View File

@ -0,0 +1,78 @@
[English version of README](README.en.md)
[Deutsche Version von README](README.de.md)
[Polska wersja README](README.md)
[Česká verze README](README.cs.md)
# Wulkanowy
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
[![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy)
[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr)
[![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/)
[![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases)
Neoficiálny klient denníka VULCAN UONET+ pre žiaka a rodičov
## Funkcie
* prihlásenie pomocou emailu a hesla
* funkcie z webovej stránky denníka:
* známky
* štatistiky známok
* frekvencia
* percento frekvencie
* skúšky
* plán lekcie
* dokončené lekcie
* správy
* domáce úlohy
* poznámky
* šťastné číslo
* ďalšie lekcie
* školské stretnutie
* informácie o žiakovi a škole
* výpočet priemeru nezávisle od preferencií školy
* upozornenia, napr. o nových známkach
* podpora viacerých účtov s možnosťou premenovania žiakov
* tmavý a čierny (AMOLED) motív
* offline režim
* žiadne reklamy
## Stiahnuť
Aktuálnu verziu si môžete stiahnuť z Google Play, F-Droid alebo Huawei AppGallery
[<img src="https://play.google.com/intl/sk/badges/images/generic/sk_badge_web_generic.png"
alt="Nyní na Google Play"
height="80">](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Stiahnuť s F-Droid"
height="80">](https://f-droid.org/packages/io.github.wulkanowy/)
[<img src="https://i.imgur.com/sX8UyAw.png"
alt="Objavíte v AppGallery"
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
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
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
* [Kotlin Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html)
* [Hilt](https://dagger.dev/hilt/)
* [Room](https://developer.android.com/topic/libraries/architecture/room)
* [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager)
## Spolupráca
Prispejte do projektu vytvorením PR alebo odoslaním issue na GitHub.
Pre záujemcov o preklad aplikácie do rôznych jazykov poskytujeme Crowdin:
https://crowdin.com/project/wulkanowy2
## Licencia
Tento projekt je licencovaný pod licenciou Apache License 2.0 - podrobnosti v súbore [LICENSE](LICENSE)

View File

@ -22,8 +22,8 @@ android {
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 21
targetSdkVersion 31
versionCode 98
versionName "1.4.0"
versionCode 102
versionName "1.4.4"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "app_name", "Wulkanowy"
@ -150,7 +150,7 @@ kapt {
play {
defaultToAppBundles = false
track = 'beta'
updatePriority = 1
updatePriority = 4
enabled.set(false)
}
@ -165,16 +165,16 @@ huaweiPublish {
}
ext {
work_manager = "2.7.0"
work_manager = "2.7.1"
android_hilt = "1.0.0"
room = "2.3.0"
chucker = "3.5.2"
mockk = "1.12.0"
mockk = "1.12.1"
coroutines = "1.5.2"
}
dependencies {
implementation "io.github.wulkanowy:sdk:1.4.0"
implementation "io.github.wulkanowy:sdk:1.4.4"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
@ -184,15 +184,15 @@ dependencies {
implementation "androidx.core:core-ktx:1.7.0"
implementation 'androidx.core:core-splashscreen:1.0.0-alpha02'
implementation "androidx.activity:activity-ktx:1.4.0"
implementation "androidx.appcompat:appcompat:1.4.0-rc01"
implementation "androidx.fragment:fragment-ktx:1.4.0-rc01"
implementation "androidx.appcompat:appcompat:1.4.0"
implementation "androidx.fragment:fragment-ktx:1.4.0"
implementation "androidx.annotation:annotation:1.3.0"
implementation "androidx.preference:preference-ktx:1.1.1"
implementation "androidx.recyclerview:recyclerview:1.2.1"
implementation "androidx.viewpager:viewpager:1.0.0"
implementation "androidx.viewpager2:viewpager2:1.1.0-beta01"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "androidx.constraintlayout:constraintlayout:2.1.1"
implementation "androidx.constraintlayout:constraintlayout:2.1.2"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
implementation "com.google.android.material:material:1.4.0"
implementation "com.github.wulkanowy:material-chips-input:2.3.1"
@ -218,7 +218,7 @@ dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0"
implementation "com.squareup.okhttp3:logging-interceptor:4.9.2"
implementation "com.squareup.okhttp3:logging-interceptor:4.9.3"
implementation "com.jakewharton.timber:timber:5.0.1"
implementation "at.favre.lib:slf4j-timber:1.0.1"
@ -227,18 +227,18 @@ dependencies {
implementation "io.coil-kt:coil:1.4.0"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
implementation 'com.fredporciuncula:flow-preferences:1.5.0'
implementation 'com.fredporciuncula:flow-preferences:1.6.0'
playImplementation platform('com.google.firebase:firebase-bom:29.0.0')
playImplementation platform('com.google.firebase:firebase-bom:29.0.2')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
playImplementation 'com.google.android.play:core:1.10.2'
playImplementation 'com.google.android.play:core-ktx:1.8.1'
playImplementation 'com.google.android.gms:play-services-ads:20.4.0'
playImplementation 'com.google.android.gms:play-services-ads:20.5.0'
hmsImplementation 'com.huawei.hms:hianalytics:6.3.0.303'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.1.300'
hmsImplementation 'com.huawei.hms:hianalytics:6.3.2.300'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.2.300'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
@ -250,7 +250,7 @@ dependencies {
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines"
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
testImplementation 'org.robolectric:robolectric:4.7'
testImplementation 'org.robolectric:robolectric:4.7.3'
testImplementation "androidx.test:runner:1.4.0"
testImplementation "androidx.test.ext:junit:1.1.3"
testImplementation "androidx.test:core:1.4.0"

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@ import io.github.wulkanowy.ui.modules.main.MainActivity
import javax.inject.Singleton
import javax.inject.Inject
@Suppress("UNUSED_PARAMETER", "unused")
@Singleton
class InAppReviewHelper @Inject constructor(
@ApplicationContext private val context: Context

View File

@ -9,6 +9,7 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<queries>
<intent>

View File

@ -103,6 +103,7 @@ import io.github.wulkanowy.data.db.migrations.Migration40
import io.github.wulkanowy.data.db.migrations.Migration41
import io.github.wulkanowy.data.db.migrations.Migration42
import io.github.wulkanowy.data.db.migrations.Migration43
import io.github.wulkanowy.data.db.migrations.Migration44
import io.github.wulkanowy.data.db.migrations.Migration5
import io.github.wulkanowy.data.db.migrations.Migration6
import io.github.wulkanowy.data.db.migrations.Migration7
@ -152,7 +153,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() {
companion object {
const val VERSION_SCHEMA = 43
const val VERSION_SCHEMA = 44
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
Migration2(),
@ -196,7 +197,8 @@ abstract class AppDatabase : RoomDatabase() {
Migration40(),
Migration41(sharedPrefProvider),
Migration42(),
Migration43()
Migration43(),
Migration44()
)
fun newInstance(

View File

@ -10,6 +10,6 @@ import javax.inject.Singleton
@Singleton
interface SchoolAnnouncementDao : BaseDao<SchoolAnnouncement> {
@Query("SELECT * FROM SchoolAnnouncements WHERE student_id = :studentId")
@Query("SELECT * FROM SchoolAnnouncements WHERE student_id = :studentId ORDER BY date DESC")
fun loadAll(studentId: Int): Flow<List<SchoolAnnouncement>>
}

View File

@ -33,5 +33,8 @@ data class AdminMessage(
val priority: String,
val type: String
val type: String,
@ColumnInfo(name = "is_dismissible")
val isDismissible: Boolean = false
)

View File

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.ui.modules.grade.GradeExpandMode
import io.github.wulkanowy.data.enums.GradeExpandMode
class Migration41(private val sharedPrefProvider: SharedPrefProvider) : Migration(40, 41) {

View File

@ -0,0 +1,11 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration44 : Migration(43, 44) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE AdminMessages ADD COLUMN is_dismissible INTEGER NOT NULL DEFAULT 0")
}
}

View File

@ -0,0 +1,12 @@
package io.github.wulkanowy.data.enums
enum class AppTheme(val value: String) {
SYSTEM("system"),
LIGHT("light"),
DARK("dark"),
BLACK("black");
companion object {
fun getByValue(value: String) = values().find { it.value == value } ?: LIGHT
}
}

View File

@ -0,0 +1,13 @@
package io.github.wulkanowy.data.enums
import java.io.Serializable
enum class GradeColorTheme(val value: String) : Serializable {
VULCAN("vulcan"),
MATERIAL("material"),
GRADE_COLOR("grade_color");
companion object {
fun getByValue(value: String) = values().find { it.value == value } ?: VULCAN
}
}

View File

@ -0,0 +1,11 @@
package io.github.wulkanowy.data.enums
enum class GradeExpandMode(val value: String) {
ONE("one"),
UNLIMITED("any"),
ALWAYS_EXPANDED("always");
companion object {
fun getByValue(value: String) = values().find { it.value == value } ?: ONE
}
}

View File

@ -0,0 +1,10 @@
package io.github.wulkanowy.data.enums
enum class GradeSortingMode(val value: String) {
ALPHABETIC("alphabetic"),
DATE("date");
companion object {
fun getByValue(value: String) = values().find { it.value == value } ?: ALPHABETIC
}
}

View File

@ -0,0 +1,11 @@
package io.github.wulkanowy.data.enums
enum class TimetableMode(val value: String) {
WHOLE_PLAN("yes"),
ONLY_CURRENT_GROUP("no"),
SMALL_OTHER_GROUP("small");
companion object {
fun getByValue(value: String) = values().find { it.value == value } ?: ONLY_CURRENT_GROUP
}
}

View File

@ -7,11 +7,14 @@ import com.fredporciuncula.flow.preferences.FlowSharedPreferences
import com.fredporciuncula.flow.preferences.Preference
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.R
import io.github.wulkanowy.data.enums.AppTheme
import io.github.wulkanowy.data.enums.GradeColorTheme
import io.github.wulkanowy.data.enums.GradeExpandMode
import io.github.wulkanowy.data.enums.GradeSortingMode
import io.github.wulkanowy.data.enums.TimetableMode
import io.github.wulkanowy.sdk.toLocalDate
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
import io.github.wulkanowy.ui.modules.grade.GradeExpandMode
import io.github.wulkanowy.ui.modules.grade.GradeSortingMode
import io.github.wulkanowy.utils.toLocalDateTime
import io.github.wulkanowy.utils.toTimestamp
import kotlinx.coroutines.ExperimentalCoroutinesApi
@ -20,8 +23,6 @@ import kotlinx.coroutines.flow.map
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.lang.ClassCastException
import java.lang.IllegalStateException
import java.time.LocalDate
import java.time.LocalDateTime
import javax.inject.Inject
@ -74,13 +75,15 @@ class PreferencesRepository @Inject constructor(
)
val appThemeKey = context.getString(R.string.pref_key_app_theme)
val appTheme: String
get() = getString(appThemeKey, R.string.pref_default_app_theme)
val appTheme: AppTheme
get() = AppTheme.getByValue(getString(appThemeKey, R.string.pref_default_app_theme))
val gradeColorTheme: String
get() = getString(
R.string.pref_key_grade_color_scheme,
R.string.pref_default_grade_color_scheme
val gradeColorTheme: GradeColorTheme
get() = GradeColorTheme.getByValue(
getString(
R.string.pref_key_grade_color_scheme,
R.string.pref_default_grade_color_scheme
)
)
val appLanguageKey = context.getString(R.string.pref_key_app_language)
@ -105,7 +108,10 @@ class PreferencesRepository @Inject constructor(
val isUpcomingLessonsNotificationsEnableKey =
context.getString(R.string.pref_key_notifications_upcoming_lessons_enable)
val isUpcomingLessonsNotificationsEnable: Boolean
var isUpcomingLessonsNotificationsEnable: Boolean
set(value) {
sharedPref.edit { putBoolean(isUpcomingLessonsNotificationsEnableKey, value) }
}
get() = getBoolean(
isUpcomingLessonsNotificationsEnableKey,
R.bool.pref_default_notification_upcoming_lessons_enable
@ -155,10 +161,12 @@ class PreferencesRepository @Inject constructor(
R.bool.pref_default_timetable_show_groups
)
val showWholeClassPlan: String
get() = getString(
R.string.pref_key_timetable_show_whole_class,
R.string.pref_default_timetable_show_whole_class
val showWholeClassPlan: TimetableMode
get() = TimetableMode.getByValue(
getString(
R.string.pref_key_timetable_show_whole_class,
R.string.pref_default_timetable_show_whole_class
)
)
val gradeSortingMode: GradeSortingMode
@ -244,6 +252,14 @@ class PreferencesRepository @Inject constructor(
return flowSharedPref.getStringSet(prefKey, defaultSet)
}
var dismissedAdminMessageIds: List<Int>
get() = sharedPref.getStringSet(PREF_KEY_ADMIN_DISMISSED_MESSAGE_IDS, emptySet())
.orEmpty()
.map { it.toInt() }
set(value) = sharedPref.edit {
putStringSet(PREF_KEY_ADMIN_DISMISSED_MESSAGE_IDS, value.map { it.toString() }.toSet())
}
var inAppReviewCount: Int
get() = sharedPref.getInt(PREF_KEY_IN_APP_REVIEW_COUNT, 0)
set(value) = sharedPref.edit().putInt(PREF_KEY_IN_APP_REVIEW_COUNT, value).apply()
@ -285,5 +301,7 @@ class PreferencesRepository @Inject constructor(
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_ADMIN_DISMISSED_MESSAGE_IDS = "admin_message_dismissed_ids"
}
}

View File

@ -5,6 +5,7 @@ import android.app.AlarmManager.RTC_WAKEUP
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.app.AlarmManagerCompat
import androidx.core.app.NotificationManagerCompat
import dagger.hilt.android.qualifiers.ApplicationContext
@ -91,6 +92,12 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
return cancelScheduled(lessons, student)
}
if (!canScheduleExactAlarms()) {
Timber.w("Exact alarms are disabled by user")
preferencesRepository.isUpcomingLessonsNotificationsEnable = false
return
}
if (lessons.firstOrNull()?.date?.isAfter(LocalDate.now().plusDays(2)) == true) {
Timber.d("Timetable notification scheduling skipped - lessons are too far")
return
@ -169,8 +176,18 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
intent.getStringExtra(LESSON_TITLE)
}, start: $time, student: $studentId"
)
} catch (e: IllegalStateException) {
} catch (e: Throwable) {
Timber.e(e)
}
}
fun canScheduleExactAlarms(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
try {
alarmManager.canScheduleExactAlarms()
} catch (e: Throwable) {
false
}
} else true
}
}

View File

@ -74,7 +74,7 @@ class AppNotificationManager @Inject constructor(
student: Student
) {
val notificationType = groupNotificationData.type
val groupType = notificationType.group ?: return
val groupType = notificationType.channel
val group = "${groupType}_${student.id}"
sendSummaryNotification(groupNotificationData, group, student)

View File

@ -14,72 +14,58 @@ import io.github.wulkanowy.services.sync.channels.PushChannel
import io.github.wulkanowy.services.sync.channels.TimetableChangeChannel
enum class NotificationType(
val group: String?,
val channel: String,
val icon: Int
) {
NEW_CONFERENCE(
group = "new_conferences_group",
channel = NewConferencesChannel.CHANNEL_ID,
icon = R.drawable.ic_more_conferences,
),
NEW_EXAM(
group = "new_exam_group",
channel = NewExamChannel.CHANNEL_ID,
icon = R.drawable.ic_main_exam
),
NEW_GRADE_DETAILS(
group = "new_grade_details_group",
channel = NewGradesChannel.CHANNEL_ID,
icon = R.drawable.ic_stat_grade,
),
NEW_GRADE_PREDICTED(
group = "new_grade_predicted_group",
channel = NewGradesChannel.CHANNEL_ID,
icon = R.drawable.ic_stat_grade,
),
NEW_GRADE_FINAL(
group = "new_grade_final_group",
channel = NewGradesChannel.CHANNEL_ID,
icon = R.drawable.ic_stat_grade,
),
NEW_HOMEWORK(
group = "new_homework_group",
channel = NewHomeworkChannel.CHANNEL_ID,
icon = R.drawable.ic_more_homework,
),
NEW_LUCKY_NUMBER(
group = null,
channel = LuckyNumberChannel.CHANNEL_ID,
icon = R.drawable.ic_stat_luckynumber,
),
NEW_MESSAGE(
group = "new_message_group",
channel = NewMessagesChannel.CHANNEL_ID,
icon = R.drawable.ic_stat_message,
),
NEW_NOTE(
group = "new_notes_group",
channel = NewNotesChannel.CHANNEL_ID,
icon = R.drawable.ic_stat_note
),
NEW_ANNOUNCEMENT(
group = "new_school_announcements_group",
channel = NewSchoolAnnouncementsChannel.CHANNEL_ID,
icon = R.drawable.ic_all_about
),
CHANGE_TIMETABLE(
group = "change_timetable_group",
channel = TimetableChangeChannel.CHANNEL_ID,
icon = R.drawable.ic_main_timetable
),
NEW_ATTENDANCE(
group = "new_attendance_group",
channel = NewAttendanceChannel.CHANNEL_ID,
icon = R.drawable.ic_main_attendance
),
PUSH(
group = null,
channel = PushChannel.CHANNEL_ID,
icon = R.drawable.ic_stat_all
)

View File

@ -7,6 +7,7 @@ import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
import io.github.wulkanowy.R
import io.github.wulkanowy.data.enums.AppTheme
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.ui.modules.main.MainActivity
@ -20,7 +21,7 @@ class ThemeManager @Inject constructor(private val preferencesRepository: Prefer
fun applyActivityTheme(activity: AppCompatActivity) {
if (isThemeApplicable(activity)) {
applyDefaultTheme()
if (preferencesRepository.appTheme == "black") {
if (preferencesRepository.appTheme == AppTheme.BLACK) {
when (activity) {
is MainActivity -> activity.setTheme(R.style.WulkanowyTheme_Black)
is LoginActivity -> activity.setTheme(R.style.WulkanowyTheme_Login_Black)
@ -32,11 +33,10 @@ class ThemeManager @Inject constructor(private val preferencesRepository: Prefer
fun applyDefaultTheme() {
AppCompatDelegate.setDefaultNightMode(
when (val theme = preferencesRepository.appTheme) {
"light" -> MODE_NIGHT_NO
"dark", "black" -> MODE_NIGHT_YES
"system" -> MODE_NIGHT_FOLLOW_SYSTEM
else -> throw IllegalArgumentException("Wrong theme: $theme")
when (preferencesRepository.appTheme) {
AppTheme.LIGHT -> MODE_NIGHT_NO
AppTheme.DARK, AppTheme.BLACK -> MODE_NIGHT_YES
AppTheme.SYSTEM -> MODE_NIGHT_FOLLOW_SYSTEM
}
)
}

View File

@ -16,9 +16,11 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.AdminMessage
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.db.entities.TimetableHeader
import io.github.wulkanowy.data.enums.GradeColorTheme
import io.github.wulkanowy.databinding.ItemDashboardAccountBinding
import io.github.wulkanowy.databinding.ItemDashboardAdminMessageBinding
import io.github.wulkanowy.databinding.ItemDashboardAnnouncementsBinding
@ -68,6 +70,8 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
var onAdminMessageClickListener: (String?) -> Unit = {}
var onAdminMessageDismissClickListener: (AdminMessage) -> Unit = {}
val items = mutableListOf<DashboardItem>()
fun submitList(newItems: List<DashboardItem>) {
@ -259,7 +263,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
val isLoading = item.isLoading
val dashboardGradesAdapter = gradesViewHolder.adapter.apply {
this.items = subjectWithGrades.toList()
this.gradeTheme = gradeTheme.orEmpty()
this.gradeColorTheme = gradeTheme ?: GradeColorTheme.VULCAN
}
with(gradesViewHolder.binding) {
@ -418,10 +422,12 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
isFirstTimeRangeVisible = true
isFirstTimeVisible = false
} else {
firstTimeText = context.resources.getQuantityString(
R.plurals.dashboard_timetable_first_lesson_time_in_minutes,
minutesToStartLesson.toInt(),
minutesToStartLesson
firstTimeText = context.getString(
R.string.timetable_time_until,
context.getString(
R.string.timetable_minutes,
minutesToStartLesson.toString()
)
)
firstTimeRangeText = ""
@ -457,10 +463,12 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
0
}
firstTimeText = context.resources.getQuantityString(
R.plurals.dashboard_timetable_first_lesson_time_more_minutes,
minutesToEndLesson.toInt(),
minutesToEndLesson
firstTimeText = context.getString(
R.string.timetable_time_left,
context.getString(
R.string.timetable_minutes,
minutesToEndLesson.toString()
)
)
firstTimeRangeText = ""
@ -727,6 +735,10 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
dashboardAdminMessageItemDescription.text = item.content
dashboardAdminMessageItemDescription.setTextColor(textColor)
dashboardAdminMessageItemIcon.setColorFilter(textColor)
dashboardAdminMessageItemDismiss.isVisible = item.isDismissible
dashboardAdminMessageItemDismiss.setOnClickListener {
onAdminMessageDismissClickListener(item)
}
root.setCardBackgroundColor(backgroundColor?.let { ColorStateList.valueOf(it) })
item.destinationUrl?.let { url ->

View File

@ -100,6 +100,7 @@ class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragme
mainActivity.pushView(ConferenceFragment.newInstance())
}
onAdminMessageClickListener = presenter::onAdminMessageSelected
onAdminMessageDismissClickListener = presenter::onAdminMessageDismissed
registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {

View File

@ -4,6 +4,7 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.enums.GradeColorTheme
import io.github.wulkanowy.databinding.SubitemDashboardGradesBinding
import io.github.wulkanowy.databinding.SubitemDashboardSmallGradeBinding
import io.github.wulkanowy.utils.getBackgroundColor
@ -12,7 +13,7 @@ class DashboardGradesAdapter : RecyclerView.Adapter<DashboardGradesAdapter.ViewH
var items = listOf<Pair<String, List<Grade>>>()
var gradeTheme = ""
lateinit var gradeColorTheme: GradeColorTheme
override fun getItemCount() = items.size
@ -36,7 +37,7 @@ class DashboardGradesAdapter : RecyclerView.Adapter<DashboardGradesAdapter.ViewH
with(subitemBinding.dashboardSmallGradeSubitemValue) {
text = it.entry
setBackgroundResource(it.getBackgroundColor(gradeTheme))
setBackgroundResource(it.getBackgroundColor(gradeColorTheme))
}
dashboardGradesSubitemGradeContainer.addView(subitemBinding.root)

View File

@ -6,6 +6,7 @@ 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.pojos.TimetableFull
import io.github.wulkanowy.data.db.entities.Homework as EntitiesHomework
@ -52,7 +53,7 @@ sealed class DashboardItem(val type: Type) {
data class Grades(
val subjectWithGrades: Map<String, List<Grade>>? = null,
val gradeTheme: String? = null,
val gradeTheme: GradeColorTheme? = null,
override val error: Throwable? = null,
override val isLoading: Boolean = false
) : DashboardItem(Type.GRADES) {

View File

@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.dashboard
import io.github.wulkanowy.data.Resource
import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.db.entities.AdminMessage
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.enums.MessageFolder
@ -81,6 +82,12 @@ class DashboardPresenter @Inject constructor(
.launch("dashboard_pref")
}
fun onAdminMessageDismissed(adminMessage: AdminMessage) {
preferencesRepository.dismissedAdminMessageIds += adminMessage.id
loadData(preferencesRepository.selectedDashboardTiles)
}
fun onDragAndDropEnd(list: List<DashboardItem>) {
with(dashboardItemLoadedList) {
clear()
@ -117,6 +124,7 @@ class DashboardPresenter @Inject constructor(
forceRefresh: Boolean
) = dashboardTilesToLoad.filter { newItemToLoad ->
dashboardLoadedTiles.none { it == newItemToLoad } || forceRefresh
|| newItemToLoad == DashboardItem.Tile.ADMIN_MESSAGE
}
private fun removeUnselectedTiles(tilesToLoad: List<DashboardItem.Tile>) {
@ -575,6 +583,10 @@ class DashboardPresenter @Inject constructor(
private fun loadAdminMessage(student: Student, forceRefresh: Boolean) {
flowWithResourceIn { adminMessageRepository.getAdminMessages(student, forceRefresh) }
.map {
val isDismissed = it.data?.id in preferencesRepository.dismissedAdminMessageIds
it.copy(data = it.data.takeUnless { isDismissed })
}
.onEach {
when (it.status) {
Status.LOADING -> {
@ -617,11 +629,16 @@ class DashboardPresenter @Inject constructor(
sortDashboardItems()
if (dashboardItem is DashboardItem.AdminMessages && !dashboardItem.isDataLoaded) {
dashboardItemsToLoad = dashboardItemsToLoad - DashboardItem.Type.ADMIN_MESSAGE
dashboardTileLoadedList = dashboardTileLoadedList - DashboardItem.Tile.ADMIN_MESSAGE
if (dashboardItem is DashboardItem.AdminMessages) {
if (!dashboardItem.isDataLoaded) {
dashboardItemsToLoad = dashboardItemsToLoad - DashboardItem.Type.ADMIN_MESSAGE
dashboardTileLoadedList = dashboardTileLoadedList - DashboardItem.Tile.ADMIN_MESSAGE
dashboardItemLoadedList.removeAll { it.type == DashboardItem.Type.ADMIN_MESSAGE }
dashboardItemLoadedList.removeAll { it.type == DashboardItem.Type.ADMIN_MESSAGE }
} else {
dashboardItemsToLoad = dashboardItemsToLoad + DashboardItem.Type.ADMIN_MESSAGE
dashboardTileLoadedList = dashboardTileLoadedList + DashboardItem.Tile.ADMIN_MESSAGE
}
}
if (forceRefresh) {

View File

@ -1,9 +0,0 @@
package io.github.wulkanowy.ui.modules.grade
enum class GradeExpandMode(val value: String) {
ONE("one"), UNLIMITED("any"), ALWAYS_EXPANDED("always");
companion object {
fun getByValue(value: String) = values().firstOrNull { it.value == value } ?: ONE
}
}

View File

@ -1,10 +0,0 @@
package io.github.wulkanowy.ui.modules.grade
enum class GradeSortingMode(val value: String) {
ALPHABETIC("alphabetic"),
DATE("date");
companion object {
fun getByValue(value: String) = values().firstOrNull { it.value == value } ?: ALPHABETIC
}
}

View File

@ -11,10 +11,11 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.NO_POSITION
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.enums.GradeColorTheme
import io.github.wulkanowy.data.enums.GradeExpandMode
import io.github.wulkanowy.databinding.HeaderGradeDetailsBinding
import io.github.wulkanowy.databinding.ItemGradeDetailsBinding
import io.github.wulkanowy.ui.base.BaseExpandableAdapter
import io.github.wulkanowy.ui.modules.grade.GradeExpandMode
import io.github.wulkanowy.utils.getBackgroundColor
import io.github.wulkanowy.utils.toFormattedString
import timber.log.Timber
@ -33,7 +34,7 @@ class GradeDetailsAdapter @Inject constructor() : BaseExpandableAdapter<Recycler
var onClickListener: (Grade, position: Int) -> Unit = { _, _ -> }
var colorTheme = ""
lateinit var gradeColorTheme: GradeColorTheme
fun setDataItems(data: List<GradeDetailsItem>, expandMode: GradeExpandMode = this.expandMode) {
headers = data.filter { it.viewType == ViewType.HEADER }.toMutableList()
@ -202,7 +203,7 @@ class GradeDetailsAdapter @Inject constructor() : BaseExpandableAdapter<Recycler
with(holder.binding) {
gradeItemValue.run {
text = grade.entry
setBackgroundResource(grade.getBackgroundColor(colorTheme))
setBackgroundResource(grade.getBackgroundColor(gradeColorTheme))
}
gradeItemDescription.text = when {
grade.description.isNotBlank() -> grade.description

View File

@ -8,6 +8,7 @@ import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.enums.GradeColorTheme
import io.github.wulkanowy.databinding.DialogGradeBinding
import io.github.wulkanowy.utils.colorStringId
import io.github.wulkanowy.utils.getBackgroundColor
@ -21,19 +22,19 @@ class GradeDetailsDialog : DialogFragment() {
private lateinit var grade: Grade
private lateinit var colorScheme: String
private lateinit var gradeColorTheme: GradeColorTheme
companion object {
private const val ARGUMENT_KEY = "Item"
private const val COLOR_SCHEME_KEY = "Scheme"
private const val COLOR_THEME_KEY = "Theme"
fun newInstance(grade: Grade, colorScheme: String) =
fun newInstance(grade: Grade, colorTheme: GradeColorTheme) =
GradeDetailsDialog().apply {
arguments = Bundle().apply {
putSerializable(ARGUMENT_KEY, grade)
putString(COLOR_SCHEME_KEY, colorScheme)
putSerializable(COLOR_THEME_KEY, colorTheme)
}
}
}
@ -43,7 +44,7 @@ class GradeDetailsDialog : DialogFragment() {
setStyle(STYLE_NO_TITLE, 0)
arguments?.run {
grade = getSerializable(ARGUMENT_KEY) as Grade
colorScheme = getString(COLOR_SCHEME_KEY) ?: "default"
gradeColorTheme = getSerializable(COLOR_THEME_KEY) as GradeColorTheme
}
}
@ -76,7 +77,7 @@ class GradeDetailsDialog : DialogFragment() {
gradeDialogValue.run {
text = grade.entry
setBackgroundResource(grade.getBackgroundColor(colorScheme))
setBackgroundResource(grade.getBackgroundColor(gradeColorTheme))
}
gradeDialogTeacherValue.text = if (grade.teacher.isBlank()) {

View File

@ -12,7 +12,8 @@ import androidx.recyclerview.widget.LinearLayoutManager
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.ui.modules.grade.GradeExpandMode
import io.github.wulkanowy.data.enums.GradeColorTheme
import io.github.wulkanowy.data.enums.GradeExpandMode
import io.github.wulkanowy.databinding.FragmentGradeDetailsBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.grade.GradeFragment
@ -80,9 +81,9 @@ class GradeDetailsFragment :
else false
}
override fun updateData(data: List<GradeDetailsItem>, expandMode: GradeExpandMode, gradeColorTheme: String) {
override fun updateData(data: List<GradeDetailsItem>, expandMode: GradeExpandMode, gradeColorTheme: GradeColorTheme) {
with(gradeDetailsAdapter) {
colorTheme = gradeColorTheme
this.gradeColorTheme = gradeColorTheme
setDataItems(data, expandMode)
notifyDataSetChanged()
}
@ -143,8 +144,8 @@ class GradeDetailsFragment :
binding.gradeDetailsSwipe.isRefreshing = show
}
override fun showGradeDialog(grade: Grade, colorScheme: String) {
(activity as? MainActivity)?.showDialogFragment(GradeDetailsDialog.newInstance(grade, colorScheme))
override fun showGradeDialog(grade: Grade, colorTheme: GradeColorTheme) {
(activity as? MainActivity)?.showDialogFragment(GradeDetailsDialog.newInstance(grade, colorTheme))
}
override fun onParentLoadData(semesterId: Int, forceRefresh: Boolean) {

View File

@ -2,6 +2,9 @@ package io.github.wulkanowy.ui.modules.grade.details
import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.enums.GradeExpandMode
import io.github.wulkanowy.data.enums.GradeSortingMode.ALPHABETIC
import io.github.wulkanowy.data.enums.GradeSortingMode.DATE
import io.github.wulkanowy.data.repositories.GradeRepository
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.SemesterRepository
@ -9,9 +12,6 @@ import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider
import io.github.wulkanowy.ui.modules.grade.GradeExpandMode
import io.github.wulkanowy.ui.modules.grade.GradeSortingMode.ALPHABETIC
import io.github.wulkanowy.ui.modules.grade.GradeSortingMode.DATE
import io.github.wulkanowy.ui.modules.grade.GradeSubject
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.afterLoading
@ -230,10 +230,14 @@ class GradeDetailsPresenter @Inject constructor(
gradesWithAverages.filter { it.grades.isNotEmpty() }
} else gradesWithAverages
}
.let {
.let { gradeSubjects ->
when (preferencesRepository.gradeSortingMode) {
DATE -> it.sortedByDescending { gradeDetailsWithAverage -> gradeDetailsWithAverage.grades.firstOrNull()?.date }
ALPHABETIC -> it.sortedBy { gradeDetailsWithAverage -> gradeDetailsWithAverage.subject.lowercase() }
DATE -> gradeSubjects.sortedByDescending { gradeDetailsWithAverage ->
gradeDetailsWithAverage.grades.maxByOrNull { it.date }?.date
}
ALPHABETIC -> gradeSubjects.sortedBy { gradeDetailsWithAverage ->
gradeDetailsWithAverage.subject.lowercase()
}
}
}
.map { (subject, average, points, _, grades) ->

View File

@ -1,7 +1,8 @@
package io.github.wulkanowy.ui.modules.grade.details
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.ui.modules.grade.GradeExpandMode
import io.github.wulkanowy.data.enums.GradeColorTheme
import io.github.wulkanowy.data.enums.GradeExpandMode
import io.github.wulkanowy.ui.base.BaseView
interface GradeDetailsView : BaseView {
@ -10,7 +11,7 @@ interface GradeDetailsView : BaseView {
fun initView()
fun updateData(data: List<GradeDetailsItem>, expandMode: GradeExpandMode, gradeColorTheme: String)
fun updateData(data: List<GradeDetailsItem>, expandMode: GradeExpandMode, gradeColorTheme: GradeColorTheme)
fun updateItem(item: Grade, position: Int)
@ -22,7 +23,7 @@ interface GradeDetailsView : BaseView {
fun collapseAllItems()
fun showGradeDialog(grade: Grade, colorScheme: String)
fun showGradeDialog(grade: Grade, colorTheme: GradeColorTheme)
fun showContent(show: Boolean)

View File

@ -20,6 +20,7 @@ import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
import io.github.wulkanowy.data.enums.GradeColorTheme
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
import io.github.wulkanowy.databinding.ItemGradeStatisticsBarBinding
import io.github.wulkanowy.databinding.ItemGradeStatisticsHeaderBinding
@ -34,7 +35,7 @@ class GradeStatisticsAdapter @Inject constructor() :
var items = emptyList<GradeStatisticsItem>()
var theme: String = "vulcan"
lateinit var gradeColorTheme: GradeColorTheme
var showAllSubjectsOnList: Boolean = false
@ -156,8 +157,8 @@ class GradeStatisticsAdapter @Inject constructor() :
visibility = if (items.size == 1 || !showAllSubjectsOnList) GONE else VISIBLE
}
val gradeColors = when (theme) {
"vulcan" -> vulcanGradeColors
val gradeColors = when (gradeColorTheme) {
GradeColorTheme.VULCAN -> vulcanGradeColors
else -> materialGradeColors
}

View File

@ -7,6 +7,7 @@ import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.enums.GradeColorTheme
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
import io.github.wulkanowy.databinding.FragmentGradeStatisticsBinding
import io.github.wulkanowy.ui.base.BaseFragment
@ -43,7 +44,7 @@ class GradeStatisticsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentGradeStatisticsBinding.bind(view)
messageContainer = binding.gradeStatisticsSwipe
messageContainer = binding.gradeStatisticsRecycler
presenter.onAttachView(
this,
savedInstanceState?.getSerializable(SAVED_CHART_TYPE) as? GradeStatisticsItem.DataType
@ -90,12 +91,12 @@ class GradeStatisticsFragment :
override fun updateData(
newItems: List<GradeStatisticsItem>,
newTheme: String,
newTheme: GradeColorTheme,
showAllSubjectsOnStatisticsList: Boolean
) {
with(statisticsAdapter) {
showAllSubjectsOnList = showAllSubjectsOnStatisticsList
theme = newTheme
gradeColorTheme = newTheme
items = newItems
notifyDataSetChanged()
}

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.grade.statistics
import io.github.wulkanowy.data.enums.GradeColorTheme
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
import io.github.wulkanowy.ui.base.BaseView
@ -15,7 +16,7 @@ interface GradeStatisticsView : BaseView {
fun updateData(
newItems: List<GradeStatisticsItem>,
newTheme: String,
newTheme: GradeColorTheme,
showAllSubjectsOnStatisticsList: Boolean
)

View File

@ -72,9 +72,9 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
}
with(binding.loginViewpager) {
offscreenPageLimit = 2
adapter = pagerAdapter
isUserInputEnabled = false
offscreenPageLimit = 2
setOnSelectPageListener(presenter::onViewSelected)
}

View File

@ -52,6 +52,8 @@ class LoginFormPresenter @Inject constructor(
clearHostError()
if (formHostValue.contains("fakelog")) {
setCredentials("jan@fakelog.cf", "jan123")
} else if (formUsernameValue == "jan@fakelog.cf" && formPassValue == "jan123") {
setCredentials("", "")
}
updateUsernameLabel()
}

View File

@ -50,7 +50,10 @@ class LoginSymbolPresenter @Inject constructor(
}
fun attemptLogin(symbol: String) {
if (loginData == null) throw IllegalArgumentException("Login data is null")
if (loginData == null) {
Timber.w("LoginSymbolPresenter - Login data is null")
return
}
if (symbol.isBlank()) {
view?.setErrorSymbolRequire()

View File

@ -56,7 +56,7 @@ class SendMessagePresenter @Inject constructor(
}
message?.let {
setSubject(when (reply) {
true -> "RE: "
true -> "Re: "
else -> "FW: "
} + message.subject)
if (preferencesRepository.fillMessageContent || reply != true) {

View File

@ -74,7 +74,7 @@ class SchoolAnnouncementPresenter @Inject constructor(
Status.SUCCESS -> {
Timber.i("Loading School announcement result: Success")
view?.apply {
updateData(it.data!!.sortedByDescending { item -> item.date })
updateData(it.data!!)
showEmpty(it.data.isEmpty())
showErrorView(false)
showContent(it.data.isNotEmpty())

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.settings.notifications
import android.annotation.SuppressLint
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
@ -50,10 +51,14 @@ class NotificationsFragment : PreferenceFragmentCompat(),
return appPackageName in packageNameList
}
private val notificationSettingsContract =
private val notificationSettingsPiggybackContract =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
presenter.onNotificationPiggybackPermissionResult()
}
presenter.onNotificationPermissionResult()
private val notificationSettingsExactAlarmsContract =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
presenter.onNotificationExactAlarmPermissionResult()
}
override fun initView(showDebugNotificationSwitch: Boolean) {
@ -136,7 +141,7 @@ class NotificationsFragment : PreferenceFragmentCompat(),
.setTitle(R.string.pref_notify_fix_sync_issues)
.setMessage(R.string.pref_notify_fix_sync_issues_message)
.setNegativeButton(android.R.string.cancel) { _, _ -> }
.setPositiveButton(R.string.pref_notify_fix_sync_issues_settings_button) { _, _ ->
.setPositiveButton(R.string.pref_notify_open_system_settings) { _, _ ->
try {
AppKillerManager.doActionPowerSaving(requireContext())
AppKillerManager.doActionAutoStart(requireContext())
@ -151,6 +156,7 @@ class NotificationsFragment : PreferenceFragmentCompat(),
.show()
}
@SuppressLint("InlinedApi")
override fun openSystemSettings() {
val intent = if (appInfo.systemVersion >= Build.VERSION_CODES.O) {
Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
@ -172,8 +178,8 @@ class NotificationsFragment : PreferenceFragmentCompat(),
AlertDialog.Builder(requireContext())
.setTitle(getString(R.string.pref_notification_piggyback_popup_title))
.setMessage(getString(R.string.pref_notification_piggyback_popup_description))
.setPositiveButton(getString(R.string.pref_notification_piggyback_popup_positive)) { _, _ ->
notificationSettingsContract.launch(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
.setPositiveButton(getString(R.string.pref_notification_go_to_settings)) { _, _ ->
notificationSettingsPiggybackContract.launch(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
}
.setNegativeButton(android.R.string.cancel) { _, _ ->
setNotificationPiggybackPreferenceChecked(false)
@ -182,11 +188,30 @@ class NotificationsFragment : PreferenceFragmentCompat(),
.show()
}
override fun openNotificationExactAlarmSettings() {
AlertDialog.Builder(requireContext())
.setTitle(getString(R.string.pref_notification_exact_alarm_popup_title))
.setMessage(getString(R.string.pref_notification_exact_alarm_popup_descriptions))
.setPositiveButton(getString(R.string.pref_notification_go_to_settings)) { _, _ ->
notificationSettingsExactAlarmsContract.launch(Intent("android.settings.REQUEST_SCHEDULE_EXACT_ALARM"))
}
.setNegativeButton(android.R.string.cancel) { _, _ ->
setUpcomingLessonsNotificationPreferenceChecked(false)
}
.setOnDismissListener { setUpcomingLessonsNotificationPreferenceChecked(false) }
.show()
}
override fun setNotificationPiggybackPreferenceChecked(isChecked: Boolean) {
findPreference<SwitchPreferenceCompat>(getString(R.string.pref_key_notifications_piggyback))?.isChecked =
isChecked
}
override fun setUpcomingLessonsNotificationPreferenceChecked(isChecked: Boolean) {
findPreference<SwitchPreferenceCompat>(getString(R.string.pref_key_notifications_upcoming_lessons_enable))?.isChecked =
isChecked
}
override fun onResume() {
super.onResume()
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)

View File

@ -45,6 +45,8 @@ class NotificationsPresenter @Inject constructor(
isUpcomingLessonsNotificationsEnableKey, isUpcomingLessonsNotificationsPersistentKey -> {
if (!isUpcomingLessonsNotificationsEnable) {
timetableNotificationHelper.cancelNotification()
} else if (!timetableNotificationHelper.canScheduleExactAlarms()) {
view?.openNotificationExactAlarmSettings()
}
}
isDebugNotificationEnableKey -> {
@ -68,12 +70,16 @@ class NotificationsPresenter @Inject constructor(
view?.openSystemSettings()
}
fun onNotificationPermissionResult() {
fun onNotificationPiggybackPermissionResult() {
view?.run {
setNotificationPiggybackPreferenceChecked(isNotificationPermissionGranted)
}
}
fun onNotificationExactAlarmPermissionResult() {
view?.setUpcomingLessonsNotificationPreferenceChecked(timetableNotificationHelper.canScheduleExactAlarms())
}
private fun checkNotificationPiggybackState() {
if (preferencesRepository.isNotificationPiggybackEnabled) {
view?.run {

View File

@ -16,5 +16,9 @@ interface NotificationsView : BaseView {
fun openNotificationPermissionDialog()
fun openNotificationExactAlarmSettings()
fun setNotificationPiggybackPreferenceChecked(isChecked: Boolean)
fun setUpcomingLessonsNotificationPreferenceChecked(isChecked: Boolean)
}

View File

@ -12,6 +12,7 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.enums.TimetableMode
import io.github.wulkanowy.databinding.ItemTimetableBinding
import io.github.wulkanowy.databinding.ItemTimetableSmallBinding
import io.github.wulkanowy.utils.getThemeAttrColor
@ -35,7 +36,7 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
var onClickListener: (Timetable) -> Unit = {}
private var showWholeClassPlan: String = "no"
private var showWholeClassPlan = TimetableMode.ONLY_CURRENT_GROUP
private var showGroupsInPlan: Boolean = false
@ -47,7 +48,7 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
fun submitList(
newTimetable: List<Timetable>,
showWholeClassPlan: String = this.showWholeClassPlan,
showWholeClassPlan: TimetableMode = this.showWholeClassPlan,
showGroupsInPlan: Boolean = this.showGroupsInPlan,
showTimers: Boolean = this.showTimers
) {
@ -87,7 +88,7 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
override fun getItemCount() = items.size
override fun getItemViewType(position: Int) = when {
!items[position].isStudentPlan && showWholeClassPlan == "small" -> ViewType.ITEM_SMALL.ordinal
!items[position].isStudentPlan && showWholeClassPlan == TimetableMode.SMALL_OTHER_GROUP -> ViewType.ITEM_SMALL.ordinal
else -> ViewType.ITEM_NORMAL.ordinal
}

View File

@ -14,6 +14,7 @@ import com.google.android.material.datepicker.MaterialDatePicker
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.enums.TimetableMode
import io.github.wulkanowy.databinding.FragmentTimetableBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.main.MainActivity
@ -115,7 +116,7 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
override fun updateData(
data: List<Timetable>,
showWholeClassPlanType: String,
showWholeClassPlanType: TimetableMode,
showGroupsInPlanType: Boolean,
showTimetableTimers: Boolean
) {

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.timetable
import android.annotation.SuppressLint
import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.enums.TimetableMode
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.SemesterRepository
import io.github.wulkanowy.data.repositories.StudentRepository
@ -197,7 +198,7 @@ class TimetablePresenter @Inject constructor(
}
private fun createItems(items: List<Timetable>) = items.filter { item ->
if (prefRepository.showWholeClassPlan == "no") item.isStudentPlan else true
if (prefRepository.showWholeClassPlan == TimetableMode.ONLY_CURRENT_GROUP) item.isStudentPlan else true
}.sortedWith(compareBy({ item -> item.number }, { item -> !item.isStudentPlan }))
private fun showErrorViewOnError(message: String, error: Throwable) {

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.ui.modules.timetable
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.enums.TimetableMode
import io.github.wulkanowy.ui.base.BaseView
import java.time.LocalDate
@ -12,7 +13,12 @@ interface TimetableView : BaseView {
fun initView()
fun updateData(data: List<Timetable>, showWholeClassPlanType: String, showGroupsInPlanType: Boolean, showTimetableTimers: Boolean)
fun updateData(
data: List<Timetable>,
showWholeClassPlanType: TimetableMode,
showGroupsInPlanType: Boolean,
showTimetableTimers: Boolean
)
fun updateNavigationDay(date: String)

View File

@ -14,6 +14,7 @@ import android.widget.RemoteViewsService
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.enums.TimetableMode
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.SemesterRepository
import io.github.wulkanowy.data.repositories.StudentRepository
@ -88,7 +89,7 @@ class TimetableWidgetFactory(
private fun getItemLayout(lesson: Timetable): Int {
return when {
prefRepository.showWholeClassPlan == "small" && !lesson.isStudentPlan -> {
prefRepository.showWholeClassPlan == TimetableMode.SMALL_OTHER_GROUP && !lesson.isStudentPlan -> {
if (savedCurrentTheme == 0L) R.layout.item_widget_timetable_small
else R.layout.item_widget_timetable_small_dark
}
@ -109,7 +110,11 @@ class TimetableWidgetFactory(
timetableRepository.getTimetable(student, semester, date, date, false)
.toFirstResult().data?.lessons.orEmpty()
.sortedWith(compareBy({ it.number }, { !it.isStudentPlan }))
.filter { if (prefRepository.showWholeClassPlan == "no") it.isStudentPlan else true }
.filter {
if (prefRepository.showWholeClassPlan == TimetableMode.ONLY_CURRENT_GROUP) {
it.isStudentPlan
} else true
}
}
} catch (e: Exception) {
Timber.e(e, "An error has occurred in timetable widget factory")
@ -124,8 +129,14 @@ class TimetableWidgetFactory(
return RemoteViews(context.packageName, getItemLayout(lesson)).apply {
setTextViewText(R.id.timetableWidgetItemSubject, lesson.subject)
setTextViewText(R.id.timetableWidgetItemNumber, lesson.number.toString())
setTextViewText(R.id.timetableWidgetItemTimeStart, lesson.start.toFormattedString("HH:mm"))
setTextViewText(R.id.timetableWidgetItemTimeFinish, lesson.end.toFormattedString("HH:mm"))
setTextViewText(
R.id.timetableWidgetItemTimeStart,
lesson.start.toFormattedString("HH:mm")
)
setTextViewText(
R.id.timetableWidgetItemTimeFinish,
lesson.end.toFormattedString("HH:mm")
)
updateDescription(this, lesson)
@ -156,11 +167,16 @@ class TimetableWidgetFactory(
private fun updateStylesCanceled(remoteViews: RemoteViews) {
with(remoteViews) {
setInt(R.id.timetableWidgetItemSubject, "setPaintFlags",
STRIKE_THRU_TEXT_FLAG or ANTI_ALIAS_FLAG)
setInt(
R.id.timetableWidgetItemSubject, "setPaintFlags",
STRIKE_THRU_TEXT_FLAG or ANTI_ALIAS_FLAG
)
setTextColor(R.id.timetableWidgetItemNumber, context.getCompatColor(primaryColor!!))
setTextColor(R.id.timetableWidgetItemSubject, context.getCompatColor(primaryColor!!))
setTextColor(R.id.timetableWidgetItemDescription, context.getCompatColor(primaryColor!!))
setTextColor(
R.id.timetableWidgetItemDescription,
context.getCompatColor(primaryColor!!)
)
}
}
@ -168,7 +184,10 @@ class TimetableWidgetFactory(
with(remoteViews) {
setInt(R.id.timetableWidgetItemSubject, "setPaintFlags", ANTI_ALIAS_FLAG)
setTextColor(R.id.timetableWidgetItemSubject, context.getCompatColor(textColor!!))
setTextColor(R.id.timetableWidgetItemDescription, context.getCompatColor(timetableChangeColor!!))
setTextColor(
R.id.timetableWidgetItemDescription,
context.getCompatColor(timetableChangeColor!!)
)
updateNotCanceledLessonNumberColor(this, lesson)
updateNotCanceledSubjectColor(this, lesson)
@ -180,37 +199,53 @@ class TimetableWidgetFactory(
}
private fun updateNotCanceledLessonNumberColor(remoteViews: RemoteViews, lesson: Timetable) {
remoteViews.setTextColor(R.id.timetableWidgetItemNumber, context.getCompatColor(
if (lesson.changes || (lesson.info.isNotBlank() && !lesson.canceled)) timetableChangeColor!!
else textColor!!
))
remoteViews.setTextColor(
R.id.timetableWidgetItemNumber, context.getCompatColor(
if (lesson.changes || (lesson.info.isNotBlank() && !lesson.canceled)) timetableChangeColor!!
else textColor!!
)
)
}
private fun updateNotCanceledSubjectColor(remoteViews: RemoteViews, lesson: Timetable) {
remoteViews.setTextColor(R.id.timetableWidgetItemSubject, context.getCompatColor(
if (lesson.subjectOld.isNotBlank() && lesson.subject != lesson.subjectOld) timetableChangeColor!!
else textColor!!
))
remoteViews.setTextColor(
R.id.timetableWidgetItemSubject, context.getCompatColor(
if (lesson.subjectOld.isNotBlank() && lesson.subject != lesson.subjectOld) timetableChangeColor!!
else textColor!!
)
)
}
private fun updateNotCanceledRoom(remoteViews: RemoteViews, lesson: Timetable, teacherChange: Boolean) {
private fun updateNotCanceledRoom(
remoteViews: RemoteViews,
lesson: Timetable,
teacherChange: Boolean
) {
with(remoteViews) {
if (lesson.room.isNotBlank()) {
setTextViewText(R.id.timetableWidgetItemRoom,
setTextViewText(
R.id.timetableWidgetItemRoom,
if (teacherChange) lesson.room
else "${context.getString(R.string.timetable_room)} ${lesson.room}"
)
setTextColor(R.id.timetableWidgetItemRoom, context.getCompatColor(
if (lesson.roomOld.isNotBlank() && lesson.room != lesson.roomOld) timetableChangeColor!!
else textColor!!
))
setTextColor(
R.id.timetableWidgetItemRoom, context.getCompatColor(
if (lesson.roomOld.isNotBlank() && lesson.room != lesson.roomOld) timetableChangeColor!!
else textColor!!
)
)
} else setTextViewText(R.id.timetableWidgetItemRoom, "")
}
}
private fun updateNotCanceledTeacher(remoteViews: RemoteViews, lesson: Timetable, teacherChange: Boolean) {
remoteViews.setTextViewText(R.id.timetableWidgetItemTeacher,
private fun updateNotCanceledTeacher(
remoteViews: RemoteViews,
lesson: Timetable,
teacherChange: Boolean
) {
remoteViews.setTextViewText(
R.id.timetableWidgetItemTeacher,
if (teacherChange) lesson.teacher
else ""
)

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.utils
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.enums.GradeColorTheme
import io.github.wulkanowy.sdk.scrapper.grades.isGradeValid
fun List<Grade>.calcAverage(isOptionalArithmeticAverage: Boolean): Double {
@ -37,28 +38,6 @@ fun List<GradeSummary>.calcFinalAverage(plusModifier: Double, minusModifier: Dou
.average()
.let { if (it.isNaN()) 0.0 else it }
fun Grade.getBackgroundColor(theme: String) = when (theme) {
"grade_color" -> getGradeColor()
"material" -> when (value.toInt()) {
6 -> R.color.grade_material_six
5 -> R.color.grade_material_five
4 -> R.color.grade_material_four
3 -> R.color.grade_material_three
2 -> R.color.grade_material_two
1 -> R.color.grade_material_one
else -> R.color.grade_material_default
}
else -> when (value.toInt()) {
6 -> R.color.grade_vulcan_six
5 -> R.color.grade_vulcan_five
4 -> R.color.grade_vulcan_four
3 -> R.color.grade_vulcan_three
2 -> R.color.grade_vulcan_two
1 -> R.color.grade_vulcan_one
else -> R.color.grade_vulcan_default
}
}
fun Grade.getGradeColor() = when (color) {
"000000" -> R.color.grade_black
"F04C4C" -> R.color.grade_red
@ -83,3 +62,25 @@ fun Grade.changeModifier(plusModifier: Double, minusModifier: Double) = when {
modifier < 0 -> copy(modifier = -minusModifier)
else -> this
}
fun Grade.getBackgroundColor(theme: GradeColorTheme) = when (theme) {
GradeColorTheme.GRADE_COLOR -> getGradeColor()
GradeColorTheme.MATERIAL -> when (value.toInt()) {
6 -> R.color.grade_material_six
5 -> R.color.grade_material_five
4 -> R.color.grade_material_four
3 -> R.color.grade_material_three
2 -> R.color.grade_material_two
1 -> R.color.grade_material_one
else -> R.color.grade_material_default
}
GradeColorTheme.VULCAN -> when (value.toInt()) {
6 -> R.color.grade_vulcan_six
5 -> R.color.grade_vulcan_five
4 -> R.color.grade_vulcan_four
3 -> R.color.grade_vulcan_three
2 -> R.color.grade_vulcan_two
1 -> R.color.grade_vulcan_one
else -> R.color.grade_vulcan_default
}
}

View File

@ -123,14 +123,6 @@ class FragmentLifecycleLogger @Inject constructor() :
Timber.d("${f::class.java.simpleName} VIEW DESTROYED")
}
override fun onFragmentActivityCreated(
fm: FragmentManager,
f: Fragment,
savedInstanceState: Bundle?
) {
Timber.d("${f::class.java.simpleName} ACTIVITY CREATED ${savedInstanceState.checkSavedState()}")
}
override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
Timber.d("${f::class.java.simpleName} PAUSED")
}
@ -141,5 +133,5 @@ class FragmentLifecycleLogger @Inject constructor() :
}
private fun Bundle?.checkSavedState() =
if (this == null) "(STATE IS NULL)" else "(STATE IS NOT NULL)"
if (this == null) "(STATE IS NULL)" else "(RESTORE STATE)"

View File

@ -1,10 +1,6 @@
Wersja 1.4.0
Wersja 1.4.4
- dodaliśmy możliwość dodawania własnych zadań domowych
- dodaliśmy kafelek z wiadomościami od twórców
- dodaliśmy dodatkowy tryb rozwijania szczegółów ocen
- dodaliśmy wsparcie dla Androida 12
- ulepszyliśmy powiadomienia na Mi Bandzie
- dokonaliśmy też kilka innych zmian i kosmetycznych poprawek poprawiających komfort używania aplikacji
- naprawiliśmy logowanie do Gdańskiej Platformy Edukacyjnej
- naprawiliśmy sortowanie ocen oraz ogłoszeń
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases

View File

@ -1,158 +1,164 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:layout_height="match_parent">
<io.github.wulkanowy.ui.widgets.MaterialLinearLayout
android:id="@+id/gradeStatisticsSubjectsContainer"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:windowBackground"
android:padding="5dp"
android:visibility="visible"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="UnusedAttribute"
tools:listitem="@layout/item_attendance_summary"
tools:visibility="visible">
android:layout_height="match_parent"
android:orientation="vertical"
tools:ignore="UselessParent">
<Spinner
android:id="@+id/gradeStatisticsSubjects"
<io.github.wulkanowy.ui.widgets.MaterialLinearLayout
android:id="@+id/gradeStatisticsSubjectsContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="middle"
android:paddingStart="10dp"
android:paddingLeft="10dp"
android:paddingTop="10dp"
android:paddingEnd="30dp"
android:paddingRight="30dp"
android:paddingBottom="10dp"
android:spinnerMode="dialog" />
</io.github.wulkanowy.ui.widgets.MaterialLinearLayout>
android:background="?android:windowBackground"
android:padding="5dp"
android:visibility="visible"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="UnusedAttribute"
tools:listitem="@layout/item_attendance_summary"
tools:visibility="visible">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/gradeStatisticsSwipe"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Spinner
android:id="@+id/gradeStatisticsSubjects"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="middle"
android:paddingStart="10dp"
android:paddingLeft="10dp"
android:paddingTop="10dp"
android:paddingEnd="30dp"
android:paddingRight="30dp"
android:paddingBottom="10dp"
android:spinnerMode="dialog" />
</io.github.wulkanowy.ui.widgets.MaterialLinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/gradeStatisticsSwipe"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/gradeStatisticsProgress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/gradeStatisticsRecycler"
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="@layout/item_grade_statistics_pie"
tools:visibility="visible" />
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="12dp"
android:fillViewport="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/gradeStatisticsRecycler">
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/gradeStatisticsProgress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="gone" />
<androidx.constraintlayout.widget.ConstraintLayout
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/gradeStatisticsRecycler"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="@layout/item_grade_statistics_pie"
tools:visibility="visible" />
<LinearLayout
android:id="@+id/gradeStatisticsEmpty"
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="12dp"
android:fillViewport="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/gradeStatisticsRecycler">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="UseCompoundDrawables"
tools:visibility="gone">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
app:srcCompat="@drawable/ic_main_grade"
app:tint="?colorOnBackground"
tools:ignore="contentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="@string/grade_no_items"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/gradeStatisticsError"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="UseCompoundDrawables"
tools:visibility="gone">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
app:srcCompat="@drawable/ic_error"
app:tint="?colorOnBackground"
tools:ignore="contentDescription" />
<TextView
android:id="@+id/gradeStatisticsErrorMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:padding="8dp"
android:text="@string/error_unknown"
android:textSize="20sp" />
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/gradeStatisticsEmpty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center"
android:orientation="horizontal">
android:orientation="vertical"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="UseCompoundDrawables"
tools:visibility="gone">
<com.google.android.material.button.MaterialButton
android:id="@+id/gradeStatisticsErrorDetails"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
app:srcCompat="@drawable/ic_main_grade"
app:tint="?colorOnBackground"
tools:ignore="contentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:text="@string/all_details" />
<com.google.android.material.button.MaterialButton
android:id="@+id/gradeStatisticsErrorRetry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/all_retry" />
android:layout_marginTop="20dp"
android:gravity="center"
android:text="@string/grade_no_items"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/gradeStatisticsError"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="UseCompoundDrawables"
tools:visibility="gone">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
app:srcCompat="@drawable/ic_error"
app:tint="?colorOnBackground"
tools:ignore="contentDescription" />
<TextView
android:id="@+id/gradeStatisticsErrorMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:padding="8dp"
android:text="@string/error_unknown"
android:textSize="20sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/gradeStatisticsErrorDetails"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:text="@string/all_details" />
<com.google.android.material.button.MaterialButton
android:id="@+id/gradeStatisticsErrorRetry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/all_retry" />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout>
</FrameLayout>

View File

@ -33,8 +33,8 @@
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:textStyle="bold"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/dashboard_admin_message_item_icon"
app:layout_constraintTop_toTopOf="parent"
@ -53,8 +53,23 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/dashboard_admin_message_item_title"
app:layout_constraintVertical_bias="0"
app:lineHeight="20dp"
tools:maxLines="5"
tools:text="@tools:sample/lorem/random" />
<com.google.android.material.button.MaterialButton
android:id="@+id/dashboard_admin_message_item_dismiss"
style="@style/Widget.MaterialComponents.Button.TextButton.Dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:text="@android:string/ok"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/dashboard_admin_message_item_description"
app:layout_constraintVertical_bias="0" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>

View File

@ -553,18 +553,6 @@
<string name="dashboard_timetable_first_lesson_title_soon">Brzy:</string>
<string name="dashboard_timetable_first_lesson_title_first">První:</string>
<string name="dashboard_timetable_first_lesson_title_now">Teď:</string>
<plurals name="dashboard_timetable_first_lesson_time_in_minutes">
<item quantity="one">za %1$d minutu</item>
<item quantity="few">za %1$d minuty</item>
<item quantity="many">za %1$d minut</item>
<item quantity="other">za %1$d minut</item>
</plurals>
<plurals name="dashboard_timetable_first_lesson_time_more_minutes">
<item quantity="one">ještě %1$d minutu</item>
<item quantity="few">ještě %1$d minuty</item>
<item quantity="many">ještě %1$d minut</item>
<item quantity="other">ještě %1$d minut</item>
</plurals>
<string name="dashboard_timetable_second_lesson_value_end">Konec lekcí</string>
<string name="dashboard_timetable_second_lessons_title">Další:</string>
<string name="dashboard_timetable_third_title">Později:</string>
@ -678,13 +666,14 @@
<string name="pref_notify_open_system_settings">Otevřít systémová nastavení upozornění</string>
<string name="pref_notify_fix_sync_issues">Opravte problémy se synchronizací a upozorněním</string>
<string name="pref_notify_fix_sync_issues_message">Vaše zařízení může mít problémy se synchronizací dat as upozorněními.\n\nChcete-li je opravit, přidejte Wulkanového do funkce Autostart a vypněte optimalizaci/úsporu baterie v nastavení systému telefonu.</string>
<string name="pref_notify_fix_sync_issues_settings_button">Přejít do nastavení</string>
<string name="pref_notify_debug_switch">Zobrazit upozornění o ladění</string>
<string name="pref_notify_disabled_summary">Synchronizace je vypnutá</string>
<string name="pref_notify_notifications_piggyback">Zachytit upozornění oficiální aplikací</string>
<string name="pref_notification_piggyback_popup_title">Zachytit upozornění</string>
<string name="pref_notification_piggyback_popup_description">S touto funkcí můžete získat náhradu push upozornění jako v oficiální aplikaci. Vše, co musíte udělat, je povolit Wulkanowému číst všechna vaše upozornění v nastaveních systému.\n\nJak to funguje?\nKdyž obdržíte oznámení v Deníčku VULCAN, Wulkanowy bude o tom informován (k tomu je to dodatečné povolení) a spustí synchronizaci, aby mohl zaslat vlastní upozornění.\n\nPOUZE PRO POKROČILÉ UŽIVATELE</string>
<string name="pref_notification_piggyback_popup_positive">Přejít do nastavení</string>
<string name="pref_notification_exact_alarm_popup_title">Upozornění o nadcházející lekci</string>
<string name="pref_notification_exact_alarm_popup_descriptions">Musíte povolit Wulkanovému nastavit budíky a připomenutí v nastavení vašeho systému pro použití této funkce.</string>
<string name="pref_notification_go_to_settings">Přejít do nastavení</string>
<string name="pref_services_header">Synchronizace</string>
<string name="pref_services_switch">Automatická aktualizace</string>
<string name="pref_services_suspended">Pozastaveno na dovolené</string>
@ -706,6 +695,7 @@
<string name="pref_ads_privacy_agree">Souhlasím</string>
<string name="pref_ads_privacy_link">Ochrana osobních údajů</string>
<string name="pref_ads_loading">Reklama se načítá</string>
<string name="pref_ads_once_per_visit">Děkujeme za vaši podporu, vraťte se později pro více reklam</string>
<string name="pref_settings_advanced_title">Pokročilé</string>
<string name="pref_settings_appearance_title">Vzhled a chování</string>
<string name="pref_settings_notifications_title">Upozornění</string>

View File

@ -477,14 +477,6 @@
<string name="dashboard_timetable_first_lesson_title_soon">Bald:</string>
<string name="dashboard_timetable_first_lesson_title_first">Erstens:</string>
<string name="dashboard_timetable_first_lesson_title_now">Jetzt:</string>
<plurals name="dashboard_timetable_first_lesson_time_in_minutes">
<item quantity="one">in %1$d Minute</item>
<item quantity="other">in %1$d Minuten</item>
</plurals>
<plurals name="dashboard_timetable_first_lesson_time_more_minutes">
<item quantity="one">Noch %1$d Minute</item>
<item quantity="other">Noch %1$d Minuten</item>
</plurals>
<string name="dashboard_timetable_second_lesson_value_end">Ende der Lektion</string>
<string name="dashboard_timetable_second_lessons_title">Nächste:</string>
<string name="dashboard_timetable_third_title">Später:</string>
@ -588,13 +580,14 @@
<string name="pref_notify_open_system_settings">Systembenachrichtigungseinstellungen öffnen</string>
<string name="pref_notify_fix_sync_issues">Synchronisierungs- und Benachrichtigungsprobleme reparieren</string>
<string name="pref_notify_fix_sync_issues_message">Ihr Gerät hat möglicherweise Probleme mit der Datensynchronisierung und Benachrichtigungen.\n\nUm diese zu reparieren, fügen Sie Wulkanowy zum Autostart hinzu und deaktivieren Sie die Batterieoptimierung in den Systemeinstellungen des Geräts.</string>
<string name="pref_notify_fix_sync_issues_settings_button">Gehe zu den Einstellungen</string>
<string name="pref_notify_debug_switch">Debug-Benachrichtigungen anzeigen</string>
<string name="pref_notify_disabled_summary">Synchronisierung ist deaktiviert</string>
<string name="pref_notify_notifications_piggyback">Offizielle App-Benachrichtigungen erfassen</string>
<string name="pref_notification_piggyback_popup_title">Benachrichtigungen erfassen</string>
<string name="pref_notification_piggyback_popup_description">With this feature you can gain a substitute of push notifications like in the official app. All you need to do is allow Wulkanowy to receive all notifications in your system settings.\n\nHow it works?\nWhen you get a notification in Dziennik VULCAN, Wulkanowy will be notified (that\'s what these extra permissions are for) and will trigger a sync so that can send its own notification.\n\nFOR ADVANCED USERS ONLY</string>
<string name="pref_notification_piggyback_popup_positive">Gehe zu Einstellungen</string>
<string name="pref_notification_exact_alarm_popup_title">Upcoming lesson notifications</string>
<string name="pref_notification_exact_alarm_popup_descriptions">You must allow the Wulkanowy app to set alarms and reminders in your system settings to use this feature.</string>
<string name="pref_notification_go_to_settings">Go to settings</string>
<string name="pref_services_header">Synchronisierung</string>
<string name="pref_services_switch">Automatische Aktualisierung</string>
<string name="pref_services_suspended">An Feiertagen suspendiert</string>
@ -616,6 +609,7 @@
<string name="pref_ads_privacy_agree">Agree</string>
<string name="pref_ads_privacy_link">Privacy policy</string>
<string name="pref_ads_loading">Ad is loading</string>
<string name="pref_ads_once_per_visit">Thank you for your support, come back later for more ads</string>
<string name="pref_settings_advanced_title">Erweitert</string>
<string name="pref_settings_appearance_title">Aussehen &amp; Verhalten</string>
<string name="pref_settings_notifications_title">Benachrichtigungen</string>

View File

@ -553,18 +553,6 @@
<string name="dashboard_timetable_first_lesson_title_soon">Wkrótce:</string>
<string name="dashboard_timetable_first_lesson_title_first">Pierwsza:</string>
<string name="dashboard_timetable_first_lesson_title_now">Teraz:</string>
<plurals name="dashboard_timetable_first_lesson_time_in_minutes">
<item quantity="one">za %1$d minutę</item>
<item quantity="few">za %1$d minuty</item>
<item quantity="many">za %1$d minut</item>
<item quantity="other">za %1$d minut</item>
</plurals>
<plurals name="dashboard_timetable_first_lesson_time_more_minutes">
<item quantity="one">jeszcze %1$d minuta</item>
<item quantity="few">jeszcze %1$d minuty</item>
<item quantity="many">jeszcze %1$d minut</item>
<item quantity="other">jeszcze %1$d minut</item>
</plurals>
<string name="dashboard_timetable_second_lesson_value_end">Koniec lekcji</string>
<string name="dashboard_timetable_second_lessons_title">Następnie:</string>
<string name="dashboard_timetable_third_title">Później:</string>
@ -678,13 +666,14 @@
<string name="pref_notify_open_system_settings">Otwórz systemowe ustawienia powiadomień</string>
<string name="pref_notify_fix_sync_issues">Napraw problemy z synchronizacją i powiadomieniami</string>
<string name="pref_notify_fix_sync_issues_message">Na twoim urządzeniu mogą występować problemy z synchronizacją danych i powiadomieniami.\n\nBy je naprawić, dodaj Wulkanowego do autostartu i wyłącz optymalizację/oszczędzanie baterii w ustawieniach systemowych telefonu.</string>
<string name="pref_notify_fix_sync_issues_settings_button">Przejdź do ustawień</string>
<string name="pref_notify_debug_switch">Pokazuj powiadomienia debugowania</string>
<string name="pref_notify_disabled_summary">Synchronizacja jest wyłączona</string>
<string name="pref_notify_notifications_piggyback">Przechwytywanie powiadomień oficjalnej aplikacji</string>
<string name="pref_notification_piggyback_popup_title">Przechwytywanie powiadomień</string>
<string name="pref_notification_piggyback_popup_description">Dzięki tej funkcji możesz uzyskać namiastkę powiadomień push, takich jak w oficjalnej aplikacji. Wszystko, co musisz zrobić, to zezwolić Wulkanowemu na odczytywanie wszystkich powiadomień w ustawieniach systemowych.\n\nJak to działa?\nKiedy otrzymasz powiadomienie w Dzienniczku VULCAN, Wulkanowy zostanie o tym powiadomiony (do tego jest to dodatkowe uprawnienie) i uruchomi synchronizację, aby mógł wysłać własne powiadomienie.\n\nWYŁĄCZNIE DLA ZAAWANSOWANYCH UŻYTKOWNIKÓW</string>
<string name="pref_notification_piggyback_popup_positive">Przejdź do ustawień</string>
<string name="pref_notification_exact_alarm_popup_title">Powiadomienia o nadchodzących lekcjach</string>
<string name="pref_notification_exact_alarm_popup_descriptions">Musisz pozwolić Wulkanowemu na tworzenie alarmów i przypomnień w ustawieniach Twojego systemu, aby użyć tej funkcji.</string>
<string name="pref_notification_go_to_settings">Przejdź do ustawień</string>
<string name="pref_services_header">Synchronizacja</string>
<string name="pref_services_switch">Automatyczna aktualizacja</string>
<string name="pref_services_suspended">Zawieszona na wakacjach</string>
@ -706,6 +695,7 @@
<string name="pref_ads_privacy_agree">Akceptuję</string>
<string name="pref_ads_privacy_link">Polityka prywatności</string>
<string name="pref_ads_loading">Ładowanie reklamy</string>
<string name="pref_ads_once_per_visit">Dziękujemy za wsparcie, wróć później po więcej reklam</string>
<string name="pref_settings_advanced_title">Zaawansowane</string>
<string name="pref_settings_appearance_title">Wygląd i zachowanie</string>
<string name="pref_settings_notifications_title">Powiadomienia</string>

View File

@ -553,18 +553,6 @@
<string name="dashboard_timetable_first_lesson_title_soon">Скоро:</string>
<string name="dashboard_timetable_first_lesson_title_first">Первый:</string>
<string name="dashboard_timetable_first_lesson_title_now">Сейчас:</string>
<plurals name="dashboard_timetable_first_lesson_time_in_minutes">
<item quantity="one">через %1$d минуту</item>
<item quantity="few">через %1$d минуту</item>
<item quantity="many">через %1$d минуту</item>
<item quantity="other">через %1$d минут</item>
</plurals>
<plurals name="dashboard_timetable_first_lesson_time_more_minutes">
<item quantity="one">Еще %1$d минута</item>
<item quantity="few">Еще %1$d минута</item>
<item quantity="many">Еще %1$d минута</item>
<item quantity="other">Ещё %1$d минут</item>
</plurals>
<string name="dashboard_timetable_second_lesson_value_end">Окончание уроков</string>
<string name="dashboard_timetable_second_lessons_title">Далее:</string>
<string name="dashboard_timetable_third_title">Позднее:</string>
@ -678,13 +666,14 @@
<string name="pref_notify_open_system_settings">Открыть настройки уведомлений системы</string>
<string name="pref_notify_fix_sync_issues">Исправить проблемы с синхронизацией и уведомлениями</string>
<string name="pref_notify_fix_sync_issues_message">На вашем устройстве могут быть проблемы с синхронизацией данных и уведомлениями.\n\nЧтобы их исправить, вам необходимо добавить Wulkanowy в авто-старт и выключить оптимизацию/экономию батареи в настройках устройства.</string>
<string name="pref_notify_fix_sync_issues_settings_button">Перейти в настройски</string>
<string name="pref_notify_debug_switch">Показывать дебаг-уведомления</string>
<string name="pref_notify_disabled_summary">Синхронизация отключена</string>
<string name="pref_notify_notifications_piggyback">Записывать официальные уведомления</string>
<string name="pref_notification_piggyback_popup_title">Показывать push-уведомления</string>
<string name="pref_notification_piggyback_popup_description">С помощью этой функции вы можете получить замену push-уведомлений, как в официальном приложении. Все, что вам нужно сделать, это разрешить Wulkanowy получать все уведомления в настройках системы.\n\nКак это работает?\nКогда вы получаете уведомление в Dziennik VULCAN, Wulkanowy будет уведомлен (это требует дополнительных прав) и запустит синхронизацию, чтобы отправить свое уведомление.\n\nТОЛЬКО ДЛЯ ПОЛЬЗОВАТЕЛЯ</string>
<string name="pref_notification_piggyback_popup_positive">Перейти к настройкам</string>
<string name="pref_notification_exact_alarm_popup_title">Upcoming lesson notifications</string>
<string name="pref_notification_exact_alarm_popup_descriptions">You must allow the Wulkanowy app to set alarms and reminders in your system settings to use this feature.</string>
<string name="pref_notification_go_to_settings">Go to settings</string>
<string name="pref_services_header">Синхронизация</string>
<string name="pref_services_switch">Автоматическая синхронизация</string>
<string name="pref_services_suspended">Приостановить синхронизации во время каникул</string>
@ -706,6 +695,7 @@
<string name="pref_ads_privacy_agree">Согласен</string>
<string name="pref_ads_privacy_link">Политика конфиденциальности</string>
<string name="pref_ads_loading">Объявление загружается</string>
<string name="pref_ads_once_per_visit">Thank you for your support, come back later for more ads</string>
<string name="pref_settings_advanced_title">Расширенные</string>
<string name="pref_settings_appearance_title">Внешний вид &amp; Поведение</string>
<string name="pref_settings_notifications_title">Уведомления</string>

View File

@ -553,18 +553,6 @@
<string name="dashboard_timetable_first_lesson_title_soon">Čoskoro:</string>
<string name="dashboard_timetable_first_lesson_title_first">Prvá:</string>
<string name="dashboard_timetable_first_lesson_title_now">Teraz:</string>
<plurals name="dashboard_timetable_first_lesson_time_in_minutes">
<item quantity="one">za %1$d minútu</item>
<item quantity="few">za %1$d minúty</item>
<item quantity="many">za %1$d minút</item>
<item quantity="other">za %1$d minút</item>
</plurals>
<plurals name="dashboard_timetable_first_lesson_time_more_minutes">
<item quantity="one">ešte %1$d minútu</item>
<item quantity="few">ešte %1$d minúty</item>
<item quantity="many">ešte %1$d minút</item>
<item quantity="other">ešte %1$d minút</item>
</plurals>
<string name="dashboard_timetable_second_lesson_value_end">Koniec lekcií</string>
<string name="dashboard_timetable_second_lessons_title">Ďalej:</string>
<string name="dashboard_timetable_third_title">Neskôr:</string>
@ -678,13 +666,14 @@
<string name="pref_notify_open_system_settings">Otvoriť systémové nastavenia upozornení</string>
<string name="pref_notify_fix_sync_issues">Opravte problémy so synchronizáciou a upozornením</string>
<string name="pref_notify_fix_sync_issues_message">Vaše zariadenie môže mať problémy so synchronizáciou dát as upozorneniami.\n\nAk ich chcete opraviť, pridajte Wulkanového do funkcie Autostart a vypnite optimalizáciu/úsporu batérie v nastavení systému telefóne.</string>
<string name="pref_notify_fix_sync_issues_settings_button">Prejsť do nastavení</string>
<string name="pref_notify_debug_switch">Zobraziť upozornenia o ladení</string>
<string name="pref_notify_disabled_summary">Synchronizácia je vypnutá</string>
<string name="pref_notify_notifications_piggyback">Zachytiť upozornenia oficiálnej aplikácie</string>
<string name="pref_notification_piggyback_popup_title">Zachytiť upozornenia</string>
<string name="pref_notification_piggyback_popup_description">S touto funkciou môžete získať náhradu push upozornení ako v oficiálnej aplikácii. Všetko, čo musíte urobiť, je povoliť Wulkanowému čítať všetky vaše upozornenia v nastaveniach systému.\n\nAko to funguje?\nKeď dostanete oznámenie v Deníčku VULCAN, Wulkanowy bude o tom informovaný (k tomu je to dodatočné povolenie) a spustí synchronizáciu, aby mohol zaslať vlastné upozornenie.\n\nLEN PRE POKROČILÝCH POUŽĺVATEĹOV</string>
<string name="pref_notification_piggyback_popup_positive">Prejsť do nastavení</string>
<string name="pref_notification_exact_alarm_popup_title">Upozornenia o nadchádzajúcej lekciu</string>
<string name="pref_notification_exact_alarm_popup_descriptions">Musíte povoliť Wulkanovému nastaviť budíky a pripomenutie v nastavení vášho systému pre použitie tejto funkcie.</string>
<string name="pref_notification_go_to_settings">Prejsť do nastavení</string>
<string name="pref_services_header">Synchronizácia</string>
<string name="pref_services_switch">Automatická aktualizácia</string>
<string name="pref_services_suspended">Pozastavený počas dovolenky</string>
@ -706,6 +695,7 @@
<string name="pref_ads_privacy_agree">Súhlasím</string>
<string name="pref_ads_privacy_link">Ochrana osobných údajov</string>
<string name="pref_ads_loading">Reklama sa načítava</string>
<string name="pref_ads_once_per_visit">Ďakujeme za vašu podporu, vráťte sa neskôr pre viac reklám</string>
<string name="pref_settings_advanced_title">Pokročilé</string>
<string name="pref_settings_appearance_title">Vzhľad a správanie</string>
<string name="pref_settings_notifications_title">Upozornenia</string>

View File

@ -553,18 +553,6 @@
<string name="dashboard_timetable_first_lesson_title_soon">Незабаром:</string>
<string name="dashboard_timetable_first_lesson_title_first">Перше:</string>
<string name="dashboard_timetable_first_lesson_title_now">Зараз:</string>
<plurals name="dashboard_timetable_first_lesson_time_in_minutes">
<item quantity="one">через %1$d хвилину</item>
<item quantity="few">через %1$d хвилину</item>
<item quantity="many">через %1$d хвилину</item>
<item quantity="other">через %1$d хвилин</item>
</plurals>
<plurals name="dashboard_timetable_first_lesson_time_more_minutes">
<item quantity="one">%1$d більше хвилини</item>
<item quantity="few">%1$d більше хвилини</item>
<item quantity="many">%1$d більше хвилини</item>
<item quantity="other">%1$d ще хвилин</item>
</plurals>
<string name="dashboard_timetable_second_lesson_value_end">Кінець уроків</string>
<string name="dashboard_timetable_second_lessons_title">Далі:</string>
<string name="dashboard_timetable_third_title">Пізніше :</string>
@ -678,13 +666,14 @@
<string name="pref_notify_open_system_settings">Відкрити налаштування сповіщень системи</string>
<string name="pref_notify_fix_sync_issues">Виправити помилки з синхронізацією і повідомленнями</string>
<string name="pref_notify_fix_sync_issues_message">На вашому пристрої можуть бути помилки з синхронізацією і повідомленнями\n\nЩоб виправити іх, вам необхідно додати Wulkanowy в авто-старт и вимкнути оптимізацію/экономію батареї в налаштуваннях пристрою.</string>
<string name="pref_notify_fix_sync_issues_settings_button">Перейти до налаштувань</string>
<string name="pref_notify_debug_switch">Показувати дебаг-повідомлення</string>
<string name="pref_notify_disabled_summary">Синхронізація вимкнена</string>
<string name="pref_notify_notifications_piggyback">Захоплювати офіційні сповіщення програм</string>
<string name="pref_notification_piggyback_popup_title">Показувати push-повідомлення</string>
<string name="pref_notification_piggyback_popup_description">За допомогою цієї функції ви можете отримати заміну push -повідомлень, як у офіційному додатку. Все, що вам потрібно зробити, це дозволити Wulkanowy отримувати всі сповіщення у налаштуваннях вашої системи. \ N \ nЯк це працює? \ NКоли ви отримаєте сповіщення у Dziennik VULCAN, Wulkanowy отримає сповіщення (для цього призначені ці додаткові дозволи) і запустить синхронізація, яка може надсилати власне сповіщення. \ n \ n ТІЛЬКИ ДЛЯ РОЗШИРЕНИХ КОРИСТУВАЧІВ</string>
<string name="pref_notification_piggyback_popup_positive">Перейти до налаштувань</string>
<string name="pref_notification_exact_alarm_popup_title">Upcoming lesson notifications</string>
<string name="pref_notification_exact_alarm_popup_descriptions">You must allow the Wulkanowy app to set alarms and reminders in your system settings to use this feature.</string>
<string name="pref_notification_go_to_settings">Go to settings</string>
<string name="pref_services_header">Синхронізація</string>
<string name="pref_services_switch">Автоматична синхронізація</string>
<string name="pref_services_suspended">Призупинено на час канікул</string>
@ -706,6 +695,7 @@
<string name="pref_ads_privacy_agree">Погоджуюсь</string>
<string name="pref_ads_privacy_link">Політика конфіденційності</string>
<string name="pref_ads_loading">Реклама завантажується</string>
<string name="pref_ads_once_per_visit">Thank you for your support, come back later for more ads</string>
<string name="pref_settings_advanced_title">Додатково</string>
<string name="pref_settings_appearance_title">Вигляд &amp; Поведінка</string>
<string name="pref_settings_notifications_title">Повідомлення</string>

View File

@ -71,7 +71,7 @@
<string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">Send email</string>
<string name="login_email_subject" translatable="false">Zgłoszenie: Problemy z logowaniem</string>
<string name="login_email_text" translatable="false">Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\nDodatkowe informacje: %4$s\nOstatni błąd: %5$s\n\nPełna nazwa szkoły i klasa ucznia: </string>
<string name="login_email_text" translatable="false">Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\nDodatkowe informacje: %4$s\nOstatni błąd: %5$s\n\nNazwa szkoły wraz z miejscowością i numer klasy: </string>
<string name="login_recover_warning">Make sure you select the correct UONET+ register variation!</string>
<string name="login_recover_button">I forgot my password</string>
<string name="login_recover_title">Recover your account</string>
@ -247,8 +247,8 @@
<item quantity="other">New exams</item>
</plurals>
<plurals name="exam_notify_new_item_content">
<item quantity="one">You received %d new exam</item>
<item quantity="other">You received %d new exams</item>
<item quantity="one">%d new exam</item>
<item quantity="other">%d new exams</item>
</plurals>
<plurals name="exam_number_item">
<item quantity="one">%d exam</item>
@ -541,14 +541,6 @@
<string name="dashboard_timetable_first_lesson_title_soon">Soon:</string>
<string name="dashboard_timetable_first_lesson_title_first">First:</string>
<string name="dashboard_timetable_first_lesson_title_now">Now:</string>
<plurals name="dashboard_timetable_first_lesson_time_in_minutes">
<item quantity="one">in %1$d minute</item>
<item quantity="other">in %1$d minutes</item>
</plurals>
<plurals name="dashboard_timetable_first_lesson_time_more_minutes">
<item quantity="one">%1$d more minute</item>
<item quantity="other">%1$d more minutes</item>
</plurals>
<string name="dashboard_timetable_second_lesson_value_end">End of lessons</string>
<string name="dashboard_timetable_second_lessons_title">Next:</string>
<string name="dashboard_timetable_third_title">Later:</string>
@ -667,13 +659,14 @@
<string name="pref_notify_open_system_settings">Open system notification settings</string>
<string name="pref_notify_fix_sync_issues">Fix synchronization &amp; notifications issues</string>
<string name="pref_notify_fix_sync_issues_message">Your device may have data synchronization issues and with notifications.\n\nTo fix them, you need to add Wulkanowy to the autostart and turn off battery optimization/saving in the phone settings.</string>
<string name="pref_notify_fix_sync_issues_settings_button">Go to settings</string>
<string name="pref_notify_debug_switch">Show debug notifications</string>
<string name="pref_notify_disabled_summary">Synchronization is disabled</string>
<string name="pref_notify_notifications_piggyback">Capture official app notifications</string>
<string name="pref_notification_piggyback_popup_title">Capture notifications</string>
<string name="pref_notification_piggyback_popup_description">With this feature you can gain a substitute of push notifications like in the official app. All you need to do is allow Wulkanowy to receive all notifications in your system settings.\n\nHow it works?\nWhen you get a notification in Dziennik VULCAN, Wulkanowy will be notified (that\'s what these extra permissions are for) and will trigger a sync so that can send its own notification.\n\nFOR ADVANCED USERS ONLY</string>
<string name="pref_notification_piggyback_popup_positive">Go to settings</string>
<string name="pref_notification_exact_alarm_popup_title">Upcoming lesson notifications</string>
<string name="pref_notification_exact_alarm_popup_descriptions">You must allow the Wulkanowy app to set alarms and reminders in your system settings to use this feature.</string>
<string name="pref_notification_go_to_settings">Go to settings</string>
<string name="pref_services_header">Synchronization</string>
<string name="pref_services_switch">Automatic update</string>
@ -698,6 +691,7 @@
<string name="pref_ads_privacy_agree">Agree</string>
<string name="pref_ads_privacy_link">Privacy policy</string>
<string name="pref_ads_loading">Ad is loading</string>
<string name="pref_ads_once_per_visit">Thank you for your support, come back later for more ads</string>
<string name="pref_settings_advanced_title">Advanced</string>
<string name="pref_settings_appearance_title">Appearance &amp; Behavior</string>

View File

@ -68,6 +68,13 @@ class AdsFragment : PreferenceFragmentCompat(), MainView.TitledView, AdsView {
}
}
override fun showWatchAdOncePerVisit(show: Boolean) {
findPreference<Preference>(getString(R.string.pref_key_ads_single_support))?.run {
isEnabled = !show
summary = if (show) getString(R.string.pref_ads_once_per_visit) else null
}
}
override fun showError(text: String, error: Throwable) {
(activity as? BaseActivity<*, *>)?.showError(text, error)
}

View File

@ -35,7 +35,10 @@ class AdsPresenter @Inject constructor(
.onFailure(errorHandler::dispatch)
.onSuccess { it?.let { view?.showAd(it) } }
view?.showLoadingSupportAd(false)
view?.run {
showLoadingSupportAd(false)
showWatchAdOncePerVisit(true)
}
}
}
}

View File

@ -14,4 +14,6 @@ interface AdsView : BaseView {
fun openPrivacyPolicy()
fun showLoadingSupportAd(show: Boolean)
fun showWatchAdOncePerVisit(show: Boolean)
}

View File

@ -1,6 +1,8 @@
package io.github.wulkanowy.utils
import android.content.Context
import android.os.Bundle
import com.google.ads.mediation.admob.AdMobAdapter
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.MobileAds
@ -18,7 +20,10 @@ class AdsHelper @Inject constructor(@ApplicationContext private val context: Con
suspend fun getSupportAd(): RewardedInterstitialAd? {
MobileAds.initialize(context)
val adRequest = AdRequest.Builder().build()
val extra = Bundle().apply { putString("npa", "1") }
val adRequest = AdRequest.Builder()
.addNetworkExtrasBundle(AdMobAdapter::class.java, extra)
.build()
return suspendCoroutine {
RewardedInterstitialAd.load(

View File

@ -6,7 +6,7 @@
<Preference
app:iconSpaceReserved="false"
app:key="@string/pref_key_ads_single_support"
app:singleLineTitle="true"
app:singleLineTitle="false"
app:title="@string/pref_ads_support" />
</PreferenceCategory>
</PreferenceScreen>

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.utils
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.enums.GradeColorTheme
import io.mockk.MockKAnnotations
import io.mockk.impl.annotations.MockK
import org.junit.Assert.assertEquals
@ -46,10 +47,25 @@ class GradeExtensionTest {
@Test
fun getBackgroundColor() {
assertEquals(R.color.grade_material_five, createGrade(5.0).getBackgroundColor("material"))
assertEquals(R.color.grade_material_five, createGrade(5.5).getBackgroundColor("material"))
assertEquals(R.color.grade_material_five, createGrade(5.9).getBackgroundColor("material"))
assertEquals(R.color.grade_vulcan_five, createGrade(5.9).getBackgroundColor("whatever"))
assertEquals(
R.color.grade_material_five, createGrade(5.0).getBackgroundColor(
GradeColorTheme.MATERIAL
)
)
assertEquals(
R.color.grade_material_five, createGrade(5.5).getBackgroundColor(
GradeColorTheme.MATERIAL
)
)
assertEquals(
R.color.grade_material_five, createGrade(5.9).getBackgroundColor(
GradeColorTheme.MATERIAL
)
)
assertEquals(
R.color.grade_vulcan_five,
createGrade(5.9).getBackgroundColor(GradeColorTheme.VULCAN)
)
}
@Test

View File

@ -1,8 +1,8 @@
buildscript {
ext {
kotlin_version = '1.5.31'
kotlin_version = '1.6.0'
about_libraries = '8.9.4'
hilt_version = "2.40.1"
hilt_version = "2.40.5"
}
repositories {
mavenCentral()
@ -13,11 +13,11 @@ buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath 'com.android.tools.build:gradle:7.0.3'
classpath 'com.android.tools.build:gradle:7.0.4'
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.google.gms:google-services:4.3.10'
classpath 'com.huawei.agconnect:agcp:1.6.1.300'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.0'
classpath 'com.huawei.agconnect:agcp:1.6.2.300'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
classpath "com.github.triplet.gradle:play-publisher:3.6.0"
classpath "ru.cian:huawei-publish-gradle-plugin:1.3.0"
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.3"