mirror of
https://github.com/wulkanowy/wulkanowy.git
synced 2025-02-23 18:54:45 +01:00
Merge branch 'release/1.7.0'
This commit is contained in:
commit
c293c76398
20
.github/workflows/deploy-store.yml
vendored
20
.github/workflows/deploy-store.yml
vendored
@ -1,4 +1,4 @@
|
|||||||
name: Deploy to app stores
|
name: Deploy release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
@ -7,16 +7,17 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
deploy-google-play:
|
deploy-google-play:
|
||||||
name: Deploy to google play
|
name: Google Play
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
environment: google-play
|
environment: google-play
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
java-version: 11
|
java-version: 11
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
@ -41,16 +42,17 @@ jobs:
|
|||||||
run: ./gradlew publishPlayReleaseApps -PenableFirebase --stacktrace;
|
run: ./gradlew publishPlayReleaseApps -PenableFirebase --stacktrace;
|
||||||
|
|
||||||
deploy-app-gallery:
|
deploy-app-gallery:
|
||||||
name: Deploy to AppGallery
|
name: AppGallery
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
environment: app-gallery
|
environment: app-gallery
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
java-version: 11
|
java-version: 11
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
|
20
.github/workflows/deploy-test.yml
vendored
20
.github/workflows/deploy-test.yml
vendored
@ -1,4 +1,4 @@
|
|||||||
name: Deploy to app tests
|
name: Deploy DEV
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@ -18,11 +18,12 @@ jobs:
|
|||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
environment: app-center
|
environment: app-center
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
java-version: 11
|
java-version: 11
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
@ -66,7 +67,7 @@ jobs:
|
|||||||
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
|
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
|
||||||
run: ./gradlew assembleFdroidDebug --stacktrace
|
run: ./gradlew assembleFdroidDebug --stacktrace
|
||||||
- name: Upload apk to github artifacts
|
- name: Upload apk to github artifacts
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: wulkanowyDEV-${{ env.RUN_NUMBER }}.apk
|
name: wulkanowyDEV-${{ env.RUN_NUMBER }}.apk
|
||||||
path: app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk
|
path: app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk
|
||||||
@ -87,11 +88,12 @@ jobs:
|
|||||||
environment: app-distribution
|
environment: app-distribution
|
||||||
if: github.event_name != 'pull_request_target'
|
if: github.event_name != 'pull_request_target'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
java-version: 11
|
java-version: 11
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
@ -131,7 +133,7 @@ jobs:
|
|||||||
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
|
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
|
||||||
run: ./gradlew assemblePlayDebug -PenableFirebase --stacktrace
|
run: ./gradlew assemblePlayDebug -PenableFirebase --stacktrace
|
||||||
- name: Upload apk to github artifacts
|
- name: Upload apk to github artifacts
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: wulkanowyDEV-${{ env.RUN_NUMBER }}-dev.apk
|
name: wulkanowyDEV-${{ env.RUN_NUMBER }}-dev.apk
|
||||||
path: app/build/outputs/apk/play/debug/app-play-debug.apk
|
path: app/build/outputs/apk/play/debug/app-play-debug.apk
|
||||||
|
66
.github/workflows/test.yml
vendored
66
.github/workflows/test.yml
vendored
@ -8,18 +8,20 @@ on:
|
|||||||
branches: [ master, develop ]
|
branches: [ master, develop ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
unit-tests:
|
|
||||||
name: Unit tests
|
tests-fdroid:
|
||||||
|
name: F-Droid
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
- uses: fkirc/skip-duplicate-actions@master
|
- uses: fkirc/skip-duplicate-actions@master
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: gradle/wrapper-validation-action@v1
|
- uses: gradle/wrapper-validation-action@v1
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
java-version: 11
|
java-version: 11
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
@ -29,6 +31,58 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
./gradlew testFdroidDebugUnitTest --stacktrace
|
./gradlew testFdroidDebugUnitTest --stacktrace
|
||||||
./gradlew jacocoTestReport --stacktrace
|
./gradlew jacocoTestReport --stacktrace
|
||||||
- uses: codecov/codecov-action@v1
|
- uses: codecov/codecov-action@v3
|
||||||
|
with:
|
||||||
|
flags: unit
|
||||||
|
|
||||||
|
tests-play:
|
||||||
|
name: Play
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- uses: fkirc/skip-duplicate-actions@master
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: gradle/wrapper-validation-action@v1
|
||||||
|
- uses: actions/setup-java@v2
|
||||||
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
|
java-version: 11
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
./gradlew testPlayDebugUnitTest --stacktrace
|
||||||
|
./gradlew jacocoTestReport --stacktrace
|
||||||
|
- uses: codecov/codecov-action@v3
|
||||||
|
with:
|
||||||
|
flags: unit
|
||||||
|
|
||||||
|
tests-hms:
|
||||||
|
name: HMS
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- uses: fkirc/skip-duplicate-actions@master
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: gradle/wrapper-validation-action@v1
|
||||||
|
- uses: actions/setup-java@v2
|
||||||
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
|
java-version: 11
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
./gradlew testHmsDebugUnitTest --stacktrace
|
||||||
|
./gradlew jacocoTestReport --stacktrace
|
||||||
|
- uses: codecov/codecov-action@v3
|
||||||
with:
|
with:
|
||||||
flags: unit
|
flags: unit
|
||||||
|
@ -51,7 +51,7 @@ Die aktuelle Version können Sie von der Google Play, F-Droid oder Huawei AppGal
|
|||||||
alt="Explore it on AppGallery"
|
alt="Explore it on AppGallery"
|
||||||
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
|
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
|
||||||
|
|
||||||
Sie können auch ein [Entwicklungsversion herunterladen](https://wulkanowy.github.io/#download) das beinhaltet neue Funktionen, die für die nächste Version vorbereitet werden
|
Sie können auch eine [Entwicklungsversion herunterladen](https://wulkanowy.github.io/#download) die beinhaltet neue Funktionen, die für die nächste Version vorbereitet werden
|
||||||
|
|
||||||
## Gebaut mit
|
## Gebaut mit
|
||||||
|
|
||||||
|
@ -15,15 +15,16 @@ apply from: 'sonarqube.gradle'
|
|||||||
apply from: 'hooks.gradle'
|
apply from: 'hooks.gradle'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 31
|
namespace 'io.github.wulkanowy'
|
||||||
|
compileSdkVersion 32
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "io.github.wulkanowy"
|
applicationId "io.github.wulkanowy"
|
||||||
testApplicationId "io.github.tests.wulkanowy"
|
testApplicationId "io.github.tests.wulkanowy"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 31
|
targetSdkVersion 32
|
||||||
versionCode 108
|
versionCode 109
|
||||||
versionName "1.6.4"
|
versionName "1.7.0"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
resValue "string", "app_name", "Wulkanowy"
|
resValue "string", "app_name", "Wulkanowy"
|
||||||
@ -42,6 +43,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "null"
|
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "null"
|
||||||
|
buildConfigField "String", "DASHBOARD_TILE_AD_ID", "null"
|
||||||
|
|
||||||
if (System.env.SET_BUILD_TIMESTAMP) {
|
if (System.env.SET_BUILD_TIMESTAMP) {
|
||||||
buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis())
|
buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis())
|
||||||
@ -98,6 +100,8 @@ android {
|
|||||||
admob_project_id: System.getenv("ADMOB_PROJECT_ID") ?: "ca-app-pub-3940256099942544~3347511713"
|
admob_project_id: System.getenv("ADMOB_PROJECT_ID") ?: "ca-app-pub-3940256099942544~3347511713"
|
||||||
]
|
]
|
||||||
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "\"${System.getenv("SINGLE_SUPPORT_AD_ID") ?: "ca-app-pub-3940256099942544/5354046379"}\""
|
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "\"${System.getenv("SINGLE_SUPPORT_AD_ID") ?: "ca-app-pub-3940256099942544/5354046379"}\""
|
||||||
|
buildConfigField "String", "DASHBOARD_TILE_AD_ID", "\"${System.getenv("DASHBOARD_TILE_AD_ID") ?: "ca-app-pub-3940256099942544/6300978111"}\""
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fdroid {
|
fdroid {
|
||||||
@ -122,6 +126,8 @@ android {
|
|||||||
|
|
||||||
testOptions.unitTests {
|
testOptions.unitTests {
|
||||||
includeAndroidResources = true
|
includeAndroidResources = true
|
||||||
|
// workaround HMS test errors https://github.com/robolectric/robolectric/issues/2750
|
||||||
|
all { jvmArgs '-noverify' }
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
@ -136,8 +142,10 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
exclude 'META-INF/library_release.kotlin_module'
|
resources {
|
||||||
exclude 'META-INF/library-core_release.kotlin_module'
|
excludes += ['META-INF/library_release.kotlin_module',
|
||||||
|
'META-INF/library-core_release.kotlin_module']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
aboutLibraries {
|
aboutLibraries {
|
||||||
@ -153,8 +161,8 @@ play {
|
|||||||
defaultToAppBundles = false
|
defaultToAppBundles = false
|
||||||
track = 'production'
|
track = 'production'
|
||||||
releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS
|
releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS
|
||||||
userFraction = 0.50d
|
userFraction = 0.05d
|
||||||
updatePriority = 3
|
updatePriority = 5
|
||||||
enabled.set(false)
|
enabled.set(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,34 +179,34 @@ huaweiPublish {
|
|||||||
ext {
|
ext {
|
||||||
work_manager = "2.7.1"
|
work_manager = "2.7.1"
|
||||||
android_hilt = "1.0.0"
|
android_hilt = "1.0.0"
|
||||||
room = "2.4.2"
|
room = "2.4.3"
|
||||||
chucker = "3.5.2"
|
chucker = "3.5.2"
|
||||||
mockk = "1.12.4"
|
mockk = "1.12.5"
|
||||||
coroutines = "1.6.1"
|
coroutines = "1.6.4"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "io.github.wulkanowy:sdk:1.6.4"
|
implementation "io.github.wulkanowy:sdk:1.7.0"
|
||||||
|
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.6'
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3"
|
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
|
||||||
|
|
||||||
implementation "androidx.core:core-ktx:1.7.0"
|
implementation "androidx.core:core-ktx:1.8.0"
|
||||||
implementation 'androidx.core:core-splashscreen:1.0.0-beta02'
|
implementation 'androidx.core:core-splashscreen:1.0.0'
|
||||||
implementation "androidx.activity:activity-ktx:1.4.0"
|
implementation "androidx.activity:activity-ktx:1.5.1"
|
||||||
implementation "androidx.appcompat:appcompat:1.4.1"
|
implementation "androidx.appcompat:appcompat:1.5.0"
|
||||||
implementation "androidx.fragment:fragment-ktx:1.4.1"
|
implementation "androidx.fragment:fragment-ktx:1.5.2"
|
||||||
implementation "androidx.annotation:annotation:1.3.0"
|
implementation "androidx.annotation:annotation:1.4.0"
|
||||||
|
|
||||||
implementation "androidx.preference:preference-ktx:1.2.0"
|
implementation "androidx.preference:preference-ktx:1.2.0"
|
||||||
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
||||||
implementation "androidx.viewpager2:viewpager2:1.1.0-beta01"
|
implementation "androidx.viewpager2:viewpager2:1.1.0-beta01"
|
||||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||||
implementation "androidx.constraintlayout:constraintlayout:2.1.3"
|
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
|
||||||
implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
|
implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
|
||||||
implementation "com.google.android.material:material:1.5.0"
|
implementation "com.google.android.material:material:1.6.1"
|
||||||
implementation "com.github.wulkanowy:material-chips-input:2.3.1"
|
implementation "com.github.wulkanowy:material-chips-input:2.3.1"
|
||||||
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
|
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
|
||||||
implementation 'com.github.lopspower:CircularImageView:4.2.0'
|
implementation 'com.github.lopspower:CircularImageView:4.2.0'
|
||||||
@ -206,7 +214,7 @@ dependencies {
|
|||||||
implementation "androidx.work:work-runtime-ktx:$work_manager"
|
implementation "androidx.work:work-runtime-ktx:$work_manager"
|
||||||
playImplementation "androidx.work:work-gcm:$work_manager"
|
playImplementation "androidx.work:work-gcm:$work_manager"
|
||||||
|
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1"
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
|
||||||
|
|
||||||
implementation "androidx.room:room-runtime:$room"
|
implementation "androidx.room:room-runtime:$room"
|
||||||
implementation "androidx.room:room-ktx:$room"
|
implementation "androidx.room:room-ktx:$room"
|
||||||
@ -222,27 +230,27 @@ dependencies {
|
|||||||
|
|
||||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||||
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0"
|
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0"
|
||||||
implementation "com.squareup.okhttp3:logging-interceptor:4.9.3"
|
implementation "com.squareup.okhttp3:logging-interceptor:4.10.0"
|
||||||
|
|
||||||
implementation "com.jakewharton.timber:timber:5.0.1"
|
implementation "com.jakewharton.timber:timber:5.0.1"
|
||||||
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
||||||
implementation 'com.github.bastienpaulfr:Treessence:1.0.5'
|
implementation 'com.github.bastienpaulfr:Treessence:1.0.5'
|
||||||
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
||||||
implementation "io.coil-kt:coil:2.0.0"
|
implementation "io.coil-kt:coil:2.2.0"
|
||||||
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
|
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
|
||||||
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
|
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
|
||||||
implementation 'com.fredporciuncula:flow-preferences:1.7.0'
|
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
|
||||||
|
|
||||||
playImplementation platform('com.google.firebase:firebase-bom:30.0.1')
|
playImplementation platform('com.google.firebase:firebase-bom:30.3.2')
|
||||||
playImplementation 'com.google.firebase:firebase-analytics-ktx'
|
playImplementation 'com.google.firebase:firebase-analytics-ktx'
|
||||||
playImplementation 'com.google.firebase:firebase-messaging:'
|
playImplementation 'com.google.firebase:firebase-messaging:'
|
||||||
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
||||||
playImplementation 'com.google.android.play:core:1.10.3'
|
playImplementation 'com.google.android.play:core:1.10.3'
|
||||||
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
||||||
playImplementation 'com.google.android.gms:play-services-ads:20.6.0'
|
playImplementation 'com.google.android.gms:play-services-ads:21.1.0'
|
||||||
|
|
||||||
hmsImplementation 'com.huawei.hms:hianalytics:6.5.0.300'
|
hmsImplementation 'com.huawei.hms:hianalytics:6.7.0.300'
|
||||||
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.6.200'
|
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.1.300'
|
||||||
|
|
||||||
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
||||||
|
|
||||||
|
2445
app/schemas/io.github.wulkanowy.data.db.AppDatabase/49.json
Normal file
2445
app/schemas/io.github.wulkanowy.data.db.AppDatabase/49.json
Normal file
File diff suppressed because it is too large
Load Diff
2445
app/schemas/io.github.wulkanowy.data.db.AppDatabase/50.json
Normal file
2445
app/schemas/io.github.wulkanowy.data.db.AppDatabase/50.json
Normal file
File diff suppressed because it is too large
Load Diff
2409
app/schemas/io.github.wulkanowy.data.db.AppDatabase/51.json
Normal file
2409
app/schemas/io.github.wulkanowy.data.db.AppDatabase/51.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,33 +1,92 @@
|
|||||||
{
|
{
|
||||||
"agcgw":{
|
"agcgw": {
|
||||||
"backurl":"connect-dre.dbankcloud.cn",
|
"backurl": "connect-dre.hispace.hicloud.com",
|
||||||
"url":"connect-dre.hispace.hicloud.com"
|
"url": "connect-dre.dbankcloud.cn",
|
||||||
|
"websocketbackurl": "connect-ws-dre.hispace.dbankcloud.com",
|
||||||
|
"websocketurl": "connect-ws-dre.hispace.dbankcloud.cn"
|
||||||
},
|
},
|
||||||
"client":{
|
"agcgw_all": {
|
||||||
"cp_id":"890048000024105546",
|
"CN": "connect-drcn.dbankcloud.cn",
|
||||||
"product_id":"",
|
"CN_back": "connect-drcn.hispace.hicloud.com",
|
||||||
"client_id":"",
|
"DE": "connect-dre.dbankcloud.cn",
|
||||||
"client_secret":"",
|
"DE_back": "connect-dre.hispace.hicloud.com",
|
||||||
"app_id":"101440411",
|
"RU": "connect-drru.hispace.dbankcloud.ru",
|
||||||
"package_name":"io.github.wulkanowy.dev",
|
"RU_back": "connect-drru.hispace.dbankcloud.cn",
|
||||||
"api_key":""
|
"SG": "connect-dra.dbankcloud.cn",
|
||||||
|
"SG_back": "connect-dra.hispace.hicloud.com"
|
||||||
},
|
},
|
||||||
"service":{
|
"websocketgw_all": {
|
||||||
"analytics":{
|
"CN": "connect-ws-drcn.hispace.dbankcloud.cn",
|
||||||
"collector_url":"datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
|
"CN_back": "connect-ws-drcn.hispace.dbankcloud.com",
|
||||||
"resource_id":"p1",
|
"DE": "connect-ws-dre.hispace.dbankcloud.cn",
|
||||||
"channel_id":""
|
"DE_back": "connect-ws-dre.hispace.dbankcloud.com",
|
||||||
|
"RU": "connect-ws-drru.hispace.dbankcloud.ru",
|
||||||
|
"RU_back": "connect-ws-drru.hispace.dbankcloud.cn",
|
||||||
|
"SG": "connect-ws-dra.hispace.dbankcloud.cn",
|
||||||
|
"SG_back": "connect-ws-dra.hispace.dbankcloud.com"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"cp_id": "890048000024105546",
|
||||||
|
"product_id": "736430079244736562",
|
||||||
|
"client_id": "514530959291319360",
|
||||||
|
"client_secret": "C42522DBF17D3D4BBE9D9C1783A54484B7E6844B388B7A67502D36A633A4186B",
|
||||||
|
"project_id": "736430079244736562",
|
||||||
|
"app_id": "106552551",
|
||||||
|
"api_key": "CgB6e3x9BUNiq+r8ebCHNojjjYsMT4pJSjjNDOkm9owtBb6rVI6LjnASoZBRxbjjhObcrV5gANo99fI/eKZDTbWS",
|
||||||
|
"package_name": "io.github.wulkanowy.dev"
|
||||||
|
},
|
||||||
|
"oauth_client": {
|
||||||
|
"client_id": "106552551",
|
||||||
|
"client_type": 1
|
||||||
|
},
|
||||||
|
"app_info": {
|
||||||
|
"app_id": "106552551",
|
||||||
|
"package_name": "io.github.wulkanowy.dev"
|
||||||
|
},
|
||||||
|
"service": {
|
||||||
|
"analytics": {
|
||||||
|
"collector_url": "datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
|
||||||
|
"collector_url_ru": "datacollector-drru.dt.dbankcloud.ru,datacollector-drru.dt.hicloud.com",
|
||||||
|
"collector_url_sg": "datacollector-dra.dt.hicloud.com,datacollector-dra.dt.dbankcloud.cn",
|
||||||
|
"collector_url_de": "datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
|
||||||
|
"collector_url_cn": "datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn",
|
||||||
|
"resource_id": "p1",
|
||||||
|
"channel_id": ""
|
||||||
},
|
},
|
||||||
"search":{
|
"search":{
|
||||||
"url":"https://search-dre.cloud.huawei.com"
|
"url":"https://search-dre.cloud.huawei.com"
|
||||||
},
|
},
|
||||||
"cloudstorage":{
|
"cloudstorage": {
|
||||||
"storage_url":"https://ops-dre.agcstorage.link"
|
"storage_url_sg_back": "https://agc-storage-dra.cloud.huawei.asia",
|
||||||
|
"storage_url_ru_back": "https://agc-storage-drru.cloud.huawei.ru",
|
||||||
|
"storage_url_ru": "https://agc-storage-drru.cloud.huawei.ru",
|
||||||
|
"storage_url_de_back": "https://agc-storage-dre.cloud.huawei.eu",
|
||||||
|
"storage_url_de": "https://ops-dre.agcstorage.link",
|
||||||
|
"storage_url": "https://agc-storage-drcn.platform.dbankcloud.cn",
|
||||||
|
"storage_url_sg": "https://ops-dra.agcstorage.link",
|
||||||
|
"storage_url_cn_back": "https://agc-storage-drcn.cloud.huawei.com.cn",
|
||||||
|
"storage_url_cn": "https://agc-storage-drcn.platform.dbankcloud.cn"
|
||||||
},
|
},
|
||||||
"ml":{
|
"ml": {
|
||||||
"mlservice_url":"ml-api-dre.ai.dbankcloud.com,ml-api-dre.ai.dbankcloud.cn"
|
"mlservice_url": "ml-api-dre.ai.dbankcloud.com,ml-api-dre.ai.dbankcloud.cn"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"region":"DE",
|
"region": "DE",
|
||||||
"configuration_version":"1.0"
|
"configuration_version": "3.0",
|
||||||
|
"appInfos": [
|
||||||
|
{
|
||||||
|
"package_name": "io.github.wulkanowy.dev",
|
||||||
|
"client": {
|
||||||
|
"app_id": "106552551"
|
||||||
|
},
|
||||||
|
"app_info": {
|
||||||
|
"package_name": "io.github.wulkanowy.dev",
|
||||||
|
"app_id": "106552551"
|
||||||
|
},
|
||||||
|
"oauth_client": {
|
||||||
|
"client_type": 1,
|
||||||
|
"client_id": "106552551"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
28
app/src/fdroid/java/io/github/wulkanowy/utils/AdsHelper.kt
Normal file
28
app/src/fdroid/java/io/github/wulkanowy/utils/AdsHelper.kt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package io.github.wulkanowy.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
class AdsHelper @Inject constructor(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
|
private val preferencesRepository: PreferencesRepository
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun initialize() {
|
||||||
|
preferencesRepository.isAdsEnabled = false
|
||||||
|
preferencesRepository.isAgreeToProcessData = false
|
||||||
|
preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("RedundantSuspendModifier", "UNUSED_PARAMETER")
|
||||||
|
suspend fun getDashboardTileAdBanner(width: Int): AdBanner {
|
||||||
|
throw IllegalStateException("Can't get ad banner (F-droid)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class AdBanner(val view: View)
|
28
app/src/hms/java/io/github/wulkanowy/utils/AdsHelper.kt
Normal file
28
app/src/hms/java/io/github/wulkanowy/utils/AdsHelper.kt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package io.github.wulkanowy.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
class AdsHelper @Inject constructor(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
|
private val preferencesRepository: PreferencesRepository
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun initialize() {
|
||||||
|
preferencesRepository.isAdsEnabled = false
|
||||||
|
preferencesRepository.isAgreeToProcessData = false
|
||||||
|
preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("RedundantSuspendModifier", "UNUSED_PARAMETER")
|
||||||
|
suspend fun getDashboardTileAdBanner(width: Int): AdBanner {
|
||||||
|
throw IllegalStateException("Can't get ad banner (HMS)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class AdBanner(val view: View)
|
@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="io.github.wulkanowy"
|
|
||||||
android:installLocation="internalOnly">
|
android:installLocation="internalOnly">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
@ -31,10 +31,14 @@ class WulkanowyApp : Application(), Configuration.Provider {
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var analyticsHelper: AnalyticsHelper
|
lateinit var analyticsHelper: AnalyticsHelper
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var adsHelper: AdsHelper
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
initializeAppLanguage()
|
initializeAppLanguage()
|
||||||
themeManager.applyDefaultTheme()
|
themeManager.applyDefaultTheme()
|
||||||
|
adsHelper.initialize()
|
||||||
initLogging()
|
initLogging()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@ import io.github.wulkanowy.data.db.SharedPrefProvider
|
|||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.AppInfo
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
@ -110,7 +109,6 @@ internal class DataModule {
|
|||||||
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences =
|
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences =
|
||||||
PreferenceManager.getDefaultSharedPreferences(context)
|
PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideFlowSharedPref(sharedPreferences: SharedPreferences) =
|
fun provideFlowSharedPref(sharedPreferences: SharedPreferences) =
|
||||||
@ -197,7 +195,7 @@ internal class DataModule {
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideReportingUnitDao(database: AppDatabase) = database.reportingUnitDao
|
fun provideMailboxesDao(database: AppDatabase) = database.mailboxDao
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -30,7 +30,7 @@ import javax.inject.Singleton
|
|||||||
Subject::class,
|
Subject::class,
|
||||||
LuckyNumber::class,
|
LuckyNumber::class,
|
||||||
CompletedLesson::class,
|
CompletedLesson::class,
|
||||||
ReportingUnit::class,
|
Mailbox::class,
|
||||||
Recipient::class,
|
Recipient::class,
|
||||||
MobileDevice::class,
|
MobileDevice::class,
|
||||||
Teacher::class,
|
Teacher::class,
|
||||||
@ -55,7 +55,7 @@ import javax.inject.Singleton
|
|||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val VERSION_SCHEMA = 48
|
const val VERSION_SCHEMA = 51
|
||||||
|
|
||||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
||||||
Migration2(),
|
Migration2(),
|
||||||
@ -102,6 +102,9 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
Migration43(),
|
Migration43(),
|
||||||
Migration44(),
|
Migration44(),
|
||||||
Migration46(),
|
Migration46(),
|
||||||
|
Migration49(),
|
||||||
|
Migration50(),
|
||||||
|
Migration51(),
|
||||||
)
|
)
|
||||||
|
|
||||||
fun newInstance(
|
fun newInstance(
|
||||||
@ -152,7 +155,7 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
|
|
||||||
abstract val completedLessonsDao: CompletedLessonsDao
|
abstract val completedLessonsDao: CompletedLessonsDao
|
||||||
|
|
||||||
abstract val reportingUnitDao: ReportingUnitDao
|
abstract val mailboxDao: MailboxDao
|
||||||
|
|
||||||
abstract val recipientDao: RecipientDao
|
abstract val recipientDao: RecipientDao
|
||||||
|
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
package io.github.wulkanowy.data.db.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Dao
|
||||||
|
interface MailboxDao : BaseDao<Mailbox> {
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Mailboxes WHERE userLoginId = :userLoginId ")
|
||||||
|
suspend fun loadAll(userLoginId: Int): List<Mailbox>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Mailboxes WHERE userLoginId = :userLoginId AND studentName = :studentName ")
|
||||||
|
suspend fun load(userLoginId: Int, studentName: String): Mailbox?
|
||||||
|
}
|
@ -11,9 +11,9 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
interface MessagesDao : BaseDao<Message> {
|
interface MessagesDao : BaseDao<Message> {
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND message_id = :messageId")
|
@Query("SELECT * FROM Messages WHERE message_global_key = :messageGlobalKey")
|
||||||
fun loadMessageWithAttachment(studentId: Int, messageId: Int): Flow<MessageWithAttachment?>
|
fun loadMessageWithAttachment(messageGlobalKey: String): Flow<MessageWithAttachment?>
|
||||||
|
|
||||||
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder ORDER BY date DESC")
|
@Query("SELECT * FROM Messages WHERE mailbox_key = :mailboxKey AND folder_id = :folder ORDER BY date DESC")
|
||||||
fun loadAll(studentId: Int, folder: Int): Flow<List<Message>>
|
fun loadAll(mailboxKey: String, folder: Int): Flow<List<Message>>
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,6 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
@Dao
|
@Dao
|
||||||
interface MobileDeviceDao : BaseDao<MobileDevice> {
|
interface MobileDeviceDao : BaseDao<MobileDevice> {
|
||||||
|
|
||||||
@Query("SELECT * FROM MobileDevices WHERE student_id = :userLoginId ORDER BY date DESC")
|
@Query("SELECT * FROM MobileDevices WHERE user_login_id = :userLoginId ORDER BY date DESC")
|
||||||
fun loadAll(userLoginId: Int): Flow<List<MobileDevice>>
|
fun loadAll(userLoginId: Int): Flow<List<MobileDevice>>
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.data.db.dao
|
|||||||
|
|
||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
|
import io.github.wulkanowy.data.db.entities.MailboxType
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -9,6 +10,6 @@ import javax.inject.Singleton
|
|||||||
@Dao
|
@Dao
|
||||||
interface RecipientDao : BaseDao<Recipient> {
|
interface RecipientDao : BaseDao<Recipient> {
|
||||||
|
|
||||||
@Query("SELECT * FROM Recipients WHERE student_id = :studentId AND unit_id = :unitId AND role = :role")
|
@Query("SELECT * FROM Recipients WHERE type = :type AND studentMailboxGlobalKey = :studentMailboxGlobalKey")
|
||||||
suspend fun loadAll(studentId: Int, unitId: Int, role: Int): List<Recipient>
|
suspend fun loadAll(type: MailboxType, studentMailboxGlobalKey: String): List<Recipient>
|
||||||
}
|
}
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
package io.github.wulkanowy.data.db.dao
|
|
||||||
|
|
||||||
import androidx.room.Dao
|
|
||||||
import androidx.room.Query
|
|
||||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Dao
|
|
||||||
interface ReportingUnitDao : BaseDao<ReportingUnit> {
|
|
||||||
|
|
||||||
@Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId")
|
|
||||||
suspend fun load(studentId: Int): List<ReportingUnit>
|
|
||||||
|
|
||||||
@Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId AND real_id = :unitId")
|
|
||||||
suspend fun loadOne(studentId: Int, unitId: Int): ReportingUnit?
|
|
||||||
}
|
|
@ -10,6 +10,6 @@ import javax.inject.Singleton
|
|||||||
@Singleton
|
@Singleton
|
||||||
interface SchoolAnnouncementDao : BaseDao<SchoolAnnouncement> {
|
interface SchoolAnnouncementDao : BaseDao<SchoolAnnouncement> {
|
||||||
|
|
||||||
@Query("SELECT * FROM SchoolAnnouncements WHERE student_id = :studentId ORDER BY date DESC")
|
@Query("SELECT * FROM SchoolAnnouncements WHERE user_login_id = :userLoginId ORDER BY date DESC")
|
||||||
fun loadAll(studentId: Int): Flow<List<SchoolAnnouncement>>
|
fun loadAll(userLoginId: Int): Flow<List<SchoolAnnouncement>>
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
package io.github.wulkanowy.data.db.entities
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(tableName = "Mailboxes")
|
||||||
|
data class Mailbox(
|
||||||
|
|
||||||
|
@PrimaryKey
|
||||||
|
val globalKey: String,
|
||||||
|
val fullName: String,
|
||||||
|
val userName: String,
|
||||||
|
val userLoginId: Int,
|
||||||
|
val studentName: String,
|
||||||
|
val schoolNameShort: String,
|
||||||
|
val type: MailboxType,
|
||||||
|
)
|
||||||
|
|
||||||
|
enum class MailboxType {
|
||||||
|
STUDENT,
|
||||||
|
PARENT,
|
||||||
|
GUARDIAN,
|
||||||
|
EMPLOYEE,
|
||||||
|
UNKNOWN,
|
||||||
|
}
|
@ -9,23 +9,16 @@ import java.time.Instant
|
|||||||
@Entity(tableName = "Messages")
|
@Entity(tableName = "Messages")
|
||||||
data class Message(
|
data class Message(
|
||||||
|
|
||||||
@ColumnInfo(name = "student_id")
|
@ColumnInfo(name = "message_global_key")
|
||||||
val studentId: Long,
|
val messageGlobalKey: String,
|
||||||
|
|
||||||
@ColumnInfo(name = "real_id")
|
@ColumnInfo(name = "mailbox_key")
|
||||||
val realId: Int,
|
val mailboxKey: String,
|
||||||
|
|
||||||
@ColumnInfo(name = "message_id")
|
@ColumnInfo(name = "message_id")
|
||||||
val messageId: Int,
|
val messageId: Int,
|
||||||
|
|
||||||
@ColumnInfo(name = "sender_name")
|
val correspondents: String,
|
||||||
val sender: String,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "sender_id")
|
|
||||||
val senderId: Int,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "recipient_name")
|
|
||||||
val recipient: String,
|
|
||||||
|
|
||||||
val subject: String,
|
val subject: String,
|
||||||
|
|
||||||
@ -36,8 +29,6 @@ data class Message(
|
|||||||
|
|
||||||
var unread: Boolean,
|
var unread: Boolean,
|
||||||
|
|
||||||
val removed: Boolean,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "has_attachments")
|
@ColumnInfo(name = "has_attachments")
|
||||||
val hasAttachments: Boolean
|
val hasAttachments: Boolean
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
@ -48,11 +39,7 @@ data class Message(
|
|||||||
@ColumnInfo(name = "is_notified")
|
@ColumnInfo(name = "is_notified")
|
||||||
var isNotified: Boolean = true
|
var isNotified: Boolean = true
|
||||||
|
|
||||||
@ColumnInfo(name = "unread_by")
|
|
||||||
var unreadBy: Int = 0
|
|
||||||
|
|
||||||
@ColumnInfo(name = "read_by")
|
|
||||||
var readBy: Int = 0
|
|
||||||
|
|
||||||
var content: String = ""
|
var content: String = ""
|
||||||
|
var sender: String? = null
|
||||||
|
var recipients: String? = null
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,8 @@ data class MessageAttachment(
|
|||||||
@ColumnInfo(name = "real_id")
|
@ColumnInfo(name = "real_id")
|
||||||
val realId: Int,
|
val realId: Int,
|
||||||
|
|
||||||
@ColumnInfo(name = "message_id")
|
@ColumnInfo(name = "message_global_key")
|
||||||
val messageId: Int,
|
val messageGlobalKey: String,
|
||||||
|
|
||||||
@ColumnInfo(name = "one_drive_id")
|
|
||||||
val oneDriveId: String,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "url")
|
@ColumnInfo(name = "url")
|
||||||
val url: String,
|
val url: String,
|
||||||
|
@ -7,6 +7,6 @@ data class MessageWithAttachment(
|
|||||||
@Embedded
|
@Embedded
|
||||||
val message: Message,
|
val message: Message,
|
||||||
|
|
||||||
@Relation(parentColumn = "message_id", entityColumn = "message_id")
|
@Relation(parentColumn = "message_global_key", entityColumn = "message_global_key")
|
||||||
val attachments: List<MessageAttachment>
|
val attachments: List<MessageAttachment>
|
||||||
)
|
)
|
||||||
|
@ -9,7 +9,7 @@ import java.time.Instant
|
|||||||
@Entity(tableName = "MobileDevices")
|
@Entity(tableName = "MobileDevices")
|
||||||
data class MobileDevice(
|
data class MobileDevice(
|
||||||
|
|
||||||
@ColumnInfo(name = "student_id")
|
@ColumnInfo(name = "user_login_id")
|
||||||
val userLoginId: Int,
|
val userLoginId: Int,
|
||||||
|
|
||||||
@ColumnInfo(name = "device_id")
|
@ColumnInfo(name = "device_id")
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.data.db.entities
|
package io.github.wulkanowy.data.db.entities
|
||||||
|
|
||||||
import androidx.room.ColumnInfo
|
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
@ -8,32 +7,16 @@ import java.io.Serializable
|
|||||||
@kotlinx.serialization.Serializable
|
@kotlinx.serialization.Serializable
|
||||||
@Entity(tableName = "Recipients")
|
@Entity(tableName = "Recipients")
|
||||||
data class Recipient(
|
data class Recipient(
|
||||||
|
val mailboxGlobalKey: String,
|
||||||
@ColumnInfo(name = "student_id")
|
val studentMailboxGlobalKey: String,
|
||||||
val studentId: Int,
|
val fullName: String,
|
||||||
|
val userName: String,
|
||||||
@ColumnInfo(name = "real_id")
|
val schoolShortName: String,
|
||||||
val realId: String,
|
val type: MailboxType,
|
||||||
|
|
||||||
val name: String,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "real_name")
|
|
||||||
val realName: String,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "login_id")
|
|
||||||
val loginId: Int,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "unit_id")
|
|
||||||
val unitId: Int,
|
|
||||||
|
|
||||||
val role: Int,
|
|
||||||
|
|
||||||
val hash: String
|
|
||||||
|
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
var id: Long = 0
|
var id: Long = 0
|
||||||
|
|
||||||
override fun toString() = name
|
override fun toString() = userName
|
||||||
}
|
}
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
package io.github.wulkanowy.data.db.entities
|
|
||||||
|
|
||||||
import androidx.room.ColumnInfo
|
|
||||||
import androidx.room.Entity
|
|
||||||
import androidx.room.PrimaryKey
|
|
||||||
import java.io.Serializable
|
|
||||||
|
|
||||||
@Entity(tableName = "ReportingUnits")
|
|
||||||
data class ReportingUnit(
|
|
||||||
|
|
||||||
@ColumnInfo(name = "student_id")
|
|
||||||
val studentId: Int,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "real_id")
|
|
||||||
val unitId: Int,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "short")
|
|
||||||
val shortName: String,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "sender_id")
|
|
||||||
val senderId: Int,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "sender_name")
|
|
||||||
val senderName: String,
|
|
||||||
|
|
||||||
val roles: List<Int>
|
|
||||||
|
|
||||||
) : Serializable {
|
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
|
||||||
var id: Long = 0
|
|
||||||
}
|
|
@ -9,8 +9,8 @@ import java.time.LocalDate
|
|||||||
@Entity(tableName = "SchoolAnnouncements")
|
@Entity(tableName = "SchoolAnnouncements")
|
||||||
data class SchoolAnnouncement(
|
data class SchoolAnnouncement(
|
||||||
|
|
||||||
@ColumnInfo(name = "student_id")
|
@ColumnInfo(name = "user_login_id")
|
||||||
val studentId: Int,
|
val userLoginId: Int,
|
||||||
|
|
||||||
val date: LocalDate,
|
val date: LocalDate,
|
||||||
|
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration49 : Migration(48, 49) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS SchoolAnnouncements")
|
||||||
|
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `SchoolAnnouncements` (
|
||||||
|
`user_login_id` INTEGER NOT NULL,
|
||||||
|
`date` INTEGER NOT NULL,
|
||||||
|
`subject` TEXT NOT NULL,
|
||||||
|
`content` TEXT NOT NULL,
|
||||||
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
`is_notified` INTEGER NOT NULL)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration50 : Migration(49, 50) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS MobileDevices")
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `MobileDevices` (
|
||||||
|
`user_login_id` INTEGER NOT NULL,
|
||||||
|
`device_id` INTEGER NOT NULL,
|
||||||
|
`name` TEXT NOT NULL,
|
||||||
|
`date` INTEGER NOT NULL,
|
||||||
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration51 : Migration(50, 51) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
createMailboxTable(database)
|
||||||
|
recreateMessagesTable(database)
|
||||||
|
recreateMessageAttachmentsTable(database)
|
||||||
|
recreateRecipientsTable(database)
|
||||||
|
deleteReportingUnitTable(database)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createMailboxTable(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS Mailboxes")
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `Mailboxes` (
|
||||||
|
`globalKey` TEXT NOT NULL,
|
||||||
|
`fullName` TEXT NOT NULL,
|
||||||
|
`userName` TEXT NOT NULL,
|
||||||
|
`userLoginId` INTEGER NOT NULL,
|
||||||
|
`studentName` TEXT NOT NULL,
|
||||||
|
`schoolNameShort` TEXT NOT NULL,
|
||||||
|
`type` TEXT NOT NULL,
|
||||||
|
PRIMARY KEY(`globalKey`)
|
||||||
|
)""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun recreateMessagesTable(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS Messages")
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `Messages` (
|
||||||
|
`message_global_key` TEXT NOT NULL,
|
||||||
|
`mailbox_key` TEXT NOT NULL,
|
||||||
|
`message_id` INTEGER NOT NULL,
|
||||||
|
`correspondents` TEXT NOT NULL,
|
||||||
|
`subject` TEXT NOT NULL,
|
||||||
|
`date` INTEGER NOT NULL,
|
||||||
|
`folder_id` INTEGER NOT NULL,
|
||||||
|
`unread` INTEGER NOT NULL,
|
||||||
|
`has_attachments` INTEGER NOT NULL,
|
||||||
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
`is_notified` INTEGER NOT NULL,
|
||||||
|
`content` TEXT NOT NULL,
|
||||||
|
`sender` TEXT, `recipients` TEXT
|
||||||
|
)""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun recreateMessageAttachmentsTable(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS MessageAttachments")
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `MessageAttachments` (
|
||||||
|
`real_id` INTEGER NOT NULL,
|
||||||
|
`message_global_key` TEXT NOT NULL,
|
||||||
|
`url` TEXT NOT NULL,
|
||||||
|
`filename` TEXT NOT NULL,
|
||||||
|
PRIMARY KEY(`real_id`)
|
||||||
|
)""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun recreateRecipientsTable(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS Recipients")
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `Recipients` (
|
||||||
|
`mailboxGlobalKey` TEXT NOT NULL,
|
||||||
|
`studentMailboxGlobalKey` TEXT NOT NULL,
|
||||||
|
`fullName` TEXT NOT NULL,
|
||||||
|
`userName` TEXT NOT NULL,
|
||||||
|
`schoolShortName` TEXT NOT NULL,
|
||||||
|
`type` TEXT NOT NULL,
|
||||||
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
|
||||||
|
)""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteReportingUnitTable(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS ReportingUnits")
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,8 @@ package io.github.wulkanowy.data.enums
|
|||||||
|
|
||||||
enum class GradeSortingMode(val value: String) {
|
enum class GradeSortingMode(val value: String) {
|
||||||
ALPHABETIC("alphabetic"),
|
ALPHABETIC("alphabetic"),
|
||||||
DATE("date");
|
DATE("date"),
|
||||||
|
AVERAGE("average");
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getByValue(value: String) = values().find { it.value == value } ?: ALPHABETIC
|
fun getByValue(value: String) = values().find { it.value == value } ?: ALPHABETIC
|
||||||
|
@ -6,7 +6,7 @@ import io.github.wulkanowy.sdk.pojo.DirectorInformation as SdkDirectorInformatio
|
|||||||
|
|
||||||
fun List<SdkDirectorInformation>.mapToEntities(student: Student) = map {
|
fun List<SdkDirectorInformation>.mapToEntities(student: Student) = map {
|
||||||
SchoolAnnouncement(
|
SchoolAnnouncement(
|
||||||
studentId = student.userLoginId,
|
userLoginId = student.userLoginId,
|
||||||
date = it.date,
|
date = it.date,
|
||||||
subject = it.subject,
|
subject = it.subject,
|
||||||
content = it.content,
|
content = it.content,
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package io.github.wulkanowy.data.mappers
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
import io.github.wulkanowy.data.db.entities.MailboxType
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.sdk.pojo.Mailbox as SdkMailbox
|
||||||
|
|
||||||
|
fun List<SdkMailbox>.mapToEntities(student: Student) = map {
|
||||||
|
Mailbox(
|
||||||
|
globalKey = it.globalKey,
|
||||||
|
fullName = it.fullName,
|
||||||
|
userName = it.userName,
|
||||||
|
userLoginId = student.userLoginId,
|
||||||
|
studentName = it.studentName,
|
||||||
|
schoolNameShort = it.schoolNameShort,
|
||||||
|
type = MailboxType.valueOf(it.type.name),
|
||||||
|
)
|
||||||
|
}
|
@ -1,40 +1,31 @@
|
|||||||
package io.github.wulkanowy.data.mappers
|
package io.github.wulkanowy.data.mappers
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.*
|
||||||
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
import io.github.wulkanowy.sdk.pojo.MailboxType
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import java.time.Instant
|
|
||||||
import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
|
import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
|
||||||
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
|
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
|
||||||
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
|
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
|
||||||
|
|
||||||
fun List<SdkMessage>.mapToEntities(student: Student) = map {
|
fun List<SdkMessage>.mapToEntities(mailbox: Mailbox) = map {
|
||||||
Message(
|
Message(
|
||||||
studentId = student.id,
|
messageGlobalKey = it.globalKey,
|
||||||
realId = it.id ?: 0,
|
mailboxKey = mailbox.globalKey,
|
||||||
messageId = it.messageId ?: 0,
|
messageId = it.id,
|
||||||
sender = it.sender?.name.orEmpty(),
|
correspondents = it.correspondents,
|
||||||
senderId = it.sender?.loginId ?: 0,
|
|
||||||
recipient = it.recipients.singleOrNull()?.name ?: "Wielu adresatów",
|
|
||||||
subject = it.subject.trim(),
|
subject = it.subject.trim(),
|
||||||
date = it.dateZoned?.toInstant() ?: Instant.now(),
|
date = it.dateZoned.toInstant(),
|
||||||
folderId = it.folderId,
|
folderId = it.folderId,
|
||||||
unread = it.unread ?: false,
|
unread = it.unread,
|
||||||
removed = it.removed,
|
|
||||||
hasAttachments = it.hasAttachments
|
hasAttachments = it.hasAttachments
|
||||||
).apply {
|
).apply {
|
||||||
content = it.content.orEmpty()
|
content = it.content.orEmpty()
|
||||||
unreadBy = it.unreadBy ?: 0
|
|
||||||
readBy = it.readBy ?: 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun List<SdkMessageAttachment>.mapToEntities() = map {
|
fun List<SdkMessageAttachment>.mapToEntities(messageGlobalKey: String) = map {
|
||||||
MessageAttachment(
|
MessageAttachment(
|
||||||
realId = it.id,
|
messageGlobalKey = messageGlobalKey,
|
||||||
messageId = it.messageId,
|
realId = it.url.hashCode(),
|
||||||
oneDriveId = it.oneDriveId,
|
|
||||||
url = it.url,
|
url = it.url,
|
||||||
filename = it.filename
|
filename = it.filename
|
||||||
)
|
)
|
||||||
@ -42,12 +33,11 @@ fun List<SdkMessageAttachment>.mapToEntities() = map {
|
|||||||
|
|
||||||
fun List<Recipient>.mapFromEntities() = map {
|
fun List<Recipient>.mapFromEntities() = map {
|
||||||
SdkRecipient(
|
SdkRecipient(
|
||||||
id = it.realId,
|
fullName = it.fullName,
|
||||||
name = it.realName,
|
userName = it.userName,
|
||||||
loginId = it.loginId,
|
studentName = it.userName,
|
||||||
reportingUnitId = it.unitId,
|
mailboxGlobalKey = it.mailboxGlobalKey,
|
||||||
role = it.role,
|
schoolNameShort = it.schoolShortName,
|
||||||
hash = it.hash,
|
type = MailboxType.valueOf(it.type.name),
|
||||||
shortName = it.name
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package io.github.wulkanowy.data.mappers
|
package io.github.wulkanowy.data.mappers
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.MobileDevice
|
import io.github.wulkanowy.data.db.entities.MobileDevice
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.pojos.MobileDeviceToken
|
import io.github.wulkanowy.data.pojos.MobileDeviceToken
|
||||||
import io.github.wulkanowy.sdk.pojo.Device as SdkDevice
|
import io.github.wulkanowy.sdk.pojo.Device as SdkDevice
|
||||||
import io.github.wulkanowy.sdk.pojo.Token as SdkToken
|
import io.github.wulkanowy.sdk.pojo.Token as SdkToken
|
||||||
|
|
||||||
fun List<SdkDevice>.mapToEntities(semester: Semester) = map {
|
fun List<SdkDevice>.mapToEntities(student: Student) = map {
|
||||||
MobileDevice(
|
MobileDevice(
|
||||||
userLoginId = semester.studentId,
|
userLoginId = student.userLoginId,
|
||||||
date = it.createDateZoned.toInstant(),
|
date = it.createDateZoned.toInstant(),
|
||||||
deviceId = it.id,
|
deviceId = it.id,
|
||||||
name = it.name
|
name = it.name
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
package io.github.wulkanowy.data.mappers
|
package io.github.wulkanowy.data.mappers
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.MailboxType
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
|
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
|
||||||
|
|
||||||
fun List<SdkRecipient>.mapToEntities(userLoginId: Int) = map {
|
fun List<SdkRecipient>.mapToEntities(studentMailboxGlobalKey: String) = map {
|
||||||
Recipient(
|
Recipient(
|
||||||
studentId = userLoginId,
|
mailboxGlobalKey = it.mailboxGlobalKey,
|
||||||
realId = it.id,
|
fullName = it.fullName,
|
||||||
realName = it.name,
|
userName = it.userName,
|
||||||
name = it.shortName,
|
studentMailboxGlobalKey = studentMailboxGlobalKey,
|
||||||
hash = it.hash,
|
schoolShortName = it.schoolNameShort,
|
||||||
loginId = it.loginId,
|
type = MailboxType.valueOf(it.type.name),
|
||||||
role = it.role,
|
|
||||||
unitId = it.reportingUnitId ?: 0
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
package io.github.wulkanowy.data.mappers
|
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import io.github.wulkanowy.sdk.pojo.ReportingUnit as SdkReportingUnit
|
|
||||||
|
|
||||||
fun List<SdkReportingUnit>.mapToEntities(student: Student) = map {
|
|
||||||
ReportingUnit(
|
|
||||||
studentId = student.id.toInt(),
|
|
||||||
unitId = it.id,
|
|
||||||
roles = it.roles,
|
|
||||||
senderId = it.senderId,
|
|
||||||
senderName = it.senderName,
|
|
||||||
shortName = it.short
|
|
||||||
)
|
|
||||||
}
|
|
@ -0,0 +1,48 @@
|
|||||||
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.dao.MailboxDao
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
|
import io.github.wulkanowy.utils.getRefreshKey
|
||||||
|
import io.github.wulkanowy.utils.init
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class MailboxRepository @Inject constructor(
|
||||||
|
private val mailboxDao: MailboxDao,
|
||||||
|
private val sdk: Sdk,
|
||||||
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
|
) {
|
||||||
|
private val cacheKey = "mailboxes"
|
||||||
|
|
||||||
|
suspend fun refreshMailboxes(student: Student) {
|
||||||
|
val new = sdk.init(student).getMailboxes().mapToEntities(student)
|
||||||
|
val old = mailboxDao.loadAll(student.userLoginId)
|
||||||
|
|
||||||
|
mailboxDao.deleteAll(old uniqueSubtract new)
|
||||||
|
mailboxDao.insertAll(new uniqueSubtract old)
|
||||||
|
|
||||||
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getMailbox(student: Student): Mailbox {
|
||||||
|
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
|
||||||
|
val mailbox = mailboxDao.load(student.userLoginId, student.studentName)
|
||||||
|
|
||||||
|
return if (isExpired || mailbox == null) {
|
||||||
|
refreshMailboxes(student)
|
||||||
|
val newMailbox = mailboxDao.load(student.userLoginId, student.studentName)
|
||||||
|
|
||||||
|
requireNotNull(newMailbox) {
|
||||||
|
"Mailbox for ${student.userName} - ${student.studentName} not found!"
|
||||||
|
}
|
||||||
|
|
||||||
|
newMailbox
|
||||||
|
} else mailbox
|
||||||
|
}
|
||||||
|
}
|
@ -10,24 +10,24 @@ import io.github.wulkanowy.data.db.dao.MessagesDao
|
|||||||
import io.github.wulkanowy.data.db.entities.*
|
import io.github.wulkanowy.data.db.entities.*
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder
|
import io.github.wulkanowy.data.enums.MessageFolder
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
|
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
|
||||||
|
import io.github.wulkanowy.data.enums.MessageFolder.TRASHED
|
||||||
import io.github.wulkanowy.data.mappers.mapFromEntities
|
import io.github.wulkanowy.data.mappers.mapFromEntities
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
import io.github.wulkanowy.data.networkBoundResource
|
import io.github.wulkanowy.data.networkBoundResource
|
||||||
import io.github.wulkanowy.data.pojos.MessageDraft
|
import io.github.wulkanowy.data.pojos.MessageDraft
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.sdk.pojo.Folder
|
import io.github.wulkanowy.sdk.pojo.Folder
|
||||||
import io.github.wulkanowy.sdk.pojo.SentMessage
|
|
||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
import io.github.wulkanowy.utils.getRefreshKey
|
import io.github.wulkanowy.utils.getRefreshKey
|
||||||
import io.github.wulkanowy.utils.init
|
import io.github.wulkanowy.utils.init
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.time.LocalDateTime.now
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ class MessageRepository @Inject constructor(
|
|||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
fun getMessages(
|
fun getMessages(
|
||||||
student: Student,
|
student: Student,
|
||||||
semester: Semester,
|
mailbox: Mailbox,
|
||||||
folder: MessageFolder,
|
folder: MessageFolder,
|
||||||
forceRefresh: Boolean,
|
forceRefresh: Boolean,
|
||||||
notify: Boolean = false,
|
notify: Boolean = false,
|
||||||
@ -62,42 +62,20 @@ class MessageRepository @Inject constructor(
|
|||||||
)
|
)
|
||||||
it.isEmpty() || forceRefresh || isExpired
|
it.isEmpty() || forceRefresh || isExpired
|
||||||
},
|
},
|
||||||
query = { messagesDb.loadAll(student.id.toInt(), folder.id) },
|
query = { messagesDb.loadAll(mailbox.globalKey, folder.id) },
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).getMessages(Folder.valueOf(folder.name), now().minusMonths(3), now())
|
sdk.init(student).getMessages(Folder.valueOf(folder.name)).mapToEntities(mailbox)
|
||||||
.mapToEntities(student)
|
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
messagesDb.deleteAll(old uniqueSubtract new)
|
messagesDb.deleteAll(old uniqueSubtract new)
|
||||||
messagesDb.insertAll((new uniqueSubtract old).onEach {
|
messagesDb.insertAll((new uniqueSubtract old).onEach {
|
||||||
it.isNotified = !notify
|
it.isNotified = !notify
|
||||||
})
|
})
|
||||||
messagesDb.updateAll(getMessagesWithReadByChange(old, new, !notify))
|
|
||||||
|
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student, folder))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student, folder))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun getMessagesWithReadByChange(
|
|
||||||
old: List<Message>,
|
|
||||||
new: List<Message>,
|
|
||||||
setNotified: Boolean
|
|
||||||
): List<Message> {
|
|
||||||
val oldMeta = old.map { Triple(it, it.readBy, it.unreadBy) }
|
|
||||||
val newMeta = new.map { Triple(it, it.readBy, it.unreadBy) }
|
|
||||||
|
|
||||||
val updatedItems = newMeta uniqueSubtract oldMeta
|
|
||||||
|
|
||||||
return updatedItems.map {
|
|
||||||
val oldItem = old.find { item -> item.messageId == it.first.messageId }
|
|
||||||
it.first.apply {
|
|
||||||
id = oldItem?.id ?: 0
|
|
||||||
isNotified = oldItem?.isNotified ?: setNotified
|
|
||||||
content = oldItem?.content.orEmpty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getMessage(
|
fun getMessage(
|
||||||
student: Student,
|
student: Student,
|
||||||
message: Message,
|
message: Message,
|
||||||
@ -106,34 +84,34 @@ class MessageRepository @Inject constructor(
|
|||||||
isResultEmpty = { it?.message?.content.isNullOrBlank() },
|
isResultEmpty = { it?.message?.content.isNullOrBlank() },
|
||||||
shouldFetch = {
|
shouldFetch = {
|
||||||
checkNotNull(it) { "This message no longer exist!" }
|
checkNotNull(it) { "This message no longer exist!" }
|
||||||
Timber.d("Message content in db empty: ${it.message.content.isEmpty()}")
|
Timber.d("Message content in db empty: ${it.message.content.isBlank()}")
|
||||||
it.message.unread || it.message.content.isEmpty()
|
it.message.unread || it.message.content.isBlank()
|
||||||
},
|
},
|
||||||
query = { messagesDb.loadMessageWithAttachment(student.id.toInt(), message.messageId) },
|
query = { messagesDb.loadMessageWithAttachment(message.messageGlobalKey) },
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).getMessageDetails(
|
sdk.init(student).getMessageDetails(it!!.message.messageGlobalKey)
|
||||||
messageId = it!!.message.messageId,
|
|
||||||
folderId = message.folderId,
|
|
||||||
read = markAsRead,
|
|
||||||
id = message.realId
|
|
||||||
).let { details ->
|
|
||||||
details.content to details.attachments.mapToEntities()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, (downloadedMessage, attachments) ->
|
saveFetchResult = { old, new ->
|
||||||
checkNotNull(old) { "Fetched message no longer exist!" }
|
checkNotNull(old) { "Fetched message no longer exist!" }
|
||||||
messagesDb.updateAll(listOf(old.message.apply {
|
messagesDb.updateAll(
|
||||||
id = old.message.id
|
listOf(old.message.apply {
|
||||||
|
id = message.id
|
||||||
unread = !markAsRead
|
unread = !markAsRead
|
||||||
content = content.ifBlank { downloadedMessage }
|
sender = new.sender
|
||||||
}))
|
recipients = new.recipients.firstOrNull() ?: "Wielu adresoatów"
|
||||||
messageAttachmentDao.insertAttachments(attachments)
|
content = content.ifBlank { new.content }
|
||||||
|
})
|
||||||
|
)
|
||||||
|
messageAttachmentDao.insertAttachments(
|
||||||
|
items = new.attachments.mapToEntities(message.messageGlobalKey),
|
||||||
|
)
|
||||||
|
|
||||||
Timber.d("Message ${message.messageId} with blank content: ${old.message.content.isBlank()}, marked as read")
|
Timber.d("Message ${message.messageId} with blank content: ${old.message.content.isBlank()}, marked as read")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getMessagesFromDatabase(student: Student): Flow<List<Message>> {
|
fun getMessagesFromDatabase(mailbox: Mailbox): Flow<List<Message>> {
|
||||||
return messagesDb.loadAll(student.id.toInt(), RECEIVED.id)
|
return messagesDb.loadAll(mailbox.globalKey, RECEIVED.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateMessages(messages: List<Message>) {
|
suspend fun updateMessages(messages: List<Message>) {
|
||||||
@ -145,32 +123,48 @@ class MessageRepository @Inject constructor(
|
|||||||
subject: String,
|
subject: String,
|
||||||
content: String,
|
content: String,
|
||||||
recipients: List<Recipient>,
|
recipients: List<Recipient>,
|
||||||
): SentMessage = sdk.init(student).sendMessage(
|
mailboxId: String,
|
||||||
|
) {
|
||||||
|
sdk.init(student).sendMessage(
|
||||||
subject = subject,
|
subject = subject,
|
||||||
content = content,
|
content = content,
|
||||||
recipients = recipients.mapFromEntities()
|
recipients = recipients.mapFromEntities(),
|
||||||
|
mailboxId = mailboxId,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun deleteMessages(student: Student, mailbox: Mailbox, messages: List<Message>) {
|
||||||
|
val firstMessage = messages.first()
|
||||||
|
sdk.init(student).deleteMessages(
|
||||||
|
messages = messages.map { it.messageGlobalKey },
|
||||||
|
removeForever = firstMessage.folderId == TRASHED.id,
|
||||||
)
|
)
|
||||||
|
|
||||||
suspend fun deleteMessages(student: Student, messages: List<Message>) {
|
if (firstMessage.folderId != TRASHED.id) {
|
||||||
val folderId = messages.first().folderId
|
|
||||||
val isDeleted = sdk.init(student)
|
|
||||||
.deleteMessages(messages = messages.map { it.messageId }, folderId = folderId)
|
|
||||||
|
|
||||||
if (folderId != MessageFolder.TRASHED.id && isDeleted) {
|
|
||||||
val deletedMessages = messages.map {
|
val deletedMessages = messages.map {
|
||||||
it.copy(folderId = MessageFolder.TRASHED.id)
|
it.copy(folderId = TRASHED.id)
|
||||||
.apply {
|
.apply {
|
||||||
id = it.id
|
id = it.id
|
||||||
content = it.content
|
content = it.content
|
||||||
|
sender = it.sender
|
||||||
|
recipients = it.recipients
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
messagesDb.updateAll(deletedMessages)
|
messagesDb.updateAll(deletedMessages)
|
||||||
} else messagesDb.deleteAll(messages)
|
} else messagesDb.deleteAll(messages)
|
||||||
|
|
||||||
|
getMessages(
|
||||||
|
student = student,
|
||||||
|
mailbox = mailbox,
|
||||||
|
folder = TRASHED,
|
||||||
|
forceRefresh = true,
|
||||||
|
).first()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun deleteMessage(student: Student, message: Message) =
|
suspend fun deleteMessage(student: Student, mailbox: Mailbox, message: Message) {
|
||||||
deleteMessages(student, listOf(message))
|
deleteMessages(student, mailbox, listOf(message))
|
||||||
|
}
|
||||||
|
|
||||||
var draftMessage: MessageDraft?
|
var draftMessage: MessageDraft?
|
||||||
get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_send_draft))
|
get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_send_draft))
|
||||||
|
@ -39,12 +39,12 @@ class MobileDeviceRepository @Inject constructor(
|
|||||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
|
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
|
||||||
it.isEmpty() || forceRefresh || isExpired
|
it.isEmpty() || forceRefresh || isExpired
|
||||||
},
|
},
|
||||||
query = { mobileDb.loadAll(student.userLoginId.takeIf { it != 0 } ?: student.studentId) },
|
query = { mobileDb.loadAll(student.userLoginId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student)
|
sdk.init(student)
|
||||||
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
|
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
|
||||||
.getRegisteredDevices()
|
.getRegisteredDevices()
|
||||||
.mapToEntities(semester)
|
.mapToEntities(student)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
mobileDb.deleteAll(old uniqueSubtract new)
|
mobileDb.deleteAll(old uniqueSubtract new)
|
||||||
|
@ -222,19 +222,31 @@ class PreferencesRepository @Inject constructor(
|
|||||||
get() = selectedDashboardTilesPreference.asFlow()
|
get() = selectedDashboardTilesPreference.asFlow()
|
||||||
.map { set ->
|
.map { set ->
|
||||||
set.map { DashboardItem.Tile.valueOf(it) }
|
set.map { DashboardItem.Tile.valueOf(it) }
|
||||||
.plus(DashboardItem.Tile.ACCOUNT)
|
.plus(
|
||||||
.plus(DashboardItem.Tile.ADMIN_MESSAGE)
|
listOfNotNull(
|
||||||
|
DashboardItem.Tile.ACCOUNT,
|
||||||
|
DashboardItem.Tile.ADMIN_MESSAGE,
|
||||||
|
DashboardItem.Tile.ADS.takeIf { isAdsEnabled }
|
||||||
|
)
|
||||||
|
)
|
||||||
.toSet()
|
.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectedDashboardTiles: Set<DashboardItem.Tile>
|
var selectedDashboardTiles: Set<DashboardItem.Tile>
|
||||||
get() = selectedDashboardTilesPreference.get()
|
get() = selectedDashboardTilesPreference.get()
|
||||||
.map { DashboardItem.Tile.valueOf(it) }
|
.map { DashboardItem.Tile.valueOf(it) }
|
||||||
.plus(DashboardItem.Tile.ACCOUNT)
|
.plus(
|
||||||
.plus(DashboardItem.Tile.ADMIN_MESSAGE)
|
listOfNotNull(
|
||||||
|
DashboardItem.Tile.ACCOUNT,
|
||||||
|
DashboardItem.Tile.ADMIN_MESSAGE,
|
||||||
|
DashboardItem.Tile.ADS.takeIf { isAdsEnabled }
|
||||||
|
)
|
||||||
|
)
|
||||||
.toSet()
|
.toSet()
|
||||||
set(value) {
|
set(value) {
|
||||||
val filteredValue = value.filterNot { it == DashboardItem.Tile.ACCOUNT }
|
val filteredValue = value.filterNot {
|
||||||
|
it == DashboardItem.Tile.ACCOUNT || it == DashboardItem.Tile.ADMIN_MESSAGE
|
||||||
|
}
|
||||||
.map { it.name }
|
.map { it.name }
|
||||||
.toSet()
|
.toSet()
|
||||||
|
|
||||||
@ -271,7 +283,38 @@ class PreferencesRepository @Inject constructor(
|
|||||||
|
|
||||||
var isAppReviewDone: Boolean
|
var isAppReviewDone: Boolean
|
||||||
get() = sharedPref.getBoolean(PREF_KEY_IN_APP_REVIEW_DONE, false)
|
get() = sharedPref.getBoolean(PREF_KEY_IN_APP_REVIEW_DONE, false)
|
||||||
set(value) = sharedPref.edit().putBoolean(PREF_KEY_IN_APP_REVIEW_DONE, value).apply()
|
set(value) = sharedPref.edit { putBoolean(PREF_KEY_IN_APP_REVIEW_DONE, value) }
|
||||||
|
|
||||||
|
var isAppSupportShown: Boolean
|
||||||
|
get() = sharedPref.getBoolean(PREF_KEY_APP_SUPPORT_SHOWN, false)
|
||||||
|
set(value) = sharedPref.edit { putBoolean(PREF_KEY_APP_SUPPORT_SHOWN, value) }
|
||||||
|
|
||||||
|
var isAgreeToProcessData: Boolean
|
||||||
|
get() = getBoolean(
|
||||||
|
R.string.pref_key_ads_consent_data_processing,
|
||||||
|
R.bool.pref_default_ads_consent_data_processing
|
||||||
|
)
|
||||||
|
set(value) = sharedPref.edit {
|
||||||
|
putBoolean(context.getString(R.string.pref_key_ads_consent_data_processing), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
var isPersonalizedAdsEnabled: Boolean
|
||||||
|
get() = sharedPref.getBoolean(PREF_KEY_PERSONALIZED_ADS_ENABLED, false)
|
||||||
|
set(value) = sharedPref.edit { putBoolean(PREF_KEY_PERSONALIZED_ADS_ENABLED, value) }
|
||||||
|
|
||||||
|
val isAdsEnabledFlow = flowSharedPref.getBoolean(
|
||||||
|
context.getString(R.string.pref_key_ads_enabled),
|
||||||
|
context.resources.getBoolean(R.bool.pref_default_ads_enabled)
|
||||||
|
).asFlow()
|
||||||
|
|
||||||
|
var isAdsEnabled: Boolean
|
||||||
|
get() = getBoolean(
|
||||||
|
R.string.pref_key_ads_enabled,
|
||||||
|
R.bool.pref_default_ads_enabled
|
||||||
|
)
|
||||||
|
set(value) = sharedPref.edit {
|
||||||
|
putBoolean(context.getString(R.string.pref_key_ads_enabled), value)
|
||||||
|
}
|
||||||
|
|
||||||
private fun getLong(id: Int, default: Int) = getLong(context.getString(id), default)
|
private fun getLong(id: Int, default: Int) = getLong(context.getString(id), default)
|
||||||
|
|
||||||
@ -301,6 +344,10 @@ class PreferencesRepository @Inject constructor(
|
|||||||
|
|
||||||
private const val PREF_KEY_IN_APP_REVIEW_DONE = "in_app_review_done"
|
private const val PREF_KEY_IN_APP_REVIEW_DONE = "in_app_review_done"
|
||||||
|
|
||||||
|
private const val PREF_KEY_APP_SUPPORT_SHOWN = "app_support_shown"
|
||||||
|
|
||||||
|
private const val PREF_KEY_PERSONALIZED_ADS_ENABLED = "personalized_ads_enabled"
|
||||||
|
|
||||||
private const val PREF_KEY_ADMIN_DISMISSED_MESSAGE_IDS = "admin_message_dismissed_ids"
|
private const val PREF_KEY_ADMIN_DISMISSED_MESSAGE_IDS = "admin_message_dismissed_ids"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
package io.github.wulkanowy.data.repositories
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.dao.RecipientDao
|
import io.github.wulkanowy.data.db.dao.RecipientDao
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.*
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
|
||||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
@ -23,9 +20,10 @@ class RecipientRepository @Inject constructor(
|
|||||||
|
|
||||||
private val cacheKey = "recipient"
|
private val cacheKey = "recipient"
|
||||||
|
|
||||||
suspend fun refreshRecipients(student: Student, unit: ReportingUnit, role: Int) {
|
suspend fun refreshRecipients(student: Student, mailbox: Mailbox, type: MailboxType) {
|
||||||
val new = sdk.init(student).getRecipients(unit.unitId, role).mapToEntities(unit.studentId)
|
val new = sdk.init(student).getRecipients(mailbox.globalKey)
|
||||||
val old = recipientDb.loadAll(unit.studentId, unit.unitId, role)
|
.mapToEntities(mailbox.globalKey)
|
||||||
|
val old = recipientDb.loadAll(type, mailbox.globalKey)
|
||||||
|
|
||||||
recipientDb.deleteAll(old uniqueSubtract new)
|
recipientDb.deleteAll(old uniqueSubtract new)
|
||||||
recipientDb.insertAll(new uniqueSubtract old)
|
recipientDb.insertAll(new uniqueSubtract old)
|
||||||
@ -33,18 +31,27 @@ class RecipientRepository @Inject constructor(
|
|||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getRecipients(student: Student, unit: ReportingUnit, role: Int): List<Recipient> {
|
suspend fun getRecipients(
|
||||||
val cached = recipientDb.loadAll(unit.studentId, unit.unitId, role)
|
student: Student,
|
||||||
|
mailbox: Mailbox,
|
||||||
|
type: MailboxType
|
||||||
|
): List<Recipient> {
|
||||||
|
val cached = recipientDb.loadAll(type, mailbox.globalKey)
|
||||||
|
|
||||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
|
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
|
||||||
return if (cached.isEmpty() || isExpired) {
|
return if (cached.isEmpty() || isExpired) {
|
||||||
refreshRecipients(student, unit, role)
|
refreshRecipients(student, mailbox, type)
|
||||||
recipientDb.loadAll(unit.studentId, unit.unitId, role)
|
recipientDb.loadAll(type, mailbox.globalKey)
|
||||||
} else cached
|
} else cached
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getMessageRecipients(student: Student, message: Message): List<Recipient> {
|
suspend fun getMessageSender(
|
||||||
return sdk.init(student).getMessageRecipients(message.messageId, message.senderId)
|
student: Student,
|
||||||
.mapToEntities(student.studentId)
|
mailbox: Mailbox,
|
||||||
}
|
message: Message
|
||||||
|
): List<Recipient> = sdk.init(student)
|
||||||
|
.getMessageReplayDetails(message.messageGlobalKey)
|
||||||
|
.sender
|
||||||
|
.let(::listOf)
|
||||||
|
.mapToEntities(mailbox.globalKey)
|
||||||
}
|
}
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
package io.github.wulkanowy.data.repositories
|
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.dao.ReportingUnitDao
|
|
||||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
|
||||||
import io.github.wulkanowy.utils.init
|
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
class ReportingUnitRepository @Inject constructor(
|
|
||||||
private val reportingUnitDb: ReportingUnitDao,
|
|
||||||
private val sdk: Sdk
|
|
||||||
) {
|
|
||||||
|
|
||||||
suspend fun refreshReportingUnits(student: Student) {
|
|
||||||
val new = sdk.init(student).getReportingUnits().mapToEntities(student)
|
|
||||||
val old = reportingUnitDb.load(student.id.toInt())
|
|
||||||
|
|
||||||
reportingUnitDb.deleteAll(old.uniqueSubtract(new))
|
|
||||||
reportingUnitDb.insertAll(new.uniqueSubtract(old))
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getReportingUnits(student: Student): List<ReportingUnit> {
|
|
||||||
return reportingUnitDb.load(student.id.toInt()).ifEmpty {
|
|
||||||
refreshReportingUnits(student)
|
|
||||||
|
|
||||||
reportingUnitDb.load(student.id.toInt())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getReportingUnit(student: Student, unitId: Int): ReportingUnit? {
|
|
||||||
return reportingUnitDb.loadOne(student.id.toInt(), unitId) ?: run {
|
|
||||||
refreshReportingUnits(student)
|
|
||||||
|
|
||||||
return reportingUnitDb.loadOne(student.id.toInt(), unitId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -28,7 +28,8 @@ class SchoolAnnouncementRepository @Inject constructor(
|
|||||||
|
|
||||||
fun getSchoolAnnouncements(
|
fun getSchoolAnnouncements(
|
||||||
student: Student,
|
student: Student,
|
||||||
forceRefresh: Boolean, notify: Boolean = false
|
forceRefresh: Boolean,
|
||||||
|
notify: Boolean = false
|
||||||
) = networkBoundResource(
|
) = networkBoundResource(
|
||||||
mutex = saveFetchResultMutex,
|
mutex = saveFetchResultMutex,
|
||||||
isResultEmpty = { it.isEmpty() },
|
isResultEmpty = { it.isEmpty() },
|
||||||
@ -37,7 +38,7 @@ class SchoolAnnouncementRepository @Inject constructor(
|
|||||||
it.isEmpty() || forceRefresh || isExpired
|
it.isEmpty() || forceRefresh || isExpired
|
||||||
},
|
},
|
||||||
query = {
|
query = {
|
||||||
schoolAnnouncementDb.loadAll(student.studentId)
|
schoolAnnouncementDb.loadAll(student.userLoginId)
|
||||||
},
|
},
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student)
|
sdk.init(student)
|
||||||
@ -56,7 +57,7 @@ class SchoolAnnouncementRepository @Inject constructor(
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun getSchoolAnnouncementFromDatabase(student: Student): Flow<List<SchoolAnnouncement>> {
|
fun getSchoolAnnouncementFromDatabase(student: Student): Flow<List<SchoolAnnouncement>> {
|
||||||
return schoolAnnouncementDb.loadAll(student.studentId)
|
return schoolAnnouncementDb.loadAll(student.userLoginId)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateSchoolAnnouncement(schoolAnnouncement: List<SchoolAnnouncement>) =
|
suspend fun updateSchoolAnnouncement(schoolAnnouncement: List<SchoolAnnouncement>) =
|
||||||
|
@ -21,7 +21,7 @@ class NewMessageNotification @Inject constructor(
|
|||||||
val notificationDataList = items.map {
|
val notificationDataList = items.map {
|
||||||
NotificationData(
|
NotificationData(
|
||||||
title = context.getPlural(R.plurals.message_new_items, 1),
|
title = context.getPlural(R.plurals.message_new_items, 1),
|
||||||
content = "${it.sender}: ${it.subject}",
|
content = "${it.correspondents}: ${it.subject}",
|
||||||
destination = Destination.Message,
|
destination = Destination.Message,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.services.sync.works
|
|||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
|
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
|
||||||
|
import io.github.wulkanowy.data.repositories.MailboxRepository
|
||||||
import io.github.wulkanowy.data.repositories.MessageRepository
|
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||||
import io.github.wulkanowy.data.waitForResult
|
import io.github.wulkanowy.data.waitForResult
|
||||||
import io.github.wulkanowy.services.sync.notifications.NewMessageNotification
|
import io.github.wulkanowy.services.sync.notifications.NewMessageNotification
|
||||||
@ -11,19 +12,21 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
class MessageWork @Inject constructor(
|
class MessageWork @Inject constructor(
|
||||||
private val messageRepository: MessageRepository,
|
private val messageRepository: MessageRepository,
|
||||||
|
private val mailboxRepository: MailboxRepository,
|
||||||
private val newMessageNotification: NewMessageNotification,
|
private val newMessageNotification: NewMessageNotification,
|
||||||
) : Work {
|
) : Work {
|
||||||
|
|
||||||
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
|
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
|
||||||
|
val mailbox = mailboxRepository.getMailbox(student)
|
||||||
messageRepository.getMessages(
|
messageRepository.getMessages(
|
||||||
student = student,
|
student = student,
|
||||||
semester = semester,
|
mailbox = mailbox,
|
||||||
folder = RECEIVED,
|
folder = RECEIVED,
|
||||||
forceRefresh = true,
|
forceRefresh = true,
|
||||||
notify = notify
|
notify = notify
|
||||||
).waitForResult()
|
).waitForResult()
|
||||||
|
|
||||||
messageRepository.getMessagesFromDatabase(student).first()
|
messageRepository.getMessagesFromDatabase(mailbox).first()
|
||||||
.filter { !it.isNotified && it.unread }.let {
|
.filter { !it.isNotified && it.unread }.let {
|
||||||
if (it.isNotEmpty()) newMessageNotification.notify(it, student)
|
if (it.isNotEmpty()) newMessageNotification.notify(it, student)
|
||||||
messageRepository.updateMessages(it.onEach { message -> message.isNotified = true })
|
messageRepository.updateMessages(it.onEach { message -> message.isNotified = true })
|
||||||
|
@ -1,23 +1,22 @@
|
|||||||
package io.github.wulkanowy.services.sync.works
|
package io.github.wulkanowy.services.sync.works
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.MailboxType
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.data.repositories.MailboxRepository
|
||||||
import io.github.wulkanowy.data.repositories.RecipientRepository
|
import io.github.wulkanowy.data.repositories.RecipientRepository
|
||||||
import io.github.wulkanowy.data.repositories.ReportingUnitRepository
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class RecipientWork @Inject constructor(
|
class RecipientWork @Inject constructor(
|
||||||
private val reportingUnitRepository: ReportingUnitRepository,
|
private val mailboxRepository: MailboxRepository,
|
||||||
private val recipientRepository: RecipientRepository
|
private val recipientRepository: RecipientRepository
|
||||||
) : Work {
|
) : Work {
|
||||||
|
|
||||||
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
|
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
|
||||||
reportingUnitRepository.refreshReportingUnits(student)
|
mailboxRepository.refreshMailboxes(student)
|
||||||
|
|
||||||
reportingUnitRepository.getReportingUnits(student).let { units ->
|
val mailbox = mailboxRepository.getMailbox(student)
|
||||||
units.map {
|
|
||||||
recipientRepository.refreshRecipients(student, it, 2)
|
recipientRepository.refreshRecipients(student, mailbox, MailboxType.EMPLOYEE)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import io.github.wulkanowy.data.repositories.SchoolAnnouncementRepository
|
|||||||
import io.github.wulkanowy.data.waitForResult
|
import io.github.wulkanowy.data.waitForResult
|
||||||
import io.github.wulkanowy.services.sync.notifications.NewSchoolAnnouncementNotification
|
import io.github.wulkanowy.services.sync.notifications.NewSchoolAnnouncementNotification
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
|
import java.time.LocalDate
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class SchoolAnnouncementWork @Inject constructor(
|
class SchoolAnnouncementWork @Inject constructor(
|
||||||
@ -20,10 +21,13 @@ class SchoolAnnouncementWork @Inject constructor(
|
|||||||
notify = notify,
|
notify = notify,
|
||||||
).waitForResult()
|
).waitForResult()
|
||||||
|
|
||||||
|
schoolAnnouncementRepository.getSchoolAnnouncementFromDatabase(student)
|
||||||
schoolAnnouncementRepository.getSchoolAnnouncementFromDatabase(student).first()
|
.first()
|
||||||
.filter { !it.isNotified }.let {
|
.filter { !it.isNotified && it.date >= LocalDate.now() }
|
||||||
if (it.isNotEmpty()) newSchoolAnnouncementNotification.notify(it, student)
|
.let {
|
||||||
|
if (it.isNotEmpty()) {
|
||||||
|
newSchoolAnnouncementNotification.notify(it, student)
|
||||||
|
}
|
||||||
|
|
||||||
schoolAnnouncementRepository.updateSchoolAnnouncement(it.onEach { schoolAnnouncement ->
|
schoolAnnouncementRepository.updateSchoolAnnouncement(it.onEach { schoolAnnouncement ->
|
||||||
schoolAnnouncement.isNotified = true
|
schoolAnnouncement.isNotified = true
|
||||||
|
@ -91,15 +91,19 @@ class AttendancePresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onViewReselected() {
|
fun onViewReselected() {
|
||||||
Timber.i("Attendance view is reselected")
|
Timber.i("Attendance view is reselected")
|
||||||
view?.also { view ->
|
view?.let { view ->
|
||||||
if (view.currentStackSize == 1) {
|
if (view.currentStackSize == 1) {
|
||||||
baseDate.also {
|
baseDate = now().previousOrSameSchoolDay
|
||||||
if (currentDate != it) {
|
|
||||||
reloadView(it)
|
if (currentDate != baseDate) {
|
||||||
|
reloadView(baseDate)
|
||||||
loadData()
|
loadData()
|
||||||
} else if (!view.isViewEmpty) view.resetView()
|
} else if (!view.isViewEmpty) {
|
||||||
|
view.resetView()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
view.popView()
|
||||||
}
|
}
|
||||||
} else view.popView()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ import io.github.wulkanowy.ui.base.BaseFragment
|
|||||||
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsFragment
|
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsFragment
|
||||||
import io.github.wulkanowy.ui.modules.attendance.summary.AttendanceSummaryFragment
|
import io.github.wulkanowy.ui.modules.attendance.summary.AttendanceSummaryFragment
|
||||||
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
|
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.dashboard.adapters.DashboardAdapter
|
||||||
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
||||||
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
||||||
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
||||||
@ -47,6 +48,14 @@ class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragme
|
|||||||
override var subtitleString =
|
override var subtitleString =
|
||||||
LocalDate.now().toFormattedString("EEEE, d MMMM yyyy").capitalise()
|
LocalDate.now().toFormattedString("EEEE, d MMMM yyyy").capitalise()
|
||||||
|
|
||||||
|
override val tileWidth: Int
|
||||||
|
get() {
|
||||||
|
val recyclerWidth = binding.dashboardRecycler.width
|
||||||
|
val margin = requireContext().dpToPx(24f).toInt()
|
||||||
|
|
||||||
|
return ((recyclerWidth - margin) / resources.displayMetrics.density).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun newInstance() = DashboardFragment()
|
fun newInstance() = DashboardFragment()
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
import io.github.wulkanowy.data.db.entities.*
|
||||||
import io.github.wulkanowy.data.db.entities.Conference
|
|
||||||
import io.github.wulkanowy.data.db.entities.Exam
|
|
||||||
import io.github.wulkanowy.data.db.entities.Grade
|
|
||||||
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import io.github.wulkanowy.data.enums.GradeColorTheme
|
import io.github.wulkanowy.data.enums.GradeColorTheme
|
||||||
import io.github.wulkanowy.data.pojos.TimetableFull
|
import io.github.wulkanowy.data.pojos.TimetableFull
|
||||||
|
import io.github.wulkanowy.utils.AdBanner
|
||||||
import io.github.wulkanowy.data.db.entities.Homework as EntitiesHomework
|
import io.github.wulkanowy.data.db.entities.Homework as EntitiesHomework
|
||||||
|
|
||||||
sealed class DashboardItem(val type: Type) {
|
sealed class DashboardItem(val type: Type) {
|
||||||
@ -106,17 +102,26 @@ sealed class DashboardItem(val type: Type) {
|
|||||||
override val isDataLoaded get() = conferences != null
|
override val isDataLoaded get() = conferences != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class Ads(
|
||||||
|
val adBanner: AdBanner? = null,
|
||||||
|
override val error: Throwable? = null,
|
||||||
|
override val isLoading: Boolean = false
|
||||||
|
) : DashboardItem(Type.ADS) {
|
||||||
|
|
||||||
|
override val isDataLoaded get() = adBanner != null
|
||||||
|
}
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
ADMIN_MESSAGE,
|
ADMIN_MESSAGE,
|
||||||
ACCOUNT,
|
ACCOUNT,
|
||||||
HORIZONTAL_GROUP,
|
HORIZONTAL_GROUP,
|
||||||
LESSONS,
|
LESSONS,
|
||||||
|
ADS,
|
||||||
GRADES,
|
GRADES,
|
||||||
HOMEWORK,
|
HOMEWORK,
|
||||||
ANNOUNCEMENTS,
|
ANNOUNCEMENTS,
|
||||||
EXAMS,
|
EXAMS,
|
||||||
CONFERENCES,
|
CONFERENCES,
|
||||||
ADS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Tile {
|
enum class Tile {
|
||||||
@ -126,12 +131,12 @@ sealed class DashboardItem(val type: Type) {
|
|||||||
MESSAGES,
|
MESSAGES,
|
||||||
ATTENDANCE,
|
ATTENDANCE,
|
||||||
LESSONS,
|
LESSONS,
|
||||||
|
ADS,
|
||||||
GRADES,
|
GRADES,
|
||||||
HOMEWORK,
|
HOMEWORK,
|
||||||
ANNOUNCEMENTS,
|
ANNOUNCEMENTS,
|
||||||
EXAMS,
|
EXAMS,
|
||||||
CONFERENCES,
|
CONFERENCES,
|
||||||
ADS
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,8 @@ package io.github.wulkanowy.ui.modules.dashboard
|
|||||||
|
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import java.util.Collections
|
import io.github.wulkanowy.ui.modules.dashboard.adapters.DashboardAdapter
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class DashboardItemMoveCallback(
|
class DashboardItemMoveCallback(
|
||||||
private val dashboardAdapter: DashboardAdapter,
|
private val dashboardAdapter: DashboardAdapter,
|
||||||
|
@ -8,6 +8,7 @@ import io.github.wulkanowy.data.enums.MessageFolder
|
|||||||
import io.github.wulkanowy.data.repositories.*
|
import io.github.wulkanowy.data.repositories.*
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
|
import io.github.wulkanowy.utils.AdsHelper
|
||||||
import io.github.wulkanowy.utils.calculatePercentage
|
import io.github.wulkanowy.utils.calculatePercentage
|
||||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
@ -24,6 +25,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
private val gradeRepository: GradeRepository,
|
private val gradeRepository: GradeRepository,
|
||||||
private val semesterRepository: SemesterRepository,
|
private val semesterRepository: SemesterRepository,
|
||||||
private val messageRepository: MessageRepository,
|
private val messageRepository: MessageRepository,
|
||||||
|
private val mailboxRepository: MailboxRepository,
|
||||||
private val attendanceSummaryRepository: AttendanceSummaryRepository,
|
private val attendanceSummaryRepository: AttendanceSummaryRepository,
|
||||||
private val timetableRepository: TimetableRepository,
|
private val timetableRepository: TimetableRepository,
|
||||||
private val homeworkRepository: HomeworkRepository,
|
private val homeworkRepository: HomeworkRepository,
|
||||||
@ -31,7 +33,8 @@ class DashboardPresenter @Inject constructor(
|
|||||||
private val conferenceRepository: ConferenceRepository,
|
private val conferenceRepository: ConferenceRepository,
|
||||||
private val preferencesRepository: PreferencesRepository,
|
private val preferencesRepository: PreferencesRepository,
|
||||||
private val schoolAnnouncementRepository: SchoolAnnouncementRepository,
|
private val schoolAnnouncementRepository: SchoolAnnouncementRepository,
|
||||||
private val adminMessageRepository: AdminMessageRepository
|
private val adminMessageRepository: AdminMessageRepository,
|
||||||
|
private val adsHelper: AdsHelper
|
||||||
) : BasePresenter<DashboardView>(errorHandler, studentRepository) {
|
) : BasePresenter<DashboardView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
private val dashboardItemLoadedList = mutableListOf<DashboardItem>()
|
private val dashboardItemLoadedList = mutableListOf<DashboardItem>()
|
||||||
@ -55,7 +58,11 @@ class DashboardPresenter @Inject constructor(
|
|||||||
showContent(false)
|
showContent(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
preferencesRepository.selectedDashboardTilesFlow
|
merge(
|
||||||
|
preferencesRepository.selectedDashboardTilesFlow,
|
||||||
|
preferencesRepository.isAdsEnabledFlow
|
||||||
|
.map { preferencesRepository.selectedDashboardTiles }
|
||||||
|
)
|
||||||
.onEach { loadData(tilesToLoad = it) }
|
.onEach { loadData(tilesToLoad = it) }
|
||||||
.launch("dashboard_pref")
|
.launch("dashboard_pref")
|
||||||
}
|
}
|
||||||
@ -166,7 +173,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
DashboardItem.Type.CONFERENCES -> {
|
DashboardItem.Type.CONFERENCES -> {
|
||||||
loadConferences(student, forceRefresh)
|
loadConferences(student, forceRefresh)
|
||||||
}
|
}
|
||||||
DashboardItem.Type.ADS -> TODO()
|
DashboardItem.Type.ADS -> loadAds(forceRefresh)
|
||||||
DashboardItem.Type.ADMIN_MESSAGE -> loadAdminMessage(student, forceRefresh)
|
DashboardItem.Type.ADMIN_MESSAGE -> loadAdminMessage(student, forceRefresh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,6 +228,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) {
|
private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) {
|
||||||
flow {
|
flow {
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val semester = semesterRepository.getCurrentSemester(student)
|
||||||
|
val mailbox = mailboxRepository.getMailbox(student)
|
||||||
val selectedTiles = preferencesRepository.selectedDashboardTiles
|
val selectedTiles = preferencesRepository.selectedDashboardTiles
|
||||||
|
|
||||||
val flowSuccess = flowOf(Resource.Success(null))
|
val flowSuccess = flowOf(Resource.Success(null))
|
||||||
@ -232,7 +240,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
|
|
||||||
val messageFLow = messageRepository.getMessages(
|
val messageFLow = messageRepository.getMessages(
|
||||||
student = student,
|
student = student,
|
||||||
semester = semester,
|
mailbox = mailbox,
|
||||||
folder = MessageFolder.RECEIVED,
|
folder = MessageFolder.RECEIVED,
|
||||||
forceRefresh = forceRefresh
|
forceRefresh = forceRefresh
|
||||||
).takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowSuccess
|
).takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowSuccess
|
||||||
@ -595,6 +603,23 @@ class DashboardPresenter @Inject constructor(
|
|||||||
.launchWithUniqueRefreshJob("dashboard_admin_messages", forceRefresh)
|
.launchWithUniqueRefreshJob("dashboard_admin_messages", forceRefresh)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadAds(forceRefresh: Boolean) {
|
||||||
|
presenterScope.launch {
|
||||||
|
if (!forceRefresh) {
|
||||||
|
updateData(DashboardItem.Ads(), forceRefresh)
|
||||||
|
}
|
||||||
|
|
||||||
|
val dashboardAdItem =
|
||||||
|
runCatching {
|
||||||
|
DashboardItem.Ads(adsHelper.getDashboardTileAdBanner(view!!.tileWidth))
|
||||||
|
}
|
||||||
|
.onFailure { Timber.e(it) }
|
||||||
|
.getOrElse { DashboardItem.Ads(error = it) }
|
||||||
|
|
||||||
|
updateData(dashboardAdItem, forceRefresh)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateData(dashboardItem: DashboardItem, forceRefresh: Boolean) {
|
private fun updateData(dashboardItem: DashboardItem, forceRefresh: Boolean) {
|
||||||
val isForceRefreshError = forceRefresh && dashboardItem.error != null
|
val isForceRefreshError = forceRefresh && dashboardItem.error != null
|
||||||
val isFirstRunDataLoadedError =
|
val isFirstRunDataLoadedError =
|
||||||
@ -619,6 +644,18 @@ class DashboardPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dashboardItem is DashboardItem.Ads) {
|
||||||
|
if (!dashboardItem.isDataLoaded) {
|
||||||
|
dashboardItemsToLoad = dashboardItemsToLoad - DashboardItem.Type.ADS
|
||||||
|
dashboardTileLoadedList = dashboardTileLoadedList - DashboardItem.Tile.ADS
|
||||||
|
|
||||||
|
dashboardItemLoadedList.removeAll { it.type == DashboardItem.Type.ADS }
|
||||||
|
} else {
|
||||||
|
dashboardItemsToLoad = dashboardItemsToLoad + DashboardItem.Type.ADS
|
||||||
|
dashboardTileLoadedList = dashboardTileLoadedList + DashboardItem.Tile.ADS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (forceRefresh) {
|
if (forceRefresh) {
|
||||||
updateForceRefreshData(dashboardItem)
|
updateForceRefreshData(dashboardItem)
|
||||||
} else {
|
} else {
|
||||||
|
@ -4,6 +4,8 @@ import io.github.wulkanowy.ui.base.BaseView
|
|||||||
|
|
||||||
interface DashboardView : BaseView {
|
interface DashboardView : BaseView {
|
||||||
|
|
||||||
|
val tileWidth: Int
|
||||||
|
|
||||||
fun initView()
|
fun initView()
|
||||||
|
|
||||||
fun updateData(data: List<DashboardItem>)
|
fun updateData(data: List<DashboardItem>)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
@ -22,24 +22,15 @@ import io.github.wulkanowy.data.db.entities.Student
|
|||||||
import io.github.wulkanowy.data.db.entities.Timetable
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
||||||
import io.github.wulkanowy.data.enums.GradeColorTheme
|
import io.github.wulkanowy.data.enums.GradeColorTheme
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardAccountBinding
|
import io.github.wulkanowy.databinding.*
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardAdminMessageBinding
|
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardAnnouncementsBinding
|
import io.github.wulkanowy.utils.*
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardConferencesBinding
|
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardExamsBinding
|
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardGradesBinding
|
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardHomeworkBinding
|
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardHorizontalGroupBinding
|
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardLessonsBinding
|
|
||||||
import io.github.wulkanowy.utils.createNameInitialsDrawable
|
|
||||||
import io.github.wulkanowy.utils.dpToPx
|
|
||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
|
||||||
import io.github.wulkanowy.utils.left
|
|
||||||
import io.github.wulkanowy.utils.nickOrName
|
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.time.*
|
import java.time.Duration
|
||||||
import java.util.Timer
|
import java.time.Instant
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.concurrent.timer
|
import kotlin.concurrent.timer
|
||||||
|
|
||||||
@ -120,6 +111,9 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
DashboardItem.Type.ADMIN_MESSAGE.ordinal -> AdminMessageViewHolder(
|
DashboardItem.Type.ADMIN_MESSAGE.ordinal -> AdminMessageViewHolder(
|
||||||
ItemDashboardAdminMessageBinding.inflate(inflater, parent, false)
|
ItemDashboardAdminMessageBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
DashboardItem.Type.ADS.ordinal -> AdsViewHolder(
|
||||||
|
ItemDashboardAdsBinding.inflate(inflater, parent, false)
|
||||||
|
)
|
||||||
else -> throw IllegalArgumentException()
|
else -> throw IllegalArgumentException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,6 +129,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
is ExamsViewHolder -> bindExamsViewHolder(holder, position)
|
is ExamsViewHolder -> bindExamsViewHolder(holder, position)
|
||||||
is ConferencesViewHolder -> bindConferencesViewHolder(holder, position)
|
is ConferencesViewHolder -> bindConferencesViewHolder(holder, position)
|
||||||
is AdminMessageViewHolder -> bindAdminMessage(holder, position)
|
is AdminMessageViewHolder -> bindAdminMessage(holder, position)
|
||||||
|
is AdsViewHolder -> bindAdsViewHolder(holder, position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -746,6 +741,20 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun bindAdsViewHolder(adsViewHolder: AdsViewHolder, position: Int) {
|
||||||
|
val item = (items[position] as DashboardItem.Ads).adBanner ?: return
|
||||||
|
val binding = adsViewHolder.binding
|
||||||
|
|
||||||
|
binding.dashboardAdminMessageItemContent.removeAllViews()
|
||||||
|
binding.dashboardAdminMessageItemContent.addView(
|
||||||
|
item.view,
|
||||||
|
ViewGroup.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
class AccountViewHolder(val binding: ItemDashboardAccountBinding) :
|
class AccountViewHolder(val binding: ItemDashboardAccountBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
@ -788,6 +797,9 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
class AdminMessageViewHolder(val binding: ItemDashboardAdminMessageBinding) :
|
class AdminMessageViewHolder(val binding: ItemDashboardAdminMessageBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
|
class AdsViewHolder(val binding: ItemDashboardAdsBinding) :
|
||||||
|
RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
private class DiffCallback(
|
private class DiffCallback(
|
||||||
private val newList: List<DashboardItem>,
|
private val newList: List<DashboardItem>,
|
||||||
private val oldList: List<DashboardItem>
|
private val oldList: List<DashboardItem>
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
@ -17,16 +17,13 @@ val debugMessageItems = listOf(
|
|||||||
)
|
)
|
||||||
|
|
||||||
private fun generateMessage(sender: String, subject: String) = Message(
|
private fun generateMessage(sender: String, subject: String) = Message(
|
||||||
sender = sender,
|
|
||||||
subject = subject,
|
subject = subject,
|
||||||
studentId = 0,
|
messageId = 123,
|
||||||
realId = 0,
|
|
||||||
messageId = 0,
|
|
||||||
senderId = 0,
|
|
||||||
recipient = "",
|
|
||||||
date = Instant.now(),
|
date = Instant.now(),
|
||||||
folderId = 0,
|
folderId = 0,
|
||||||
unread = true,
|
unread = true,
|
||||||
removed = false,
|
hasAttachments = false,
|
||||||
hasAttachments = false
|
messageGlobalKey = "",
|
||||||
|
correspondents = sender,
|
||||||
|
mailboxKey = "",
|
||||||
)
|
)
|
||||||
|
@ -19,6 +19,6 @@ val debugSchoolAnnouncementItems = listOf(
|
|||||||
private fun generateAnnouncement(subject: String, content: String) = SchoolAnnouncement(
|
private fun generateAnnouncement(subject: String, content: String) = SchoolAnnouncement(
|
||||||
subject = subject,
|
subject = subject,
|
||||||
content = content,
|
content = content,
|
||||||
studentId = 0,
|
userLoginId = 0,
|
||||||
date = LocalDate.now()
|
date = LocalDate.now()
|
||||||
)
|
)
|
||||||
|
@ -3,8 +3,8 @@ package io.github.wulkanowy.ui.modules.grade.details
|
|||||||
import io.github.wulkanowy.data.*
|
import io.github.wulkanowy.data.*
|
||||||
import io.github.wulkanowy.data.db.entities.Grade
|
import io.github.wulkanowy.data.db.entities.Grade
|
||||||
import io.github.wulkanowy.data.enums.GradeExpandMode
|
import io.github.wulkanowy.data.enums.GradeExpandMode
|
||||||
import io.github.wulkanowy.data.enums.GradeSortingMode.ALPHABETIC
|
import io.github.wulkanowy.data.enums.GradeSortingMode
|
||||||
import io.github.wulkanowy.data.enums.GradeSortingMode.DATE
|
import io.github.wulkanowy.data.enums.GradeSortingMode.*
|
||||||
import io.github.wulkanowy.data.repositories.GradeRepository
|
import io.github.wulkanowy.data.repositories.GradeRepository
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||||
@ -204,6 +204,7 @@ class GradeDetailsPresenter @Inject constructor(
|
|||||||
ALPHABETIC -> gradeSubjects.sortedBy { gradeDetailsWithAverage ->
|
ALPHABETIC -> gradeSubjects.sortedBy { gradeDetailsWithAverage ->
|
||||||
gradeDetailsWithAverage.subject.lowercase()
|
gradeDetailsWithAverage.subject.lowercase()
|
||||||
}
|
}
|
||||||
|
AVERAGE -> gradeSubjects.sortedByDescending { it.average }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.map { (subject, average, points, _, grades) ->
|
.map { (subject, average, points, _, grades) ->
|
||||||
|
@ -2,6 +2,9 @@ package io.github.wulkanowy.ui.modules.grade.summary
|
|||||||
|
|
||||||
import io.github.wulkanowy.data.*
|
import io.github.wulkanowy.data.*
|
||||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||||
|
import io.github.wulkanowy.data.enums.GradeSortingMode
|
||||||
|
import io.github.wulkanowy.data.enums.GradeSortingMode.*
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
@ -14,6 +17,7 @@ import javax.inject.Inject
|
|||||||
class GradeSummaryPresenter @Inject constructor(
|
class GradeSummaryPresenter @Inject constructor(
|
||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
|
private val preferencesRepository: PreferencesRepository,
|
||||||
private val averageProvider: GradeAverageProvider,
|
private val averageProvider: GradeAverageProvider,
|
||||||
private val analytics: AnalyticsHelper
|
private val analytics: AnalyticsHelper
|
||||||
) : BasePresenter<GradeSummaryView>(errorHandler, studentRepository) {
|
) : BasePresenter<GradeSummaryView>(errorHandler, studentRepository) {
|
||||||
@ -127,7 +131,17 @@ class GradeSummaryPresenter @Inject constructor(
|
|||||||
private fun createGradeSummaryItems(items: List<GradeSubject>): List<GradeSummary> {
|
private fun createGradeSummaryItems(items: List<GradeSubject>): List<GradeSummary> {
|
||||||
return items
|
return items
|
||||||
.filter { !checkEmpty(it) }
|
.filter { !checkEmpty(it) }
|
||||||
.sortedBy { it.subject }
|
.let { gradeSubjects ->
|
||||||
|
when (preferencesRepository.gradeSortingMode) {
|
||||||
|
DATE -> gradeSubjects.sortedByDescending { gradeDetailsWithAverage ->
|
||||||
|
gradeDetailsWithAverage.grades.maxByOrNull { it.date }?.date
|
||||||
|
}
|
||||||
|
ALPHABETIC -> gradeSubjects.sortedBy { gradeDetailsWithAverage ->
|
||||||
|
gradeDetailsWithAverage.subject.lowercase()
|
||||||
|
}
|
||||||
|
AVERAGE -> gradeSubjects.sortedByDescending { it.average }
|
||||||
|
}
|
||||||
|
}
|
||||||
.map { it.summary.copy(average = it.average) }
|
.map { it.summary.copy(average = it.average) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +93,7 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
|
|||||||
}
|
}
|
||||||
|
|
||||||
//https://developer.android.com/guide/playcore/in-app-updates#status_callback
|
//https://developer.android.com/guide/playcore/in-app-updates#status_callback
|
||||||
|
@Deprecated("Deprecated in Java")
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
@ -172,7 +172,7 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
if ("@" in login && "||" !in login && "login" !in host && "email" !in host) {
|
if ("@" in login && "||" !in login && "login" !in host && "email" !in host) {
|
||||||
val emailHost = login.substringAfter("@")
|
val emailHost = login.substringAfter("@")
|
||||||
val emailDomain = URL(host).host
|
val emailDomain = URL(host).host
|
||||||
if (emailHost != emailDomain) {
|
if (!emailHost.equals(emailDomain, true)) {
|
||||||
view?.setErrorEmailInvalid(domain = emailDomain)
|
view?.setErrorEmailInvalid(domain = emailDomain)
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,7 @@ import android.os.Bundle
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
import android.webkit.JavascriptInterface
|
import android.webkit.*
|
||||||
import android.webkit.WebView
|
|
||||||
import android.webkit.WebViewClient
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.doOnTextChanged
|
import androidx.core.widget.doOnTextChanged
|
||||||
import com.yariksoffice.lingver.Lingver
|
import com.yariksoffice.lingver.Lingver
|
||||||
@ -206,10 +204,9 @@ class LoginRecoverFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onReceivedError(
|
override fun onReceivedError(
|
||||||
view: WebView,
|
view: WebView?,
|
||||||
errorCode: Int,
|
request: WebResourceRequest?,
|
||||||
description: String,
|
error: WebResourceError?
|
||||||
failingUrl: String
|
|
||||||
) {
|
) {
|
||||||
recoverWebViewSuccess = false
|
recoverWebViewSuccess = false
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import androidx.fragment.app.DialogFragment
|
|||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.elevation.ElevationOverlayProvider
|
import com.google.android.material.elevation.ElevationOverlayProvider
|
||||||
import com.ncapdevi.fragnav.FragNavController
|
import com.ncapdevi.fragnav.FragNavController
|
||||||
import com.ncapdevi.fragnav.FragNavController.Companion.HIDE
|
import com.ncapdevi.fragnav.FragNavController.Companion.HIDE
|
||||||
@ -20,6 +21,7 @@ import io.github.wulkanowy.R
|
|||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.databinding.ActivityMainBinding
|
import io.github.wulkanowy.databinding.ActivityMainBinding
|
||||||
|
import io.github.wulkanowy.databinding.DialogAdsConsentBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
import io.github.wulkanowy.ui.modules.Destination
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
|
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
|
||||||
@ -100,6 +102,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
}
|
}
|
||||||
|
|
||||||
//https://developer.android.com/guide/playcore/in-app-updates#status_callback
|
//https://developer.android.com/guide/playcore/in-app-updates#status_callback
|
||||||
|
@Deprecated("Deprecated in Java")
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
@ -287,6 +290,50 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
inAppReviewHelper.showInAppReview(this)
|
inAppReviewHelper.showInAppReview(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showAppSupport() {
|
||||||
|
MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.main_support_title)
|
||||||
|
.setMessage(R.string.main_support_description)
|
||||||
|
.setPositiveButton(R.string.main_support_positive) { _, _ -> presenter.onEnableAdsSelected() }
|
||||||
|
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||||
|
.setOnDismissListener { }
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showPrivacyPolicyDialog() {
|
||||||
|
val dialogAdsConsentBinding = DialogAdsConsentBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
val dialog = MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.pref_ads_consent_title)
|
||||||
|
.setMessage(R.string.pref_ads_consent_description)
|
||||||
|
.setView(dialogAdsConsentBinding.root)
|
||||||
|
.show()
|
||||||
|
|
||||||
|
dialogAdsConsentBinding.adsConsentOver.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
dialogAdsConsentBinding.adsConsentPersonalised.isEnabled = isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogAdsConsentBinding.adsConsentPersonalised.setOnClickListener {
|
||||||
|
presenter.onPrivacyAgree(true)
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogAdsConsentBinding.adsConsentNonPersonalised.setOnClickListener {
|
||||||
|
presenter.onPrivacyAgree(false)
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogAdsConsentBinding.adsConsentPrivacy.setOnClickListener { presenter.onPrivacySelected() }
|
||||||
|
dialogAdsConsentBinding.adsConsentCancel.setOnClickListener { dialog.cancel() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openPrivacyPolicy() {
|
||||||
|
openInternetBrowser(
|
||||||
|
"https://wulkanowy.github.io/polityka-prywatnosci.html",
|
||||||
|
::showMessage
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
navController.onSaveInstanceState(outState)
|
navController.onSaveInstanceState(outState)
|
||||||
|
@ -18,7 +18,10 @@ import io.github.wulkanowy.ui.modules.grade.GradeView
|
|||||||
import io.github.wulkanowy.ui.modules.message.MessageView
|
import io.github.wulkanowy.ui.modules.message.MessageView
|
||||||
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersView
|
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersView
|
||||||
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
|
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
|
||||||
|
import io.github.wulkanowy.utils.AdsHelper
|
||||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||||
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -29,10 +32,12 @@ import javax.inject.Inject
|
|||||||
class MainPresenter @Inject constructor(
|
class MainPresenter @Inject constructor(
|
||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val prefRepository: PreferencesRepository,
|
private val preferencesRepository: PreferencesRepository,
|
||||||
private val syncManager: SyncManager,
|
private val syncManager: SyncManager,
|
||||||
private val analytics: AnalyticsHelper,
|
private val analytics: AnalyticsHelper,
|
||||||
private val json: Json
|
private val json: Json,
|
||||||
|
private val adsHelper: AdsHelper,
|
||||||
|
private val appInfo: AppInfo
|
||||||
) : BasePresenter<MainView>(errorHandler, studentRepository) {
|
) : BasePresenter<MainView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
private var studentsWitSemesters: List<StudentWithSemesters>? = null
|
private var studentsWitSemesters: List<StudentWithSemesters>? = null
|
||||||
@ -47,7 +52,7 @@ class MainPresenter @Inject constructor(
|
|||||||
|
|
||||||
private val Destination?.startMenuIndex
|
private val Destination?.startMenuIndex
|
||||||
get() = when {
|
get() = when {
|
||||||
this == null -> prefRepository.startMenuIndex
|
this == null -> preferencesRepository.startMenuIndex
|
||||||
destinationType in rootDestinationTypeList -> {
|
destinationType in rootDestinationTypeList -> {
|
||||||
rootDestinationTypeList.indexOf(destinationType)
|
rootDestinationTypeList.indexOf(destinationType)
|
||||||
}
|
}
|
||||||
@ -71,6 +76,8 @@ class MainPresenter @Inject constructor(
|
|||||||
|
|
||||||
syncManager.startPeriodicSyncWorker()
|
syncManager.startPeriodicSyncWorker()
|
||||||
|
|
||||||
|
checkAppSupport()
|
||||||
|
|
||||||
analytics.logEvent("app_open", "destination" to initDestination.toString())
|
analytics.logEvent("app_open", "destination" to initDestination.toString())
|
||||||
Timber.i("Main view was initialized with $initDestination")
|
Timber.i("Main view was initialized with $initDestination")
|
||||||
}
|
}
|
||||||
@ -155,18 +162,52 @@ class MainPresenter @Inject constructor(
|
|||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkInAppReview() {
|
fun onEnableAdsSelected() {
|
||||||
prefRepository.inAppReviewCount++
|
view?.showPrivacyPolicyDialog()
|
||||||
|
|
||||||
if (prefRepository.inAppReviewDate == null) {
|
|
||||||
prefRepository.inAppReviewDate = Instant.now()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prefRepository.isAppReviewDone && prefRepository.inAppReviewCount >= 50 &&
|
fun onPrivacyAgree(isPersonalizedAds: Boolean) {
|
||||||
Instant.now().minus(Duration.ofDays(14)).isAfter(prefRepository.inAppReviewDate)
|
preferencesRepository.isAgreeToProcessData = true
|
||||||
|
preferencesRepository.isPersonalizedAdsEnabled = isPersonalizedAds
|
||||||
|
|
||||||
|
adsHelper.initialize()
|
||||||
|
|
||||||
|
preferencesRepository.isAdsEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onPrivacySelected() {
|
||||||
|
view?.openPrivacyPolicy()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkInAppReview() {
|
||||||
|
preferencesRepository.inAppReviewCount++
|
||||||
|
|
||||||
|
if (preferencesRepository.inAppReviewDate == null) {
|
||||||
|
preferencesRepository.inAppReviewDate = Instant.now()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preferencesRepository.isAppReviewDone && preferencesRepository.inAppReviewCount >= 50 &&
|
||||||
|
Instant.now().minus(Duration.ofDays(14)).isAfter(preferencesRepository.inAppReviewDate)
|
||||||
) {
|
) {
|
||||||
view?.showInAppReview()
|
view?.showInAppReview()
|
||||||
prefRepository.isAppReviewDone = true
|
preferencesRepository.isAppReviewDone = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkAppSupport() {
|
||||||
|
if (!preferencesRepository.isAppSupportShown && !preferencesRepository.isAdsEnabled
|
||||||
|
&& appInfo.buildFlavor == "play"
|
||||||
|
) {
|
||||||
|
presenterScope.launch {
|
||||||
|
val student = runCatching { studentRepository.getCurrentStudent(false) }
|
||||||
|
.onFailure { Timber.e(it) }
|
||||||
|
.getOrElse { return@launch }
|
||||||
|
|
||||||
|
if (Instant.now().minus(Duration.ofDays(28)).isAfter(student.registrationDate)) {
|
||||||
|
view?.showAppSupport()
|
||||||
|
preferencesRepository.isAppSupportShown = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,12 @@ interface MainView : BaseView {
|
|||||||
|
|
||||||
fun showInAppReview()
|
fun showInAppReview()
|
||||||
|
|
||||||
|
fun showAppSupport()
|
||||||
|
|
||||||
|
fun showPrivacyPolicyDialog()
|
||||||
|
|
||||||
|
fun openPrivacyPolicy()
|
||||||
|
|
||||||
fun openMoreDestination(destination: Destination)
|
fun openMoreDestination(destination: Destination)
|
||||||
|
|
||||||
interface MainChildView {
|
interface MainChildView {
|
||||||
|
@ -4,6 +4,8 @@ import android.annotation.SuppressLint
|
|||||||
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.core.text.HtmlCompat.FROM_HTML_MODE_COMPACT
|
||||||
|
import androidx.core.text.parseAsHtml
|
||||||
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.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
@ -75,29 +77,25 @@ class MessagePreviewAdapter @Inject constructor() :
|
|||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
private fun bindMessage(holder: MessageViewHolder, message: Message) {
|
private fun bindMessage(holder: MessageViewHolder, message: Message) {
|
||||||
val context = holder.binding.root.context
|
val context = holder.binding.root.context
|
||||||
val recipientCount = message.unreadBy + message.readBy
|
|
||||||
|
|
||||||
val readText = when {
|
val readTextValue = when {
|
||||||
recipientCount > 1 -> {
|
!message.unread -> R.string.all_yes
|
||||||
context.getString(R.string.message_read_by, message.readBy, recipientCount)
|
else -> R.string.all_no
|
||||||
}
|
|
||||||
message.readBy == 1 -> {
|
|
||||||
context.getString(R.string.message_read, context.getString(R.string.all_yes))
|
|
||||||
}
|
|
||||||
else -> context.getString(R.string.message_read, context.getString(R.string.all_no))
|
|
||||||
}
|
}
|
||||||
|
val readText = context.getString(R.string.message_read, context.getString(readTextValue))
|
||||||
|
|
||||||
with(holder.binding) {
|
with(holder.binding) {
|
||||||
messagePreviewSubject.text =
|
messagePreviewSubject.text = message.subject.ifBlank {
|
||||||
message.subject.ifBlank { root.context.getString(R.string.message_no_subject) }
|
context.getString(R.string.message_no_subject)
|
||||||
messagePreviewDate.text = root.context.getString(
|
}
|
||||||
|
messagePreviewDate.text = context.getString(
|
||||||
R.string.message_date,
|
R.string.message_date,
|
||||||
message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")
|
message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")
|
||||||
)
|
)
|
||||||
messagePreviewRead.text = readText
|
messagePreviewRead.text = readText
|
||||||
messagePreviewContent.text = message.content
|
messagePreviewContent.text = message.content.parseAsHtml(FROM_HTML_MODE_COMPACT)
|
||||||
messagePreviewFromSender.text = message.sender
|
messagePreviewFromSender.text = message.sender
|
||||||
messagePreviewToRecipient.text = message.recipient
|
messagePreviewToRecipient.text = message.recipients
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,8 @@ class MessagePreviewFragment :
|
|||||||
get() = getString(R.string.message_no_subject)
|
get() = getString(R.string.message_no_subject)
|
||||||
|
|
||||||
override val printHTML: String
|
override val printHTML: String
|
||||||
get() = requireContext().assets.open("message-print-page.html").bufferedReader().use { it.readText() }
|
get() = requireContext().assets.open("message-print-page.html").bufferedReader()
|
||||||
|
.use { it.readText() }
|
||||||
|
|
||||||
override val messageNotExists: String
|
override val messageNotExists: String
|
||||||
get() = getString(R.string.message_not_exists)
|
get() = getString(R.string.message_not_exists)
|
||||||
@ -81,7 +82,10 @@ class MessagePreviewFragment :
|
|||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding = FragmentMessagePreviewBinding.bind(view)
|
binding = FragmentMessagePreviewBinding.bind(view)
|
||||||
messageContainer = binding.messagePreviewContainer
|
messageContainer = binding.messagePreviewContainer
|
||||||
presenter.onAttachView(this, (savedInstanceState ?: arguments)?.getSerializable(MESSAGE_ID_KEY) as? Message)
|
presenter.onAttachView(
|
||||||
|
this,
|
||||||
|
(savedInstanceState ?: arguments)?.getSerializable(MESSAGE_ID_KEY) as? Message
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initView() {
|
override fun initView() {
|
||||||
@ -101,6 +105,8 @@ class MessagePreviewFragment :
|
|||||||
menuShareButton = menu.findItem(R.id.messagePreviewMenuShare)
|
menuShareButton = menu.findItem(R.id.messagePreviewMenuShare)
|
||||||
menuPrintButton = menu.findItem(R.id.messagePreviewMenuPrint)
|
menuPrintButton = menu.findItem(R.id.messagePreviewMenuPrint)
|
||||||
presenter.onCreateOptionsMenu()
|
presenter.onCreateOptionsMenu()
|
||||||
|
|
||||||
|
menu.findItem(R.id.mainMenuAccount).isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
@ -129,8 +135,8 @@ class MessagePreviewFragment :
|
|||||||
binding.messagePreviewRecycler.visibility = if (show) VISIBLE else GONE
|
binding.messagePreviewRecycler.visibility = if (show) VISIBLE else GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showOptions(show: Boolean) {
|
override fun showOptions(show: Boolean, isReplayable: Boolean) {
|
||||||
menuReplyButton?.isVisible = show
|
menuReplyButton?.isVisible = isReplayable
|
||||||
menuForwardButton?.isVisible = show
|
menuForwardButton?.isVisible = show
|
||||||
menuDeleteButton?.isVisible = show
|
menuDeleteButton?.isVisible = show
|
||||||
menuShareButton?.isVisible = show
|
menuShareButton?.isVisible = show
|
||||||
@ -173,7 +179,8 @@ class MessagePreviewFragment :
|
|||||||
val webView = WebView(requireContext())
|
val webView = WebView(requireContext())
|
||||||
webView.webViewClient = object : WebViewClient() {
|
webView.webViewClient = object : WebViewClient() {
|
||||||
|
|
||||||
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest) = false
|
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest) =
|
||||||
|
false
|
||||||
|
|
||||||
override fun onPageFinished(view: WebView, url: String) {
|
override fun onPageFinished(view: WebView, url: String) {
|
||||||
createWebPrintJob(view, jobName)
|
createWebPrintJob(view, jobName)
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package io.github.wulkanowy.ui.modules.message.preview
|
package io.github.wulkanowy.ui.modules.message.preview
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import androidx.core.text.parseAsHtml
|
||||||
import io.github.wulkanowy.data.*
|
import io.github.wulkanowy.data.*
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
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.enums.MessageFolder
|
import io.github.wulkanowy.data.enums.MessageFolder
|
||||||
|
import io.github.wulkanowy.data.repositories.MailboxRepository
|
||||||
import io.github.wulkanowy.data.repositories.MessageRepository
|
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||||
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
|
||||||
@ -19,6 +21,7 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val messageRepository: MessageRepository,
|
private val messageRepository: MessageRepository,
|
||||||
|
private val mailboxRepository: MailboxRepository,
|
||||||
private val analytics: AnalyticsHelper
|
private val analytics: AnalyticsHelper
|
||||||
) : BasePresenter<MessagePreviewView>(errorHandler, studentRepository) {
|
) : BasePresenter<MessagePreviewView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
@ -52,7 +55,7 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
|
|
||||||
private fun loadData(messageToLoad: Message) {
|
private fun loadData(messageToLoad: Message) {
|
||||||
flatResourceFlow {
|
flatResourceFlow {
|
||||||
val student = studentRepository.getStudentById(messageToLoad.studentId)
|
val student = studentRepository.getCurrentStudent()
|
||||||
messageRepository.getMessage(student, messageToLoad, true)
|
messageRepository.getMessage(student, messageToLoad, true)
|
||||||
}
|
}
|
||||||
.logResourceStatus("message ${messageToLoad.messageId} preview")
|
.logResourceStatus("message ${messageToLoad.messageId} preview")
|
||||||
@ -104,63 +107,70 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onShare(): Boolean {
|
fun onShare(): Boolean {
|
||||||
message?.let {
|
val message = message ?: return false
|
||||||
var text =
|
val subject = message.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }
|
||||||
"Temat: ${it.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }}\n" + when (it.sender.isNotEmpty()) {
|
|
||||||
true -> "Od: ${it.sender}\n"
|
|
||||||
false -> "Do: ${it.recipient}\n"
|
|
||||||
} + "Data: ${it.date.toFormattedString("yyyy-MM-dd HH:mm:ss")}\n\n${it.content}"
|
|
||||||
|
|
||||||
attachments?.let { attachments ->
|
val text = buildString {
|
||||||
if (attachments.isNotEmpty()) {
|
appendLine("Temat: $subject")
|
||||||
text += "\n\nZałączniki:"
|
appendLine("Od: ${message.sender}")
|
||||||
|
appendLine("Do: ${message.recipients}")
|
||||||
|
appendLine("Data: ${message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")}")
|
||||||
|
|
||||||
attachments.forEach { attachment ->
|
appendLine()
|
||||||
text += "\n${attachment.filename}: ${attachment.url}"
|
|
||||||
}
|
appendLine(message.content.parseAsHtml())
|
||||||
|
|
||||||
|
if (!attachments.isNullOrEmpty()) {
|
||||||
|
appendLine()
|
||||||
|
appendLine("Załączniki:")
|
||||||
|
|
||||||
|
append(attachments.orEmpty().joinToString(separator = "\n") { attachment ->
|
||||||
|
"${attachment.filename}: ${attachment.url}"
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
view?.shareText(
|
view?.shareText(
|
||||||
text,
|
subject = "FW: $subject",
|
||||||
"FW: ${it.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }}"
|
text = text,
|
||||||
)
|
)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
fun onPrint(): Boolean {
|
fun onPrint(): Boolean {
|
||||||
message?.let {
|
val message = message ?: return false
|
||||||
val dateString = it.date.toFormattedString("yyyy-MM-dd HH:mm:ss")
|
val subject = message.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }
|
||||||
val infoContent = "<div><h4>Data wysłania</h4>$dateString</div>" + when {
|
|
||||||
it.sender.isNotEmpty() -> "<div><h4>Od</h4>${it.sender}</div>"
|
|
||||||
else -> "<div><h4>Do</h4>${it.recipient}</div>"
|
|
||||||
}
|
|
||||||
|
|
||||||
val messageContent = "<p>${it.content}</p>"
|
val dateString = message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")
|
||||||
|
|
||||||
|
val infoContent = buildString {
|
||||||
|
append("<div><h4>Data wysłania</h4>$dateString</div>")
|
||||||
|
|
||||||
|
append("<div><h4>Od</h4>${message.sender}</div>")
|
||||||
|
append("<div><h4>DO</h4>${message.recipients}</div>")
|
||||||
|
}
|
||||||
|
val messageContent = "<p>${message.content}</p>"
|
||||||
.replace(Regex("[\\n\\r]{2,}"), "</p><p>")
|
.replace(Regex("[\\n\\r]{2,}"), "</p><p>")
|
||||||
.replace(Regex("[\\n\\r]"), "<br>")
|
.replace(Regex("[\\n\\r]"), "<br>")
|
||||||
|
|
||||||
val jobName = "Wiadomość " + when {
|
val jobName = buildString {
|
||||||
it.sender.isNotEmpty() -> "od ${it.sender}"
|
append("Wiadomość ")
|
||||||
else -> "do ${it.recipient}"
|
append("od ${message.correspondents}")
|
||||||
} + " $dateString: ${it.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }} | Wulkanowy"
|
append("do ${message.correspondents}")
|
||||||
|
append(" $dateString: $subject | Wulkanowy")
|
||||||
|
}
|
||||||
|
|
||||||
view?.apply {
|
view?.apply {
|
||||||
val html = printHTML
|
val html = printHTML
|
||||||
.replace(
|
.replace("%SUBJECT%", subject)
|
||||||
"%SUBJECT%",
|
|
||||||
it.subject.ifBlank { view?.messageNoSubjectString.orEmpty() })
|
|
||||||
.replace("%CONTENT%", messageContent)
|
.replace("%CONTENT%", messageContent)
|
||||||
.replace("%INFO%", infoContent)
|
.replace("%INFO%", infoContent)
|
||||||
printDocument(html, jobName)
|
printDocument(html, jobName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun deleteMessage() {
|
private fun deleteMessage() {
|
||||||
message ?: return
|
message ?: return
|
||||||
@ -168,16 +178,17 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
view?.run {
|
view?.run {
|
||||||
showContent(false)
|
showContent(false)
|
||||||
showProgress(true)
|
showProgress(true)
|
||||||
showOptions(false)
|
showOptions(show = false, isReplayable = false)
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
Timber.i("Delete message ${message?.id}")
|
Timber.i("Delete message ${message?.messageGlobalKey}")
|
||||||
|
|
||||||
presenterScope.launch {
|
presenterScope.launch {
|
||||||
runCatching {
|
runCatching {
|
||||||
val student = studentRepository.getCurrentStudent()
|
val student = studentRepository.getCurrentStudent(decryptPass = true)
|
||||||
messageRepository.deleteMessage(student, message!!)
|
val mailbox = mailboxRepository.getMailbox(student)
|
||||||
|
messageRepository.deleteMessage(student, mailbox, message!!)
|
||||||
}
|
}
|
||||||
.onFailure {
|
.onFailure {
|
||||||
retryCallback = { onMessageDelete() }
|
retryCallback = { onMessageDelete() }
|
||||||
@ -211,7 +222,10 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
|
|
||||||
private fun initOptions() {
|
private fun initOptions() {
|
||||||
view?.apply {
|
view?.apply {
|
||||||
showOptions(message != null)
|
showOptions(
|
||||||
|
show = message != null,
|
||||||
|
isReplayable = message?.folderId != MessageFolder.SENT.id,
|
||||||
|
)
|
||||||
message?.let {
|
message?.let {
|
||||||
when (it.folderId == MessageFolder.TRASHED.id) {
|
when (it.folderId == MessageFolder.TRASHED.id) {
|
||||||
true -> setDeletedOptionsLabels()
|
true -> setDeletedOptionsLabels()
|
||||||
|
@ -28,7 +28,7 @@ interface MessagePreviewView : BaseView {
|
|||||||
|
|
||||||
fun setErrorRetryCallback(callback: () -> Unit)
|
fun setErrorRetryCallback(callback: () -> Unit)
|
||||||
|
|
||||||
fun showOptions(show: Boolean)
|
fun showOptions(show: Boolean, isReplayable: Boolean)
|
||||||
|
|
||||||
fun setDeletedOptionsLabels()
|
fun setDeletedOptionsLabels()
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.text.Spanned
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.TouchDelegate
|
import android.view.TouchDelegate
|
||||||
@ -13,11 +14,12 @@ import android.view.View.GONE
|
|||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import android.widget.Toast.LENGTH_LONG
|
import android.widget.Toast.LENGTH_LONG
|
||||||
|
import androidx.core.text.parseAsHtml
|
||||||
|
import androidx.core.text.toHtml
|
||||||
import androidx.core.widget.doOnTextChanged
|
import androidx.core.widget.doOnTextChanged
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
|
||||||
import io.github.wulkanowy.databinding.ActivitySendMessageBinding
|
import io.github.wulkanowy.databinding.ActivitySendMessageBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
import io.github.wulkanowy.utils.dpToPx
|
import io.github.wulkanowy.utils.dpToPx
|
||||||
@ -72,17 +74,32 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter, ActivitySendMessa
|
|||||||
override val messageSuccess: String
|
override val messageSuccess: String
|
||||||
get() = getString(R.string.message_send_successful)
|
get() = getString(R.string.message_send_successful)
|
||||||
|
|
||||||
|
override val mailboxStudent: String
|
||||||
|
get() = getString(R.string.message_mailbox_type_student)
|
||||||
|
|
||||||
|
override val mailboxParent: String
|
||||||
|
get() = getString(R.string.message_mailbox_type_parent)
|
||||||
|
|
||||||
|
override val mailboxGuardian: String
|
||||||
|
get() = getString(R.string.message_mailbox_type_guardian)
|
||||||
|
|
||||||
|
override val mailboxEmployee: String
|
||||||
|
get() = getString(R.string.message_mailbox_type_employee)
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(ActivitySendMessageBinding.inflate(layoutInflater).apply { binding = this }.root)
|
setContentView(
|
||||||
|
ActivitySendMessageBinding.inflate(layoutInflater).apply { binding = this }.root
|
||||||
|
)
|
||||||
setSupportActionBar(binding.sendMessageToolbar)
|
setSupportActionBar(binding.sendMessageToolbar)
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
messageContainer = binding.sendMessageContainer
|
messageContainer = binding.sendMessageContainer
|
||||||
|
|
||||||
formRecipientsData = binding.sendMessageTo.addedChipItems as List<RecipientChipItem>
|
formRecipientsData = binding.sendMessageTo.addedChipItems as List<RecipientChipItem>
|
||||||
formSubjectValue = binding.sendMessageSubject.text.toString()
|
formSubjectValue = binding.sendMessageSubject.text.toString()
|
||||||
formContentValue = binding.sendMessageMessageContent.text.toString()
|
formContentValue =
|
||||||
|
binding.sendMessageMessageContent.text.toString().parseAsHtml().toString()
|
||||||
|
|
||||||
presenter.onAttachView(
|
presenter.onAttachView(
|
||||||
view = this,
|
view = this,
|
||||||
@ -110,7 +127,7 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter, ActivitySendMessa
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onMessageContentChange(text: CharSequence?) {
|
private fun onMessageContentChange(text: CharSequence?) {
|
||||||
formContentValue = text.toString()
|
formContentValue = (text as Spanned).toHtml()
|
||||||
presenter.onMessageContentChange()
|
presenter.onMessageContentChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,8 +149,8 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter, ActivitySendMessa
|
|||||||
return presenter.onUpNavigate()
|
return presenter.onUpNavigate()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setReportingUnit(unit: ReportingUnit) {
|
override fun setMailbox(mailbox: String) {
|
||||||
binding.sendMessageFrom.text = unit.senderName
|
binding.sendMessageFrom.text = mailbox
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setRecipients(recipients: List<RecipientChipItem>) {
|
override fun setRecipients(recipients: List<RecipientChipItem>) {
|
||||||
@ -165,7 +182,7 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter, ActivitySendMessa
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun setContent(content: String) {
|
override fun setContent(content: String) {
|
||||||
binding.sendMessageMessageContent.setText(content)
|
binding.sendMessageMessageContent.setText(content.parseAsHtml())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showMessage(text: String) {
|
override fun showMessage(text: String) {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package io.github.wulkanowy.ui.modules.message.send
|
package io.github.wulkanowy.ui.modules.message.send
|
||||||
|
|
||||||
import io.github.wulkanowy.data.Resource
|
import io.github.wulkanowy.data.Resource
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
import io.github.wulkanowy.data.db.entities.MailboxType
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
import io.github.wulkanowy.data.logResourceStatus
|
import io.github.wulkanowy.data.logResourceStatus
|
||||||
@ -25,9 +27,8 @@ import javax.inject.Inject
|
|||||||
class SendMessagePresenter @Inject constructor(
|
class SendMessagePresenter @Inject constructor(
|
||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val semesterRepository: SemesterRepository,
|
|
||||||
private val messageRepository: MessageRepository,
|
private val messageRepository: MessageRepository,
|
||||||
private val reportingUnitRepository: ReportingUnitRepository,
|
private val mailboxRepository: MailboxRepository,
|
||||||
private val recipientRepository: RecipientRepository,
|
private val recipientRepository: RecipientRepository,
|
||||||
private val preferencesRepository: PreferencesRepository,
|
private val preferencesRepository: PreferencesRepository,
|
||||||
private val analytics: AnalyticsHelper
|
private val analytics: AnalyticsHelper
|
||||||
@ -52,20 +53,21 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
message?.let {
|
message?.let {
|
||||||
setSubject(
|
setSubject(
|
||||||
when (reply) {
|
when (reply) {
|
||||||
true -> "Re: "
|
true -> "RE: "
|
||||||
else -> "FW: "
|
else -> "FW: "
|
||||||
} + message.subject
|
} + message.subject
|
||||||
)
|
)
|
||||||
if (preferencesRepository.fillMessageContent || reply != true) {
|
if (preferencesRepository.fillMessageContent || reply != true) {
|
||||||
setContent(
|
setContent(buildString {
|
||||||
when (reply) {
|
if (reply == true) {
|
||||||
true -> "\n\n"
|
append("<br><br>")
|
||||||
else -> ""
|
}
|
||||||
} + when (message.sender.isNotEmpty()) {
|
|
||||||
true -> "Od: ${message.sender}\n"
|
append("Od: ${message.sender}<br>")
|
||||||
false -> "Do: ${message.recipient}\n"
|
append("Do: ${message.recipients}<br>")
|
||||||
} + "Data: ${message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")}\n\n${message.content}"
|
append("Data: ${message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")}<br><br>")
|
||||||
)
|
append(message.content)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,21 +113,24 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
private fun loadData(message: Message?, reply: Boolean?) {
|
private fun loadData(message: Message?, reply: Boolean?) {
|
||||||
resourceFlow {
|
resourceFlow {
|
||||||
val student = studentRepository.getCurrentStudent()
|
val student = studentRepository.getCurrentStudent()
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val mailbox = mailboxRepository.getMailbox(student)
|
||||||
val unit = reportingUnitRepository.getReportingUnit(student, semester.unitId)
|
|
||||||
|
|
||||||
Timber.i("Loading recipients started")
|
Timber.i("Loading recipients started")
|
||||||
val recipients = when {
|
val recipients = createChips(
|
||||||
unit != null -> recipientRepository.getRecipients(student, unit, 2)
|
recipients = recipientRepository.getRecipients(
|
||||||
else -> listOf()
|
student = student,
|
||||||
}.let { createChips(it) }
|
mailbox = mailbox,
|
||||||
|
type = MailboxType.EMPLOYEE,
|
||||||
|
)
|
||||||
|
)
|
||||||
Timber.i("Loading recipients result: Success, fetched %d recipients", recipients.size)
|
Timber.i("Loading recipients result: Success, fetched %d recipients", recipients.size)
|
||||||
|
|
||||||
Timber.i("Loading message recipients started")
|
Timber.i("Loading message recipients started")
|
||||||
val messageRecipients = when {
|
val messageRecipients = when {
|
||||||
message != null && reply == true -> recipientRepository.getMessageRecipients(
|
message != null && reply == true -> recipientRepository.getMessageSender(
|
||||||
student,
|
student = student,
|
||||||
message
|
message = message,
|
||||||
|
mailbox = mailbox,
|
||||||
)
|
)
|
||||||
else -> emptyList()
|
else -> emptyList()
|
||||||
}.let { createChips(it) }
|
}.let { createChips(it) }
|
||||||
@ -134,7 +139,7 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
messageRecipients.size
|
messageRecipients.size
|
||||||
)
|
)
|
||||||
|
|
||||||
Triple(unit, recipients, messageRecipients)
|
Triple(mailbox, recipients, messageRecipients)
|
||||||
}
|
}
|
||||||
.logResourceStatus("load recipients")
|
.logResourceStatus("load recipients")
|
||||||
.onEach {
|
.onEach {
|
||||||
@ -143,19 +148,14 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
showProgress(true)
|
showProgress(true)
|
||||||
showContent(false)
|
showContent(false)
|
||||||
}
|
}
|
||||||
is Resource.Success -> it.data.let { (reportingUnit, recipientChips, selectedRecipientChips) ->
|
is Resource.Success -> it.data.let { (mailbox, recipientChips, selectedRecipientChips) ->
|
||||||
view?.run {
|
view?.run {
|
||||||
if (reportingUnit != null) {
|
setMailbox(getMailboxName(mailbox))
|
||||||
setReportingUnit(reportingUnit)
|
|
||||||
setRecipients(recipientChips)
|
setRecipients(recipientChips)
|
||||||
if (selectedRecipientChips.isNotEmpty()) setSelectedRecipients(
|
if (selectedRecipientChips.isNotEmpty()) setSelectedRecipients(
|
||||||
selectedRecipientChips
|
selectedRecipientChips
|
||||||
)
|
)
|
||||||
showContent(true)
|
showContent(true)
|
||||||
} else {
|
|
||||||
Timber.i("Loading recipients result: Can't find the reporting unit")
|
|
||||||
view?.showEmpty(true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Resource.Error -> {
|
is Resource.Error -> {
|
||||||
@ -171,7 +171,14 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
private fun sendMessage(subject: String, content: String, recipients: List<Recipient>) {
|
private fun sendMessage(subject: String, content: String, recipients: List<Recipient>) {
|
||||||
resourceFlow {
|
resourceFlow {
|
||||||
val student = studentRepository.getCurrentStudent()
|
val student = studentRepository.getCurrentStudent()
|
||||||
messageRepository.sendMessage(student, subject, content, recipients)
|
val mailbox = mailboxRepository.getMailbox(student)
|
||||||
|
messageRepository.sendMessage(
|
||||||
|
student = student,
|
||||||
|
subject = subject,
|
||||||
|
content = content,
|
||||||
|
recipients = recipients,
|
||||||
|
mailboxId = mailbox.globalKey,
|
||||||
|
)
|
||||||
}.logResourceStatus("sending message").onEach {
|
}.logResourceStatus("sending message").onEach {
|
||||||
when (it) {
|
when (it) {
|
||||||
is Resource.Loading -> view?.run {
|
is Resource.Loading -> view?.run {
|
||||||
@ -201,31 +208,44 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createChips(recipients: List<Recipient>): List<RecipientChipItem> {
|
private fun createChips(recipients: List<Recipient>): List<RecipientChipItem> {
|
||||||
fun generateCorrectSummary(recipientRealName: String): String {
|
|
||||||
val substring = recipientRealName.substringBeforeLast("-")
|
|
||||||
return when {
|
|
||||||
substring == recipientRealName -> recipientRealName
|
|
||||||
substring.indexOf("(") != -1 -> {
|
|
||||||
recipientRealName.indexOf("(")
|
|
||||||
.let { recipientRealName.substring(if (it != -1) it else 0) }
|
|
||||||
}
|
|
||||||
substring.indexOf("[") != -1 -> {
|
|
||||||
recipientRealName.indexOf("[")
|
|
||||||
.let { recipientRealName.substring(if (it != -1) it else 0) }
|
|
||||||
}
|
|
||||||
else -> recipientRealName.substringAfter("-")
|
|
||||||
}.trim()
|
|
||||||
}
|
|
||||||
|
|
||||||
return recipients.map {
|
return recipients.map {
|
||||||
RecipientChipItem(
|
RecipientChipItem(
|
||||||
title = it.name,
|
title = it.userName,
|
||||||
summary = generateCorrectSummary(it.realName),
|
summary = buildString {
|
||||||
|
getMailboxType(it.type)?.let(::append)
|
||||||
|
if (isNotBlank()) append(" ")
|
||||||
|
|
||||||
|
append("(${it.schoolShortName})")
|
||||||
|
},
|
||||||
recipient = it
|
recipient = it
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getMailboxName(mailbox: Mailbox): String {
|
||||||
|
return buildString {
|
||||||
|
append(mailbox.userName)
|
||||||
|
append(" - ")
|
||||||
|
append(getMailboxType(mailbox.type))
|
||||||
|
|
||||||
|
if (mailbox.type == MailboxType.PARENT) {
|
||||||
|
append(" - ")
|
||||||
|
append(mailbox.studentName)
|
||||||
|
}
|
||||||
|
|
||||||
|
append(" - ")
|
||||||
|
append("(${mailbox.schoolNameShort})")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMailboxType(type: MailboxType): String? = when (type) {
|
||||||
|
MailboxType.STUDENT -> view?.mailboxStudent
|
||||||
|
MailboxType.PARENT -> view?.mailboxParent
|
||||||
|
MailboxType.GUARDIAN -> view?.mailboxGuardian
|
||||||
|
MailboxType.EMPLOYEE -> view?.mailboxEmployee
|
||||||
|
MailboxType.UNKNOWN -> null
|
||||||
|
}
|
||||||
|
|
||||||
fun onMessageContentChange() {
|
fun onMessageContentChange() {
|
||||||
presenterScope.launch {
|
presenterScope.launch {
|
||||||
messageUpdateChannel.send(Unit)
|
messageUpdateChannel.send(Unit)
|
||||||
@ -263,7 +283,7 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
|
|
||||||
fun getRecipientsNames(): String {
|
fun getRecipientsNames(): String {
|
||||||
return messageRepository.draftMessage?.recipients.orEmpty()
|
return messageRepository.draftMessage?.recipients.orEmpty()
|
||||||
.joinToString { it.recipient.name }
|
.joinToString { it.recipient.userName }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearDraft() {
|
fun clearDraft() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package io.github.wulkanowy.ui.modules.message.send
|
package io.github.wulkanowy.ui.modules.message.send
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
import io.github.wulkanowy.ui.base.BaseView
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
interface SendMessageView : BaseView {
|
interface SendMessageView : BaseView {
|
||||||
@ -18,9 +18,17 @@ interface SendMessageView : BaseView {
|
|||||||
|
|
||||||
val messageSuccess: String
|
val messageSuccess: String
|
||||||
|
|
||||||
|
val mailboxStudent: String
|
||||||
|
|
||||||
|
val mailboxParent: String
|
||||||
|
|
||||||
|
val mailboxGuardian: String
|
||||||
|
|
||||||
|
val mailboxEmployee: String
|
||||||
|
|
||||||
fun initView()
|
fun initView()
|
||||||
|
|
||||||
fun setReportingUnit(unit: ReportingUnit)
|
fun setMailbox(mailbox: String)
|
||||||
|
|
||||||
fun setRecipients(recipients: List<RecipientChipItem>)
|
fun setRecipients(recipients: List<RecipientChipItem>)
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ import androidx.core.view.isVisible
|
|||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
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.enums.MessageFolder
|
|
||||||
import io.github.wulkanowy.databinding.ItemMessageBinding
|
import io.github.wulkanowy.databinding.ItemMessageBinding
|
||||||
import io.github.wulkanowy.databinding.ItemMessageChipsBinding
|
import io.github.wulkanowy.databinding.ItemMessageChipsBinding
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
@ -88,12 +87,8 @@ class MessageTabAdapter @Inject constructor() :
|
|||||||
with(holder.binding) {
|
with(holder.binding) {
|
||||||
val style = if (message.unread) Typeface.BOLD else Typeface.NORMAL
|
val style = if (message.unread) Typeface.BOLD else Typeface.NORMAL
|
||||||
|
|
||||||
messageItemAuthor.run {
|
with(messageItemAuthor) {
|
||||||
text = if (message.folderId == MessageFolder.SENT.id) {
|
text = message.correspondents
|
||||||
message.recipient
|
|
||||||
} else {
|
|
||||||
message.sender
|
|
||||||
}
|
|
||||||
setTypeface(null, style)
|
setTypeface(null, style)
|
||||||
}
|
}
|
||||||
messageItemSubject.run {
|
messageItemSubject.run {
|
||||||
@ -145,7 +140,7 @@ class MessageTabAdapter @Inject constructor() :
|
|||||||
val newItem = new[newItemPosition]
|
val newItem = new[newItemPosition]
|
||||||
|
|
||||||
return if (oldItem is MessageTabDataItem.MessageItem && newItem is MessageTabDataItem.MessageItem) {
|
return if (oldItem is MessageTabDataItem.MessageItem && newItem is MessageTabDataItem.MessageItem) {
|
||||||
oldItem.message.id == newItem.message.id
|
oldItem.message.messageGlobalKey == newItem.message.messageGlobalKey
|
||||||
} else {
|
} else {
|
||||||
oldItem.viewType == newItem.viewType
|
oldItem.viewType == newItem.viewType
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ package io.github.wulkanowy.ui.modules.message.tab
|
|||||||
import io.github.wulkanowy.data.*
|
import io.github.wulkanowy.data.*
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder
|
import io.github.wulkanowy.data.enums.MessageFolder
|
||||||
|
import io.github.wulkanowy.data.repositories.MailboxRepository
|
||||||
import io.github.wulkanowy.data.repositories.MessageRepository
|
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
|
||||||
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
|
||||||
@ -26,7 +26,7 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val messageRepository: MessageRepository,
|
private val messageRepository: MessageRepository,
|
||||||
private val semesterRepository: SemesterRepository,
|
private val mailboxRepository: MailboxRepository,
|
||||||
private val analytics: AnalyticsHelper
|
private val analytics: AnalyticsHelper
|
||||||
) : BasePresenter<MessageTabView>(errorHandler, studentRepository) {
|
) : BasePresenter<MessageTabView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
@ -122,7 +122,8 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
|
|
||||||
runCatching {
|
runCatching {
|
||||||
val student = studentRepository.getCurrentStudent(true)
|
val student = studentRepository.getCurrentStudent(true)
|
||||||
messageRepository.deleteMessages(student, messageList)
|
val mailbox = mailboxRepository.getMailbox(student)
|
||||||
|
messageRepository.deleteMessages(student, mailbox, messageList)
|
||||||
}
|
}
|
||||||
.onFailure(errorHandler::dispatch)
|
.onFailure(errorHandler::dispatch)
|
||||||
.onSuccess { view?.showMessagesDeleted() }
|
.onSuccess { view?.showMessagesDeleted() }
|
||||||
@ -159,7 +160,7 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onMessageItemSelected(messageItem: MessageTabDataItem.MessageItem, position: Int) {
|
fun onMessageItemSelected(messageItem: MessageTabDataItem.MessageItem, position: Int) {
|
||||||
Timber.i("Select message ${messageItem.message.id} item (position: $position)")
|
Timber.i("Select message ${messageItem.message.messageGlobalKey} item (position: $position)")
|
||||||
|
|
||||||
if (!isActionMode) {
|
if (!isActionMode) {
|
||||||
view?.run {
|
view?.run {
|
||||||
@ -206,8 +207,8 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
|
|
||||||
flatResourceFlow {
|
flatResourceFlow {
|
||||||
val student = studentRepository.getCurrentStudent()
|
val student = studentRepository.getCurrentStudent()
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val mailbox = mailboxRepository.getMailbox(student)
|
||||||
messageRepository.getMessages(student, semester, folder, forceRefresh)
|
messageRepository.getMessages(student, mailbox, folder, forceRefresh)
|
||||||
}
|
}
|
||||||
.logResourceStatus("load $folder message")
|
.logResourceStatus("load $folder message")
|
||||||
.onResourceData {
|
.onResourceData {
|
||||||
@ -333,7 +334,7 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
addAll(data.map { message ->
|
addAll(data.map { message ->
|
||||||
MessageTabDataItem.MessageItem(
|
MessageTabDataItem.MessageItem(
|
||||||
message = message,
|
message = message,
|
||||||
isSelected = messagesToDelete.any { it.id == message.id },
|
isSelected = messagesToDelete.any { it.messageGlobalKey == message.messageGlobalKey },
|
||||||
isActionMode = isActionMode
|
isActionMode = isActionMode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -345,10 +346,9 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
private fun calculateMatchRatio(message: Message, query: String): Int {
|
private fun calculateMatchRatio(message: Message, query: String): Int {
|
||||||
val subjectRatio = FuzzySearch.tokenSortPartialRatio(query.lowercase(), message.subject)
|
val subjectRatio = FuzzySearch.tokenSortPartialRatio(query.lowercase(), message.subject)
|
||||||
|
|
||||||
val senderOrRecipientRatio = FuzzySearch.tokenSortPartialRatio(
|
val correspondentsRatio = FuzzySearch.tokenSortPartialRatio(
|
||||||
query.lowercase(),
|
query.lowercase(),
|
||||||
if (message.sender.isNotEmpty()) message.sender.lowercase()
|
message.correspondents
|
||||||
else message.recipient.lowercase()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val dateRatio = listOf(
|
val dateRatio = listOf(
|
||||||
@ -364,7 +364,7 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
|
|
||||||
|
|
||||||
return (subjectRatio.toDouble().pow(2)
|
return (subjectRatio.toDouble().pow(2)
|
||||||
+ senderOrRecipientRatio.toDouble().pow(2)
|
+ correspondentsRatio.toDouble().pow(2)
|
||||||
+ dateRatio.toDouble().pow(2) * 2
|
+ dateRatio.toDouble().pow(2) * 2
|
||||||
).toInt()
|
).toInt()
|
||||||
}
|
}
|
||||||
|
@ -87,15 +87,19 @@ class TimetablePresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onViewReselected() {
|
fun onViewReselected() {
|
||||||
Timber.i("Timetable view is reselected")
|
Timber.i("Timetable view is reselected")
|
||||||
view?.also { view ->
|
view?.let { view ->
|
||||||
if (view.currentStackSize == 1) {
|
if (view.currentStackSize == 1) {
|
||||||
baseDate.also {
|
baseDate = now().nextOrSameSchoolDay
|
||||||
if (currentDate != it) {
|
|
||||||
reloadView(it)
|
if (currentDate != baseDate) {
|
||||||
|
reloadView(baseDate)
|
||||||
loadData()
|
loadData()
|
||||||
} else if (!view.isViewEmpty) view.resetView()
|
} else if (!view.isViewEmpty) {
|
||||||
|
view.resetView()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
view.popView()
|
||||||
}
|
}
|
||||||
} else view.popView()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package io.github.wulkanowy.ui.modules.timetablewidget
|
package io.github.wulkanowy.ui.modules.timetablewidget
|
||||||
|
|
||||||
import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
import android.appwidget.AppWidgetManager.*
|
||||||
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID
|
|
||||||
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@ -17,6 +15,7 @@ import io.github.wulkanowy.databinding.ActivityWidgetConfigureBinding
|
|||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
import io.github.wulkanowy.ui.base.WidgetConfigureAdapter
|
import io.github.wulkanowy.ui.base.WidgetConfigureAdapter
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.EXTRA_FROM_CONFIGURE
|
||||||
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.EXTRA_FROM_PROVIDER
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.EXTRA_FROM_PROVIDER
|
||||||
import io.github.wulkanowy.utils.AppInfo
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -92,6 +91,7 @@ class TimetableWidgetConfigureActivity :
|
|||||||
.apply {
|
.apply {
|
||||||
action = ACTION_APPWIDGET_UPDATE
|
action = ACTION_APPWIDGET_UPDATE
|
||||||
putExtra(EXTRA_APPWIDGET_IDS, intArrayOf(widgetId))
|
putExtra(EXTRA_APPWIDGET_IDS, intArrayOf(widgetId))
|
||||||
|
putExtra(EXTRA_FROM_CONFIGURE, true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.timetablewidget
|
package io.github.wulkanowy.ui.modules.timetablewidget
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.AppWidgetManager
|
||||||
import android.appwidget.AppWidgetManager.*
|
import android.appwidget.AppWidgetManager.*
|
||||||
@ -61,6 +60,8 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
|||||||
|
|
||||||
private const val BUTTON_RESET = "buttonReset"
|
private const val BUTTON_RESET = "buttonReset"
|
||||||
|
|
||||||
|
const val EXTRA_FROM_CONFIGURE = "extraFromConfigure"
|
||||||
|
|
||||||
const val EXTRA_FROM_PROVIDER = "extraFromProvider"
|
const val EXTRA_FROM_PROVIDER = "extraFromProvider"
|
||||||
|
|
||||||
fun getDateWidgetKey(appWidgetId: Int) = "timetable_widget_date_$appWidgetId"
|
fun getDateWidgetKey(appWidgetId: Int) = "timetable_widget_date_$appWidgetId"
|
||||||
@ -87,12 +88,22 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun onUpdate(context: Context, intent: Intent) {
|
private suspend fun onUpdate(context: Context, intent: Intent) {
|
||||||
if (intent.getStringExtra(EXTRA_BUTTON_TYPE) === null) {
|
if (intent.getStringExtra(EXTRA_BUTTON_TYPE) == null) {
|
||||||
intent.getIntArrayExtra(EXTRA_APPWIDGET_IDS)?.forEach { appWidgetId ->
|
val isFromConfigure = intent.getBooleanExtra(EXTRA_FROM_CONFIGURE, false)
|
||||||
|
val appWidgetIds = intent.getIntArrayExtra(EXTRA_APPWIDGET_IDS) ?: return
|
||||||
|
|
||||||
|
appWidgetIds.forEach { appWidgetId ->
|
||||||
val student =
|
val student =
|
||||||
getStudent(sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0), appWidgetId)
|
getStudent(sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0), appWidgetId)
|
||||||
|
val savedDataEpochDay = sharedPref.getLong(getDateWidgetKey(appWidgetId), 0)
|
||||||
|
|
||||||
updateWidget(context, appWidgetId, getWidgetDateToLoad(appWidgetId), student)
|
val dateToLoad = if (isFromConfigure && savedDataEpochDay != 0L) {
|
||||||
|
LocalDate.ofEpochDay(savedDataEpochDay)
|
||||||
|
} else {
|
||||||
|
getWidgetDefaultDateToLoad(appWidgetId)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateWidget(context, appWidgetId, dateToLoad, student)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val buttonType = intent.getStringExtra(EXTRA_BUTTON_TYPE)
|
val buttonType = intent.getStringExtra(EXTRA_BUTTON_TYPE)
|
||||||
@ -104,10 +115,10 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
|||||||
val savedDate =
|
val savedDate =
|
||||||
LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(toggledWidgetId), 0))
|
LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(toggledWidgetId), 0))
|
||||||
val date = when (buttonType) {
|
val date = when (buttonType) {
|
||||||
BUTTON_RESET -> getWidgetDateToLoad(toggledWidgetId)
|
BUTTON_RESET -> getWidgetDefaultDateToLoad(toggledWidgetId)
|
||||||
BUTTON_NEXT -> savedDate.nextSchoolDay
|
BUTTON_NEXT -> savedDate.nextSchoolDay
|
||||||
BUTTON_PREV -> savedDate.previousSchoolDay
|
BUTTON_PREV -> savedDate.previousSchoolDay
|
||||||
else -> getWidgetDateToLoad(toggledWidgetId)
|
else -> getWidgetDefaultDateToLoad(toggledWidgetId)
|
||||||
}
|
}
|
||||||
if (!buttonType.isNullOrBlank()) {
|
if (!buttonType.isNullOrBlank()) {
|
||||||
analytics.logEvent(
|
analytics.logEvent(
|
||||||
@ -132,7 +143,6 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("DefaultLocale")
|
|
||||||
private fun updateWidget(
|
private fun updateWidget(
|
||||||
context: Context,
|
context: Context,
|
||||||
appWidgetId: Int,
|
appWidgetId: Int,
|
||||||
@ -273,7 +283,7 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
|||||||
return avatarBitmap
|
return avatarBitmap
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getWidgetDateToLoad(appWidgetId: Int): LocalDate {
|
private fun getWidgetDefaultDateToLoad(appWidgetId: Int): LocalDate {
|
||||||
val lastLessonEndTimestamp =
|
val lastLessonEndTimestamp =
|
||||||
sharedPref.getLong(getTodayLastLessonEndDateTimeWidgetKey(appWidgetId), 0)
|
sharedPref.getLong(getTodayLastLessonEndDateTimeWidgetKey(appWidgetId), 0)
|
||||||
val lastLessonEndDateTime =
|
val lastLessonEndDateTime =
|
||||||
|
@ -13,6 +13,7 @@ import androidx.core.graphics.drawable.RoundedBitmapDrawable
|
|||||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
|
|
||||||
|
|
||||||
@ColorInt
|
@ColorInt
|
||||||
fun Context.getThemeAttrColor(@AttrRes colorAttr: Int): Int {
|
fun Context.getThemeAttrColor(@AttrRes colorAttr: Int): Int {
|
||||||
val array = obtainStyledAttributes(null, intArrayOf(colorAttr))
|
val array = obtainStyledAttributes(null, intArrayOf(colorAttr))
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
Wersja 1.6.4
|
Wersja 1.7.0
|
||||||
|
|
||||||
- naprawiliśmy błąd ładowania frekwencji na GPE i Lubelskim Portalu Oświatowym
|
- naprawiliśmy logowanie do aplikacji
|
||||||
|
- dodaliśmy wsparcie nowego modułu Wiadomości Plus
|
||||||
|
- dodaliśmy nową możliwość wsparcia naszego projektu przez opcjonalne reklamy
|
||||||
|
- dodaliśmy sortowanie po średniej
|
||||||
|
- naprawiliśmy też kilka usterek wpływających na komfort używania aplikacji
|
||||||
|
|
||||||
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
||||||
|
@ -16,8 +16,7 @@
|
|||||||
app:layout_constraintBottom_toTopOf="@id/sendMessageScroll"
|
app:layout_constraintBottom_toTopOf="@id/sendMessageScroll"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
tools:targetApi="lollipop" />
|
|
||||||
|
|
||||||
<io.github.wulkanowy.materialchipsinput.ConsumedNestedScrollView
|
<io.github.wulkanowy.materialchipsinput.ConsumedNestedScrollView
|
||||||
android:id="@+id/sendMessageScroll"
|
android:id="@+id/sendMessageScroll"
|
||||||
|
79
app/src/main/res/layout/dialog_ads_consent.xml
Normal file
79
app/src/main/res/layout/dialog_ads_consent.xml
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/ads_consent_privacy"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:padding="0dp"
|
||||||
|
android:text="Privacy Policy"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/ads_consent_over"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="17dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="I am over 18 years old"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:textSize="14dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/ads_consent_privacy" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/ads_consent_personalised"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:enabled="false"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:text="Yes, personalized ads"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/ads_consent_over" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/ads_consent_non_personalised"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:layout_marginBottom="24dp"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:text="Yes, non-personalized ads"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/ads_consent_cancel"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/ads_consent_personalised"
|
||||||
|
app:layout_constraintVertical_bias="0" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/ads_consent_cancel"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:layout_marginBottom="24dp"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:text="Cancel"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -19,7 +19,9 @@
|
|||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/noteRecycler"
|
android:id="@+id/noteRecycler"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent"
|
||||||
|
tools:itemCount="4"
|
||||||
|
tools:listitem="@layout/item_note" />
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
android:padding="10dp"
|
android:padding="10dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:ignore="UseCompoundDrawables"
|
tools:ignore="UseCompoundDrawables"
|
||||||
tools:visibility="visible">
|
tools:visibility="gone">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="100dp"
|
android:layout_width="100dp"
|
||||||
@ -63,7 +63,7 @@
|
|||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
tools:ignore="UseCompoundDrawables"
|
tools:ignore="UseCompoundDrawables"
|
||||||
tools:visibility="visible">
|
tools:visibility="gone">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="100dp"
|
android:layout_width="100dp"
|
||||||
|
15
app/src/main/res/layout/item_dashboard_ads.xml
Normal file
15
app/src/main/res/layout/item_dashboard_ads.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="12dp"
|
||||||
|
android:layout_marginVertical="6dp"
|
||||||
|
app:cardElevation="4dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/dashboard_admin_message_item_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
@ -54,7 +54,7 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/noteItemPoints"
|
android:id="@+id/noteItemPoints"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
|
@ -3,10 +3,11 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="64dp"
|
android:layout_height="wrap_content"
|
||||||
android:background="?selectableItemBackground"
|
android:background="?selectableItemBackground"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true">
|
android:focusable="true"
|
||||||
|
android:minHeight="64dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/student_info_item_title"
|
android:id="@+id/student_info_item_title"
|
||||||
@ -16,12 +17,12 @@
|
|||||||
android:layout_marginTop="13dp"
|
android:layout_marginTop="13dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:gravity="bottom"
|
android:gravity="bottom"
|
||||||
android:maxLines="1"
|
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
app:layout_constraintEnd_toStartOf="@id/student_info_item_arrow"
|
app:layout_constraintEnd_toStartOf="@id/student_info_item_arrow"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:maxLines="1"
|
||||||
tools:text="@tools:sample/lorem/random" />
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -31,12 +32,12 @@
|
|||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:gravity="bottom"
|
android:gravity="bottom"
|
||||||
android:maxLines="1"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorPrimary"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
app:layout_constraintEnd_toStartOf="@id/student_info_item_arrow"
|
app:layout_constraintEnd_toStartOf="@id/student_info_item_arrow"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/student_info_item_title"
|
app:layout_constraintTop_toBottomOf="@id/student_info_item_title"
|
||||||
|
tools:maxLines="1"
|
||||||
tools:text="@tools:sample/lorem/random" />
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
<string-array name="grade_sorting_mode_entries">
|
<string-array name="grade_sorting_mode_entries">
|
||||||
<item>Abecedně</item>
|
<item>Abecedně</item>
|
||||||
<item>Podle data</item>
|
<item>Podle data</item>
|
||||||
|
<item>Podle průměru</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="grade_color_scheme_entries">
|
<string-array name="grade_color_scheme_entries">
|
||||||
<item>Dzienniczek+</item>
|
<item>Dzienniczek+</item>
|
||||||
|
@ -77,6 +77,9 @@
|
|||||||
<string name="main_log_in">Přihlásit se</string>
|
<string name="main_log_in">Přihlásit se</string>
|
||||||
<string name="main_session_expired">Relace vypršela</string>
|
<string name="main_session_expired">Relace vypršela</string>
|
||||||
<string name="main_session_relogin">Relace vypršela. Přihlaste se prosím znovu</string>
|
<string name="main_session_relogin">Relace vypršela. Přihlaste se prosím znovu</string>
|
||||||
|
<string name="main_support_title">Podpora aplikace</string>
|
||||||
|
<string name="main_support_description">Líbí se Vám tato aplikace? Podpořte její vývoj tím, že povolíte neinvazivní reklamy, které můžete kdykoliv vypnout</string>
|
||||||
|
<string name="main_support_positive">Zapnout reklamy</string>
|
||||||
<!--Grade-->
|
<!--Grade-->
|
||||||
<string name="grade_header">Známka</string>
|
<string name="grade_header">Známka</string>
|
||||||
<string name="grade_semester">Semestr %d</string>
|
<string name="grade_semester">Semestr %d</string>
|
||||||
@ -94,7 +97,7 @@
|
|||||||
<string name="grade_summary_predicted_grade">Předpokládaná známka</string>
|
<string name="grade_summary_predicted_grade">Předpokládaná známka</string>
|
||||||
<string name="grade_summary_calculated_average">Vypočítaný průměr</string>
|
<string name="grade_summary_calculated_average">Vypočítaný průměr</string>
|
||||||
<string name="grade_summary_calculated_average_help_dialog_title">Jak funguje vypočítaný průměr?</string>
|
<string name="grade_summary_calculated_average_help_dialog_title">Jak funguje vypočítaný průměr?</string>
|
||||||
<string name="grade_summary_calculated_average_help_dialog_message">Vypočítaný průměr je aritmetický průměr vypočítaný z průměrů předmětů. Umožňuje vám to znát přibližný konečný průměr. Vypočítává se způsobem zvoleným uživatelem v nastavení aplikaci. Doporučuje se vybrat příslušnou možnost. Důvodem je rozdílný výpočet školních průměrů. Pokud vaše škola navíc uvádí průměr předmětů na stránce deníku Vulcan, aplikace si je stáhne a tyto průměry nepočítá. To lze změnit vynucením výpočtu průměru v nastavení aplikaci.\n\n<b>Průměr známek pouze z vybraného semestru</b>:\n1. Výpočet váženého průměru pro každý předmět v daném semestru\n2. Sčítání vypočítaných průměrů\n3. Výpočet aritmetického průměru součtených průměrů\n\n<b>Průměr průměrů z obou semestrů</b>:\n1. Výpočet váženého průměru pro každý předmět v semestru 1 a 2\n2. Výpočet aritmetického průměru vypočítaných průměrů za semestry 1 a 2 pro každý předmět.\n3. Sčítání vypočítaných průměrů\n4. Výpočet aritmetického průměru sečtených průměrů\n\n<b>Průměr známek z celého roku:</b>\n1. Výpočet váženého průměru za rok pro každý předmět. Konečný průměr v 1. semestru je nepodstatný.\n3. Sčítání vypočítaných průměrů\n4. Výpočet aritmetického průměru součtených průměrů</string>
|
<string name="grade_summary_calculated_average_help_dialog_message">Vypočítaný průměr je aritmetický průměr vypočítaný z průměrů předmětů. Umožňuje vám to znát přibližný konečný průměr. Vypočítává se způsobem zvoleným uživatelem v nastavení aplikaci. Doporučuje se vybrat příslušnou možnost. Důvodem je rozdílný výpočet školních průměrů. Pokud vaše škola navíc uvádí průměr předmětů na stránce deníku Vulcan, aplikace si je stáhne a tyto průměry nepočítá. To lze změnit vynucením výpočtu průměru v nastavení aplikaci.\n\n<b>Průměr známek pouze z vybraného semestru</b>:\n1. Výpočet váženého průměru pro každý předmět v daném semestru\n2. Sčítání vypočítaných průměrů\n3. Výpočet aritmetického průměru součtených průměrů\n\n<b>Průměr průměrů z obou semestrů</b>:\n1. Výpočet váženého průměru pro každý předmět v semestru 1 a 2\n2. Výpočet aritmetického průměru vypočítaných průměrů za semestry 1 a 2 pro každý předmět.\n3. Sčítání vypočítaných průměrů\n4. Výpočet aritmetického průměru sečtených průměrů\n\n<b>Průměr známek z celého roku:</b>\n1. Výpočet váženého průměru za rok pro každý předmět. Konečný průměr v 1. semestru je nepodstatný.\n2. Sčítání vypočítaných průměrů\n3. Výpočet aritmetického průměru součtených průměrů</string>
|
||||||
<string name="grade_summary_final_average_help_dialog_title">Jak funguje konečný průměr?</string>
|
<string name="grade_summary_final_average_help_dialog_title">Jak funguje konečný průměr?</string>
|
||||||
<string name="grade_summary_final_average_help_dialog_message">Konečný průměr je aritmetický průměr vypočítaný ze všech aktuálně dostupných konečných známek v daném semestru.\n\nSchéma výpočtu se skládá z následujících kroků:\n1. Sčítání konečných známek zadaných učiteli\n2. Děleno počtem předmětů, pro které už byly uděleny známky</string>
|
<string name="grade_summary_final_average_help_dialog_message">Konečný průměr je aritmetický průměr vypočítaný ze všech aktuálně dostupných konečných známek v daném semestru.\n\nSchéma výpočtu se skládá z následujících kroků:\n1. Sčítání konečných známek zadaných učiteli\n2. Děleno počtem předmětů, pro které už byly uděleny známky</string>
|
||||||
<string name="grade_summary_final_average">Konečný průměr</string>
|
<string name="grade_summary_final_average">Konečný průměr</string>
|
||||||
@ -294,6 +297,10 @@
|
|||||||
<string name="message_move_to_trash">Přesunout do koše</string>
|
<string name="message_move_to_trash">Přesunout do koše</string>
|
||||||
<string name="message_delete_forever">Odstranit natrvalo</string>
|
<string name="message_delete_forever">Odstranit natrvalo</string>
|
||||||
<string name="message_delete_success">Zpráva byla úspěšně odstraněna</string>
|
<string name="message_delete_success">Zpráva byla úspěšně odstraněna</string>
|
||||||
|
<string name="message_mailbox_type_student">žák</string>
|
||||||
|
<string name="message_mailbox_type_parent">rodič</string>
|
||||||
|
<string name="message_mailbox_type_guardian">opatrovník</string>
|
||||||
|
<string name="message_mailbox_type_employee">pracovník</string>
|
||||||
<string name="message_share">Sdílet</string>
|
<string name="message_share">Sdílet</string>
|
||||||
<string name="message_print">Vytisknout</string>
|
<string name="message_print">Vytisknout</string>
|
||||||
<string name="message_subject">Předmět</string>
|
<string name="message_subject">Předmět</string>
|
||||||
@ -305,7 +312,6 @@
|
|||||||
<string name="message_chip_only_unread">Pouze nepřečtené</string>
|
<string name="message_chip_only_unread">Pouze nepřečtené</string>
|
||||||
<string name="message_chip_only_with_attachments">Pouze s přílohami</string>
|
<string name="message_chip_only_with_attachments">Pouze s přílohami</string>
|
||||||
<string name="message_read">Přečtena: %s</string>
|
<string name="message_read">Přečtena: %s</string>
|
||||||
<string name="message_read_by">Přečtena přes: %1$d z %2$d osob</string>
|
|
||||||
<plurals name="message_number_item">
|
<plurals name="message_number_item">
|
||||||
<item quantity="one">%1$d zpráva</item>
|
<item quantity="one">%1$d zpráva</item>
|
||||||
<item quantity="few">%1$d zprávy</item>
|
<item quantity="few">%1$d zprávy</item>
|
||||||
@ -721,6 +727,10 @@
|
|||||||
<string name="pref_ads_privacy_link">Ochrana osobních údajů</string>
|
<string name="pref_ads_privacy_link">Ochrana osobních údajů</string>
|
||||||
<string name="pref_ads_loading">Reklama se načítá</string>
|
<string name="pref_ads_loading">Reklama se načítá</string>
|
||||||
<string name="pref_ads_once_per_visit">Děkujeme za vaši podporu, vraťte se později pro více reklam</string>
|
<string name="pref_ads_once_per_visit">Děkujeme za vaši podporu, vraťte se později pro více reklam</string>
|
||||||
|
<string name="pref_ads_consent_title">Můžeme použít Vaše data k zobrazení reklam?</string>
|
||||||
|
<string name="pref_ads_consent_description">Volbu můžete kdykoliv změnit v nastavení aplikace. Můžeme použít Vaše data k zobrazení reklam šitých pro vás nebo pomocí méně vašich dat zobrazovat nepřizpůsobené reklamy. Podrobnosti naleznete v našich Zásadách ochrany osobních údajů</string>
|
||||||
|
<string name="pref_ads_summary_personalized">Přizpůsobené reklamy</string>
|
||||||
|
<string name="pref_ads_summary_non_personalized">Nepřizpůsobené reklamy</string>
|
||||||
<string name="pref_settings_advanced_title">Pokročilé</string>
|
<string name="pref_settings_advanced_title">Pokročilé</string>
|
||||||
<string name="pref_settings_appearance_title">Vzhled a chování</string>
|
<string name="pref_settings_appearance_title">Vzhled a chování</string>
|
||||||
<string name="pref_settings_notifications_title">Oznámení</string>
|
<string name="pref_settings_notifications_title">Oznámení</string>
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
<string-array name="grade_sorting_mode_entries">
|
<string-array name="grade_sorting_mode_entries">
|
||||||
<item>Alphabetisch</item>
|
<item>Alphabetisch</item>
|
||||||
<item>Nach Datum</item>
|
<item>Nach Datum</item>
|
||||||
|
<item>Nach Durchschnitt</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="grade_color_scheme_entries">
|
<string-array name="grade_color_scheme_entries">
|
||||||
<item>Dzienniczek+</item>
|
<item>Dzienniczek+</item>
|
||||||
|
@ -77,6 +77,9 @@
|
|||||||
<string name="main_log_in">Anmelden</string>
|
<string name="main_log_in">Anmelden</string>
|
||||||
<string name="main_session_expired">Die Sitzung ist abgelaufen</string>
|
<string name="main_session_expired">Die Sitzung ist abgelaufen</string>
|
||||||
<string name="main_session_relogin">Die Sitzung ist abgelaufen, bitte loggen Sie sich erneut ein</string>
|
<string name="main_session_relogin">Die Sitzung ist abgelaufen, bitte loggen Sie sich erneut ein</string>
|
||||||
|
<string name="main_support_title">Anwendungsunterstützung</string>
|
||||||
|
<string name="main_support_description">Gefällt Ihnen diese App? Unterstützen Sie ihre Entwicklung, indem Sie nicht-invasive Werbung aktivieren, die Sie jederzeit deaktivieren können</string>
|
||||||
|
<string name="main_support_positive">Werbung aktivieren</string>
|
||||||
<!--Grade-->
|
<!--Grade-->
|
||||||
<string name="grade_header">Note</string>
|
<string name="grade_header">Note</string>
|
||||||
<string name="grade_semester">Semester %d</string>
|
<string name="grade_semester">Semester %d</string>
|
||||||
@ -94,7 +97,7 @@
|
|||||||
<string name="grade_summary_predicted_grade">Vorhergesagte Note</string>
|
<string name="grade_summary_predicted_grade">Vorhergesagte Note</string>
|
||||||
<string name="grade_summary_calculated_average">Berechnender Durchschnitt</string>
|
<string name="grade_summary_calculated_average">Berechnender Durchschnitt</string>
|
||||||
<string name="grade_summary_calculated_average_help_dialog_title">Wie funktioniert der berechnete Durchschnitt?</string>
|
<string name="grade_summary_calculated_average_help_dialog_title">Wie funktioniert der berechnete Durchschnitt?</string>
|
||||||
<string name="grade_summary_calculated_average_help_dialog_message">Der berechnete Mittelwert ist das arithmetische Mittel, das aus den Durchschnittswerten der Probanden errechnet wird. Es erlaubt Ihnen, den ungefähre endgültigen Durchschnitt zu kennen. Sie wird auf eine vom Anwender in den Anwendungseinstellungen gewählte Weise berechnet. Es wird empfohlen, die entsprechende Option zu wählen. Das liegt daran, dass die Berechnung der Schuldurchschnitte unterschiedlich ist. Wenn Ihre Schule den Durchschnitt der Fächer auf der Vulcan-Seite angibt, lädt die Anwendung diese Fächer herunter und berechnet nicht den Durchschnitt. Dies kann geändert werden, indem die Berechnung des Durchschnitts in den Anwendungseinstellungen erzwungen wird. \n\n<b>Durchschnitt der Noten nur aus dem ausgewählten Semester </b>:\n1. Berechnung des gewichteten Durchschnitts für jedes Fach in einem bestimmten Semester\n2. Addition der berechneten Durchschnittswerte\n3. Berechnung des arithmetischen Mittels der summierten Durchschnitte\n<b>Durchschnitt der Durchschnitte aus beiden Semestern</b>:\n1. Berechnung des gewichteten Durchschnitts für jedes Fach in Semester 1 und 2\n2. Berechnung des arithmetischen Mittels der berechneten Durchschnitte für Semester 1 und 2 für jedes Fach. \n3. Hinzufügen von berechneten Durchschnittswerten\n4. Berechnung des arithmetischen Mittels der summierten Durchschnitte\n<b>Durchschnitt der Noten aus dem ganzen Jahr:</b>\n1. Berechnung des gewichteten Jahresdurchschnitts für jedes Fach. Der Abschlussdurchschnitt im 1. Semester ist irrelevant. \n3. Addition der berechneten Durchschnittswerte\n4. Berechnung des arithmetischen Mittels der summierten Mittelwerte</string>
|
<string name="grade_summary_calculated_average_help_dialog_message">Der berechnete Mittelwert ist das arithmetische Mittel, das aus den Durchschnittswerten der Probanden errechnet wird. Es erlaubt Ihnen, den ungefähre endgültigen Durchschnitt zu kennen. Sie wird auf eine vom Anwender in den Anwendungseinstellungen gewählte Weise berechnet. Es wird empfohlen, die entsprechende Option zu wählen. Das liegt daran, dass die Berechnung der Schuldurchschnitte unterschiedlich ist. Wenn Ihre Schule den Durchschnitt der Fächer auf der Vulcan-Seite angibt, lädt die Anwendung diese Fächer herunter und berechnet nicht den Durchschnitt. Dies kann geändert werden, indem die Berechnung des Durchschnitts in den Anwendungseinstellungen erzwungen wird. \n\n<b>Durchschnitt der Noten nur aus dem ausgewählten Semester </b>:\n1. Berechnung des gewichteten Durchschnitts für jedes Fach in einem bestimmten Semester\n2. Addition der berechneten Durchschnittswerte\n3. Berechnung des arithmetischen Mittels der summierten Durchschnitte\n<b>Durchschnitt der Durchschnitte aus beiden Semestern</b>:\n1. Berechnung des gewichteten Durchschnitts für jedes Fach in Semester 1 und 2\n2. Berechnung des arithmetischen Mittels der berechneten Durchschnitte für Semester 1 und 2 für jedes Fach. \n3. Hinzufügen von berechneten Durchschnittswerten\n4. Berechnung des arithmetischen Mittels der summierten Durchschnitte\n<b>Durchschnitt der Noten aus dem ganzen Jahr:</b>\n1. Berechnung des gewichteten Jahresdurchschnitts für jedes Fach. Der Abschlussdurchschnitt im 1. Semester ist irrelevant. \n2. Addition der berechneten Durchschnittswerte\n3. Berechnung des arithmetischen Mittels der summierten Mittelwerte</string>
|
||||||
<string name="grade_summary_final_average_help_dialog_title">Wie funktioniert der endgültige Durchschnitt?</string>
|
<string name="grade_summary_final_average_help_dialog_title">Wie funktioniert der endgültige Durchschnitt?</string>
|
||||||
<string name="grade_summary_final_average_help_dialog_message">Der Final Average ist das arithmetische Mittel, das aus allen derzeit verfügbaren Abschlussnoten des jeweiligen Semesters berechnet wird. \n\nDas Berechnungsschema besteht aus folgenden Schritten:\n1. Zusammenfassung der von den Lehrern gegebenen Abschlussnoten\n2. Division durch die Anzahl der Fächer, die bereits bewertet wurden</string>
|
<string name="grade_summary_final_average_help_dialog_message">Der Final Average ist das arithmetische Mittel, das aus allen derzeit verfügbaren Abschlussnoten des jeweiligen Semesters berechnet wird. \n\nDas Berechnungsschema besteht aus folgenden Schritten:\n1. Zusammenfassung der von den Lehrern gegebenen Abschlussnoten\n2. Division durch die Anzahl der Fächer, die bereits bewertet wurden</string>
|
||||||
<string name="grade_summary_final_average">Finaler Durchschnitt</string>
|
<string name="grade_summary_final_average">Finaler Durchschnitt</string>
|
||||||
@ -260,6 +263,10 @@
|
|||||||
<string name="message_move_to_trash">In Papierkorb verschieben</string>
|
<string name="message_move_to_trash">In Papierkorb verschieben</string>
|
||||||
<string name="message_delete_forever">Dauerhaft löschen</string>
|
<string name="message_delete_forever">Dauerhaft löschen</string>
|
||||||
<string name="message_delete_success">Nachricht erfolgreich gelöscht</string>
|
<string name="message_delete_success">Nachricht erfolgreich gelöscht</string>
|
||||||
|
<string name="message_mailbox_type_student">schüler</string>
|
||||||
|
<string name="message_mailbox_type_parent">Eltern</string>
|
||||||
|
<string name="message_mailbox_type_guardian">Betreuer</string>
|
||||||
|
<string name="message_mailbox_type_employee">Mitarbeiter</string>
|
||||||
<string name="message_share">Teilen</string>
|
<string name="message_share">Teilen</string>
|
||||||
<string name="message_print">Drucken</string>
|
<string name="message_print">Drucken</string>
|
||||||
<string name="message_subject">Thema</string>
|
<string name="message_subject">Thema</string>
|
||||||
@ -271,7 +278,6 @@
|
|||||||
<string name="message_chip_only_unread">Nur ungelesen</string>
|
<string name="message_chip_only_unread">Nur ungelesen</string>
|
||||||
<string name="message_chip_only_with_attachments">Nur mit Anhängen</string>
|
<string name="message_chip_only_with_attachments">Nur mit Anhängen</string>
|
||||||
<string name="message_read">Lesen: %s</string>
|
<string name="message_read">Lesen: %s</string>
|
||||||
<string name="message_read_by">Lesen von: %1$d von %2$d Personen</string>
|
|
||||||
<plurals name="message_number_item">
|
<plurals name="message_number_item">
|
||||||
<item quantity="one">%1$d Nachricht</item>
|
<item quantity="one">%1$d Nachricht</item>
|
||||||
<item quantity="other">%1$d Nachrichten</item>
|
<item quantity="other">%1$d Nachrichten</item>
|
||||||
@ -633,6 +639,10 @@
|
|||||||
<string name="pref_ads_privacy_link">Datenschutzerklärung</string>
|
<string name="pref_ads_privacy_link">Datenschutzerklärung</string>
|
||||||
<string name="pref_ads_loading">Anzeige wird geladen</string>
|
<string name="pref_ads_loading">Anzeige wird geladen</string>
|
||||||
<string name="pref_ads_once_per_visit">Vielen Dank für Ihre Unterstützung, kommen Sie später wieder für weitere Anzeigen</string>
|
<string name="pref_ads_once_per_visit">Vielen Dank für Ihre Unterstützung, kommen Sie später wieder für weitere Anzeigen</string>
|
||||||
|
<string name="pref_ads_consent_title">Können wir Ihre Daten zur Anzeige von Werbung verwenden?</string>
|
||||||
|
<string name="pref_ads_consent_description">Sie können Ihre Wahl jederzeit in den App-Einstellungen ändern. Wir verwenden Ihre Daten, um auf Sie zugeschnittene Anzeigen anzuzeigen oder unter Verwendung weniger Ihrer Daten nicht personalisierte Werbung anzuzeigen. Bitte lesen Sie unsere Datenschutzerklärung für Details</string>
|
||||||
|
<string name="pref_ads_summary_personalized">Personalisierte Werbung</string>
|
||||||
|
<string name="pref_ads_summary_non_personalized">keine personalisierte Werbung</string>
|
||||||
<string name="pref_settings_advanced_title">Erweitert</string>
|
<string name="pref_settings_advanced_title">Erweitert</string>
|
||||||
<string name="pref_settings_appearance_title">Aussehen & Verhalten</string>
|
<string name="pref_settings_appearance_title">Aussehen & Verhalten</string>
|
||||||
<string name="pref_settings_notifications_title">Benachrichtigungen</string>
|
<string name="pref_settings_notifications_title">Benachrichtigungen</string>
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
<string-array name="grade_sorting_mode_entries">
|
<string-array name="grade_sorting_mode_entries">
|
||||||
<item>Alfabetycznie</item>
|
<item>Alfabetycznie</item>
|
||||||
<item>Według daty</item>
|
<item>Według daty</item>
|
||||||
|
<item>Według średniej</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="grade_color_scheme_entries">
|
<string-array name="grade_color_scheme_entries">
|
||||||
<item>Dzienniczek+</item>
|
<item>Dzienniczek+</item>
|
||||||
|
@ -77,6 +77,9 @@
|
|||||||
<string name="main_log_in">Zaloguj się</string>
|
<string name="main_log_in">Zaloguj się</string>
|
||||||
<string name="main_session_expired">Sesja wygasła</string>
|
<string name="main_session_expired">Sesja wygasła</string>
|
||||||
<string name="main_session_relogin">Sesja wygasła, zaloguj się ponownie</string>
|
<string name="main_session_relogin">Sesja wygasła, zaloguj się ponownie</string>
|
||||||
|
<string name="main_support_title">Wparcie aplikacji</string>
|
||||||
|
<string name="main_support_description">Podoba Ci się ta aplikacja? Wspieraj jej rozwój poprzez włączenie nieinwazyjnych reklam, które możesz wyłączyć w dowolnym momencie</string>
|
||||||
|
<string name="main_support_positive">Włącz reklamy</string>
|
||||||
<!--Grade-->
|
<!--Grade-->
|
||||||
<string name="grade_header">Ocena</string>
|
<string name="grade_header">Ocena</string>
|
||||||
<string name="grade_semester">Semestr %d</string>
|
<string name="grade_semester">Semestr %d</string>
|
||||||
@ -94,7 +97,7 @@
|
|||||||
<string name="grade_summary_predicted_grade">Przewidywana ocena</string>
|
<string name="grade_summary_predicted_grade">Przewidywana ocena</string>
|
||||||
<string name="grade_summary_calculated_average">Obliczona średnia</string>
|
<string name="grade_summary_calculated_average">Obliczona średnia</string>
|
||||||
<string name="grade_summary_calculated_average_help_dialog_title">Jak działa obliczona średnia?</string>
|
<string name="grade_summary_calculated_average_help_dialog_title">Jak działa obliczona średnia?</string>
|
||||||
<string name="grade_summary_calculated_average_help_dialog_message">Obliczona średnia jest średnią arytmetyczną obliczoną ze średnich przedmiotów. Pozwala ona na poznanie przybliżonej średniej końcowej. Jest obliczana w sposób wybrany przez użytkownika w ustawieniach aplikacji. Zaleca się wybranie odpowiedniej opcji. Dzieje się tak dlatego, że obliczanie średnich w szkołach różni się. Dodatkowo, jeśli twoja szkoła ma włączone średnie przedmiotów na stronie dziennika Vulcan, aplikacja pobiera je i ich nie oblicza. Można to zmienić, wymuszając obliczanie średniej w ustawieniach aplikacji.\n\n<b>Średnia ocen tylko z wybranego semestru</b>:\n1. Obliczanie średniej arytmetycznej każdego przedmiotu w danym semestrze\n2. Zsumowanie obliczonych średnich\n3. Obliczanie średniej arytmetycznej zsumowanych średnich\n\n<b>Średnia ze średnich z obu semestrów</b>:\n1.Obliczanie średniej arytmetycznej każdego przedmiotu w semestrze 1 i 2\n2. Obliczanie średniej arytmetycznej obliczonych średnich w semetrze 1 i 2 każdego przedmiotu.\n3. Zsumowanie obliczonych średnich\n4. Obliczanie średniej arytmetycznej zsumowanych średnich\n\n<b>Średnia wszystkich ocen z całego roku:</b>\n1. Obliczanie średniej arytmetycznej z każdego przedmiotu w ciągu całego roku. Końcowa ocena w 1 semestrze jest bez znaczenia.\n3. Zsumowanie obliczonych średnich\n4. Obliczanie średniej arytmetycznej z zsumowanych średnich</string>
|
<string name="grade_summary_calculated_average_help_dialog_message">Obliczona średnia jest średnią arytmetyczną obliczoną ze średnich przedmiotów. Pozwala ona na poznanie przybliżonej średniej końcowej. Jest obliczana w sposób wybrany przez użytkownika w ustawieniach aplikacji. Zaleca się wybranie odpowiedniej opcji. Dzieje się tak dlatego, że obliczanie średnich w szkołach różni się. Dodatkowo, jeśli twoja szkoła ma włączone średnie przedmiotów na stronie dziennika Vulcan, aplikacja pobiera je i ich nie oblicza. Można to zmienić, wymuszając obliczanie średniej w ustawieniach aplikacji.\n\n<b>Średnia ocen tylko z wybranego semestru</b>:\n1. Obliczanie średniej arytmetycznej każdego przedmiotu w danym semestrze\n2. Zsumowanie obliczonych średnich\n3. Obliczanie średniej arytmetycznej zsumowanych średnich\n\n<b>Średnia ze średnich z obu semestrów</b>:\n1.Obliczanie średniej arytmetycznej każdego przedmiotu w semestrze 1 i 2\n2. Obliczanie średniej arytmetycznej obliczonych średnich w semestrze 1 i 2 każdego przedmiotu.\n3. Zsumowanie obliczonych średnich\n4. Obliczanie średniej arytmetycznej zsumowanych średnich\n\n<b>Średnia wszystkich ocen z całego roku:</b>\n1. Obliczanie średniej arytmetycznej z każdego przedmiotu w ciągu całego roku. Końcowa ocena w 1 semestrze jest bez znaczenia.\n2. Zsumowanie obliczonych średnich\n3. Obliczanie średniej arytmetycznej z zsumowanych średnich</string>
|
||||||
<string name="grade_summary_final_average_help_dialog_title">Jak działa końcowa średnia?</string>
|
<string name="grade_summary_final_average_help_dialog_title">Jak działa końcowa średnia?</string>
|
||||||
<string name="grade_summary_final_average_help_dialog_message">Średnią końcową jest średnia arytmetyczna obliczona na podstawie wszystkich obecnie dostępnych ocen końcowych w danym semestrze.\n\nSchemat obliczeń składa się z następujących kroków:\n1. Sumowanie końcowych ocen wpisanych przez nauczycieli\n2. Dzielenie przez liczbę przedmiotów, z których oceny zostały już wystawione</string>
|
<string name="grade_summary_final_average_help_dialog_message">Średnią końcową jest średnia arytmetyczna obliczona na podstawie wszystkich obecnie dostępnych ocen końcowych w danym semestrze.\n\nSchemat obliczeń składa się z następujących kroków:\n1. Sumowanie końcowych ocen wpisanych przez nauczycieli\n2. Dzielenie przez liczbę przedmiotów, z których oceny zostały już wystawione</string>
|
||||||
<string name="grade_summary_final_average">Końcowa średnia</string>
|
<string name="grade_summary_final_average">Końcowa średnia</string>
|
||||||
@ -294,6 +297,10 @@
|
|||||||
<string name="message_move_to_trash">Przenieś do kosza</string>
|
<string name="message_move_to_trash">Przenieś do kosza</string>
|
||||||
<string name="message_delete_forever">Usuń trwale</string>
|
<string name="message_delete_forever">Usuń trwale</string>
|
||||||
<string name="message_delete_success">Wiadomość usunięta pomyślnie</string>
|
<string name="message_delete_success">Wiadomość usunięta pomyślnie</string>
|
||||||
|
<string name="message_mailbox_type_student">uczeń</string>
|
||||||
|
<string name="message_mailbox_type_parent">rodzic</string>
|
||||||
|
<string name="message_mailbox_type_guardian">opiekun</string>
|
||||||
|
<string name="message_mailbox_type_employee">pracownik</string>
|
||||||
<string name="message_share">Udostępnij</string>
|
<string name="message_share">Udostępnij</string>
|
||||||
<string name="message_print">Drukuj</string>
|
<string name="message_print">Drukuj</string>
|
||||||
<string name="message_subject">Temat</string>
|
<string name="message_subject">Temat</string>
|
||||||
@ -305,7 +312,6 @@
|
|||||||
<string name="message_chip_only_unread">Tylko nieprzeczytane</string>
|
<string name="message_chip_only_unread">Tylko nieprzeczytane</string>
|
||||||
<string name="message_chip_only_with_attachments">Tylko z załącznikami</string>
|
<string name="message_chip_only_with_attachments">Tylko z załącznikami</string>
|
||||||
<string name="message_read">Przeczytana: %s</string>
|
<string name="message_read">Przeczytana: %s</string>
|
||||||
<string name="message_read_by">Przeczytana przez: %1$d z %2$d osób</string>
|
|
||||||
<plurals name="message_number_item">
|
<plurals name="message_number_item">
|
||||||
<item quantity="one">%1$d wiadomość</item>
|
<item quantity="one">%1$d wiadomość</item>
|
||||||
<item quantity="few">%1$d wiadomości</item>
|
<item quantity="few">%1$d wiadomości</item>
|
||||||
@ -701,7 +707,7 @@
|
|||||||
<string name="pref_notification_go_to_settings">Przejdź do ustawień</string>
|
<string name="pref_notification_go_to_settings">Przejdź do ustawień</string>
|
||||||
<string name="pref_services_header">Synchronizacja</string>
|
<string name="pref_services_header">Synchronizacja</string>
|
||||||
<string name="pref_services_switch">Automatyczna aktualizacja</string>
|
<string name="pref_services_switch">Automatyczna aktualizacja</string>
|
||||||
<string name="pref_services_suspended">Zawieszona na wakacjach</string>
|
<string name="pref_services_suspended">Wstrzymana podczas wakacji</string>
|
||||||
<string name="pref_services_interval">Interwał aktualizacji</string>
|
<string name="pref_services_interval">Interwał aktualizacji</string>
|
||||||
<string name="pref_services_wifi">Tylko WiFi</string>
|
<string name="pref_services_wifi">Tylko WiFi</string>
|
||||||
<string name="pref_services_force_sync">Synchronizuj teraz</string>
|
<string name="pref_services_force_sync">Synchronizuj teraz</string>
|
||||||
@ -721,6 +727,10 @@
|
|||||||
<string name="pref_ads_privacy_link">Polityka prywatności</string>
|
<string name="pref_ads_privacy_link">Polityka prywatności</string>
|
||||||
<string name="pref_ads_loading">Ładowanie reklamy</string>
|
<string name="pref_ads_loading">Ładowanie reklamy</string>
|
||||||
<string name="pref_ads_once_per_visit">Dziękujemy za wsparcie, wróć później po więcej reklam</string>
|
<string name="pref_ads_once_per_visit">Dziękujemy za wsparcie, wróć później po więcej reklam</string>
|
||||||
|
<string name="pref_ads_consent_title">Czy możemy używać Twoich danych do wyświetlania reklam?</string>
|
||||||
|
<string name="pref_ads_consent_description">Możesz zmienić swój wybór w dowolnym momencie w ustawieniach aplikacji. Możemy wykorzystać Twoje dane do wyświetlania reklam dostosowanych do Ciebie lub, przy użyciu mniejszej ilości danych, wyświetlić niepersonalizowane reklamy. Zobacz naszą Politykę Prywatności, aby uzyskać więcej informacji</string>
|
||||||
|
<string name="pref_ads_summary_personalized">Spersonalizowane reklamy</string>
|
||||||
|
<string name="pref_ads_summary_non_personalized">Niespersonalizowane reklamy</string>
|
||||||
<string name="pref_settings_advanced_title">Zaawansowane</string>
|
<string name="pref_settings_advanced_title">Zaawansowane</string>
|
||||||
<string name="pref_settings_appearance_title">Wygląd i zachowanie</string>
|
<string name="pref_settings_appearance_title">Wygląd i zachowanie</string>
|
||||||
<string name="pref_settings_notifications_title">Powiadomienia</string>
|
<string name="pref_settings_notifications_title">Powiadomienia</string>
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
<string-array name="grade_sorting_mode_entries">
|
<string-array name="grade_sorting_mode_entries">
|
||||||
<item>В алфавитном порядке</item>
|
<item>В алфавитном порядке</item>
|
||||||
<item>По дате</item>
|
<item>По дате</item>
|
||||||
|
<item>По средней</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="grade_color_scheme_entries">
|
<string-array name="grade_color_scheme_entries">
|
||||||
<item>Dzienniczek+</item>
|
<item>Dzienniczek+</item>
|
||||||
|
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