forked from github/wulkanowy-mirror
Merge branch 'release/1.1.0'
This commit is contained in:
commit
e15eb03299
78
.github/workflows/test.yml
vendored
78
.github/workflows/test.yml
vendored
@ -10,8 +10,8 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
unit-tests:
|
||||||
name: Pre-build
|
name: Unit tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
@ -27,36 +27,6 @@ jobs:
|
|||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
~/.gradle/wrapper
|
~/.gradle/wrapper
|
||||||
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||||
- name: Build
|
|
||||||
run: ./gradlew --build-cache compileFdroidDebugUnitTestKotlin preFdroidDebugAndroidTestBuild dexBuilderFdroidDebugAndroidTest packageFdroidDebug packageFdroidDebugAndroidTest
|
|
||||||
- name: Prepare build cache
|
|
||||||
run: tar -cf prebuild.tar .build-cache .gradle app/build
|
|
||||||
- uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: prebuild.tar
|
|
||||||
path: prebuild.tar
|
|
||||||
|
|
||||||
unit-tests:
|
|
||||||
name: Unit tests
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 10
|
|
||||||
needs: [ build ]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions/setup-java@v1
|
|
||||||
with:
|
|
||||||
java-version: 11
|
|
||||||
- uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.gradle/caches
|
|
||||||
~/.gradle/wrapper
|
|
||||||
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
|
||||||
- uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: prebuild.tar
|
|
||||||
- name: Extract build cache
|
|
||||||
run: tar -xf prebuild.tar
|
|
||||||
- name: Unit tests
|
- name: Unit tests
|
||||||
run: |
|
run: |
|
||||||
./gradlew --build-cache -Pcoverage testFdroidDebugUnitTest --stacktrace
|
./gradlew --build-cache -Pcoverage testFdroidDebugUnitTest --stacktrace
|
||||||
@ -65,49 +35,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
flags: unit
|
flags: unit
|
||||||
|
|
||||||
instrumentation-tests:
|
|
||||||
name: Instrumentation tests
|
|
||||||
runs-on: macOS-latest
|
|
||||||
timeout-minutes: 15
|
|
||||||
needs: [ build ]
|
|
||||||
strategy:
|
|
||||||
fail-fast: true
|
|
||||||
matrix:
|
|
||||||
api-level: [21, 29]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions/setup-java@v1
|
|
||||||
with:
|
|
||||||
java-version: 11
|
|
||||||
- uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.gradle/caches
|
|
||||||
~/.gradle/wrapper
|
|
||||||
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
|
||||||
- uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: prebuild.tar
|
|
||||||
- name: Extract build cache
|
|
||||||
run: tar -xf prebuild.tar
|
|
||||||
- name: Instrumentation tests
|
|
||||||
uses: reactivecircus/android-emulator-runner@v2
|
|
||||||
with:
|
|
||||||
api-level: ${{ matrix.api-level }}
|
|
||||||
arch: x86
|
|
||||||
script: |
|
|
||||||
./gradlew --build-cache -Pcoverage connectedFdroidDebugAndroidTest --stacktrace
|
|
||||||
./gradlew --build-cache -Pcoverage jacocoTestReport --stacktrace
|
|
||||||
- uses: codecov/codecov-action@v1
|
|
||||||
with:
|
|
||||||
flags: instrumented,api-${{ matrix.api-level }}
|
|
||||||
|
|
||||||
deploy-google-play:
|
deploy-google-play:
|
||||||
name: Deploy to google play
|
name: Deploy to google play
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
environment: google-play
|
environment: google-play
|
||||||
needs: [ build, unit-tests, instrumentation-tests ]
|
needs: [ unit-tests ]
|
||||||
if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
|
if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@ -120,11 +53,6 @@ jobs:
|
|||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
~/.gradle/wrapper
|
~/.gradle/wrapper
|
||||||
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||||
- uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: prebuild.tar
|
|
||||||
- name: Extract build cache
|
|
||||||
run: tar -xf prebuild.tar
|
|
||||||
- name: Decrypt keys
|
- name: Decrypt keys
|
||||||
env:
|
env:
|
||||||
ENCRYPT_KEY: ${{ secrets.ENCRYPT_KEY }}
|
ENCRYPT_KEY: ${{ secrets.ENCRYPT_KEY }}
|
||||||
|
11
README.en.md
11
README.en.md
@ -12,7 +12,7 @@ Unofficial android VULCAN UONET+ register client for both students and their par
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* logging in using the email and password OR using token and pin
|
* logging in using the email and password
|
||||||
* functions from the register website:
|
* functions from the register website:
|
||||||
* grades
|
* grades
|
||||||
* grade statistics
|
* grade statistics
|
||||||
@ -25,15 +25,19 @@ Unofficial android VULCAN UONET+ register client for both students and their par
|
|||||||
* homework
|
* homework
|
||||||
* notes
|
* notes
|
||||||
* lucky number
|
* lucky number
|
||||||
|
* additional lessons
|
||||||
|
* school conferences
|
||||||
|
* student and school information
|
||||||
* calculation of the average independently of school's preferences
|
* calculation of the average independently of school's preferences
|
||||||
* notifications, e.g. about a new grade
|
* notifications, e.g. about a new grade
|
||||||
|
* support for multiple accounts with the ability to rename students
|
||||||
* dark and black (AMOLED) theme
|
* dark and black (AMOLED) theme
|
||||||
* offline mode
|
* offline mode
|
||||||
* no ads
|
* no ads
|
||||||
|
|
||||||
## Download
|
## Download
|
||||||
|
|
||||||
You can download the current beta version from the Google Play, F-Droid or Huawei AppGallery store
|
You can download the current version from the Google Play, F-Droid or Huawei AppGallery store
|
||||||
|
|
||||||
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
|
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
|
||||||
alt="Get it on Google Play"
|
alt="Get it on Google Play"
|
||||||
@ -60,6 +64,9 @@ You can also download a [development version](https://wulkanowy.github.io/#downl
|
|||||||
|
|
||||||
Please contribute to the project either by creating a PR or submitting an issue on GitHub.
|
Please contribute to the project either by creating a PR or submitting an issue on GitHub.
|
||||||
|
|
||||||
|
For people interested in translating the application into different languages, we provide Crowdin
|
||||||
|
https://crowdin.com/project/wulkanowy2
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details
|
This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details
|
||||||
|
11
README.md
11
README.md
@ -12,7 +12,7 @@ Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
|
|||||||
|
|
||||||
## Funkcje
|
## Funkcje
|
||||||
|
|
||||||
* logowanie za pomocą e-maila i hasła LUB tokena i pinu
|
* logowanie za pomocą e-maila i hasła
|
||||||
* funkcje ze strony internetowej dziennika:
|
* funkcje ze strony internetowej dziennika:
|
||||||
* oceny
|
* oceny
|
||||||
* statystyki ocen
|
* statystyki ocen
|
||||||
@ -25,15 +25,19 @@ Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
|
|||||||
* zadania domowe
|
* zadania domowe
|
||||||
* uwagi
|
* uwagi
|
||||||
* szczęśliwy numerek
|
* szczęśliwy numerek
|
||||||
|
* dodatkowe lekcje
|
||||||
|
* zebrania w szkole
|
||||||
|
* informacje o uczniu i szkole
|
||||||
* obliczanie średniej niezależnie od preferencji szkoły
|
* obliczanie średniej niezależnie od preferencji szkoły
|
||||||
* powiadomienia np. o nowej ocenie
|
* powiadomienia np. o nowej ocenie
|
||||||
|
* obsługa wielu kont wraz z możliwością zmiany nazwy ucznia
|
||||||
* ciemny i czarny (AMOLED) motyw
|
* ciemny i czarny (AMOLED) motyw
|
||||||
* tryb offilne
|
* tryb offilne
|
||||||
* brak reklam
|
* brak reklam
|
||||||
|
|
||||||
## Pobierz
|
## Pobierz
|
||||||
|
|
||||||
Aktualną wersję beta możesz pobrać ze sklepu Google Play, F-Droid lub Huawei AppGallery
|
Aktualną wersję możesz pobrać ze sklepu Google Play, F-Droid lub Huawei AppGallery
|
||||||
|
|
||||||
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
|
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
|
||||||
alt="Pobierz z Google Play"
|
alt="Pobierz z Google Play"
|
||||||
@ -61,6 +65,9 @@ Możesz także pobrać [wersję rozwojową](https://wulkanowy.github.io/#downloa
|
|||||||
|
|
||||||
Wnieś swój wkład w projekt, tworząc PR lub wysyłając issue na GitHub.
|
Wnieś swój wkład w projekt, tworząc PR lub wysyłając issue na GitHub.
|
||||||
|
|
||||||
|
Dla osób zainteresowanych tłumaczeniem aplikacji na różne języki udostępniamy Crowdina
|
||||||
|
https://crowdin.com/project/wulkanowy2
|
||||||
|
|
||||||
## Licencja
|
## Licencja
|
||||||
|
|
||||||
Ten projekt udostępniany jest na licencji Apache License 2.0 - szczegóły w pliku [LICENSE](LICENSE)
|
Ten projekt udostępniany jest na licencji Apache License 2.0 - szczegóły w pliku [LICENSE](LICENSE)
|
||||||
|
@ -18,8 +18,8 @@ android {
|
|||||||
testApplicationId "io.github.tests.wulkanowy"
|
testApplicationId "io.github.tests.wulkanowy"
|
||||||
minSdkVersion 17
|
minSdkVersion 17
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 84
|
versionCode 86
|
||||||
versionName "1.0.0"
|
versionName "1.1.0"
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
@ -41,7 +41,8 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
|
// https://github.com/robolectric/robolectric/issues/3928#issuecomment-395309991
|
||||||
|
debug.assets.srcDirs += files("$projectDir/schemas".toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
@ -103,6 +104,10 @@ android {
|
|||||||
disable 'HardwareIds'
|
disable 'HardwareIds'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testOptions.unitTests {
|
||||||
|
includeAndroidResources = true
|
||||||
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
coreLibraryDesugaringEnabled true
|
coreLibraryDesugaringEnabled true
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
@ -128,32 +133,32 @@ play {
|
|||||||
serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") ?: "jan@fakelog.cf"
|
serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") ?: "jan@fakelog.cf"
|
||||||
serviceAccountCredentials = file('key.p12')
|
serviceAccountCredentials = file('key.p12')
|
||||||
defaultToAppBundles = false
|
defaultToAppBundles = false
|
||||||
track = 'alpha'
|
track = 'production'
|
||||||
updatePriority = 3
|
updatePriority = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
work_manager = "2.5.0"
|
work_manager = "2.5.0"
|
||||||
work_hilt = "1.0.0-alpha03"
|
work_hilt = "1.0.0-alpha03"
|
||||||
room = "2.3.0-beta01"
|
room = "2.3.0-beta02"
|
||||||
chucker = "3.4.0"
|
chucker = "3.4.0"
|
||||||
mockk = "1.10.5"
|
mockk = "1.10.6"
|
||||||
moshi = "1.11.0"
|
moshi = "1.11.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "io.github.wulkanowy:sdk:1.0.0"
|
implementation "io.github.wulkanowy:sdk:1.1.0"
|
||||||
|
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2'
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2'
|
||||||
|
|
||||||
implementation "androidx.core:core-ktx:1.3.2"
|
implementation "androidx.core:core-ktx:1.3.2"
|
||||||
implementation "androidx.activity:activity-ktx:1.1.0"
|
implementation "androidx.activity:activity-ktx:1.2.0"
|
||||||
implementation "androidx.appcompat:appcompat:1.2.0"
|
implementation "androidx.appcompat:appcompat:1.2.0"
|
||||||
implementation "androidx.appcompat:appcompat-resources:1.2.0"
|
implementation "androidx.appcompat:appcompat-resources:1.2.0"
|
||||||
implementation "androidx.fragment:fragment-ktx:1.2.5"
|
implementation "androidx.fragment:fragment-ktx:1.3.0"
|
||||||
implementation "androidx.annotation:annotation:1.1.0"
|
implementation "androidx.annotation:annotation:1.1.0"
|
||||||
implementation "androidx.multidex:multidex:2.0.1"
|
implementation "androidx.multidex:multidex:2.0.1"
|
||||||
|
|
||||||
@ -163,14 +168,15 @@ dependencies {
|
|||||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||||
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
|
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
|
||||||
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
|
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
|
||||||
implementation "com.google.android.material:material:1.3.0-rc01"
|
implementation "com.google.android.material:material:1.3.0"
|
||||||
implementation "com.github.wulkanowy:material-chips-input:2.1.1"
|
implementation "com.github.wulkanowy:material-chips-input:2.1.1"
|
||||||
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
|
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
|
||||||
|
implementation 'com.mikhaellopez:circularimageview:4.2.0'
|
||||||
|
|
||||||
implementation "androidx.work:work-runtime-ktx:$work_manager"
|
implementation "androidx.work:work-runtime-ktx:$work_manager"
|
||||||
playImplementation "androidx.work:work-gcm:$work_manager"
|
playImplementation "androidx.work:work-gcm:$work_manager"
|
||||||
|
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.0"
|
||||||
|
|
||||||
implementation "androidx.room:room-runtime:$room"
|
implementation "androidx.room:room-runtime:$room"
|
||||||
implementation "androidx.room:room-ktx:$room"
|
implementation "androidx.room:room-ktx:$room"
|
||||||
@ -197,7 +203,7 @@ dependencies {
|
|||||||
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
|
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
|
||||||
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
|
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
|
||||||
|
|
||||||
playImplementation platform('com.google.firebase:firebase-bom:26.4.0')
|
playImplementation platform('com.google.firebase:firebase-bom:26.6.0')
|
||||||
playImplementation 'com.google.firebase:firebase-analytics-ktx'
|
playImplementation 'com.google.firebase:firebase-analytics-ktx'
|
||||||
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx'
|
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx'
|
||||||
playImplementation "com.google.firebase:firebase-inappmessaging-ktx"
|
playImplementation "com.google.firebase:firebase-inappmessaging-ktx"
|
||||||
@ -206,24 +212,31 @@ dependencies {
|
|||||||
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
||||||
playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
|
playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
|
||||||
|
|
||||||
hmsImplementation 'com.huawei.hms:hianalytics:5.1.0.301'
|
hmsImplementation 'com.huawei.hms:hianalytics:5.2.0.300'
|
||||||
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.5.0.200'
|
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.5.0.300'
|
||||||
|
|
||||||
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
||||||
|
|
||||||
debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker"
|
debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker"
|
||||||
debugImplementation "com.amitshekhar.android:debug-db:1.0.6"
|
debugImplementation "com.amitshekhar.android:debug-db:1.0.6"
|
||||||
|
|
||||||
testImplementation "junit:junit:4.13.1"
|
testImplementation "junit:junit:4.13.2"
|
||||||
testImplementation "io.mockk:mockk:$mockk"
|
testImplementation "io.mockk:mockk:$mockk"
|
||||||
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2'
|
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2'
|
||||||
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
|
|
||||||
|
testImplementation 'org.robolectric:robolectric:4.5.1'
|
||||||
|
testImplementation "androidx.test:runner:1.3.0"
|
||||||
|
testImplementation "androidx.test.ext:junit:1.1.2"
|
||||||
|
testImplementation "androidx.test:core:1.3.0"
|
||||||
|
testImplementation "androidx.room:room-testing:$room"
|
||||||
|
testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
|
||||||
|
kaptTest "com.google.dagger:hilt-android-compiler:$hilt_version"
|
||||||
|
|
||||||
androidTestImplementation "androidx.test:core:1.3.0"
|
androidTestImplementation "androidx.test:core:1.3.0"
|
||||||
androidTestImplementation "androidx.test:runner:1.3.0"
|
androidTestImplementation "androidx.test:runner:1.3.0"
|
||||||
androidTestImplementation "androidx.test.ext:junit:1.1.2"
|
androidTestImplementation "androidx.test.ext:junit:1.1.2"
|
||||||
androidTestImplementation "io.mockk:mockk-android:$mockk"
|
androidTestImplementation "io.mockk:mockk-android:$mockk"
|
||||||
androidTestImplementation "androidx.room:room-testing:$room"
|
|
||||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2142
app/schemas/io.github.wulkanowy.data.db.AppDatabase/34.json
Normal file
2142
app/schemas/io.github.wulkanowy.data.db.AppDatabase/34.json
Normal file
File diff suppressed because it is too large
Load Diff
2148
app/schemas/io.github.wulkanowy.data.db.AppDatabase/35.json
Normal file
2148
app/schemas/io.github.wulkanowy.data.db.AppDatabase/35.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -56,7 +56,7 @@
|
|||||||
android:name=".ui.modules.login.LoginActivity"
|
android:name=".ui.modules.login.LoginActivity"
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:label="@string/login_title"
|
android:label="@string/login_title"
|
||||||
android:theme="@style/WulkanowyTheme.NoActionBar"
|
android:theme="@style/WulkanowyTheme.Login"
|
||||||
android:windowSoftInputMode="adjustResize" />
|
android:windowSoftInputMode="adjustResize" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.modules.main.MainActivity"
|
android:name=".ui.modules.main.MainActivity"
|
||||||
@ -68,7 +68,7 @@
|
|||||||
android:name=".ui.modules.message.send.SendMessageActivity"
|
android:name=".ui.modules.message.send.SendMessageActivity"
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:label="@string/send_message_title"
|
android:label="@string/send_message_title"
|
||||||
android:theme="@style/WulkanowyTheme.NoActionBar"
|
android:theme="@style/WulkanowyTheme.MessageSend"
|
||||||
android:windowSoftInputMode="adjustResize" />
|
android:windowSoftInputMode="adjustResize" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.modules.timetablewidget.TimetableWidgetConfigureActivity"
|
android:name=".ui.modules.timetablewidget.TimetableWidgetConfigureActivity"
|
||||||
|
@ -38,5 +38,13 @@
|
|||||||
{
|
{
|
||||||
"displayName": "MRmlik12",
|
"displayName": "MRmlik12",
|
||||||
"githubUsername": "MRmlik12"
|
"githubUsername": "MRmlik12"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Damian Czupryn",
|
||||||
|
"githubUsername": "Daxxxis"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Kamil Studziński",
|
||||||
|
"githubUsername": "studzinskik"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package io.github.wulkanowy
|
package io.github.wulkanowy
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log.DEBUG
|
import android.util.Log.DEBUG
|
||||||
import android.util.Log.INFO
|
import android.util.Log.INFO
|
||||||
import android.util.Log.VERBOSE
|
import android.util.Log.VERBOSE
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.hilt.work.HiltWorkerFactory
|
import androidx.hilt.work.HiltWorkerFactory
|
||||||
import androidx.multidex.MultiDex
|
import androidx.multidex.MultiDex
|
||||||
import androidx.work.Configuration
|
import androidx.work.Configuration
|
||||||
@ -46,9 +48,10 @@ class WulkanowyApp : Application(), Configuration.Provider {
|
|||||||
MultiDex.install(this)
|
MultiDex.install(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("UnsafeOptInUsageWarning")
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
FragmentManager.enableNewStateManager(false)
|
||||||
initializeAppLanguage()
|
initializeAppLanguage()
|
||||||
themeManager.applyDefaultTheme()
|
themeManager.applyDefaultTheme()
|
||||||
initLogging()
|
initLogging()
|
||||||
|
@ -17,6 +17,7 @@ import io.github.wulkanowy.data.db.AppDatabase
|
|||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -60,7 +61,8 @@ internal class RepositoryModule {
|
|||||||
fun provideDatabase(
|
fun provideDatabase(
|
||||||
@ApplicationContext context: Context,
|
@ApplicationContext context: Context,
|
||||||
sharedPrefProvider: SharedPrefProvider,
|
sharedPrefProvider: SharedPrefProvider,
|
||||||
) = AppDatabase.newInstance(context, sharedPrefProvider)
|
appInfo: AppInfo
|
||||||
|
) = AppDatabase.newInstance(context, sharedPrefProvider, appInfo)
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -6,7 +6,6 @@ import androidx.room.Room
|
|||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
import androidx.room.RoomDatabase.JournalMode.TRUNCATE
|
import androidx.room.RoomDatabase.JournalMode.TRUNCATE
|
||||||
import androidx.room.TypeConverters
|
import androidx.room.TypeConverters
|
||||||
import androidx.room.migration.Migration
|
|
||||||
import io.github.wulkanowy.data.db.dao.AttendanceDao
|
import io.github.wulkanowy.data.db.dao.AttendanceDao
|
||||||
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
|
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
|
||||||
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
|
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
|
||||||
@ -85,12 +84,15 @@ import io.github.wulkanowy.data.db.migrations.Migration30
|
|||||||
import io.github.wulkanowy.data.db.migrations.Migration31
|
import io.github.wulkanowy.data.db.migrations.Migration31
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration32
|
import io.github.wulkanowy.data.db.migrations.Migration32
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration33
|
import io.github.wulkanowy.data.db.migrations.Migration33
|
||||||
|
import io.github.wulkanowy.data.db.migrations.Migration34
|
||||||
|
import io.github.wulkanowy.data.db.migrations.Migration35
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration4
|
import io.github.wulkanowy.data.db.migrations.Migration4
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration5
|
import io.github.wulkanowy.data.db.migrations.Migration5
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration6
|
import io.github.wulkanowy.data.db.migrations.Migration6
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration7
|
import io.github.wulkanowy.data.db.migrations.Migration7
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration8
|
import io.github.wulkanowy.data.db.migrations.Migration8
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration9
|
import io.github.wulkanowy.data.db.migrations.Migration9
|
||||||
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@ -130,10 +132,9 @@ import javax.inject.Singleton
|
|||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val VERSION_SCHEMA = 33
|
const val VERSION_SCHEMA = 35
|
||||||
|
|
||||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> {
|
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
||||||
return arrayOf(
|
|
||||||
Migration2(),
|
Migration2(),
|
||||||
Migration3(),
|
Migration3(),
|
||||||
Migration4(),
|
Migration4(),
|
||||||
@ -165,19 +166,22 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
Migration30(),
|
Migration30(),
|
||||||
Migration31(),
|
Migration31(),
|
||||||
Migration32(),
|
Migration32(),
|
||||||
Migration33()
|
Migration33(),
|
||||||
|
Migration34(),
|
||||||
|
Migration35(appInfo)
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
fun newInstance(context: Context, sharedPrefProvider: SharedPrefProvider): AppDatabase {
|
fun newInstance(
|
||||||
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
|
context: Context,
|
||||||
|
sharedPrefProvider: SharedPrefProvider,
|
||||||
|
appInfo: AppInfo
|
||||||
|
) = Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
|
||||||
.setJournalMode(TRUNCATE)
|
.setJournalMode(TRUNCATE)
|
||||||
.fallbackToDestructiveMigrationFrom(VERSION_SCHEMA + 1)
|
.fallbackToDestructiveMigrationFrom(VERSION_SCHEMA + 1)
|
||||||
.fallbackToDestructiveMigrationOnDowngrade()
|
.fallbackToDestructiveMigrationOnDowngrade()
|
||||||
.addMigrations(*getMigrations(sharedPrefProvider))
|
.addMigrations(*getMigrations(sharedPrefProvider, appInfo))
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
abstract val studentDao: StudentDao
|
abstract val studentDao: StudentDao
|
||||||
|
|
||||||
|
@ -13,4 +13,7 @@ interface LuckyNumberDao : BaseDao<LuckyNumber> {
|
|||||||
|
|
||||||
@Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date = :date")
|
@Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date = :date")
|
||||||
fun load(studentId: Int, date: LocalDate): Flow<LuckyNumber?>
|
fun load(studentId: Int, date: LocalDate): Flow<LuckyNumber?>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date >= :start AND date <= :end")
|
||||||
|
fun getAll(studentId: Int, start: LocalDate, end: LocalDate): Flow<List<LuckyNumber>>
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import androidx.room.Query
|
|||||||
import androidx.room.Transaction
|
import androidx.room.Transaction
|
||||||
import androidx.room.Update
|
import androidx.room.Update
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.db.entities.StudentNick
|
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -23,13 +23,13 @@ interface StudentDao {
|
|||||||
suspend fun delete(student: Student)
|
suspend fun delete(student: Student)
|
||||||
|
|
||||||
@Update(entity = Student::class)
|
@Update(entity = Student::class)
|
||||||
suspend fun update(studentNick: StudentNick)
|
suspend fun update(studentNickAndAvatar: StudentNickAndAvatar)
|
||||||
|
|
||||||
@Query("SELECT * FROM Students WHERE is_current = 1")
|
@Query("SELECT * FROM Students WHERE is_current = 1")
|
||||||
suspend fun loadCurrent(): Student?
|
suspend fun loadCurrent(): Student?
|
||||||
|
|
||||||
@Query("SELECT * FROM Students WHERE id = :id")
|
@Query("SELECT * FROM Students WHERE id = :id")
|
||||||
suspend fun loadById(id: Int): Student?
|
suspend fun loadById(id: Long): Student?
|
||||||
|
|
||||||
@Query("SELECT * FROM Students")
|
@Query("SELECT * FROM Students")
|
||||||
suspend fun loadAll(): List<Student>
|
suspend fun loadAll(): List<Student>
|
||||||
|
@ -10,7 +10,7 @@ import java.time.LocalDateTime
|
|||||||
data class Message(
|
data class Message(
|
||||||
|
|
||||||
@ColumnInfo(name = "student_id")
|
@ColumnInfo(name = "student_id")
|
||||||
val studentId: Int,
|
val studentId: Long,
|
||||||
|
|
||||||
@ColumnInfo(name = "real_id")
|
@ColumnInfo(name = "real_id")
|
||||||
val realId: Int,
|
val realId: Int,
|
||||||
|
@ -81,4 +81,7 @@ data class Student(
|
|||||||
var id: Long = 0
|
var id: Long = 0
|
||||||
|
|
||||||
var nick = ""
|
var nick = ""
|
||||||
|
|
||||||
|
@ColumnInfo(name = "avatar_color")
|
||||||
|
var avatarColor = 0L
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
package io.github.wulkanowy.data.db.entities
|
package io.github.wulkanowy.data.db.entities
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
data class StudentNick(
|
data class StudentNickAndAvatar(
|
||||||
|
|
||||||
val nick: String
|
val nick: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "avatar_color")
|
||||||
|
var avatarColor: Long
|
||||||
|
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
|
|
@ -0,0 +1,13 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration34 : Migration(33, 34) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DELETE FROM ReportingUnits")
|
||||||
|
database.execSQL("DELETE FROM Recipients")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.core.database.getLongOrNull
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
|
|
||||||
|
class Migration35(private val appInfo: AppInfo) : Migration(34, 35) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("ALTER TABLE Students ADD COLUMN `avatar_color` INTEGER NOT NULL DEFAULT 0")
|
||||||
|
|
||||||
|
val studentsCursor = database.query("SELECT * FROM Students")
|
||||||
|
|
||||||
|
while (studentsCursor.moveToNext()) {
|
||||||
|
val studentId = studentsCursor.getLongOrNull(0)
|
||||||
|
database.execSQL(
|
||||||
|
"""UPDATE Students
|
||||||
|
SET avatar_color = ${appInfo.defaultColorsForAvatar.random()}
|
||||||
|
WHERE id = $studentId"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,10 +5,9 @@ import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
|||||||
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
|
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
|
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
|
||||||
import io.github.wulkanowy.ui.modules.grade.statistics.ViewType
|
|
||||||
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSubject as SdkGradeStatisticsSubject
|
|
||||||
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSemester as SdkGradeStatisticsSemester
|
|
||||||
import io.github.wulkanowy.sdk.pojo.GradePointsStatistics as SdkGradePointsStatistics
|
import io.github.wulkanowy.sdk.pojo.GradePointsStatistics as SdkGradePointsStatistics
|
||||||
|
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSemester as SdkGradeStatisticsSemester
|
||||||
|
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSubject as SdkGradeStatisticsSubject
|
||||||
|
|
||||||
@JvmName("mapToEntitiesSubject")
|
@JvmName("mapToEntitiesSubject")
|
||||||
fun List<SdkGradeStatisticsSubject>.mapToEntities(semester: Semester) = map {
|
fun List<SdkGradeStatisticsSubject>.mapToEntities(semester: Semester) = map {
|
||||||
@ -51,7 +50,7 @@ fun List<SdkGradePointsStatistics>.mapToEntities(semester: Semester) = map {
|
|||||||
|
|
||||||
fun List<GradePartialStatistics>.mapPartialToStatisticItems() = filterNot { it.classAmounts.isEmpty() }.map {
|
fun List<GradePartialStatistics>.mapPartialToStatisticItems() = filterNot { it.classAmounts.isEmpty() }.map {
|
||||||
GradeStatisticsItem(
|
GradeStatisticsItem(
|
||||||
type = ViewType.PARTIAL,
|
type = GradeStatisticsItem.DataType.PARTIAL,
|
||||||
average = it.classAverage,
|
average = it.classAverage,
|
||||||
partial = it,
|
partial = it,
|
||||||
points = null,
|
points = null,
|
||||||
@ -61,7 +60,7 @@ fun List<GradePartialStatistics>.mapPartialToStatisticItems() = filterNot { it.c
|
|||||||
|
|
||||||
fun List<GradeSemesterStatistics>.mapSemesterToStatisticItems() = filterNot { it.amounts.isEmpty() }.map {
|
fun List<GradeSemesterStatistics>.mapSemesterToStatisticItems() = filterNot { it.amounts.isEmpty() }.map {
|
||||||
GradeStatisticsItem(
|
GradeStatisticsItem(
|
||||||
type = ViewType.SEMESTER,
|
type = GradeStatisticsItem.DataType.SEMESTER,
|
||||||
partial = null,
|
partial = null,
|
||||||
points = null,
|
points = null,
|
||||||
average = "",
|
average = "",
|
||||||
@ -71,7 +70,7 @@ fun List<GradeSemesterStatistics>.mapSemesterToStatisticItems() = filterNot { it
|
|||||||
|
|
||||||
fun List<GradePointsStatistics>.mapPointsToStatisticsItems() = map {
|
fun List<GradePointsStatistics>.mapPointsToStatisticsItems() = map {
|
||||||
GradeStatisticsItem(
|
GradeStatisticsItem(
|
||||||
type = ViewType.POINTS,
|
type = GradeStatisticsItem.DataType.POINTS,
|
||||||
partial = null,
|
partial = null,
|
||||||
semester = null,
|
semester = null,
|
||||||
average = "",
|
average = "",
|
||||||
|
@ -4,14 +4,14 @@ import io.github.wulkanowy.data.db.entities.Message
|
|||||||
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
|
|
||||||
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
|
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
|
import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
|
||||||
|
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
|
||||||
|
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
|
||||||
|
|
||||||
fun List<SdkMessage>.mapToEntities(student: Student) = map {
|
fun List<SdkMessage>.mapToEntities(student: Student) = map {
|
||||||
Message(
|
Message(
|
||||||
studentId = student.id.toInt(),
|
studentId = student.id,
|
||||||
realId = it.id ?: 0,
|
realId = it.id ?: 0,
|
||||||
messageId = it.messageId ?: 0,
|
messageId = it.messageId ?: 0,
|
||||||
sender = it.sender?.name.orEmpty(),
|
sender = it.sender?.name.orEmpty(),
|
||||||
|
@ -5,7 +5,7 @@ import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
|||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import io.github.wulkanowy.sdk.pojo.Student as SdkStudent
|
import io.github.wulkanowy.sdk.pojo.Student as SdkStudent
|
||||||
|
|
||||||
fun List<SdkStudent>.mapToEntities(password: String = "") = map {
|
fun List<SdkStudent>.mapToEntities(password: String = "", colors: List<Long>) = map {
|
||||||
StudentWithSemesters(
|
StudentWithSemesters(
|
||||||
student = Student(
|
student = Student(
|
||||||
email = it.email,
|
email = it.email,
|
||||||
@ -28,8 +28,10 @@ fun List<SdkStudent>.mapToEntities(password: String = "") = map {
|
|||||||
mobileBaseUrl = it.mobileBaseUrl,
|
mobileBaseUrl = it.mobileBaseUrl,
|
||||||
privateKey = it.privateKey,
|
privateKey = it.privateKey,
|
||||||
certificateKey = it.certificateKey,
|
certificateKey = it.certificateKey,
|
||||||
loginMode = it.loginMode.name
|
loginMode = it.loginMode.name,
|
||||||
),
|
).apply {
|
||||||
|
avatarColor = colors.random()
|
||||||
|
},
|
||||||
semesters = it.semesters.mapToEntities(it.studentId)
|
semesters = it.semesters.mapToEntities(it.studentId)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,10 @@ package io.github.wulkanowy.data.pojos
|
|||||||
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
|
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
|
||||||
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
||||||
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
|
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
|
||||||
import io.github.wulkanowy.ui.modules.grade.statistics.ViewType
|
|
||||||
|
|
||||||
data class GradeStatisticsItem(
|
data class GradeStatisticsItem(
|
||||||
|
|
||||||
val type: ViewType,
|
val type: DataType,
|
||||||
|
|
||||||
val average: String,
|
val average: String,
|
||||||
|
|
||||||
@ -16,4 +15,11 @@ data class GradeStatisticsItem(
|
|||||||
val semester: GradeSemesterStatistics?,
|
val semester: GradeSemesterStatistics?,
|
||||||
|
|
||||||
val points: GradePointsStatistics?
|
val points: GradePointsStatistics?
|
||||||
)
|
|
||||||
|
) {
|
||||||
|
enum class DataType {
|
||||||
|
SEMESTER,
|
||||||
|
PARTIAL,
|
||||||
|
POINTS,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -14,6 +14,7 @@ import io.github.wulkanowy.utils.monday
|
|||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
import io.github.wulkanowy.utils.sunday
|
import io.github.wulkanowy.utils.sunday
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.LocalTime
|
import java.time.LocalTime
|
||||||
@ -27,9 +28,12 @@ class AttendanceRepository @Inject constructor(
|
|||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private val cacheKey = "attendance"
|
private val cacheKey = "attendance"
|
||||||
|
|
||||||
fun getAttendance(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
|
fun getAttendance(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
||||||
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday) },
|
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday) },
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -10,6 +10,7 @@ import io.github.wulkanowy.utils.getRefreshKey
|
|||||||
import io.github.wulkanowy.utils.init
|
import io.github.wulkanowy.utils.init
|
||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -20,9 +21,12 @@ class AttendanceSummaryRepository @Inject constructor(
|
|||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private val cacheKey = "attendance_summary"
|
private val cacheKey = "attendance_summary"
|
||||||
|
|
||||||
fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int, forceRefresh: Boolean) = networkBoundResource(
|
fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int, forceRefresh: Boolean) = networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
|
||||||
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId) },
|
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -12,6 +12,7 @@ import io.github.wulkanowy.utils.monday
|
|||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
import io.github.wulkanowy.utils.sunday
|
import io.github.wulkanowy.utils.sunday
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@ -23,9 +24,12 @@ class CompletedLessonsRepository @Inject constructor(
|
|||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private val cacheKey = "completed"
|
private val cacheKey = "completed"
|
||||||
|
|
||||||
fun getCompletedLessons(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
|
fun getCompletedLessons(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
||||||
query = { completedLessonsDb.loadAll(semester.studentId, semester.diaryId, start.monday, end.sunday) },
|
query = { completedLessonsDb.loadAll(semester.studentId, semester.diaryId, start.monday, end.sunday) },
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -10,6 +10,7 @@ import io.github.wulkanowy.utils.getRefreshKey
|
|||||||
import io.github.wulkanowy.utils.init
|
import io.github.wulkanowy.utils.init
|
||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -20,9 +21,12 @@ class ConferenceRepository @Inject constructor(
|
|||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private val cacheKey = "conference"
|
private val cacheKey = "conference"
|
||||||
|
|
||||||
fun getConferences(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
|
fun getConferences(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
|
||||||
query = { conferenceDb.loadAll(semester.diaryId, student.studentId) },
|
query = { conferenceDb.loadAll(semester.diaryId, student.studentId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -12,6 +12,7 @@ import io.github.wulkanowy.utils.init
|
|||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
import io.github.wulkanowy.utils.startExamsDay
|
import io.github.wulkanowy.utils.startExamsDay
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@ -23,9 +24,12 @@ class ExamRepository @Inject constructor(
|
|||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private val cacheKey = "exam"
|
private val cacheKey = "exam"
|
||||||
|
|
||||||
fun getExams(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
|
fun getExams(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
||||||
query = { examDb.loadAll(semester.diaryId, semester.studentId, start.startExamsDay, start.endExamsDay) },
|
query = { examDb.loadAll(semester.diaryId, semester.studentId, start.startExamsDay, start.endExamsDay) },
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -16,6 +16,7 @@ import io.github.wulkanowy.utils.uniqueSubtract
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@ -28,14 +29,20 @@ class GradeRepository @Inject constructor(
|
|||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private val cacheKey = "grade"
|
private val cacheKey = "grade"
|
||||||
|
|
||||||
fun getGrades(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
|
fun getGrades(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
|
||||||
shouldFetch = { (details, summaries) -> details.isEmpty() || summaries.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
|
mutex = saveFetchResultMutex,
|
||||||
|
shouldFetch = { (details, summaries) ->
|
||||||
|
val isShouldBeRefreshed = refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||||
|
details.isEmpty() || summaries.isEmpty() || forceRefresh || isShouldBeRefreshed
|
||||||
|
},
|
||||||
query = {
|
query = {
|
||||||
gradeDb.loadAll(semester.semesterId, semester.studentId).combine(gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)) { details, summaries ->
|
val detailsFlow = gradeDb.loadAll(semester.semesterId, semester.studentId)
|
||||||
details to summaries
|
val summaryFlow = gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)
|
||||||
}
|
detailsFlow.combine(summaryFlow) { details, summaries -> details to summaries }
|
||||||
},
|
},
|
||||||
fetch = {
|
fetch = {
|
||||||
val (details, summary) = sdk.init(student)
|
val (details, summary) = sdk.init(student)
|
||||||
@ -92,19 +99,27 @@ class GradeRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getUnreadGrades(semester: Semester): Flow<List<Grade>> {
|
fun getUnreadGrades(semester: Semester): Flow<List<Grade>> {
|
||||||
return gradeDb.loadAll(semester.semesterId, semester.studentId).map { it.filter { grade -> !grade.isRead } }
|
return gradeDb.loadAll(semester.semesterId, semester.studentId).map {
|
||||||
|
it.filter { grade -> !grade.isRead }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNotNotifiedGrades(semester: Semester): Flow<List<Grade>> {
|
fun getNotNotifiedGrades(semester: Semester): Flow<List<Grade>> {
|
||||||
return gradeDb.loadAll(semester.semesterId, semester.studentId).map { it.filter { grade -> !grade.isNotified } }
|
return gradeDb.loadAll(semester.semesterId, semester.studentId).map {
|
||||||
|
it.filter { grade -> !grade.isNotified }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNotNotifiedPredictedGrades(semester: Semester): Flow<List<GradeSummary>> {
|
fun getNotNotifiedPredictedGrades(semester: Semester): Flow<List<GradeSummary>> {
|
||||||
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).map { it.filter { gradeSummary -> !gradeSummary.isPredictedGradeNotified } }
|
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).map {
|
||||||
|
it.filter { gradeSummary -> !gradeSummary.isPredictedGradeNotified }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNotNotifiedFinalGrades(semester: Semester): Flow<List<GradeSummary>> {
|
fun getNotNotifiedFinalGrades(semester: Semester): Flow<List<GradeSummary>> {
|
||||||
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).map { it.filter { gradeSummary -> !gradeSummary.isFinalGradeNotified } }
|
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).map {
|
||||||
|
it.filter { gradeSummary -> !gradeSummary.isFinalGradeNotified }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateGrade(grade: Grade) {
|
suspend fun updateGrade(grade: Grade) {
|
||||||
|
@ -17,6 +17,7 @@ import io.github.wulkanowy.utils.getRefreshKey
|
|||||||
import io.github.wulkanowy.utils.init
|
import io.github.wulkanowy.utils.init
|
||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@ -30,11 +31,16 @@ class GradeStatisticsRepository @Inject constructor(
|
|||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val partialMutex = Mutex()
|
||||||
|
private val semesterMutex = Mutex()
|
||||||
|
private val pointsMutex = Mutex()
|
||||||
|
|
||||||
private val partialCacheKey = "grade_stats_partial"
|
private val partialCacheKey = "grade_stats_partial"
|
||||||
private val semesterCacheKey = "grade_stats_semester"
|
private val semesterCacheKey = "grade_stats_semester"
|
||||||
private val pointsCacheKey = "grade_stats_points"
|
private val pointsCacheKey = "grade_stats_points"
|
||||||
|
|
||||||
fun getGradesPartialStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
|
fun getGradesPartialStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
|
||||||
|
mutex = partialMutex,
|
||||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(partialCacheKey, semester)) },
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(partialCacheKey, semester)) },
|
||||||
query = { gradePartialStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
|
query = { gradePartialStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
@ -71,6 +77,7 @@ class GradeStatisticsRepository @Inject constructor(
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun getGradesSemesterStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
|
fun getGradesSemesterStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
|
||||||
|
mutex = semesterMutex,
|
||||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(semesterCacheKey, semester)) },
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(semesterCacheKey, semester)) },
|
||||||
query = { gradeSemesterStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
|
query = { gradeSemesterStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
@ -112,6 +119,7 @@ class GradeStatisticsRepository @Inject constructor(
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun getGradesPointsStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
|
fun getGradesPointsStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
|
||||||
|
mutex = pointsMutex,
|
||||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(pointsCacheKey, semester)) },
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(pointsCacheKey, semester)) },
|
||||||
query = { gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
|
query = { gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -13,6 +13,7 @@ import io.github.wulkanowy.utils.monday
|
|||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
import io.github.wulkanowy.utils.sunday
|
import io.github.wulkanowy.utils.sunday
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@ -24,9 +25,12 @@ class HomeworkRepository @Inject constructor(
|
|||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private val cacheKey = "homework"
|
private val cacheKey = "homework"
|
||||||
|
|
||||||
fun getHomework(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
|
fun getHomework(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
||||||
query = { homeworkDb.loadAll(semester.semesterId, semester.studentId, start.monday, end.sunday) },
|
query = { homeworkDb.loadAll(semester.semesterId, semester.studentId, start.monday, end.sunday) },
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -9,6 +9,8 @@ import io.github.wulkanowy.utils.init
|
|||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import java.time.LocalDate
|
||||||
import java.time.LocalDate.now
|
import java.time.LocalDate.now
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@ -19,7 +21,10 @@ class LuckyNumberRepository @Inject constructor(
|
|||||||
private val sdk: Sdk
|
private val sdk: Sdk
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
fun getLuckyNumber(student: Student, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
|
fun getLuckyNumber(student: Student, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { it == null || forceRefresh },
|
shouldFetch = { it == null || forceRefresh },
|
||||||
query = { luckyNumberDb.load(student.studentId, now()) },
|
query = { luckyNumberDb.load(student.studentId, now()) },
|
||||||
fetch = { sdk.init(student).getLuckyNumber(student.schoolShortName)?.mapToEntity(student) },
|
fetch = { sdk.init(student).getLuckyNumber(student.schoolShortName)?.mapToEntity(student) },
|
||||||
@ -33,6 +38,9 @@ class LuckyNumberRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun getLuckyNumberHistory(student: Student, start: LocalDate, end: LocalDate) =
|
||||||
|
luckyNumberDb.getAll(student.studentId, start, end)
|
||||||
|
|
||||||
suspend fun getNotNotifiedLuckyNumber(student: Student) = luckyNumberDb.load(student.studentId, now()).map {
|
suspend fun getNotNotifiedLuckyNumber(student: Student) = luckyNumberDb.load(student.studentId, now()).map {
|
||||||
if (it?.isNotified == false) it else null
|
if (it?.isNotified == false) it else null
|
||||||
}.first()
|
}.first()
|
||||||
|
@ -20,6 +20,7 @@ import io.github.wulkanowy.utils.networkBoundResource
|
|||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.time.LocalDateTime.now
|
import java.time.LocalDateTime.now
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -33,10 +34,13 @@ class MessageRepository @Inject constructor(
|
|||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private val cacheKey = "message"
|
private val cacheKey = "message"
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
fun getMessages(student: Student, semester: Semester, folder: MessageFolder, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
|
fun getMessages(student: Student, semester: Semester, folder: MessageFolder, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, student, folder)) },
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, student, folder)) },
|
||||||
query = { messagesDb.loadAll(student.id.toInt(), folder.id) },
|
query = { messagesDb.loadAll(student.id.toInt(), folder.id) },
|
||||||
fetch = { sdk.init(student).getMessages(Folder.valueOf(folder.name), now().minusMonths(3), now()).mapToEntities(student) },
|
fetch = { sdk.init(student).getMessages(Folder.valueOf(folder.name), now().minusMonths(3), now()).mapToEntities(student) },
|
||||||
|
@ -13,6 +13,7 @@ import io.github.wulkanowy.utils.getRefreshKey
|
|||||||
import io.github.wulkanowy.utils.init
|
import io.github.wulkanowy.utils.init
|
||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -23,9 +24,12 @@ class MobileDeviceRepository @Inject constructor(
|
|||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private val cacheKey = "devices"
|
private val cacheKey = "devices"
|
||||||
|
|
||||||
fun getDevices(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
|
fun getDevices(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, student)) },
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, student)) },
|
||||||
query = { mobileDb.loadAll(student.userLoginId.takeIf { it != 0 } ?: student.studentId) },
|
query = { mobileDb.loadAll(student.userLoginId.takeIf { it != 0 } ?: student.studentId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -13,6 +13,7 @@ import io.github.wulkanowy.utils.networkBoundResource
|
|||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -23,9 +24,12 @@ class NoteRepository @Inject constructor(
|
|||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private val cacheKey = "note"
|
private val cacheKey = "note"
|
||||||
|
|
||||||
fun getNotes(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
|
fun getNotes(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
|
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
|
||||||
query = { noteDb.loadAll(student.studentId) },
|
query = { noteDb.loadAll(student.studentId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -18,26 +18,43 @@ class PreferencesRepository @Inject constructor(
|
|||||||
get() = getString(R.string.pref_key_start_menu, R.string.pref_default_startup).toInt()
|
get() = getString(R.string.pref_key_start_menu, R.string.pref_default_startup).toInt()
|
||||||
|
|
||||||
val isShowPresent: Boolean
|
val isShowPresent: Boolean
|
||||||
get() = getBoolean(R.string.pref_key_attendance_present, R.bool.pref_default_attendance_present)
|
get() = getBoolean(
|
||||||
|
R.string.pref_key_attendance_present,
|
||||||
|
R.bool.pref_default_attendance_present
|
||||||
|
)
|
||||||
|
|
||||||
val gradeAverageMode: GradeAverageMode
|
val gradeAverageMode: GradeAverageMode
|
||||||
get() = GradeAverageMode.getByValue(getString(R.string.pref_key_grade_average_mode, R.string.pref_default_grade_average_mode))
|
get() = GradeAverageMode.getByValue(
|
||||||
|
getString(
|
||||||
|
R.string.pref_key_grade_average_mode,
|
||||||
|
R.string.pref_default_grade_average_mode
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
val gradeAverageForceCalc: Boolean
|
val gradeAverageForceCalc: Boolean
|
||||||
get() = getBoolean(R.string.pref_key_grade_average_force_calc, R.bool.pref_default_grade_average_force_calc)
|
get() = getBoolean(
|
||||||
|
R.string.pref_key_grade_average_force_calc,
|
||||||
|
R.bool.pref_default_grade_average_force_calc
|
||||||
|
)
|
||||||
|
|
||||||
val isGradeExpandable: Boolean
|
val isGradeExpandable: Boolean
|
||||||
get() = !getBoolean(R.string.pref_key_expand_grade, R.bool.pref_default_expand_grade)
|
get() = !getBoolean(R.string.pref_key_expand_grade, R.bool.pref_default_expand_grade)
|
||||||
|
|
||||||
val showAllSubjectsOnStatisticsList: Boolean
|
val showAllSubjectsOnStatisticsList: Boolean
|
||||||
get() = getBoolean(R.string.pref_key_grade_statistics_list, R.bool.pref_default_grade_statistics_list)
|
get() = getBoolean(
|
||||||
|
R.string.pref_key_grade_statistics_list,
|
||||||
|
R.bool.pref_default_grade_statistics_list
|
||||||
|
)
|
||||||
|
|
||||||
val appThemeKey = context.getString(R.string.pref_key_app_theme)
|
val appThemeKey = context.getString(R.string.pref_key_app_theme)
|
||||||
val appTheme: String
|
val appTheme: String
|
||||||
get() = getString(appThemeKey, R.string.pref_default_app_theme)
|
get() = getString(appThemeKey, R.string.pref_default_app_theme)
|
||||||
|
|
||||||
val gradeColorTheme: String
|
val gradeColorTheme: String
|
||||||
get() = getString(R.string.pref_key_grade_color_scheme, R.string.pref_default_grade_color_scheme)
|
get() = 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)
|
val appLanguageKey = context.getString(R.string.pref_key_app_language)
|
||||||
val appLanguage
|
val appLanguage
|
||||||
@ -55,50 +72,86 @@ class PreferencesRepository @Inject constructor(
|
|||||||
val isServicesOnlyWifi: Boolean
|
val isServicesOnlyWifi: Boolean
|
||||||
get() = getBoolean(servicesOnlyWifiKey, R.bool.pref_default_services_wifi_only)
|
get() = getBoolean(servicesOnlyWifiKey, R.bool.pref_default_services_wifi_only)
|
||||||
|
|
||||||
|
val notificationsEnableKey = context.getString(R.string.pref_key_notifications_enable)
|
||||||
val isNotificationsEnable: Boolean
|
val isNotificationsEnable: Boolean
|
||||||
get() = getBoolean(R.string.pref_key_notifications_enable, R.bool.pref_default_notifications_enable)
|
get() = getBoolean(notificationsEnableKey, R.bool.pref_default_notifications_enable)
|
||||||
|
|
||||||
val isUpcomingLessonsNotificationsEnableKey = context.getString(R.string.pref_key_notifications_upcoming_lessons_enable)
|
val isUpcomingLessonsNotificationsEnableKey =
|
||||||
|
context.getString(R.string.pref_key_notifications_upcoming_lessons_enable)
|
||||||
val isUpcomingLessonsNotificationsEnable: Boolean
|
val isUpcomingLessonsNotificationsEnable: Boolean
|
||||||
get() = getBoolean(isUpcomingLessonsNotificationsEnableKey, R.bool.pref_default_notification_upcoming_lessons_enable)
|
get() = getBoolean(
|
||||||
|
isUpcomingLessonsNotificationsEnableKey,
|
||||||
|
R.bool.pref_default_notification_upcoming_lessons_enable
|
||||||
|
)
|
||||||
|
|
||||||
val isDebugNotificationEnableKey = context.getString(R.string.pref_key_notification_debug)
|
val isDebugNotificationEnableKey = context.getString(R.string.pref_key_notification_debug)
|
||||||
val isDebugNotificationEnable: Boolean
|
val isDebugNotificationEnable: Boolean
|
||||||
get() = getBoolean(isDebugNotificationEnableKey, R.bool.pref_default_notification_debug)
|
get() = getBoolean(isDebugNotificationEnableKey, R.bool.pref_default_notification_debug)
|
||||||
|
|
||||||
val gradePlusModifier: Double
|
val gradePlusModifier: Double
|
||||||
get() = getString(R.string.pref_key_grade_modifier_plus, R.string.pref_default_grade_modifier_plus).toDouble()
|
get() = getString(
|
||||||
|
R.string.pref_key_grade_modifier_plus,
|
||||||
|
R.string.pref_default_grade_modifier_plus
|
||||||
|
).toDouble()
|
||||||
|
|
||||||
val gradeMinusModifier: Double
|
val gradeMinusModifier: Double
|
||||||
get() = getString(R.string.pref_key_grade_modifier_minus, R.string.pref_default_grade_modifier_minus).toDouble()
|
get() = getString(
|
||||||
|
R.string.pref_key_grade_modifier_minus,
|
||||||
|
R.string.pref_default_grade_modifier_minus
|
||||||
|
).toDouble()
|
||||||
|
|
||||||
val fillMessageContent: Boolean
|
val fillMessageContent: Boolean
|
||||||
get() = getBoolean(R.string.pref_key_fill_message_content, R.bool.pref_default_fill_message_content)
|
get() = getBoolean(
|
||||||
|
R.string.pref_key_fill_message_content,
|
||||||
|
R.bool.pref_default_fill_message_content
|
||||||
|
)
|
||||||
|
|
||||||
val showGroupsInPlan: Boolean
|
val showGroupsInPlan: Boolean
|
||||||
get() = getBoolean(R.string.pref_key_timetable_show_groups, R.bool.pref_default_timetable_show_groups)
|
get() = getBoolean(
|
||||||
|
R.string.pref_key_timetable_show_groups,
|
||||||
|
R.bool.pref_default_timetable_show_groups
|
||||||
|
)
|
||||||
|
|
||||||
val showWholeClassPlan: String
|
val showWholeClassPlan: String
|
||||||
get() = getString(R.string.pref_key_timetable_show_whole_class, R.string.pref_default_timetable_show_whole_class)
|
get() = getString(
|
||||||
|
R.string.pref_key_timetable_show_whole_class,
|
||||||
|
R.string.pref_default_timetable_show_whole_class
|
||||||
|
)
|
||||||
|
|
||||||
val gradeSortingMode: GradeSortingMode
|
val gradeSortingMode: GradeSortingMode
|
||||||
get() = GradeSortingMode.getByValue(getString(R.string.pref_key_grade_sorting_mode, R.string.pref_default_grade_sorting_mode))
|
get() = GradeSortingMode.getByValue(
|
||||||
|
getString(
|
||||||
|
R.string.pref_key_grade_sorting_mode,
|
||||||
|
R.string.pref_default_grade_sorting_mode
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
val showTimetableTimers: Boolean
|
val showTimetableTimers: Boolean
|
||||||
get() = getBoolean(R.string.pref_key_timetable_show_timers, R.bool.pref_default_timetable_show_timers)
|
get() = getBoolean(
|
||||||
|
R.string.pref_key_timetable_show_timers,
|
||||||
|
R.bool.pref_default_timetable_show_timers
|
||||||
|
)
|
||||||
|
|
||||||
var isHomeworkFullscreen: Boolean
|
var isHomeworkFullscreen: Boolean
|
||||||
get() = getBoolean(R.string.pref_key_homework_fullscreen, R.bool.pref_default_homework_fullscreen)
|
get() = getBoolean(
|
||||||
|
R.string.pref_key_homework_fullscreen,
|
||||||
|
R.bool.pref_default_homework_fullscreen
|
||||||
|
)
|
||||||
set(value) = sharedPref.edit().putBoolean("homework_fullscreen", value).apply()
|
set(value) = sharedPref.edit().putBoolean("homework_fullscreen", value).apply()
|
||||||
|
|
||||||
val showSubjectsWithoutGrades: Boolean
|
val showSubjectsWithoutGrades: Boolean
|
||||||
get() = getBoolean(R.string.pref_key_subjects_without_grades, R.bool.pref_default_subjects_without_grades)
|
get() = getBoolean(
|
||||||
|
R.string.pref_key_subjects_without_grades,
|
||||||
|
R.bool.pref_default_subjects_without_grades
|
||||||
|
)
|
||||||
|
|
||||||
private fun getString(id: Int, default: Int) = getString(context.getString(id), default)
|
private fun getString(id: Int, default: Int) = getString(context.getString(id), default)
|
||||||
|
|
||||||
private fun getString(id: String, default: Int) = sharedPref.getString(id, context.getString(default)) ?: context.getString(default)
|
private fun getString(id: String, default: Int) =
|
||||||
|
sharedPref.getString(id, context.getString(default)) ?: context.getString(default)
|
||||||
|
|
||||||
private fun getBoolean(id: Int, default: Int) = getBoolean(context.getString(id), default)
|
private fun getBoolean(id: Int, default: Int) = getBoolean(context.getString(id), default)
|
||||||
|
|
||||||
private fun getBoolean(id: String, default: Int) = sharedPref.getBoolean(id, context.resources.getBoolean(default))
|
private fun getBoolean(id: String, default: Int) =
|
||||||
|
sharedPref.getBoolean(id, context.resources.getBoolean(default))
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import io.github.wulkanowy.data.mappers.mapToEntity
|
|||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.init
|
import io.github.wulkanowy.utils.init
|
||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -16,8 +17,11 @@ class SchoolRepository @Inject constructor(
|
|||||||
private val sdk: Sdk
|
private val sdk: Sdk
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
fun getSchoolInfo(student: Student, semester: Semester, forceRefresh: Boolean) =
|
fun getSchoolInfo(student: Student, semester: Semester, forceRefresh: Boolean) =
|
||||||
networkBoundResource(
|
networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { it == null || forceRefresh },
|
shouldFetch = { it == null || forceRefresh },
|
||||||
query = { schoolDb.load(semester.studentId, semester.classId) },
|
query = { schoolDb.load(semester.studentId, semester.classId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -7,6 +7,7 @@ import io.github.wulkanowy.data.mappers.mapToEntity
|
|||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.init
|
import io.github.wulkanowy.utils.init
|
||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -16,8 +17,11 @@ class StudentInfoRepository @Inject constructor(
|
|||||||
private val sdk: Sdk
|
private val sdk: Sdk
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
fun getStudentInfo(student: Student, semester: Semester, forceRefresh: Boolean) =
|
fun getStudentInfo(student: Student, semester: Semester, forceRefresh: Boolean) =
|
||||||
networkBoundResource(
|
networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { it == null || forceRefresh },
|
shouldFetch = { it == null || forceRefresh },
|
||||||
query = { studentInfoDao.loadStudentInfo(student.studentId) },
|
query = { studentInfoDao.loadStudentInfo(student.studentId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -5,11 +5,12 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
|||||||
import io.github.wulkanowy.data.db.dao.SemesterDao
|
import io.github.wulkanowy.data.db.dao.SemesterDao
|
||||||
import io.github.wulkanowy.data.db.dao.StudentDao
|
import io.github.wulkanowy.data.db.dao.StudentDao
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.db.entities.StudentNick
|
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import io.github.wulkanowy.utils.DispatchersProvider
|
import io.github.wulkanowy.utils.DispatchersProvider
|
||||||
import io.github.wulkanowy.utils.security.decrypt
|
import io.github.wulkanowy.utils.security.decrypt
|
||||||
import io.github.wulkanowy.utils.security.encrypt
|
import io.github.wulkanowy.utils.security.encrypt
|
||||||
@ -23,7 +24,8 @@ class StudentRepository @Inject constructor(
|
|||||||
private val dispatchers: DispatchersProvider,
|
private val dispatchers: DispatchersProvider,
|
||||||
private val studentDb: StudentDao,
|
private val studentDb: StudentDao,
|
||||||
private val semesterDb: SemesterDao,
|
private val semesterDb: SemesterDao,
|
||||||
private val sdk: Sdk
|
private val sdk: Sdk,
|
||||||
|
private val appInfo: AppInfo
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun isStudentSaved() = getSavedStudents(false).isNotEmpty()
|
suspend fun isStudentSaved() = getSavedStudents(false).isNotEmpty()
|
||||||
@ -35,7 +37,8 @@ class StudentRepository @Inject constructor(
|
|||||||
symbol: String,
|
symbol: String,
|
||||||
token: String
|
token: String
|
||||||
): List<StudentWithSemesters> =
|
): List<StudentWithSemesters> =
|
||||||
sdk.getStudentsFromMobileApi(token, pin, symbol, "").mapToEntities()
|
sdk.getStudentsFromMobileApi(token, pin, symbol, "")
|
||||||
|
.mapToEntities(colors = appInfo.defaultColorsForAvatar)
|
||||||
|
|
||||||
suspend fun getStudentsScrapper(
|
suspend fun getStudentsScrapper(
|
||||||
email: String,
|
email: String,
|
||||||
@ -44,7 +47,7 @@ class StudentRepository @Inject constructor(
|
|||||||
symbol: String
|
symbol: String
|
||||||
): List<StudentWithSemesters> =
|
): List<StudentWithSemesters> =
|
||||||
sdk.getStudentsFromScrapper(email, password, scrapperBaseUrl, symbol)
|
sdk.getStudentsFromScrapper(email, password, scrapperBaseUrl, symbol)
|
||||||
.mapToEntities(password)
|
.mapToEntities(password, appInfo.defaultColorsForAvatar)
|
||||||
|
|
||||||
suspend fun getStudentsHybrid(
|
suspend fun getStudentsHybrid(
|
||||||
email: String,
|
email: String,
|
||||||
@ -52,47 +55,59 @@ class StudentRepository @Inject constructor(
|
|||||||
scrapperBaseUrl: String,
|
scrapperBaseUrl: String,
|
||||||
symbol: String
|
symbol: String
|
||||||
): List<StudentWithSemesters> =
|
): List<StudentWithSemesters> =
|
||||||
sdk.getStudentsHybrid(email, password, scrapperBaseUrl, "", symbol).mapToEntities(password)
|
sdk.getStudentsHybrid(email, password, scrapperBaseUrl, "", symbol)
|
||||||
|
.mapToEntities(password, appInfo.defaultColorsForAvatar)
|
||||||
|
|
||||||
suspend fun getSavedStudents(decryptPass: Boolean = true) =
|
suspend fun getSavedStudents(decryptPass: Boolean = true) =
|
||||||
withContext(dispatchers.backgroundThread) {
|
studentDb.loadStudentsWithSemesters()
|
||||||
studentDb.loadStudentsWithSemesters().map {
|
.map {
|
||||||
it.apply {
|
it.apply {
|
||||||
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
|
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
|
||||||
student.password = decrypt(student.password)
|
student.password = withContext(dispatchers.backgroundThread) {
|
||||||
|
decrypt(student.password)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getStudentById(id: Int) = withContext(dispatchers.backgroundThread) {
|
suspend fun getStudentById(id: Long, decryptPass: Boolean = true): Student {
|
||||||
studentDb.loadById(id)?.apply {
|
val student = studentDb.loadById(id) ?: throw NoCurrentStudentException()
|
||||||
if (Sdk.Mode.valueOf(loginMode) != Sdk.Mode.API) {
|
|
||||||
password = decrypt(password)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ?: throw NoCurrentStudentException()
|
|
||||||
|
|
||||||
suspend fun getCurrentStudent(decryptPass: Boolean = true) =
|
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
|
||||||
withContext(dispatchers.backgroundThread) {
|
student.password = withContext(dispatchers.backgroundThread) {
|
||||||
studentDb.loadCurrent()?.apply {
|
decrypt(student.password)
|
||||||
if (decryptPass && Sdk.Mode.valueOf(loginMode) != Sdk.Mode.API) {
|
|
||||||
password = decrypt(password)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} ?: throw NoCurrentStudentException()
|
return student
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getCurrentStudent(decryptPass: Boolean = true): Student {
|
||||||
|
val student = studentDb.loadCurrent() ?: throw NoCurrentStudentException()
|
||||||
|
|
||||||
|
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
|
||||||
|
student.password = withContext(dispatchers.backgroundThread) {
|
||||||
|
decrypt(student.password)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return student
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun saveStudents(studentsWithSemesters: List<StudentWithSemesters>): List<Long> {
|
suspend fun saveStudents(studentsWithSemesters: List<StudentWithSemesters>): List<Long> {
|
||||||
semesterDb.insertSemesters(studentsWithSemesters.flatMap { it.semesters })
|
val semesters = studentsWithSemesters.flatMap { it.semesters }
|
||||||
|
val students = studentsWithSemesters.map { it.student }
|
||||||
return withContext(dispatchers.backgroundThread) {
|
.map {
|
||||||
studentDb.insertAll(studentsWithSemesters.map { it.student }.map {
|
it.apply {
|
||||||
if (Sdk.Mode.valueOf(it.loginMode) != Sdk.Mode.API) {
|
if (Sdk.Mode.valueOf(it.loginMode) != Sdk.Mode.API) {
|
||||||
it.copy(password = encrypt(it.password, context))
|
password = withContext(dispatchers.backgroundThread) {
|
||||||
} else it
|
encrypt(password, context)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
semesterDb.insertSemesters(semesters)
|
||||||
|
return studentDb.insertAll(students)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun switchStudent(studentWithSemesters: StudentWithSemesters) {
|
suspend fun switchStudent(studentWithSemesters: StudentWithSemesters) {
|
||||||
with(studentDb) {
|
with(studentDb) {
|
||||||
@ -103,5 +118,6 @@ class StudentRepository @Inject constructor(
|
|||||||
|
|
||||||
suspend fun logoutStudent(student: Student) = studentDb.delete(student)
|
suspend fun logoutStudent(student: Student) = studentDb.delete(student)
|
||||||
|
|
||||||
suspend fun updateStudentNick(studentNick: StudentNick) = studentDb.update(studentNick)
|
suspend fun updateStudentNickAndAvatar(studentNickAndAvatar: StudentNickAndAvatar) =
|
||||||
|
studentDb.update(studentNickAndAvatar)
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import io.github.wulkanowy.sdk.Sdk
|
|||||||
import io.github.wulkanowy.utils.init
|
import io.github.wulkanowy.utils.init
|
||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -17,7 +18,10 @@ class SubjectRepository @Inject constructor(
|
|||||||
private val sdk: Sdk
|
private val sdk: Sdk
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
fun getSubjects(student: Student, semester: Semester, forceRefresh: Boolean = false) = networkBoundResource(
|
fun getSubjects(student: Student, semester: Semester, forceRefresh: Boolean = false) = networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { it.isEmpty() || forceRefresh },
|
shouldFetch = { it.isEmpty() || forceRefresh },
|
||||||
query = { subjectDao.loadAll(semester.diaryId, semester.studentId) },
|
query = { subjectDao.loadAll(semester.diaryId, semester.studentId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -8,6 +8,7 @@ import io.github.wulkanowy.sdk.Sdk
|
|||||||
import io.github.wulkanowy.utils.init
|
import io.github.wulkanowy.utils.init
|
||||||
import io.github.wulkanowy.utils.networkBoundResource
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -17,7 +18,10 @@ class TeacherRepository @Inject constructor(
|
|||||||
private val sdk: Sdk
|
private val sdk: Sdk
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
fun getTeachers(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
|
fun getTeachers(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { it.isEmpty() || forceRefresh },
|
shouldFetch = { it.isEmpty() || forceRefresh },
|
||||||
query = { teacherDb.loadAll(semester.studentId, semester.classId) },
|
query = { teacherDb.loadAll(semester.studentId, semester.classId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -18,6 +18,7 @@ import io.github.wulkanowy.utils.sunday
|
|||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@ -31,9 +32,12 @@ class TimetableRepository @Inject constructor(
|
|||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private val cacheKey = "timetable"
|
private val cacheKey = "timetable"
|
||||||
|
|
||||||
fun getTimetable(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean, refreshAdditional: Boolean = false) = networkBoundResource(
|
fun getTimetable(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean, refreshAdditional: Boolean = false) = networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { (timetable, additional) -> timetable.isEmpty() || (additional.isEmpty() && refreshAdditional) || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
shouldFetch = { (timetable, additional) -> timetable.isEmpty() || (additional.isEmpty() && refreshAdditional) || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
|
||||||
query = {
|
query = {
|
||||||
timetableDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)
|
timetableDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)
|
||||||
|
@ -37,6 +37,7 @@ abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
|
|||||||
abstract var presenter: T
|
abstract var presenter: T
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
inject()
|
||||||
themeManager.applyActivityTheme(this)
|
themeManager.applyActivityTheme(this)
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleLogger, true)
|
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleLogger, true)
|
||||||
@ -44,7 +45,9 @@ abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
|
|||||||
|
|
||||||
if (SDK_INT >= LOLLIPOP) {
|
if (SDK_INT >= LOLLIPOP) {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
setTaskDescription(ActivityManager.TaskDescription(null, null, getThemeAttrColor(R.attr.colorSurface)))
|
setTaskDescription(
|
||||||
|
ActivityManager.TaskDescription(null, null, getThemeAttrColor(R.attr.colorSurface))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,4 +87,9 @@ abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
|
|||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//https://github.com/google/dagger/releases/tag/dagger-2.33
|
||||||
|
protected open fun inject() {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import androidx.fragment.app.Fragment
|
|||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.fragment.app.FragmentPagerAdapter
|
import androidx.fragment.app.FragmentPagerAdapter
|
||||||
|
|
||||||
|
//TODO Use ViewPager2
|
||||||
class BaseFragmentPagerAdapter(private val fragmentManager: FragmentManager) :
|
class BaseFragmentPagerAdapter(private val fragmentManager: FragmentManager) :
|
||||||
FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
|
FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
|
||||||
|
|
||||||
|
@ -42,12 +42,10 @@ class ErrorDialog : BaseDialogFragment<DialogErrorBinding>() {
|
|||||||
companion object {
|
companion object {
|
||||||
private const val ARGUMENT_KEY = "Data"
|
private const val ARGUMENT_KEY = "Data"
|
||||||
|
|
||||||
fun newInstance(error: Throwable): ErrorDialog {
|
fun newInstance(error: Throwable) = ErrorDialog().apply {
|
||||||
return ErrorDialog().apply {
|
|
||||||
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, error) }
|
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, error) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -57,12 +55,14 @@ class ErrorDialog : BaseDialogFragment<DialogErrorBinding>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun onCreateView(
|
||||||
return DialogErrorBinding.inflate(inflater).apply { binding = this }.root
|
inflater: LayoutInflater,
|
||||||
}
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
) = DialogErrorBinding.inflate(inflater).apply { binding = this }.root
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
val stringWriter = StringWriter().apply {
|
val stringWriter = StringWriter().apply {
|
||||||
error.printStackTrace(PrintWriter(this))
|
error.printStackTrace(PrintWriter(this))
|
||||||
|
@ -8,6 +8,9 @@ import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
|
|||||||
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
|
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -17,7 +20,13 @@ class ThemeManager @Inject constructor(private val preferencesRepository: Prefer
|
|||||||
fun applyActivityTheme(activity: AppCompatActivity) {
|
fun applyActivityTheme(activity: AppCompatActivity) {
|
||||||
if (isThemeApplicable(activity)) {
|
if (isThemeApplicable(activity)) {
|
||||||
applyDefaultTheme()
|
applyDefaultTheme()
|
||||||
if (preferencesRepository.appTheme == "black") activity.setTheme(R.style.WulkanowyTheme_Black)
|
if (preferencesRepository.appTheme == "black") {
|
||||||
|
when (activity) {
|
||||||
|
is MainActivity -> activity.setTheme(R.style.WulkanowyTheme_Black)
|
||||||
|
is LoginActivity -> activity.setTheme(R.style.WulkanowyTheme_Login_Black)
|
||||||
|
is SendMessageActivity -> activity.setTheme(R.style.WulkanowyTheme_MessageSend_Black)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,8 +42,13 @@ class ThemeManager @Inject constructor(private val preferencesRepository: Prefer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isThemeApplicable(activity: AppCompatActivity): Boolean {
|
private fun isThemeApplicable(activity: AppCompatActivity): Boolean {
|
||||||
return activity.packageManager.getPackageInfo(activity.packageName, GET_ACTIVITIES)
|
return activity.packageManager
|
||||||
.activities.singleOrNull { it.name == activity::class.java.canonicalName }?.theme
|
.getPackageInfo(activity.packageName, GET_ACTIVITIES)
|
||||||
.let { it == R.style.WulkanowyTheme_Black || it == R.style.WulkanowyTheme_NoActionBar }
|
.activities.singleOrNull { it.name == activity::class.java.canonicalName }
|
||||||
|
?.theme.let {
|
||||||
|
it == R.style.WulkanowyTheme_Black || it == R.style.WulkanowyTheme_NoActionBar
|
||||||
|
|| it == R.style.WulkanowyTheme_Login || it == R.style.WulkanowyTheme_Login_Black
|
||||||
|
|| it == R.style.WulkanowyTheme_MessageSend || it == R.style.WulkanowyTheme_MessageSend_Black
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,9 @@ import android.os.Bundle
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.core.text.parseAsHtml
|
import androidx.core.text.parseAsHtml
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.mikepenz.aboutlibraries.Libs
|
import com.mikepenz.aboutlibraries.Libs
|
||||||
import com.mikepenz.aboutlibraries.entity.Library
|
import com.mikepenz.aboutlibraries.entity.Library
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
@ -26,14 +26,9 @@ class LicenseFragment : BaseFragment<FragmentLicenseBinding>(R.layout.fragment_l
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var licenseAdapter: LicenseAdapter
|
lateinit var licenseAdapter: LicenseAdapter
|
||||||
|
|
||||||
private val libs by lazy { Libs(requireContext()) }
|
|
||||||
|
|
||||||
override val titleStringId get() = R.string.license_title
|
override val titleStringId get() = R.string.license_title
|
||||||
|
|
||||||
override val appLibraries: ArrayList<Library>?
|
override val appLibraries by lazy { Libs(requireContext()).libraries }
|
||||||
get() = context?.let {
|
|
||||||
libs.prepareLibraries(it, emptyArray(), emptyArray(), autoDetect = true, checkCachedDetection = true, sort = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance() = LicenseFragment()
|
fun newInstance() = LicenseFragment()
|
||||||
@ -63,7 +58,7 @@ class LicenseFragment : BaseFragment<FragmentLicenseBinding>(R.layout.fragment_l
|
|||||||
|
|
||||||
override fun openLicense(licenseHtml: String) {
|
override fun openLicense(licenseHtml: String) {
|
||||||
context?.let {
|
context?.let {
|
||||||
AlertDialog.Builder(it).apply {
|
MaterialAlertDialogBuilder(it).apply {
|
||||||
setTitle(R.string.license_dialog_title)
|
setTitle(R.string.license_dialog_title)
|
||||||
setMessage(licenseHtml.parseAsHtml())
|
setMessage(licenseHtml.parseAsHtml())
|
||||||
setPositiveButton(android.R.string.ok) { _, _ -> }
|
setPositiveButton(android.R.string.ok) { _, _ -> }
|
||||||
|
@ -5,7 +5,7 @@ import io.github.wulkanowy.ui.base.BaseView
|
|||||||
|
|
||||||
interface LicenseView : BaseView {
|
interface LicenseView : BaseView {
|
||||||
|
|
||||||
val appLibraries: ArrayList<Library>?
|
val appLibraries: List<Library>
|
||||||
|
|
||||||
fun initView()
|
fun initView()
|
||||||
|
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
package io.github.wulkanowy.ui.modules.account
|
package io.github.wulkanowy.ui.modules.account
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.graphics.PorterDuff
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.databinding.HeaderAccountBinding
|
import io.github.wulkanowy.databinding.HeaderAccountBinding
|
||||||
import io.github.wulkanowy.databinding.ItemAccountBinding
|
import io.github.wulkanowy.databinding.ItemAccountBinding
|
||||||
|
import io.github.wulkanowy.utils.createNameInitialsDrawable
|
||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
import io.github.wulkanowy.utils.nickOrName
|
import io.github.wulkanowy.utils.nickOrName
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -72,9 +73,13 @@ class AccountAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.V
|
|||||||
binding: ItemAccountBinding,
|
binding: ItemAccountBinding,
|
||||||
studentWithSemesters: StudentWithSemesters
|
studentWithSemesters: StudentWithSemesters
|
||||||
) {
|
) {
|
||||||
|
val context = binding.root.context
|
||||||
val student = studentWithSemesters.student
|
val student = studentWithSemesters.student
|
||||||
val semesters = studentWithSemesters.semesters
|
val semesters = studentWithSemesters.semesters
|
||||||
val diary = semesters.maxByOrNull { it.semesterId }
|
val diary = semesters.maxByOrNull { it.semesterId }
|
||||||
|
val avatar = context.createNameInitialsDrawable(student.nickOrName, student.avatarColor)
|
||||||
|
val checkBackgroundColor =
|
||||||
|
context.getThemeAttrColor(if (isAccountQuickDialogMode) R.attr.colorBackgroundFloating else R.attr.colorSurface)
|
||||||
val isDuplicatedStudent = items.filter {
|
val isDuplicatedStudent = items.filter {
|
||||||
if (it.value !is StudentWithSemesters) return@filter false
|
if (it.value !is StudentWithSemesters) return@filter false
|
||||||
val studentToCompare = it.value.student
|
val studentToCompare = it.value.student
|
||||||
@ -87,15 +92,17 @@ class AccountAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.V
|
|||||||
with(binding) {
|
with(binding) {
|
||||||
accountItemName.text = "${student.nickOrName} ${diary?.diaryName.orEmpty()}"
|
accountItemName.text = "${student.nickOrName} ${diary?.diaryName.orEmpty()}"
|
||||||
accountItemSchool.text = studentWithSemesters.student.schoolName
|
accountItemSchool.text = studentWithSemesters.student.schoolName
|
||||||
accountItemAccountType.setText(if (student.isParent) R.string.account_type_parent else R.string.account_type_student)
|
accountItemImage.setImageDrawable(avatar)
|
||||||
accountItemAccountType.visibility = if (isDuplicatedStudent) VISIBLE else GONE
|
|
||||||
|
|
||||||
with(accountItemImage) {
|
with(accountItemAccountType) {
|
||||||
val colorImage =
|
setText(if (student.isParent) R.string.account_type_parent else R.string.account_type_student)
|
||||||
if (student.isCurrent) context.getThemeAttrColor(R.attr.colorPrimary)
|
isVisible = isDuplicatedStudent
|
||||||
else context.getThemeAttrColor(R.attr.colorOnSurface, 153)
|
}
|
||||||
|
|
||||||
setColorFilter(colorImage, PorterDuff.Mode.SRC_IN)
|
with(accountItemCheck) {
|
||||||
|
isVisible = student.isCurrent
|
||||||
|
borderColor = checkBackgroundColor
|
||||||
|
circleColor = checkBackgroundColor
|
||||||
}
|
}
|
||||||
|
|
||||||
root.setOnClickListener { onClickListener(studentWithSemesters) }
|
root.setOnClickListener { onClickListener(studentWithSemesters) }
|
||||||
|
@ -34,25 +34,20 @@ class AccountFragment : BaseFragment<FragmentAccountBinding>(R.layout.fragment_a
|
|||||||
|
|
||||||
override val titleStringId = R.string.account_title
|
override val titleStringId = R.string.account_title
|
||||||
|
|
||||||
override var subtitleString = ""
|
|
||||||
|
|
||||||
override val isViewEmpty get() = accountAdapter.items.isEmpty()
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
binding = FragmentAccountBinding.bind(view)
|
binding = FragmentAccountBinding.bind(view)
|
||||||
presenter.onAttachView(this)
|
presenter.onAttachView(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initView() {
|
override fun initView() {
|
||||||
binding.accountErrorRetry.setOnClickListener { presenter.onRetry() }
|
|
||||||
binding.accountErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
|
||||||
|
|
||||||
binding.accountRecycler.apply {
|
binding.accountRecycler.apply {
|
||||||
layoutManager = LinearLayoutManager(context)
|
layoutManager = LinearLayoutManager(context)
|
||||||
adapter = accountAdapter
|
adapter = accountAdapter
|
||||||
@ -60,9 +55,7 @@ class AccountFragment : BaseFragment<FragmentAccountBinding>(R.layout.fragment_a
|
|||||||
|
|
||||||
accountAdapter.onClickListener = presenter::onItemSelected
|
accountAdapter.onClickListener = presenter::onItemSelected
|
||||||
|
|
||||||
with(binding) {
|
binding.accountAdd.setOnClickListener { presenter.onAddSelected() }
|
||||||
accountAdd.setOnClickListener { presenter.onAddSelected() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
@ -84,28 +77,7 @@ class AccountFragment : BaseFragment<FragmentAccountBinding>(R.layout.fragment_a
|
|||||||
|
|
||||||
override fun openAccountDetailsView(studentWithSemesters: StudentWithSemesters) {
|
override fun openAccountDetailsView(studentWithSemesters: StudentWithSemesters) {
|
||||||
(activity as? MainActivity)?.pushView(
|
(activity as? MainActivity)?.pushView(
|
||||||
AccountDetailsFragment.newInstance(
|
AccountDetailsFragment.newInstance(studentWithSemesters)
|
||||||
studentWithSemesters
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showErrorView(show: Boolean) {
|
|
||||||
binding.accountError.visibility = if (show) View.VISIBLE else View.GONE
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setErrorDetails(message: String) {
|
|
||||||
binding.accountErrorMessage.text = message
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showProgress(show: Boolean) {
|
|
||||||
binding.accountProgress.visibility = if (show) View.VISIBLE else View.GONE
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showContent(show: Boolean) {
|
|
||||||
with(binding) {
|
|
||||||
accountRecycler.visibility = if (show) View.VISIBLE else View.GONE
|
|
||||||
accountAdd.visibility = if (show) View.VISIBLE else View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
|||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
import io.github.wulkanowy.utils.afterLoading
|
|
||||||
import io.github.wulkanowy.utils.flowWithResource
|
import io.github.wulkanowy.utils.flowWithResource
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -16,28 +15,13 @@ class AccountPresenter @Inject constructor(
|
|||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
) : BasePresenter<AccountView>(errorHandler, studentRepository) {
|
) : BasePresenter<AccountView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
private lateinit var lastError: Throwable
|
|
||||||
|
|
||||||
override fun onAttachView(view: AccountView) {
|
override fun onAttachView(view: AccountView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
view.initView()
|
view.initView()
|
||||||
Timber.i("Account view was initialized")
|
Timber.i("Account view was initialized")
|
||||||
errorHandler.showErrorMessage = ::showErrorViewOnError
|
|
||||||
loadData()
|
loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onRetry() {
|
|
||||||
view?.run {
|
|
||||||
showErrorView(false)
|
|
||||||
showProgress(true)
|
|
||||||
}
|
|
||||||
loadData()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onDetailsClick() {
|
|
||||||
view?.showErrorDetailsDialog(lastError)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onAddSelected() {
|
fun onAddSelected() {
|
||||||
Timber.i("Select add account")
|
Timber.i("Select add account")
|
||||||
view?.openLoginView()
|
view?.openLoginView()
|
||||||
@ -47,6 +31,24 @@ class AccountPresenter @Inject constructor(
|
|||||||
view?.openAccountDetailsView(studentWithSemesters)
|
view?.openAccountDetailsView(studentWithSemesters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadData() {
|
||||||
|
flowWithResource { studentRepository.getSavedStudents(false) }
|
||||||
|
.onEach {
|
||||||
|
when (it.status) {
|
||||||
|
Status.LOADING -> Timber.i("Loading account data started")
|
||||||
|
Status.SUCCESS -> {
|
||||||
|
Timber.i("Loading account result: Success")
|
||||||
|
view?.updateData(createAccountItems(it.data!!))
|
||||||
|
}
|
||||||
|
Status.ERROR -> {
|
||||||
|
Timber.i("Loading account result: An exception occurred")
|
||||||
|
errorHandler.dispatch(it.error!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.launch("load")
|
||||||
|
}
|
||||||
|
|
||||||
private fun createAccountItems(items: List<StudentWithSemesters>): List<AccountItem<*>> {
|
private fun createAccountItems(items: List<StudentWithSemesters>): List<AccountItem<*>> {
|
||||||
return items.groupBy {
|
return items.groupBy {
|
||||||
Account("${it.student.userName} (${it.student.email})", it.student.isParent)
|
Account("${it.student.userName} (${it.student.email})", it.student.isParent)
|
||||||
@ -60,45 +62,4 @@ class AccountPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadData() {
|
|
||||||
flowWithResource { studentRepository.getSavedStudents(false) }
|
|
||||||
.onEach {
|
|
||||||
when (it.status) {
|
|
||||||
Status.LOADING -> {
|
|
||||||
Timber.i("Loading account data started")
|
|
||||||
view?.run {
|
|
||||||
showProgress(true)
|
|
||||||
showContent(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Status.SUCCESS -> {
|
|
||||||
Timber.i("Loading account result: Success")
|
|
||||||
view?.updateData(createAccountItems(it.data!!))
|
|
||||||
view?.run {
|
|
||||||
showContent(true)
|
|
||||||
showErrorView(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Status.ERROR -> {
|
|
||||||
Timber.i("Loading account result: An exception occurred")
|
|
||||||
errorHandler.dispatch(it.error!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.afterLoading { view?.showProgress(false) }
|
|
||||||
.launch()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showErrorViewOnError(message: String, error: Throwable) {
|
|
||||||
view?.run {
|
|
||||||
if (isViewEmpty) {
|
|
||||||
lastError = error
|
|
||||||
setErrorDetails(message)
|
|
||||||
showErrorView(true)
|
|
||||||
showContent(false)
|
|
||||||
showProgress(false)
|
|
||||||
} else showError(message, error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,6 @@ import io.github.wulkanowy.ui.base.BaseView
|
|||||||
|
|
||||||
interface AccountView : BaseView {
|
interface AccountView : BaseView {
|
||||||
|
|
||||||
val isViewEmpty: Boolean
|
|
||||||
|
|
||||||
fun initView()
|
fun initView()
|
||||||
|
|
||||||
fun updateData(data: List<AccountItem<*>>)
|
fun updateData(data: List<AccountItem<*>>)
|
||||||
@ -14,13 +12,4 @@ interface AccountView : BaseView {
|
|||||||
fun openLoginView()
|
fun openLoginView()
|
||||||
|
|
||||||
fun openAccountDetailsView(studentWithSemesters: StudentWithSemesters)
|
fun openAccountDetailsView(studentWithSemesters: StudentWithSemesters)
|
||||||
|
|
||||||
fun showErrorView(show: Boolean)
|
|
||||||
|
|
||||||
fun setErrorDetails(message: String)
|
|
||||||
|
|
||||||
fun showProgress(show: Boolean)
|
|
||||||
|
|
||||||
fun showContent(show: Boolean)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import android.view.MenuItem
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.get
|
import androidx.core.view.get
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
@ -18,6 +19,7 @@ import io.github.wulkanowy.ui.modules.main.MainActivity
|
|||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoFragment
|
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoFragment
|
||||||
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
|
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
|
||||||
|
import io.github.wulkanowy.utils.createNameInitialsDrawable
|
||||||
import io.github.wulkanowy.utils.nickOrName
|
import io.github.wulkanowy.utils.nickOrName
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -31,8 +33,6 @@ class AccountDetailsFragment :
|
|||||||
|
|
||||||
override val titleStringId = R.string.account_details_title
|
override val titleStringId = R.string.account_details_title
|
||||||
|
|
||||||
override var subtitleString = ""
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val ARGUMENT_KEY = "Data"
|
private const val ARGUMENT_KEY = "Data"
|
||||||
@ -88,8 +88,15 @@ class AccountDetailsFragment :
|
|||||||
|
|
||||||
override fun showAccountData(student: Student) {
|
override fun showAccountData(student: Student) {
|
||||||
with(binding) {
|
with(binding) {
|
||||||
|
accountDetailsCheck.isVisible = student.isCurrent
|
||||||
accountDetailsName.text = student.nickOrName
|
accountDetailsName.text = student.nickOrName
|
||||||
accountDetailsSchool.text = student.schoolName
|
accountDetailsSchool.text = student.schoolName
|
||||||
|
accountDetailsAvatar.setImageDrawable(
|
||||||
|
requireContext().createNameInitialsDrawable(
|
||||||
|
student.nickOrName,
|
||||||
|
student.avatarColor
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ class AccountDetailsPresenter @Inject constructor(
|
|||||||
private val syncManager: SyncManager
|
private val syncManager: SyncManager
|
||||||
) : BasePresenter<AccountDetailsView>(errorHandler, studentRepository) {
|
) : BasePresenter<AccountDetailsView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
private lateinit var studentWithSemesters: StudentWithSemesters
|
private var studentWithSemesters: StudentWithSemesters? = null
|
||||||
|
|
||||||
private lateinit var lastError: Throwable
|
private lateinit var lastError: Throwable
|
||||||
|
|
||||||
@ -69,10 +69,10 @@ class AccountDetailsPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
Status.SUCCESS -> {
|
Status.SUCCESS -> {
|
||||||
Timber.i("Loading account details view result: Success")
|
Timber.i("Loading account details view result: Success")
|
||||||
studentWithSemesters = it.data!!
|
studentWithSemesters = it.data
|
||||||
view?.run {
|
view?.run {
|
||||||
showAccountData(studentWithSemesters.student)
|
showAccountData(studentWithSemesters!!.student)
|
||||||
enableSelectStudentButton(!studentWithSemesters.student.isCurrent)
|
enableSelectStudentButton(!studentWithSemesters!!.student.isCurrent)
|
||||||
showContent(true)
|
showContent(true)
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
}
|
}
|
||||||
@ -88,17 +88,23 @@ class AccountDetailsPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onAccountEditSelected() {
|
fun onAccountEditSelected() {
|
||||||
view?.showAccountEditDetailsDialog(studentWithSemesters.student)
|
studentWithSemesters?.let {
|
||||||
|
view?.showAccountEditDetailsDialog(it.student)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onStudentInfoSelected(infoType: StudentInfoView.Type) {
|
fun onStudentInfoSelected(infoType: StudentInfoView.Type) {
|
||||||
view?.openStudentInfoView(infoType, studentWithSemesters)
|
studentWithSemesters?.let {
|
||||||
|
view?.openStudentInfoView(infoType, it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onStudentSelect() {
|
fun onStudentSelect() {
|
||||||
Timber.i("Select student ${studentWithSemesters.student.id}")
|
if (studentWithSemesters == null) return
|
||||||
|
|
||||||
flowWithResource { studentRepository.switchStudent(studentWithSemesters) }
|
Timber.i("Select student ${studentWithSemesters!!.student.id}")
|
||||||
|
|
||||||
|
flowWithResource { studentRepository.switchStudent(studentWithSemesters!!) }
|
||||||
.onEach {
|
.onEach {
|
||||||
when (it.status) {
|
when (it.status) {
|
||||||
Status.LOADING -> Timber.i("Attempt to change a student")
|
Status.LOADING -> Timber.i("Attempt to change a student")
|
||||||
@ -122,8 +128,10 @@ class AccountDetailsPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onLogoutConfirm() {
|
fun onLogoutConfirm() {
|
||||||
|
if (studentWithSemesters == null) return
|
||||||
|
|
||||||
flowWithResource {
|
flowWithResource {
|
||||||
val studentToLogout = studentWithSemesters.student
|
val studentToLogout = studentWithSemesters!!.student
|
||||||
|
|
||||||
studentRepository.logoutStudent(studentToLogout)
|
studentRepository.logoutStudent(studentToLogout)
|
||||||
val students = studentRepository.getSavedStudents(false)
|
val students = studentRepository.getSavedStudents(false)
|
||||||
@ -143,7 +151,7 @@ class AccountDetailsPresenter @Inject constructor(
|
|||||||
syncManager.stopSyncWorker()
|
syncManager.stopSyncWorker()
|
||||||
openClearLoginView()
|
openClearLoginView()
|
||||||
}
|
}
|
||||||
studentWithSemesters.student.isCurrent -> {
|
studentWithSemesters!!.student.isCurrent -> {
|
||||||
Timber.i("Logout result: Logout student and switch to another")
|
Timber.i("Logout result: Logout student and switch to another")
|
||||||
recreateMainView()
|
recreateMainView()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,90 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.account.accountedit
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.graphics.drawable.GradientDrawable
|
||||||
|
import android.graphics.drawable.RippleDrawable
|
||||||
|
import android.graphics.drawable.StateListDrawable
|
||||||
|
import android.os.Build
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import io.github.wulkanowy.databinding.ItemAccountEditColorBinding
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class AccountEditColorAdapter @Inject constructor() :
|
||||||
|
RecyclerView.Adapter<AccountEditColorAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
var items = listOf<Int>()
|
||||||
|
|
||||||
|
var selectedColor = 0
|
||||||
|
|
||||||
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||||
|
ItemAccountEditColorBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
)
|
||||||
|
|
||||||
|
@SuppressLint("RestrictedApi", "NewApi")
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
val item = items[position]
|
||||||
|
|
||||||
|
with(holder.binding) {
|
||||||
|
accountEditItemColor.setImageDrawable(GradientDrawable().apply {
|
||||||
|
shape = GradientDrawable.OVAL
|
||||||
|
setColor(item)
|
||||||
|
})
|
||||||
|
|
||||||
|
accountEditItemColorContainer.foreground = item.createForegroundDrawable()
|
||||||
|
accountEditCheck.isVisible = selectedColor == item
|
||||||
|
|
||||||
|
root.setOnClickListener {
|
||||||
|
val oldSelectedPosition = items.indexOf(selectedColor)
|
||||||
|
selectedColor = item
|
||||||
|
|
||||||
|
notifyItemChanged(oldSelectedPosition)
|
||||||
|
notifyItemChanged(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Int.createForegroundDrawable(): Drawable =
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
val mask = GradientDrawable().apply {
|
||||||
|
shape = GradientDrawable.OVAL
|
||||||
|
setColor(Color.BLACK)
|
||||||
|
}
|
||||||
|
RippleDrawable(ColorStateList.valueOf(this.rippleColor), null, mask)
|
||||||
|
} else {
|
||||||
|
val foreground = StateListDrawable().apply {
|
||||||
|
alpha = 80
|
||||||
|
setEnterFadeDuration(250)
|
||||||
|
setExitFadeDuration(250)
|
||||||
|
}
|
||||||
|
|
||||||
|
val mask = GradientDrawable().apply {
|
||||||
|
shape = GradientDrawable.OVAL
|
||||||
|
setColor(this@createForegroundDrawable.rippleColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
foreground.apply {
|
||||||
|
addState(intArrayOf(android.R.attr.state_pressed), mask)
|
||||||
|
addState(intArrayOf(), ColorDrawable(Color.TRANSPARENT))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline val Int.rippleColor: Int
|
||||||
|
get() {
|
||||||
|
val hsv = FloatArray(3)
|
||||||
|
Color.colorToHSV(this, hsv)
|
||||||
|
hsv[2] = hsv[2] * 0.5f
|
||||||
|
return Color.HSVToColor(hsv)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewHolder(val binding: ItemAccountEditColorBinding) :
|
||||||
|
RecyclerView.ViewHolder(binding.root)
|
||||||
|
}
|
@ -4,6 +4,7 @@ import android.os.Bundle
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.databinding.DialogAccountEditBinding
|
import io.github.wulkanowy.databinding.DialogAccountEditBinding
|
||||||
@ -16,6 +17,9 @@ class AccountEditDialog : BaseDialogFragment<DialogAccountEditBinding>(), Accoun
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: AccountEditPresenter
|
lateinit var presenter: AccountEditPresenter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var accountEditColorAdapter: AccountEditColorAdapter
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val ARGUMENT_KEY = "student_with_semesters"
|
private const val ARGUMENT_KEY = "student_with_semesters"
|
||||||
@ -48,8 +52,30 @@ class AccountEditDialog : BaseDialogFragment<DialogAccountEditBinding>(), Accoun
|
|||||||
with(binding) {
|
with(binding) {
|
||||||
accountEditDetailsCancel.setOnClickListener { dismiss() }
|
accountEditDetailsCancel.setOnClickListener { dismiss() }
|
||||||
accountEditDetailsSave.setOnClickListener {
|
accountEditDetailsSave.setOnClickListener {
|
||||||
presenter.changeStudentNick(binding.accountEditDetailsNickText.text.toString())
|
presenter.changeStudentNickAndAvatar(
|
||||||
|
binding.accountEditDetailsNickText.text.toString(),
|
||||||
|
accountEditColorAdapter.selectedColor
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
with(binding.accountEditColors) {
|
||||||
|
layoutManager = GridLayoutManager(context, 4)
|
||||||
|
adapter = accountEditColorAdapter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateSelectedColorData(color: Int) {
|
||||||
|
with(accountEditColorAdapter) {
|
||||||
|
selectedColor = color
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateColorsData(colors: List<Int>) {
|
||||||
|
with(accountEditColorAdapter) {
|
||||||
|
items = colors
|
||||||
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,10 +2,11 @@ package io.github.wulkanowy.ui.modules.account.accountedit
|
|||||||
|
|
||||||
import io.github.wulkanowy.data.Status
|
import io.github.wulkanowy.data.Status
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.db.entities.StudentNick
|
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import io.github.wulkanowy.utils.afterLoading
|
import io.github.wulkanowy.utils.afterLoading
|
||||||
import io.github.wulkanowy.utils.flowWithResource
|
import io.github.wulkanowy.utils.flowWithResource
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
@ -13,12 +14,15 @@ import timber.log.Timber
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class AccountEditPresenter @Inject constructor(
|
class AccountEditPresenter @Inject constructor(
|
||||||
|
private val appInfo: AppInfo,
|
||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository
|
studentRepository: StudentRepository
|
||||||
) : BasePresenter<AccountEditView>(errorHandler, studentRepository) {
|
) : BasePresenter<AccountEditView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
lateinit var student: Student
|
lateinit var student: Student
|
||||||
|
|
||||||
|
private val colors = appInfo.defaultColorsForAvatar.map { it.toInt() }
|
||||||
|
|
||||||
fun onAttachView(view: AccountEditView, student: Student) {
|
fun onAttachView(view: AccountEditView, student: Student) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
this.student = student
|
this.student = student
|
||||||
@ -28,27 +32,49 @@ class AccountEditPresenter @Inject constructor(
|
|||||||
showCurrentNick(student.nick.trim())
|
showCurrentNick(student.nick.trim())
|
||||||
}
|
}
|
||||||
Timber.i("Account edit dialog view was initialized")
|
Timber.i("Account edit dialog view was initialized")
|
||||||
|
loadData()
|
||||||
|
|
||||||
|
view.updateColorsData(colors)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun changeStudentNick(nick: String) {
|
private fun loadData() {
|
||||||
|
flowWithResource {
|
||||||
|
studentRepository.getStudentById(student.id, false).avatarColor
|
||||||
|
}.onEach { resource ->
|
||||||
|
when (resource.status) {
|
||||||
|
Status.LOADING -> Timber.i("Attempt to load student")
|
||||||
|
Status.SUCCESS -> {
|
||||||
|
view?.updateSelectedColorData(resource.data?.toInt()!!)
|
||||||
|
Timber.i("Attempt to load student: Success")
|
||||||
|
}
|
||||||
|
Status.ERROR -> {
|
||||||
|
Timber.i("Attempt to load student: An exception occurred")
|
||||||
|
errorHandler.dispatch(resource.error!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.launch("load_data")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun changeStudentNickAndAvatar(nick: String, avatarColor: Int) {
|
||||||
flowWithResource {
|
flowWithResource {
|
||||||
val studentNick =
|
val studentNick =
|
||||||
StudentNick(nick = nick.trim()).apply { id = student.id }
|
StudentNickAndAvatar(nick = nick.trim(), avatarColor = avatarColor.toLong())
|
||||||
studentRepository.updateStudentNick(studentNick)
|
.apply { id = student.id }
|
||||||
|
studentRepository.updateStudentNickAndAvatar(studentNick)
|
||||||
}.onEach {
|
}.onEach {
|
||||||
when (it.status) {
|
when (it.status) {
|
||||||
Status.LOADING -> Timber.i("Attempt to change a student nick")
|
Status.LOADING -> Timber.i("Attempt to change a student nick and avatar")
|
||||||
Status.SUCCESS -> {
|
Status.SUCCESS -> {
|
||||||
Timber.i("Change a student nick result: Success")
|
Timber.i("Change a student nick and avatar result: Success")
|
||||||
view?.recreateMainView()
|
view?.recreateMainView()
|
||||||
}
|
}
|
||||||
Status.ERROR -> {
|
Status.ERROR -> {
|
||||||
Timber.i("Change a student result: An exception occurred")
|
Timber.i("Change a student nick and avatar result: An exception occurred")
|
||||||
errorHandler.dispatch(it.error!!)
|
errorHandler.dispatch(it.error!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.afterLoading { view?.popView() }
|
.afterLoading { view?.popView() }
|
||||||
.launch()
|
.launch("update_student")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,4 +11,8 @@ interface AccountEditView : BaseView {
|
|||||||
fun recreateMainView()
|
fun recreateMainView()
|
||||||
|
|
||||||
fun showCurrentNick(nick: String)
|
fun showCurrentNick(nick: String)
|
||||||
|
|
||||||
|
fun updateSelectedColorData(color: Int)
|
||||||
|
|
||||||
|
fun updateColorsData(colors: List<Int>)
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.databinding.DialogAccountQuickBinding
|
import io.github.wulkanowy.databinding.DialogAccountQuickBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
||||||
import io.github.wulkanowy.ui.modules.account.AccountAdapter
|
import io.github.wulkanowy.ui.modules.account.AccountAdapter
|
||||||
@ -24,7 +25,15 @@ class AccountQuickDialog : BaseDialogFragment<DialogAccountQuickBinding>(), Acco
|
|||||||
lateinit var presenter: AccountQuickPresenter
|
lateinit var presenter: AccountQuickPresenter
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance() = AccountQuickDialog()
|
|
||||||
|
private const val STUDENTS_ARGUMENT_KEY = "students"
|
||||||
|
|
||||||
|
fun newInstance(studentsWithSemesters: List<StudentWithSemesters>) =
|
||||||
|
AccountQuickDialog().apply {
|
||||||
|
arguments = Bundle().apply {
|
||||||
|
putSerializable(STUDENTS_ARGUMENT_KEY, studentsWithSemesters.toTypedArray())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@ -38,8 +47,12 @@ class AccountQuickDialog : BaseDialogFragment<DialogAccountQuickBinding>(), Acco
|
|||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
) = DialogAccountQuickBinding.inflate(inflater).apply { binding = this }.root
|
) = DialogAccountQuickBinding.inflate(inflater).apply { binding = this }.root
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
presenter.onAttachView(this)
|
val studentsWithSemesters =
|
||||||
|
(requireArguments()[STUDENTS_ARGUMENT_KEY] as Array<StudentWithSemesters>).toList()
|
||||||
|
|
||||||
|
presenter.onAttachView(this, studentsWithSemesters)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initView() {
|
override fun initView() {
|
||||||
|
@ -17,11 +17,15 @@ class AccountQuickPresenter @Inject constructor(
|
|||||||
studentRepository: StudentRepository
|
studentRepository: StudentRepository
|
||||||
) : BasePresenter<AccountQuickView>(errorHandler, studentRepository) {
|
) : BasePresenter<AccountQuickView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
override fun onAttachView(view: AccountQuickView) {
|
private lateinit var studentsWithSemesters: List<StudentWithSemesters>
|
||||||
|
|
||||||
|
fun onAttachView(view: AccountQuickView, studentsWithSemesters: List<StudentWithSemesters>) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
|
this.studentsWithSemesters = studentsWithSemesters
|
||||||
|
|
||||||
view.initView()
|
view.initView()
|
||||||
Timber.i("Account quick dialog view was initialized")
|
Timber.i("Account quick dialog view was initialized")
|
||||||
loadData()
|
view.updateData(createAccountItems(studentsWithSemesters))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onManagerSelected() {
|
fun onManagerSelected() {
|
||||||
@ -57,22 +61,6 @@ class AccountQuickPresenter @Inject constructor(
|
|||||||
.launch("switch")
|
.launch("switch")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadData() {
|
|
||||||
flowWithResource { studentRepository.getSavedStudents(false) }.onEach {
|
|
||||||
when (it.status) {
|
|
||||||
Status.LOADING -> Timber.i("Loading account data started")
|
|
||||||
Status.SUCCESS -> {
|
|
||||||
Timber.i("Loading account result: Success")
|
|
||||||
view?.updateData(createAccountItems(it.data!!))
|
|
||||||
}
|
|
||||||
Status.ERROR -> {
|
|
||||||
Timber.i("Loading account result: An exception occurred")
|
|
||||||
errorHandler.dispatch(it.error!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.launch()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createAccountItems(items: List<StudentWithSemesters>) = items.map {
|
private fun createAccountItems(items: List<StudentWithSemesters>) = items.map {
|
||||||
AccountItem(it, AccountItem.ViewType.ITEM)
|
AccountItem(it, AccountItem.ViewType.ITEM)
|
||||||
}
|
}
|
||||||
|
@ -18,14 +18,13 @@ class AttendanceDialog : DialogFragment() {
|
|||||||
private lateinit var attendance: Attendance
|
private lateinit var attendance: Attendance
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val ARGUMENT_KEY = "Item"
|
private const val ARGUMENT_KEY = "Item"
|
||||||
|
|
||||||
fun newInstance(exam: Attendance): AttendanceDialog {
|
fun newInstance(exam: Attendance) = AttendanceDialog().apply {
|
||||||
return AttendanceDialog().apply {
|
|
||||||
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) }
|
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -35,12 +34,14 @@ class AttendanceDialog : DialogFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(
|
||||||
return DialogAttendanceBinding.inflate(inflater).apply { binding = this }.root
|
inflater: LayoutInflater,
|
||||||
}
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
) = DialogAttendanceBinding.inflate(inflater).apply { binding = this }.root
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
with(binding) {
|
with(binding) {
|
||||||
attendanceDialogSubject.text = attendance.subject
|
attendanceDialogSubject.text = attendance.subject
|
||||||
|
@ -17,14 +17,13 @@ class ExamDialog : DialogFragment() {
|
|||||||
private lateinit var exam: Exam
|
private lateinit var exam: Exam
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val ARGUMENT_KEY = "Item"
|
private const val ARGUMENT_KEY = "Item"
|
||||||
|
|
||||||
fun newInstance(exam: Exam): ExamDialog {
|
fun newInstance(exam: Exam) = ExamDialog().apply {
|
||||||
return ExamDialog().apply {
|
|
||||||
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) }
|
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -34,12 +33,14 @@ class ExamDialog : DialogFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(
|
||||||
return DialogExamBinding.inflate(inflater).apply { binding = this }.root
|
inflater: LayoutInflater,
|
||||||
}
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
) = DialogExamBinding.inflate(inflater).apply { binding = this }.root
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
with(binding) {
|
with(binding) {
|
||||||
examDialogSubjectValue.text = exam.subject
|
examDialogSubjectValue.text = exam.subject
|
||||||
|
@ -86,7 +86,11 @@ class GradeAverageProvider @Inject constructor(
|
|||||||
return@combine firstSemesterGradeSubject
|
return@combine firstSemesterGradeSubject
|
||||||
}
|
}
|
||||||
|
|
||||||
val isAnyAverage = secondSemesterGradeSubject.data.orEmpty().any { it.average != .0 }
|
val isAnyVulcanAverageInFirstSemester =
|
||||||
|
firstSemesterGradeSubject.data.orEmpty().any { it.average != .0 }
|
||||||
|
val isAnyVulcanAverageInSecondSemester =
|
||||||
|
secondSemesterGradeSubject.data.orEmpty().any { it.average != .0 }
|
||||||
|
|
||||||
val updatedData = secondSemesterGradeSubject.data?.map { secondSemesterSubject ->
|
val updatedData = secondSemesterGradeSubject.data?.map { secondSemesterSubject ->
|
||||||
val firstSemesterSubject = firstSemesterGradeSubject.data.orEmpty()
|
val firstSemesterSubject = firstSemesterGradeSubject.data.orEmpty()
|
||||||
.singleOrNull { it.subject == secondSemesterSubject.subject }
|
.singleOrNull { it.subject == secondSemesterSubject.subject }
|
||||||
@ -94,7 +98,7 @@ class GradeAverageProvider @Inject constructor(
|
|||||||
val updatedAverage = if (averageMode == ALL_YEAR) {
|
val updatedAverage = if (averageMode == ALL_YEAR) {
|
||||||
calculateAllYearAverage(
|
calculateAllYearAverage(
|
||||||
student = student,
|
student = student,
|
||||||
isAnyAverage = isAnyAverage,
|
isAnyVulcanAverage = isAnyVulcanAverageInFirstSemester || isAnyVulcanAverageInSecondSemester,
|
||||||
gradeAverageForceCalc = gradeAverageForceCalc,
|
gradeAverageForceCalc = gradeAverageForceCalc,
|
||||||
secondSemesterSubject = secondSemesterSubject,
|
secondSemesterSubject = secondSemesterSubject,
|
||||||
firstSemesterSubject = firstSemesterSubject
|
firstSemesterSubject = firstSemesterSubject
|
||||||
@ -102,7 +106,7 @@ class GradeAverageProvider @Inject constructor(
|
|||||||
} else {
|
} else {
|
||||||
calculateBothSemestersAverage(
|
calculateBothSemestersAverage(
|
||||||
student = student,
|
student = student,
|
||||||
isAnyAverage = isAnyAverage,
|
isAnyVulcanAverage = isAnyVulcanAverageInFirstSemester || isAnyVulcanAverageInSecondSemester,
|
||||||
gradeAverageForceCalc = gradeAverageForceCalc,
|
gradeAverageForceCalc = gradeAverageForceCalc,
|
||||||
secondSemesterSubject = secondSemesterSubject,
|
secondSemesterSubject = secondSemesterSubject,
|
||||||
firstSemesterSubject = firstSemesterSubject
|
firstSemesterSubject = firstSemesterSubject
|
||||||
@ -116,11 +120,11 @@ class GradeAverageProvider @Inject constructor(
|
|||||||
|
|
||||||
private fun calculateAllYearAverage(
|
private fun calculateAllYearAverage(
|
||||||
student: Student,
|
student: Student,
|
||||||
isAnyAverage: Boolean,
|
isAnyVulcanAverage: Boolean,
|
||||||
gradeAverageForceCalc: Boolean,
|
gradeAverageForceCalc: Boolean,
|
||||||
secondSemesterSubject: GradeSubject,
|
secondSemesterSubject: GradeSubject,
|
||||||
firstSemesterSubject: GradeSubject?
|
firstSemesterSubject: GradeSubject?
|
||||||
) = if (!isAnyAverage || gradeAverageForceCalc) {
|
) = if (!isAnyVulcanAverage || gradeAverageForceCalc) {
|
||||||
val updatedSecondSemesterGrades =
|
val updatedSecondSemesterGrades =
|
||||||
secondSemesterSubject.grades.updateModifiers(student)
|
secondSemesterSubject.grades.updateModifiers(student)
|
||||||
val updatedFirstSemesterGrades =
|
val updatedFirstSemesterGrades =
|
||||||
@ -133,20 +137,23 @@ class GradeAverageProvider @Inject constructor(
|
|||||||
|
|
||||||
private fun calculateBothSemestersAverage(
|
private fun calculateBothSemestersAverage(
|
||||||
student: Student,
|
student: Student,
|
||||||
isAnyAverage: Boolean,
|
isAnyVulcanAverage: Boolean,
|
||||||
gradeAverageForceCalc: Boolean,
|
gradeAverageForceCalc: Boolean,
|
||||||
secondSemesterSubject: GradeSubject,
|
secondSemesterSubject: GradeSubject,
|
||||||
firstSemesterSubject: GradeSubject?
|
firstSemesterSubject: GradeSubject?
|
||||||
) = if (!isAnyAverage || gradeAverageForceCalc) {
|
): Double {
|
||||||
|
val divider = if (secondSemesterSubject.grades.any { it.weightValue > .0 }) 2 else 1
|
||||||
|
|
||||||
|
return if (!isAnyVulcanAverage || gradeAverageForceCalc) {
|
||||||
val secondSemesterAverage =
|
val secondSemesterAverage =
|
||||||
secondSemesterSubject.grades.updateModifiers(student).calcAverage()
|
secondSemesterSubject.grades.updateModifiers(student).calcAverage()
|
||||||
val firstSemesterAverage = firstSemesterSubject?.grades?.updateModifiers(student)
|
val firstSemesterAverage = firstSemesterSubject?.grades?.updateModifiers(student)
|
||||||
?.calcAverage() ?: secondSemesterAverage
|
?.calcAverage() ?: secondSemesterAverage
|
||||||
val divider = if (secondSemesterSubject.grades.any { it.weightValue > .0 }) 2 else 1
|
|
||||||
|
|
||||||
(secondSemesterAverage + firstSemesterAverage) / divider
|
(secondSemesterAverage + firstSemesterAverage) / divider
|
||||||
} else {
|
} else {
|
||||||
(secondSemesterSubject.average + (firstSemesterSubject?.average ?: secondSemesterSubject.average)) / 2
|
(secondSemesterSubject.average + (firstSemesterSubject?.average ?: secondSemesterSubject.average)) / divider
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getGradeSubjects(
|
private fun getGradeSubjects(
|
||||||
|
@ -63,11 +63,13 @@ class GradeFragment : BaseFragment<FragmentGradeBinding>(R.layout.fragment_grade
|
|||||||
override fun initView() {
|
override fun initView() {
|
||||||
with(pagerAdapter) {
|
with(pagerAdapter) {
|
||||||
containerId = binding.gradeViewPager.id
|
containerId = binding.gradeViewPager.id
|
||||||
addFragmentsWithTitle(mapOf(
|
addFragmentsWithTitle(
|
||||||
|
mapOf(
|
||||||
GradeDetailsFragment.newInstance() to getString(R.string.all_details),
|
GradeDetailsFragment.newInstance() to getString(R.string.all_details),
|
||||||
GradeSummaryFragment.newInstance() to getString(R.string.grade_menu_summary),
|
GradeSummaryFragment.newInstance() to getString(R.string.grade_menu_summary),
|
||||||
GradeStatisticsFragment.newInstance() to getString(R.string.grade_menu_statistics)
|
GradeStatisticsFragment.newInstance() to getString(R.string.grade_menu_statistics)
|
||||||
))
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
with(binding.gradeViewPager) {
|
with(binding.gradeViewPager) {
|
||||||
@ -137,7 +139,10 @@ class GradeFragment : BaseFragment<FragmentGradeBinding>(R.layout.fragment_grade
|
|||||||
|
|
||||||
override fun setCurrentSemesterName(semester: Int, schoolYear: Int) {
|
override fun setCurrentSemesterName(semester: Int, schoolYear: Int) {
|
||||||
subtitleString = getString(R.string.grade_subtitle, semester, schoolYear, schoolYear + 1)
|
subtitleString = getString(R.string.grade_subtitle, semester, schoolYear, schoolYear + 1)
|
||||||
(activity as MainView).setViewSubTitle(subtitleString)
|
|
||||||
|
if (isVisible) {
|
||||||
|
(activity as MainView?)?.setViewSubTitle(subtitleString)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onChildRefresh() {
|
fun onChildRefresh() {
|
||||||
@ -149,7 +154,8 @@ class GradeFragment : BaseFragment<FragmentGradeBinding>(R.layout.fragment_grade
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun notifyChildLoadData(index: Int, semesterId: Int, forceRefresh: Boolean) {
|
override fun notifyChildLoadData(index: Int, semesterId: Int, forceRefresh: Boolean) {
|
||||||
(pagerAdapter.getFragmentInstance(index) as? GradeView.GradeChildView)?.onParentLoadData(semesterId, forceRefresh)
|
(pagerAdapter.getFragmentInstance(index) as? GradeView.GradeChildView)
|
||||||
|
?.onParentLoadData(semesterId, forceRefresh)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun notifyChildParentReselected(index: Int) {
|
override fun notifyChildParentReselected(index: Int) {
|
||||||
|
@ -24,18 +24,19 @@ class GradeDetailsDialog : DialogFragment() {
|
|||||||
private lateinit var colorScheme: String
|
private lateinit var colorScheme: String
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val ARGUMENT_KEY = "Item"
|
private const val ARGUMENT_KEY = "Item"
|
||||||
|
|
||||||
private const val COLOR_SCHEME_KEY = "Scheme"
|
private const val COLOR_SCHEME_KEY = "Scheme"
|
||||||
|
|
||||||
fun newInstance(grade: Grade, colorScheme: String): GradeDetailsDialog {
|
fun newInstance(grade: Grade, colorScheme: String) =
|
||||||
return GradeDetailsDialog().apply {
|
GradeDetailsDialog().apply {
|
||||||
arguments = Bundle().apply {
|
arguments = Bundle().apply {
|
||||||
putSerializable(ARGUMENT_KEY, grade)
|
putSerializable(ARGUMENT_KEY, grade)
|
||||||
putString(COLOR_SCHEME_KEY, colorScheme)
|
putString(COLOR_SCHEME_KEY, colorScheme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -46,12 +47,14 @@ class GradeDetailsDialog : DialogFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(
|
||||||
return DialogGradeBinding.inflate(inflater).apply { binding = this }.root
|
inflater: LayoutInflater,
|
||||||
}
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
) = DialogGradeBinding.inflate(inflater).apply { binding = this }.root
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
with(binding) {
|
with(binding) {
|
||||||
gradeDialogSubject.text = grade.subject
|
gradeDialogSubject.text = grade.subject
|
||||||
|
@ -22,6 +22,7 @@ import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
|||||||
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
|
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
|
||||||
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
|
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
|
||||||
import io.github.wulkanowy.databinding.ItemGradeStatisticsBarBinding
|
import io.github.wulkanowy.databinding.ItemGradeStatisticsBarBinding
|
||||||
|
import io.github.wulkanowy.databinding.ItemGradeStatisticsHeaderBinding
|
||||||
import io.github.wulkanowy.databinding.ItemGradeStatisticsPieBinding
|
import io.github.wulkanowy.databinding.ItemGradeStatisticsPieBinding
|
||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -29,12 +30,16 @@ import javax.inject.Inject
|
|||||||
class GradeStatisticsAdapter @Inject constructor() :
|
class GradeStatisticsAdapter @Inject constructor() :
|
||||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
|
var currentDataType = GradeStatisticsItem.DataType.PARTIAL
|
||||||
|
|
||||||
var items = emptyList<GradeStatisticsItem>()
|
var items = emptyList<GradeStatisticsItem>()
|
||||||
|
|
||||||
var theme: String = "vulcan"
|
var theme: String = "vulcan"
|
||||||
|
|
||||||
var showAllSubjectsOnList: Boolean = false
|
var showAllSubjectsOnList: Boolean = false
|
||||||
|
|
||||||
|
var onDataTypeChangeListener: () -> Unit = {}
|
||||||
|
|
||||||
private val vulcanGradeColors = listOf(
|
private val vulcanGradeColors = listOf(
|
||||||
6 to R.color.grade_vulcan_six,
|
6 to R.color.grade_vulcan_six,
|
||||||
5 to R.color.grade_vulcan_five,
|
5 to R.color.grade_vulcan_five,
|
||||||
@ -62,37 +67,90 @@ class GradeStatisticsAdapter @Inject constructor() :
|
|||||||
"6, 6-", "5, 5-, 5+", "4, 4-, 4+", "3, 3-, 3+", "2, 2-, 2+", "1, 1+"
|
"6, 6-", "5, 5-, 5+", "4, 4-, 4+", "3, 3-, 3+", "2, 2-, 2+", "1, 1+"
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun getItemCount() = if (showAllSubjectsOnList) items.size else (if (items.isEmpty()) 0 else 1)
|
override fun getItemCount() =
|
||||||
|
(if (showAllSubjectsOnList) items.size else (if (items.isEmpty()) 0 else 1)) + 1
|
||||||
|
|
||||||
override fun getItemViewType(position: Int) = items[position].type.id
|
override fun getItemViewType(position: Int) =
|
||||||
|
if (position == 0) {
|
||||||
|
ViewType.HEADER.id
|
||||||
|
} else {
|
||||||
|
when (items[position - 1].type) {
|
||||||
|
GradeStatisticsItem.DataType.PARTIAL -> ViewType.PARTIAL.id
|
||||||
|
GradeStatisticsItem.DataType.POINTS -> ViewType.POINTS.id
|
||||||
|
GradeStatisticsItem.DataType.SEMESTER -> ViewType.SEMESTER.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
val inflater = LayoutInflater.from(parent.context)
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
ViewType.PARTIAL.id -> PartialViewHolder(ItemGradeStatisticsPieBinding.inflate(inflater, parent, false))
|
ViewType.PARTIAL.id -> PartialViewHolder(
|
||||||
ViewType.SEMESTER.id -> SemesterViewHolder(ItemGradeStatisticsPieBinding.inflate(inflater, parent, false))
|
ItemGradeStatisticsPieBinding.inflate(inflater, parent, false)
|
||||||
ViewType.POINTS.id -> PointsViewHolder(ItemGradeStatisticsBarBinding.inflate(inflater, parent, false))
|
)
|
||||||
|
ViewType.SEMESTER.id -> SemesterViewHolder(
|
||||||
|
ItemGradeStatisticsPieBinding.inflate(inflater, parent, false)
|
||||||
|
)
|
||||||
|
ViewType.POINTS.id -> PointsViewHolder(
|
||||||
|
ItemGradeStatisticsBarBinding.inflate(inflater, parent, false)
|
||||||
|
)
|
||||||
|
ViewType.HEADER.id -> HeaderViewHolder(
|
||||||
|
ItemGradeStatisticsHeaderBinding.inflate(inflater, parent, false)
|
||||||
|
)
|
||||||
else -> throw IllegalStateException()
|
else -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
val index = position - 1
|
||||||
|
|
||||||
when (holder) {
|
when (holder) {
|
||||||
is PartialViewHolder -> bindPartialChart(holder.binding, items[position].partial!!)
|
is PartialViewHolder -> bindPartialChart(holder.binding, items[index].partial!!)
|
||||||
is SemesterViewHolder -> bindSemesterChart(holder.binding, items[position].semester!!)
|
is SemesterViewHolder -> bindSemesterChart(holder.binding, items[index].semester!!)
|
||||||
is PointsViewHolder -> bindBarChart(holder.binding, items[position].points!!)
|
is PointsViewHolder -> bindBarChart(holder.binding, items[index].points!!)
|
||||||
|
is HeaderViewHolder -> bindHeader(holder.binding)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindPartialChart(binding: ItemGradeStatisticsPieBinding, partials: GradePartialStatistics) {
|
private fun bindHeader(binding: ItemGradeStatisticsHeaderBinding) {
|
||||||
|
binding.gradeStatisticsTypeSwitch.check(
|
||||||
|
when (currentDataType) {
|
||||||
|
GradeStatisticsItem.DataType.PARTIAL -> R.id.gradeStatisticsTypePartial
|
||||||
|
GradeStatisticsItem.DataType.SEMESTER -> R.id.gradeStatisticsTypeSemester
|
||||||
|
GradeStatisticsItem.DataType.POINTS -> R.id.gradeStatisticsTypePoints
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.gradeStatisticsTypeSwitch.setOnCheckedChangeListener { _, checkedId ->
|
||||||
|
currentDataType = when (checkedId) {
|
||||||
|
R.id.gradeStatisticsTypePartial -> GradeStatisticsItem.DataType.PARTIAL
|
||||||
|
R.id.gradeStatisticsTypeSemester -> GradeStatisticsItem.DataType.SEMESTER
|
||||||
|
R.id.gradeStatisticsTypePoints -> GradeStatisticsItem.DataType.POINTS
|
||||||
|
else -> GradeStatisticsItem.DataType.PARTIAL
|
||||||
|
}
|
||||||
|
onDataTypeChangeListener()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bindPartialChart(
|
||||||
|
binding: ItemGradeStatisticsPieBinding,
|
||||||
|
partials: GradePartialStatistics
|
||||||
|
) {
|
||||||
bindPieChart(binding, partials.subject, partials.classAverage, partials.classAmounts)
|
bindPieChart(binding, partials.subject, partials.classAverage, partials.classAmounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindSemesterChart(binding: ItemGradeStatisticsPieBinding, semester: GradeSemesterStatistics) {
|
private fun bindSemesterChart(
|
||||||
|
binding: ItemGradeStatisticsPieBinding,
|
||||||
|
semester: GradeSemesterStatistics
|
||||||
|
) {
|
||||||
bindPieChart(binding, semester.subject, semester.average, semester.amounts)
|
bindPieChart(binding, semester.subject, semester.average, semester.amounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindPieChart(binding: ItemGradeStatisticsPieBinding, subject: String, average: String, amounts: List<Int>) {
|
private fun bindPieChart(
|
||||||
|
binding: ItemGradeStatisticsPieBinding,
|
||||||
|
subject: String,
|
||||||
|
average: String,
|
||||||
|
amounts: List<Int>
|
||||||
|
) {
|
||||||
with(binding.gradeStatisticsPieTitle) {
|
with(binding.gradeStatisticsPieTitle) {
|
||||||
text = subject
|
text = subject
|
||||||
visibility = if (items.size == 1 || !showAllSubjectsOnList) GONE else VISIBLE
|
visibility = if (items.size == 1 || !showAllSubjectsOnList) GONE else VISIBLE
|
||||||
@ -114,7 +172,8 @@ class GradeStatisticsAdapter @Inject constructor() :
|
|||||||
valueTextSize = 12f
|
valueTextSize = 12f
|
||||||
sliceSpace = 1f
|
sliceSpace = 1f
|
||||||
valueTextColor = Color.WHITE
|
valueTextColor = Color.WHITE
|
||||||
val grades = amounts.mapIndexed { grade, amount -> (grade + 1) to amount }.filterNot { it.second == 0 }
|
val grades = amounts.mapIndexed { grade, amount -> (grade + 1) to amount }
|
||||||
|
.filterNot { it.second == 0 }
|
||||||
setColors(grades.reversed().map { (grade, _) ->
|
setColors(grades.reversed().map { (grade, _) ->
|
||||||
gradeColors.single { color -> color.first == grade }.second
|
gradeColors.single { color -> color.first == grade }.second
|
||||||
}.toIntArray(), binding.root.context)
|
}.toIntArray(), binding.root.context)
|
||||||
@ -126,7 +185,11 @@ class GradeStatisticsAdapter @Inject constructor() :
|
|||||||
data = PieData(dataset).apply {
|
data = PieData(dataset).apply {
|
||||||
setValueFormatter(object : ValueFormatter() {
|
setValueFormatter(object : ValueFormatter() {
|
||||||
override fun getPieLabel(value: Float, pieEntry: PieEntry): String {
|
override fun getPieLabel(value: Float, pieEntry: PieEntry): String {
|
||||||
return resources.getQuantityString(R.plurals.grade_number_item, value.toInt(), value.toInt())
|
return resources.getQuantityString(
|
||||||
|
R.plurals.grade_number_item,
|
||||||
|
value.toInt(),
|
||||||
|
value.toInt()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -143,11 +206,14 @@ class GradeStatisticsAdapter @Inject constructor() :
|
|||||||
|
|
||||||
val numberOfGradesString = amounts.fold(0) { acc, it -> acc + it }
|
val numberOfGradesString = amounts.fold(0) { acc, it -> acc + it }
|
||||||
.let { resources.getQuantityString(R.plurals.grade_number_item, it, it) }
|
.let { resources.getQuantityString(R.plurals.grade_number_item, it, it) }
|
||||||
val averageString = binding.root.context.getString(R.string.grade_statistics_average, average)
|
val averageString =
|
||||||
|
binding.root.context.getString(R.string.grade_statistics_average, average)
|
||||||
|
|
||||||
minAngleForSlices = 25f
|
minAngleForSlices = 25f
|
||||||
description.isEnabled = false
|
description.isEnabled = false
|
||||||
centerText = numberOfGradesString + ("\n\n" + averageString).takeIf { average.isNotBlank() }.orEmpty()
|
centerText =
|
||||||
|
numberOfGradesString + ("\n\n" + averageString).takeIf { average.isNotBlank() }
|
||||||
|
.orEmpty()
|
||||||
|
|
||||||
setHoleColor(context.getThemeAttrColor(android.R.attr.windowBackground))
|
setHoleColor(context.getThemeAttrColor(android.R.attr.windowBackground))
|
||||||
setCenterTextColor(context.getThemeAttrColor(android.R.attr.textColorPrimary))
|
setCenterTextColor(context.getThemeAttrColor(android.R.attr.textColorPrimary))
|
||||||
@ -155,16 +221,21 @@ class GradeStatisticsAdapter @Inject constructor() :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindBarChart(binding: ItemGradeStatisticsBarBinding, points: GradePointsStatistics) {
|
private fun bindBarChart(
|
||||||
|
binding: ItemGradeStatisticsBarBinding,
|
||||||
|
points: GradePointsStatistics
|
||||||
|
) {
|
||||||
with(binding.gradeStatisticsBarTitle) {
|
with(binding.gradeStatisticsBarTitle) {
|
||||||
text = points.subject
|
text = points.subject
|
||||||
visibility = if (items.size == 1) GONE else VISIBLE
|
visibility = if (items.size == 1) GONE else VISIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
val dataset = BarDataSet(listOf(
|
val dataset = BarDataSet(
|
||||||
|
listOf(
|
||||||
BarEntry(1f, points.others.toFloat()),
|
BarEntry(1f, points.others.toFloat()),
|
||||||
BarEntry(2f, points.student.toFloat())
|
BarEntry(2f, points.student.toFloat())
|
||||||
), binding.root.context.getString(R.string.grade_statistics_legend))
|
), binding.root.context.getString(R.string.grade_statistics_legend)
|
||||||
|
)
|
||||||
|
|
||||||
with(dataset) {
|
with(dataset) {
|
||||||
valueTextSize = 12f
|
valueTextSize = 12f
|
||||||
@ -189,7 +260,8 @@ class GradeStatisticsAdapter @Inject constructor() :
|
|||||||
form = Legend.LegendForm.SQUARE
|
form = Legend.LegendForm.SQUARE
|
||||||
},
|
},
|
||||||
LegendEntry().apply {
|
LegendEntry().apply {
|
||||||
label = binding.root.context.getString(R.string.grade_statistics_average_student)
|
label =
|
||||||
|
binding.root.context.getString(R.string.grade_statistics_average_student)
|
||||||
formColor = gradePointsColors[1]
|
formColor = gradePointsColors[1]
|
||||||
form = Legend.LegendForm.SQUARE
|
form = Legend.LegendForm.SQUARE
|
||||||
}
|
}
|
||||||
@ -226,4 +298,7 @@ class GradeStatisticsAdapter @Inject constructor() :
|
|||||||
|
|
||||||
private class PointsViewHolder(val binding: ItemGradeStatisticsBarBinding) :
|
private class PointsViewHolder(val binding: ItemGradeStatisticsBarBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
|
private class HeaderViewHolder(val binding: ItemGradeStatisticsHeaderBinding) :
|
||||||
|
RecyclerView.ViewHolder(binding.root)
|
||||||
}
|
}
|
||||||
|
@ -38,27 +38,28 @@ class GradeStatisticsFragment :
|
|||||||
|
|
||||||
override val isViewEmpty get() = statisticsAdapter.items.isEmpty()
|
override val isViewEmpty get() = statisticsAdapter.items.isEmpty()
|
||||||
|
|
||||||
override val currentType
|
override val currentType get() = statisticsAdapter.currentDataType
|
||||||
get() = when (binding.gradeStatisticsTypeSwitch.checkedRadioButtonId) {
|
|
||||||
R.id.gradeStatisticsTypeSemester -> ViewType.SEMESTER
|
|
||||||
R.id.gradeStatisticsTypePartial -> ViewType.PARTIAL
|
|
||||||
else -> ViewType.POINTS
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding = FragmentGradeStatisticsBinding.bind(view)
|
binding = FragmentGradeStatisticsBinding.bind(view)
|
||||||
messageContainer = binding.gradeStatisticsSwipe
|
messageContainer = binding.gradeStatisticsSwipe
|
||||||
presenter.onAttachView(this, savedInstanceState?.getSerializable(SAVED_CHART_TYPE) as? ViewType)
|
presenter.onAttachView(
|
||||||
|
this,
|
||||||
|
savedInstanceState?.getSerializable(SAVED_CHART_TYPE) as? GradeStatisticsItem.DataType
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initView() {
|
override fun initView() {
|
||||||
|
statisticsAdapter.onDataTypeChangeListener = presenter::onTypeChange
|
||||||
|
|
||||||
with(binding.gradeStatisticsRecycler) {
|
with(binding.gradeStatisticsRecycler) {
|
||||||
layoutManager = LinearLayoutManager(requireContext())
|
layoutManager = LinearLayoutManager(requireContext())
|
||||||
adapter = statisticsAdapter
|
adapter = statisticsAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
subjectsAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, mutableListOf())
|
subjectsAdapter =
|
||||||
|
ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, mutableListOf())
|
||||||
subjectsAdapter.setDropDownViewResource(R.layout.item_attendance_summary_subject)
|
subjectsAdapter.setDropDownViewResource(R.layout.item_attendance_summary_subject)
|
||||||
|
|
||||||
with(binding.gradeStatisticsSubjects) {
|
with(binding.gradeStatisticsSubjects) {
|
||||||
@ -71,7 +72,9 @@ class GradeStatisticsFragment :
|
|||||||
|
|
||||||
gradeStatisticsSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
|
gradeStatisticsSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
|
||||||
gradeStatisticsSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
|
gradeStatisticsSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
|
||||||
gradeStatisticsSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh))
|
gradeStatisticsSwipe.setProgressBackgroundColorSchemeColor(
|
||||||
|
requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)
|
||||||
|
)
|
||||||
gradeStatisticsErrorRetry.setOnClickListener { presenter.onRetry() }
|
gradeStatisticsErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||||
gradeStatisticsErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
gradeStatisticsErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||||
}
|
}
|
||||||
@ -85,11 +88,15 @@ class GradeStatisticsFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateData(items: List<GradeStatisticsItem>, theme: String, showAllSubjectsOnStatisticsList: Boolean) {
|
override fun updateData(
|
||||||
|
newItems: List<GradeStatisticsItem>,
|
||||||
|
newTheme: String,
|
||||||
|
showAllSubjectsOnStatisticsList: Boolean
|
||||||
|
) {
|
||||||
with(statisticsAdapter) {
|
with(statisticsAdapter) {
|
||||||
this.showAllSubjectsOnList = showAllSubjectsOnStatisticsList
|
showAllSubjectsOnList = showAllSubjectsOnStatisticsList
|
||||||
this.theme = theme
|
theme = newTheme
|
||||||
this.items = items
|
items = newItems
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,11 +110,7 @@ class GradeStatisticsFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun resetView() {
|
override fun resetView() {
|
||||||
binding.gradeStatisticsScroll.scrollTo(0, 0)
|
binding.gradeStatisticsRecycler.scrollToPosition(0)
|
||||||
}
|
|
||||||
|
|
||||||
override fun showContent(show: Boolean) {
|
|
||||||
binding.gradeStatisticsRecycler.visibility = if (show) View.VISIBLE else View.GONE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showEmpty(show: Boolean) {
|
override fun showEmpty(show: Boolean) {
|
||||||
@ -154,11 +157,6 @@ class GradeStatisticsFragment :
|
|||||||
(parentFragment as? GradeFragment)?.onChildRefresh()
|
(parentFragment as? GradeFragment)?.onChildRefresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
binding.gradeStatisticsTypeSwitch.setOnCheckedChangeListener { _, _ -> presenter.onTypeChange() }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
outState.putSerializable(SAVED_CHART_TYPE, presenter.currentType)
|
outState.putSerializable(SAVED_CHART_TYPE, presenter.currentType)
|
||||||
|
@ -35,12 +35,12 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
|
|
||||||
private lateinit var lastError: Throwable
|
private lateinit var lastError: Throwable
|
||||||
|
|
||||||
var currentType: ViewType = ViewType.PARTIAL
|
var currentType: GradeStatisticsItem.DataType = GradeStatisticsItem.DataType.PARTIAL
|
||||||
private set
|
private set
|
||||||
|
|
||||||
fun onAttachView(view: GradeStatisticsView, type: ViewType?) {
|
fun onAttachView(view: GradeStatisticsView, type: GradeStatisticsItem.DataType?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
currentType = type ?: ViewType.PARTIAL
|
currentType = type ?: GradeStatisticsItem.DataType.PARTIAL
|
||||||
view.initView()
|
view.initView()
|
||||||
errorHandler.showErrorMessage = ::showErrorViewOnError
|
errorHandler.showErrorMessage = ::showErrorViewOnError
|
||||||
}
|
}
|
||||||
@ -59,11 +59,11 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onParentViewChangeSemester() {
|
fun onParentViewChangeSemester() {
|
||||||
|
clearDataInView()
|
||||||
view?.run {
|
view?.run {
|
||||||
showProgress(true)
|
showProgress(true)
|
||||||
enableSwipe(false)
|
enableSwipe(false)
|
||||||
showRefresh(false)
|
showRefresh(false)
|
||||||
showContent(false)
|
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
showEmpty(false)
|
showEmpty(false)
|
||||||
clearView()
|
clearView()
|
||||||
@ -90,8 +90,8 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onSubjectSelected(name: String?) {
|
fun onSubjectSelected(name: String?) {
|
||||||
Timber.i("Select grade stats subject $name")
|
Timber.i("Select grade stats subject $name")
|
||||||
|
clearDataInView()
|
||||||
view?.run {
|
view?.run {
|
||||||
showContent(false)
|
|
||||||
showProgress(true)
|
showProgress(true)
|
||||||
enableSwipe(false)
|
enableSwipe(false)
|
||||||
showEmpty(false)
|
showEmpty(false)
|
||||||
@ -104,11 +104,11 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onTypeChange() {
|
fun onTypeChange() {
|
||||||
val type = view?.currentType ?: ViewType.POINTS
|
val type = view?.currentType ?: GradeStatisticsItem.DataType.POINTS
|
||||||
Timber.i("Select grade stats semester: $type")
|
Timber.i("Select grade stats semester: $type")
|
||||||
cancelJobs("load")
|
cancelJobs("load")
|
||||||
|
clearDataInView()
|
||||||
view?.run {
|
view?.run {
|
||||||
showContent(false)
|
|
||||||
showProgress(true)
|
showProgress(true)
|
||||||
enableSwipe(false)
|
enableSwipe(false)
|
||||||
showEmpty(false)
|
showEmpty(false)
|
||||||
@ -143,10 +143,16 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
}.launch("subjects")
|
}.launch("subjects")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadDataByType(semesterId: Int, subjectName: String, type: ViewType, forceRefresh: Boolean = false) {
|
private fun loadDataByType(
|
||||||
|
semesterId: Int,
|
||||||
|
subjectName: String,
|
||||||
|
type: GradeStatisticsItem.DataType,
|
||||||
|
forceRefresh: Boolean = false
|
||||||
|
) {
|
||||||
Timber.i("Loading grade stats data started")
|
Timber.i("Loading grade stats data started")
|
||||||
|
|
||||||
currentSubjectName = if (preferencesRepository.showAllSubjectsOnStatisticsList) "Wszystkie" else subjectName
|
currentSubjectName =
|
||||||
|
if (preferencesRepository.showAllSubjectsOnStatisticsList) "Wszystkie" else subjectName
|
||||||
currentType = type
|
currentType = type
|
||||||
|
|
||||||
flowWithResourceIn {
|
flowWithResourceIn {
|
||||||
@ -156,9 +162,30 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
|
|
||||||
with(gradeStatisticsRepository) {
|
with(gradeStatisticsRepository) {
|
||||||
when (type) {
|
when (type) {
|
||||||
ViewType.PARTIAL -> getGradesPartialStatistics(student, semester, currentSubjectName, forceRefresh)
|
GradeStatisticsItem.DataType.PARTIAL -> {
|
||||||
ViewType.SEMESTER -> getGradesSemesterStatistics(student, semester, currentSubjectName, forceRefresh)
|
getGradesPartialStatistics(
|
||||||
ViewType.POINTS -> getGradesPointsStatistics(student, semester, currentSubjectName, forceRefresh)
|
student = student,
|
||||||
|
semester = semester,
|
||||||
|
subjectName = currentSubjectName,
|
||||||
|
forceRefresh = forceRefresh
|
||||||
|
)
|
||||||
|
}
|
||||||
|
GradeStatisticsItem.DataType.SEMESTER -> {
|
||||||
|
getGradesSemesterStatistics(
|
||||||
|
student = student,
|
||||||
|
semester = semester,
|
||||||
|
subjectName = currentSubjectName,
|
||||||
|
forceRefresh = forceRefresh
|
||||||
|
)
|
||||||
|
}
|
||||||
|
GradeStatisticsItem.DataType.POINTS -> {
|
||||||
|
getGradesPointsStatistics(
|
||||||
|
student = student,
|
||||||
|
semester = semester,
|
||||||
|
subjectName = currentSubjectName,
|
||||||
|
forceRefresh = forceRefresh
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.onEach {
|
}.onEach {
|
||||||
@ -168,12 +195,15 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
if (!isNoContent) {
|
if (!isNoContent) {
|
||||||
view?.run {
|
view?.run {
|
||||||
showEmpty(isNoContent)
|
showEmpty(isNoContent)
|
||||||
showContent(!isNoContent)
|
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
enableSwipe(true)
|
enableSwipe(true)
|
||||||
showRefresh(true)
|
showRefresh(true)
|
||||||
showProgress(false)
|
showProgress(false)
|
||||||
updateData(it.data!!, preferencesRepository.gradeColorTheme, preferencesRepository.showAllSubjectsOnStatisticsList)
|
updateData(
|
||||||
|
if (isNoContent) emptyList() else it.data!!,
|
||||||
|
preferencesRepository.gradeColorTheme,
|
||||||
|
preferencesRepository.showAllSubjectsOnStatisticsList
|
||||||
|
)
|
||||||
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)
|
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,9 +213,12 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
view?.run {
|
view?.run {
|
||||||
val isNoContent = checkIsNoContent(it.data!!, type)
|
val isNoContent = checkIsNoContent(it.data!!, type)
|
||||||
showEmpty(isNoContent)
|
showEmpty(isNoContent)
|
||||||
showContent(!isNoContent)
|
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
updateData(it.data, preferencesRepository.gradeColorTheme, preferencesRepository.showAllSubjectsOnStatisticsList)
|
updateData(
|
||||||
|
if (isNoContent) emptyList() else it.data,
|
||||||
|
preferencesRepository.gradeColorTheme,
|
||||||
|
preferencesRepository.showAllSubjectsOnStatisticsList
|
||||||
|
)
|
||||||
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)
|
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)
|
||||||
}
|
}
|
||||||
analytics.logEvent(
|
analytics.logEvent(
|
||||||
@ -209,14 +242,29 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
}.launch("load")
|
}.launch("load")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkIsNoContent(items: List<GradeStatisticsItem>, type: ViewType): Boolean {
|
private fun checkIsNoContent(
|
||||||
|
items: List<GradeStatisticsItem>,
|
||||||
|
type: GradeStatisticsItem.DataType
|
||||||
|
): Boolean {
|
||||||
return items.isEmpty() || when (type) {
|
return items.isEmpty() || when (type) {
|
||||||
ViewType.SEMESTER -> items.firstOrNull()?.semester?.amounts.orEmpty().sum() == 0
|
GradeStatisticsItem.DataType.SEMESTER -> {
|
||||||
ViewType.PARTIAL -> items.firstOrNull()?.partial?.classAmounts.orEmpty().sum() == 0
|
items.firstOrNull()?.semester?.amounts.orEmpty().sum() == 0
|
||||||
ViewType.POINTS -> items.firstOrNull()?.points?.let { points ->
|
|
||||||
points.student == .0 && points.others == .0
|
|
||||||
} ?: false
|
|
||||||
}
|
}
|
||||||
|
GradeStatisticsItem.DataType.PARTIAL -> {
|
||||||
|
items.firstOrNull()?.partial?.classAmounts.orEmpty().sum() == 0
|
||||||
|
}
|
||||||
|
GradeStatisticsItem.DataType.POINTS -> {
|
||||||
|
items.firstOrNull()?.points?.let { points -> points.student == .0 && points.others == .0 } ?: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearDataInView() {
|
||||||
|
view?.updateData(
|
||||||
|
emptyList(),
|
||||||
|
preferencesRepository.gradeColorTheme,
|
||||||
|
preferencesRepository.showAllSubjectsOnStatisticsList
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showErrorViewOnError(message: String, error: Throwable) {
|
private fun showErrorViewOnError(message: String, error: Throwable) {
|
||||||
|
@ -7,13 +7,17 @@ interface GradeStatisticsView : BaseView {
|
|||||||
|
|
||||||
val isViewEmpty: Boolean
|
val isViewEmpty: Boolean
|
||||||
|
|
||||||
val currentType: ViewType
|
val currentType: GradeStatisticsItem.DataType
|
||||||
|
|
||||||
fun initView()
|
fun initView()
|
||||||
|
|
||||||
fun updateSubjects(data: ArrayList<String>)
|
fun updateSubjects(data: ArrayList<String>)
|
||||||
|
|
||||||
fun updateData(items: List<GradeStatisticsItem>, theme: String, showAllSubjectsOnStatisticsList: Boolean)
|
fun updateData(
|
||||||
|
newItems: List<GradeStatisticsItem>,
|
||||||
|
newTheme: String,
|
||||||
|
showAllSubjectsOnStatisticsList: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
fun showSubjects(show: Boolean)
|
fun showSubjects(show: Boolean)
|
||||||
|
|
||||||
@ -25,8 +29,6 @@ interface GradeStatisticsView : BaseView {
|
|||||||
|
|
||||||
fun resetView()
|
fun resetView()
|
||||||
|
|
||||||
fun showContent(show: Boolean)
|
|
||||||
|
|
||||||
fun showEmpty(show: Boolean)
|
fun showEmpty(show: Boolean)
|
||||||
|
|
||||||
fun showErrorView(show: Boolean)
|
fun showErrorView(show: Boolean)
|
||||||
|
@ -3,5 +3,6 @@ package io.github.wulkanowy.ui.modules.grade.statistics
|
|||||||
enum class ViewType(val id: Int) {
|
enum class ViewType(val id: Int) {
|
||||||
SEMESTER(1),
|
SEMESTER(1),
|
||||||
PARTIAL(2),
|
PARTIAL(2),
|
||||||
POINTS(3)
|
POINTS(3),
|
||||||
|
HEADER(4)
|
||||||
}
|
}
|
||||||
|
@ -28,14 +28,13 @@ class HomeworkDetailsDialog : BaseDialogFragment<DialogHomeworkBinding>(), Homew
|
|||||||
private lateinit var homework: Homework
|
private lateinit var homework: Homework
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val ARGUMENT_KEY = "Item"
|
private const val ARGUMENT_KEY = "Item"
|
||||||
|
|
||||||
fun newInstance(homework: Homework): HomeworkDetailsDialog {
|
fun newInstance(homework: Homework) = HomeworkDetailsDialog().apply {
|
||||||
return HomeworkDetailsDialog().apply {
|
|
||||||
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, homework) }
|
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, homework) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -45,19 +44,22 @@ class HomeworkDetailsDialog : BaseDialogFragment<DialogHomeworkBinding>(), Homew
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(
|
||||||
return DialogHomeworkBinding.inflate(inflater).apply { binding = this }.root
|
inflater: LayoutInflater,
|
||||||
}
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
) = DialogHomeworkBinding.inflate(inflater).apply { binding = this }.root
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
presenter.onAttachView(this)
|
presenter.onAttachView(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
override fun initView() {
|
override fun initView() {
|
||||||
with(binding) {
|
with(binding) {
|
||||||
homeworkDialogRead.text = view?.context?.getString(if (homework.isDone) R.string.homework_mark_as_undone else R.string.homework_mark_as_done)
|
homeworkDialogRead.text =
|
||||||
|
view?.context?.getString(if (homework.isDone) R.string.homework_mark_as_undone else R.string.homework_mark_as_done)
|
||||||
homeworkDialogRead.setOnClickListener { presenter.toggleDone(homework) }
|
homeworkDialogRead.setOnClickListener { presenter.toggleDone(homework) }
|
||||||
homeworkDialogClose.setOnClickListener { dismiss() }
|
homeworkDialogClose.setOnClickListener { dismiss() }
|
||||||
}
|
}
|
||||||
@ -87,7 +89,8 @@ class HomeworkDetailsDialog : BaseDialogFragment<DialogHomeworkBinding>(), Homew
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun updateMarkAsDoneLabel(isDone: Boolean) {
|
override fun updateMarkAsDoneLabel(isDone: Boolean) {
|
||||||
binding.homeworkDialogRead.text = view?.context?.getString(if (isDone) R.string.homework_mark_as_undone else R.string.homework_mark_as_done)
|
binding.homeworkDialogRead.text =
|
||||||
|
view?.context?.getString(if (isDone) R.string.homework_mark_as_undone else R.string.homework_mark_as_done)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
@ -52,6 +52,8 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
|
|||||||
updateHelper.onResume(this)
|
updateHelper.onResume(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//https://developer.android.com/guide/playcore/in-app-updates#status_callback
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
updateHelper.onActivityResult(requestCode, resultCode)
|
updateHelper.onActivityResult(requestCode, resultCode)
|
||||||
@ -65,13 +67,15 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
|
|||||||
|
|
||||||
with(loginAdapter) {
|
with(loginAdapter) {
|
||||||
containerId = binding.loginViewpager.id
|
containerId = binding.loginViewpager.id
|
||||||
addFragments(listOf(
|
addFragments(
|
||||||
|
listOf(
|
||||||
LoginFormFragment.newInstance(),
|
LoginFormFragment.newInstance(),
|
||||||
LoginSymbolFragment.newInstance(),
|
LoginSymbolFragment.newInstance(),
|
||||||
LoginStudentSelectFragment.newInstance(),
|
LoginStudentSelectFragment.newInstance(),
|
||||||
LoginAdvancedFragment.newInstance(),
|
LoginAdvancedFragment.newInstance(),
|
||||||
LoginRecoverFragment.newInstance()
|
LoginRecoverFragment.newInstance()
|
||||||
))
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
with(binding.loginViewpager) {
|
with(binding.loginViewpager) {
|
||||||
@ -99,14 +103,20 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun notifyInitSymbolFragment(loginData: Triple<String, String, String>) {
|
override fun notifyInitSymbolFragment(loginData: Triple<String, String, String>) {
|
||||||
(loginAdapter.getFragmentInstance(1) as? LoginSymbolFragment)?.onParentInitSymbolFragment(loginData)
|
(loginAdapter.getFragmentInstance(1) as? LoginSymbolFragment)?.onParentInitSymbolFragment(
|
||||||
|
loginData
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun notifyInitStudentSelectFragment(studentsWithSemesters: List<StudentWithSemesters>) {
|
override fun notifyInitStudentSelectFragment(studentsWithSemesters: List<StudentWithSemesters>) {
|
||||||
(loginAdapter.getFragmentInstance(2) as? LoginStudentSelectFragment)?.onParentInitStudentSelectFragment(studentsWithSemesters)
|
(loginAdapter.getFragmentInstance(2) as? LoginStudentSelectFragment)
|
||||||
|
?.onParentInitStudentSelectFragment(studentsWithSemesters)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onFormFragmentAccountLogged(studentsWithSemesters: List<StudentWithSemesters>, loginData: Triple<String, String, String>) {
|
fun onFormFragmentAccountLogged(
|
||||||
|
studentsWithSemesters: List<StudentWithSemesters>,
|
||||||
|
loginData: Triple<String, String, String>
|
||||||
|
) {
|
||||||
presenter.onFormViewAccountLogged(studentsWithSemesters, loginData)
|
presenter.onFormViewAccountLogged(studentsWithSemesters, loginData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,6 +150,13 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setErrorEmailInvalid(domain: String) {
|
||||||
|
with(binding.loginFormUsernameLayout) {
|
||||||
|
requestFocus()
|
||||||
|
error = getString(R.string.login_invalid_custom_email,domain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun clearUsernameError() {
|
override fun clearUsernameError() {
|
||||||
binding.loginFormUsernameLayout.error = null
|
binding.loginFormUsernameLayout.error = null
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import io.github.wulkanowy.utils.flowWithResource
|
|||||||
import io.github.wulkanowy.utils.ifNullOrBlank
|
import io.github.wulkanowy.utils.ifNullOrBlank
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.net.URL
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class LoginFormPresenter @Inject constructor(
|
class LoginFormPresenter @Inject constructor(
|
||||||
@ -87,7 +88,14 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
|
|
||||||
if (!validateCredentials(email, password, host)) return
|
if (!validateCredentials(email, password, host)) return
|
||||||
|
|
||||||
flowWithResource { studentRepository.getStudentsScrapper(email, password, host, symbol) }.onEach {
|
flowWithResource {
|
||||||
|
studentRepository.getStudentsScrapper(
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
host,
|
||||||
|
symbol
|
||||||
|
)
|
||||||
|
}.onEach {
|
||||||
when (it.status) {
|
when (it.status) {
|
||||||
Status.LOADING -> view?.run {
|
Status.LOADING -> view?.run {
|
||||||
Timber.i("Login started")
|
Timber.i("Login started")
|
||||||
@ -150,11 +158,18 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
view?.setErrorLoginRequired()
|
view?.setErrorLoginRequired()
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("@" !in login && "email" in host) {
|
if ("@" !in login && "email" in host) {
|
||||||
view?.setErrorEmailRequired()
|
view?.setErrorEmailRequired()
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
}
|
}
|
||||||
|
if ("@" in login && "login" !in host && "email" !in host) {
|
||||||
|
val emailHost = login.substringAfter("@")
|
||||||
|
val emailDomain = URL(host).host
|
||||||
|
if (emailHost != emailDomain) {
|
||||||
|
view?.setErrorEmailInvalid(domain = emailDomain)
|
||||||
|
isCorrect = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (password.isEmpty()) {
|
if (password.isEmpty()) {
|
||||||
|
@ -39,6 +39,8 @@ interface LoginFormView : BaseView {
|
|||||||
|
|
||||||
fun setErrorPassIncorrect()
|
fun setErrorPassIncorrect()
|
||||||
|
|
||||||
|
fun setErrorEmailInvalid(domain: String)
|
||||||
|
|
||||||
fun clearUsernameError()
|
fun clearUsernameError()
|
||||||
|
|
||||||
fun clearPassError()
|
fun clearPassError()
|
||||||
|
@ -9,6 +9,8 @@ import io.github.wulkanowy.R
|
|||||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||||
import io.github.wulkanowy.databinding.FragmentLuckyNumberBinding
|
import io.github.wulkanowy.databinding.FragmentLuckyNumberBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.luckynumber.history.LuckyNumberHistoryFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -42,6 +44,7 @@ class LuckyNumberFragment :
|
|||||||
luckyNumberSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
|
luckyNumberSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
|
||||||
luckyNumberSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
|
luckyNumberSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
|
||||||
luckyNumberSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh))
|
luckyNumberSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh))
|
||||||
|
luckyNumberHistoryButton.setOnClickListener { openLuckyNumberHistory() }
|
||||||
luckyNumberErrorRetry.setOnClickListener { presenter.onRetry() }
|
luckyNumberErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||||
luckyNumberErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
luckyNumberErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||||
}
|
}
|
||||||
@ -79,6 +82,10 @@ class LuckyNumberFragment :
|
|||||||
binding.luckyNumberContent.visibility = if (show) VISIBLE else GONE
|
binding.luckyNumberContent.visibility = if (show) VISIBLE else GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun openLuckyNumberHistory() {
|
||||||
|
(activity as? MainActivity)?.pushView(LuckyNumberHistoryFragment.newInstance())
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -24,4 +24,6 @@ interface LuckyNumberView : BaseView {
|
|||||||
fun enableSwipe(enable: Boolean)
|
fun enableSwipe(enable: Boolean)
|
||||||
|
|
||||||
fun showContent(show: Boolean)
|
fun showContent(show: Boolean)
|
||||||
|
|
||||||
|
fun openLuckyNumberHistory()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.luckynumber.history
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||||
|
import io.github.wulkanowy.databinding.ItemLuckyNumberHistoryBinding
|
||||||
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
|
import io.github.wulkanowy.utils.weekDayName
|
||||||
|
import java.util.Locale
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class LuckyNumberHistoryAdapter @Inject constructor() :
|
||||||
|
RecyclerView.Adapter<LuckyNumberHistoryAdapter.ItemViewHolder>() {
|
||||||
|
|
||||||
|
var items = emptyList<LuckyNumber>()
|
||||||
|
|
||||||
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
|
||||||
|
ItemLuckyNumberHistoryBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
)
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
|
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
|
||||||
|
val item = items[position]
|
||||||
|
with(holder.binding) {
|
||||||
|
luckyNumberHistoryWeekName.text = item.date.weekDayName.capitalize()
|
||||||
|
luckyNumberHistoryDate.text = item.date.toFormattedString()
|
||||||
|
luckyNumberHistory.text = item.luckyNumber.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ItemViewHolder(val binding: ItemLuckyNumberHistoryBinding) : RecyclerView.ViewHolder(binding.root)
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.luckynumber.history
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.view.View.GONE
|
||||||
|
import android.view.View.VISIBLE
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||||
|
import io.github.wulkanowy.databinding.FragmentLuckyNumberHistoryBinding
|
||||||
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
|
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||||
|
import io.github.wulkanowy.utils.SchooldaysRangeLimiter
|
||||||
|
import io.github.wulkanowy.utils.dpToPx
|
||||||
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
|
import java.time.LocalDate
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class LuckyNumberHistoryFragment :
|
||||||
|
BaseFragment<FragmentLuckyNumberHistoryBinding>(R.layout.fragment_lucky_number_history), LuckyNumberHistoryView,
|
||||||
|
MainView.TitledView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: LuckyNumberHistoryPresenter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var luckyNumberHistoryAdapter: LuckyNumberHistoryAdapter
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = LuckyNumberHistoryFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val titleStringId: Int
|
||||||
|
get() = R.string.lucky_number_history_title
|
||||||
|
|
||||||
|
override val isViewEmpty get() = luckyNumberHistoryAdapter.items.isEmpty()
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
binding = FragmentLuckyNumberHistoryBinding.bind(view)
|
||||||
|
messageContainer = binding.luckyNumberHistoryRecycler
|
||||||
|
presenter.onAttachView(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initView() {
|
||||||
|
with(binding.luckyNumberHistoryRecycler) {
|
||||||
|
layoutManager = LinearLayoutManager(context)
|
||||||
|
adapter = luckyNumberHistoryAdapter
|
||||||
|
addItemDecoration(DividerItemDecoration(context))
|
||||||
|
}
|
||||||
|
|
||||||
|
with(binding) {
|
||||||
|
luckyNumberHistoryNavDate.setOnClickListener { presenter.onPickDate() }
|
||||||
|
luckyNumberHistoryErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||||
|
luckyNumberHistoryErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||||
|
|
||||||
|
luckyNumberHistoryPreviousButton.setOnClickListener { presenter.onPreviousWeek() }
|
||||||
|
luckyNumberHistoryNextButton.setOnClickListener { presenter.onNextWeek() }
|
||||||
|
|
||||||
|
luckyNumberHistoryNavContainer.setElevationCompat(requireContext().dpToPx(8f))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateData(data: List<LuckyNumber>) {
|
||||||
|
with(luckyNumberHistoryAdapter) {
|
||||||
|
items = data
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearData() {
|
||||||
|
with(luckyNumberHistoryAdapter) {
|
||||||
|
items = emptyList()
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showEmpty(show: Boolean) {
|
||||||
|
binding.luckyNumberHistoryEmpty.visibility = if (show) VISIBLE else GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showErrorView(show: Boolean) {
|
||||||
|
binding.luckyNumberHistoryError.visibility = if (show) VISIBLE else GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setErrorDetails(message: String) {
|
||||||
|
binding.luckyNumberHistoryErrorMessage.text = message
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateNavigationWeek(date: String) {
|
||||||
|
binding.luckyNumberHistoryNavDate.text = date
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showProgress(show: Boolean) {
|
||||||
|
binding.luckyNumberHistoryProgress.visibility = if (show) VISIBLE else GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showPreButton(show: Boolean) {
|
||||||
|
binding.luckyNumberHistoryPreviousButton.visibility = if (show) VISIBLE else View.INVISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showNextButton(show: Boolean) {
|
||||||
|
binding.luckyNumberHistoryNextButton.visibility = if (show) VISIBLE else View.INVISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showDatePickerDialog(currentDate: LocalDate) {
|
||||||
|
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
|
||||||
|
presenter.onDateSet(year, month + 1, dayOfMonth)
|
||||||
|
}
|
||||||
|
val datePickerDialog = DatePickerDialog.newInstance(dateSetListener,
|
||||||
|
currentDate.year, currentDate.monthValue - 1, currentDate.dayOfMonth)
|
||||||
|
|
||||||
|
with(datePickerDialog) {
|
||||||
|
setDateRangeLimiter(SchooldaysRangeLimiter())
|
||||||
|
version = DatePickerDialog.Version.VERSION_2
|
||||||
|
scrollOrientation = DatePickerDialog.ScrollOrientation.VERTICAL
|
||||||
|
vibrate(false)
|
||||||
|
show(this@LuckyNumberHistoryFragment.parentFragmentManager, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showContent(show: Boolean) {
|
||||||
|
binding.luckyNumberHistoryRecycler.visibility = if (show) VISIBLE else GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
presenter.onDetachView()
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,151 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.luckynumber.history
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.Status
|
||||||
|
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
|
||||||
|
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.utils.AnalyticsHelper
|
||||||
|
import io.github.wulkanowy.utils.afterLoading
|
||||||
|
import io.github.wulkanowy.utils.flowWithResource
|
||||||
|
import io.github.wulkanowy.utils.isHolidays
|
||||||
|
import io.github.wulkanowy.utils.monday
|
||||||
|
import io.github.wulkanowy.utils.previousOrSameSchoolDay
|
||||||
|
import io.github.wulkanowy.utils.sunday
|
||||||
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.time.LocalDate
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class LuckyNumberHistoryPresenter @Inject constructor(
|
||||||
|
errorHandler: ErrorHandler,
|
||||||
|
studentRepository: StudentRepository,
|
||||||
|
private val luckyNumberRepository: LuckyNumberRepository,
|
||||||
|
private val analytics: AnalyticsHelper
|
||||||
|
) : BasePresenter<LuckyNumberHistoryView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
|
private lateinit var lastError: Throwable
|
||||||
|
|
||||||
|
var currentDate: LocalDate = LocalDate.now().previousOrSameSchoolDay
|
||||||
|
|
||||||
|
override fun onAttachView(view: LuckyNumberHistoryView) {
|
||||||
|
super.onAttachView(view)
|
||||||
|
view.run {
|
||||||
|
initView()
|
||||||
|
reloadNavigation()
|
||||||
|
showContent(false)
|
||||||
|
}
|
||||||
|
Timber.i("Lucky number history view was initialized")
|
||||||
|
errorHandler.showErrorMessage = ::showErrorViewOnError
|
||||||
|
loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadData() {
|
||||||
|
flowWithResource {
|
||||||
|
val student = studentRepository.getCurrentStudent()
|
||||||
|
luckyNumberRepository.getLuckyNumberHistory(student, currentDate.monday, currentDate.sunday)
|
||||||
|
}.onEach {
|
||||||
|
when (it.status) {
|
||||||
|
Status.LOADING -> Timber.i("Loading lucky number history started")
|
||||||
|
Status.SUCCESS -> {
|
||||||
|
if (!it.data?.first().isNullOrEmpty()) {
|
||||||
|
Timber.i("Loading lucky number result: Success")
|
||||||
|
view?.apply {
|
||||||
|
updateData(it.data!!.first())
|
||||||
|
showContent(true)
|
||||||
|
showEmpty(false)
|
||||||
|
showErrorView(false)
|
||||||
|
showProgress(false)
|
||||||
|
}
|
||||||
|
analytics.logEvent(
|
||||||
|
"load_items",
|
||||||
|
"type" to "lucky_number_history",
|
||||||
|
"numbers" to it.data
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Timber.i("Loading lucky number history result: No lucky numbers found")
|
||||||
|
view?.run {
|
||||||
|
showContent(false)
|
||||||
|
showEmpty(true)
|
||||||
|
showErrorView(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Status.ERROR -> {
|
||||||
|
Timber.i("Loading lucky number history result: An exception occurred")
|
||||||
|
errorHandler.dispatch(it.error!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.afterLoading {
|
||||||
|
view?.run {
|
||||||
|
showProgress(false)
|
||||||
|
}
|
||||||
|
}.launch()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showErrorViewOnError(message: String, error: Throwable) {
|
||||||
|
view?.run {
|
||||||
|
if (isViewEmpty) {
|
||||||
|
lastError = error
|
||||||
|
setErrorDetails(message)
|
||||||
|
showErrorView(true)
|
||||||
|
showEmpty(false)
|
||||||
|
} else showError(message, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reloadView(date: LocalDate) {
|
||||||
|
currentDate = date
|
||||||
|
Timber.i("Reload lucky number history view with the date ${currentDate.toFormattedString()}")
|
||||||
|
view?.apply {
|
||||||
|
showProgress(true)
|
||||||
|
showContent(false)
|
||||||
|
showEmpty(false)
|
||||||
|
showErrorView(false)
|
||||||
|
clearData()
|
||||||
|
reloadNavigation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onRetry() {
|
||||||
|
view?.run {
|
||||||
|
showErrorView(false)
|
||||||
|
showProgress(true)
|
||||||
|
}
|
||||||
|
loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onDetailsClick() {
|
||||||
|
view?.showErrorDetailsDialog(lastError)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reloadNavigation() {
|
||||||
|
view?.apply {
|
||||||
|
showPreButton(!currentDate.minusDays(7).isHolidays)
|
||||||
|
showNextButton(!currentDate.plusDays(7).isHolidays)
|
||||||
|
updateNavigationWeek("${currentDate.monday.toFormattedString("dd.MM")} - " +
|
||||||
|
currentDate.sunday.toFormattedString("dd.MM"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onDateSet(year: Int, month: Int, day: Int) {
|
||||||
|
reloadView(LocalDate.of(year, month, day))
|
||||||
|
loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onPickDate() {
|
||||||
|
view?.showDatePickerDialog(currentDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onPreviousWeek() {
|
||||||
|
reloadView(currentDate.minusDays(7))
|
||||||
|
loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onNextWeek() {
|
||||||
|
reloadView(currentDate.plusDays(7))
|
||||||
|
loadData()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.luckynumber.history
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||||
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
import java.time.LocalDate
|
||||||
|
|
||||||
|
interface LuckyNumberHistoryView : BaseView {
|
||||||
|
|
||||||
|
val isViewEmpty: Boolean
|
||||||
|
|
||||||
|
fun initView()
|
||||||
|
|
||||||
|
fun updateData(data: List<LuckyNumber>)
|
||||||
|
|
||||||
|
fun clearData()
|
||||||
|
|
||||||
|
fun showEmpty(show: Boolean)
|
||||||
|
|
||||||
|
fun showErrorView(show: Boolean)
|
||||||
|
|
||||||
|
fun setErrorDetails(message: String)
|
||||||
|
|
||||||
|
fun updateNavigationWeek(date: String)
|
||||||
|
|
||||||
|
fun showProgress(show: Boolean)
|
||||||
|
|
||||||
|
fun showPreButton(show: Boolean)
|
||||||
|
|
||||||
|
fun showNextButton(show: Boolean)
|
||||||
|
|
||||||
|
fun showDatePickerDialog(currentDate: LocalDate)
|
||||||
|
|
||||||
|
fun showContent(show: Boolean)
|
||||||
|
|
||||||
|
fun onDestroyView()
|
||||||
|
}
|
@ -11,15 +11,21 @@ import android.graphics.drawable.Icon
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Build.VERSION.SDK_INT
|
import android.os.Build.VERSION.SDK_INT
|
||||||
import android.os.Build.VERSION_CODES.LOLLIPOP
|
import android.os.Build.VERSION_CODES.LOLLIPOP
|
||||||
|
import android.os.Build.VERSION_CODES.P
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.ViewGroup
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.core.view.updateLayoutParams
|
||||||
|
import androidx.core.view.updateMargins
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import com.aurelhubert.ahbottomnavigation.AHBottomNavigation.TitleState.ALWAYS_SHOW
|
import com.aurelhubert.ahbottomnavigation.AHBottomNavigation.TitleState.ALWAYS_SHOW
|
||||||
import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem
|
import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem
|
||||||
import com.google.android.material.elevation.ElevationOverlayProvider
|
import com.google.android.material.elevation.ElevationOverlayProvider
|
||||||
@ -27,6 +33,8 @@ import com.ncapdevi.fragnav.FragNavController
|
|||||||
import com.ncapdevi.fragnav.FragNavController.Companion.HIDE
|
import com.ncapdevi.fragnav.FragNavController.Companion.HIDE
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.databinding.ActivityMainBinding
|
import io.github.wulkanowy.databinding.ActivityMainBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
|
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
|
||||||
@ -42,15 +50,18 @@ import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
|||||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||||
import io.github.wulkanowy.utils.AppInfo
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import io.github.wulkanowy.utils.UpdateHelper
|
import io.github.wulkanowy.utils.UpdateHelper
|
||||||
|
import io.github.wulkanowy.utils.createNameInitialsDrawable
|
||||||
import io.github.wulkanowy.utils.dpToPx
|
import io.github.wulkanowy.utils.dpToPx
|
||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
|
import io.github.wulkanowy.utils.nickOrName
|
||||||
import io.github.wulkanowy.utils.safelyPopFragments
|
import io.github.wulkanowy.utils.safelyPopFragments
|
||||||
import io.github.wulkanowy.utils.setOnViewChangeListener
|
import io.github.wulkanowy.utils.setOnViewChangeListener
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainView {
|
class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainView,
|
||||||
|
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
override lateinit var presenter: MainPresenter
|
override lateinit var presenter: MainPresenter
|
||||||
@ -64,6 +75,8 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var appInfo: AppInfo
|
lateinit var appInfo: AppInfo
|
||||||
|
|
||||||
|
private var accountMenu: MenuItem? = null
|
||||||
|
|
||||||
private val overlayProvider by lazy { ElevationOverlayProvider(this) }
|
private val overlayProvider by lazy { ElevationOverlayProvider(this) }
|
||||||
|
|
||||||
private val navController =
|
private val navController =
|
||||||
@ -121,6 +134,11 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
initialize(startMenuIndex, savedInstanceState)
|
initialize(startMenuIndex, savedInstanceState)
|
||||||
pushFragment(moreMenuFragments[startMenuMoreIndex])
|
pushFragment(moreMenuFragments[startMenuMoreIndex])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (appInfo.systemVersion >= Build.VERSION_CODES.N_MR1) {
|
||||||
|
initShortcuts()
|
||||||
|
}
|
||||||
|
|
||||||
updateHelper.checkAndInstallUpdates(this)
|
updateHelper.checkAndInstallUpdates(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,11 +147,11 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
updateHelper.onResume(this)
|
updateHelper.onResume(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
//https://developer.android.com/guide/playcore/in-app-updates#status_callback
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
updateHelper.onActivityResult(requestCode, resultCode)
|
updateHelper.onActivityResult(requestCode, resultCode)
|
||||||
if (appInfo.systemVersion >= Build.VERSION_CODES.N_MR1) initShortcuts()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
||||||
@ -160,11 +178,6 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
getString(R.string.timetable_title),
|
getString(R.string.timetable_title),
|
||||||
R.drawable.ic_shortcut_timetable,
|
R.drawable.ic_shortcut_timetable,
|
||||||
MainView.Section.TIMETABLE
|
MainView.Section.TIMETABLE
|
||||||
),
|
|
||||||
Triple(
|
|
||||||
getString(R.string.message_title),
|
|
||||||
R.drawable.ic_shortcut_message,
|
|
||||||
MainView.Section.MESSAGE
|
|
||||||
)
|
)
|
||||||
).forEach { (title, icon, enum) ->
|
).forEach { (title, icon, enum) ->
|
||||||
shortcutsList.add(
|
shortcutsList.add(
|
||||||
@ -191,9 +204,13 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||||
menuInflater.inflate(R.menu.action_menu_main, menu)
|
menuInflater.inflate(R.menu.action_menu_main, menu)
|
||||||
|
accountMenu = menu?.findItem(R.id.mainMenuAccount)
|
||||||
|
|
||||||
|
presenter.onActionMenuCreated()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
override fun initView() {
|
override fun initView() {
|
||||||
with(binding.mainToolbar) {
|
with(binding.mainToolbar) {
|
||||||
if (SDK_INT >= LOLLIPOP) stateListAnimator = null
|
if (SDK_INT >= LOLLIPOP) stateListAnimator = null
|
||||||
@ -233,11 +250,25 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
|
|
||||||
with(navController) {
|
with(navController) {
|
||||||
setOnViewChangeListener { section, name ->
|
setOnViewChangeListener { section, name ->
|
||||||
binding.mainBottomNav.visibility =
|
|
||||||
if (section == MainView.Section.ACCOUNT || section == MainView.Section.STUDENT_INFO) {
|
if (section == MainView.Section.ACCOUNT || section == MainView.Section.STUDENT_INFO) {
|
||||||
View.GONE
|
binding.mainBottomNav.isVisible = false
|
||||||
|
binding.mainFragmentContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
|
updateMargins(bottom = 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appInfo.systemVersion >= P) {
|
||||||
|
window.navigationBarColor = getThemeAttrColor(R.attr.colorSurface)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
View.VISIBLE
|
binding.mainBottomNav.isVisible = true
|
||||||
|
binding.mainFragmentContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
|
updateMargins(bottom = dpToPx(56f).toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appInfo.systemVersion >= P) {
|
||||||
|
window.navigationBarColor =
|
||||||
|
getThemeAttrColor(android.R.attr.navigationBarColor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
analytics.setCurrentScreen(this@MainActivity, name)
|
analytics.setCurrentScreen(this@MainActivity, name)
|
||||||
@ -254,6 +285,16 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPreferenceStartFragment(
|
||||||
|
caller: PreferenceFragmentCompat,
|
||||||
|
pref: Preference
|
||||||
|
): Boolean {
|
||||||
|
val fragment =
|
||||||
|
supportFragmentManager.fragmentFactory.instantiate(classLoader, pref.fragment)
|
||||||
|
navController.pushFragment(fragment)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
return if (item.itemId == R.id.mainMenuAccount) presenter.onAccountManagerSelected()
|
return if (item.itemId == R.id.mainMenuAccount) presenter.onAccountManagerSelected()
|
||||||
else false
|
else false
|
||||||
@ -280,8 +321,8 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
supportActionBar?.setDisplayHomeAsUpEnabled(show)
|
supportActionBar?.setDisplayHomeAsUpEnabled(show)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showAccountPicker() {
|
override fun showAccountPicker(studentWithSemesters: List<StudentWithSemesters>) {
|
||||||
navController.showDialogFragment(AccountQuickDialog.newInstance())
|
navController.showDialogFragment(AccountQuickDialog.newInstance(studentWithSemesters))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showActionBarElevation(show: Boolean) {
|
override fun showActionBarElevation(show: Boolean) {
|
||||||
@ -315,6 +356,13 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
presenter.onBackPressed { super.onBackPressed() }
|
presenter.onBackPressed { super.onBackPressed() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showStudentAvatar(student: Student) {
|
||||||
|
accountMenu?.run {
|
||||||
|
icon = createNameInitialsDrawable(student.nickOrName, student.avatarColor, 0.44f)
|
||||||
|
title = getString(R.string.main_account_picker)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
navController.onSaveInstanceState(outState)
|
navController.onSaveInstanceState(outState)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package io.github.wulkanowy.ui.modules.main
|
package io.github.wulkanowy.ui.modules.main
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.Status
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.services.sync.SyncManager
|
import io.github.wulkanowy.services.sync.SyncManager
|
||||||
@ -9,6 +11,8 @@ import io.github.wulkanowy.ui.modules.main.MainView.Section.GRADE
|
|||||||
import io.github.wulkanowy.ui.modules.main.MainView.Section.MESSAGE
|
import io.github.wulkanowy.ui.modules.main.MainView.Section.MESSAGE
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView.Section.SCHOOL
|
import io.github.wulkanowy.ui.modules.main.MainView.Section.SCHOOL
|
||||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||||
|
import io.github.wulkanowy.utils.flowWithResource
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -17,9 +21,11 @@ class MainPresenter @Inject constructor(
|
|||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val prefRepository: PreferencesRepository,
|
private val prefRepository: PreferencesRepository,
|
||||||
private val syncManager: SyncManager,
|
private val syncManager: SyncManager,
|
||||||
private val analytics: AnalyticsHelper
|
private val analytics: AnalyticsHelper,
|
||||||
) : BasePresenter<MainView>(errorHandler, studentRepository) {
|
) : BasePresenter<MainView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
|
var studentsWitSemesters: List<StudentWithSemesters>? = null
|
||||||
|
|
||||||
fun onAttachView(view: MainView, initMenu: MainView.Section?) {
|
fun onAttachView(view: MainView, initMenu: MainView.Section?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
view.apply {
|
view.apply {
|
||||||
@ -35,6 +41,28 @@ class MainPresenter @Inject constructor(
|
|||||||
analytics.logEvent("app_open", "destination" to initMenu?.name)
|
analytics.logEvent("app_open", "destination" to initMenu?.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onActionMenuCreated() {
|
||||||
|
if (!studentsWitSemesters.isNullOrEmpty()) {
|
||||||
|
showCurrentStudentAvatar()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
flowWithResource { studentRepository.getSavedStudents(false) }
|
||||||
|
.onEach { resource ->
|
||||||
|
when (resource.status) {
|
||||||
|
Status.LOADING -> Timber.i("Loading student avatar data started")
|
||||||
|
Status.SUCCESS -> {
|
||||||
|
studentsWitSemesters = resource.data
|
||||||
|
showCurrentStudentAvatar()
|
||||||
|
}
|
||||||
|
Status.ERROR -> {
|
||||||
|
Timber.i("Loading student avatar result: An exception occurred")
|
||||||
|
errorHandler.dispatch(resource.error!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.launch("avatar")
|
||||||
|
}
|
||||||
|
|
||||||
fun onViewChange(section: MainView.Section?) {
|
fun onViewChange(section: MainView.Section?) {
|
||||||
view?.apply {
|
view?.apply {
|
||||||
showActionBarElevation(section != GRADE && section != MESSAGE && section != SCHOOL)
|
showActionBarElevation(section != GRADE && section != MESSAGE && section != SCHOOL)
|
||||||
@ -48,8 +76,10 @@ class MainPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onAccountManagerSelected(): Boolean {
|
fun onAccountManagerSelected(): Boolean {
|
||||||
|
if (studentsWitSemesters.isNullOrEmpty()) return true
|
||||||
|
|
||||||
Timber.i("Select account manager")
|
Timber.i("Select account manager")
|
||||||
view?.showAccountPicker()
|
view?.showAccountPicker(studentsWitSemesters!!)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +111,13 @@ class MainPresenter @Inject constructor(
|
|||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showCurrentStudentAvatar() {
|
||||||
|
val currentStudent =
|
||||||
|
studentsWitSemesters!!.single { it.student.isCurrent }.student
|
||||||
|
|
||||||
|
view?.showStudentAvatar(currentStudent)
|
||||||
|
}
|
||||||
|
|
||||||
private fun getProperViewIndexes(initMenu: MainView.Section?): Pair<Int, Int> {
|
private fun getProperViewIndexes(initMenu: MainView.Section?): Pair<Int, Int> {
|
||||||
return when (initMenu?.id) {
|
return when (initMenu?.id) {
|
||||||
in 0..3 -> initMenu!!.id to -1
|
in 0..3 -> initMenu!!.id to -1
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package io.github.wulkanowy.ui.modules.main
|
package io.github.wulkanowy.ui.modules.main
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.ui.base.BaseView
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
interface MainView : BaseView {
|
interface MainView : BaseView {
|
||||||
@ -22,7 +24,7 @@ interface MainView : BaseView {
|
|||||||
|
|
||||||
fun showHomeArrow(show: Boolean)
|
fun showHomeArrow(show: Boolean)
|
||||||
|
|
||||||
fun showAccountPicker()
|
fun showAccountPicker(studentWithSemesters: List<StudentWithSemesters>)
|
||||||
|
|
||||||
fun showActionBarElevation(show: Boolean)
|
fun showActionBarElevation(show: Boolean)
|
||||||
|
|
||||||
@ -36,6 +38,8 @@ interface MainView : BaseView {
|
|||||||
|
|
||||||
fun popView(depth: Int = 1)
|
fun popView(depth: Int = 1)
|
||||||
|
|
||||||
|
fun showStudentAvatar(student: Student)
|
||||||
|
|
||||||
interface MainChildView {
|
interface MainChildView {
|
||||||
|
|
||||||
fun onFragmentReselected()
|
fun onFragmentReselected()
|
||||||
|
@ -20,13 +20,15 @@ import io.github.wulkanowy.ui.base.BaseDialogFragment
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MobileDeviceTokenDialog : BaseDialogFragment<DialogMobileDeviceBinding>(), MobileDeviceTokenVIew {
|
class MobileDeviceTokenDialog : BaseDialogFragment<DialogMobileDeviceBinding>(),
|
||||||
|
MobileDeviceTokenVIew {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: MobileDeviceTokenPresenter
|
lateinit var presenter: MobileDeviceTokenPresenter
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance(): MobileDeviceTokenDialog = MobileDeviceTokenDialog()
|
|
||||||
|
fun newInstance() = MobileDeviceTokenDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@ -34,12 +36,14 @@ class MobileDeviceTokenDialog : BaseDialogFragment<DialogMobileDeviceBinding>(),
|
|||||||
setStyle(STYLE_NO_TITLE, 0)
|
setStyle(STYLE_NO_TITLE, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(
|
||||||
return DialogMobileDeviceBinding.inflate(inflater).apply { binding = this }.root
|
inflater: LayoutInflater,
|
||||||
}
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
) = DialogMobileDeviceBinding.inflate(inflater).apply { binding = this }.root
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
presenter.onAttachView(this)
|
presenter.onAttachView(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,9 +63,6 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
|
|||||||
override val settingsRes: Pair<String, Drawable?>?
|
override val settingsRes: Pair<String, Drawable?>?
|
||||||
get() = context?.run { getString(R.string.settings_title) to getCompatDrawable(R.drawable.ic_more_settings) }
|
get() = context?.run { getString(R.string.settings_title) to getCompatDrawable(R.drawable.ic_more_settings) }
|
||||||
|
|
||||||
override val aboutRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.about_title) to getCompatDrawable(R.drawable.ic_all_about) }
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding = FragmentMoreBinding.bind(view)
|
binding = FragmentMoreBinding.bind(view)
|
||||||
@ -124,10 +121,6 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
|
|||||||
(activity as? MainActivity)?.pushView(SettingsFragment.newInstance())
|
(activity as? MainActivity)?.pushView(SettingsFragment.newInstance())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openAboutView() {
|
|
||||||
(activity as? MainActivity)?.pushView(AboutFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popView(depth: Int) {
|
override fun popView(depth: Int) {
|
||||||
(activity as? MainActivity)?.popView(depth)
|
(activity as? MainActivity)?.popView(depth)
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ class MorePresenter @Inject constructor(
|
|||||||
conferencesRes?.first -> openConferencesView()
|
conferencesRes?.first -> openConferencesView()
|
||||||
schoolAndTeachersRes?.first -> openSchoolAndTeachersView()
|
schoolAndTeachersRes?.first -> openSchoolAndTeachersView()
|
||||||
settingsRes?.first -> openSettingsView()
|
settingsRes?.first -> openSettingsView()
|
||||||
aboutRes?.first -> openAboutView()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,8 +50,7 @@ class MorePresenter @Inject constructor(
|
|||||||
mobileDevicesRes,
|
mobileDevicesRes,
|
||||||
conferencesRes,
|
conferencesRes,
|
||||||
schoolAndTeachersRes,
|
schoolAndTeachersRes,
|
||||||
settingsRes,
|
settingsRes
|
||||||
aboutRes
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,16 +21,12 @@ interface MoreView : BaseView {
|
|||||||
|
|
||||||
val settingsRes: Pair<String, Drawable?>?
|
val settingsRes: Pair<String, Drawable?>?
|
||||||
|
|
||||||
val aboutRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
fun initView()
|
fun initView()
|
||||||
|
|
||||||
fun updateData(data: List<Pair<String, Drawable?>>)
|
fun updateData(data: List<Pair<String, Drawable?>>)
|
||||||
|
|
||||||
fun openSettingsView()
|
fun openSettingsView()
|
||||||
|
|
||||||
fun openAboutView()
|
|
||||||
|
|
||||||
fun popView(depth: Int)
|
fun popView(depth: Int)
|
||||||
|
|
||||||
fun openMessagesView()
|
fun openMessagesView()
|
||||||
|
@ -22,14 +22,13 @@ class NoteDialog : DialogFragment() {
|
|||||||
private lateinit var note: Note
|
private lateinit var note: Note
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val ARGUMENT_KEY = "Item"
|
private const val ARGUMENT_KEY = "Item"
|
||||||
|
|
||||||
fun newInstance(exam: Note): NoteDialog {
|
fun newInstance(exam: Note) = NoteDialog().apply {
|
||||||
return NoteDialog().apply {
|
|
||||||
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) }
|
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -39,13 +38,15 @@ class NoteDialog : DialogFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(
|
||||||
return DialogNoteBinding.inflate(inflater).apply { binding = this }.root
|
inflater: LayoutInflater,
|
||||||
}
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
) = DialogNoteBinding.inflate(inflater).apply { binding = this }.root
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
with(binding) {
|
with(binding) {
|
||||||
noteDialogDate.text = note.date.toFormattedString()
|
noteDialogDate.text = note.date.toFormattedString()
|
||||||
@ -57,11 +58,19 @@ class NoteDialog : DialogFragment() {
|
|||||||
if (note.isPointsShow) {
|
if (note.isPointsShow) {
|
||||||
with(binding.noteDialogPoints) {
|
with(binding.noteDialogPoints) {
|
||||||
text = "${if (note.points > 0) "+" else ""}${note.points}"
|
text = "${if (note.points > 0) "+" else ""}${note.points}"
|
||||||
setTextColor(when (NoteCategory.getByValue(note.categoryType)) {
|
setTextColor(
|
||||||
NoteCategory.POSITIVE -> ContextCompat.getColor(requireContext(), R.color.note_positive)
|
when (NoteCategory.getByValue(note.categoryType)) {
|
||||||
NoteCategory.NEGATIVE -> ContextCompat.getColor(requireContext(), R.color.note_negative)
|
NoteCategory.POSITIVE -> ContextCompat.getColor(
|
||||||
|
requireContext(),
|
||||||
|
R.color.note_positive
|
||||||
|
)
|
||||||
|
NoteCategory.NEGATIVE -> ContextCompat.getColor(
|
||||||
|
requireContext(),
|
||||||
|
R.color.note_negative
|
||||||
|
)
|
||||||
else -> requireContext().getThemeAttrColor(android.R.attr.textColorPrimary)
|
else -> requireContext().getThemeAttrColor(android.R.attr.textColorPrimary)
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,148 +1,22 @@
|
|||||||
package io.github.wulkanowy.ui.modules.settings
|
package io.github.wulkanowy.ui.modules.settings
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.preference.Preference
|
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import com.thelittlefireman.appkillermanager.AppKillerManager
|
|
||||||
import com.thelittlefireman.appkillermanager.exceptions.NoActionFoundException
|
|
||||||
import com.yariksoffice.lingver.Lingver
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
|
||||||
import io.github.wulkanowy.ui.base.ErrorDialog
|
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
import io.github.wulkanowy.utils.AppInfo
|
import timber.log.Timber
|
||||||
import io.github.wulkanowy.utils.openInternetBrowser
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
class SettingsFragment : PreferenceFragmentCompat(), MainView.TitledView {
|
||||||
class SettingsFragment : PreferenceFragmentCompat(),
|
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener,
|
|
||||||
MainView.TitledView, SettingsView {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var presenter: SettingsPresenter
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var appInfo: AppInfo
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var lingver: Lingver
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun newInstance() = SettingsFragment()
|
fun newInstance() = SettingsFragment()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val titleStringId get() = R.string.settings_title
|
override val titleStringId get() = R.string.settings_title
|
||||||
|
|
||||||
override val syncSuccessString get() = getString(R.string.pref_services_message_sync_success)
|
|
||||||
|
|
||||||
override val syncFailedString get() = getString(R.string.pref_services_message_sync_failed)
|
|
||||||
|
|
||||||
override fun initView() {
|
|
||||||
findPreference<Preference>(getString(R.string.pref_key_services_force_sync))?.run {
|
|
||||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
|
||||||
presenter.onSyncNowClicked()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
findPreference<Preference>(getString(R.string.pref_key_notifications_fix_issues))?.run {
|
|
||||||
isVisible = AppKillerManager.isDeviceSupported() && AppKillerManager.isAnyActionAvailable(requireContext())
|
|
||||||
setOnPreferenceClickListener {
|
|
||||||
presenter.onFixSyncIssuesClicked()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
||||||
super.onActivityCreated(savedInstanceState)
|
|
||||||
presenter.onAttachView(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
setPreferencesFromResource(R.xml.scheme_preferences, rootKey)
|
setPreferencesFromResource(R.xml.scheme_preferences, rootKey)
|
||||||
findPreference<Preference>(getString(R.string.pref_key_notification_debug))?.isVisible = appInfo.isDebug
|
Timber.i("Settings view was initialized")
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
|
||||||
presenter.onSharedPreferenceChanged(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun recreateView() {
|
|
||||||
activity?.recreate()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateLanguage(langCode: String) {
|
|
||||||
lingver.setLocale(requireContext(), langCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateLanguageToFollowSystem() {
|
|
||||||
lingver.setFollowSystemLocale(requireContext())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean) {
|
|
||||||
findPreference<Preference>(serviceEnablesKey)?.run {
|
|
||||||
summary = if (isHolidays) getString(R.string.pref_services_suspended) else ""
|
|
||||||
isEnabled = !isHolidays
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setSyncInProgress(inProgress: Boolean) {
|
|
||||||
if (activity == null || !isAdded) return
|
|
||||||
|
|
||||||
findPreference<Preference>(getString(R.string.pref_key_services_force_sync))?.run {
|
|
||||||
isEnabled = !inProgress
|
|
||||||
summary = if (inProgress) getString(R.string.pref_services_sync_in_progress) else ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showError(text: String, error: Throwable) {
|
|
||||||
(activity as? BaseActivity<*, *>)?.showError(text, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showMessage(text: String) {
|
|
||||||
(activity as? BaseActivity<*, *>)?.showMessage(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showExpiredDialog() {
|
|
||||||
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openClearLoginView() {
|
|
||||||
(activity as? BaseActivity<*, *>)?.openClearLoginView()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showErrorDetailsDialog(error: Throwable) {
|
|
||||||
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showFixSyncDialog() {
|
|
||||||
AlertDialog.Builder(requireContext())
|
|
||||||
.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) { _, _ ->
|
|
||||||
try {
|
|
||||||
AppKillerManager.doActionPowerSaving(requireContext())
|
|
||||||
AppKillerManager.doActionAutoStart(requireContext())
|
|
||||||
AppKillerManager.doActionNotification(requireContext())
|
|
||||||
} catch (e: NoActionFoundException) {
|
|
||||||
requireContext().openInternetBrowser("https://dontkillmyapp.com/${AppKillerManager.getDevice()?.manufacturer}", ::showMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.advanced
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import com.yariksoffice.lingver.Lingver
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
|
import io.github.wulkanowy.ui.base.ErrorDialog
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class AdvancedFragment : PreferenceFragmentCompat(),
|
||||||
|
SharedPreferences.OnSharedPreferenceChangeListener,
|
||||||
|
MainView.TitledView, AdvancedView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: AdvancedPresenter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var appInfo: AppInfo
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var lingver: Lingver
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = AdvancedFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val titleStringId get() = R.string.pref_settings_advanced_title
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
presenter.onAttachView(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.scheme_preferences_advanced, rootKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||||
|
presenter.onSharedPreferenceChanged(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showError(text: String, error: Throwable) {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showError(text, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showMessage(text: String) {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showMessage(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showExpiredDialog() {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openClearLoginView() {
|
||||||
|
(activity as? BaseActivity<*, *>)?.openClearLoginView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showErrorDetailsDialog(error: Throwable) {
|
||||||
|
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.advanced
|
||||||
|
|
||||||
|
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.utils.AnalyticsHelper
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class AdvancedPresenter @Inject constructor(
|
||||||
|
errorHandler: ErrorHandler,
|
||||||
|
studentRepository: StudentRepository,
|
||||||
|
private val analytics: AnalyticsHelper,
|
||||||
|
) : BasePresenter<AdvancedView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
|
override fun onAttachView(view: AdvancedView) {
|
||||||
|
super.onAttachView(view)
|
||||||
|
Timber.i("Settings advanced view was initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onSharedPreferenceChanged(key: String) {
|
||||||
|
Timber.i("Change settings $key")
|
||||||
|
analytics.logEvent("setting_changed", "name" to key)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.advanced
|
||||||
|
|
||||||
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
|
interface AdvancedView : BaseView {}
|
@ -0,0 +1,90 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.appearance
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import com.yariksoffice.lingver.Lingver
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
|
import io.github.wulkanowy.ui.base.ErrorDialog
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class AppearanceFragment : PreferenceFragmentCompat(),
|
||||||
|
SharedPreferences.OnSharedPreferenceChangeListener,
|
||||||
|
MainView.TitledView, AppearanceView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: AppearancePresenter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var appInfo: AppInfo
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var lingver: Lingver
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = AppearanceFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val titleStringId get() = R.string.pref_settings_appearance_title
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
presenter.onAttachView(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.scheme_preferences_appearance, rootKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||||
|
presenter.onSharedPreferenceChanged(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun recreateView() {
|
||||||
|
activity?.recreate()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateLanguage(langCode: String) {
|
||||||
|
lingver.setLocale(requireContext(), langCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateLanguageToFollowSystem() {
|
||||||
|
lingver.setFollowSystemLocale(requireContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showError(text: String, error: Throwable) {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showError(text, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showMessage(text: String) {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showMessage(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showExpiredDialog() {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openClearLoginView() {
|
||||||
|
(activity as? BaseActivity<*, *>)?.openClearLoginView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showErrorDetailsDialog(error: Throwable) {
|
||||||
|
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.appearance
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
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.utils.AnalyticsHelper
|
||||||
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class AppearancePresenter @Inject constructor(
|
||||||
|
errorHandler: ErrorHandler,
|
||||||
|
studentRepository: StudentRepository,
|
||||||
|
private val preferencesRepository: PreferencesRepository,
|
||||||
|
private val analytics: AnalyticsHelper,
|
||||||
|
private val appInfo: AppInfo
|
||||||
|
) : BasePresenter<AppearanceView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
|
override fun onAttachView(view: AppearanceView) {
|
||||||
|
super.onAttachView(view)
|
||||||
|
Timber.i("Settings appearance view was initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onSharedPreferenceChanged(key: String) {
|
||||||
|
Timber.i("Change settings $key")
|
||||||
|
|
||||||
|
preferencesRepository.apply {
|
||||||
|
when (key) {
|
||||||
|
appThemeKey -> view?.recreateView()
|
||||||
|
appLanguageKey -> view?.run {
|
||||||
|
if (appLanguage == "system") {
|
||||||
|
updateLanguageToFollowSystem()
|
||||||
|
analytics.logEvent("language", "setting_changed" to appInfo.systemLanguage)
|
||||||
|
} else {
|
||||||
|
updateLanguage(appLanguage)
|
||||||
|
analytics.logEvent("language", "setting_changed" to appLanguage)
|
||||||
|
}
|
||||||
|
recreateView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
analytics.logEvent("setting_changed", "name" to key)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.appearance
|
||||||
|
|
||||||
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
|
interface AppearanceView : BaseView {
|
||||||
|
|
||||||
|
fun recreateView()
|
||||||
|
|
||||||
|
fun updateLanguage(langCode: String)
|
||||||
|
|
||||||
|
fun updateLanguageToFollowSystem()
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.notifications
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.thelittlefireman.appkillermanager.AppKillerManager
|
||||||
|
import com.thelittlefireman.appkillermanager.exceptions.NoActionFoundException
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
|
import io.github.wulkanowy.ui.base.ErrorDialog
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
|
import io.github.wulkanowy.utils.openInternetBrowser
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class NotificationsFragment : PreferenceFragmentCompat(),
|
||||||
|
SharedPreferences.OnSharedPreferenceChangeListener,
|
||||||
|
MainView.TitledView, NotificationsView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: NotificationsPresenter
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = NotificationsFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val titleStringId get() = R.string.pref_settings_notifications_title
|
||||||
|
|
||||||
|
override fun initView(showDebugNotificationSwitch: Boolean) {
|
||||||
|
findPreference<Preference>(getString(R.string.pref_key_notification_debug))?.isVisible =
|
||||||
|
showDebugNotificationSwitch
|
||||||
|
|
||||||
|
findPreference<Preference>(getString(R.string.pref_key_notifications_fix_issues))?.run {
|
||||||
|
isVisible = AppKillerManager.isDeviceSupported()
|
||||||
|
&& AppKillerManager.isAnyActionAvailable(requireContext())
|
||||||
|
|
||||||
|
setOnPreferenceClickListener {
|
||||||
|
presenter.onFixSyncIssuesClicked()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateRecyclerView(
|
||||||
|
inflater: LayoutInflater?,
|
||||||
|
parent: ViewGroup?,
|
||||||
|
state: Bundle?
|
||||||
|
): RecyclerView? = super.onCreateRecyclerView(inflater, parent, state)
|
||||||
|
.also {
|
||||||
|
it.itemAnimator = null
|
||||||
|
it.layoutAnimation = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
presenter.onAttachView(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.scheme_preferences_notifications, rootKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||||
|
presenter.onSharedPreferenceChanged(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun enableNotification(notificationKey: String, enable: Boolean) {
|
||||||
|
findPreference<Preference>(notificationKey)?.run {
|
||||||
|
isEnabled = enable
|
||||||
|
summary = if (enable) null else getString(R.string.pref_notify_disabled_summary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showError(text: String, error: Throwable) {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showError(text, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showMessage(text: String) {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showMessage(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showExpiredDialog() {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openClearLoginView() {
|
||||||
|
(activity as? BaseActivity<*, *>)?.openClearLoginView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showErrorDetailsDialog(error: Throwable) {
|
||||||
|
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showFixSyncDialog() {
|
||||||
|
AlertDialog.Builder(requireContext())
|
||||||
|
.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) { _, _ ->
|
||||||
|
try {
|
||||||
|
AppKillerManager.doActionPowerSaving(requireContext())
|
||||||
|
AppKillerManager.doActionAutoStart(requireContext())
|
||||||
|
AppKillerManager.doActionNotification(requireContext())
|
||||||
|
} catch (e: NoActionFoundException) {
|
||||||
|
requireContext().openInternetBrowser(
|
||||||
|
"https://dontkillmyapp.com/${AppKillerManager.getDevice()?.manufacturer}",
|
||||||
|
::showMessage
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.notifications
|
||||||
|
|
||||||
|
import com.chuckerteam.chucker.api.ChuckerCollector
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
|
import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
|
||||||
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
|
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||||
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class NotificationsPresenter @Inject constructor(
|
||||||
|
errorHandler: ErrorHandler,
|
||||||
|
studentRepository: StudentRepository,
|
||||||
|
private val preferencesRepository: PreferencesRepository,
|
||||||
|
private val timetableNotificationHelper: TimetableNotificationSchedulerHelper,
|
||||||
|
private val appInfo: AppInfo,
|
||||||
|
private val analytics: AnalyticsHelper,
|
||||||
|
private val chuckerCollector: ChuckerCollector
|
||||||
|
) : BasePresenter<NotificationsView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
|
override fun onAttachView(view: NotificationsView) {
|
||||||
|
super.onAttachView(view)
|
||||||
|
|
||||||
|
with(view) {
|
||||||
|
enableNotification(
|
||||||
|
preferencesRepository.notificationsEnableKey,
|
||||||
|
preferencesRepository.isServiceEnabled
|
||||||
|
)
|
||||||
|
initView(appInfo.isDebug)
|
||||||
|
}
|
||||||
|
Timber.i("Settings notifications view was initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onSharedPreferenceChanged(key: String) {
|
||||||
|
Timber.i("Change settings $key")
|
||||||
|
|
||||||
|
preferencesRepository.apply {
|
||||||
|
when (key) {
|
||||||
|
isUpcomingLessonsNotificationsEnableKey -> {
|
||||||
|
if (!isUpcomingLessonsNotificationsEnable) {
|
||||||
|
timetableNotificationHelper.cancelNotification()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isDebugNotificationEnableKey -> {
|
||||||
|
chuckerCollector.showNotification = isDebugNotificationEnable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
analytics.logEvent("setting_changed", "name" to key)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onFixSyncIssuesClicked() {
|
||||||
|
view?.showFixSyncDialog()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.notifications
|
||||||
|
|
||||||
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
|
interface NotificationsView : BaseView {
|
||||||
|
|
||||||
|
fun initView(showDebugNotificationSwitch: Boolean)
|
||||||
|
|
||||||
|
fun showFixSyncDialog()
|
||||||
|
|
||||||
|
fun enableNotification(notificationKey: String, enable: Boolean)
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.sync
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
|
import io.github.wulkanowy.ui.base.ErrorDialog
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class SyncFragment : PreferenceFragmentCompat(),
|
||||||
|
SharedPreferences.OnSharedPreferenceChangeListener,
|
||||||
|
MainView.TitledView, SyncView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: SyncPresenter
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = SyncFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val titleStringId get() = R.string.pref_settings_sync_title
|
||||||
|
|
||||||
|
override val syncSuccessString get() = getString(R.string.pref_services_message_sync_success)
|
||||||
|
|
||||||
|
override val syncFailedString get() = getString(R.string.pref_services_message_sync_failed)
|
||||||
|
|
||||||
|
override fun initView() {
|
||||||
|
findPreference<Preference>(getString(R.string.pref_key_services_force_sync))?.run {
|
||||||
|
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
presenter.onSyncNowClicked()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
presenter.onAttachView(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.scheme_preferences_sync, rootKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||||
|
presenter.onSharedPreferenceChanged(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean) {
|
||||||
|
findPreference<Preference>(serviceEnablesKey)?.run {
|
||||||
|
summary = if (isHolidays) getString(R.string.pref_services_suspended) else ""
|
||||||
|
isEnabled = !isHolidays
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setSyncInProgress(inProgress: Boolean) {
|
||||||
|
if (activity == null || !isAdded) return
|
||||||
|
|
||||||
|
findPreference<Preference>(getString(R.string.pref_key_services_force_sync))?.run {
|
||||||
|
isEnabled = !inProgress
|
||||||
|
summary = if (inProgress) getString(R.string.pref_services_sync_in_progress) else ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showError(text: String, error: Throwable) {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showError(text, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showMessage(text: String) {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showMessage(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showExpiredDialog() {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openClearLoginView() {
|
||||||
|
(activity as? BaseActivity<*, *>)?.openClearLoginView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showErrorDetailsDialog(error: Throwable) {
|
||||||
|
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user