1
0

Compare commits

...

67 Commits
2.2.1 ... 2.3.0

Author SHA1 Message Date
eb31f9578f Merge branch 'release/2.3.0' 2024-01-02 01:51:52 +01:00
f69d50d2c1 Version 2.3.0 2024-01-02 01:51:09 +01:00
8a424ee6a4 New Crowdin updates (#2381) 2024-01-02 01:30:31 +01:00
7dfa48bbe3 Add User Messaging Platform SDK for ads agreements (#2375) 2024-01-01 21:19:00 +01:00
d811cdb919 Bump com.huawei.agconnect:agcp from 1.9.1.302 to 1.9.1.303 (#2377) 2024-01-01 17:39:08 +00:00
e2f2e21081 Bump com.huawei.agconnect:agconnect-crash from 1.9.1.302 to 1.9.1.303 (#2379) 2024-01-01 17:38:29 +00:00
c812310497 Bump about_libraries from 10.9.2 to 10.10.0 (#2380) 2024-01-01 18:36:02 +01:00
7f6475cf35 Merge branch 'release/2.2.7' into develop 2023-12-27 22:21:18 +01:00
a2a7d2ebb2 Merge branch 'release/2.2.7' 2023-12-27 22:21:13 +01:00
a5bc45c5da Version 2.2.7 2023-12-27 22:21:07 +01:00
5646befbd7 Revert "Bump com.google.android.material:material from 1.10.0 to 1.11.0 (#2368)" (#2376)
This reverts commit 7f4539fd27.
2023-12-27 21:52:04 +01:00
75f496b5d2 Bump kotlin_version from 1.9.21 to 1.9.22 (#2371) 2023-12-27 16:11:58 +00:00
23d989d22a Bump hilt_version from 2.49 to 2.50 (#2372) 2023-12-24 07:01:40 +00:00
9e013f7cd9 Bump ru.cian:huawei-publish-gradle-plugin from 1.4.0 to 1.4.2 (#2370) 2023-12-24 07:00:42 +00:00
c63a7c03f1 Bump com.huawei.agconnect:agcp from 1.9.1.301 to 1.9.1.302 (#2373) 2023-12-24 06:54:28 +00:00
5ceee84f0e Bump com.huawei.agconnect:agconnect-crash from 1.9.1.301 to 1.9.1.302 (#2374) 2023-12-24 06:54:09 +00:00
7f4539fd27 Bump com.google.android.material:material from 1.10.0 to 1.11.0 (#2368) 2023-12-22 13:48:13 +00:00
71ebf1260b Bump com.android.tools.build:gradle from 8.1.4 to 8.2.0 (#2361) 2023-12-15 19:44:32 +00:00
784ee58384 Bump work_manager from 2.8.1 to 2.9.0 (#2363) 2023-12-15 16:21:08 +00:00
eceef3f582 Bump com.google.firebase:firebase-bom from 32.6.0 to 32.7.0 (#2366) 2023-12-15 15:52:54 +00:00
0d950fbd86 Bump com.google.android.gms:play-services-ads from 22.5.0 to 22.6.0 (#2367) 2023-12-15 15:52:35 +00:00
003d63b516 Bump room from 2.6.0 to 2.6.1 (#2360) 2023-12-07 22:44:50 +00:00
b4c0440a8e Bump hilt_version from 2.48.1 to 2.49 (#2362) 2023-12-07 22:44:37 +00:00
137c305295 Bump org.jetbrains.kotlinx:kotlinx-serialization-json (#2365) 2023-12-07 22:44:23 +00:00
2c40c221c3 Bump kotlin_version from 1.9.10 to 1.9.21 (#2357) 2023-11-28 22:32:32 +00:00
e82ac78d4a Bump androidx.fragment:fragment-ktx from 1.6.1 to 1.6.2 (#2348) 2023-11-28 22:32:18 +00:00
59d46ce956 Bump com.google.android.gms:play-services-ads from 22.4.0 to 22.5.0 (#2346) 2023-11-28 22:21:19 +00:00
17caa8ecbd Bump com.android.tools:desugar_jdk_libs from 2.0.3 to 2.0.4 (#2345) 2023-11-28 22:21:00 +00:00
e9540b4012 Bump androidx.activity:activity-ktx from 1.8.0 to 1.8.1 (#2354) 2023-11-28 22:20:41 +00:00
643ad60455 Bump com.google.firebase:firebase-bom from 32.5.0 to 32.6.0 (#2355) 2023-11-28 22:20:18 +00:00
01f892ce5c Bump com.android.tools.build:gradle from 8.1.2 to 8.1.4 (#2356) 2023-11-28 22:19:53 +00:00
f61b6a5e78 Bump com.google.android.play:integrity from 1.2.0 to 1.3.0 (#2351) 2023-11-28 22:10:32 +00:00
650cf7484e Bump android_hilt from 1.0.0 to 1.1.0 (#2343) 2023-11-28 22:10:11 +00:00
037cbb0b19 Bump about_libraries from 10.9.1 to 10.9.2 (#2344)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2023-11-28 23:08:13 +01:00
e49835e89e Merge branch 'release/2.2.6' into develop 2023-11-06 11:22:25 +01:00
c64be2fab0 Merge branch 'release/2.2.6' 2023-11-06 11:22:19 +01:00
ce9cb35172 Version 2.2.6 2023-11-06 11:22:15 +01:00
7fa9219c7b Bump sdk version 2023-11-06 09:40:47 +01:00
1fe1618220 Merge branch 'release/2.2.5' into develop 2023-11-03 23:05:48 +01:00
d9bab2af78 Merge branch 'release/2.2.5' 2023-11-03 23:05:42 +01:00
06b6d88dd1 Version 2.2.5 2023-11-03 23:05:35 +01:00
3bf27baed5 Bump org.robolectric:robolectric from 4.11 to 4.11.1 (#2342) 2023-11-01 17:31:24 +00:00
6802d74002 Bump com.google.firebase:firebase-bom from 32.4.1 to 32.5.0 (#2341) 2023-11-01 17:31:05 +00:00
3fd2683df7 Update dependencies and remove deprecations (#2340) 2023-11-01 16:47:39 +01:00
b708c70ea2 Merge branch 'release/2.2.4' into develop 2023-10-27 14:49:54 +02:00
aba08e6aa9 Merge branch 'release/2.2.4' 2023-10-27 14:49:46 +02:00
124b6dfd79 Version 2.2.4 2023-10-27 14:49:41 +02:00
1dbaa8bfdc Migrate to separate app-update and review artifacts from play:core (#2336) 2023-10-27 14:09:42 +02:00
25ac171298 Merge branch 'release/2.2.3' into develop 2023-10-26 18:32:01 +02:00
387ff1cba7 Merge branch 'release/2.2.3' 2023-10-26 18:31:56 +02:00
eef3464d0b Version 2.2.3 2023-10-26 18:31:51 +02:00
61297a01c7 New Crowdin updates (#2334) 2023-10-26 14:01:45 +02:00
762d4b1393 Timetable timers fixes (#2333) 2023-10-26 10:06:54 +02:00
2e86b67eec Merge branch 'release/2.2.2' into develop 2023-10-23 20:02:32 +02:00
6071b7571b Merge branch 'release/2.2.2' 2023-10-23 20:02:25 +02:00
fcea2218b5 Version 2.2.2 2023-10-23 19:56:46 +02:00
a4a191700e Bump com.google.firebase:firebase-bom from 32.3.1 to 32.4.0 (#2331) 2023-10-23 17:28:38 +00:00
3d76d41b55 Bump com.squareup.okhttp3:logging-interceptor from 4.11.0 to 4.12.0 (#2330) 2023-10-23 16:49:58 +00:00
0e1c20a952 Bump room from 2.5.2 to 2.6.0 (#2329) 2023-10-23 16:48:23 +00:00
5d14ee7f4e Bump androidx.recyclerview:recyclerview from 1.3.1 to 1.3.2 (#2332) 2023-10-23 16:47:03 +00:00
83527d91f3 Allow direct access to weekend from day navigation when there is any lesson during weekend (#2326) 2023-10-23 13:05:46 +02:00
9d62410530 Sort teachers by name in school and teachers tab (#2327) 2023-10-23 13:05:05 +02:00
5dffbdadfa Points statistics improvements (#2328) 2023-10-23 13:04:42 +02:00
516922d5aa Bump org.sonarsource.scanner.gradle:sonarqube-gradle-plugin (#2324) 2023-10-14 19:18:28 +00:00
9098e74065 Bump com.google.android.material:material from 1.9.0 to 1.10.0 (#2325) 2023-10-14 19:17:56 +00:00
2f5577cc54 Update SDK to 34 (#2322) 2023-10-06 10:07:55 +02:00
3272c38356 Merge branch 'release/2.2.1' into develop 2023-10-03 01:14:25 +02:00
113 changed files with 930 additions and 929 deletions

10
.idea/migrations.xml generated Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

View File

@ -20,15 +20,15 @@ apply from: 'hooks.gradle'
android { android {
namespace 'io.github.wulkanowy' namespace 'io.github.wulkanowy'
compileSdk 33 compileSdk 34
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 33 targetSdkVersion 34
versionCode 133 versionCode 140
versionName "2.2.1" versionName "2.3.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "app_name", "Wulkanowy" resValue "string", "app_name", "Wulkanowy"
@ -113,6 +113,7 @@ android {
buildFeatures { buildFeatures {
viewBinding true viewBinding true
buildConfig true
} }
bundle { bundle {
@ -161,7 +162,7 @@ play {
defaultToAppBundles = false defaultToAppBundles = false
track = 'production' track = 'production'
releaseStatus = ReleaseStatus.IN_PROGRESS releaseStatus = ReleaseStatus.IN_PROGRESS
userFraction = 0.01d userFraction = 0.15d
updatePriority = 3 updatePriority = 3
enabled.set(false) enabled.set(false)
} }
@ -183,41 +184,41 @@ huaweiPublish {
} }
ext { ext {
work_manager = "2.8.1" work_manager = "2.9.0"
android_hilt = "1.0.0" android_hilt = "1.1.0"
room = "2.5.2" room = "2.6.1"
chucker = "3.5.2" chucker = "4.0.0"
mockk = "1.13.8" mockk = "1.13.8"
coroutines = "1.7.3" coroutines = "1.7.3"
} }
dependencies { dependencies {
implementation 'io.github.wulkanowy:sdk:2.2.1' implementation 'io.github.wulkanowy:sdk:2.3.1'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0" implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
implementation "androidx.core:core-ktx:1.10.1" implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.core:core-splashscreen:1.0.1' implementation 'androidx.core:core-splashscreen:1.0.1'
implementation "androidx.activity:activity-ktx:1.7.2" implementation "androidx.activity:activity-ktx:1.8.2"
implementation "androidx.appcompat:appcompat:1.6.1" implementation "androidx.appcompat:appcompat:1.6.1"
implementation "androidx.fragment:fragment-ktx:1.6.1" implementation "androidx.fragment:fragment-ktx:1.6.2"
implementation "androidx.annotation:annotation:1.7.0" implementation "androidx.annotation:annotation:1.7.1"
implementation "androidx.preference:preference-ktx:1.2.1" implementation "androidx.preference:preference-ktx:1.2.1"
implementation "androidx.recyclerview:recyclerview:1.3.1" implementation "androidx.recyclerview:recyclerview:1.3.2"
implementation "androidx.viewpager2:viewpager2:1.1.0-beta02" implementation "androidx.viewpager2:viewpager2:1.1.0-beta02"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "androidx.constraintlayout:constraintlayout:2.1.4" 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.9.0" implementation "com.google.android.material:material:1.10.0"
implementation "com.github.wulkanowy:material-chips-input:2.3.1" implementation "com.github.wulkanowy:material-chips-input:2.3.1"
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0" implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
implementation 'com.github.lopspower:CircularImageView:4.3.0' implementation 'com.github.lopspower:CircularImageView:4.3.0'
implementation "androidx.work:work-runtime-ktx:$work_manager" implementation "androidx.work:work-runtime:$work_manager"
playImplementation "androidx.work:work-gcm:$work_manager" playImplementation "androidx.work:work-gcm:$work_manager"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2" implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2"
@ -236,34 +237,36 @@ 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:1.0.0" implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0"
implementation "com.squareup.okhttp3:logging-interceptor:4.11.0" implementation "com.squareup.okhttp3:logging-interceptor:4.12.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.1.2' implementation 'com.github.bastienpaulfr:Treessence:1.1.2'
implementation "com.mikepenz:aboutlibraries-core:$about_libraries" implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
implementation "io.coil-kt:coil:2.4.0" implementation 'io.coil-kt:coil:2.5.0'
implementation "io.github.wulkanowy:AppKillerManager:3.0.1" implementation "io.github.wulkanowy:AppKillerManager:3.0.1"
implementation 'me.xdrop:fuzzywuzzy:1.4.0' implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.9.1' implementation 'com.fredporciuncula:flow-preferences:1.9.1'
implementation 'org.apache.commons:commons-text:1.10.0' implementation 'org.apache.commons:commons-text:1.11.0'
playImplementation platform('com.google.firebase:firebase-bom:32.3.1') playImplementation platform('com.google.firebase:firebase-bom:32.7.0')
playImplementation 'com.google.firebase:firebase-analytics-ktx' playImplementation 'com.google.firebase:firebase-analytics'
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.firebase:firebase-config-ktx' playImplementation 'com.google.firebase:firebase-config'
playImplementation 'com.google.android.play:core:1.10.3'
playImplementation 'com.google.android.play:core-ktx:1.8.1' playImplementation 'com.google.android.gms:play-services-ads:22.6.0'
playImplementation 'com.google.android.gms:play-services-ads:22.4.0' playImplementation "com.google.android.play:integrity:1.3.0"
playImplementation "com.google.android.play:integrity:1.2.0" playImplementation 'com.google.android.play:app-update-ktx:2.1.0'
playImplementation 'com.google.android.play:review-ktx:2.0.1'
playImplementation "com.google.android.ump:user-messaging-platform:2.1.0"
hmsImplementation 'com.huawei.hms:hianalytics:6.12.0.300' hmsImplementation 'com.huawei.hms:hianalytics:6.12.0.300'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.9.1.301' hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.9.1.303'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker" releaseImplementation "com.github.chuckerteam.chucker:library-no-op:$chucker"
debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker" debugImplementation "com.github.chuckerteam.chucker:library:$chucker"
debugImplementation 'com.github.amitshekhariitbhu.Android-Debug-Database:debug-db:1.0.6' debugImplementation 'com.github.amitshekhariitbhu.Android-Debug-Database:debug-db:1.0.6'
debugImplementation 'com.github.haroldadmin:WhatTheStack:1.0.0-alpha04' debugImplementation 'com.github.haroldadmin:WhatTheStack:1.0.0-alpha04'
@ -272,7 +275,7 @@ dependencies {
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines"
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
testImplementation 'org.robolectric:robolectric:4.10.3' testImplementation 'org.robolectric:robolectric:4.11.1'
testImplementation "androidx.test:runner:1.5.2" testImplementation "androidx.test:runner:1.5.2"
testImplementation "androidx.test.ext:junit:1.1.5" testImplementation "androidx.test.ext:junit:1.1.5"
testImplementation "androidx.test:core:1.5.0" testImplementation "androidx.test:core:1.5.0"

View File

@ -1,16 +1,16 @@
apply plugin: "jacoco" apply plugin: "jacoco"
jacoco { jacoco {
toolVersion "0.8.7" toolVersion "0.8.11"
reportsDirectory.set(file("$buildDir/reports")) reportsDirectory.set(file("$buildDir/reports"))
} }
tasks.withType(Test) { tasks.withType(Test).configureEach {
jacoco.includeNoLocationClasses = true jacoco.includeNoLocationClasses = true
jacoco.excludes = ['jdk.internal.*'] jacoco.excludes = ['jdk.internal.*']
} }
task jacocoTestReport(type: JacocoReport) { tasks.register('jacocoTestReport', JacocoReport) {
group = "Reporting" group = "Reporting"
description = "Generate Jacoco coverage reports" description = "Generate Jacoco coverage reports"
@ -33,19 +33,19 @@ task jacocoTestReport(type: JacocoReport) {
'**/*_Factory.*'] '**/*_Factory.*']
classDirectories.setFrom(fileTree( classDirectories.setFrom(fileTree(
dir: "$buildDir/intermediates/classes/debug", dir: "$buildDir/intermediates/classes/debug",
excludes: excludes excludes: excludes
) + fileTree( ) + fileTree(
dir: "$buildDir/tmp/kotlin-classes/fdroidDebug", dir: "$buildDir/tmp/kotlin-classes/fdroidDebug",
excludes: excludes excludes: excludes
)) ))
sourceDirectories.setFrom(files([ sourceDirectories.setFrom(files([
"src/main/java", "src/main/java",
"src/fdroid/java" "src/fdroid/java"
])) ]))
executionData.setFrom(fileTree( executionData.setFrom(fileTree(
dir: project.projectDir, dir: project.projectDir,
includes: ["**/*.exec", "**/*.ec"] includes: ["**/*.exec", "**/*.ec"]
)) ))
} }

View File

@ -5,6 +5,7 @@ import android.view.View
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
import kotlinx.coroutines.flow.MutableStateFlow
import javax.inject.Inject import javax.inject.Inject
@Suppress("unused") @Suppress("unused")
@ -13,9 +14,11 @@ class AdsHelper @Inject constructor(
private val preferencesRepository: PreferencesRepository private val preferencesRepository: PreferencesRepository
) { ) {
val isMobileAdsSdkInitialized = MutableStateFlow(false)
val canShowAd = false
fun initialize() { fun initialize() {
preferencesRepository.isAdsEnabled = false preferencesRepository.isAdsEnabled = false
preferencesRepository.isAgreeToProcessData = false
preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS
} }

View File

@ -0,0 +1,13 @@
package io.github.wulkanowy.utils
import android.view.View
import javax.inject.Inject
class InAppUpdateHelper @Inject constructor() {
lateinit var messageContainer: View
fun checkAndInstallUpdates() {}
fun onResume() {}
}

View File

@ -1,17 +0,0 @@
package io.github.wulkanowy.utils
import android.app.Activity
import android.view.View
import javax.inject.Inject
@Suppress("UNUSED_PARAMETER")
class UpdateHelper @Inject constructor() {
lateinit var messageContainer: View
fun checkAndInstallUpdates(activity: Activity) {}
fun onActivityResult(requestCode: Int, resultCode: Int) {}
fun onResume(activity: Activity) {}
}

View File

@ -5,6 +5,7 @@ import android.view.View
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
import kotlinx.coroutines.flow.MutableStateFlow
import javax.inject.Inject import javax.inject.Inject
@Suppress("unused") @Suppress("unused")
@ -12,10 +13,11 @@ class AdsHelper @Inject constructor(
@ApplicationContext private val context: Context, @ApplicationContext private val context: Context,
private val preferencesRepository: PreferencesRepository private val preferencesRepository: PreferencesRepository
) { ) {
val isMobileAdsSdkInitialized = MutableStateFlow(false)
val canShowAd = false
fun initialize() { fun initialize() {
preferencesRepository.isAdsEnabled = false preferencesRepository.isAdsEnabled = false
preferencesRepository.isAgreeToProcessData = false
preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS
} }

View File

@ -0,0 +1,13 @@
package io.github.wulkanowy.utils
import android.view.View
import javax.inject.Inject
class InAppUpdateHelper @Inject constructor() {
lateinit var messageContainer: View
fun checkAndInstallUpdates() {}
fun onResume() {}
}

View File

@ -1,17 +0,0 @@
package io.github.wulkanowy.utils
import android.app.Activity
import android.view.View
import javax.inject.Inject
@Suppress("UNUSED_PARAMETER")
class UpdateHelper @Inject constructor() {
lateinit var messageContainer: View
fun checkAndInstallUpdates(activity: Activity) {}
fun onActivityResult(requestCode: Int, resultCode: Int) {}
fun onResume(activity: Activity) {}
}

View File

@ -1,7 +1,9 @@
package io.github.wulkanowy package io.github.wulkanowy
import android.app.Application import android.app.Application
import android.util.Log.* import android.util.Log.DEBUG
import android.util.Log.INFO
import android.util.Log.VERBOSE
import androidx.hilt.work.HiltWorkerFactory import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration import androidx.work.Configuration
import com.yariksoffice.lingver.Lingver import com.yariksoffice.lingver.Lingver
@ -9,16 +11,19 @@ import dagger.hilt.android.HiltAndroidApp
import fr.bipi.treessence.file.FileLoggerTree import fr.bipi.treessence.file.FileLoggerTree
import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.ui.base.ThemeManager import io.github.wulkanowy.ui.base.ThemeManager
import io.github.wulkanowy.utils.* import io.github.wulkanowy.utils.ActivityLifecycleLogger
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.CrashLogExceptionTree
import io.github.wulkanowy.utils.CrashLogTree
import io.github.wulkanowy.utils.DebugLogTree
import io.github.wulkanowy.utils.RemoteConfigHelper
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@HiltAndroidApp @HiltAndroidApp
class WulkanowyApp : Application(), Configuration.Provider { class WulkanowyApp : Application(), Configuration.Provider {
@Inject
lateinit var workerFactory: HiltWorkerFactory
@Inject @Inject
lateinit var themeManager: ThemeManager lateinit var themeManager: ThemeManager
@ -32,16 +37,21 @@ class WulkanowyApp : Application(), Configuration.Provider {
lateinit var analyticsHelper: AnalyticsHelper lateinit var analyticsHelper: AnalyticsHelper
@Inject @Inject
lateinit var adsHelper: AdsHelper lateinit var remoteConfigHelper: RemoteConfigHelper
@Inject @Inject
lateinit var remoteConfigHelper: RemoteConfigHelper lateinit var workerFactory: HiltWorkerFactory
override val workManagerConfiguration: Configuration
get() = Configuration.Builder()
.setWorkerFactory(workerFactory)
.setMinimumLoggingLevel(if (appInfo.isDebug) VERBOSE else INFO)
.build()
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
initializeAppLanguage() initializeAppLanguage()
themeManager.applyDefaultTheme() themeManager.applyDefaultTheme()
adsHelper.initialize()
remoteConfigHelper.initialize() remoteConfigHelper.initialize()
initLogging() initLogging()
} }
@ -74,9 +84,4 @@ class WulkanowyApp : Application(), Configuration.Provider {
analyticsHelper.logEvent("language", "startup" to preferencesRepository.appLanguage) analyticsHelper.logEvent("language", "startup" to preferencesRepository.appLanguage)
} }
} }
override fun getWorkManagerConfiguration() = Configuration.Builder()
.setWorkerFactory(workerFactory)
.setMinimumLoggingLevel(if (appInfo.isDebug) VERBOSE else INFO)
.build()
} }

View File

@ -5,7 +5,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration10 : Migration(9, 10) { class Migration10 : Migration(9, 10) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Grades_Summary RENAME TO GradesSummary") db.execSQL("ALTER TABLE Grades_Summary RENAME TO GradesSummary")
} }
} }

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration11 : Migration(10, 11) { class Migration11 : Migration(10, 11) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Grades_temp ( CREATE TABLE IF NOT EXISTS Grades_temp (
id INTEGER PRIMARY KEY NOT NULL, id INTEGER PRIMARY KEY NOT NULL,
is_read INTEGER NOT NULL, is_read INTEGER NOT NULL,
@ -26,9 +27,10 @@ class Migration11 : Migration(10, 11) {
date INTEGER NOT NULL, date INTEGER NOT NULL,
teacher TEXT NOT NULL teacher TEXT NOT NULL
) )
""") """
database.execSQL("INSERT INTO Grades_temp SELECT * FROM Grades") )
database.execSQL("DROP TABLE Grades") db.execSQL("INSERT INTO Grades_temp SELECT * FROM Grades")
database.execSQL("ALTER TABLE Grades_temp RENAME TO Grades") db.execSQL("DROP TABLE Grades")
db.execSQL("ALTER TABLE Grades_temp RENAME TO Grades")
} }
} }

View File

@ -5,16 +5,17 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration12 : Migration(11, 12) { class Migration12 : Migration(11, 12) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
createTempStudentsTable(database) createTempStudentsTable(db)
replaceStudentTable(database) replaceStudentTable(db)
updateStudentsWithClassId(database, getStudentsIds(database)) updateStudentsWithClassId(db, getStudentsIds(db))
removeStudentsWithNoClassId(database) removeStudentsWithNoClassId(db)
ensureThereIsOnlyOneCurrentStudent(database) ensureThereIsOnlyOneCurrentStudent(db)
} }
private fun createTempStudentsTable(database: SupportSQLiteDatabase) { private fun createTempStudentsTable(db: SupportSQLiteDatabase) {
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Students_tmp ( CREATE TABLE IF NOT EXISTS Students_tmp (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
endpoint TEXT NOT NULL, endpoint TEXT NOT NULL,
@ -30,15 +31,16 @@ class Migration12 : Migration(11, 12) {
registration_date INTEGER NOT NULL, registration_date INTEGER NOT NULL,
class_id INTEGER NOT NULL class_id INTEGER NOT NULL
) )
""") """
database.execSQL("CREATE UNIQUE INDEX index_Students_email_symbol_student_id_school_id_class_id ON Students_tmp (email, symbol, student_id, school_id, class_id)") )
db.execSQL("CREATE UNIQUE INDEX index_Students_email_symbol_student_id_school_id_class_id ON Students_tmp (email, symbol, student_id, school_id, class_id)")
} }
private fun replaceStudentTable(database: SupportSQLiteDatabase) { private fun replaceStudentTable(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN class_id INTEGER DEFAULT 0 NOT NULL") db.execSQL("ALTER TABLE Students ADD COLUMN class_id INTEGER DEFAULT 0 NOT NULL")
database.execSQL("INSERT INTO Students_tmp SELECT * FROM Students") db.execSQL("INSERT INTO Students_tmp SELECT * FROM Students")
database.execSQL("DROP TABLE Students") db.execSQL("DROP TABLE Students")
database.execSQL("ALTER TABLE Students_tmp RENAME TO Students") db.execSQL("ALTER TABLE Students_tmp RENAME TO Students")
} }
private fun getStudentsIds(database: SupportSQLiteDatabase): List<Int> { private fun getStudentsIds(database: SupportSQLiteDatabase): List<Int> {
@ -54,18 +56,18 @@ class Migration12 : Migration(11, 12) {
return students return students
} }
private fun updateStudentsWithClassId(database: SupportSQLiteDatabase, students: List<Int>) { private fun updateStudentsWithClassId(db: SupportSQLiteDatabase, students: List<Int>) {
students.forEach { students.forEach {
database.execSQL("UPDATE Students SET class_id = IFNULL((SELECT class_id FROM Semesters WHERE student_id = $it), 0) WHERE student_id = $it") db.execSQL("UPDATE Students SET class_id = IFNULL((SELECT class_id FROM Semesters WHERE student_id = $it), 0) WHERE student_id = $it")
} }
} }
private fun removeStudentsWithNoClassId(database: SupportSQLiteDatabase) { private fun removeStudentsWithNoClassId(db: SupportSQLiteDatabase) {
database.execSQL("DELETE FROM Students WHERE class_id = 0") db.execSQL("DELETE FROM Students WHERE class_id = 0")
} }
private fun ensureThereIsOnlyOneCurrentStudent(database: SupportSQLiteDatabase) { private fun ensureThereIsOnlyOneCurrentStudent(db: SupportSQLiteDatabase) {
database.execSQL("UPDATE Students SET is_current = 0") db.execSQL("UPDATE Students SET is_current = 0")
database.execSQL("UPDATE Students SET is_current = 1 WHERE id = (SELECT MAX(id) FROM Students)") db.execSQL("UPDATE Students SET is_current = 1 WHERE id = (SELECT MAX(id) FROM Students)")
} }
} }

View File

@ -5,27 +5,30 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration13 : Migration(12, 13) { class Migration13 : Migration(12, 13) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
addClassNameToStudents(database, getStudentsIds(database)) addClassNameToStudents(db, getStudentsIds(db))
updateSemestersTable(database) updateSemestersTable(db)
markAtLeastAndOnlyOneSemesterAtCurrent(database, getStudentsAndClassIds(database)) markAtLeastAndOnlyOneSemesterAtCurrent(db, getStudentsAndClassIds(db))
clearMessagesTable(database) clearMessagesTable(db)
} }
private fun addClassNameToStudents(database: SupportSQLiteDatabase, students: List<Pair<Int, String>>) { private fun addClassNameToStudents(
database.execSQL("ALTER TABLE Students ADD COLUMN class_name TEXT DEFAULT \"\" NOT NULL") db: SupportSQLiteDatabase,
students: List<Pair<Int, String>>
) {
db.execSQL("ALTER TABLE Students ADD COLUMN class_name TEXT DEFAULT \"\" NOT NULL")
students.forEach { (id, name) -> students.forEach { (id, name) ->
val schoolName = name.substringAfter(" - ") val schoolName = name.substringAfter(" - ")
val className = name.substringBefore(" - ", "").replace("Klasa ", "") val className = name.substringBefore(" - ", "").replace("Klasa ", "")
database.execSQL("UPDATE Students SET class_name = '$className' WHERE id = '$id'") db.execSQL("UPDATE Students SET class_name = '$className' WHERE id = '$id'")
database.execSQL("UPDATE Students SET school_name = '$schoolName' WHERE id = '$id'") db.execSQL("UPDATE Students SET school_name = '$schoolName' WHERE id = '$id'")
} }
} }
private fun getStudentsIds(database: SupportSQLiteDatabase): MutableList<Pair<Int, String>> { private fun getStudentsIds(db: SupportSQLiteDatabase): MutableList<Pair<Int, String>> {
val students = mutableListOf<Pair<Int, String>>() val students = mutableListOf<Pair<Int, String>>()
database.query("SELECT id, school_name FROM Students").use { db.query("SELECT id, school_name FROM Students").use {
if (it.moveToFirst()) { if (it.moveToFirst()) {
do { do {
students.add(it.getInt(0) to it.getString(1)) students.add(it.getInt(0) to it.getString(1))
@ -36,15 +39,15 @@ class Migration13 : Migration(12, 13) {
return students return students
} }
private fun updateSemestersTable(database: SupportSQLiteDatabase) { private fun updateSemestersTable(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Semesters ADD COLUMN school_year INTEGER DEFAULT 1970 NOT NULL") db.execSQL("ALTER TABLE Semesters ADD COLUMN school_year INTEGER DEFAULT 1970 NOT NULL")
database.execSQL("ALTER TABLE Semesters ADD COLUMN start INTEGER DEFAULT 0 NOT NULL") db.execSQL("ALTER TABLE Semesters ADD COLUMN start INTEGER DEFAULT 0 NOT NULL")
database.execSQL("ALTER TABLE Semesters ADD COLUMN `end` INTEGER DEFAULT 0 NOT NULL") db.execSQL("ALTER TABLE Semesters ADD COLUMN `end` INTEGER DEFAULT 0 NOT NULL")
} }
private fun getStudentsAndClassIds(database: SupportSQLiteDatabase): List<Pair<Int, Int>> { private fun getStudentsAndClassIds(db: SupportSQLiteDatabase): List<Pair<Int, Int>> {
val students = mutableListOf<Pair<Int, Int>>() val students = mutableListOf<Pair<Int, Int>>()
database.query("SELECT student_id, class_id FROM Students").use { db.query("SELECT student_id, class_id FROM Students").use {
if (it.moveToFirst()) { if (it.moveToFirst()) {
do { do {
students.add(it.getInt(0) to it.getInt(1)) students.add(it.getInt(0) to it.getInt(1))
@ -55,14 +58,17 @@ class Migration13 : Migration(12, 13) {
return students return students
} }
private fun markAtLeastAndOnlyOneSemesterAtCurrent(database: SupportSQLiteDatabase, students: List<Pair<Int, Int>>) { private fun markAtLeastAndOnlyOneSemesterAtCurrent(
db: SupportSQLiteDatabase,
students: List<Pair<Int, Int>>
) {
students.forEach { (studentId, classId) -> students.forEach { (studentId, classId) ->
database.execSQL("UPDATE Semesters SET is_current = 0 WHERE student_id = '$studentId' AND class_id = '$classId'") db.execSQL("UPDATE Semesters SET is_current = 0 WHERE student_id = '$studentId' AND class_id = '$classId'")
database.execSQL("UPDATE Semesters SET is_current = 1 WHERE id = (SELECT id FROM Semesters WHERE student_id = '$studentId' AND class_id = '$classId' ORDER BY semester_id DESC)") db.execSQL("UPDATE Semesters SET is_current = 1 WHERE id = (SELECT id FROM Semesters WHERE student_id = '$studentId' AND class_id = '$classId' ORDER BY semester_id DESC)")
} }
} }
private fun clearMessagesTable(database: SupportSQLiteDatabase) { private fun clearMessagesTable(db: SupportSQLiteDatabase) {
database.execSQL("DELETE FROM Messages") db.execSQL("DELETE FROM Messages")
} }
} }

View File

@ -5,9 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration14 : Migration(13, 14) { class Migration14 : Migration(13, 14) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS GradesSummary") db.execSQL("DROP TABLE IF EXISTS GradesSummary")
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS GradesSummary ( CREATE TABLE IF NOT EXISTS GradesSummary (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
semester_id INTEGER NOT NULL, semester_id INTEGER NOT NULL,

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration15 : Migration(14, 15) { class Migration15 : Migration(14, 15) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS MobileDevices ( CREATE TABLE IF NOT EXISTS MobileDevices (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL, student_id INTEGER NOT NULL,
@ -14,6 +15,7 @@ class Migration15 : Migration(14, 15) {
name TEXT NOT NULL, name TEXT NOT NULL,
date INTEGER NOT NULL date INTEGER NOT NULL
) )
""") """
)
} }
} }

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration16 : Migration(15, 16) { class Migration16 : Migration(15, 16) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Teachers ( CREATE TABLE IF NOT EXISTS Teachers (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL, student_id INTEGER NOT NULL,
@ -15,6 +16,7 @@ class Migration16 : Migration(15, 16) {
name TEXT NOT NULL, name TEXT NOT NULL,
short_name TEXT NOT NULL short_name TEXT NOT NULL
) )
""") """
)
} }
} }

View File

@ -5,13 +5,14 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration17 : Migration(16, 17) { class Migration17 : Migration(16, 17) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
createGradesPointsStatisticsTable(database) createGradesPointsStatisticsTable(db)
truncateSemestersTable(database) truncateSemestersTable(db)
} }
private fun createGradesPointsStatisticsTable(database: SupportSQLiteDatabase) { private fun createGradesPointsStatisticsTable(db: SupportSQLiteDatabase) {
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS GradesPointsStatistics( CREATE TABLE IF NOT EXISTS GradesPointsStatistics(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL, student_id INTEGER NOT NULL,
@ -20,10 +21,11 @@ class Migration17 : Migration(16, 17) {
others REAL NOT NULL, others REAL NOT NULL,
student REAL NOT NULL student REAL NOT NULL
) )
""") """
)
} }
private fun truncateSemestersTable(database: SupportSQLiteDatabase) { private fun truncateSemestersTable(db: SupportSQLiteDatabase) {
database.execSQL("DELETE FROM Semesters") db.execSQL("DELETE FROM Semesters")
} }
} }

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration18 : Migration(17, 18) { class Migration18 : Migration(17, 18) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS School ( CREATE TABLE IF NOT EXISTS School (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL, student_id INTEGER NOT NULL,

View File

@ -6,16 +6,17 @@ import io.github.wulkanowy.data.db.SharedPrefProvider
class Migration19(private val sharedPrefProvider: SharedPrefProvider) : Migration(18, 19) { class Migration19(private val sharedPrefProvider: SharedPrefProvider) : Migration(18, 19) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
migrateMessages(database) migrateMessages(db)
migrateGrades(database) migrateGrades(db)
migrateStudents(database) migrateStudents(db)
migrateSharedPreferences() migrateSharedPreferences()
} }
private fun migrateMessages(database: SupportSQLiteDatabase) { private fun migrateMessages(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE Messages") db.execSQL("DROP TABLE Messages")
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Messages ( CREATE TABLE IF NOT EXISTS Messages (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
is_notified INTEGER NOT NULL, is_notified INTEGER NOT NULL,
@ -34,12 +35,14 @@ class Migration19(private val sharedPrefProvider: SharedPrefProvider) : Migratio
read_by INTEGER NOT NULL, read_by INTEGER NOT NULL,
removed INTEGER NOT NULL removed INTEGER NOT NULL
) )
""") """
)
} }
private fun migrateGrades(database: SupportSQLiteDatabase) { private fun migrateGrades(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE Grades") db.execSQL("DROP TABLE Grades")
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Grades ( CREATE TABLE IF NOT EXISTS Grades (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
is_read INTEGER NOT NULL, is_read INTEGER NOT NULL,
@ -59,11 +62,13 @@ class Migration19(private val sharedPrefProvider: SharedPrefProvider) : Migratio
date INTEGER NOT NULL, date INTEGER NOT NULL,
teacher TEXT NOT NULL teacher TEXT NOT NULL
) )
""") """
)
} }
private fun migrateStudents(database: SupportSQLiteDatabase) { private fun migrateStudents(db: SupportSQLiteDatabase) {
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Students_tmp ( CREATE TABLE IF NOT EXISTS Students_tmp (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
scrapper_base_url TEXT NOT NULL, scrapper_base_url TEXT NOT NULL,
@ -86,26 +91,29 @@ class Migration19(private val sharedPrefProvider: SharedPrefProvider) : Migratio
is_current INTEGER NOT NULL, is_current INTEGER NOT NULL,
registration_date INTEGER NOT NULL registration_date INTEGER NOT NULL
) )
""") """
)
database.execSQL("ALTER TABLE Students ADD COLUMN scrapperBaseUrl TEXT NOT NULL DEFAULT \"\";") db.execSQL("ALTER TABLE Students ADD COLUMN scrapperBaseUrl TEXT NOT NULL DEFAULT \"\";")
database.execSQL("ALTER TABLE Students ADD COLUMN apiBaseUrl TEXT NOT NULL DEFAULT \"\";") db.execSQL("ALTER TABLE Students ADD COLUMN apiBaseUrl TEXT NOT NULL DEFAULT \"\";")
database.execSQL("ALTER TABLE Students ADD COLUMN is_parent INT NOT NULL DEFAULT 0;") db.execSQL("ALTER TABLE Students ADD COLUMN is_parent INT NOT NULL DEFAULT 0;")
database.execSQL("ALTER TABLE Students ADD COLUMN loginMode TEXT NOT NULL DEFAULT \"\";") db.execSQL("ALTER TABLE Students ADD COLUMN loginMode TEXT NOT NULL DEFAULT \"\";")
database.execSQL("ALTER TABLE Students ADD COLUMN certificateKey TEXT NOT NULL DEFAULT \"\";") db.execSQL("ALTER TABLE Students ADD COLUMN certificateKey TEXT NOT NULL DEFAULT \"\";")
database.execSQL("ALTER TABLE Students ADD COLUMN privateKey TEXT NOT NULL DEFAULT \"\";") db.execSQL("ALTER TABLE Students ADD COLUMN privateKey TEXT NOT NULL DEFAULT \"\";")
database.execSQL("ALTER TABLE Students ADD COLUMN user_login_id INTEGER NOT NULL DEFAULT 0;") db.execSQL("ALTER TABLE Students ADD COLUMN user_login_id INTEGER NOT NULL DEFAULT 0;")
database.execSQL(""" db.execSQL(
"""
INSERT INTO Students_tmp( INSERT INTO Students_tmp(
id, scrapper_base_url, mobile_base_url, is_parent, login_type, login_mode, certificate_key, private_key, email, password, symbol, student_id, user_login_id, student_name, school_id, school_name, school_id, school_name, class_name, class_id, is_current, registration_date) id, scrapper_base_url, mobile_base_url, is_parent, login_type, login_mode, certificate_key, private_key, email, password, symbol, student_id, user_login_id, student_name, school_id, school_name, school_id, school_name, class_name, class_id, is_current, registration_date)
SELECT SELECT
id, endpoint, apiBaseUrl, is_parent, loginType, "SCRAPPER", certificateKey, privateKey, email, password, symbol, student_id, user_login_id, student_name, school_id, school_name, school_id, school_name, class_name, class_id, is_current, registration_date id, endpoint, apiBaseUrl, is_parent, loginType, "SCRAPPER", certificateKey, privateKey, email, password, symbol, student_id, user_login_id, student_name, school_id, school_name, school_id, school_name, class_name, class_id, is_current, registration_date
FROM Students FROM Students
""") """
database.execSQL("DROP TABLE Students") )
database.execSQL("ALTER TABLE Students_tmp RENAME TO Students") db.execSQL("DROP TABLE Students")
database.execSQL("CREATE UNIQUE INDEX index_Students_email_symbol_student_id_school_id_class_id ON Students (email, symbol, student_id, school_id, class_id)") db.execSQL("ALTER TABLE Students_tmp RENAME TO Students")
db.execSQL("CREATE UNIQUE INDEX index_Students_email_symbol_student_id_school_id_class_id ON Students (email, symbol, student_id, school_id, class_id)")
} }
private fun migrateSharedPreferences() { private fun migrateSharedPreferences() {

View File

@ -5,14 +5,16 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration2 : Migration(1, 2) { class Migration2 : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS LuckyNumbers ( CREATE TABLE IF NOT EXISTS LuckyNumbers (
id INTEGER PRIMARY KEY NOT NULL, id INTEGER PRIMARY KEY NOT NULL,
is_notified INTEGER NOT NULL, is_notified INTEGER NOT NULL,
student_id INTEGER NOT NULL, student_id INTEGER NOT NULL,
date INTEGER NOT NULL, date INTEGER NOT NULL,
lucky_number INTEGER NOT NULL) lucky_number INTEGER NOT NULL)
""") """
)
} }
} }

View File

@ -5,14 +5,15 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration20 : Migration(19, 20) { class Migration20 : Migration(19, 20) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
migrateTimetable(database) migrateTimetable(db)
truncateSubjects(database) truncateSubjects(db)
} }
private fun migrateTimetable(database: SupportSQLiteDatabase) { private fun migrateTimetable(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE Timetable") db.execSQL("DROP TABLE Timetable")
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS `Timetable` ( CREATE TABLE IF NOT EXISTS `Timetable` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`student_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL,
@ -33,10 +34,11 @@ class Migration20 : Migration(19, 20) {
`changes` INTEGER NOT NULL, `changes` INTEGER NOT NULL,
`canceled` INTEGER NOT NULL `canceled` INTEGER NOT NULL
) )
""") """
)
} }
private fun truncateSubjects(database: SupportSQLiteDatabase) { private fun truncateSubjects(db: SupportSQLiteDatabase) {
database.execSQL("DELETE FROM Subjects") db.execSQL("DELETE FROM Subjects")
} }
} }

View File

@ -5,11 +5,11 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration21 : Migration(20, 21) { class Migration21 : Migration(20, 21) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Attendance ADD COLUMN excusable INTEGER NOT NULL DEFAULT 0") db.execSQL("ALTER TABLE Attendance ADD COLUMN excusable INTEGER NOT NULL DEFAULT 0")
database.execSQL("ALTER TABLE Attendance ADD COLUMN time_id INTEGER NOT NULL DEFAULT 0") db.execSQL("ALTER TABLE Attendance ADD COLUMN time_id INTEGER NOT NULL DEFAULT 0")
database.execSQL("ALTER TABLE Attendance ADD COLUMN excuse_status TEXT DEFAULT NULL") db.execSQL("ALTER TABLE Attendance ADD COLUMN excuse_status TEXT DEFAULT NULL")
database.execSQL("DELETE FROM Semesters") db.execSQL("DELETE FROM Semesters")
} }
} }

View File

@ -5,7 +5,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration22 : Migration(21, 22) { class Migration22 : Migration(21, 22) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN school_short TEXT NOT NULL DEFAULT ''") db.execSQL("ALTER TABLE Students ADD COLUMN school_short TEXT NOT NULL DEFAULT ''")
} }
} }

View File

@ -5,10 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration23 : Migration(22, 23) { class Migration23 : Migration(22, 23) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Notes ADD COLUMN teacher_symbol TEXT NOT NULL DEFAULT ''") db.execSQL("ALTER TABLE Notes ADD COLUMN teacher_symbol TEXT NOT NULL DEFAULT ''")
database.execSQL("ALTER TABLE Notes ADD COLUMN category_type INTEGER NOT NULL DEFAULT 0") db.execSQL("ALTER TABLE Notes ADD COLUMN category_type INTEGER NOT NULL DEFAULT 0")
database.execSQL("ALTER TABLE Notes ADD COLUMN is_points_show INTEGER NOT NULL DEFAULT 0") db.execSQL("ALTER TABLE Notes ADD COLUMN is_points_show INTEGER NOT NULL DEFAULT 0")
database.execSQL("ALTER TABLE Notes ADD COLUMN points INTEGER NOT NULL DEFAULT 0") db.execSQL("ALTER TABLE Notes ADD COLUMN points INTEGER NOT NULL DEFAULT 0")
} }
} }

View File

@ -5,9 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration24 : Migration(23, 24) { class Migration24 : Migration(23, 24) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Messages ADD COLUMN has_attachments INTEGER NOT NULL DEFAULT 0") db.execSQL("ALTER TABLE Messages ADD COLUMN has_attachments INTEGER NOT NULL DEFAULT 0")
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS MessageAttachments ( CREATE TABLE IF NOT EXISTS MessageAttachments (
real_id INTEGER NOT NULL, real_id INTEGER NOT NULL,
message_id INTEGER NOT NULL, message_id INTEGER NOT NULL,
@ -16,6 +17,7 @@ class Migration24 : Migration(23, 24) {
filename TEXT NOT NULL, filename TEXT NOT NULL,
PRIMARY KEY(real_id) PRIMARY KEY(real_id)
) )
""") """
)
} }
} }

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration25 : Migration(24, 25) { class Migration25 : Migration(24, 25) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Homework ADD COLUMN is_done INTEGER NOT NULL DEFAULT 0") db.execSQL("ALTER TABLE Homework ADD COLUMN is_done INTEGER NOT NULL DEFAULT 0")
database.execSQL("ALTER TABLE Homework ADD COLUMN attachments TEXT NOT NULL DEFAULT \"[]\"") db.execSQL("ALTER TABLE Homework ADD COLUMN attachments TEXT NOT NULL DEFAULT \"[]\"")
} }
} }

View File

@ -5,10 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration26 : Migration(25, 26) { class Migration26 : Migration(25, 26) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE GradesSummary ADD COLUMN is_predicted_grade_notified INTEGER NOT NULL DEFAULT 1") db.execSQL("ALTER TABLE GradesSummary ADD COLUMN is_predicted_grade_notified INTEGER NOT NULL DEFAULT 1")
database.execSQL("ALTER TABLE GradesSummary ADD COLUMN is_final_grade_notified INTEGER NOT NULL DEFAULT 1") db.execSQL("ALTER TABLE GradesSummary ADD COLUMN is_final_grade_notified INTEGER NOT NULL DEFAULT 1")
database.execSQL("ALTER TABLE GradesSummary ADD COLUMN predicted_grade_last_change INTEGER NOT NULL DEFAULT 0") db.execSQL("ALTER TABLE GradesSummary ADD COLUMN predicted_grade_last_change INTEGER NOT NULL DEFAULT 0")
database.execSQL("ALTER TABLE GradesSummary ADD COLUMN final_grade_last_change INTEGER NOT NULL DEFAULT 0") db.execSQL("ALTER TABLE GradesSummary ADD COLUMN final_grade_last_change INTEGER NOT NULL DEFAULT 0")
} }
} }

View File

@ -5,24 +5,25 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration27 : Migration(26, 27) { class Migration27 : Migration(26, 27) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN user_name TEXT NOT NULL DEFAULT \"\"") db.execSQL("ALTER TABLE Students ADD COLUMN user_name TEXT NOT NULL DEFAULT \"\"")
val students = getStudentsIdsAndNames(database) val students = getStudentsIdsAndNames(db)
val units = getReportingUnits(database) val units = getReportingUnits(db)
students.forEach { (id, userLoginId, studentName) -> students.forEach { (id, userLoginId, studentName) ->
val userNameFromUnits = units.singleOrNull { (senderId, _) -> senderId == userLoginId }?.second val userNameFromUnits =
units.singleOrNull { (senderId, _) -> senderId == userLoginId }?.second
val normalizedStudentName = studentName.split(" ").asReversed().joinToString(" ") val normalizedStudentName = studentName.split(" ").asReversed().joinToString(" ")
val userName = userNameFromUnits ?: normalizedStudentName val userName = userNameFromUnits ?: normalizedStudentName
database.execSQL("UPDATE Students SET user_name = '$userName' WHERE id = '$id'") db.execSQL("UPDATE Students SET user_name = '$userName' WHERE id = '$id'")
} }
} }
private fun getStudentsIdsAndNames(database: SupportSQLiteDatabase): MutableList<Triple<Long, Int, String>> { private fun getStudentsIdsAndNames(db: SupportSQLiteDatabase): MutableList<Triple<Long, Int, String>> {
val students = mutableListOf<Triple<Long, Int, String>>() val students = mutableListOf<Triple<Long, Int, String>>()
database.query("SELECT id, user_login_id, student_name FROM Students").use { db.query("SELECT id, user_login_id, student_name FROM Students").use {
if (it.moveToFirst()) { if (it.moveToFirst()) {
do { do {
students.add(Triple(it.getLong(0), it.getInt(1), it.getString(2))) students.add(Triple(it.getLong(0), it.getInt(1), it.getString(2)))
@ -33,9 +34,9 @@ class Migration27 : Migration(26, 27) {
return students return students
} }
private fun getReportingUnits(database: SupportSQLiteDatabase): MutableList<Pair<Int, String>> { private fun getReportingUnits(db: SupportSQLiteDatabase): MutableList<Pair<Int, String>> {
val units = mutableListOf<Pair<Int, String>>() val units = mutableListOf<Pair<Int, String>>()
database.query("SELECT sender_id, sender_name FROM ReportingUnits").use { db.query("SELECT sender_id, sender_name FROM ReportingUnits").use {
if (it.moveToFirst()) { if (it.moveToFirst()) {
do { do {
units.add(it.getInt(0) to it.getString(1)) units.add(it.getInt(0) to it.getString(1))

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration28 : Migration(27, 28) { class Migration28 : Migration(27, 28) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Conferences ( CREATE TABLE IF NOT EXISTS Conferences (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL, student_id INTEGER NOT NULL,

View File

@ -5,9 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration29 : Migration(28, 29) { class Migration29 : Migration(28, 29) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS GradesStatistics") db.execSQL("DROP TABLE IF EXISTS GradesStatistics")
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS GradeSemesterStatistics ( CREATE TABLE IF NOT EXISTS GradeSemesterStatistics (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL, student_id INTEGER NOT NULL,
@ -16,8 +17,10 @@ class Migration29 : Migration(28, 29) {
amounts TEXT NOT NULL, amounts TEXT NOT NULL,
student_grade INTEGER NOT NULL student_grade INTEGER NOT NULL
) )
""") """
database.execSQL(""" )
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS GradePartialStatistics ( CREATE TABLE IF NOT EXISTS GradePartialStatistics (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL, student_id INTEGER NOT NULL,

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration3 : Migration(2, 3) { class Migration3 : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS CompletedLesson ( CREATE TABLE IF NOT EXISTS CompletedLesson (
id INTEGER PRIMARY KEY NOT NULL, id INTEGER PRIMARY KEY NOT NULL,
student_id INTEGER NOT NULL, student_id INTEGER NOT NULL,

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration30 : Migration(29, 30) { class Migration30 : Migration(29, 30) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL(""" db.execSQL(
"""
CREATE TABLE TimetableAdditional ( CREATE TABLE TimetableAdditional (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL, student_id INTEGER NOT NULL,
@ -16,6 +17,7 @@ class Migration30 : Migration(29, 30) {
date INTEGER NOT NULL, date INTEGER NOT NULL,
subject TEXT NOT NULL subject TEXT NOT NULL
) )
""") """
)
} }
} }

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration31 : Migration(30, 31) { class Migration31 : Migration(30, 31) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL( db.execSQL(
"""CREATE TABLE IF NOT EXISTS StudentInfo ( """CREATE TABLE IF NOT EXISTS StudentInfo (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL, student_id INTEGER NOT NULL,

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration32 : Migration(31, 32) { class Migration32 : Migration(31, 32) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN nick TEXT NOT NULL DEFAULT \"\"") db.execSQL("ALTER TABLE Students ADD COLUMN nick TEXT NOT NULL DEFAULT \"\"")
} }
} }

View File

@ -5,10 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration33 : Migration(32, 33) { class Migration33 : Migration(32, 33) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS StudentInfo") db.execSQL("DROP TABLE IF EXISTS StudentInfo")
database.execSQL( db.execSQL(
"""CREATE TABLE IF NOT EXISTS StudentInfo ( """CREATE TABLE IF NOT EXISTS StudentInfo (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL, student_id INTEGER NOT NULL,

View File

@ -5,9 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration34 : Migration(33, 34) { class Migration34 : Migration(33, 34) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("DELETE FROM ReportingUnits") db.execSQL("DELETE FROM ReportingUnits")
database.execSQL("DELETE FROM Recipients") db.execSQL("DELETE FROM Recipients")
} }
} }

View File

@ -7,13 +7,13 @@ import io.github.wulkanowy.utils.AppInfo
class Migration35(private val appInfo: AppInfo) : Migration(34, 35) { class Migration35(private val appInfo: AppInfo) : Migration(34, 35) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN `avatar_color` INTEGER NOT NULL DEFAULT 0") db.execSQL("ALTER TABLE Students ADD COLUMN `avatar_color` INTEGER NOT NULL DEFAULT 0")
database.query("SELECT * FROM Students").use { db.query("SELECT * FROM Students").use {
while (it.moveToNext()) { while (it.moveToNext()) {
val studentId = it.getLongOrNull(0) val studentId = it.getLongOrNull(0)
database.execSQL( db.execSQL(
""" """
UPDATE Students UPDATE Students
SET avatar_color = ${appInfo.defaultColorsForAvatar.random()} SET avatar_color = ${appInfo.defaultColorsForAvatar.random()}

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration36 : Migration(35, 36) { class Migration36 : Migration(35, 36) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Exams ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1") db.execSQL("ALTER TABLE Exams ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
database.execSQL("ALTER TABLE Homework ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1") db.execSQL("ALTER TABLE Homework ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
} }
} }

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration37 : Migration(36, 37) { class Migration37 : Migration(36, 37) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL( db.execSQL(
""" """
CREATE TABLE IF NOT EXISTS TimetableHeaders ( CREATE TABLE IF NOT EXISTS TimetableHeaders (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration38 : Migration(37, 38) { class Migration38 : Migration(37, 38) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS `SchoolAnnouncements` ( CREATE TABLE IF NOT EXISTS `SchoolAnnouncements` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`student_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL,
@ -14,6 +15,7 @@ class Migration38 : Migration(37, 38) {
`subject` TEXT NOT NULL, `subject` TEXT NOT NULL,
`content` TEXT NOT NULL `content` TEXT NOT NULL
) )
""") """
)
} }
} }

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration39 : Migration(38, 39) { class Migration39 : Migration(38, 39) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Conferences ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1") db.execSQL("ALTER TABLE Conferences ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
database.execSQL("ALTER TABLE SchoolAnnouncements ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1") db.execSQL("ALTER TABLE SchoolAnnouncements ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
} }
} }

View File

@ -5,9 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration4 : Migration(3, 4) { class Migration4 : Migration(3, 4) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Messages") db.execSQL("DROP TABLE IF EXISTS Messages")
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Messages ( CREATE TABLE IF NOT EXISTS Messages (
id INTEGER PRIMARY KEY NOT NULL, id INTEGER PRIMARY KEY NOT NULL,
is_notified INTEGER NOT NULL, is_notified INTEGER NOT NULL,

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration40 : Migration(39, 40) { class Migration40 : Migration(39, 40) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL( db.execSQL(
""" """
CREATE TABLE IF NOT EXISTS `Notifications` ( CREATE TABLE IF NOT EXISTS `Notifications` (
`student_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL,

View File

@ -7,9 +7,9 @@ import io.github.wulkanowy.data.enums.GradeExpandMode
class Migration41(private val sharedPrefProvider: SharedPrefProvider) : Migration(40, 41) { class Migration41(private val sharedPrefProvider: SharedPrefProvider) : Migration(40, 41) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
migrateSharedPreferences() migrateSharedPreferences()
database.execSQL("ALTER TABLE Homework ADD COLUMN is_added_by_user INTEGER NOT NULL DEFAULT 0") db.execSQL("ALTER TABLE Homework ADD COLUMN is_added_by_user INTEGER NOT NULL DEFAULT 0")
} }
private fun migrateSharedPreferences() { private fun migrateSharedPreferences() {

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration42 : Migration(41, 42) { class Migration42 : Migration(41, 42) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL( db.execSQL(
"""CREATE TABLE IF NOT EXISTS `AdminMessages` ( """CREATE TABLE IF NOT EXISTS `AdminMessages` (
`id` INTEGER NOT NULL, `id` INTEGER NOT NULL,
`title` TEXT NOT NULL, `title` TEXT NOT NULL,

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration43 : Migration(42, 43) { class Migration43 : Migration(42, 43) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Timetable ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1") db.execSQL("ALTER TABLE Timetable ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
database.execSQL("ALTER TABLE Attendance ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1") db.execSQL("ALTER TABLE Attendance ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
} }
} }

View File

@ -5,7 +5,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration44 : Migration(43, 44) { class Migration44 : Migration(43, 44) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE AdminMessages ADD COLUMN is_dismissible INTEGER NOT NULL DEFAULT 0") db.execSQL("ALTER TABLE AdminMessages ADD COLUMN is_dismissible INTEGER NOT NULL DEFAULT 0")
} }
} }

View File

@ -8,65 +8,65 @@ import java.time.ZoneOffset
class Migration46 : Migration(45, 46) { class Migration46 : Migration(45, 46) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
migrateConferences(database) migrateConferences(db)
migrateMessages(database) migrateMessages(db)
migrateMobileDevices(database) migrateMobileDevices(db)
migrateNotifications(database) migrateNotifications(db)
migrateTimetable(database) migrateTimetable(db)
migrateTimetableAdditional(database) migrateTimetableAdditional(db)
} }
private fun migrateConferences(database: SupportSQLiteDatabase) { private fun migrateConferences(db: SupportSQLiteDatabase) {
database.query("SELECT * FROM Conferences").use { db.query("SELECT * FROM Conferences").use {
while (it.moveToNext()) { while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id")) val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date")) val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date"))
val timestampUtc = timestampLocal.timestampLocalToUTC() val timestampUtc = timestampLocal.timestampLocalToUTC()
database.execSQL("UPDATE Conferences SET date = $timestampUtc WHERE id = $id") db.execSQL("UPDATE Conferences SET date = $timestampUtc WHERE id = $id")
} }
} }
} }
private fun migrateMessages(database: SupportSQLiteDatabase) { private fun migrateMessages(db: SupportSQLiteDatabase) {
database.query("SELECT * FROM Messages").use { db.query("SELECT * FROM Messages").use {
while (it.moveToNext()) { while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id")) val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date")) val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date"))
val timestampUtc = timestampLocal.timestampLocalToUTC() val timestampUtc = timestampLocal.timestampLocalToUTC()
database.execSQL("UPDATE Messages SET date = $timestampUtc WHERE id = $id") db.execSQL("UPDATE Messages SET date = $timestampUtc WHERE id = $id")
} }
} }
} }
private fun migrateMobileDevices(database: SupportSQLiteDatabase) { private fun migrateMobileDevices(db: SupportSQLiteDatabase) {
database.query("SELECT * FROM MobileDevices").use { db.query("SELECT * FROM MobileDevices").use {
while (it.moveToNext()) { while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id")) val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date")) val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date"))
val timestampUtc = timestampLocal.timestampLocalToUTC() val timestampUtc = timestampLocal.timestampLocalToUTC()
database.execSQL("UPDATE MobileDevices SET date = $timestampUtc WHERE id = $id") db.execSQL("UPDATE MobileDevices SET date = $timestampUtc WHERE id = $id")
} }
} }
} }
private fun migrateNotifications(database: SupportSQLiteDatabase) { private fun migrateNotifications(db: SupportSQLiteDatabase) {
database.query("SELECT * FROM Notifications").use { db.query("SELECT * FROM Notifications").use {
while (it.moveToNext()) { while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id")) val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date")) val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date"))
val timestampUtc = timestampLocal.timestampLocalToUTC() val timestampUtc = timestampLocal.timestampLocalToUTC()
database.execSQL("UPDATE Notifications SET date = $timestampUtc WHERE id = $id") db.execSQL("UPDATE Notifications SET date = $timestampUtc WHERE id = $id")
} }
} }
} }
private fun migrateTimetable(database: SupportSQLiteDatabase) { private fun migrateTimetable(db: SupportSQLiteDatabase) {
database.query("SELECT * FROM Timetable").use { db.query("SELECT * FROM Timetable").use {
while (it.moveToNext()) { while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id")) val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocalStart = it.getLong(it.getColumnIndexOrThrow("start")) val timestampLocalStart = it.getLong(it.getColumnIndexOrThrow("start"))
@ -74,13 +74,13 @@ class Migration46 : Migration(45, 46) {
val timestampUtcStart = timestampLocalStart.timestampLocalToUTC() val timestampUtcStart = timestampLocalStart.timestampLocalToUTC()
val timestampUtcEnd = timestampLocalEnd.timestampLocalToUTC() val timestampUtcEnd = timestampLocalEnd.timestampLocalToUTC()
database.execSQL("UPDATE Timetable SET start = $timestampUtcStart, end = $timestampUtcEnd WHERE id = $id") db.execSQL("UPDATE Timetable SET start = $timestampUtcStart, end = $timestampUtcEnd WHERE id = $id")
} }
} }
} }
private fun migrateTimetableAdditional(database: SupportSQLiteDatabase) { private fun migrateTimetableAdditional(db: SupportSQLiteDatabase) {
database.query("SELECT * FROM TimetableAdditional").use { db.query("SELECT * FROM TimetableAdditional").use {
while (it.moveToNext()) { while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id")) val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocalStart = it.getLong(it.getColumnIndexOrThrow("start")) val timestampLocalStart = it.getLong(it.getColumnIndexOrThrow("start"))
@ -88,7 +88,7 @@ class Migration46 : Migration(45, 46) {
val timestampUtcStart = timestampLocalStart.timestampLocalToUTC() val timestampUtcStart = timestampLocalStart.timestampLocalToUTC()
val timestampUtcEnd = timestampLocalEnd.timestampLocalToUTC() val timestampUtcEnd = timestampLocalEnd.timestampLocalToUTC()
database.execSQL("UPDATE TimetableAdditional SET start = $timestampUtcStart, end = $timestampUtcEnd WHERE id = $id") db.execSQL("UPDATE TimetableAdditional SET start = $timestampUtcStart, end = $timestampUtcEnd WHERE id = $id")
} }
} }
} }

View File

@ -5,10 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration49 : Migration(48, 49) { class Migration49 : Migration(48, 49) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS SchoolAnnouncements") db.execSQL("DROP TABLE IF EXISTS SchoolAnnouncements")
database.execSQL( db.execSQL(
""" """
CREATE TABLE IF NOT EXISTS `SchoolAnnouncements` ( CREATE TABLE IF NOT EXISTS `SchoolAnnouncements` (
`user_login_id` INTEGER NOT NULL, `user_login_id` INTEGER NOT NULL,

View File

@ -7,11 +7,16 @@ import java.time.ZoneOffset
class Migration5 : Migration(4, 5) { class Migration5 : Migration(4, 5) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN registration_date INTEGER DEFAULT 0 NOT NULL") db.execSQL("ALTER TABLE Students ADD COLUMN registration_date INTEGER DEFAULT 0 NOT NULL")
database.execSQL("UPDATE Students SET registration_date = '${now().atZone(ZoneOffset.UTC).toInstant().toEpochMilli()}'") db.execSQL(
database.execSQL("DROP TABLE IF EXISTS Notes") "UPDATE Students SET registration_date = '${
database.execSQL(""" now().atZone(ZoneOffset.UTC).toInstant().toEpochMilli()
}'"
)
db.execSQL("DROP TABLE IF EXISTS Notes")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Notes ( CREATE TABLE IF NOT EXISTS Notes (
id INTEGER PRIMARY KEY NOT NULL, id INTEGER PRIMARY KEY NOT NULL,
is_read INTEGER NOT NULL, is_read INTEGER NOT NULL,
@ -21,6 +26,7 @@ class Migration5 : Migration(4, 5) {
teacher TEXT NOT NULL, teacher TEXT NOT NULL,
category TEXT NOT NULL, category TEXT NOT NULL,
content TEXT NOT NULL) content TEXT NOT NULL)
""") """
)
} }
} }

View File

@ -5,9 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration50 : Migration(49, 50) { class Migration50 : Migration(49, 50) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS MobileDevices") db.execSQL("DROP TABLE IF EXISTS MobileDevices")
database.execSQL( db.execSQL(
""" """
CREATE TABLE IF NOT EXISTS `MobileDevices` ( CREATE TABLE IF NOT EXISTS `MobileDevices` (
`user_login_id` INTEGER NOT NULL, `user_login_id` INTEGER NOT NULL,

View File

@ -5,17 +5,17 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration51 : Migration(50, 51) { class Migration51 : Migration(50, 51) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
createMailboxTable(database) createMailboxTable(db)
recreateMessagesTable(database) recreateMessagesTable(db)
recreateMessageAttachmentsTable(database) recreateMessageAttachmentsTable(db)
recreateRecipientsTable(database) recreateRecipientsTable(db)
deleteReportingUnitTable(database) deleteReportingUnitTable(db)
} }
private fun createMailboxTable(database: SupportSQLiteDatabase) { private fun createMailboxTable(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Mailboxes") db.execSQL("DROP TABLE IF EXISTS Mailboxes")
database.execSQL( db.execSQL(
""" """
CREATE TABLE IF NOT EXISTS `Mailboxes` ( CREATE TABLE IF NOT EXISTS `Mailboxes` (
`globalKey` TEXT NOT NULL, `globalKey` TEXT NOT NULL,
@ -30,9 +30,9 @@ class Migration51 : Migration(50, 51) {
) )
} }
private fun recreateMessagesTable(database: SupportSQLiteDatabase) { private fun recreateMessagesTable(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Messages") db.execSQL("DROP TABLE IF EXISTS Messages")
database.execSQL( db.execSQL(
""" """
CREATE TABLE IF NOT EXISTS `Messages` ( CREATE TABLE IF NOT EXISTS `Messages` (
`message_global_key` TEXT NOT NULL, `message_global_key` TEXT NOT NULL,
@ -52,9 +52,9 @@ class Migration51 : Migration(50, 51) {
) )
} }
private fun recreateMessageAttachmentsTable(database: SupportSQLiteDatabase) { private fun recreateMessageAttachmentsTable(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS MessageAttachments") db.execSQL("DROP TABLE IF EXISTS MessageAttachments")
database.execSQL( db.execSQL(
""" """
CREATE TABLE IF NOT EXISTS `MessageAttachments` ( CREATE TABLE IF NOT EXISTS `MessageAttachments` (
`real_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL,
@ -66,9 +66,9 @@ class Migration51 : Migration(50, 51) {
) )
} }
private fun recreateRecipientsTable(database: SupportSQLiteDatabase) { private fun recreateRecipientsTable(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Recipients") db.execSQL("DROP TABLE IF EXISTS Recipients")
database.execSQL( db.execSQL(
""" """
CREATE TABLE IF NOT EXISTS `Recipients` ( CREATE TABLE IF NOT EXISTS `Recipients` (
`mailboxGlobalKey` TEXT NOT NULL, `mailboxGlobalKey` TEXT NOT NULL,
@ -82,7 +82,7 @@ class Migration51 : Migration(50, 51) {
) )
} }
private fun deleteReportingUnitTable(database: SupportSQLiteDatabase) { private fun deleteReportingUnitTable(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS ReportingUnits") db.execSQL("DROP TABLE IF EXISTS ReportingUnits")
} }
} }

View File

@ -5,14 +5,14 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration53 : Migration(52, 53) { class Migration53 : Migration(52, 53) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
createMailboxTable(database) createMailboxTable(db)
recreateMessagesTable(database) recreateMessagesTable(db)
} }
private fun createMailboxTable(database: SupportSQLiteDatabase) { private fun createMailboxTable(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Mailboxes") db.execSQL("DROP TABLE IF EXISTS Mailboxes")
database.execSQL( db.execSQL(
""" """
CREATE TABLE IF NOT EXISTS `Mailboxes` ( CREATE TABLE IF NOT EXISTS `Mailboxes` (
`globalKey` TEXT NOT NULL, `globalKey` TEXT NOT NULL,
@ -29,9 +29,9 @@ class Migration53 : Migration(52, 53) {
) )
} }
private fun recreateMessagesTable(database: SupportSQLiteDatabase) { private fun recreateMessagesTable(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Messages") db.execSQL("DROP TABLE IF EXISTS Messages")
database.execSQL( db.execSQL(
""" """
CREATE TABLE IF NOT EXISTS `Messages` ( CREATE TABLE IF NOT EXISTS `Messages` (
`email` TEXT NOT NULL, `email` TEXT NOT NULL,

View File

@ -5,22 +5,24 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration54 : Migration(53, 54) { class Migration54 : Migration(53, 54) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
migrateResman(database) migrateResman(db)
removeTomaszowMazowieckiStudents(database) removeTomaszowMazowieckiStudents(db)
} }
private fun migrateResman(database: SupportSQLiteDatabase) { private fun migrateResman(db: SupportSQLiteDatabase) {
database.execSQL(""" db.execSQL(
"""
UPDATE Students SET UPDATE Students SET
scrapper_base_url = 'https://vulcan.net.pl', scrapper_base_url = 'https://vulcan.net.pl',
login_type = 'ADFSLightScoped', login_type = 'ADFSLightScoped',
symbol = 'rzeszowprojekt' symbol = 'rzeszowprojekt'
WHERE scrapper_base_url = 'https://resman.pl' WHERE scrapper_base_url = 'https://resman.pl'
""".trimIndent()) """.trimIndent()
)
} }
private fun removeTomaszowMazowieckiStudents(database: SupportSQLiteDatabase) { private fun removeTomaszowMazowieckiStudents(db: SupportSQLiteDatabase) {
database.execSQL("DELETE FROM Students WHERE symbol = 'tomaszowmazowiecki'") db.execSQL("DELETE FROM Students WHERE symbol = 'tomaszowmazowiecki'")
} }
} }

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration6 : Migration(5, 6) { class Migration6 : Migration(5, 6) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS ReportingUnits ( CREATE TABLE IF NOT EXISTS ReportingUnits (
id INTEGER PRIMARY KEY NOT NULL, id INTEGER PRIMARY KEY NOT NULL,
student_id INTEGER NOT NULL, student_id INTEGER NOT NULL,
@ -15,9 +16,11 @@ class Migration6 : Migration(5, 6) {
sender_id INTEGER NOT NULL, sender_id INTEGER NOT NULL,
sender_name TEXT NOT NULL, sender_name TEXT NOT NULL,
roles TEXT NOT NULL) roles TEXT NOT NULL)
""") """
)
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Recipients ( CREATE TABLE IF NOT EXISTS Recipients (
id INTEGER PRIMARY KEY NOT NULL, id INTEGER PRIMARY KEY NOT NULL,
student_id INTEGER NOT NULL, student_id INTEGER NOT NULL,
@ -28,10 +31,11 @@ class Migration6 : Migration(5, 6) {
unit_id INTEGER NOT NULL, unit_id INTEGER NOT NULL,
role INTEGER NOT NULL, role INTEGER NOT NULL,
hash TEXT NOT NULL) hash TEXT NOT NULL)
""") """
)
database.execSQL("DELETE FROM Semesters WHERE 1") db.execSQL("DELETE FROM Semesters WHERE 1")
database.execSQL("ALTER TABLE Semesters ADD COLUMN class_id INTEGER DEFAULT 0 NOT NULL") db.execSQL("ALTER TABLE Semesters ADD COLUMN class_id INTEGER DEFAULT 0 NOT NULL")
database.execSQL("ALTER TABLE Semesters ADD COLUMN unit_id INTEGER DEFAULT 0 NOT NULL") db.execSQL("ALTER TABLE Semesters ADD COLUMN unit_id INTEGER DEFAULT 0 NOT NULL")
} }
} }

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration7 : Migration(6, 7) { class Migration7 : Migration(6, 7) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS GradesStatistics ( CREATE TABLE IF NOT EXISTS GradesStatistics (
id INTEGER PRIMARY KEY NOT NULL, id INTEGER PRIMARY KEY NOT NULL,
student_id INTEGER NOT NULL, student_id INTEGER NOT NULL,
@ -15,6 +16,7 @@ class Migration7 : Migration(6, 7) {
grade INTEGER NOT NULL, grade INTEGER NOT NULL,
amount INTEGER NOT NULL, amount INTEGER NOT NULL,
is_semester INTEGER NOT NULL) is_semester INTEGER NOT NULL)
""") """
)
} }
} }

View File

@ -5,9 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration8 : Migration(7, 8) { class Migration8 : Migration(7, 8) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Timetable ADD COLUMN subjectOld TEXT DEFAULT \"\" NOT NULL") db.execSQL("ALTER TABLE Timetable ADD COLUMN subjectOld TEXT DEFAULT \"\" NOT NULL")
database.execSQL("ALTER TABLE Timetable ADD COLUMN roomOld TEXT DEFAULT \"\" NOT NULL") db.execSQL("ALTER TABLE Timetable ADD COLUMN roomOld TEXT DEFAULT \"\" NOT NULL")
database.execSQL("ALTER TABLE Timetable ADD COLUMN teacherOld TEXT DEFAULT \"\" NOT NULL") db.execSQL("ALTER TABLE Timetable ADD COLUMN teacherOld TEXT DEFAULT \"\" NOT NULL")
} }
} }

View File

@ -5,9 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration9 : Migration(8, 9) { class Migration9 : Migration(8, 9) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(db: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Messages") db.execSQL("DROP TABLE IF EXISTS Messages")
database.execSQL(""" db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Messages ( CREATE TABLE IF NOT EXISTS Messages (
id INTEGER PRIMARY KEY NOT NULL, id INTEGER PRIMARY KEY NOT NULL,
student_id INTEGER NOT NULL, student_id INTEGER NOT NULL,

View File

@ -9,7 +9,12 @@ import com.fredporciuncula.flow.preferences.Preference
import com.fredporciuncula.flow.preferences.Serializer import com.fredporciuncula.flow.preferences.Serializer
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.data.enums.* import io.github.wulkanowy.data.enums.AppTheme
import io.github.wulkanowy.data.enums.GradeColorTheme
import io.github.wulkanowy.data.enums.GradeExpandMode
import io.github.wulkanowy.data.enums.GradeSortingMode
import io.github.wulkanowy.data.enums.TimetableGapsMode
import io.github.wulkanowy.data.enums.TimetableMode
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
import io.github.wulkanowy.ui.modules.settings.appearance.menuorder.AppMenuItem import io.github.wulkanowy.ui.modules.settings.appearance.menuorder.AppMenuItem
@ -18,7 +23,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import java.time.Instant import java.time.Instant
import java.util.* import java.util.UUID
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -194,12 +199,6 @@ class PreferencesRepository @Inject constructor(
) )
) )
val showTimetableTimers: Boolean
get() = getBoolean(
R.string.pref_key_timetable_show_timers,
R.bool.pref_default_timetable_show_timers
)
val showTimetableGaps: TimetableGapsMode val showTimetableGaps: TimetableGapsMode
get() = TimetableGapsMode.getByValue( get() = TimetableGapsMode.getByValue(
getString( getString(
@ -309,19 +308,6 @@ class PreferencesRepository @Inject constructor(
get() = sharedPref.getBoolean(PREF_KEY_APP_SUPPORT_SHOWN, false) get() = sharedPref.getBoolean(PREF_KEY_APP_SUPPORT_SHOWN, false)
set(value) = sharedPref.edit { putBoolean(PREF_KEY_APP_SUPPORT_SHOWN, value) } 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( val isAdsEnabledFlow = flowSharedPref.getBoolean(
context.getString(R.string.pref_key_ads_enabled), context.getString(R.string.pref_key_ads_enabled),
context.resources.getBoolean(R.bool.pref_default_ads_enabled) context.resources.getBoolean(R.bool.pref_default_ads_enabled)
@ -404,7 +390,6 @@ class PreferencesRepository @Inject constructor(
private const val PREF_KEY_IN_APP_REVIEW_DATE = "in_app_review_date" private const val PREF_KEY_IN_APP_REVIEW_DATE = "in_app_review_date"
private const val PREF_KEY_IN_APP_REVIEW_DONE = "in_app_review_done" private const val PREF_KEY_IN_APP_REVIEW_DONE = "in_app_review_done"
private const val PREF_KEY_APP_SUPPORT_SHOWN = "app_support_shown" private const val PREF_KEY_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"
} }
} }

View File

@ -148,6 +148,10 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag
binding.attendanceNavDate.text = date binding.attendanceNavDate.text = date
} }
override fun showNavigation(show: Boolean) {
binding.attendanceNavContainer.isVisible = show
}
override fun clearData() { override fun clearData() {
with(attendanceAdapter) { with(attendanceAdapter) {
items = emptyList() items = emptyList()
@ -281,7 +285,9 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay()) presenter.currentDate?.let {
outState.putLong(SAVED_DATE_KEY, it.toEpochDay())
}
} }
override fun onDestroyView() { override fun onDestroyView() {

View File

@ -3,10 +3,14 @@ package io.github.wulkanowy.ui.modules.attendance
import android.annotation.SuppressLint import android.annotation.SuppressLint
import io.github.wulkanowy.data.* import io.github.wulkanowy.data.*
import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.repositories.AttendanceRepository import io.github.wulkanowy.data.repositories.AttendanceRepository
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
import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.data.repositories.TimetableRepository
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.* import io.github.wulkanowy.utils.*
@ -14,6 +18,7 @@ import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import timber.log.Timber import timber.log.Timber
import java.time.DayOfWeek
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDate.now import java.time.LocalDate.now
import java.time.LocalDate.ofEpochDay import java.time.LocalDate.ofEpochDay
@ -28,9 +33,10 @@ class AttendancePresenter @Inject constructor(
private val analytics: AnalyticsHelper private val analytics: AnalyticsHelper
) : BasePresenter<AttendanceView>(errorHandler, studentRepository) { ) : BasePresenter<AttendanceView>(errorHandler, studentRepository) {
private var baseDate: LocalDate = now().previousOrSameSchoolDay private var initialDate: LocalDate? = null
private var isWeekendHasLessons: Boolean = false
lateinit var currentDate: LocalDate var currentDate: LocalDate? = null
private set private set
private lateinit var lastError: Throwable private lateinit var lastError: Throwable
@ -44,27 +50,34 @@ class AttendancePresenter @Inject constructor(
view.initView() view.initView()
Timber.i("Attendance view was initialized") Timber.i("Attendance view was initialized")
errorHandler.showErrorMessage = ::showErrorViewOnError errorHandler.showErrorMessage = ::showErrorViewOnError
reloadView(ofEpochDay(date ?: baseDate.toEpochDay())) currentDate = date?.let(::ofEpochDay)
loadData() loadData()
if (currentDate.isHolidays) setBaseDateOnHolidays()
} }
fun onPreviousDay() { fun onPreviousDay() {
val date = if (isWeekendHasLessons) {
currentDate?.minusDays(1)
} else currentDate?.previousSchoolDay
view?.finishActionMode() view?.finishActionMode()
attendanceToExcuseList.clear() attendanceToExcuseList.clear()
reloadView(currentDate.previousSchoolDay) reloadView(date ?: return)
loadData() loadData()
} }
fun onNextDay() { fun onNextDay() {
val date = if (isWeekendHasLessons) {
currentDate?.plusDays(1)
} else currentDate?.nextSchoolDay
view?.finishActionMode() view?.finishActionMode()
attendanceToExcuseList.clear() attendanceToExcuseList.clear()
reloadView(currentDate.nextSchoolDay) reloadView(date ?: return)
loadData() loadData()
} }
fun onPickDate() { fun onPickDate() {
view?.showDatePickerDialog(currentDate) view?.showDatePickerDialog(currentDate ?: return)
} }
fun onDateSet(year: Int, month: Int, day: Int) { fun onDateSet(year: Int, month: Int, day: Int) {
@ -93,10 +106,8 @@ class AttendancePresenter @Inject constructor(
Timber.i("Attendance view is reselected") Timber.i("Attendance view is reselected")
view?.let { view -> view?.let { view ->
if (view.currentStackSize == 1) { if (view.currentStackSize == 1) {
baseDate = now().previousOrSameSchoolDay if (currentDate != initialDate) {
reloadView(initialDate ?: return)
if (currentDate != baseDate) {
reloadView(baseDate)
loadData() loadData()
} else if (!view.isViewEmpty) { } else if (!view.isViewEmpty) {
view.resetView() view.resetView()
@ -188,19 +199,6 @@ class AttendancePresenter @Inject constructor(
return true return true
} }
private fun setBaseDateOnHolidays() {
flow {
val student = studentRepository.getCurrentStudent()
emit(semesterRepository.getCurrentSemester(student))
}.catch {
Timber.i("Loading semester result: An exception occurred")
}.onEach {
baseDate = baseDate.getLastSchoolDayIfHoliday(it.schoolYear)
currentDate = baseDate
reloadNavigation()
}.launch("holidays")
}
private fun loadData(forceRefresh: Boolean = false) { private fun loadData(forceRefresh: Boolean = false) {
Timber.i("Loading attendance data started") Timber.i("Loading attendance data started")
@ -211,11 +209,13 @@ class AttendancePresenter @Inject constructor(
isParent = student.isParent isParent = student.isParent
val semester = semesterRepository.getCurrentSemester(student) val semester = semesterRepository.getCurrentSemester(student)
checkInitialAndCurrentDate(student, semester)
attendanceRepository.getAttendance( attendanceRepository.getAttendance(
student = student, student = student,
semester = semester, semester = semester,
start = currentDate, start = currentDate ?: now(),
end = currentDate, end = currentDate ?: now(),
forceRefresh = forceRefresh forceRefresh = forceRefresh
) )
} }
@ -231,6 +231,8 @@ class AttendancePresenter @Inject constructor(
}.sortedBy { item -> item.number } }.sortedBy { item -> item.number }
} }
.onResourceData { .onResourceData {
isWeekendHasLessons = isWeekendHasLessons || isWeekendHasLessons(it)
view?.run { view?.run {
enableSwipe(true) enableSwipe(true)
showProgress(false) showProgress(false)
@ -238,6 +240,7 @@ class AttendancePresenter @Inject constructor(
showEmpty(it.isEmpty()) showEmpty(it.isEmpty())
showContent(it.isNotEmpty()) showContent(it.isNotEmpty())
updateData(it) updateData(it)
reloadNavigation()
} }
} }
.onResourceIntermediate { view?.showRefresh(true) } .onResourceIntermediate { view?.showRefresh(true) }
@ -263,6 +266,43 @@ class AttendancePresenter @Inject constructor(
.launch() .launch()
} }
private suspend fun checkInitialAndCurrentDate(student: Student, semester: Semester) {
if (initialDate == null) {
val lessons = attendanceRepository.getAttendance(
student = student,
semester = semester,
start = now().monday,
end = now().sunday,
forceRefresh = false,
).toFirstResult().dataOrNull.orEmpty()
isWeekendHasLessons = isWeekendHasLessons(lessons)
initialDate = getInitialDate(semester)
}
if (currentDate == null) {
currentDate = initialDate
}
}
private fun isWeekendHasLessons(
lessons: List<Attendance>,
): Boolean = lessons.any {
it.date.dayOfWeek in listOf(
DayOfWeek.SATURDAY,
DayOfWeek.SUNDAY,
)
}
private fun getInitialDate(semester: Semester): LocalDate {
val now = now()
return when {
now.isHolidays -> now.getLastSchoolDayIfHoliday(semester.schoolYear)
isWeekendHasLessons -> now
else -> now.previousOrSameSchoolDay
}
}
private fun excuseAbsence(reason: String?, toExcuseList: List<Attendance>) { private fun excuseAbsence(reason: String?, toExcuseList: List<Attendance>) {
resourceFlow { resourceFlow {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
@ -311,7 +351,7 @@ class AttendancePresenter @Inject constructor(
private fun reloadView(date: LocalDate) { private fun reloadView(date: LocalDate) {
currentDate = date currentDate = date
Timber.i("Reload attendance view with the date ${currentDate.toFormattedString()}") Timber.i("Reload attendance view with the date ${currentDate?.toFormattedString()}")
view?.apply { view?.apply {
showProgress(true) showProgress(true)
enableSwipe(false) enableSwipe(false)
@ -326,10 +366,13 @@ class AttendancePresenter @Inject constructor(
@SuppressLint("DefaultLocale") @SuppressLint("DefaultLocale")
private fun reloadNavigation() { private fun reloadNavigation() {
val currentDate = currentDate ?: return
view?.apply { view?.apply {
showPreButton(!currentDate.minusDays(1).isHolidays) showPreButton(!currentDate.minusDays(1).isHolidays)
showNextButton(!currentDate.plusDays(1).isHolidays) showNextButton(!currentDate.plusDays(1).isHolidays)
updateNavigationDay(currentDate.toFormattedString("EEEE, dd.MM").capitalise()) updateNavigationDay(currentDate.toFormattedString("EEEE, dd.MM").capitalise())
showNavigation(true)
} }
} }
} }

View File

@ -40,6 +40,8 @@ interface AttendanceView : BaseView {
fun showContent(show: Boolean) fun showContent(show: Boolean)
fun showNavigation(show: Boolean)
fun showPreButton(show: Boolean) fun showPreButton(show: Boolean)
fun showNextButton(show: Boolean) fun showNextButton(show: Boolean)

View File

@ -1,19 +1,46 @@
package io.github.wulkanowy.ui.modules.dashboard package io.github.wulkanowy.ui.modules.dashboard
import io.github.wulkanowy.data.* import io.github.wulkanowy.data.Resource
import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.entities.AdminMessage import io.github.wulkanowy.data.db.entities.AdminMessage
import io.github.wulkanowy.data.db.entities.LuckyNumber import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.enums.MessageFolder import io.github.wulkanowy.data.enums.MessageFolder
import io.github.wulkanowy.data.enums.MessageType import io.github.wulkanowy.data.enums.MessageType
import io.github.wulkanowy.data.repositories.* import io.github.wulkanowy.data.errorOrNull
import io.github.wulkanowy.data.flatResourceFlow
import io.github.wulkanowy.data.mapResourceData
import io.github.wulkanowy.data.onResourceError
import io.github.wulkanowy.data.repositories.AttendanceSummaryRepository
import io.github.wulkanowy.data.repositories.ConferenceRepository
import io.github.wulkanowy.data.repositories.ExamRepository
import io.github.wulkanowy.data.repositories.GradeRepository
import io.github.wulkanowy.data.repositories.HomeworkRepository
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
import io.github.wulkanowy.data.repositories.MessageRepository
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.SchoolAnnouncementRepository
import io.github.wulkanowy.data.repositories.SemesterRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.data.repositories.TimetableRepository
import io.github.wulkanowy.domain.adminmessage.GetAppropriateAdminMessageUseCase import io.github.wulkanowy.domain.adminmessage.GetAppropriateAdminMessageUseCase
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.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.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNot
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import java.time.Instant import java.time.Instant
@ -48,6 +75,11 @@ class DashboardPresenter @Inject constructor(
private val firstLoadedItemList = mutableListOf<DashboardItem.Type>() private val firstLoadedItemList = mutableListOf<DashboardItem.Type>()
private val selectedDashboardTiles
get() = preferencesRepository.selectedDashboardTiles
.filterNot { it == DashboardItem.Tile.ADS && !adsHelper.canShowAd }
.toSet()
private lateinit var lastError: Throwable private lateinit var lastError: Throwable
override fun onAttachView(view: DashboardView) { override fun onAttachView(view: DashboardView) {
@ -59,10 +91,19 @@ class DashboardPresenter @Inject constructor(
showContent(false) showContent(false)
} }
val selectedDashboardTilesFlow = preferencesRepository.selectedDashboardTilesFlow
.map { selectedDashboardTiles }
val isAdsEnabledFlow = preferencesRepository.isAdsEnabledFlow
.filter { (adsHelper.canShowAd && it) || !it }
.map { selectedDashboardTiles }
val isMobileAdsSdkInitializedFlow = adsHelper.isMobileAdsSdkInitialized
.filter { it }
.map { selectedDashboardTiles }
merge( merge(
preferencesRepository.selectedDashboardTilesFlow, selectedDashboardTilesFlow,
preferencesRepository.isAdsEnabledFlow isAdsEnabledFlow,
.map { preferencesRepository.selectedDashboardTiles } isMobileAdsSdkInitializedFlow
) )
.onEach { loadData(tilesToLoad = it) } .onEach { loadData(tilesToLoad = it) }
.launch("dashboard_pref") .launch("dashboard_pref")
@ -71,7 +112,7 @@ class DashboardPresenter @Inject constructor(
fun onAdminMessageDismissed(adminMessage: AdminMessage) { fun onAdminMessageDismissed(adminMessage: AdminMessage) {
preferencesRepository.dismissedAdminMessageIds += adminMessage.id preferencesRepository.dismissedAdminMessageIds += adminMessage.id
loadData(preferencesRepository.selectedDashboardTiles) loadData(selectedDashboardTiles)
} }
fun onDragAndDropEnd(list: List<DashboardItem>) { fun onDragAndDropEnd(list: List<DashboardItem>) {
@ -187,7 +228,7 @@ class DashboardPresenter @Inject constructor(
fun onSwipeRefresh() { fun onSwipeRefresh() {
Timber.i("Force refreshing the dashboard") Timber.i("Force refreshing the dashboard")
loadData(preferencesRepository.selectedDashboardTiles, forceRefresh = true) loadData(selectedDashboardTiles, forceRefresh = true)
} }
fun onRetry() { fun onRetry() {
@ -195,7 +236,7 @@ class DashboardPresenter @Inject constructor(
showErrorView(false) showErrorView(false)
showProgress(true) showProgress(true)
} }
loadData(preferencesRepository.selectedDashboardTiles, forceRefresh = true) loadData(selectedDashboardTiles, forceRefresh = true)
} }
fun onViewReselected() { fun onViewReselected() {
@ -216,7 +257,7 @@ class DashboardPresenter @Inject constructor(
} }
fun onDashboardTileSettingsSelected(): Boolean { fun onDashboardTileSettingsSelected(): Boolean {
view?.showDashboardTileSettings(preferencesRepository.selectedDashboardTiles.toList()) view?.showDashboardTileSettings(selectedDashboardTiles.toList())
return true return true
} }
@ -232,7 +273,7 @@ class DashboardPresenter @Inject constructor(
private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) { private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) {
flow { flow {
val selectedTiles = preferencesRepository.selectedDashboardTiles val selectedTiles = selectedDashboardTiles
val flowSuccess = flowOf(Resource.Success(null)) val flowSuccess = flowOf(Resource.Success(null))
val luckyNumberFlow = luckyNumberRepository.getLuckyNumber(student, forceRefresh) val luckyNumberFlow = luckyNumberRepository.getLuckyNumber(student, forceRefresh)
@ -386,7 +427,7 @@ class DashboardPresenter @Inject constructor(
private fun loadLessons(student: Student, forceRefresh: Boolean) { private fun loadLessons(student: Student, forceRefresh: Boolean) {
flatResourceFlow { flatResourceFlow {
val semester = semesterRepository.getCurrentSemester(student) val semester = semesterRepository.getCurrentSemester(student)
val date = LocalDate.now().nextOrSameSchoolDay val date = LocalDate.now()
timetableRepository.getTimetable( timetableRepository.getTimetable(
student = student, student = student,

View File

@ -22,6 +22,8 @@ import io.github.wulkanowy.databinding.ItemGradeStatisticsHeaderBinding
import io.github.wulkanowy.databinding.ItemGradeStatisticsPieBinding import io.github.wulkanowy.databinding.ItemGradeStatisticsPieBinding
import io.github.wulkanowy.utils.getThemeAttrColor import io.github.wulkanowy.utils.getThemeAttrColor
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.max
import kotlin.math.roundToInt
class GradeStatisticsAdapter @Inject constructor() : class GradeStatisticsAdapter @Inject constructor() :
RecyclerView.Adapter<RecyclerView.ViewHolder>() { RecyclerView.Adapter<RecyclerView.ViewHolder>() {
@ -269,7 +271,7 @@ class GradeStatisticsAdapter @Inject constructor() :
valueTextSize = 12f valueTextSize = 12f
valueTextColor = binding.root.context.getThemeAttrColor(android.R.attr.textColorPrimary) valueTextColor = binding.root.context.getThemeAttrColor(android.R.attr.textColorPrimary)
valueFormatter = object : ValueFormatter() { valueFormatter = object : ValueFormatter() {
override fun getBarLabel(barEntry: BarEntry) = "${barEntry.y}%" override fun getBarLabel(barEntry: BarEntry) = "${barEntry.y}"
} }
colors = gradePointsColors colors = gradePointsColors
} }
@ -304,15 +306,20 @@ class GradeStatisticsAdapter @Inject constructor() :
} }
xAxis.setDrawLabels(false) xAxis.setDrawLabels(false)
xAxis.setDrawGridLines(false) xAxis.setDrawGridLines(false)
val yMaxFromValues = (max(points.others, points.student)).roundToInt() + 30f
val yMaxFromValuesWithMargin = ((yMaxFromValues / 10.0).roundToInt() * 10).toFloat()
val yMax = yMaxFromValuesWithMargin.coerceAtLeast(100f)
val yLabelCount = (yMax / 10).toInt() + 1
with(axisLeft) { with(axisLeft) {
axisMinimum = 0f axisMinimum = 0f
axisMaximum = 100f axisMaximum = yMax
labelCount = 11 labelCount = yLabelCount
} }
with(axisRight) { with(axisRight) {
axisMinimum = 0f axisMinimum = 0f
axisMaximum = 100f axisMaximum = yMax
labelCount = 11 labelCount = yLabelCount
} }
invalidate() invalidate()
} }

View File

@ -42,7 +42,7 @@ class GradeSummaryPresenter @Inject constructor(
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
averageProvider.getGradesDetailsWithAverage(student, semesterId, forceRefresh) averageProvider.getGradesDetailsWithAverage(student, semesterId, forceRefresh)
} }
.logResourceStatus("load grade summary", showData = true) .logResourceStatus("load grade summary")
.mapResourceData { createGradeSummaryItems(it) } .mapResourceData { createGradeSummaryItems(it) }
.onResourceData { .onResourceData {
view?.run { view?.run {

View File

@ -23,7 +23,7 @@ import io.github.wulkanowy.ui.modules.login.symbol.LoginSymbolFragment
import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.notifications.NotificationsFragment import io.github.wulkanowy.ui.modules.notifications.NotificationsFragment
import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.UpdateHelper import io.github.wulkanowy.utils.InAppUpdateHelper
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
@ -33,7 +33,7 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
override lateinit var presenter: LoginPresenter override lateinit var presenter: LoginPresenter
@Inject @Inject
lateinit var updateHelper: UpdateHelper lateinit var inAppUpdateHelper: InAppUpdateHelper
@Inject @Inject
lateinit var appInfo: AppInfo lateinit var appInfo: AppInfo
@ -47,10 +47,10 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
setContentView(ActivityLoginBinding.inflate(layoutInflater).apply { binding = this }.root) setContentView(ActivityLoginBinding.inflate(layoutInflater).apply { binding = this }.root)
setSupportActionBar(binding.loginToolbar) setSupportActionBar(binding.loginToolbar)
messageContainer = binding.loginContainer messageContainer = binding.loginContainer
updateHelper.messageContainer = binding.loginContainer inAppUpdateHelper.messageContainer = binding.loginContainer
presenter.onAttachView(this) presenter.onAttachView(this)
updateHelper.checkAndInstallUpdates(this) inAppUpdateHelper.checkAndInstallUpdates()
if (savedInstanceState == null) { if (savedInstanceState == null) {
openFragment(LoginFormFragment.newInstance(), clearBackStack = true) openFragment(LoginFormFragment.newInstance(), clearBackStack = true)
@ -117,14 +117,6 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
updateHelper.onResume(this) inAppUpdateHelper.onResume()
}
//https://developer.android.com/guide/playcore/in-app-updates#status_callback
@Deprecated("Deprecated in Java")
@Suppress("DEPRECATION")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
updateHelper.onActivityResult(requestCode, resultCode)
} }
} }

View File

@ -9,7 +9,11 @@ import android.view.MenuItem
import android.view.ViewGroup.MarginLayoutParams import android.view.ViewGroup.MarginLayoutParams
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.activity.addCallback import androidx.activity.addCallback
import androidx.core.view.* import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.preference.Preference import androidx.preference.Preference
@ -23,12 +27,19 @@ import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.databinding.ActivityMainBinding import io.github.wulkanowy.databinding.ActivityMainBinding
import io.github.wulkanowy.databinding.DialogAdsConsentBinding
import io.github.wulkanowy.ui.base.BaseActivity import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.modules.Destination import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
import io.github.wulkanowy.ui.modules.settings.appearance.menuorder.AppMenuItem import io.github.wulkanowy.ui.modules.settings.appearance.menuorder.AppMenuItem
import io.github.wulkanowy.utils.* import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.InAppReviewHelper
import io.github.wulkanowy.utils.InAppUpdateHelper
import io.github.wulkanowy.utils.createNameInitialsDrawable
import io.github.wulkanowy.utils.dpToPx
import io.github.wulkanowy.utils.nickOrName
import io.github.wulkanowy.utils.safelyPopFragments
import io.github.wulkanowy.utils.setOnViewChangeListener
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
@ -45,7 +56,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
lateinit var analytics: AnalyticsHelper lateinit var analytics: AnalyticsHelper
@Inject @Inject
lateinit var updateHelper: UpdateHelper lateinit var inAppUpdateHelper: InAppUpdateHelper
@Inject @Inject
lateinit var inAppReviewHelper: InAppReviewHelper lateinit var inAppReviewHelper: InAppReviewHelper
@ -100,7 +111,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
this.savedInstanceState = savedInstanceState this.savedInstanceState = savedInstanceState
messageContainer = binding.mainMessageContainer messageContainer = binding.mainMessageContainer
messageAnchor = binding.mainMessageContainer messageAnchor = binding.mainMessageContainer
updateHelper.messageContainer = binding.mainFragmentContainer inAppUpdateHelper.messageContainer = binding.mainFragmentContainer
onBackCallback = onBackPressedDispatcher.addCallback(this, enabled = false) { onBackCallback = onBackPressedDispatcher.addCallback(this, enabled = false) {
presenter.onBackPressed() presenter.onBackPressed()
} }
@ -109,19 +120,12 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
?.takeIf { savedInstanceState == null } ?.takeIf { savedInstanceState == null }
presenter.onAttachView(this, destination) presenter.onAttachView(this, destination)
updateHelper.checkAndInstallUpdates(this) inAppUpdateHelper.checkAndInstallUpdates()
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
updateHelper.onResume(this) inAppUpdateHelper.onResume()
}
//https://developer.android.com/guide/playcore/in-app-updates#status_callback
@Deprecated("Deprecated in Java")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
updateHelper.onActivityResult(requestCode, resultCode)
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
@ -319,40 +323,6 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
.show() .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)

View File

@ -19,7 +19,6 @@ 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 io.github.wulkanowy.utils.AppInfo
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import timber.log.Timber import timber.log.Timber
import java.time.Duration import java.time.Duration
@ -52,6 +51,7 @@ class MainPresenter @Inject constructor(
destinationType in rootDestinationTypeList -> { destinationType in rootDestinationTypeList -> {
rootDestinationTypeList.indexOf(destinationType) rootDestinationTypeList.indexOf(destinationType)
} }
else -> 4 else -> 4
} }
@ -110,6 +110,7 @@ class MainPresenter @Inject constructor(
is AccountView, is AccountView,
is StudentInfoView, is StudentInfoView,
is AccountDetailsView -> false is AccountDetailsView -> false
else -> true else -> true
} }
@ -148,20 +149,8 @@ class MainPresenter @Inject constructor(
} }
fun onEnableAdsSelected() { fun onEnableAdsSelected() {
view?.showPrivacyPolicyDialog()
}
fun onPrivacyAgree(isPersonalizedAds: Boolean) {
preferencesRepository.isAgreeToProcessData = true
preferencesRepository.isPersonalizedAdsEnabled = isPersonalizedAds
adsHelper.initialize()
preferencesRepository.isAdsEnabled = true preferencesRepository.isAdsEnabled = true
} adsHelper.initialize()
fun onPrivacySelected() {
view?.openPrivacyPolicy()
} }
private fun checkInAppReview() { private fun checkInAppReview() {
@ -189,8 +178,8 @@ class MainPresenter @Inject constructor(
.getOrElse { return@launch } .getOrElse { return@launch }
if (Instant.now().minus(Duration.ofDays(28)).isAfter(student.registrationDate)) { if (Instant.now().minus(Duration.ofDays(28)).isAfter(student.registrationDate)) {
view?.showAppSupport()
preferencesRepository.isAppSupportShown = true preferencesRepository.isAppSupportShown = true
view?.showAppSupport()
} }
} }
} }

View File

@ -46,10 +46,6 @@ interface MainView : BaseView {
fun showAppSupport() fun showAppSupport()
fun showPrivacyPolicyDialog()
fun openPrivacyPolicy()
fun openMoreDestination(destination: Destination) fun openMoreDestination(destination: Destination)
interface MainChildView { interface MainChildView {

View File

@ -58,7 +58,10 @@ class TeacherPresenter @Inject constructor(
.logResourceStatus("load teachers data") .logResourceStatus("load teachers data")
.onResourceData { .onResourceData {
view?.run { view?.run {
updateData(it.filter { item -> item.name.isNotBlank() }) updateData(it
.filter { item -> item.name.isNotBlank() }
.sortedBy { it.name }
)
showContent(it.isNotEmpty()) showContent(it.isNotEmpty())
showEmpty(it.isEmpty()) showEmpty(it.isEmpty())
showErrorView(false) showErrorView(false)

View File

@ -35,7 +35,7 @@ class AdvancedFragment : PreferenceFragmentCompat(),
setPreferencesFromResource(R.xml.scheme_preferences_advanced, rootKey) setPreferencesFromResource(R.xml.scheme_preferences_advanced, rootKey)
} }
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
presenter.onSharedPreferenceChanged(key) presenter.onSharedPreferenceChanged(key)
} }

View File

@ -18,7 +18,8 @@ class AdvancedPresenter @Inject constructor(
Timber.i("Settings advanced view was initialized") Timber.i("Settings advanced view was initialized")
} }
fun onSharedPreferenceChanged(key: String) { fun onSharedPreferenceChanged(key: String?) {
key ?: return
Timber.i("Change settings $key") Timber.i("Change settings $key")
analytics.logEvent("setting_changed", "name" to key) analytics.logEvent("setting_changed", "name" to key)
} }

View File

@ -39,7 +39,7 @@ class AppearanceFragment : PreferenceFragmentCompat(),
setPreferencesFromResource(R.xml.scheme_preferences_appearance, rootKey) setPreferencesFromResource(R.xml.scheme_preferences_appearance, rootKey)
} }
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
presenter.onSharedPreferenceChanged(key) presenter.onSharedPreferenceChanged(key)
} }

View File

@ -22,7 +22,8 @@ class AppearancePresenter @Inject constructor(
Timber.i("Settings appearance view was initialized") Timber.i("Settings appearance view was initialized")
} }
fun onSharedPreferenceChanged(key: String) { fun onSharedPreferenceChanged(key: String?) {
key ?: return
Timber.i("Change settings $key") Timber.i("Change settings $key")
preferencesRepository.apply { preferencesRepository.apply {

View File

@ -114,7 +114,7 @@ class NotificationsFragment : PreferenceFragmentCompat(),
setPreferencesFromResource(R.xml.scheme_preferences_notifications, rootKey) setPreferencesFromResource(R.xml.scheme_preferences_notifications, rootKey)
} }
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
presenter.onSharedPreferenceChanged(key) presenter.onSharedPreferenceChanged(key)
} }

View File

@ -38,7 +38,8 @@ class NotificationsPresenter @Inject constructor(
Timber.i("Settings notifications view was initialized") Timber.i("Settings notifications view was initialized")
} }
fun onSharedPreferenceChanged(key: String) { fun onSharedPreferenceChanged(key: String?) {
key ?: return
Timber.i("Change settings $key") Timber.i("Change settings $key")
preferencesRepository.apply { preferencesRepository.apply {

View File

@ -52,7 +52,7 @@ class SyncFragment : PreferenceFragmentCompat(),
setPreferencesFromResource(R.xml.scheme_preferences_sync, rootKey) setPreferencesFromResource(R.xml.scheme_preferences_sync, rootKey)
} }
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
presenter.onSharedPreferenceChanged(key) presenter.onSharedPreferenceChanged(key)
} }

View File

@ -31,7 +31,8 @@ class SyncPresenter @Inject constructor(
setSyncDateInView() setSyncDateInView()
} }
fun onSharedPreferenceChanged(key: String) { fun onSharedPreferenceChanged(key: String?) {
key ?: return
Timber.i("Change settings $key") Timber.i("Change settings $key")
preferencesRepository.apply { preferencesRepository.apply {
@ -52,10 +53,12 @@ class SyncPresenter @Inject constructor(
Timber.i("Setting sync now started") Timber.i("Setting sync now started")
analytics.logEvent("sync_now", "status" to "started") analytics.logEvent("sync_now", "status" to "started")
} }
WorkInfo.State.SUCCEEDED -> { WorkInfo.State.SUCCEEDED -> {
showMessage(syncSuccessString) showMessage(syncSuccessString)
analytics.logEvent("sync_now", "status" to "success") analytics.logEvent("sync_now", "status" to "success")
} }
WorkInfo.State.FAILED -> { WorkInfo.State.FAILED -> {
showError( showError(
syncFailedString, syncFailedString,
@ -66,6 +69,7 @@ class SyncPresenter @Inject constructor(
) )
analytics.logEvent("sync_now", "status" to "failed") analytics.logEvent("sync_now", "status" to "failed")
} }
else -> Timber.d("Sync now state: ${workInfo?.state}") else -> Timber.d("Sync now state: ${workInfo?.state}")
} }
if (workInfo?.state?.isFinished == true) { if (workInfo?.state?.isFinished == true) {

View File

@ -325,7 +325,7 @@ class TimetableAdapter @Inject constructor() :
override fun getChangePayload(oldItem: TimetableItem, newItem: TimetableItem): Any? { override fun getChangePayload(oldItem: TimetableItem, newItem: TimetableItem): Any? {
return if (oldItem is TimetableItem.Normal && newItem is TimetableItem.Normal) { return if (oldItem is TimetableItem.Normal && newItem is TimetableItem.Normal) {
if (oldItem.lesson == newItem.lesson && oldItem.timeLeft != newItem.timeLeft) { if (oldItem.lesson == newItem.lesson && oldItem.showGroupsInPlan == newItem.showGroupsInPlan && oldItem.timeLeft != newItem.timeLeft) {
"time_left" "time_left"
} else super.getChangePayload(oldItem, newItem) } else super.getChangePayload(oldItem, newItem)
} else super.getChangePayload(oldItem, newItem) } else super.getChangePayload(oldItem, newItem)

View File

@ -9,6 +9,7 @@ import android.view.View.GONE
import android.view.View.VISIBLE import android.view.View.VISIBLE
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.core.text.parseAsHtml import androidx.core.text.parseAsHtml
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R import io.github.wulkanowy.R
@ -160,6 +161,10 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
binding.timetableRecycler.visibility = if (show) VISIBLE else GONE binding.timetableRecycler.visibility = if (show) VISIBLE else GONE
} }
override fun showNavigation(show: Boolean) {
binding.timetableNavContainer.isVisible = true
}
override fun showPreButton(show: Boolean) { override fun showPreButton(show: Boolean) {
binding.timetablePreviousButton.visibility = if (show) VISIBLE else View.INVISIBLE binding.timetablePreviousButton.visibility = if (show) VISIBLE else View.INVISIBLE
} }
@ -193,7 +198,9 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay()) presenter.currentDate?.toEpochDay()?.let {
outState.putLong(SAVED_DATE_KEY, it)
}
} }
override fun onDestroyView() { override fun onDestroyView() {

View File

@ -1,5 +1,10 @@
package io.github.wulkanowy.ui.modules.timetable package io.github.wulkanowy.ui.modules.timetable
import android.os.Handler
import android.os.Looper
import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.enums.TimetableGapsMode.BETWEEN_AND_BEFORE_LESSONS import io.github.wulkanowy.data.enums.TimetableGapsMode.BETWEEN_AND_BEFORE_LESSONS
import io.github.wulkanowy.data.enums.TimetableGapsMode.NO_GAPS import io.github.wulkanowy.data.enums.TimetableGapsMode.NO_GAPS
@ -15,6 +20,8 @@ import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.SemesterRepository 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.data.repositories.TimetableRepository import io.github.wulkanowy.data.repositories.TimetableRepository
import io.github.wulkanowy.data.toFirstResult
import io.github.wulkanowy.data.waitForResult
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.AnalyticsHelper import io.github.wulkanowy.utils.AnalyticsHelper
@ -24,15 +31,16 @@ import io.github.wulkanowy.utils.isHolidays
import io.github.wulkanowy.utils.isJustFinished import io.github.wulkanowy.utils.isJustFinished
import io.github.wulkanowy.utils.isShowTimeUntil import io.github.wulkanowy.utils.isShowTimeUntil
import io.github.wulkanowy.utils.left import io.github.wulkanowy.utils.left
import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.nextOrSameSchoolDay import io.github.wulkanowy.utils.nextOrSameSchoolDay
import io.github.wulkanowy.utils.nextSchoolDay import io.github.wulkanowy.utils.nextSchoolDay
import io.github.wulkanowy.utils.previousSchoolDay import io.github.wulkanowy.utils.previousSchoolDay
import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.toFormattedString import io.github.wulkanowy.utils.toFormattedString
import io.github.wulkanowy.utils.until import io.github.wulkanowy.utils.until
import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onEach
import timber.log.Timber import timber.log.Timber
import java.time.DayOfWeek
import java.time.Instant import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDate.now import java.time.LocalDate.now
@ -51,9 +59,10 @@ class TimetablePresenter @Inject constructor(
private val analytics: AnalyticsHelper, private val analytics: AnalyticsHelper,
) : BasePresenter<TimetableView>(errorHandler, studentRepository) { ) : BasePresenter<TimetableView>(errorHandler, studentRepository) {
private var baseDate: LocalDate = now().nextOrSameSchoolDay private var initialDate: LocalDate? = null
private var isWeekendHasLessons: Boolean = false
lateinit var currentDate: LocalDate var currentDate: LocalDate? = null
private set private set
private lateinit var lastError: Throwable private lateinit var lastError: Throwable
@ -65,23 +74,30 @@ class TimetablePresenter @Inject constructor(
view.initView() view.initView()
Timber.i("Timetable was initialized") Timber.i("Timetable was initialized")
errorHandler.showErrorMessage = ::showErrorViewOnError errorHandler.showErrorMessage = ::showErrorViewOnError
reloadView(ofEpochDay(date ?: baseDate.toEpochDay())) currentDate = date?.let(::ofEpochDay)
loadData() loadData()
if (currentDate.isHolidays) setBaseDateOnHolidays()
} }
fun onPreviousDay() { fun onPreviousDay() {
reloadView(currentDate.previousSchoolDay) val date = if (isWeekendHasLessons) {
currentDate?.minusDays(1)
} else currentDate?.previousSchoolDay
reloadView(date ?: return)
loadData() loadData()
} }
fun onNextDay() { fun onNextDay() {
reloadView(currentDate.nextSchoolDay) val date = if (isWeekendHasLessons) {
currentDate?.plusDays(1)
} else currentDate?.nextSchoolDay
reloadView(date ?: return)
loadData() loadData()
} }
fun onPickDate() { fun onPickDate() {
view?.showDatePickerDialog(currentDate) view?.showDatePickerDialog(currentDate ?: return)
} }
fun onDateSet(year: Int, month: Int, day: Int) { fun onDateSet(year: Int, month: Int, day: Int) {
@ -110,10 +126,8 @@ class TimetablePresenter @Inject constructor(
Timber.i("Timetable view is reselected") Timber.i("Timetable view is reselected")
view?.let { view -> view?.let { view ->
if (view.currentStackSize == 1) { if (view.currentStackSize == 1) {
baseDate = now().nextOrSameSchoolDay if (currentDate != initialDate) {
reloadView(initialDate ?: return)
if (currentDate != baseDate) {
reloadView(baseDate)
loadData() loadData()
} else if (!view.isViewEmpty) { } else if (!view.isViewEmpty) {
view.resetView() view.resetView()
@ -134,34 +148,25 @@ class TimetablePresenter @Inject constructor(
return true return true
} }
private fun setBaseDateOnHolidays() {
flow {
val student = studentRepository.getCurrentStudent()
emit(semesterRepository.getCurrentSemester(student))
}.catch {
Timber.i("Loading semester result: An exception occurred")
}.onEach {
baseDate = baseDate.getLastSchoolDayIfHoliday(it.schoolYear)
currentDate = baseDate
reloadNavigation()
}.launch("holidays")
}
private fun loadData(forceRefresh: Boolean = false) { private fun loadData(forceRefresh: Boolean = false) {
flatResourceFlow { flatResourceFlow {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
val semester = semesterRepository.getCurrentSemester(student) val semester = semesterRepository.getCurrentSemester(student)
checkInitialAndCurrentDate(student, semester)
timetableRepository.getTimetable( timetableRepository.getTimetable(
student = student, student = student,
semester = semester, semester = semester,
start = currentDate, start = currentDate ?: now(),
end = currentDate, end = currentDate ?: now(),
forceRefresh = forceRefresh, forceRefresh = forceRefresh,
timetableType = TimetableRepository.TimetableType.NORMAL timetableType = TimetableRepository.TimetableType.NORMAL
) )
} }
.logResourceStatus("load timetable data") .logResourceStatus("load timetable data")
.onResourceData { .onResourceData {
isWeekendHasLessons = isWeekendHasLessons || isWeekendHasLessons(it.lessons)
view?.run { view?.run {
enableSwipe(true) enableSwipe(true)
showProgress(false) showProgress(false)
@ -169,7 +174,8 @@ class TimetablePresenter @Inject constructor(
showContent(it.lessons.isNotEmpty()) showContent(it.lessons.isNotEmpty())
showEmpty(it.lessons.isEmpty()) showEmpty(it.lessons.isEmpty())
updateData(it.lessons) updateData(it.lessons)
setDayHeaderMessage(it.headers.singleOrNull { header -> header.date == currentDate }?.content) setDayHeaderMessage(it.headers.find { header -> header.date == currentDate }?.content)
reloadNavigation()
} }
} }
.onResourceIntermediate { view?.showRefresh(true) } .onResourceIntermediate { view?.showRefresh(true) }
@ -191,14 +197,54 @@ class TimetablePresenter @Inject constructor(
.launch() .launch()
} }
private suspend fun checkInitialAndCurrentDate(student: Student, semester: Semester) {
if (initialDate == null) {
val lessons = timetableRepository.getTimetable(
student = student,
semester = semester,
start = now().monday,
end = now().sunday,
forceRefresh = false,
timetableType = TimetableRepository.TimetableType.NORMAL
).toFirstResult().dataOrNull?.lessons.orEmpty()
isWeekendHasLessons = isWeekendHasLessons(lessons)
initialDate = getInitialDate(semester)
}
if (currentDate == null) {
currentDate = initialDate
}
}
private fun isWeekendHasLessons(
lessons: List<Timetable>,
): Boolean = lessons.any {
it.date.dayOfWeek in listOf(
DayOfWeek.SATURDAY,
DayOfWeek.SUNDAY,
)
}
private fun getInitialDate(semester: Semester): LocalDate {
val now = now()
return when {
now.isHolidays -> now.getLastSchoolDayIfHoliday(semester.schoolYear)
isWeekendHasLessons -> now
else -> now.nextOrSameSchoolDay
}
}
private fun updateData(lessons: List<Timetable>) { private fun updateData(lessons: List<Timetable>) {
tickTimer?.cancel() tickTimer?.cancel()
if (!prefRepository.showTimetableTimers) { if (currentDate != now()) {
view?.updateData(createItems(lessons)) view?.updateData(createItems(lessons))
} else { } else {
tickTimer = timer(period = 2_000) { tickTimer = timer(period = 2_000) {
view?.updateData(createItems(lessons)) Handler(Looper.getMainLooper()).post {
view?.updateData(createItems(lessons))
}
} }
} }
} }
@ -285,7 +331,7 @@ class TimetablePresenter @Inject constructor(
private fun reloadView(date: LocalDate) { private fun reloadView(date: LocalDate) {
currentDate = date currentDate = date
Timber.i("Reload timetable view with the date ${currentDate.toFormattedString()}") Timber.i("Reload timetable view with the date ${currentDate?.toFormattedString()}")
view?.apply { view?.apply {
showProgress(true) showProgress(true)
enableSwipe(false) enableSwipe(false)
@ -298,10 +344,13 @@ class TimetablePresenter @Inject constructor(
} }
private fun reloadNavigation() { private fun reloadNavigation() {
val currentDate = currentDate ?: return
view?.apply { view?.apply {
showPreButton(!currentDate.minusDays(1).isHolidays) showPreButton(!currentDate.minusDays(1).isHolidays)
showNextButton(!currentDate.plusDays(1).isHolidays) showNextButton(!currentDate.plusDays(1).isHolidays)
updateNavigationDay(currentDate.toFormattedString("EEEE, dd.MM").capitalise()) updateNavigationDay(currentDate.toFormattedString("EEEE, dd.MM").capitalise())
showNavigation(true)
} }
} }

View File

@ -36,6 +36,8 @@ interface TimetableView : BaseView {
fun showContent(show: Boolean) fun showContent(show: Boolean)
fun showNavigation(show: Boolean)
fun showPreButton(show: Boolean) fun showPreButton(show: Boolean)
fun showNextButton(show: Boolean) fun showNextButton(show: Boolean)

View File

@ -1,6 +1,6 @@
Wersja 2.2.1 Wersja 2.3.0
dokonaliśmy kilka poprawek na ekranie logowania — poprawiliśmy kilka usterek przy odświeżaniu danych (ale pewnie nie wszystkie)
naprawiliśmy przypadek z błędnym wyświetlaniem starej klasy ucznia po zalogowaniu się na konto z nowej klasy — zaktualizowaliśmy sposób pytania o zgodę na personalizowane reklamy
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases

View File

@ -1,79 +0,0 @@
<?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="@string/pref_ads_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="@string/pref_ads_over_18_years_old"
android:textColor="?android:textColorSecondary"
android:textSize="14sp"
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="@string/pref_ads_option_personalized"
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="@string/pref_ads_option_non_personalized"
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.Material3.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="@android:string/cancel"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -128,7 +128,9 @@
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:gravity="center" android:gravity="center"
android:orientation="horizontal" android:orientation="horizontal"
tools:ignore="UnusedAttribute"> android:visibility="gone"
tools:ignore="UnusedAttribute"
tools:visibility="visible">
<ImageButton <ImageButton
android:id="@+id/attendancePreviousButton" android:id="@+id/attendancePreviousButton"

View File

@ -128,7 +128,9 @@
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:gravity="center" android:gravity="center"
android:orientation="horizontal" android:orientation="horizontal"
tools:ignore="UnusedAttribute"> android:visibility="gone"
tools:ignore="UnusedAttribute"
tools:visibility="visible">
<ImageButton <ImageButton
android:id="@+id/timetablePreviousButton" android:id="@+id/timetablePreviousButton"

View File

@ -713,7 +713,6 @@
<string name="pref_view_present">Zobrazit přítomnost</string> <string name="pref_view_present">Zobrazit přítomnost</string>
<string name="pref_view_app_theme">Motiv</string> <string name="pref_view_app_theme">Motiv</string>
<string name="pref_view_expand_grade">Rozvíjení známek</string> <string name="pref_view_expand_grade">Rozvíjení známek</string>
<string name="pref_view_timetable_show_timers">Označit aktuální lekci</string>
<string name="pref_view_timetable_show_groups">Zobrazit skupiny vedle předmětů</string> <string name="pref_view_timetable_show_groups">Zobrazit skupiny vedle předmětů</string>
<string name="pref_view_timetable_show_gaps">Zobrazit prázdné dlaždice, kde není žádná lekce</string> <string name="pref_view_timetable_show_gaps">Zobrazit prázdné dlaždice, kde není žádná lekce</string>
<string name="pref_view_grade_statistics_list">Zobrazit seznam grafů v známkách třídy</string> <string name="pref_view_grade_statistics_list">Zobrazit seznam grafů v známkách třídy</string>
@ -761,7 +760,7 @@
<string name="pref_ads_support_category_name">Podpora</string> <string name="pref_ads_support_category_name">Podpora</string>
<string name="pref_ads_privacy_policy">Ochrana osobních údajů</string> <string name="pref_ads_privacy_policy">Ochrana osobních údajů</string>
<string name="pref_ads_agreements">Souhlasy</string> <string name="pref_ads_agreements">Souhlasy</string>
<string name="pref_ads_consent">Souhlas se zpracováním údajů souvisejících s reklamami</string> <string name="pref_ads_consent">Show consent to data processing</string>
<string name="pref_ads_show_in_app">Zobrazit reklamy v aplikaci</string> <string name="pref_ads_show_in_app">Zobrazit reklamy v aplikaci</string>
<string name="pref_ads_support">Podívejte se na jednu reklamu pro podporu projektu</string> <string name="pref_ads_support">Podívejte se na jednu reklamu pro podporu projektu</string>
<string name="pref_ads_privacy_title">Souhlas se zpracováním dat</string> <string name="pref_ads_privacy_title">Souhlas se zpracováním dat</string>
@ -770,13 +769,6 @@
<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_ads_over_18_years_old">Je mi více než 18 let</string>
<string name="pref_ads_option_personalized">Ano, přizpůsobené reklamy</string>
<string name="pref_ads_option_non_personalized">Ano, 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>

View File

@ -623,7 +623,6 @@
<string name="pref_view_present">Show presence</string> <string name="pref_view_present">Show presence</string>
<string name="pref_view_app_theme">Theme</string> <string name="pref_view_app_theme">Theme</string>
<string name="pref_view_expand_grade">Grades expanding</string> <string name="pref_view_expand_grade">Grades expanding</string>
<string name="pref_view_timetable_show_timers">Mark current lesson</string>
<string name="pref_view_timetable_show_groups">Show groups next to subjects</string> <string name="pref_view_timetable_show_groups">Show groups next to subjects</string>
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string> <string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
<string name="pref_view_grade_statistics_list">Show chart list in class grades</string> <string name="pref_view_grade_statistics_list">Show chart list in class grades</string>
@ -671,7 +670,7 @@
<string name="pref_ads_support_category_name">Support</string> <string name="pref_ads_support_category_name">Support</string>
<string name="pref_ads_privacy_policy">Privacy Policy</string> <string name="pref_ads_privacy_policy">Privacy Policy</string>
<string name="pref_ads_agreements">Agreements</string> <string name="pref_ads_agreements">Agreements</string>
<string name="pref_ads_consent">Consent to processing of data related to ads</string> <string name="pref_ads_consent">Show consent to data processing</string>
<string name="pref_ads_show_in_app">Show ads in app</string> <string name="pref_ads_show_in_app">Show ads in app</string>
<string name="pref_ads_support">Watch single ad to support project</string> <string name="pref_ads_support">Watch single ad to support project</string>
<string name="pref_ads_privacy_title">Consent to data processing</string> <string name="pref_ads_privacy_title">Consent to data processing</string>
@ -680,13 +679,6 @@
<string name="pref_ads_privacy_link">Privacy policy</string> <string name="pref_ads_privacy_link">Privacy policy</string>
<string name="pref_ads_loading">Ad is loading</string> <string name="pref_ads_loading">Ad is loading</string>
<string name="pref_ads_once_per_visit">Thank you for your support, come back later for more ads</string> <string name="pref_ads_once_per_visit">Thank you for your support, come back later for more ads</string>
<string name="pref_ads_consent_title">Can we use your data to display ads?</string>
<string name="pref_ads_consent_description">You can change your choice anytime in the app settings. We may use your data to display ads tailored to you or, using less of your data, display non-personalized ads. Please see our Privacy Policy for details</string>
<string name="pref_ads_summary_personalized">Personalized ads</string>
<string name="pref_ads_summary_non_personalized">Non-personalized ads</string>
<string name="pref_ads_over_18_years_old">I am over 18 years old</string>
<string name="pref_ads_option_personalized">Yes, personalized ads</string>
<string name="pref_ads_option_non_personalized">Yes, non-personalized ads</string>
<string name="pref_settings_advanced_title">Advanced</string> <string name="pref_settings_advanced_title">Advanced</string>
<string name="pref_settings_appearance_title">Appearance &amp; Behavior</string> <string name="pref_settings_appearance_title">Appearance &amp; Behavior</string>
<string name="pref_settings_notifications_title">Notifications</string> <string name="pref_settings_notifications_title">Notifications</string>

View File

@ -623,7 +623,6 @@
<string name="pref_view_present">Anwesendheit zeigen</string> <string name="pref_view_present">Anwesendheit zeigen</string>
<string name="pref_view_app_theme">Thema</string> <string name="pref_view_app_theme">Thema</string>
<string name="pref_view_expand_grade">Steigende Sorten</string> <string name="pref_view_expand_grade">Steigende Sorten</string>
<string name="pref_view_timetable_show_timers">Aktuelle Lektion markieren</string>
<string name="pref_view_timetable_show_groups">Gruppen neben Schulfächen anzeigen</string> <string name="pref_view_timetable_show_groups">Gruppen neben Schulfächen anzeigen</string>
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string> <string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
<string name="pref_view_grade_statistics_list">Liste der Diagramme in Klassenbewertungen anzeigen</string> <string name="pref_view_grade_statistics_list">Liste der Diagramme in Klassenbewertungen anzeigen</string>
@ -671,7 +670,7 @@
<string name="pref_ads_support_category_name">Unterstützung</string> <string name="pref_ads_support_category_name">Unterstützung</string>
<string name="pref_ads_privacy_policy">Datenschutz-Bestimmungen</string> <string name="pref_ads_privacy_policy">Datenschutz-Bestimmungen</string>
<string name="pref_ads_agreements">Vereinbarungen</string> <string name="pref_ads_agreements">Vereinbarungen</string>
<string name="pref_ads_consent">Zustimmung zur Verarbeitung von Daten im Zusammenhang mit Anzeigen</string> <string name="pref_ads_consent">Show consent to data processing</string>
<string name="pref_ads_show_in_app">Anzeigen in der App anzeigen</string> <string name="pref_ads_show_in_app">Anzeigen in der App anzeigen</string>
<string name="pref_ads_support">Einzelanzeige ansehen, um Projekt zu unterstützen</string> <string name="pref_ads_support">Einzelanzeige ansehen, um Projekt zu unterstützen</string>
<string name="pref_ads_privacy_title">Einwilligung in die Datenverarbeitung</string> <string name="pref_ads_privacy_title">Einwilligung in die Datenverarbeitung</string>
@ -680,13 +679,6 @@
<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_ads_over_18_years_old">Ich bin über 18 Jahre alt</string>
<string name="pref_ads_option_personalized">Ja, personalisierte Werbung</string>
<string name="pref_ads_option_non_personalized">Ja, nicht 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 &amp; Verhalten</string> <string name="pref_settings_appearance_title">Aussehen &amp; Verhalten</string>
<string name="pref_settings_notifications_title">Benachrichtigungen</string> <string name="pref_settings_notifications_title">Benachrichtigungen</string>

View File

@ -623,7 +623,6 @@
<string name="pref_view_present">Show presence</string> <string name="pref_view_present">Show presence</string>
<string name="pref_view_app_theme">Theme</string> <string name="pref_view_app_theme">Theme</string>
<string name="pref_view_expand_grade">Grades expanding</string> <string name="pref_view_expand_grade">Grades expanding</string>
<string name="pref_view_timetable_show_timers">Mark current lesson</string>
<string name="pref_view_timetable_show_groups">Show groups next to subjects</string> <string name="pref_view_timetable_show_groups">Show groups next to subjects</string>
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string> <string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
<string name="pref_view_grade_statistics_list">Show chart list in class grades</string> <string name="pref_view_grade_statistics_list">Show chart list in class grades</string>
@ -671,7 +670,7 @@
<string name="pref_ads_support_category_name">Support</string> <string name="pref_ads_support_category_name">Support</string>
<string name="pref_ads_privacy_policy">Privacy Policy</string> <string name="pref_ads_privacy_policy">Privacy Policy</string>
<string name="pref_ads_agreements">Agreements</string> <string name="pref_ads_agreements">Agreements</string>
<string name="pref_ads_consent">Consent to processing of data related to ads</string> <string name="pref_ads_consent">Show consent to data processing</string>
<string name="pref_ads_show_in_app">Show ads in app</string> <string name="pref_ads_show_in_app">Show ads in app</string>
<string name="pref_ads_support">Watch single ad to support project</string> <string name="pref_ads_support">Watch single ad to support project</string>
<string name="pref_ads_privacy_title">Consent to data processing</string> <string name="pref_ads_privacy_title">Consent to data processing</string>
@ -680,13 +679,6 @@
<string name="pref_ads_privacy_link">Privacy policy</string> <string name="pref_ads_privacy_link">Privacy policy</string>
<string name="pref_ads_loading">Ad is loading</string> <string name="pref_ads_loading">Ad is loading</string>
<string name="pref_ads_once_per_visit">Thank you for your support, come back later for more ads</string> <string name="pref_ads_once_per_visit">Thank you for your support, come back later for more ads</string>
<string name="pref_ads_consent_title">Can we use your data to display ads?</string>
<string name="pref_ads_consent_description">You can change your choice anytime in the app settings. We may use your data to display ads tailored to you or, using less of your data, display non-personalized ads. Please see our Privacy Policy for details</string>
<string name="pref_ads_summary_personalized">Personalized ads</string>
<string name="pref_ads_summary_non_personalized">Non-personalized ads</string>
<string name="pref_ads_over_18_years_old">I am over 18 years old</string>
<string name="pref_ads_option_personalized">Yes, personalized ads</string>
<string name="pref_ads_option_non_personalized">Yes, non-personalized ads</string>
<string name="pref_settings_advanced_title">Advanced</string> <string name="pref_settings_advanced_title">Advanced</string>
<string name="pref_settings_appearance_title">Appearance &amp; Behavior</string> <string name="pref_settings_appearance_title">Appearance &amp; Behavior</string>
<string name="pref_settings_notifications_title">Notifications</string> <string name="pref_settings_notifications_title">Notifications</string>

View File

@ -623,7 +623,6 @@
<string name="pref_view_present">Show presence</string> <string name="pref_view_present">Show presence</string>
<string name="pref_view_app_theme">Theme</string> <string name="pref_view_app_theme">Theme</string>
<string name="pref_view_expand_grade">Grades expanding</string> <string name="pref_view_expand_grade">Grades expanding</string>
<string name="pref_view_timetable_show_timers">Mark current lesson</string>
<string name="pref_view_timetable_show_groups">Show groups next to subjects</string> <string name="pref_view_timetable_show_groups">Show groups next to subjects</string>
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string> <string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
<string name="pref_view_grade_statistics_list">Show chart list in class grades</string> <string name="pref_view_grade_statistics_list">Show chart list in class grades</string>
@ -671,7 +670,7 @@
<string name="pref_ads_support_category_name">Support</string> <string name="pref_ads_support_category_name">Support</string>
<string name="pref_ads_privacy_policy">Privacy Policy</string> <string name="pref_ads_privacy_policy">Privacy Policy</string>
<string name="pref_ads_agreements">Agreements</string> <string name="pref_ads_agreements">Agreements</string>
<string name="pref_ads_consent">Consent to processing of data related to ads</string> <string name="pref_ads_consent">Show consent to data processing</string>
<string name="pref_ads_show_in_app">Show ads in app</string> <string name="pref_ads_show_in_app">Show ads in app</string>
<string name="pref_ads_support">Watch single ad to support project</string> <string name="pref_ads_support">Watch single ad to support project</string>
<string name="pref_ads_privacy_title">Consent to data processing</string> <string name="pref_ads_privacy_title">Consent to data processing</string>
@ -680,13 +679,6 @@
<string name="pref_ads_privacy_link">Privacy policy</string> <string name="pref_ads_privacy_link">Privacy policy</string>
<string name="pref_ads_loading">Ad is loading</string> <string name="pref_ads_loading">Ad is loading</string>
<string name="pref_ads_once_per_visit">Thank you for your support, come back later for more ads</string> <string name="pref_ads_once_per_visit">Thank you for your support, come back later for more ads</string>
<string name="pref_ads_consent_title">Can we use your data to display ads?</string>
<string name="pref_ads_consent_description">You can change your choice anytime in the app settings. We may use your data to display ads tailored to you or, using less of your data, display non-personalized ads. Please see our Privacy Policy for details</string>
<string name="pref_ads_summary_personalized">Personalized ads</string>
<string name="pref_ads_summary_non_personalized">Non-personalized ads</string>
<string name="pref_ads_over_18_years_old">I am over 18 years old</string>
<string name="pref_ads_option_personalized">Yes, personalized ads</string>
<string name="pref_ads_option_non_personalized">Yes, non-personalized ads</string>
<string name="pref_settings_advanced_title">Advanced</string> <string name="pref_settings_advanced_title">Advanced</string>
<string name="pref_settings_appearance_title">Appearance &amp; Behavior</string> <string name="pref_settings_appearance_title">Appearance &amp; Behavior</string>
<string name="pref_settings_notifications_title">Notifications</string> <string name="pref_settings_notifications_title">Notifications</string>

View File

@ -713,7 +713,6 @@
<string name="pref_view_present">Pokazuj obecność</string> <string name="pref_view_present">Pokazuj obecność</string>
<string name="pref_view_app_theme">Motyw</string> <string name="pref_view_app_theme">Motyw</string>
<string name="pref_view_expand_grade">Rozwijanie ocen</string> <string name="pref_view_expand_grade">Rozwijanie ocen</string>
<string name="pref_view_timetable_show_timers">Oznaczaj bieżącą lekcję</string>
<string name="pref_view_timetable_show_groups">Pokazuj grupę obok przedmiotu</string> <string name="pref_view_timetable_show_groups">Pokazuj grupę obok przedmiotu</string>
<string name="pref_view_timetable_show_gaps">Pokazuj puste kafelki gdzie nie ma lekcji</string> <string name="pref_view_timetable_show_gaps">Pokazuj puste kafelki gdzie nie ma lekcji</string>
<string name="pref_view_grade_statistics_list">Pokazuj listę wykresów w ocenach klasy</string> <string name="pref_view_grade_statistics_list">Pokazuj listę wykresów w ocenach klasy</string>
@ -761,7 +760,7 @@
<string name="pref_ads_support_category_name">Wsparcie</string> <string name="pref_ads_support_category_name">Wsparcie</string>
<string name="pref_ads_privacy_policy">Polityka prywatności</string> <string name="pref_ads_privacy_policy">Polityka prywatności</string>
<string name="pref_ads_agreements">Zgody</string> <string name="pref_ads_agreements">Zgody</string>
<string name="pref_ads_consent">Zgoda na przetwarzanie danych związanych z reklamami</string> <string name="pref_ads_consent">Pokaż zgodę na przetwarzanie danych</string>
<string name="pref_ads_show_in_app">Pokazuj reklamy w aplikacji</string> <string name="pref_ads_show_in_app">Pokazuj reklamy w aplikacji</string>
<string name="pref_ads_support">Obejrzyj pojedynczą reklamę, aby wesprzeć projekt</string> <string name="pref_ads_support">Obejrzyj pojedynczą reklamę, aby wesprzeć projekt</string>
<string name="pref_ads_privacy_title">Zgoda na przetwarzanie danych</string> <string name="pref_ads_privacy_title">Zgoda na przetwarzanie danych</string>
@ -770,13 +769,6 @@
<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_ads_over_18_years_old">Mam ukończone 18 lat</string>
<string name="pref_ads_option_personalized">Tak, spersonalizowane reklamy</string>
<string name="pref_ads_option_non_personalized">Tak, 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>

View File

@ -713,7 +713,6 @@
<string name="pref_view_present">Показывать присутствия</string> <string name="pref_view_present">Показывать присутствия</string>
<string name="pref_view_app_theme">Тема</string> <string name="pref_view_app_theme">Тема</string>
<string name="pref_view_expand_grade">Разворачивание оценок</string> <string name="pref_view_expand_grade">Разворачивание оценок</string>
<string name="pref_view_timetable_show_timers">Отметить текущий урок</string>
<string name="pref_view_timetable_show_groups">Показать группы рядом с темами</string> <string name="pref_view_timetable_show_groups">Показать группы рядом с темами</string>
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string> <string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
<string name="pref_view_grade_statistics_list">Показывать диаграммы в оценках класса</string> <string name="pref_view_grade_statistics_list">Показывать диаграммы в оценках класса</string>
@ -761,7 +760,7 @@
<string name="pref_ads_support_category_name">Поддержка</string> <string name="pref_ads_support_category_name">Поддержка</string>
<string name="pref_ads_privacy_policy">Политика приватности</string> <string name="pref_ads_privacy_policy">Политика приватности</string>
<string name="pref_ads_agreements">Соглашения</string> <string name="pref_ads_agreements">Соглашения</string>
<string name="pref_ads_consent">Согласие на обработку данных, связанных с объявлениями</string> <string name="pref_ads_consent">Show consent to data processing</string>
<string name="pref_ads_show_in_app">Показать рекламу в приложении</string> <string name="pref_ads_show_in_app">Показать рекламу в приложении</string>
<string name="pref_ads_support">Посмотреть рекламу для поддержки проекта</string> <string name="pref_ads_support">Посмотреть рекламу для поддержки проекта</string>
<string name="pref_ads_privacy_title">Согласие на обработку данных</string> <string name="pref_ads_privacy_title">Согласие на обработку данных</string>
@ -770,13 +769,6 @@
<string name="pref_ads_privacy_link">Политика конфиденциальности</string> <string name="pref_ads_privacy_link">Политика конфиденциальности</string>
<string name="pref_ads_loading">Реклама загружается</string> <string name="pref_ads_loading">Реклама загружается</string>
<string name="pref_ads_once_per_visit">Спасибо за вашу поддержку, возвращайтесь позже для дополнительной рекламы</string> <string name="pref_ads_once_per_visit">Спасибо за вашу поддержку, возвращайтесь позже для дополнительной рекламы</string>
<string name="pref_ads_consent_title">Можем ли мы использовать ваши данные для показа рекламы?</string>
<string name="pref_ads_consent_description">Вы можете изменить свой выбор в любое время в настройках приложения. Мы можем использовать ваши данные для показа объявлений в соответствии с вашими пожеланиями или, используя меньше данных, отображать неперсональную рекламу. Пожалуйста, ознакомьтесь с нашей политикой конфиденциальности для подробностей</string>
<string name="pref_ads_summary_personalized">Персонализированная реклама</string>
<string name="pref_ads_summary_non_personalized">Неперсонализированная реклама</string>
<string name="pref_ads_over_18_years_old">Я старше 18 лет</string>
<string name="pref_ads_option_personalized">Да, персонализировать рекламу</string>
<string name="pref_ads_option_non_personalized">Да, не персонализировать рекламу</string>
<string name="pref_settings_advanced_title">Расширенные</string> <string name="pref_settings_advanced_title">Расширенные</string>
<string name="pref_settings_appearance_title">Внешний вид и поведение</string> <string name="pref_settings_appearance_title">Внешний вид и поведение</string>
<string name="pref_settings_notifications_title">Уведомления</string> <string name="pref_settings_notifications_title">Уведомления</string>

View File

@ -713,7 +713,6 @@
<string name="pref_view_present">Zobraziť prítomnosť</string> <string name="pref_view_present">Zobraziť prítomnosť</string>
<string name="pref_view_app_theme">Motív</string> <string name="pref_view_app_theme">Motív</string>
<string name="pref_view_expand_grade">Rozvijanie známok</string> <string name="pref_view_expand_grade">Rozvijanie známok</string>
<string name="pref_view_timetable_show_timers">Označiť aktuálne lekciu</string>
<string name="pref_view_timetable_show_groups">Zobraziť skupiny vedľa predmetov</string> <string name="pref_view_timetable_show_groups">Zobraziť skupiny vedľa predmetov</string>
<string name="pref_view_timetable_show_gaps">Zobraziť prázdne dlaždice, kde nie je žiadne lekcie</string> <string name="pref_view_timetable_show_gaps">Zobraziť prázdne dlaždice, kde nie je žiadne lekcie</string>
<string name="pref_view_grade_statistics_list">Zobraziť zoznam grafov v známkach triedy</string> <string name="pref_view_grade_statistics_list">Zobraziť zoznam grafov v známkach triedy</string>
@ -761,7 +760,7 @@
<string name="pref_ads_support_category_name">Podpora</string> <string name="pref_ads_support_category_name">Podpora</string>
<string name="pref_ads_privacy_policy">Ochrana osobných údajov</string> <string name="pref_ads_privacy_policy">Ochrana osobných údajov</string>
<string name="pref_ads_agreements">Súhlasy</string> <string name="pref_ads_agreements">Súhlasy</string>
<string name="pref_ads_consent">Súhlas so spracovaním údajov súvisiacich s reklamami</string> <string name="pref_ads_consent">Show consent to data processing</string>
<string name="pref_ads_show_in_app">Zobraziť reklamy v aplikácii</string> <string name="pref_ads_show_in_app">Zobraziť reklamy v aplikácii</string>
<string name="pref_ads_support">Pozrite sa na jednu reklamu pre podporu projektu</string> <string name="pref_ads_support">Pozrite sa na jednu reklamu pre podporu projektu</string>
<string name="pref_ads_privacy_title">Súhlas so spracovaním dát</string> <string name="pref_ads_privacy_title">Súhlas so spracovaním dát</string>
@ -770,13 +769,6 @@
<string name="pref_ads_privacy_link">Ochrana osobných údajov</string> <string name="pref_ads_privacy_link">Ochrana osobných údajov</string>
<string name="pref_ads_loading">Reklama sa načítava</string> <string name="pref_ads_loading">Reklama sa načítava</string>
<string name="pref_ads_once_per_visit">Ďakujeme za vašu podporu, vráťte sa neskôr pre viac reklám</string> <string name="pref_ads_once_per_visit">Ďakujeme za vašu podporu, vráťte sa neskôr pre viac reklám</string>
<string name="pref_ads_consent_title">Môžeme použiť Vaše údaje na zobrazenie reklám?</string>
<string name="pref_ads_consent_description">Voľbu môžete kedykoľvek zmeniť v nastavení aplikácie. Môžeme použiť vaše údaje na zobrazenie reklám šitých pre vás alebo pomocou menej vašich dát zobrazovať neprispôsobené reklamy. Podrobnosti nájdete v našich Zásadách ochrany osobných údajov</string>
<string name="pref_ads_summary_personalized">Prispôsobené reklamy</string>
<string name="pref_ads_summary_non_personalized">Neprispôsobené reklamy</string>
<string name="pref_ads_over_18_years_old">Mám viac ako 18 rokov</string>
<string name="pref_ads_option_personalized">Áno, prispôsobené reklamy</string>
<string name="pref_ads_option_non_personalized">Áno, neprispô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">Vzhľad a správanie</string> <string name="pref_settings_appearance_title">Vzhľad a správanie</string>
<string name="pref_settings_notifications_title">Oznámenia</string> <string name="pref_settings_notifications_title">Oznámenia</string>

View File

@ -713,7 +713,6 @@
<string name="pref_view_present">Показувати присутність</string> <string name="pref_view_present">Показувати присутність</string>
<string name="pref_view_app_theme">Тема</string> <string name="pref_view_app_theme">Тема</string>
<string name="pref_view_expand_grade">Розгортання оцінок</string> <string name="pref_view_expand_grade">Розгортання оцінок</string>
<string name="pref_view_timetable_show_timers">Позначити поточний урок</string>
<string name="pref_view_timetable_show_groups">Показувати групи поруч з темами</string> <string name="pref_view_timetable_show_groups">Показувати групи поруч з темами</string>
<string name="pref_view_timetable_show_gaps">Показувати порожні плитки там, де немає уроків</string> <string name="pref_view_timetable_show_gaps">Показувати порожні плитки там, де немає уроків</string>
<string name="pref_view_grade_statistics_list">Показувати діаграми в оцінках класу</string> <string name="pref_view_grade_statistics_list">Показувати діаграми в оцінках класу</string>
@ -761,7 +760,7 @@
<string name="pref_ads_support_category_name">Підтримка</string> <string name="pref_ads_support_category_name">Підтримка</string>
<string name="pref_ads_privacy_policy">Політика конфіденційності</string> <string name="pref_ads_privacy_policy">Політика конфіденційності</string>
<string name="pref_ads_agreements">Угоди</string> <string name="pref_ads_agreements">Угоди</string>
<string name="pref_ads_consent">Згода на обробку даних, пов\'язаних з рекламою</string> <string name="pref_ads_consent">Показати згоду на обробку даних</string>
<string name="pref_ads_show_in_app">Показувати рекламу в додатку</string> <string name="pref_ads_show_in_app">Показувати рекламу в додатку</string>
<string name="pref_ads_support">Подивіться одну рекламу для підтримки проєкту</string> <string name="pref_ads_support">Подивіться одну рекламу для підтримки проєкту</string>
<string name="pref_ads_privacy_title">Згода в обробці даних</string> <string name="pref_ads_privacy_title">Згода в обробці даних</string>
@ -770,13 +769,6 @@
<string name="pref_ads_privacy_link">Політика конфіденційності</string> <string name="pref_ads_privacy_link">Політика конфіденційності</string>
<string name="pref_ads_loading">Реклама завантажується</string> <string name="pref_ads_loading">Реклама завантажується</string>
<string name="pref_ads_once_per_visit">Дякуємо за вашу підтримку, повертайтеся пізніше для більшої кількості реклам</string> <string name="pref_ads_once_per_visit">Дякуємо за вашу підтримку, повертайтеся пізніше для більшої кількості реклам</string>
<string name="pref_ads_consent_title">Чи можемо ми використовувати ваші дані для висвітлювання реклами?</string>
<string name="pref_ads_consent_description">Ви можете змінити свій вибір в будь-який час в налаштуваннях додатку. Ми можемо використовувати ваші дані для висвітлювання реклами, адаптованої до вас або, використовуючи менше ваших даних, висвітлювати неперсоналізовану рекламу. Перегляньте нашу Політику конфіденційності для подробиць</string>
<string name="pref_ads_summary_personalized">Персоналізована реклама</string>
<string name="pref_ads_summary_non_personalized">Неперсоналізована реклама</string>
<string name="pref_ads_over_18_years_old">Мені більше 18 років</string>
<string name="pref_ads_option_personalized">Так, персоналізована реклама</string>
<string name="pref_ads_option_non_personalized">Так, неперсоналізована реклама</string>
<string name="pref_settings_advanced_title">Додатково</string> <string name="pref_settings_advanced_title">Додатково</string>
<string name="pref_settings_appearance_title">Вигляд та поведінка</string> <string name="pref_settings_appearance_title">Вигляд та поведінка</string>
<string name="pref_settings_notifications_title">Сповіщення</string> <string name="pref_settings_notifications_title">Сповіщення</string>

View File

@ -22,7 +22,6 @@
<bool name="pref_default_timetable_show_groups">false</bool> <bool name="pref_default_timetable_show_groups">false</bool>
<string name="pref_default_timetable_show_whole_class">no</string> <string name="pref_default_timetable_show_whole_class">no</string>
<string name="pref_default_grade_sorting_mode">alphabetic</string> <string name="pref_default_grade_sorting_mode">alphabetic</string>
<bool name="pref_default_timetable_show_timers">false</bool>
<string name="pref_default_timetable_show_gaps">between</string> <string name="pref_default_timetable_show_gaps">between</string>
<bool name="pref_default_subjects_without_grades">false</bool> <bool name="pref_default_subjects_without_grades">false</bool>
<bool name="pref_default_optional_arithmetic_average">false</bool> <bool name="pref_default_optional_arithmetic_average">false</bool>

View File

@ -27,7 +27,6 @@
<string name="pref_key_grade_sorting_mode">grade_sorting_mode</string> <string name="pref_key_grade_sorting_mode">grade_sorting_mode</string>
<string name="pref_key_timetable_show_whole_class">show_whole_class_plan</string> <string name="pref_key_timetable_show_whole_class">show_whole_class_plan</string>
<string name="pref_key_timetable_show_groups">show_groups_in_plan</string> <string name="pref_key_timetable_show_groups">show_groups_in_plan</string>
<string name="pref_key_timetable_show_timers">timetable_show_timers</string>
<string name="pref_key_timetable_show_gaps">timetable_show_gaps</string> <string name="pref_key_timetable_show_gaps">timetable_show_gaps</string>
<string name="pref_key_subjects_without_grades">subjects_without_grades</string> <string name="pref_key_subjects_without_grades">subjects_without_grades</string>
<string name="pref_key_optional_arithmetic_average">optional_arithmetic_average</string> <string name="pref_key_optional_arithmetic_average">optional_arithmetic_average</string>
@ -38,8 +37,7 @@
<string name="pref_key_ads_single_support">single_ad_support</string> <string name="pref_key_ads_single_support">single_ad_support</string>
<string name="pref_key_ads_enabled">ads_enabled</string> <string name="pref_key_ads_enabled">ads_enabled</string>
<string name="pref_key_ads_privacy_policy">ads_privacy_policy</string> <string name="pref_key_ads_privacy_policy">ads_privacy_policy</string>
<string name="pref_key_ads_consent_data_processing">ads_consent_data_processing</string> <string name="pref_key_ads_ump_agreements">ads_ump_agreements</string>
<string name="pref_key_ads_over_eighteen">ads_over_eighteen</string>
<string name="pref_key_incognito_moge">incognito_mode</string> <string name="pref_key_incognito_moge">incognito_mode</string>
<string name="pref_key_menu_order">appearance_menu_order</string> <string name="pref_key_menu_order">appearance_menu_order</string>
</resources> </resources>

View File

@ -701,7 +701,6 @@
<string name="pref_view_present">Show presence</string> <string name="pref_view_present">Show presence</string>
<string name="pref_view_app_theme">Theme</string> <string name="pref_view_app_theme">Theme</string>
<string name="pref_view_expand_grade">Grades expanding</string> <string name="pref_view_expand_grade">Grades expanding</string>
<string name="pref_view_timetable_show_timers">Mark current lesson</string>
<string name="pref_view_timetable_show_groups">Show groups next to subjects</string> <string name="pref_view_timetable_show_groups">Show groups next to subjects</string>
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string> <string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
<string name="pref_view_grade_statistics_list">Show chart list in class grades</string> <string name="pref_view_grade_statistics_list">Show chart list in class grades</string>
@ -750,7 +749,7 @@
<string name="pref_ads_support_category_name">Support</string> <string name="pref_ads_support_category_name">Support</string>
<string name="pref_ads_privacy_policy">Privacy Policy</string> <string name="pref_ads_privacy_policy">Privacy Policy</string>
<string name="pref_ads_agreements">Agreements</string> <string name="pref_ads_agreements">Agreements</string>
<string name="pref_ads_consent">Consent to processing of data related to ads</string> <string name="pref_ads_consent">Show consent to data processing</string>
<string name="pref_ads_show_in_app">Show ads in app</string> <string name="pref_ads_show_in_app">Show ads in app</string>
<string name="pref_ads_support">Watch single ad to support project</string> <string name="pref_ads_support">Watch single ad to support project</string>
<string name="pref_ads_privacy_title">Consent to data processing</string> <string name="pref_ads_privacy_title">Consent to data processing</string>
@ -759,13 +758,6 @@
<string name="pref_ads_privacy_link">Privacy policy</string> <string name="pref_ads_privacy_link">Privacy policy</string>
<string name="pref_ads_loading">Ad is loading</string> <string name="pref_ads_loading">Ad is loading</string>
<string name="pref_ads_once_per_visit">Thank you for your support, come back later for more ads</string> <string name="pref_ads_once_per_visit">Thank you for your support, come back later for more ads</string>
<string name="pref_ads_consent_title">Can we use your data to display ads?</string>
<string name="pref_ads_consent_description">You can change your choice anytime in the app settings. We may use your data to display ads tailored to you or, using less of your data, display non-personalized ads. Please see our Privacy Policy for details</string>
<string name="pref_ads_summary_personalized">Personalized ads</string>
<string name="pref_ads_summary_non_personalized">Non-personalized ads</string>
<string name="pref_ads_over_18_years_old">I am over 18 years old</string>
<string name="pref_ads_option_personalized">Yes, personalized ads</string>
<string name="pref_ads_option_non_personalized">Yes, non-personalized ads</string>
<string name="pref_settings_advanced_title">Advanced</string> <string name="pref_settings_advanced_title">Advanced</string>
<string name="pref_settings_appearance_title">Appearance &amp; Behavior</string> <string name="pref_settings_appearance_title">Appearance &amp; Behavior</string>
<string name="pref_settings_notifications_title">Notifications</string> <string name="pref_settings_notifications_title">Notifications</string>

View File

@ -90,11 +90,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:iconSpaceReserved="false" app:iconSpaceReserved="false"
app:title="@string/pref_timetable_appearance_view"> app:title="@string/pref_timetable_appearance_view">
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_timetable_show_timers"
app:iconSpaceReserved="false"
app:key="@string/pref_key_timetable_show_timers"
app:title="@string/pref_view_timetable_show_timers" />
<SwitchPreferenceCompat <SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_timetable_show_groups" app:defaultValue="@bool/pref_default_timetable_show_groups"
app:iconSpaceReserved="false" app:iconSpaceReserved="false"

Some files were not shown because too many files have changed in this diff Show More