From a2804d813a73014e8b8d27bdc381b7124f1322d7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 24 May 2022 08:41:23 +0000
Subject: [PATCH 001/164] Bump firebase-bom from 30.0.1 to 30.0.2 (#1872)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 7db0acebb..57ad5c903 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -233,7 +233,7 @@ dependencies {
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.7.0'
- playImplementation platform('com.google.firebase:firebase-bom:30.0.1')
+ playImplementation platform('com.google.firebase:firebase-bom:30.0.2')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
From dc717c9fb55a8c7d7305be76e19f68e2553ac31f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 24 May 2022 08:43:32 +0000
Subject: [PATCH 002/164] Bump core-splashscreen from 1.0.0-beta02 to
1.0.0-rc01 (#1871)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 57ad5c903..2cfb7bc6d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -186,7 +186,7 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
implementation "androidx.core:core-ktx:1.7.0"
- implementation 'androidx.core:core-splashscreen:1.0.0-beta02'
+ implementation 'androidx.core:core-splashscreen:1.0.0-rc01'
implementation "androidx.activity:activity-ktx:1.4.0"
implementation "androidx.appcompat:appcompat:1.4.1"
implementation "androidx.fragment:fragment-ktx:1.4.1"
From 808927a58a2e90ee7ddea790d645e407c26d71dd Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 24 May 2022 08:43:52 +0000
Subject: [PATCH 003/164] Bump coil from 2.0.0 to 2.1.0 (#1870)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 2cfb7bc6d..b05e0501c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -228,7 +228,7 @@ dependencies {
implementation "at.favre.lib:slf4j-timber:1.0.1"
implementation 'com.github.bastienpaulfr:Treessence:1.0.5'
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
- implementation "io.coil-kt:coil:2.0.0"
+ implementation "io.coil-kt:coil:2.1.0"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.7.0'
From fa48b033af2fa28f53acdea7d6c35eda4615fb35 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 24 May 2022 08:44:17 +0000
Subject: [PATCH 004/164] Bump constraintlayout from 2.1.3 to 2.1.4 (#1869)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index b05e0501c..ab1593f82 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -196,7 +196,7 @@ dependencies {
implementation "androidx.recyclerview:recyclerview:1.2.1"
implementation "androidx.viewpager2:viewpager2:1.1.0-beta01"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
- implementation "androidx.constraintlayout:constraintlayout:2.1.3"
+ implementation "androidx.constraintlayout:constraintlayout:2.1.4"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
implementation "com.google.android.material:material:1.5.0"
implementation "com.github.wulkanowy:material-chips-input:2.3.1"
From c42a47ac48007e2db05f8f7a1c563414fcad0e7c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 26 May 2022 04:18:37 +0000
Subject: [PATCH 005/164] Bump material from 1.5.0 to 1.6.0 (#1846)
---
app/build.gradle | 2 +-
.../ui/modules/timetablewidget/TimetableWidgetProvider.kt | 2 --
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index ab1593f82..57ba0f591 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -198,7 +198,7 @@ dependencies {
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
- implementation "com.google.android.material:material:1.5.0"
+ implementation "com.google.android.material:material:1.6.0"
implementation "com.github.wulkanowy:material-chips-input:2.3.1"
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
implementation 'com.github.lopspower:CircularImageView:4.2.0'
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt
index 07e717eaf..745769864 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt
@@ -1,6 +1,5 @@
package io.github.wulkanowy.ui.modules.timetablewidget
-import android.annotation.SuppressLint
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetManager.*
@@ -132,7 +131,6 @@ class TimetableWidgetProvider : BroadcastReceiver() {
}
}
- @SuppressLint("DefaultLocale")
private fun updateWidget(
context: Context,
appWidgetId: Int,
From fcf0adfd807015178cdd9bb631c4784cf8f0380f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 26 May 2022 05:26:52 +0000
Subject: [PATCH 006/164] Bump gradle from 7.1.3 to 7.2.0 (#1857)
---
app/build.gradle | 7 +++++--
app/src/main/AndroidManifest.xml | 1 -
build.gradle | 2 +-
3 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 57ba0f591..2a36b19a9 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -15,6 +15,7 @@ apply from: 'sonarqube.gradle'
apply from: 'hooks.gradle'
android {
+ namespace 'io.github.wulkanowy'
compileSdkVersion 31
defaultConfig {
@@ -136,8 +137,10 @@ android {
}
packagingOptions {
- exclude 'META-INF/library_release.kotlin_module'
- exclude 'META-INF/library-core_release.kotlin_module'
+ resources {
+ excludes += ['META-INF/library_release.kotlin_module',
+ 'META-INF/library-core_release.kotlin_module']
+ }
}
aboutLibraries {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 72fee08a7..7835db902 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,7 +1,6 @@
diff --git a/build.gradle b/build.gradle
index c87ec1506..d778e9a63 100644
--- a/build.gradle
+++ b/build.gradle
@@ -13,7 +13,7 @@ buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
- classpath 'com.android.tools.build:gradle:7.1.3'
+ classpath 'com.android.tools.build:gradle:7.2.1'
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.google.gms:google-services:4.3.10'
classpath 'com.huawei.agconnect:agcp:1.6.6.200'
From 5c4a3d578bad1b5ace29a395b94a150529ca9c8b Mon Sep 17 00:00:00 2001
From: Michael <5672750+mibac138@users.noreply.github.com>
Date: Fri, 27 May 2022 22:19:22 +0200
Subject: [PATCH 007/164] Add grade sorting by average (#1863)
---
.../wulkanowy/data/enums/GradeSortingMode.kt | 5 +++--
.../grade/details/GradeDetailsPresenter.kt | 5 +++--
.../grade/summary/GradeSummaryPresenter.kt | 16 +++++++++++++++-
app/src/main/res/values/preferences_values.xml | 2 ++
4 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/app/src/main/java/io/github/wulkanowy/data/enums/GradeSortingMode.kt b/app/src/main/java/io/github/wulkanowy/data/enums/GradeSortingMode.kt
index c5c0196c9..a7aa4cc2f 100644
--- a/app/src/main/java/io/github/wulkanowy/data/enums/GradeSortingMode.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/enums/GradeSortingMode.kt
@@ -2,9 +2,10 @@ package io.github.wulkanowy.data.enums
enum class GradeSortingMode(val value: String) {
ALPHABETIC("alphabetic"),
- DATE("date");
+ DATE("date"),
+ AVERAGE("average");
companion object {
fun getByValue(value: String) = values().find { it.value == value } ?: ALPHABETIC
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt
index 746601a68..8cde5d6b9 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt
@@ -3,8 +3,8 @@ package io.github.wulkanowy.ui.modules.grade.details
import io.github.wulkanowy.data.*
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.enums.GradeExpandMode
-import io.github.wulkanowy.data.enums.GradeSortingMode.ALPHABETIC
-import io.github.wulkanowy.data.enums.GradeSortingMode.DATE
+import io.github.wulkanowy.data.enums.GradeSortingMode
+import io.github.wulkanowy.data.enums.GradeSortingMode.*
import io.github.wulkanowy.data.repositories.GradeRepository
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.SemesterRepository
@@ -204,6 +204,7 @@ class GradeDetailsPresenter @Inject constructor(
ALPHABETIC -> gradeSubjects.sortedBy { gradeDetailsWithAverage ->
gradeDetailsWithAverage.subject.lowercase()
}
+ AVERAGE -> gradeSubjects.sortedByDescending { it.average }
}
}
.map { (subject, average, points, _, grades) ->
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt
index b07570cb2..4d5a43d8f 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt
@@ -2,6 +2,9 @@ package io.github.wulkanowy.ui.modules.grade.summary
import io.github.wulkanowy.data.*
import io.github.wulkanowy.data.db.entities.GradeSummary
+import io.github.wulkanowy.data.enums.GradeSortingMode
+import io.github.wulkanowy.data.enums.GradeSortingMode.*
+import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
@@ -14,6 +17,7 @@ import javax.inject.Inject
class GradeSummaryPresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
+ private val preferencesRepository: PreferencesRepository,
private val averageProvider: GradeAverageProvider,
private val analytics: AnalyticsHelper
) : BasePresenter(errorHandler, studentRepository) {
@@ -127,7 +131,17 @@ class GradeSummaryPresenter @Inject constructor(
private fun createGradeSummaryItems(items: List): List {
return items
.filter { !checkEmpty(it) }
- .sortedBy { it.subject }
+ .let { gradeSubjects ->
+ when (preferencesRepository.gradeSortingMode) {
+ DATE -> gradeSubjects.sortedByDescending { gradeDetailsWithAverage ->
+ gradeDetailsWithAverage.grades.maxByOrNull { it.date }?.date
+ }
+ ALPHABETIC -> gradeSubjects.sortedBy { gradeDetailsWithAverage ->
+ gradeDetailsWithAverage.subject.lowercase()
+ }
+ AVERAGE -> gradeSubjects.sortedByDescending { it.average }
+ }
+ }
.map { it.summary.copy(average = it.average) }
}
diff --git a/app/src/main/res/values/preferences_values.xml b/app/src/main/res/values/preferences_values.xml
index 1d777bdb6..312f0b878 100644
--- a/app/src/main/res/values/preferences_values.xml
+++ b/app/src/main/res/values/preferences_values.xml
@@ -82,10 +82,12 @@
- Alphabetically
- By date
+ - By average
- alphabetic
- date
+ - average
From 891e241d1a7cb516a9233d0e5c270d0593e35600 Mon Sep 17 00:00:00 2001
From: Michael <5672750+mibac138@users.noreply.github.com>
Date: Sat, 28 May 2022 02:03:42 +0200
Subject: [PATCH 008/164] Hide account selector in MessagePreviewView and
SendMessageView (#1866)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Rafał Borcz
---
.../message/preview/MessagePreviewFragment.kt | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt
index 860ecc571..4b2685c6d 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt
@@ -57,7 +57,8 @@ class MessagePreviewFragment :
get() = getString(R.string.message_no_subject)
override val printHTML: String
- get() = requireContext().assets.open("message-print-page.html").bufferedReader().use { it.readText() }
+ get() = requireContext().assets.open("message-print-page.html").bufferedReader()
+ .use { it.readText() }
override val messageNotExists: String
get() = getString(R.string.message_not_exists)
@@ -81,7 +82,10 @@ class MessagePreviewFragment :
super.onViewCreated(view, savedInstanceState)
binding = FragmentMessagePreviewBinding.bind(view)
messageContainer = binding.messagePreviewContainer
- presenter.onAttachView(this, (savedInstanceState ?: arguments)?.getSerializable(MESSAGE_ID_KEY) as? Message)
+ presenter.onAttachView(
+ this,
+ (savedInstanceState ?: arguments)?.getSerializable(MESSAGE_ID_KEY) as? Message
+ )
}
override fun initView() {
@@ -101,6 +105,8 @@ class MessagePreviewFragment :
menuShareButton = menu.findItem(R.id.messagePreviewMenuShare)
menuPrintButton = menu.findItem(R.id.messagePreviewMenuPrint)
presenter.onCreateOptionsMenu()
+
+ menu.findItem(R.id.mainMenuAccount).isVisible = false
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
@@ -173,7 +179,8 @@ class MessagePreviewFragment :
val webView = WebView(requireContext())
webView.webViewClient = object : WebViewClient() {
- override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest) = false
+ override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest) =
+ false
override fun onPageFinished(view: WebView, url: String) {
createWebPrintJob(view, jobName)
From d2d1d1dba71a7e6b03a78fe921fc15534cffd080 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 31 May 2022 13:50:03 +0000
Subject: [PATCH 009/164] Bump firebase-bom from 30.0.2 to 30.1.0 (#1878)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 2a36b19a9..691d00f64 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -236,7 +236,7 @@ dependencies {
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.7.0'
- playImplementation platform('com.google.firebase:firebase-bom:30.0.2')
+ playImplementation platform('com.google.firebase:firebase-bom:30.1.0')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
From d074e5c9b322e317e010ffb0744b643f2df2541a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 31 May 2022 13:50:22 +0000
Subject: [PATCH 010/164] Bump play-services-ads from 20.6.0 to 21.0.0 (#1877)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 691d00f64..c9c7a9ef9 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -242,7 +242,7 @@ dependencies {
playImplementation 'com.google.firebase:firebase-crashlytics:'
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:20.6.0'
+ playImplementation 'com.google.android.gms:play-services-ads:21.0.0'
hmsImplementation 'com.huawei.hms:hianalytics:6.5.0.300'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.6.200'
From 4f3f24ac104a986a8dd42425668ed9ee576b825e Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 31 May 2022 13:50:52 +0000
Subject: [PATCH 011/164] Bump about_libraries from 10.2.0 to 10.3.0 (#1876)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index d778e9a63..5a498be90 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,7 @@
buildscript {
ext {
kotlin_version = '1.6.21'
- about_libraries = '10.2.0'
+ about_libraries = '10.3.0'
hilt_version = "2.42"
}
repositories {
From 8dcb3ed45d2625b4208df856099ad58c29a29d3b Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 31 May 2022 13:51:12 +0000
Subject: [PATCH 012/164] Bump firebase-crashlytics-gradle from 2.8.1 to 2.9.0
(#1874)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 5a498be90..7640fbc48 100644
--- a/build.gradle
+++ b/build.gradle
@@ -17,7 +17,7 @@ buildscript {
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.google.gms:google-services:4.3.10'
classpath 'com.huawei.agconnect:agcp:1.6.6.200'
- classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
+ classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.0'
classpath "com.github.triplet.gradle:play-publisher:3.6.0"
classpath "ru.cian:huawei-publish-gradle-plugin:1.3.3"
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.3"
From 8c515bd03f73f41d82f69c29a2d52f5537ae53c7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 31 May 2022 13:52:09 +0000
Subject: [PATCH 013/164] Bump coroutines from 1.6.1 to 1.6.2 (#1875)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index c9c7a9ef9..612cb9536 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -177,7 +177,7 @@ ext {
room = "2.4.2"
chucker = "3.5.2"
mockk = "1.12.4"
- coroutines = "1.6.1"
+ coroutines = "1.6.2"
}
dependencies {
From cce736410bd54e0f186191623be47c09582b89b3 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 13 Jun 2022 04:59:31 +0000
Subject: [PATCH 014/164] Bump material from 1.6.0 to 1.6.1 (#1884)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 612cb9536..1038184f2 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -201,7 +201,7 @@ dependencies {
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
- implementation "com.google.android.material:material:1.6.0"
+ implementation "com.google.android.material:material:1.6.1"
implementation "com.github.wulkanowy:material-chips-input:2.3.1"
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
implementation 'com.github.lopspower:CircularImageView:4.2.0'
From 03ad5527f8d83526d751042a5ef32d77a6056392 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 13 Jun 2022 04:59:50 +0000
Subject: [PATCH 015/164] Bump appcompat from 1.4.1 to 1.4.2 (#1883)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 1038184f2..1f680e265 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -191,7 +191,7 @@ dependencies {
implementation "androidx.core:core-ktx:1.7.0"
implementation 'androidx.core:core-splashscreen:1.0.0-rc01'
implementation "androidx.activity:activity-ktx:1.4.0"
- implementation "androidx.appcompat:appcompat:1.4.1"
+ implementation "androidx.appcompat:appcompat:1.4.2"
implementation "androidx.fragment:fragment-ktx:1.4.1"
implementation "androidx.annotation:annotation:1.3.0"
From f61d820d6fd33babb7d85cee7dff22ba80eb5d42 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 13 Jun 2022 05:07:54 +0000
Subject: [PATCH 016/164] Bump core-ktx from 1.7.0 to 1.8.0 (#1882)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 1f680e265..aa7f6b37b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -188,7 +188,7 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
- implementation "androidx.core:core-ktx:1.7.0"
+ implementation "androidx.core:core-ktx:1.8.0"
implementation 'androidx.core:core-splashscreen:1.0.0-rc01'
implementation "androidx.activity:activity-ktx:1.4.0"
implementation "androidx.appcompat:appcompat:1.4.2"
From c3cbaa6ac2f4a58b36572ed64e0d2b68049c795f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Borcz?=
Date: Mon, 13 Jun 2022 07:43:12 +0200
Subject: [PATCH 017/164] Update dependencies (#1887)
---
app/build.gradle | 4 ++--
.../wulkanowy/ui/modules/login/LoginActivity.kt | 1 +
.../ui/modules/login/recover/LoginRecoverFragment.kt | 11 ++++-------
.../github/wulkanowy/ui/modules/main/MainActivity.kt | 1 +
build.gradle | 2 +-
5 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index aa7f6b37b..230afdfe9 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -16,13 +16,13 @@ apply from: 'hooks.gradle'
android {
namespace 'io.github.wulkanowy'
- compileSdkVersion 31
+ compileSdkVersion 32
defaultConfig {
applicationId "io.github.wulkanowy"
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 21
- targetSdkVersion 31
+ targetSdkVersion 32
versionCode 108
versionName "1.6.4"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt
index d7d77f73d..aac60b56d 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt
@@ -93,6 +93,7 @@ class LoginActivity : BaseActivity(), Logi
}
//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)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverFragment.kt
index c1c111d46..786bbfce8 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverFragment.kt
@@ -6,9 +6,7 @@ import android.os.Bundle
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
-import android.webkit.JavascriptInterface
-import android.webkit.WebView
-import android.webkit.WebViewClient
+import android.webkit.*
import androidx.core.view.isVisible
import androidx.core.widget.doOnTextChanged
import com.yariksoffice.lingver.Lingver
@@ -206,10 +204,9 @@ class LoginRecoverFragment :
}
override fun onReceivedError(
- view: WebView,
- errorCode: Int,
- description: String,
- failingUrl: String
+ view: WebView?,
+ request: WebResourceRequest?,
+ error: WebResourceError?
) {
recoverWebViewSuccess = false
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt
index 1bfc8ba58..260cf76c5 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt
@@ -100,6 +100,7 @@ class MainActivity : BaseActivity(), MainVie
}
//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)
diff --git a/build.gradle b/build.gradle
index 7640fbc48..3a8ae20cc 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,6 @@
buildscript {
ext {
- kotlin_version = '1.6.21'
+ kotlin_version = '1.7.0'
about_libraries = '10.3.0'
hilt_version = "2.42"
}
From 6b705835735892114de3d666817ee00a3b69a0f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Borcz?=
Date: Mon, 13 Jun 2022 07:43:40 +0200
Subject: [PATCH 018/164] New Crowdin updates (#1873)
---
app/src/main/res/values-cs/preferences_values.xml | 1 +
app/src/main/res/values-de/preferences_values.xml | 1 +
app/src/main/res/values-pl/preferences_values.xml | 1 +
app/src/main/res/values-pl/strings.xml | 2 +-
app/src/main/res/values-ru/preferences_values.xml | 1 +
app/src/main/res/values-sk/preferences_values.xml | 1 +
app/src/main/res/values-uk/preferences_values.xml | 1 +
7 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/app/src/main/res/values-cs/preferences_values.xml b/app/src/main/res/values-cs/preferences_values.xml
index 5252f79b8..c8731372f 100644
--- a/app/src/main/res/values-cs/preferences_values.xml
+++ b/app/src/main/res/values-cs/preferences_values.xml
@@ -34,6 +34,7 @@
- Abecedně
- Podle data
+ - By average
- Dzienniczek+
diff --git a/app/src/main/res/values-de/preferences_values.xml b/app/src/main/res/values-de/preferences_values.xml
index 08b9d240b..097e90e96 100644
--- a/app/src/main/res/values-de/preferences_values.xml
+++ b/app/src/main/res/values-de/preferences_values.xml
@@ -34,6 +34,7 @@
- Alphabetisch
- Nach Datum
+ - By average
- Dzienniczek+
diff --git a/app/src/main/res/values-pl/preferences_values.xml b/app/src/main/res/values-pl/preferences_values.xml
index c823e9608..456005747 100644
--- a/app/src/main/res/values-pl/preferences_values.xml
+++ b/app/src/main/res/values-pl/preferences_values.xml
@@ -34,6 +34,7 @@
- Alfabetycznie
- Według daty
+ - Według średniej
- Dzienniczek+
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 1607b17c6..91e9fe7f3 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -94,7 +94,7 @@
Przewidywana ocena
Obliczona średnia
Jak działa obliczona średnia?
- Obliczona średnia jest średnią arytmetyczną obliczoną ze średnich przedmiotów. Pozwala ona na poznanie przybliżonej średniej końcowej. Jest obliczana w sposób wybrany przez użytkownika w ustawieniach aplikacji. Zaleca się wybranie odpowiedniej opcji. Dzieje się tak dlatego, że obliczanie średnich w szkołach różni się. Dodatkowo, jeśli twoja szkoła ma włączone średnie przedmiotów na stronie dziennika Vulcan, aplikacja pobiera je i ich nie oblicza. Można to zmienić, wymuszając obliczanie średniej w ustawieniach aplikacji.\n\nŚrednia ocen tylko z wybranego semestru:\n1. Obliczanie średniej arytmetycznej każdego przedmiotu w danym semestrze\n2. Zsumowanie obliczonych średnich\n3. Obliczanie średniej arytmetycznej zsumowanych średnich\n\nŚrednia ze średnich z obu semestrów:\n1.Obliczanie średniej arytmetycznej każdego przedmiotu w semestrze 1 i 2\n2. Obliczanie średniej arytmetycznej obliczonych średnich w semetrze 1 i 2 każdego przedmiotu.\n3. Zsumowanie obliczonych średnich\n4. Obliczanie średniej arytmetycznej zsumowanych średnich\n\nŚrednia wszystkich ocen z całego roku:\n1. Obliczanie średniej arytmetycznej z każdego przedmiotu w ciągu całego roku. Końcowa ocena w 1 semestrze jest bez znaczenia.\n3. Zsumowanie obliczonych średnich\n4. Obliczanie średniej arytmetycznej z zsumowanych średnich
+ Obliczona średnia jest średnią arytmetyczną obliczoną ze średnich przedmiotów. Pozwala ona na poznanie przybliżonej średniej końcowej. Jest obliczana w sposób wybrany przez użytkownika w ustawieniach aplikacji. Zaleca się wybranie odpowiedniej opcji. Dzieje się tak dlatego, że obliczanie średnich w szkołach różni się. Dodatkowo, jeśli twoja szkoła ma włączone średnie przedmiotów na stronie dziennika Vulcan, aplikacja pobiera je i ich nie oblicza. Można to zmienić, wymuszając obliczanie średniej w ustawieniach aplikacji.\n\nŚrednia ocen tylko z wybranego semestru:\n1. Obliczanie średniej arytmetycznej każdego przedmiotu w danym semestrze\n2. Zsumowanie obliczonych średnich\n3. Obliczanie średniej arytmetycznej zsumowanych średnich\n\nŚrednia ze średnich z obu semestrów:\n1.Obliczanie średniej arytmetycznej każdego przedmiotu w semestrze 1 i 2\n2. Obliczanie średniej arytmetycznej obliczonych średnich w semestrze 1 i 2 każdego przedmiotu.\n3. Zsumowanie obliczonych średnich\n4. Obliczanie średniej arytmetycznej zsumowanych średnich\n\nŚrednia wszystkich ocen z całego roku:\n1. Obliczanie średniej arytmetycznej z każdego przedmiotu w ciągu całego roku. Końcowa ocena w 1 semestrze jest bez znaczenia.\n3. Zsumowanie obliczonych średnich\n4. Obliczanie średniej arytmetycznej z zsumowanych średnich
Jak działa końcowa średnia?
Średnią końcową jest średnia arytmetyczna obliczona na podstawie wszystkich obecnie dostępnych ocen końcowych w danym semestrze.\n\nSchemat obliczeń składa się z następujących kroków:\n1. Sumowanie końcowych ocen wpisanych przez nauczycieli\n2. Dzielenie przez liczbę przedmiotów, z których oceny zostały już wystawione
Końcowa średnia
diff --git a/app/src/main/res/values-ru/preferences_values.xml b/app/src/main/res/values-ru/preferences_values.xml
index 9cc37620e..8a8c260da 100644
--- a/app/src/main/res/values-ru/preferences_values.xml
+++ b/app/src/main/res/values-ru/preferences_values.xml
@@ -34,6 +34,7 @@
- В алфавитном порядке
- По дате
+ - По средней
- Dzienniczek+
diff --git a/app/src/main/res/values-sk/preferences_values.xml b/app/src/main/res/values-sk/preferences_values.xml
index e64f5606a..ab0a43b64 100644
--- a/app/src/main/res/values-sk/preferences_values.xml
+++ b/app/src/main/res/values-sk/preferences_values.xml
@@ -34,6 +34,7 @@
- Abecedne
- Podľa dátumu
+ - By average
- Dzienniczek+
diff --git a/app/src/main/res/values-uk/preferences_values.xml b/app/src/main/res/values-uk/preferences_values.xml
index 82c5b6ecc..44acd18e9 100644
--- a/app/src/main/res/values-uk/preferences_values.xml
+++ b/app/src/main/res/values-uk/preferences_values.xml
@@ -34,6 +34,7 @@
- За алфавітом
- За датою
+ - За середньою
- Dzienniczek+
From 06ed5f6079ae17c2a63b2a9088fff476c5a4b4b2 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 16 Jun 2022 21:53:21 +0000
Subject: [PATCH 019/164] Bump logging-interceptor from 4.9.3 to 4.10.0 (#1889)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 230afdfe9..f3f39258c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -225,7 +225,7 @@ dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0"
- implementation "com.squareup.okhttp3:logging-interceptor:4.9.3"
+ implementation "com.squareup.okhttp3:logging-interceptor:4.10.0"
implementation "com.jakewharton.timber:timber:5.0.1"
implementation "at.favre.lib:slf4j-timber:1.0.1"
From cd59166efbd4bea7f79f2cdfc262212e0fcee8d0 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 16 Jun 2022 22:15:18 +0000
Subject: [PATCH 020/164] Bump sonarqube-gradle-plugin from 3.3 to 3.4.0.2513
(#1888)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 3a8ae20cc..9dde0b283 100644
--- a/build.gradle
+++ b/build.gradle
@@ -20,7 +20,7 @@ buildscript {
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.0'
classpath "com.github.triplet.gradle:play-publisher:3.6.0"
classpath "ru.cian:huawei-publish-gradle-plugin:1.3.3"
- classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.3"
+ classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513"
classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0"
classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$about_libraries"
}
From bfab265ccf4f5a0809788d92f535c7106bef8a0c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Borcz?=
Date: Sat, 18 Jun 2022 11:54:08 +0200
Subject: [PATCH 021/164] Fix case sensitive domain checker (#1894)
---
app/build.gradle | 2 +-
.../wulkanowy/ui/modules/login/form/LoginFormPresenter.kt | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index f3f39258c..e629134e0 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -181,7 +181,7 @@ ext {
}
dependencies {
- implementation "io.github.wulkanowy:sdk:1.6.4"
+ implementation "io.github.wulkanowy:sdk:16811fbe90"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt
index b4291ff47..0acb0ea6d 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt
@@ -172,7 +172,7 @@ class LoginFormPresenter @Inject constructor(
if ("@" in login && "||" !in login && "login" !in host && "email" !in host) {
val emailHost = login.substringAfter("@")
val emailDomain = URL(host).host
- if (emailHost != emailDomain) {
+ if (!emailHost.equals(emailDomain, true)) {
view?.setErrorEmailInvalid(domain = emailDomain)
isCorrect = false
}
From 0a2eb0784469afd19c837af49a1e7d5e45001567 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Borcz?=
Date: Sat, 18 Jun 2022 12:11:46 +0200
Subject: [PATCH 022/164] Fix date in attendance and timetable when day is
changing (#1893)
---
.../modules/attendance/AttendancePresenter.kt | 18 +++++++++++-------
.../ui/modules/timetable/TimetablePresenter.kt | 18 +++++++++++-------
2 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt
index 7fcbd002e..26bfaf19f 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt
@@ -91,15 +91,19 @@ class AttendancePresenter @Inject constructor(
fun onViewReselected() {
Timber.i("Attendance view is reselected")
- view?.also { view ->
+ view?.let { view ->
if (view.currentStackSize == 1) {
- baseDate.also {
- if (currentDate != it) {
- reloadView(it)
- loadData()
- } else if (!view.isViewEmpty) view.resetView()
+ baseDate = now().previousOrSameSchoolDay
+
+ if (currentDate != baseDate) {
+ reloadView(baseDate)
+ loadData()
+ } else if (!view.isViewEmpty) {
+ view.resetView()
}
- } else view.popView()
+ } else {
+ view.popView()
+ }
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt
index dc6c89213..d06874082 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt
@@ -87,15 +87,19 @@ class TimetablePresenter @Inject constructor(
fun onViewReselected() {
Timber.i("Timetable view is reselected")
- view?.also { view ->
+ view?.let { view ->
if (view.currentStackSize == 1) {
- baseDate.also {
- if (currentDate != it) {
- reloadView(it)
- loadData()
- } else if (!view.isViewEmpty) view.resetView()
+ baseDate = now().nextOrSameSchoolDay
+
+ if (currentDate != baseDate) {
+ reloadView(baseDate)
+ loadData()
+ } else if (!view.isViewEmpty) {
+ view.resetView()
}
- } else view.popView()
+ } else {
+ view.popView()
+ }
}
}
From a264abf8144f8ce4ba8f9370333ef8163a0e87d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Borcz?=
Date: Sat, 18 Jun 2022 12:12:04 +0200
Subject: [PATCH 023/164] Fix typo in average description (#1892)
---
app/src/main/res/values/strings.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ff25da7f5..2ca516adf 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -104,7 +104,7 @@
Predicted grade
Calculated average
How does Calculated Average work?
- The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\nAverage of grades only from selected semester:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\nAverage of averages from both semesters:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\nAverage of grades from the whole year:\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n3. Adding calculated averages\n4. Calculating the arithmetic average of summed averages
+ The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\nAverage of grades only from selected semester:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\nAverage of averages from both semesters:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\nAverage of grades from the whole year:\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n2. Adding calculated averages\n3. Calculating the arithmetic average of summed averages
How does the Final Average work?
The Final Average is the arithmetic average calculated from all currently available final grades in the given semester.\n\nThe calculation scheme consists of the following steps:\n1. Summing up the final grades given by teachers\n2. Divide by the number of subjects that have already been graded
Final average
From e9ba65f8f67e0afab0a1f27740abb863810cbac2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Borcz?=
Date: Sat, 18 Jun 2022 12:12:21 +0200
Subject: [PATCH 024/164] Fix multiline address in student info (#1891)
---
app/src/main/res/layout/fragment_student_info.xml | 4 ++--
app/src/main/res/layout/item_student_info.xml | 9 +++++----
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/app/src/main/res/layout/fragment_student_info.xml b/app/src/main/res/layout/fragment_student_info.xml
index d270da4a0..f72fed2ff 100644
--- a/app/src/main/res/layout/fragment_student_info.xml
+++ b/app/src/main/res/layout/fragment_student_info.xml
@@ -37,7 +37,7 @@
android:padding="10dp"
android:visibility="gone"
tools:ignore="UseCompoundDrawables"
- tools:visibility="visible">
+ tools:visibility="gone">
+ tools:visibility="gone">
+ android:focusable="true"
+ android:minHeight="64dp">
Date: Sun, 19 Jun 2022 21:04:05 +0200
Subject: [PATCH 025/164] Fix jumping point in notes on refresh (#1898)
---
app/src/main/res/layout/fragment_note.xml | 4 +++-
app/src/main/res/layout/item_note.xml | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/app/src/main/res/layout/fragment_note.xml b/app/src/main/res/layout/fragment_note.xml
index f62a11a64..969003cc0 100644
--- a/app/src/main/res/layout/fragment_note.xml
+++ b/app/src/main/res/layout/fragment_note.xml
@@ -19,7 +19,9 @@
+ android:layout_height="match_parent"
+ tools:itemCount="4"
+ tools:listitem="@layout/item_note" />
Date: Thu, 23 Jun 2022 12:09:25 +0000
Subject: [PATCH 026/164] Bump coroutines from 1.6.2 to 1.6.3 (#1902)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index e629134e0..7c8046dad 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -177,7 +177,7 @@ ext {
room = "2.4.2"
chucker = "3.5.2"
mockk = "1.12.4"
- coroutines = "1.6.2"
+ coroutines = "1.6.3"
}
dependencies {
From c5dfea788c1a492b3cf06f4d00c99ac1fb4899a2 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 23 Jun 2022 12:09:50 +0000
Subject: [PATCH 027/164] Bump annotation from 1.3.0 to 1.4.0 (#1900)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 7c8046dad..3e4912063 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -193,7 +193,7 @@ dependencies {
implementation "androidx.activity:activity-ktx:1.4.0"
implementation "androidx.appcompat:appcompat:1.4.2"
implementation "androidx.fragment:fragment-ktx:1.4.1"
- implementation "androidx.annotation:annotation:1.3.0"
+ implementation "androidx.annotation:annotation:1.4.0"
implementation "androidx.preference:preference-ktx:1.2.0"
implementation "androidx.recyclerview:recyclerview:1.2.1"
From 0fb55bd6c64c78f1b4e110c444f84c9094a27089 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Borcz?=
Date: Sun, 26 Jun 2022 12:12:11 +0200
Subject: [PATCH 028/164] Fix doubled announcements (#1897)
---
.../49.json | 2445 +++++++++++++++++
.../github/wulkanowy/data/db/AppDatabase.kt | 3 +-
.../data/db/dao/SchoolAnnouncementDao.kt | 4 +-
.../data/db/entities/SchoolAnnouncement.kt | 4 +-
.../data/db/migrations/Migration49.kt | 23 +
.../data/mappers/DirectorInformationMapper.kt | 2 +-
.../SchoolAnnouncementRepository.kt | 7 +-
.../sync/works/SchoolAnnouncementWork.kt | 12 +-
.../notification/mock/schoolAnnouncement.kt | 2 +-
9 files changed, 2488 insertions(+), 14 deletions(-)
create mode 100644 app/schemas/io.github.wulkanowy.data.db.AppDatabase/49.json
create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration49.kt
diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/49.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/49.json
new file mode 100644
index 000000000..5472fb78a
--- /dev/null
+++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/49.json
@@ -0,0 +1,2445 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 49,
+ "identityHash": "790d4dc0e11f38349c49af85fabf9b7b",
+ "entities": [
+ {
+ "tableName": "Students",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`scrapper_base_url` TEXT NOT NULL, `mobile_base_url` TEXT NOT NULL, `login_type` TEXT NOT NULL, `login_mode` TEXT NOT NULL, `certificate_key` TEXT NOT NULL, `private_key` TEXT NOT NULL, `is_parent` INTEGER NOT NULL, `email` TEXT NOT NULL, `password` TEXT NOT NULL, `symbol` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `user_login_id` INTEGER NOT NULL, `user_name` TEXT NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_short` TEXT NOT NULL, `school_name` TEXT NOT NULL, `class_name` TEXT NOT NULL, `class_id` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `registration_date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `nick` TEXT NOT NULL, `avatar_color` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "scrapperBaseUrl",
+ "columnName": "scrapper_base_url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mobileBaseUrl",
+ "columnName": "mobile_base_url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginType",
+ "columnName": "login_type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginMode",
+ "columnName": "login_mode",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "certificateKey",
+ "columnName": "certificate_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "privateKey",
+ "columnName": "private_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isParent",
+ "columnName": "is_parent",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "password",
+ "columnName": "password",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "symbol",
+ "columnName": "symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "user_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentName",
+ "columnName": "student_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolSymbol",
+ "columnName": "school_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolShortName",
+ "columnName": "school_short",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolName",
+ "columnName": "school_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "className",
+ "columnName": "class_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isCurrent",
+ "columnName": "is_current",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registrationDate",
+ "columnName": "registration_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "nick",
+ "columnName": "nick",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "avatarColor",
+ "columnName": "avatar_color",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_Students_email_symbol_student_id_school_id_class_id",
+ "unique": true,
+ "columnNames": [
+ "email",
+ "symbol",
+ "student_id",
+ "school_id",
+ "class_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Students_email_symbol_student_id_school_id_class_id` ON `${TABLE_NAME}` (`email`, `symbol`, `student_id`, `school_id`, `class_id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Semesters",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `kindergarten_diary_id` INTEGER NOT NULL DEFAULT 0, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "kindergartenDiaryId",
+ "columnName": "kindergarten_diary_id",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ },
+ {
+ "fieldPath": "diaryName",
+ "columnName": "diary_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolYear",
+ "columnName": "school_year",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterName",
+ "columnName": "semester_name",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unitId",
+ "columnName": "unit_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "current",
+ "columnName": "is_current",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id",
+ "unique": true,
+ "columnNames": [
+ "student_id",
+ "diary_id",
+ "kindergarten_diary_id",
+ "semester_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id` ON `${TABLE_NAME}` (`student_id`, `diary_id`, `kindergarten_diary_id`, `semester_id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Exams",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `group` TEXT NOT NULL, `type` TEXT NOT NULL, `description` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entryDate",
+ "columnName": "entry_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "group",
+ "columnName": "group",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Timetable",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `number` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `subjectOld` TEXT NOT NULL, `group` TEXT NOT NULL, `room` TEXT NOT NULL, `roomOld` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacherOld` TEXT NOT NULL, `info` TEXT NOT NULL, `student_plan` INTEGER NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectOld",
+ "columnName": "subjectOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "group",
+ "columnName": "group",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "room",
+ "columnName": "room",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "roomOld",
+ "columnName": "roomOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherOld",
+ "columnName": "teacherOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "info",
+ "columnName": "info",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isStudentPlan",
+ "columnName": "student_plan",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "changes",
+ "columnName": "changes",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "canceled",
+ "columnName": "canceled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Attendance",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `time_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `excused` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `excusable` INTEGER NOT NULL, `excuse_status` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "timeId",
+ "columnName": "time_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presence",
+ "columnName": "presence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "exemption",
+ "columnName": "exemption",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lateness",
+ "columnName": "lateness",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excused",
+ "columnName": "excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deleted",
+ "columnName": "deleted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excusable",
+ "columnName": "excusable",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excuseStatus",
+ "columnName": "excuse_status",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AttendanceSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `subject_id` INTEGER NOT NULL, `month` INTEGER NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `absence_excused` INTEGER NOT NULL, `absence_for_school_reasons` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `lateness_excused` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subject_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "month",
+ "columnName": "month",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presence",
+ "columnName": "presence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absenceExcused",
+ "columnName": "absence_excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absenceForSchoolReasons",
+ "columnName": "absence_for_school_reasons",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lateness",
+ "columnName": "lateness",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "latenessExcused",
+ "columnName": "lateness_excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "exemption",
+ "columnName": "exemption",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Grades",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `entry` TEXT NOT NULL, `value` REAL NOT NULL, `modifier` REAL NOT NULL, `comment` TEXT NOT NULL, `color` TEXT NOT NULL, `grade_symbol` TEXT NOT NULL, `description` TEXT NOT NULL, `weight` TEXT NOT NULL, `weightValue` REAL NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entry",
+ "columnName": "entry",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "modifier",
+ "columnName": "modifier",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "color",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gradeSymbol",
+ "columnName": "grade_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weightValue",
+ "columnName": "weightValue",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isRead",
+ "columnName": "is_read",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `position` INTEGER NOT NULL, `subject` TEXT NOT NULL, `predicted_grade` TEXT NOT NULL, `final_grade` TEXT NOT NULL, `proposed_points` TEXT NOT NULL, `final_points` TEXT NOT NULL, `points_sum` TEXT NOT NULL, `average` REAL NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_predicted_grade_notified` INTEGER NOT NULL, `is_final_grade_notified` INTEGER NOT NULL, `predicted_grade_last_change` INTEGER NOT NULL, `final_grade_last_change` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "position",
+ "columnName": "position",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "predictedGrade",
+ "columnName": "predicted_grade",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalGrade",
+ "columnName": "final_grade",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "proposedPoints",
+ "columnName": "proposed_points",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalPoints",
+ "columnName": "final_points",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pointsSum",
+ "columnName": "points_sum",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "average",
+ "columnName": "average",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPredictedGradeNotified",
+ "columnName": "is_predicted_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFinalGradeNotified",
+ "columnName": "is_final_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "predictedGradeLastChange",
+ "columnName": "predicted_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalGradeLastChange",
+ "columnName": "final_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradePartialStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `class_average` TEXT NOT NULL, `student_average` TEXT NOT NULL, `class_amounts` TEXT NOT NULL, `student_amounts` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classAverage",
+ "columnName": "class_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAverage",
+ "columnName": "student_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classAmounts",
+ "columnName": "class_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAmounts",
+ "columnName": "student_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesPointsStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `others` REAL NOT NULL, `student` REAL NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "others",
+ "columnName": "others",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "student",
+ "columnName": "student",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradeSemesterStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `amounts` TEXT NOT NULL, `student_grade` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "amounts",
+ "columnName": "amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentGrade",
+ "columnName": "student_grade",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Messages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `recipient_name` TEXT NOT NULL, `subject` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `removed` INTEGER NOT NULL, `has_attachments` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `unread_by` INTEGER NOT NULL, `read_by` INTEGER NOT NULL, `content` TEXT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageId",
+ "columnName": "message_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "sender",
+ "columnName": "sender_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "senderId",
+ "columnName": "sender_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "recipient",
+ "columnName": "recipient_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unread",
+ "columnName": "unread",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "removed",
+ "columnName": "removed",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasAttachments",
+ "columnName": "has_attachments",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unreadBy",
+ "columnName": "unread_by",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "readBy",
+ "columnName": "read_by",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MessageAttachments",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `one_drive_id` TEXT NOT NULL, `url` TEXT NOT NULL, `filename` TEXT NOT NULL, PRIMARY KEY(`real_id`))",
+ "fields": [
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageId",
+ "columnName": "message_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "oneDriveId",
+ "columnName": "one_drive_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filename",
+ "columnName": "filename",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "real_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `category` TEXT NOT NULL, `category_type` INTEGER NOT NULL, `is_points_show` INTEGER NOT NULL, `points` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "categoryType",
+ "columnName": "category_type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPointsShow",
+ "columnName": "is_points_show",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "points",
+ "columnName": "points",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isRead",
+ "columnName": "is_read",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Homework",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `attachments` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_done` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `is_added_by_user` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entryDate",
+ "columnName": "entry_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "attachments",
+ "columnName": "attachments",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDone",
+ "columnName": "is_done",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Subjects",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "LuckyNumbers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "luckyNumber",
+ "columnName": "lucky_number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "CompletedLesson",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `topic` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `substitution` TEXT NOT NULL, `absence` TEXT NOT NULL, `resources` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "topic",
+ "columnName": "topic",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "substitution",
+ "columnName": "substitution",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "resources",
+ "columnName": "resources",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "ReportingUnits",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `short` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `roles` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unitId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "shortName",
+ "columnName": "short",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "senderId",
+ "columnName": "sender_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "senderName",
+ "columnName": "sender_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "roles",
+ "columnName": "roles",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Recipients",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `real_id` TEXT NOT NULL, `name` TEXT NOT NULL, `real_name` TEXT NOT NULL, `login_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `role` INTEGER NOT NULL, `hash` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realName",
+ "columnName": "real_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginId",
+ "columnName": "login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unitId",
+ "columnName": "unit_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "role",
+ "columnName": "role",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hash",
+ "columnName": "hash",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MobileDevices",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deviceId",
+ "columnName": "device_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Teachers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "shortName",
+ "columnName": "short_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "School",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT NOT NULL, `contact` TEXT NOT NULL, `headmaster` TEXT NOT NULL, `pedagogue` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "contact",
+ "columnName": "contact",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "headmaster",
+ "columnName": "headmaster",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pedagogue",
+ "columnName": "pedagogue",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Conferences",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `subject` TEXT NOT NULL, `agenda` TEXT NOT NULL, `present_on_conference` TEXT NOT NULL, `conference_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "agenda",
+ "columnName": "agenda",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presentOnConference",
+ "columnName": "present_on_conference",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "conferenceId",
+ "columnName": "conference_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableAdditional",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `repeat_id` BLOB DEFAULT NULL, `is_added_by_user` INTEGER NOT NULL DEFAULT 0)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "repeatId",
+ "columnName": "repeat_id",
+ "affinity": "BLOB",
+ "notNull": false,
+ "defaultValue": "NULL"
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "StudentInfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `full_name` TEXT NOT NULL, `first_name` TEXT NOT NULL, `second_name` TEXT NOT NULL, `surname` TEXT NOT NULL, `birth_date` INTEGER NOT NULL, `birth_place` TEXT NOT NULL, `gender` TEXT NOT NULL, `has_polish_citizenship` INTEGER NOT NULL, `family_name` TEXT NOT NULL, `parents_names` TEXT NOT NULL, `address` TEXT NOT NULL, `registered_address` TEXT NOT NULL, `correspondence_address` TEXT NOT NULL, `phone_number` TEXT NOT NULL, `cell_phone_number` TEXT NOT NULL, `email` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `first_guardian_full_name` TEXT, `first_guardian_kinship` TEXT, `first_guardian_address` TEXT, `first_guardian_phones` TEXT, `first_guardian_email` TEXT, `second_guardian_full_name` TEXT, `second_guardian_kinship` TEXT, `second_guardian_address` TEXT, `second_guardian_phones` TEXT, `second_guardian_email` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "full_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstName",
+ "columnName": "first_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "secondName",
+ "columnName": "second_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "surname",
+ "columnName": "surname",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthDate",
+ "columnName": "birth_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthPlace",
+ "columnName": "birth_place",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gender",
+ "columnName": "gender",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPolishCitizenship",
+ "columnName": "has_polish_citizenship",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "familyName",
+ "columnName": "family_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentsNames",
+ "columnName": "parents_names",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registeredAddress",
+ "columnName": "registered_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "correspondenceAddress",
+ "columnName": "correspondence_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "phoneNumber",
+ "columnName": "phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "cellPhoneNumber",
+ "columnName": "cell_phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstGuardian.fullName",
+ "columnName": "first_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.kinship",
+ "columnName": "first_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.address",
+ "columnName": "first_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.phones",
+ "columnName": "first_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.email",
+ "columnName": "first_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.fullName",
+ "columnName": "second_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.kinship",
+ "columnName": "second_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.address",
+ "columnName": "second_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.phones",
+ "columnName": "second_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.email",
+ "columnName": "second_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableHeaders",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "SchoolAnnouncements",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_login_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notifications",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `type` TEXT NOT NULL, `destination` TEXT NOT NULL DEFAULT '{\"type\":\"io.github.wulkanowy.ui.modules.Destination.Dashboard\"}', `date` INTEGER NOT NULL, `data` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "destination",
+ "columnName": "destination",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'{\"type\":\"io.github.wulkanowy.ui.modules.Destination.Dashboard\"}'"
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "data",
+ "columnName": "data",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AdminMessages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `version_name` INTEGER, `version_max` INTEGER, `target_register_host` TEXT, `target_flavor` TEXT, `destination_url` TEXT, `priority` TEXT NOT NULL, `type` TEXT NOT NULL, `is_dismissible` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "versionMin",
+ "columnName": "version_name",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "versionMax",
+ "columnName": "version_max",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetRegisterHost",
+ "columnName": "target_register_host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetFlavor",
+ "columnName": "target_flavor",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "destinationUrl",
+ "columnName": "destination_url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "priority",
+ "columnName": "priority",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDismissible",
+ "columnName": "is_dismissible",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '790d4dc0e11f38349c49af85fabf9b7b')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
index 379b8738f..17fd7d696 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
@@ -55,7 +55,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() {
companion object {
- const val VERSION_SCHEMA = 48
+ const val VERSION_SCHEMA = 49
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
Migration2(),
@@ -102,6 +102,7 @@ abstract class AppDatabase : RoomDatabase() {
Migration43(),
Migration44(),
Migration46(),
+ Migration49()
)
fun newInstance(
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/SchoolAnnouncementDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/SchoolAnnouncementDao.kt
index 15655f4ae..c32e4aba3 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/SchoolAnnouncementDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/SchoolAnnouncementDao.kt
@@ -10,6 +10,6 @@ import javax.inject.Singleton
@Singleton
interface SchoolAnnouncementDao : BaseDao {
- @Query("SELECT * FROM SchoolAnnouncements WHERE student_id = :studentId ORDER BY date DESC")
- fun loadAll(studentId: Int): Flow>
+ @Query("SELECT * FROM SchoolAnnouncements WHERE user_login_id = :userLoginId ORDER BY date DESC")
+ fun loadAll(userLoginId: Int): Flow>
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/SchoolAnnouncement.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/SchoolAnnouncement.kt
index c8731bded..25e27ef18 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/SchoolAnnouncement.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/SchoolAnnouncement.kt
@@ -9,8 +9,8 @@ import java.time.LocalDate
@Entity(tableName = "SchoolAnnouncements")
data class SchoolAnnouncement(
- @ColumnInfo(name = "student_id")
- val studentId: Int,
+ @ColumnInfo(name = "user_login_id")
+ val userLoginId: Int,
val date: LocalDate,
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration49.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration49.kt
new file mode 100644
index 000000000..6e1de19d4
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration49.kt
@@ -0,0 +1,23 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class Migration49 : Migration(48, 49) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("DROP TABLE IF EXISTS SchoolAnnouncements")
+
+ database.execSQL(
+ """
+ CREATE TABLE IF NOT EXISTS `SchoolAnnouncements` (
+ `user_login_id` INTEGER NOT NULL,
+ `date` INTEGER NOT NULL,
+ `subject` TEXT NOT NULL,
+ `content` TEXT NOT NULL,
+ `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ `is_notified` INTEGER NOT NULL)
+ """.trimIndent()
+ )
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/DirectorInformationMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/DirectorInformationMapper.kt
index d059db816..16f1bbac0 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/DirectorInformationMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/DirectorInformationMapper.kt
@@ -6,7 +6,7 @@ import io.github.wulkanowy.sdk.pojo.DirectorInformation as SdkDirectorInformatio
fun List.mapToEntities(student: Student) = map {
SchoolAnnouncement(
- studentId = student.userLoginId,
+ userLoginId = student.userLoginId,
date = it.date,
subject = it.subject,
content = it.content,
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolAnnouncementRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolAnnouncementRepository.kt
index cf7ac86cd..4c42d092f 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolAnnouncementRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolAnnouncementRepository.kt
@@ -28,7 +28,8 @@ class SchoolAnnouncementRepository @Inject constructor(
fun getSchoolAnnouncements(
student: Student,
- forceRefresh: Boolean, notify: Boolean = false
+ forceRefresh: Boolean,
+ notify: Boolean = false
) = networkBoundResource(
mutex = saveFetchResultMutex,
isResultEmpty = { it.isEmpty() },
@@ -37,7 +38,7 @@ class SchoolAnnouncementRepository @Inject constructor(
it.isEmpty() || forceRefresh || isExpired
},
query = {
- schoolAnnouncementDb.loadAll(student.studentId)
+ schoolAnnouncementDb.loadAll(student.userLoginId)
},
fetch = {
sdk.init(student)
@@ -56,7 +57,7 @@ class SchoolAnnouncementRepository @Inject constructor(
)
fun getSchoolAnnouncementFromDatabase(student: Student): Flow> {
- return schoolAnnouncementDb.loadAll(student.studentId)
+ return schoolAnnouncementDb.loadAll(student.userLoginId)
}
suspend fun updateSchoolAnnouncement(schoolAnnouncement: List) =
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/SchoolAnnouncementWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/SchoolAnnouncementWork.kt
index 805ceb3e4..1aedc8399 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/SchoolAnnouncementWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/SchoolAnnouncementWork.kt
@@ -6,6 +6,7 @@ import io.github.wulkanowy.data.repositories.SchoolAnnouncementRepository
import io.github.wulkanowy.data.waitForResult
import io.github.wulkanowy.services.sync.notifications.NewSchoolAnnouncementNotification
import kotlinx.coroutines.flow.first
+import java.time.LocalDate
import javax.inject.Inject
class SchoolAnnouncementWork @Inject constructor(
@@ -20,10 +21,13 @@ class SchoolAnnouncementWork @Inject constructor(
notify = notify,
).waitForResult()
-
- schoolAnnouncementRepository.getSchoolAnnouncementFromDatabase(student).first()
- .filter { !it.isNotified }.let {
- if (it.isNotEmpty()) newSchoolAnnouncementNotification.notify(it, student)
+ schoolAnnouncementRepository.getSchoolAnnouncementFromDatabase(student)
+ .first()
+ .filter { !it.isNotified && it.date >= LocalDate.now() }
+ .let {
+ if (it.isNotEmpty()) {
+ newSchoolAnnouncementNotification.notify(it, student)
+ }
schoolAnnouncementRepository.updateSchoolAnnouncement(it.onEach { schoolAnnouncement ->
schoolAnnouncement.isNotified = true
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/schoolAnnouncement.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/schoolAnnouncement.kt
index 9b21f08e6..e2dc5cd84 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/schoolAnnouncement.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/schoolAnnouncement.kt
@@ -19,6 +19,6 @@ val debugSchoolAnnouncementItems = listOf(
private fun generateAnnouncement(subject: String, content: String) = SchoolAnnouncement(
subject = subject,
content = content,
- studentId = 0,
+ userLoginId = 0,
date = LocalDate.now()
)
From c808bf2e616eb3abf36c21f22a3e022768469ed5 Mon Sep 17 00:00:00 2001
From: Michael <5672750+mibac138@users.noreply.github.com>
Date: Sun, 26 Jun 2022 13:06:43 +0200
Subject: [PATCH 029/164] Fix timetable widget day reset (#1862)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Rafał Borcz
---
.../TimetableWidgetConfigureActivity.kt | 6 ++---
.../TimetableWidgetProvider.kt | 24 ++++++++++++++-----
2 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigureActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigureActivity.kt
index a27dba882..6ef6cfc98 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigureActivity.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigureActivity.kt
@@ -1,8 +1,6 @@
package io.github.wulkanowy.ui.modules.timetablewidget
-import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE
-import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID
-import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS
+import android.appwidget.AppWidgetManager.*
import android.content.Intent
import android.os.Build
import android.os.Bundle
@@ -17,6 +15,7 @@ import io.github.wulkanowy.databinding.ActivityWidgetConfigureBinding
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.base.WidgetConfigureAdapter
import io.github.wulkanowy.ui.modules.login.LoginActivity
+import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.EXTRA_FROM_CONFIGURE
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.EXTRA_FROM_PROVIDER
import io.github.wulkanowy.utils.AppInfo
import javax.inject.Inject
@@ -92,6 +91,7 @@ class TimetableWidgetConfigureActivity :
.apply {
action = ACTION_APPWIDGET_UPDATE
putExtra(EXTRA_APPWIDGET_IDS, intArrayOf(widgetId))
+ putExtra(EXTRA_FROM_CONFIGURE, true)
})
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt
index 745769864..3ba2ae946 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetProvider.kt
@@ -60,6 +60,8 @@ class TimetableWidgetProvider : BroadcastReceiver() {
private const val BUTTON_RESET = "buttonReset"
+ const val EXTRA_FROM_CONFIGURE = "extraFromConfigure"
+
const val EXTRA_FROM_PROVIDER = "extraFromProvider"
fun getDateWidgetKey(appWidgetId: Int) = "timetable_widget_date_$appWidgetId"
@@ -86,12 +88,22 @@ class TimetableWidgetProvider : BroadcastReceiver() {
}
private suspend fun onUpdate(context: Context, intent: Intent) {
- if (intent.getStringExtra(EXTRA_BUTTON_TYPE) === null) {
- intent.getIntArrayExtra(EXTRA_APPWIDGET_IDS)?.forEach { appWidgetId ->
+ if (intent.getStringExtra(EXTRA_BUTTON_TYPE) == null) {
+ val isFromConfigure = intent.getBooleanExtra(EXTRA_FROM_CONFIGURE, false)
+ val appWidgetIds = intent.getIntArrayExtra(EXTRA_APPWIDGET_IDS) ?: return
+
+ appWidgetIds.forEach { appWidgetId ->
val student =
getStudent(sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0), appWidgetId)
+ val savedDataEpochDay = sharedPref.getLong(getDateWidgetKey(appWidgetId), 0)
- updateWidget(context, appWidgetId, getWidgetDateToLoad(appWidgetId), student)
+ val dateToLoad = if (isFromConfigure && savedDataEpochDay != 0L) {
+ LocalDate.ofEpochDay(savedDataEpochDay)
+ } else {
+ getWidgetDefaultDateToLoad(appWidgetId)
+ }
+
+ updateWidget(context, appWidgetId, dateToLoad, student)
}
} else {
val buttonType = intent.getStringExtra(EXTRA_BUTTON_TYPE)
@@ -103,10 +115,10 @@ class TimetableWidgetProvider : BroadcastReceiver() {
val savedDate =
LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(toggledWidgetId), 0))
val date = when (buttonType) {
- BUTTON_RESET -> getWidgetDateToLoad(toggledWidgetId)
+ BUTTON_RESET -> getWidgetDefaultDateToLoad(toggledWidgetId)
BUTTON_NEXT -> savedDate.nextSchoolDay
BUTTON_PREV -> savedDate.previousSchoolDay
- else -> getWidgetDateToLoad(toggledWidgetId)
+ else -> getWidgetDefaultDateToLoad(toggledWidgetId)
}
if (!buttonType.isNullOrBlank()) {
analytics.logEvent(
@@ -271,7 +283,7 @@ class TimetableWidgetProvider : BroadcastReceiver() {
return avatarBitmap
}
- private fun getWidgetDateToLoad(appWidgetId: Int): LocalDate {
+ private fun getWidgetDefaultDateToLoad(appWidgetId: Int): LocalDate {
val lastLessonEndTimestamp =
sharedPref.getLong(getTodayLastLessonEndDateTimeWidgetKey(appWidgetId), 0)
val lastLessonEndDateTime =
From d8f644c5b4081d44e76a53a60067b31cb7baadf5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Borcz?=
Date: Sun, 26 Jun 2022 13:28:35 +0200
Subject: [PATCH 030/164] Add ads to dashboard (#1815)
---
app/build.gradle | 3 +
.../io/github/wulkanowy/utils/AdsHelper.kt | 28 +++++++
.../io/github/wulkanowy/utils/AdsHelper.kt | 28 +++++++
.../java/io/github/wulkanowy/WulkanowyApp.kt | 4 +
.../repositories/PreferencesRepository.kt | 38 +++++++--
.../ui/modules/dashboard/DashboardFragment.kt | 9 +++
.../ui/modules/dashboard/DashboardItem.kt | 23 +++---
.../dashboard/DashboardItemMoveCallback.kt | 3 +-
.../modules/dashboard/DashboardPresenter.kt | 35 +++++++-
.../ui/modules/dashboard/DashboardView.kt | 4 +-
.../{ => adapters}/DashboardAdapter.kt | 48 ++++++-----
.../DashboardAnnouncementsAdapter.kt | 4 +-
.../DashboardConferencesAdapter.kt | 4 +-
.../{ => adapters}/DashboardExamsAdapter.kt | 4 +-
.../{ => adapters}/DashboardGradesAdapter.kt | 2 +-
.../DashboardHomeworkAdapter.kt | 4 +-
.../wulkanowy/ui/modules/main/MainActivity.kt | 46 +++++++++++
.../ui/modules/main/MainPresenter.kt | 63 ++++++++++++---
.../wulkanowy/ui/modules/main/MainView.kt | 6 ++
.../wulkanowy/utils/ContextExtension.kt | 1 +
.../main/res/layout/dialog_ads_consent.xml | 79 +++++++++++++++++++
.../main/res/layout/item_dashboard_ads.xml | 15 ++++
.../main/res/values/preferences_defaults.xml | 2 +
app/src/main/res/values/preferences_keys.xml | 4 +
app/src/main/res/values/strings.xml | 7 ++
.../ui/modules/settings/ads/AdsFragment.kt | 70 ++++++++++++++--
.../ui/modules/settings/ads/AdsPresenter.kt | 64 ++++++++++++---
.../ui/modules/settings/ads/AdsView.kt | 8 +-
.../io/github/wulkanowy/utils/AdsHelper.kt | 59 ++++++++++++--
.../play/res/xml/scheme_preferences_ads.xml | 27 ++++++-
.../ui/modules/main/MainPresenterTest.kt | 14 +++-
31 files changed, 621 insertions(+), 85 deletions(-)
create mode 100644 app/src/fdroid/java/io/github/wulkanowy/utils/AdsHelper.kt
create mode 100644 app/src/hms/java/io/github/wulkanowy/utils/AdsHelper.kt
rename app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/{ => adapters}/DashboardAdapter.kt (96%)
rename app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/{ => adapters}/DashboardAnnouncementsAdapter.kt (95%)
rename app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/{ => adapters}/DashboardConferencesAdapter.kt (95%)
rename app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/{ => adapters}/DashboardExamsAdapter.kt (97%)
rename app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/{ => adapters}/DashboardGradesAdapter.kt (96%)
rename app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/{ => adapters}/DashboardHomeworkAdapter.kt (97%)
create mode 100644 app/src/main/res/layout/dialog_ads_consent.xml
create mode 100644 app/src/main/res/layout/item_dashboard_ads.xml
diff --git a/app/build.gradle b/app/build.gradle
index 3e4912063..29325abff 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -43,6 +43,7 @@ android {
}
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "null"
+ buildConfigField "String", "DASHBOARD_TILE_AD_ID", "null"
if (System.env.SET_BUILD_TIMESTAMP) {
buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis())
@@ -99,6 +100,8 @@ android {
admob_project_id: System.getenv("ADMOB_PROJECT_ID") ?: "ca-app-pub-3940256099942544~3347511713"
]
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "\"${System.getenv("SINGLE_SUPPORT_AD_ID") ?: "ca-app-pub-3940256099942544/5354046379"}\""
+ buildConfigField "String", "DASHBOARD_TILE_AD_ID", "\"${System.getenv("DASHBOARD_TILE_AD_ID") ?: "ca-app-pub-3940256099942544/6300978111"}\""
+
}
fdroid {
diff --git a/app/src/fdroid/java/io/github/wulkanowy/utils/AdsHelper.kt b/app/src/fdroid/java/io/github/wulkanowy/utils/AdsHelper.kt
new file mode 100644
index 000000000..461d29951
--- /dev/null
+++ b/app/src/fdroid/java/io/github/wulkanowy/utils/AdsHelper.kt
@@ -0,0 +1,28 @@
+package io.github.wulkanowy.utils
+
+import android.content.Context
+import android.view.View
+import dagger.hilt.android.qualifiers.ApplicationContext
+import io.github.wulkanowy.data.repositories.PreferencesRepository
+import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
+import javax.inject.Inject
+
+@Suppress("unused")
+class AdsHelper @Inject constructor(
+ @ApplicationContext private val context: Context,
+ private val preferencesRepository: PreferencesRepository
+) {
+
+ fun initialize() {
+ preferencesRepository.isAdsEnabled = false
+ preferencesRepository.isAgreeToProcessData = false
+ preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS
+ }
+
+ @Suppress("RedundantSuspendModifier", "UNUSED_PARAMETER")
+ suspend fun getDashboardTileAdBanner(width: Int): AdBanner {
+ throw IllegalStateException("Can't get ad banner (F-droid)")
+ }
+}
+
+data class AdBanner(val view: View)
diff --git a/app/src/hms/java/io/github/wulkanowy/utils/AdsHelper.kt b/app/src/hms/java/io/github/wulkanowy/utils/AdsHelper.kt
new file mode 100644
index 000000000..0e9227022
--- /dev/null
+++ b/app/src/hms/java/io/github/wulkanowy/utils/AdsHelper.kt
@@ -0,0 +1,28 @@
+package io.github.wulkanowy.utils
+
+import android.content.Context
+import android.view.View
+import dagger.hilt.android.qualifiers.ApplicationContext
+import io.github.wulkanowy.data.repositories.PreferencesRepository
+import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
+import javax.inject.Inject
+
+@Suppress("unused")
+class AdsHelper @Inject constructor(
+ @ApplicationContext private val context: Context,
+ private val preferencesRepository: PreferencesRepository
+) {
+
+ fun initialize() {
+ preferencesRepository.isAdsEnabled = false
+ preferencesRepository.isAgreeToProcessData = false
+ preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS
+ }
+
+ @Suppress("RedundantSuspendModifier", "UNUSED_PARAMETER")
+ suspend fun getDashboardTileAdBanner(width: Int): AdBanner {
+ throw IllegalStateException("Can't get ad banner (HMS)")
+ }
+}
+
+data class AdBanner(val view: View)
diff --git a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt
index b5103e3ec..7d2eeb1ec 100644
--- a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt
+++ b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt
@@ -31,10 +31,14 @@ class WulkanowyApp : Application(), Configuration.Provider {
@Inject
lateinit var analyticsHelper: AnalyticsHelper
+ @Inject
+ lateinit var adsHelper: AdsHelper
+
override fun onCreate() {
super.onCreate()
initializeAppLanguage()
themeManager.applyDefaultTheme()
+ adsHelper.initialize()
initLogging()
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt
index 4cd85586f..237fb1a0a 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt
@@ -222,16 +222,14 @@ class PreferencesRepository @Inject constructor(
get() = selectedDashboardTilesPreference.asFlow()
.map { set ->
set.map { DashboardItem.Tile.valueOf(it) }
- .plus(DashboardItem.Tile.ACCOUNT)
- .plus(DashboardItem.Tile.ADMIN_MESSAGE)
+ .plus(listOf(DashboardItem.Tile.ACCOUNT, DashboardItem.Tile.ADMIN_MESSAGE))
.toSet()
}
var selectedDashboardTiles: Set
get() = selectedDashboardTilesPreference.get()
.map { DashboardItem.Tile.valueOf(it) }
- .plus(DashboardItem.Tile.ACCOUNT)
- .plus(DashboardItem.Tile.ADMIN_MESSAGE)
+ .plus(listOf(DashboardItem.Tile.ACCOUNT, DashboardItem.Tile.ADMIN_MESSAGE))
.toSet()
set(value) {
val filteredValue = value.filterNot { it == DashboardItem.Tile.ACCOUNT }
@@ -271,7 +269,33 @@ class PreferencesRepository @Inject constructor(
var isAppReviewDone: Boolean
get() = sharedPref.getBoolean(PREF_KEY_IN_APP_REVIEW_DONE, false)
- set(value) = sharedPref.edit().putBoolean(PREF_KEY_IN_APP_REVIEW_DONE, value).apply()
+ set(value) = sharedPref.edit { putBoolean(PREF_KEY_IN_APP_REVIEW_DONE, value) }
+
+ var isAppSupportShown: Boolean
+ get() = sharedPref.getBoolean(PREF_KEY_APP_SUPPORT_SHOWN, false)
+ set(value) = sharedPref.edit { putBoolean(PREF_KEY_APP_SUPPORT_SHOWN, value) }
+
+ var isAgreeToProcessData: Boolean
+ get() = getBoolean(
+ R.string.pref_key_ads_consent_data_processing,
+ R.bool.pref_default_ads_consent_data_processing
+ )
+ set(value) = sharedPref.edit {
+ putBoolean(context.getString(R.string.pref_key_ads_consent_data_processing), value)
+ }
+
+ var isPersonalizedAdsEnabled: Boolean
+ get() = sharedPref.getBoolean(PREF_KEY_PERSONALIZED_ADS_ENABLED, false)
+ set(value) = sharedPref.edit { putBoolean(PREF_KEY_PERSONALIZED_ADS_ENABLED, value) }
+
+ var isAdsEnabled: Boolean
+ get() = getBoolean(
+ R.string.pref_key_ads_enabled,
+ R.bool.pref_default_ads_enabled
+ )
+ set(value) = sharedPref.edit {
+ putBoolean(context.getString(R.string.pref_key_ads_enabled), value)
+ }
private fun getLong(id: Int, default: Int) = getLong(context.getString(id), default)
@@ -301,6 +325,10 @@ class PreferencesRepository @Inject constructor(
private const val PREF_KEY_IN_APP_REVIEW_DONE = "in_app_review_done"
+ private const val PREF_KEY_APP_SUPPORT_SHOWN = "app_support_shown"
+
+ private const val PREF_KEY_PERSONALIZED_ADS_ENABLED = "personalized_ads_enabled"
+
private const val PREF_KEY_ADMIN_DISMISSED_MESSAGE_IDS = "admin_message_dismissed_ids"
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardFragment.kt
index 65832bdb1..de0b4a6c9 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardFragment.kt
@@ -18,6 +18,7 @@ import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsFragment
import io.github.wulkanowy.ui.modules.attendance.summary.AttendanceSummaryFragment
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
+import io.github.wulkanowy.ui.modules.dashboard.adapters.DashboardAdapter
import io.github.wulkanowy.ui.modules.exam.ExamFragment
import io.github.wulkanowy.ui.modules.grade.GradeFragment
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
@@ -47,6 +48,14 @@ class DashboardFragment : BaseFragment(R.layout.fragme
override var subtitleString =
LocalDate.now().toFormattedString("EEEE, d MMMM yyyy").capitalise()
+ override val tileWidth: Int
+ get() {
+ val recyclerWidth = binding.dashboardRecycler.width
+ val margin = requireContext().dpToPx(24f).toInt()
+
+ return ((recyclerWidth - margin) / resources.displayMetrics.density).toInt()
+ }
+
companion object {
fun newInstance() = DashboardFragment()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardItem.kt
index c20bae7fa..e220ae236 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardItem.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardItem.kt
@@ -1,13 +1,9 @@
package io.github.wulkanowy.ui.modules.dashboard
-import io.github.wulkanowy.data.db.entities.AdminMessage
-import io.github.wulkanowy.data.db.entities.Conference
-import io.github.wulkanowy.data.db.entities.Exam
-import io.github.wulkanowy.data.db.entities.Grade
-import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
-import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.data.db.entities.*
import io.github.wulkanowy.data.enums.GradeColorTheme
import io.github.wulkanowy.data.pojos.TimetableFull
+import io.github.wulkanowy.utils.AdBanner
import io.github.wulkanowy.data.db.entities.Homework as EntitiesHomework
sealed class DashboardItem(val type: Type) {
@@ -106,17 +102,26 @@ sealed class DashboardItem(val type: Type) {
override val isDataLoaded get() = conferences != null
}
+ data class Ads(
+ val adBanner: AdBanner? = null,
+ override val error: Throwable? = null,
+ override val isLoading: Boolean = false
+ ) : DashboardItem(Type.ADS) {
+
+ override val isDataLoaded get() = adBanner != null
+ }
+
enum class Type {
ADMIN_MESSAGE,
ACCOUNT,
HORIZONTAL_GROUP,
LESSONS,
+ ADS,
GRADES,
HOMEWORK,
ANNOUNCEMENTS,
EXAMS,
CONFERENCES,
- ADS
}
enum class Tile {
@@ -126,12 +131,12 @@ sealed class DashboardItem(val type: Type) {
MESSAGES,
ATTENDANCE,
LESSONS,
+ ADS,
GRADES,
HOMEWORK,
ANNOUNCEMENTS,
EXAMS,
CONFERENCES,
- ADS
}
}
@@ -148,4 +153,4 @@ fun DashboardItem.Tile.toDashboardItemType() = when (this) {
DashboardItem.Tile.EXAMS -> DashboardItem.Type.EXAMS
DashboardItem.Tile.CONFERENCES -> DashboardItem.Type.CONFERENCES
DashboardItem.Tile.ADS -> DashboardItem.Type.ADS
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardItemMoveCallback.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardItemMoveCallback.kt
index b9625570f..9c15acc35 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardItemMoveCallback.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardItemMoveCallback.kt
@@ -2,7 +2,8 @@ package io.github.wulkanowy.ui.modules.dashboard
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
-import java.util.Collections
+import io.github.wulkanowy.ui.modules.dashboard.adapters.DashboardAdapter
+import java.util.*
class DashboardItemMoveCallback(
private val dashboardAdapter: DashboardAdapter,
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
index c33955bc7..e963a0205 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
@@ -8,6 +8,7 @@ import io.github.wulkanowy.data.enums.MessageFolder
import io.github.wulkanowy.data.repositories.*
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
+import io.github.wulkanowy.utils.AdsHelper
import io.github.wulkanowy.utils.calculatePercentage
import io.github.wulkanowy.utils.nextOrSameSchoolDay
import kotlinx.coroutines.flow.*
@@ -31,7 +32,8 @@ class DashboardPresenter @Inject constructor(
private val conferenceRepository: ConferenceRepository,
private val preferencesRepository: PreferencesRepository,
private val schoolAnnouncementRepository: SchoolAnnouncementRepository,
- private val adminMessageRepository: AdminMessageRepository
+ private val adminMessageRepository: AdminMessageRepository,
+ private val adsHelper: AdsHelper
) : BasePresenter(errorHandler, studentRepository) {
private val dashboardItemLoadedList = mutableListOf()
@@ -166,7 +168,7 @@ class DashboardPresenter @Inject constructor(
DashboardItem.Type.CONFERENCES -> {
loadConferences(student, forceRefresh)
}
- DashboardItem.Type.ADS -> TODO()
+ DashboardItem.Type.ADS -> loadAds(forceRefresh)
DashboardItem.Type.ADMIN_MESSAGE -> loadAdminMessage(student, forceRefresh)
}
}
@@ -595,6 +597,23 @@ class DashboardPresenter @Inject constructor(
.launchWithUniqueRefreshJob("dashboard_admin_messages", forceRefresh)
}
+ private fun loadAds(forceRefresh: Boolean) {
+ presenterScope.launch {
+ if (!forceRefresh) {
+ updateData(DashboardItem.Ads(), forceRefresh)
+ }
+
+ val dashboardAdItem =
+ runCatching {
+ DashboardItem.Ads(adsHelper.getDashboardTileAdBanner(view!!.tileWidth))
+ }
+ .onFailure { Timber.e(it) }
+ .getOrElse { DashboardItem.Ads(error = it) }
+
+ updateData(dashboardAdItem, forceRefresh)
+ }
+ }
+
private fun updateData(dashboardItem: DashboardItem, forceRefresh: Boolean) {
val isForceRefreshError = forceRefresh && dashboardItem.error != null
val isFirstRunDataLoadedError =
@@ -619,6 +638,18 @@ class DashboardPresenter @Inject constructor(
}
}
+ if (dashboardItem is DashboardItem.Ads) {
+ if (!dashboardItem.isDataLoaded) {
+ dashboardItemsToLoad = dashboardItemsToLoad - DashboardItem.Type.ADS
+ dashboardTileLoadedList = dashboardTileLoadedList - DashboardItem.Tile.ADS
+
+ dashboardItemLoadedList.removeAll { it.type == DashboardItem.Type.ADS }
+ } else {
+ dashboardItemsToLoad = dashboardItemsToLoad + DashboardItem.Type.ADS
+ dashboardTileLoadedList = dashboardTileLoadedList + DashboardItem.Tile.ADS
+ }
+ }
+
if (forceRefresh) {
updateForceRefreshData(dashboardItem)
} else {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardView.kt
index 2cc2f1d2d..767885434 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardView.kt
@@ -4,6 +4,8 @@ import io.github.wulkanowy.ui.base.BaseView
interface DashboardView : BaseView {
+ val tileWidth: Int
+
fun initView()
fun updateData(data: List)
@@ -27,4 +29,4 @@ interface DashboardView : BaseView {
fun openNotificationsCenterView()
fun openInternetBrowser(url: String)
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardAdapter.kt
similarity index 96%
rename from app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardAdapter.kt
rename to app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardAdapter.kt
index 9191d43c9..a3c423a8b 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardAdapter.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.ui.modules.dashboard
+package io.github.wulkanowy.ui.modules.dashboard.adapters
import android.annotation.SuppressLint
import android.content.res.ColorStateList
@@ -22,24 +22,15 @@ import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.db.entities.TimetableHeader
import io.github.wulkanowy.data.enums.GradeColorTheme
-import io.github.wulkanowy.databinding.ItemDashboardAccountBinding
-import io.github.wulkanowy.databinding.ItemDashboardAdminMessageBinding
-import io.github.wulkanowy.databinding.ItemDashboardAnnouncementsBinding
-import io.github.wulkanowy.databinding.ItemDashboardConferencesBinding
-import io.github.wulkanowy.databinding.ItemDashboardExamsBinding
-import io.github.wulkanowy.databinding.ItemDashboardGradesBinding
-import io.github.wulkanowy.databinding.ItemDashboardHomeworkBinding
-import io.github.wulkanowy.databinding.ItemDashboardHorizontalGroupBinding
-import io.github.wulkanowy.databinding.ItemDashboardLessonsBinding
-import io.github.wulkanowy.utils.createNameInitialsDrawable
-import io.github.wulkanowy.utils.dpToPx
-import io.github.wulkanowy.utils.getThemeAttrColor
-import io.github.wulkanowy.utils.left
-import io.github.wulkanowy.utils.nickOrName
-import io.github.wulkanowy.utils.toFormattedString
+import io.github.wulkanowy.databinding.*
+import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
+import io.github.wulkanowy.utils.*
import timber.log.Timber
-import java.time.*
-import java.util.Timer
+import java.time.Duration
+import java.time.Instant
+import java.time.LocalDate
+import java.time.LocalDateTime
+import java.util.*
import javax.inject.Inject
import kotlin.concurrent.timer
@@ -120,6 +111,9 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter AdminMessageViewHolder(
ItemDashboardAdminMessageBinding.inflate(inflater, parent, false)
)
+ DashboardItem.Type.ADS.ordinal -> AdsViewHolder(
+ ItemDashboardAdsBinding.inflate(inflater, parent, false)
+ )
else -> throw IllegalArgumentException()
}
}
@@ -135,6 +129,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter bindExamsViewHolder(holder, position)
is ConferencesViewHolder -> bindConferencesViewHolder(holder, position)
is AdminMessageViewHolder -> bindAdminMessage(holder, position)
+ is AdsViewHolder -> bindAdsViewHolder(holder, position)
}
}
@@ -746,6 +741,20 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter,
private val oldList: List
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardAnnouncementsAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardAnnouncementsAdapter.kt
similarity index 95%
rename from app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardAnnouncementsAdapter.kt
rename to app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardAnnouncementsAdapter.kt
index 7a4c2b257..da5880153 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardAnnouncementsAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardAnnouncementsAdapter.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.ui.modules.dashboard
+package io.github.wulkanowy.ui.modules.dashboard.adapters
import android.view.LayoutInflater
import android.view.ViewGroup
@@ -33,4 +33,4 @@ class DashboardAnnouncementsAdapter :
class ViewHolder(val binding: SubitemDashboardAnnouncementsBinding) :
RecyclerView.ViewHolder(binding.root)
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardConferencesAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardConferencesAdapter.kt
similarity index 95%
rename from app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardConferencesAdapter.kt
rename to app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardConferencesAdapter.kt
index 64cf599c8..1244ff60f 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardConferencesAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardConferencesAdapter.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.ui.modules.dashboard
+package io.github.wulkanowy.ui.modules.dashboard.adapters
import android.view.LayoutInflater
import android.view.ViewGroup
@@ -33,4 +33,4 @@ class DashboardConferencesAdapter :
class ViewHolder(val binding: SubitemDashboardConferencesBinding) :
RecyclerView.ViewHolder(binding.root)
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardExamsAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardExamsAdapter.kt
similarity index 97%
rename from app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardExamsAdapter.kt
rename to app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardExamsAdapter.kt
index 060f224b3..583bf29da 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardExamsAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardExamsAdapter.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.ui.modules.dashboard
+package io.github.wulkanowy.ui.modules.dashboard.adapters
import android.annotation.SuppressLint
import android.view.LayoutInflater
@@ -56,4 +56,4 @@ class DashboardExamsAdapter :
class ViewHolder(val binding: SubitemDashboardExamsBinding) :
RecyclerView.ViewHolder(binding.root)
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardGradesAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardGradesAdapter.kt
similarity index 96%
rename from app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardGradesAdapter.kt
rename to app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardGradesAdapter.kt
index afffcc511..d00df9d41 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardGradesAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardGradesAdapter.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.ui.modules.dashboard
+package io.github.wulkanowy.ui.modules.dashboard.adapters
import android.view.LayoutInflater
import android.view.ViewGroup
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardHomeworkAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardHomeworkAdapter.kt
similarity index 97%
rename from app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardHomeworkAdapter.kt
rename to app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardHomeworkAdapter.kt
index 55ec90294..8105ff9c8 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardHomeworkAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardHomeworkAdapter.kt
@@ -1,4 +1,4 @@
-package io.github.wulkanowy.ui.modules.dashboard
+package io.github.wulkanowy.ui.modules.dashboard.adapters
import android.annotation.SuppressLint
import android.view.LayoutInflater
@@ -53,4 +53,4 @@ class DashboardHomeworkAdapter : RecyclerView.Adapter(), MainVie
inAppReviewHelper.showInAppReview(this)
}
+ override fun showAppSupport() {
+ MaterialAlertDialogBuilder(this)
+ .setTitle(R.string.main_support_title)
+ .setMessage(R.string.main_support_description)
+ .setPositiveButton(R.string.main_support_positive) { _, _ -> presenter.onEnableAdsSelected() }
+ .setNegativeButton(android.R.string.cancel) { _, _ -> }
+ .setOnDismissListener { }
+ .show()
+ }
+
+ override fun showPrivacyPolicyDialog() {
+ val dialogAdsConsentBinding = DialogAdsConsentBinding.inflate(layoutInflater)
+
+ val dialog = MaterialAlertDialogBuilder(this)
+ .setTitle(R.string.pref_ads_consent_title)
+ .setMessage(R.string.pref_ads_consent_description)
+ .setView(dialogAdsConsentBinding.root)
+ .show()
+
+ dialogAdsConsentBinding.adsConsentOver.setOnCheckedChangeListener { _, isChecked ->
+ dialogAdsConsentBinding.adsConsentPersonalised.isEnabled = isChecked
+ }
+
+ dialogAdsConsentBinding.adsConsentPersonalised.setOnClickListener {
+ presenter.onPrivacyAgree(true)
+ dialog.dismiss()
+ }
+
+ dialogAdsConsentBinding.adsConsentNonPersonalised.setOnClickListener {
+ presenter.onPrivacyAgree(false)
+ dialog.dismiss()
+ }
+
+ dialogAdsConsentBinding.adsConsentPrivacy.setOnClickListener { presenter.onPrivacySelected() }
+ dialogAdsConsentBinding.adsConsentCancel.setOnClickListener { dialog.cancel() }
+ }
+
+ override fun openPrivacyPolicy() {
+ openInternetBrowser(
+ "https://wulkanowy.github.io/polityka-prywatnosci.html",
+ ::showMessage
+ )
+ }
+
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
navController.onSaveInstanceState(outState)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt
index a07bdb371..8f457d925 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt
@@ -14,11 +14,15 @@ import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.ui.modules.account.AccountView
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsView
+import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
import io.github.wulkanowy.ui.modules.grade.GradeView
import io.github.wulkanowy.ui.modules.message.MessageView
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersView
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
+import io.github.wulkanowy.utils.AdsHelper
import io.github.wulkanowy.utils.AnalyticsHelper
+import io.github.wulkanowy.utils.AppInfo
+import kotlinx.coroutines.launch
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import timber.log.Timber
@@ -29,10 +33,12 @@ import javax.inject.Inject
class MainPresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
- private val prefRepository: PreferencesRepository,
+ private val preferencesRepository: PreferencesRepository,
private val syncManager: SyncManager,
private val analytics: AnalyticsHelper,
- private val json: Json
+ private val json: Json,
+ private val adsHelper: AdsHelper,
+ private val appInfo: AppInfo
) : BasePresenter(errorHandler, studentRepository) {
private var studentsWitSemesters: List? = null
@@ -47,7 +53,7 @@ class MainPresenter @Inject constructor(
private val Destination?.startMenuIndex
get() = when {
- this == null -> prefRepository.startMenuIndex
+ this == null -> preferencesRepository.startMenuIndex
destinationType in rootDestinationTypeList -> {
rootDestinationTypeList.indexOf(destinationType)
}
@@ -71,6 +77,8 @@ class MainPresenter @Inject constructor(
syncManager.startPeriodicSyncWorker()
+ checkAppSupport()
+
analytics.logEvent("app_open", "destination" to initDestination.toString())
Timber.i("Main view was initialized with $initDestination")
}
@@ -155,18 +163,53 @@ class MainPresenter @Inject constructor(
} == true
}
- private fun checkInAppReview() {
- prefRepository.inAppReviewCount++
+ fun onEnableAdsSelected() {
+ view?.showPrivacyPolicyDialog()
+ }
- if (prefRepository.inAppReviewDate == null) {
- prefRepository.inAppReviewDate = Instant.now()
+ fun onPrivacyAgree(isPersonalizedAds: Boolean) {
+ preferencesRepository.isAdsEnabled = true
+ preferencesRepository.isAgreeToProcessData = true
+ preferencesRepository.isPersonalizedAdsEnabled = isPersonalizedAds
+
+ adsHelper.initialize()
+
+ preferencesRepository.selectedDashboardTiles += DashboardItem.Tile.ADS
+ }
+
+ fun onPrivacySelected() {
+ view?.openPrivacyPolicy()
+ }
+
+ private fun checkInAppReview() {
+ preferencesRepository.inAppReviewCount++
+
+ if (preferencesRepository.inAppReviewDate == null) {
+ preferencesRepository.inAppReviewDate = Instant.now()
}
- if (!prefRepository.isAppReviewDone && prefRepository.inAppReviewCount >= 50 &&
- Instant.now().minus(Duration.ofDays(14)).isAfter(prefRepository.inAppReviewDate)
+ if (!preferencesRepository.isAppReviewDone && preferencesRepository.inAppReviewCount >= 50 &&
+ Instant.now().minus(Duration.ofDays(14)).isAfter(preferencesRepository.inAppReviewDate)
) {
view?.showInAppReview()
- prefRepository.isAppReviewDone = true
+ preferencesRepository.isAppReviewDone = true
+ }
+ }
+
+ private fun checkAppSupport() {
+ if (!preferencesRepository.isAppSupportShown && !preferencesRepository.isAdsEnabled
+ && appInfo.buildFlavor == "play"
+ ) {
+ presenterScope.launch {
+ val student = runCatching { studentRepository.getCurrentStudent(false) }
+ .onFailure { Timber.e(it) }
+ .getOrElse { return@launch }
+
+ if (Instant.now().minus(Duration.ofDays(28)).isAfter(student.registrationDate)) {
+ view?.showAppSupport()
+ preferencesRepository.isAppSupportShown = true
+ }
+ }
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainView.kt
index 3a57fcc6b..3d018e3d6 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainView.kt
@@ -41,6 +41,12 @@ interface MainView : BaseView {
fun showInAppReview()
+ fun showAppSupport()
+
+ fun showPrivacyPolicyDialog()
+
+ fun openPrivacyPolicy()
+
fun openMoreDestination(destination: Destination)
interface MainChildView {
diff --git a/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt
index 323e1e477..dd91d36d4 100644
--- a/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt
+++ b/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt
@@ -13,6 +13,7 @@ import androidx.core.graphics.drawable.RoundedBitmapDrawable
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
import androidx.core.graphics.drawable.toBitmap
+
@ColorInt
fun Context.getThemeAttrColor(@AttrRes colorAttr: Int): Int {
val array = obtainStyledAttributes(null, intArrayOf(colorAttr))
diff --git a/app/src/main/res/layout/dialog_ads_consent.xml b/app/src/main/res/layout/dialog_ads_consent.xml
new file mode 100644
index 000000000..395101627
--- /dev/null
+++ b/app/src/main/res/layout/dialog_ads_consent.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_dashboard_ads.xml b/app/src/main/res/layout/item_dashboard_ads.xml
new file mode 100644
index 000000000..b75bb27e0
--- /dev/null
+++ b/app/src/main/res/layout/item_dashboard_ads.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/values/preferences_defaults.xml b/app/src/main/res/values/preferences_defaults.xml
index deeb36961..9c092ec5e 100644
--- a/app/src/main/res/values/preferences_defaults.xml
+++ b/app/src/main/res/values/preferences_defaults.xml
@@ -37,4 +37,6 @@
- GRADES
- ANNOUNCEMENTS
+ false
+ false
diff --git a/app/src/main/res/values/preferences_keys.xml b/app/src/main/res/values/preferences_keys.xml
index 849d989ee..f29080b33 100644
--- a/app/src/main/res/values/preferences_keys.xml
+++ b/app/src/main/res/values/preferences_keys.xml
@@ -37,4 +37,8 @@
notifications_piggyback
notifications_piggyback_cancel_original
single_ad_support
+ ads_enabled
+ ads_privacy_policy
+ ads_consent_data_processing
+ ads_over_eighteen
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 2ca516adf..db591309f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -85,6 +85,9 @@
Log in
Session expired
Session expired, log in again
+ Application support
+ Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time
+ Enable ads
@@ -715,6 +718,10 @@
Privacy policy
Ad is loading
Thank you for your support, come back later for more ads
+ Can we use your data to display ads?
+ 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
+ Personalized ads
+ Non-personalized ads
Advanced
Appearance & Behavior
diff --git a/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsFragment.kt b/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsFragment.kt
index 8d31928b7..48a6fc3ec 100644
--- a/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsFragment.kt
+++ b/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsFragment.kt
@@ -2,12 +2,15 @@ package io.github.wulkanowy.ui.modules.settings.ads
import android.os.Bundle
import android.view.View
+import androidx.preference.CheckBoxPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
+import androidx.preference.SwitchPreferenceCompat
import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
+import io.github.wulkanowy.databinding.DialogAdsConsentBinding
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.base.ErrorDialog
import io.github.wulkanowy.ui.modules.main.MainView
@@ -36,6 +39,22 @@ class AdsFragment : PreferenceFragmentCompat(), MainView.TitledView, AdsView {
presenter.onWatchSingleAdSelected()
true
}
+
+ findPreference(getString(R.string.pref_key_ads_privacy_policy))?.setOnPreferenceClickListener {
+ presenter.onPrivacySelected()
+ true
+ }
+
+ findPreference(getString(R.string.pref_key_ads_consent_data_processing))
+ ?.setOnPreferenceChangeListener { _, newValue ->
+ presenter.onConsentSelected(newValue as Boolean)
+ true
+ }
+
+ findPreference(getString(R.string.pref_key_ads_enabled))?.setOnPreferenceChangeListener { _, newValue ->
+ presenter.onAddEnabled(newValue as Boolean)
+ true
+ }
}
override fun showAd(ad: RewardedInterstitialAd) {
@@ -45,13 +64,50 @@ class AdsFragment : PreferenceFragmentCompat(), MainView.TitledView, AdsView {
}
override fun showPrivacyPolicyDialog() {
- MaterialAlertDialogBuilder(requireContext())
- .setTitle(getString(R.string.pref_ads_privacy_title))
- .setMessage(getString(R.string.pref_ads_privacy_description))
- .setPositiveButton(getString(R.string.pref_ads_privacy_agree)) { _, _ -> presenter.onAgreedPrivacy() }
- .setNegativeButton(android.R.string.cancel) { _, _ -> }
- .setNeutralButton(getString(R.string.pref_ads_privacy_link)) { _, _ -> presenter.onPrivacySelected() }
+ val dialogAdsConsentBinding = DialogAdsConsentBinding.inflate(layoutInflater)
+
+ val dialog = MaterialAlertDialogBuilder(requireContext())
+ .setTitle(R.string.pref_ads_consent_title)
+ .setMessage(R.string.pref_ads_consent_description)
+ .setView(dialogAdsConsentBinding.root)
+ .setOnCancelListener { presenter.onPrivacyDialogCanceled() }
.show()
+
+ dialogAdsConsentBinding.adsConsentOver.setOnCheckedChangeListener { _, isChecked ->
+ dialogAdsConsentBinding.adsConsentPersonalised.isEnabled = isChecked
+ }
+
+ dialogAdsConsentBinding.adsConsentPersonalised.setOnClickListener {
+ presenter.onPersonalizedAgree()
+ dialog.dismiss()
+ }
+
+ dialogAdsConsentBinding.adsConsentNonPersonalised.setOnClickListener {
+ presenter.onNonPersonalizedAgree()
+ dialog.dismiss()
+ }
+
+ dialogAdsConsentBinding.adsConsentPrivacy.setOnClickListener { presenter.onPrivacySelected() }
+ dialogAdsConsentBinding.adsConsentCancel.setOnClickListener { dialog.cancel() }
+ }
+
+ override fun showProcessingDataSummary(isPersonalized: Boolean?) {
+ val summaryText = isPersonalized?.let {
+ getString(if (it) R.string.pref_ads_summary_personalized else R.string.pref_ads_summary_non_personalized)
+ }
+
+ findPreference(getString(R.string.pref_key_ads_consent_data_processing))
+ ?.summary = summaryText
+ }
+
+ override fun setCheckedProcessingData(checked: Boolean) {
+ findPreference(getString(R.string.pref_key_ads_consent_data_processing))
+ ?.isChecked = checked
+ }
+
+ override fun setCheckedAdsEnabled(checked: Boolean) {
+ findPreference(getString(R.string.pref_key_ads_enabled))
+ ?.isChecked = checked
}
override fun openPrivacyPolicy() {
@@ -98,4 +154,4 @@ class AdsFragment : PreferenceFragmentCompat(), MainView.TitledView, AdsView {
override fun showErrorDetailsDialog(error: Throwable) {
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
}
-}
\ No newline at end of file
+}
diff --git a/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsPresenter.kt b/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsPresenter.kt
index 5ccbce1e5..85c14c0a0 100644
--- a/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsPresenter.kt
+++ b/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsPresenter.kt
@@ -1,8 +1,10 @@
package io.github.wulkanowy.ui.modules.settings.ads
+import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
+import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
import io.github.wulkanowy.utils.AdsHelper
import kotlinx.coroutines.launch
import timber.log.Timber
@@ -11,24 +13,22 @@ import javax.inject.Inject
class AdsPresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
- private val adsHelper: AdsHelper
+ private val adsHelper: AdsHelper,
+ private val preferencesRepository: PreferencesRepository
) : BasePresenter(errorHandler, studentRepository) {
override fun onAttachView(view: AdsView) {
super.onAttachView(view)
view.initView()
Timber.i("Settings ads view was initialized")
+
+ view.showProcessingDataSummary(
+ preferencesRepository.isPersonalizedAdsEnabled.takeIf {
+ preferencesRepository.isAgreeToProcessData
+ })
}
fun onWatchSingleAdSelected() {
- view?.showPrivacyPolicyDialog()
- }
-
- fun onPrivacySelected() {
- view?.openPrivacyPolicy()
- }
-
- fun onAgreedPrivacy() {
view?.showLoadingSupportAd(true)
presenterScope.launch {
runCatching { adsHelper.getSupportAd() }
@@ -41,4 +41,48 @@ class AdsPresenter @Inject constructor(
}
}
}
-}
\ No newline at end of file
+
+ fun onConsentSelected(isChecked: Boolean) {
+ if (isChecked) {
+ view?.showPrivacyPolicyDialog()
+ } else {
+ view?.showProcessingDataSummary(null)
+ view?.setCheckedAdsEnabled(false)
+ onAddEnabled(false)
+ }
+ }
+
+ fun onPrivacySelected() {
+ view?.openPrivacyPolicy()
+ }
+
+ fun onPrivacyDialogCanceled() {
+ view?.setCheckedProcessingData(false)
+ }
+
+ fun onNonPersonalizedAgree() {
+ preferencesRepository.isPersonalizedAdsEnabled = false
+
+ adsHelper.initialize()
+
+ view?.setCheckedProcessingData(true)
+ view?.showProcessingDataSummary(false)
+ }
+
+ fun onPersonalizedAgree() {
+ preferencesRepository.isPersonalizedAdsEnabled = true
+
+ adsHelper.initialize()
+
+ view?.setCheckedProcessingData(true)
+ view?.showProcessingDataSummary(true)
+ }
+
+ fun onAddEnabled(isEnabled: Boolean) {
+ if (isEnabled) {
+ preferencesRepository.selectedDashboardTiles += DashboardItem.Tile.ADS
+ } else {
+ preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS
+ }
+ }
+}
diff --git a/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsView.kt b/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsView.kt
index 89de7bd1d..8de6e60d3 100644
--- a/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsView.kt
+++ b/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsView.kt
@@ -16,4 +16,10 @@ interface AdsView : BaseView {
fun showLoadingSupportAd(show: Boolean)
fun showWatchAdOncePerVisit(show: Boolean)
-}
\ No newline at end of file
+
+ fun setCheckedAdsEnabled(checked: Boolean)
+
+ fun setCheckedProcessingData(checked: Boolean)
+
+ fun showProcessingDataSummary(isPersonalized: Boolean?)
+}
diff --git a/app/src/play/java/io/github/wulkanowy/utils/AdsHelper.kt b/app/src/play/java/io/github/wulkanowy/utils/AdsHelper.kt
index dde4d0121..6be8e924c 100644
--- a/app/src/play/java/io/github/wulkanowy/utils/AdsHelper.kt
+++ b/app/src/play/java/io/github/wulkanowy/utils/AdsHelper.kt
@@ -2,27 +2,39 @@ package io.github.wulkanowy.utils
import android.content.Context
import android.os.Bundle
+import android.view.View
import com.google.ads.mediation.admob.AdMobAdapter
-import com.google.android.gms.ads.AdRequest
-import com.google.android.gms.ads.LoadAdError
-import com.google.android.gms.ads.MobileAds
+import com.google.android.gms.ads.*
import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd
import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAdLoadCallback
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.BuildConfig
+import io.github.wulkanowy.data.repositories.PreferencesRepository
import javax.inject.Inject
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
-class AdsHelper @Inject constructor(@ApplicationContext private val context: Context) {
+
+class AdsHelper @Inject constructor(
+ @ApplicationContext private val context: Context,
+ private val preferencesRepository: PreferencesRepository
+) {
+
+ fun initialize() {
+ if (preferencesRepository.isAgreeToProcessData) {
+ MobileAds.initialize(context)
+ }
+ }
suspend fun getSupportAd(): RewardedInterstitialAd? {
- MobileAds.initialize(context)
-
val extra = Bundle().apply { putString("npa", "1") }
val adRequest = AdRequest.Builder()
- .addNetworkExtrasBundle(AdMobAdapter::class.java, extra)
+ .apply {
+ if (!preferencesRepository.isPersonalizedAdsEnabled) {
+ addNetworkExtrasBundle(AdMobAdapter::class.java, extra)
+ }
+ }
.build()
return suspendCoroutine {
@@ -41,4 +53,35 @@ class AdsHelper @Inject constructor(@ApplicationContext private val context: Con
})
}
}
-}
\ No newline at end of file
+
+ suspend fun getDashboardTileAdBanner(width: Int): AdBanner {
+ val extra = Bundle().apply { putString("npa", "1") }
+ val adRequest = AdRequest.Builder()
+ .apply {
+ if (!preferencesRepository.isPersonalizedAdsEnabled) {
+ addNetworkExtrasBundle(AdMobAdapter::class.java, extra)
+ }
+ }
+ .build()
+
+ return suspendCoroutine {
+ val adView = AdView(context).apply {
+ adSize = AdSize.getPortraitAnchoredAdaptiveBannerAdSize(context, width)
+ adUnitId = BuildConfig.DASHBOARD_TILE_AD_ID
+ adListener = object : AdListener() {
+ override fun onAdFailedToLoad(loadAdError: LoadAdError) {
+ it.resumeWithException(IllegalArgumentException(loadAdError.message))
+ }
+
+ override fun onAdLoaded() {
+ it.resume(AdBanner(this@apply))
+ }
+ }
+ }
+
+ adView.loadAd(adRequest)
+ }
+ }
+}
+
+data class AdBanner(val view: View)
diff --git a/app/src/play/res/xml/scheme_preferences_ads.xml b/app/src/play/res/xml/scheme_preferences_ads.xml
index 52a3df58d..d5e93a355 100644
--- a/app/src/play/res/xml/scheme_preferences_ads.xml
+++ b/app/src/play/res/xml/scheme_preferences_ads.xml
@@ -2,11 +2,34 @@
+ app:title="Agreements">
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/app/src/test/java/io/github/wulkanowy/ui/modules/main/MainPresenterTest.kt b/app/src/test/java/io/github/wulkanowy/ui/modules/main/MainPresenterTest.kt
index 720239e62..6cfab1995 100644
--- a/app/src/test/java/io/github/wulkanowy/ui/modules/main/MainPresenterTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/ui/modules/main/MainPresenterTest.kt
@@ -4,7 +4,9 @@ import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.services.sync.SyncManager
import io.github.wulkanowy.ui.base.ErrorHandler
+import io.github.wulkanowy.utils.AdsHelper
import io.github.wulkanowy.utils.AnalyticsHelper
+import io.github.wulkanowy.utils.AppInfo
import io.mockk.*
import io.mockk.impl.annotations.MockK
import kotlinx.serialization.json.Json
@@ -31,6 +33,12 @@ class MainPresenterTest {
@MockK(relaxed = true)
lateinit var analytics: AnalyticsHelper
+ @MockK(relaxed = true)
+ lateinit var appInfo: AppInfo
+
+ @MockK(relaxed = true)
+ lateinit var adsHelper: AdsHelper
+
private lateinit var presenter: MainPresenter
@Before
@@ -42,10 +50,12 @@ class MainPresenterTest {
presenter = MainPresenter(
errorHandler = errorHandler,
studentRepository = studentRepository,
- prefRepository = prefRepository,
+ preferencesRepository = prefRepository,
syncManager = syncManager,
analytics = analytics,
- json = Json
+ json = Json,
+ appInfo = appInfo,
+ adsHelper = adsHelper
)
presenter.onAttachView(mainView, null)
}
From c4689fcbb38f7055f5378d7c6a537a79841e3a96 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sun, 26 Jun 2022 12:44:06 +0000
Subject: [PATCH 031/164] Bump agconnect-crash from 1.6.6.200 to 1.7.0.300
(#1899)
---
app/build.gradle | 2 +-
app/src/debug/agconnect-services.json | 115 +++++++++++++++-----
app/src/release/agconnect-services.json.gpg | Bin 608 -> 972 bytes
build.gradle | 2 +-
4 files changed, 89 insertions(+), 30 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 29325abff..ab1d0aefd 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -248,7 +248,7 @@ dependencies {
playImplementation 'com.google.android.gms:play-services-ads:21.0.0'
hmsImplementation 'com.huawei.hms:hianalytics:6.5.0.300'
- hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.6.200'
+ hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.0.300'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
diff --git a/app/src/debug/agconnect-services.json b/app/src/debug/agconnect-services.json
index 48192df01..52426f54e 100644
--- a/app/src/debug/agconnect-services.json
+++ b/app/src/debug/agconnect-services.json
@@ -1,33 +1,92 @@
{
- "agcgw":{
- "backurl":"connect-dre.dbankcloud.cn",
- "url":"connect-dre.hispace.hicloud.com"
- },
- "client":{
- "cp_id":"890048000024105546",
- "product_id":"",
- "client_id":"",
- "client_secret":"",
- "app_id":"101440411",
- "package_name":"io.github.wulkanowy.dev",
- "api_key":""
- },
- "service":{
- "analytics":{
- "collector_url":"datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
- "resource_id":"p1",
- "channel_id":""
- },
+ "agcgw": {
+ "backurl": "connect-dre.hispace.hicloud.com",
+ "url": "connect-dre.dbankcloud.cn",
+ "websocketbackurl": "connect-ws-dre.hispace.dbankcloud.com",
+ "websocketurl": "connect-ws-dre.hispace.dbankcloud.cn"
+ },
+ "agcgw_all": {
+ "CN": "connect-drcn.dbankcloud.cn",
+ "CN_back": "connect-drcn.hispace.hicloud.com",
+ "DE": "connect-dre.dbankcloud.cn",
+ "DE_back": "connect-dre.hispace.hicloud.com",
+ "RU": "connect-drru.hispace.dbankcloud.ru",
+ "RU_back": "connect-drru.hispace.dbankcloud.cn",
+ "SG": "connect-dra.dbankcloud.cn",
+ "SG_back": "connect-dra.hispace.hicloud.com"
+ },
+ "websocketgw_all": {
+ "CN": "connect-ws-drcn.hispace.dbankcloud.cn",
+ "CN_back": "connect-ws-drcn.hispace.dbankcloud.com",
+ "DE": "connect-ws-dre.hispace.dbankcloud.cn",
+ "DE_back": "connect-ws-dre.hispace.dbankcloud.com",
+ "RU": "connect-ws-drru.hispace.dbankcloud.ru",
+ "RU_back": "connect-ws-drru.hispace.dbankcloud.cn",
+ "SG": "connect-ws-dra.hispace.dbankcloud.cn",
+ "SG_back": "connect-ws-dra.hispace.dbankcloud.com"
+ },
+ "client": {
+ "cp_id": "890048000024105546",
+ "product_id": "736430079244736562",
+ "client_id": "514530959291319360",
+ "client_secret": "C42522DBF17D3D4BBE9D9C1783A54484B7E6844B388B7A67502D36A633A4186B",
+ "project_id": "736430079244736562",
+ "app_id": "106552551",
+ "api_key": "CgB6e3x9BUNiq+r8ebCHNojjjYsMT4pJSjjNDOkm9owtBb6rVI6LjnASoZBRxbjjhObcrV5gANo99fI/eKZDTbWS",
+ "package_name": "io.github.wulkanowy.dev"
+ },
+ "oauth_client": {
+ "client_id": "106552551",
+ "client_type": 1
+ },
+ "app_info": {
+ "app_id": "106552551",
+ "package_name": "io.github.wulkanowy.dev"
+ },
+ "service": {
+ "analytics": {
+ "collector_url": "datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
+ "collector_url_ru": "datacollector-drru.dt.dbankcloud.ru,datacollector-drru.dt.hicloud.com",
+ "collector_url_sg": "datacollector-dra.dt.hicloud.com,datacollector-dra.dt.dbankcloud.cn",
+ "collector_url_de": "datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
+ "collector_url_cn": "datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn",
+ "resource_id": "p1",
+ "channel_id": ""
+ },
"search":{
"url":"https://search-dre.cloud.huawei.com"
},
- "cloudstorage":{
- "storage_url":"https://ops-dre.agcstorage.link"
- },
- "ml":{
- "mlservice_url":"ml-api-dre.ai.dbankcloud.com,ml-api-dre.ai.dbankcloud.cn"
- }
- },
- "region":"DE",
- "configuration_version":"1.0"
+ "cloudstorage": {
+ "storage_url_sg_back": "https://agc-storage-dra.cloud.huawei.asia",
+ "storage_url_ru_back": "https://agc-storage-drru.cloud.huawei.ru",
+ "storage_url_ru": "https://agc-storage-drru.cloud.huawei.ru",
+ "storage_url_de_back": "https://agc-storage-dre.cloud.huawei.eu",
+ "storage_url_de": "https://ops-dre.agcstorage.link",
+ "storage_url": "https://agc-storage-drcn.platform.dbankcloud.cn",
+ "storage_url_sg": "https://ops-dra.agcstorage.link",
+ "storage_url_cn_back": "https://agc-storage-drcn.cloud.huawei.com.cn",
+ "storage_url_cn": "https://agc-storage-drcn.platform.dbankcloud.cn"
+ },
+ "ml": {
+ "mlservice_url": "ml-api-dre.ai.dbankcloud.com,ml-api-dre.ai.dbankcloud.cn"
+ }
+ },
+ "region": "DE",
+ "configuration_version": "3.0",
+ "appInfos": [
+ {
+ "package_name": "io.github.wulkanowy.dev",
+ "client": {
+ "app_id": "106552551"
+ },
+ "app_info": {
+ "package_name": "io.github.wulkanowy.dev",
+ "app_id": "106552551"
+ },
+ "oauth_client": {
+ "client_type": 1,
+ "client_id": "106552551"
+ }
+ }
+ ]
}
diff --git a/app/src/release/agconnect-services.json.gpg b/app/src/release/agconnect-services.json.gpg
index 484d8bc72d7a15b689a3fb76cddd91f1992cebf4..149b9b26818f97db4ac68202bbde3c1fde04f422 100644
GIT binary patch
literal 972
zcmeC-W#MFI%CvVWn)pF~)2B->8E2?+NK~+wEmA%j+80#$WVzsb?=#N){B2s#L*)Xl
zZftqWws;5gwPRWTW0pQkYnQlnt96a~2Ih|&t&Yz4^>Vsy1%Lha8+soXZ;TK;wAb-c
zrbc&sd2mi||2EUv+>Ym7Zc%gXTsGnJd1E!n9efv(w#Qj7esS%=ulUx5GvhiIxz#_P
zAa8$t|J~n{H%3hk+)<;rJ>W_7&Yi7mBc?8J-Bw@S<{#Nnd-zXuRmZmZPxzC=rd>DG
zt~}u2vEbt;!7KMp7@ZQk-uP{z2}AR24dvn+%J%|3UOd$m+kRe?tsiSI56
zGami;DkoQPrL^AiuG+U-!(Wc&MA)@%%}{p^851=%
zrr$g3pL@LHZlAr>@WN@kJ@Ow_I4zbIo3<9eIc%x@Xj&!5jQUq`|7{doV&wf#@kMD@
zG}q+tJvq1H@ACiQKY9MSolknG!ancx=JoR?>qkpYlT^ripBuN$E1e;Tb)iaU-O;nF
zKFpgPW$%=K=>FN$imm@!!XIinUKLEYx4R-MsOFS&udE<-)*0T92YyEExY57zP@&-F
zO`9Cv)OvRcU-Dihozx$pJ>}D-kjC6Q78zz`C7A+`-PfqRJ$ZHU=GN%2{QzB@UgFw)%4P>D`2a!wQ?_
z*t6rbZ}piinpM2|wokEc{NXCQMT%`=R?8yi-LUw{@AjehVSJr|T}orT%!4hCac3Cx
z4p%KtU8bn2ov@VA#qW1A$ByD7C&jiUU3GDL^X{z^EL66&iv3sFV(yXorruHL
z;FS4MCbdWI6g_k~z;f-%pF8^Anwt`f<4(-p*%JAahnJt7+wqHO!CVvlX6{+%yG1u0
zva4IZZGQcln_j21_lX|jEN{D%z0lypyr3&Po?X(Lf4cVH9K*Psyvnz^{@YGTo#R(E
z-)!YF*$SZrk{4~6qIHsHx~5$Y(qDPeNWG3LCrj>*&9acxT8
zenrbN!D{v|T*0w*XS%L^Sb9*_Tk4?jeV1R2JD1dM64L&9A>>KjrzZ`;kK~(Y{Jt+;
z)bDJ0?*Ej1c}}9y4D0U}&d9vu6Z%xe-qF&wPk++Yy*F;Zs*2Q7TXvaKwqe?>E3b?G
zdK9-XSUz(@jfchUcT{rL0@)a|GUkmJOb{FkC$JQ
z<9qd5f0pN$s^e^HO*OcBV|XsGG3abCtw>m8GjY=T)lWH+f*=1sbi*lPLHV{M=biou
zOO4-7_h*9V_;&zm=sJ!mvAJ
zv*7Qg%cn7C#@vW}SJ9r;-}HOaW}{FS^<({6qQ&2CW+=M^_A?7Hd^j4{7;^OKjISKR7LmZLtn6cQ|L6U~ur$r?+|kZ4&s-FIg{O8v5|;#tTV|E&Ch8nEZvEA51G>
zF!yZDzuEVEENhqdm7inF+p=lJozs`nSoU)+3l5pHXw5z|rgldYkJ)}+E2c5G2Bdgw
zz0~8>ILTT}KlYGWN?rQT$!WL$)~*a`F5Ta>kSltz^?%p-Nm54^bL|gZ(O44p
Date: Sun, 26 Jun 2022 15:50:35 +0200
Subject: [PATCH 032/164] Fix ads tile (#1905)
---
.../repositories/PreferencesRepository.kt | 25 ++++++++++++++++---
.../modules/dashboard/DashboardPresenter.kt | 6 ++++-
.../ui/modules/main/MainPresenter.kt | 4 +--
.../ui/modules/settings/ads/AdsFragment.kt | 5 ----
.../ui/modules/settings/ads/AdsPresenter.kt | 10 --------
.../io/github/wulkanowy/utils/AdsHelper.kt | 2 +-
6 files changed, 29 insertions(+), 23 deletions(-)
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt
index 237fb1a0a..486538e0c 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt
@@ -222,17 +222,31 @@ class PreferencesRepository @Inject constructor(
get() = selectedDashboardTilesPreference.asFlow()
.map { set ->
set.map { DashboardItem.Tile.valueOf(it) }
- .plus(listOf(DashboardItem.Tile.ACCOUNT, DashboardItem.Tile.ADMIN_MESSAGE))
+ .plus(
+ listOfNotNull(
+ DashboardItem.Tile.ACCOUNT,
+ DashboardItem.Tile.ADMIN_MESSAGE,
+ DashboardItem.Tile.ADS.takeIf { isAdsEnabled }
+ )
+ )
.toSet()
}
var selectedDashboardTiles: Set
get() = selectedDashboardTilesPreference.get()
.map { DashboardItem.Tile.valueOf(it) }
- .plus(listOf(DashboardItem.Tile.ACCOUNT, DashboardItem.Tile.ADMIN_MESSAGE))
+ .plus(
+ listOfNotNull(
+ DashboardItem.Tile.ACCOUNT,
+ DashboardItem.Tile.ADMIN_MESSAGE,
+ DashboardItem.Tile.ADS.takeIf { isAdsEnabled }
+ )
+ )
.toSet()
set(value) {
- val filteredValue = value.filterNot { it == DashboardItem.Tile.ACCOUNT }
+ val filteredValue = value.filterNot {
+ it == DashboardItem.Tile.ACCOUNT || it == DashboardItem.Tile.ADMIN_MESSAGE
+ }
.map { it.name }
.toSet()
@@ -288,6 +302,11 @@ class PreferencesRepository @Inject constructor(
get() = sharedPref.getBoolean(PREF_KEY_PERSONALIZED_ADS_ENABLED, false)
set(value) = sharedPref.edit { putBoolean(PREF_KEY_PERSONALIZED_ADS_ENABLED, value) }
+ val isAdsEnabledFlow = flowSharedPref.getBoolean(
+ context.getString(R.string.pref_key_ads_enabled),
+ context.resources.getBoolean(R.bool.pref_default_ads_enabled)
+ ).asFlow()
+
var isAdsEnabled: Boolean
get() = getBoolean(
R.string.pref_key_ads_enabled,
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
index e963a0205..5d7c7df4b 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
@@ -57,7 +57,11 @@ class DashboardPresenter @Inject constructor(
showContent(false)
}
- preferencesRepository.selectedDashboardTilesFlow
+ merge(
+ preferencesRepository.selectedDashboardTilesFlow,
+ preferencesRepository.isAdsEnabledFlow
+ .map { preferencesRepository.selectedDashboardTiles }
+ )
.onEach { loadData(tilesToLoad = it) }
.launch("dashboard_pref")
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt
index 8f457d925..9c32d8583 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt
@@ -14,7 +14,6 @@ import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.ui.modules.account.AccountView
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsView
-import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
import io.github.wulkanowy.ui.modules.grade.GradeView
import io.github.wulkanowy.ui.modules.message.MessageView
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersView
@@ -168,13 +167,12 @@ class MainPresenter @Inject constructor(
}
fun onPrivacyAgree(isPersonalizedAds: Boolean) {
- preferencesRepository.isAdsEnabled = true
preferencesRepository.isAgreeToProcessData = true
preferencesRepository.isPersonalizedAdsEnabled = isPersonalizedAds
adsHelper.initialize()
- preferencesRepository.selectedDashboardTiles += DashboardItem.Tile.ADS
+ preferencesRepository.isAdsEnabled = true
}
fun onPrivacySelected() {
diff --git a/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsFragment.kt b/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsFragment.kt
index 48a6fc3ec..de4c591e1 100644
--- a/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsFragment.kt
+++ b/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsFragment.kt
@@ -50,11 +50,6 @@ class AdsFragment : PreferenceFragmentCompat(), MainView.TitledView, AdsView {
presenter.onConsentSelected(newValue as Boolean)
true
}
-
- findPreference(getString(R.string.pref_key_ads_enabled))?.setOnPreferenceChangeListener { _, newValue ->
- presenter.onAddEnabled(newValue as Boolean)
- true
- }
}
override fun showAd(ad: RewardedInterstitialAd) {
diff --git a/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsPresenter.kt b/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsPresenter.kt
index 85c14c0a0..772d616d7 100644
--- a/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsPresenter.kt
+++ b/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsPresenter.kt
@@ -4,7 +4,6 @@ import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
-import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
import io.github.wulkanowy.utils.AdsHelper
import kotlinx.coroutines.launch
import timber.log.Timber
@@ -48,7 +47,6 @@ class AdsPresenter @Inject constructor(
} else {
view?.showProcessingDataSummary(null)
view?.setCheckedAdsEnabled(false)
- onAddEnabled(false)
}
}
@@ -77,12 +75,4 @@ class AdsPresenter @Inject constructor(
view?.setCheckedProcessingData(true)
view?.showProcessingDataSummary(true)
}
-
- fun onAddEnabled(isEnabled: Boolean) {
- if (isEnabled) {
- preferencesRepository.selectedDashboardTiles += DashboardItem.Tile.ADS
- } else {
- preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS
- }
- }
}
diff --git a/app/src/play/java/io/github/wulkanowy/utils/AdsHelper.kt b/app/src/play/java/io/github/wulkanowy/utils/AdsHelper.kt
index 6be8e924c..c536e2218 100644
--- a/app/src/play/java/io/github/wulkanowy/utils/AdsHelper.kt
+++ b/app/src/play/java/io/github/wulkanowy/utils/AdsHelper.kt
@@ -66,7 +66,7 @@ class AdsHelper @Inject constructor(
return suspendCoroutine {
val adView = AdView(context).apply {
- adSize = AdSize.getPortraitAnchoredAdaptiveBannerAdSize(context, width)
+ setAdSize(AdSize.getPortraitAnchoredAdaptiveBannerAdSize(context, width))
adUnitId = BuildConfig.DASHBOARD_TILE_AD_ID
adListener = object : AdListener() {
override fun onAdFailedToLoad(loadAdError: LoadAdError) {
From b70649f13672b45e8574cdc2f92c8ebc6299bfec Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 28 Jun 2022 15:05:51 +0000
Subject: [PATCH 033/164] Bump about_libraries from 10.3.0 to 10.3.1 (#1907)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 0391e282c..21964d49d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,7 @@
buildscript {
ext {
kotlin_version = '1.7.0'
- about_libraries = '10.3.0'
+ about_libraries = '10.3.1'
hilt_version = "2.42"
}
repositories {
From e70fe6f097039ea0ddd8e92d96627d82ea6ac925 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 28 Jun 2022 15:06:20 +0000
Subject: [PATCH 034/164] Bump firebase-crashlytics-gradle from 2.9.0 to 2.9.1
(#1910)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 21964d49d..7949ceaac 100644
--- a/build.gradle
+++ b/build.gradle
@@ -17,7 +17,7 @@ buildscript {
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.google.gms:google-services:4.3.10'
classpath 'com.huawei.agconnect:agcp:1.7.0.300'
- classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.0'
+ classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.1'
classpath "com.github.triplet.gradle:play-publisher:3.6.0"
classpath "ru.cian:huawei-publish-gradle-plugin:1.3.3"
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513"
From 0f11f14c3e3df07a3a77c7405df8245689831d12 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 28 Jun 2022 15:07:33 +0000
Subject: [PATCH 035/164] Bump firebase-bom from 30.1.0 to 30.2.0 (#1909)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index ab1d0aefd..b7a5c04b0 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -239,7 +239,7 @@ dependencies {
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.7.0'
- playImplementation platform('com.google.firebase:firebase-bom:30.1.0')
+ playImplementation platform('com.google.firebase:firebase-bom:30.2.0')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
From 1b74bffc06bab18be850a9a2be80a75385fb6166 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Borcz?=
Date: Sat, 2 Jul 2022 19:10:57 +0200
Subject: [PATCH 036/164] Fix no mobile devices on parent account (#1896)
---
.../50.json | 2445 +++++++++++++++++
.../github/wulkanowy/data/db/AppDatabase.kt | 5 +-
.../wulkanowy/data/db/dao/MobileDeviceDao.kt | 2 +-
.../data/db/entities/MobileDevice.kt | 2 +-
.../data/db/migrations/Migration50.kt | 21 +
.../data/mappers/MobileDeviceMapper.kt | 6 +-
.../repositories/MobileDeviceRepository.kt | 4 +-
.../MobileDeviceRepositoryTest.kt | 20 +-
8 files changed, 2486 insertions(+), 19 deletions(-)
create mode 100644 app/schemas/io.github.wulkanowy.data.db.AppDatabase/50.json
create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration50.kt
diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/50.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/50.json
new file mode 100644
index 000000000..4361db954
--- /dev/null
+++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/50.json
@@ -0,0 +1,2445 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 50,
+ "identityHash": "87455aae2b15baa976386c833afa9cd9",
+ "entities": [
+ {
+ "tableName": "Students",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`scrapper_base_url` TEXT NOT NULL, `mobile_base_url` TEXT NOT NULL, `login_type` TEXT NOT NULL, `login_mode` TEXT NOT NULL, `certificate_key` TEXT NOT NULL, `private_key` TEXT NOT NULL, `is_parent` INTEGER NOT NULL, `email` TEXT NOT NULL, `password` TEXT NOT NULL, `symbol` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `user_login_id` INTEGER NOT NULL, `user_name` TEXT NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_short` TEXT NOT NULL, `school_name` TEXT NOT NULL, `class_name` TEXT NOT NULL, `class_id` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `registration_date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `nick` TEXT NOT NULL, `avatar_color` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "scrapperBaseUrl",
+ "columnName": "scrapper_base_url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mobileBaseUrl",
+ "columnName": "mobile_base_url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginType",
+ "columnName": "login_type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginMode",
+ "columnName": "login_mode",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "certificateKey",
+ "columnName": "certificate_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "privateKey",
+ "columnName": "private_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isParent",
+ "columnName": "is_parent",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "password",
+ "columnName": "password",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "symbol",
+ "columnName": "symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "user_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentName",
+ "columnName": "student_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolSymbol",
+ "columnName": "school_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolShortName",
+ "columnName": "school_short",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolName",
+ "columnName": "school_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "className",
+ "columnName": "class_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isCurrent",
+ "columnName": "is_current",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registrationDate",
+ "columnName": "registration_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "nick",
+ "columnName": "nick",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "avatarColor",
+ "columnName": "avatar_color",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_Students_email_symbol_student_id_school_id_class_id",
+ "unique": true,
+ "columnNames": [
+ "email",
+ "symbol",
+ "student_id",
+ "school_id",
+ "class_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Students_email_symbol_student_id_school_id_class_id` ON `${TABLE_NAME}` (`email`, `symbol`, `student_id`, `school_id`, `class_id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Semesters",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `kindergarten_diary_id` INTEGER NOT NULL DEFAULT 0, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "kindergartenDiaryId",
+ "columnName": "kindergarten_diary_id",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ },
+ {
+ "fieldPath": "diaryName",
+ "columnName": "diary_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolYear",
+ "columnName": "school_year",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterName",
+ "columnName": "semester_name",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unitId",
+ "columnName": "unit_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "current",
+ "columnName": "is_current",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id",
+ "unique": true,
+ "columnNames": [
+ "student_id",
+ "diary_id",
+ "kindergarten_diary_id",
+ "semester_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id` ON `${TABLE_NAME}` (`student_id`, `diary_id`, `kindergarten_diary_id`, `semester_id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Exams",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `group` TEXT NOT NULL, `type` TEXT NOT NULL, `description` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entryDate",
+ "columnName": "entry_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "group",
+ "columnName": "group",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Timetable",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `number` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `subjectOld` TEXT NOT NULL, `group` TEXT NOT NULL, `room` TEXT NOT NULL, `roomOld` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacherOld` TEXT NOT NULL, `info` TEXT NOT NULL, `student_plan` INTEGER NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectOld",
+ "columnName": "subjectOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "group",
+ "columnName": "group",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "room",
+ "columnName": "room",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "roomOld",
+ "columnName": "roomOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherOld",
+ "columnName": "teacherOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "info",
+ "columnName": "info",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isStudentPlan",
+ "columnName": "student_plan",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "changes",
+ "columnName": "changes",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "canceled",
+ "columnName": "canceled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Attendance",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `time_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `excused` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `excusable` INTEGER NOT NULL, `excuse_status` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "timeId",
+ "columnName": "time_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presence",
+ "columnName": "presence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "exemption",
+ "columnName": "exemption",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lateness",
+ "columnName": "lateness",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excused",
+ "columnName": "excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deleted",
+ "columnName": "deleted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excusable",
+ "columnName": "excusable",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excuseStatus",
+ "columnName": "excuse_status",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AttendanceSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `subject_id` INTEGER NOT NULL, `month` INTEGER NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `absence_excused` INTEGER NOT NULL, `absence_for_school_reasons` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `lateness_excused` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subject_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "month",
+ "columnName": "month",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presence",
+ "columnName": "presence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absenceExcused",
+ "columnName": "absence_excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absenceForSchoolReasons",
+ "columnName": "absence_for_school_reasons",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lateness",
+ "columnName": "lateness",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "latenessExcused",
+ "columnName": "lateness_excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "exemption",
+ "columnName": "exemption",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Grades",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `entry` TEXT NOT NULL, `value` REAL NOT NULL, `modifier` REAL NOT NULL, `comment` TEXT NOT NULL, `color` TEXT NOT NULL, `grade_symbol` TEXT NOT NULL, `description` TEXT NOT NULL, `weight` TEXT NOT NULL, `weightValue` REAL NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entry",
+ "columnName": "entry",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "modifier",
+ "columnName": "modifier",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "color",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gradeSymbol",
+ "columnName": "grade_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weightValue",
+ "columnName": "weightValue",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isRead",
+ "columnName": "is_read",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `position` INTEGER NOT NULL, `subject` TEXT NOT NULL, `predicted_grade` TEXT NOT NULL, `final_grade` TEXT NOT NULL, `proposed_points` TEXT NOT NULL, `final_points` TEXT NOT NULL, `points_sum` TEXT NOT NULL, `average` REAL NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_predicted_grade_notified` INTEGER NOT NULL, `is_final_grade_notified` INTEGER NOT NULL, `predicted_grade_last_change` INTEGER NOT NULL, `final_grade_last_change` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "position",
+ "columnName": "position",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "predictedGrade",
+ "columnName": "predicted_grade",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalGrade",
+ "columnName": "final_grade",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "proposedPoints",
+ "columnName": "proposed_points",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalPoints",
+ "columnName": "final_points",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pointsSum",
+ "columnName": "points_sum",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "average",
+ "columnName": "average",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPredictedGradeNotified",
+ "columnName": "is_predicted_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFinalGradeNotified",
+ "columnName": "is_final_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "predictedGradeLastChange",
+ "columnName": "predicted_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalGradeLastChange",
+ "columnName": "final_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradePartialStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `class_average` TEXT NOT NULL, `student_average` TEXT NOT NULL, `class_amounts` TEXT NOT NULL, `student_amounts` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classAverage",
+ "columnName": "class_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAverage",
+ "columnName": "student_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classAmounts",
+ "columnName": "class_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAmounts",
+ "columnName": "student_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesPointsStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `others` REAL NOT NULL, `student` REAL NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "others",
+ "columnName": "others",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "student",
+ "columnName": "student",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradeSemesterStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `amounts` TEXT NOT NULL, `student_grade` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "amounts",
+ "columnName": "amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentGrade",
+ "columnName": "student_grade",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Messages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `recipient_name` TEXT NOT NULL, `subject` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `removed` INTEGER NOT NULL, `has_attachments` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `unread_by` INTEGER NOT NULL, `read_by` INTEGER NOT NULL, `content` TEXT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageId",
+ "columnName": "message_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "sender",
+ "columnName": "sender_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "senderId",
+ "columnName": "sender_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "recipient",
+ "columnName": "recipient_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unread",
+ "columnName": "unread",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "removed",
+ "columnName": "removed",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasAttachments",
+ "columnName": "has_attachments",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unreadBy",
+ "columnName": "unread_by",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "readBy",
+ "columnName": "read_by",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MessageAttachments",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `one_drive_id` TEXT NOT NULL, `url` TEXT NOT NULL, `filename` TEXT NOT NULL, PRIMARY KEY(`real_id`))",
+ "fields": [
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageId",
+ "columnName": "message_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "oneDriveId",
+ "columnName": "one_drive_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filename",
+ "columnName": "filename",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "real_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `category` TEXT NOT NULL, `category_type` INTEGER NOT NULL, `is_points_show` INTEGER NOT NULL, `points` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "categoryType",
+ "columnName": "category_type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPointsShow",
+ "columnName": "is_points_show",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "points",
+ "columnName": "points",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isRead",
+ "columnName": "is_read",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Homework",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `attachments` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_done` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `is_added_by_user` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entryDate",
+ "columnName": "entry_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "attachments",
+ "columnName": "attachments",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDone",
+ "columnName": "is_done",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Subjects",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "LuckyNumbers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "luckyNumber",
+ "columnName": "lucky_number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "CompletedLesson",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `topic` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `substitution` TEXT NOT NULL, `absence` TEXT NOT NULL, `resources` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "topic",
+ "columnName": "topic",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "substitution",
+ "columnName": "substitution",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "resources",
+ "columnName": "resources",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "ReportingUnits",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `short` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `roles` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unitId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "shortName",
+ "columnName": "short",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "senderId",
+ "columnName": "sender_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "senderName",
+ "columnName": "sender_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "roles",
+ "columnName": "roles",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Recipients",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `real_id` TEXT NOT NULL, `name` TEXT NOT NULL, `real_name` TEXT NOT NULL, `login_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `role` INTEGER NOT NULL, `hash` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realName",
+ "columnName": "real_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginId",
+ "columnName": "login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unitId",
+ "columnName": "unit_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "role",
+ "columnName": "role",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hash",
+ "columnName": "hash",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MobileDevices",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_login_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deviceId",
+ "columnName": "device_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Teachers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "shortName",
+ "columnName": "short_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "School",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT NOT NULL, `contact` TEXT NOT NULL, `headmaster` TEXT NOT NULL, `pedagogue` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "contact",
+ "columnName": "contact",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "headmaster",
+ "columnName": "headmaster",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pedagogue",
+ "columnName": "pedagogue",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Conferences",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `subject` TEXT NOT NULL, `agenda` TEXT NOT NULL, `present_on_conference` TEXT NOT NULL, `conference_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "agenda",
+ "columnName": "agenda",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presentOnConference",
+ "columnName": "present_on_conference",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "conferenceId",
+ "columnName": "conference_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableAdditional",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `repeat_id` BLOB DEFAULT NULL, `is_added_by_user` INTEGER NOT NULL DEFAULT 0)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "repeatId",
+ "columnName": "repeat_id",
+ "affinity": "BLOB",
+ "notNull": false,
+ "defaultValue": "NULL"
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "StudentInfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `full_name` TEXT NOT NULL, `first_name` TEXT NOT NULL, `second_name` TEXT NOT NULL, `surname` TEXT NOT NULL, `birth_date` INTEGER NOT NULL, `birth_place` TEXT NOT NULL, `gender` TEXT NOT NULL, `has_polish_citizenship` INTEGER NOT NULL, `family_name` TEXT NOT NULL, `parents_names` TEXT NOT NULL, `address` TEXT NOT NULL, `registered_address` TEXT NOT NULL, `correspondence_address` TEXT NOT NULL, `phone_number` TEXT NOT NULL, `cell_phone_number` TEXT NOT NULL, `email` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `first_guardian_full_name` TEXT, `first_guardian_kinship` TEXT, `first_guardian_address` TEXT, `first_guardian_phones` TEXT, `first_guardian_email` TEXT, `second_guardian_full_name` TEXT, `second_guardian_kinship` TEXT, `second_guardian_address` TEXT, `second_guardian_phones` TEXT, `second_guardian_email` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "full_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstName",
+ "columnName": "first_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "secondName",
+ "columnName": "second_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "surname",
+ "columnName": "surname",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthDate",
+ "columnName": "birth_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthPlace",
+ "columnName": "birth_place",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gender",
+ "columnName": "gender",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPolishCitizenship",
+ "columnName": "has_polish_citizenship",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "familyName",
+ "columnName": "family_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentsNames",
+ "columnName": "parents_names",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registeredAddress",
+ "columnName": "registered_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "correspondenceAddress",
+ "columnName": "correspondence_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "phoneNumber",
+ "columnName": "phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "cellPhoneNumber",
+ "columnName": "cell_phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstGuardian.fullName",
+ "columnName": "first_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.kinship",
+ "columnName": "first_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.address",
+ "columnName": "first_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.phones",
+ "columnName": "first_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.email",
+ "columnName": "first_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.fullName",
+ "columnName": "second_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.kinship",
+ "columnName": "second_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.address",
+ "columnName": "second_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.phones",
+ "columnName": "second_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.email",
+ "columnName": "second_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableHeaders",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "SchoolAnnouncements",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_login_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notifications",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `type` TEXT NOT NULL, `destination` TEXT NOT NULL DEFAULT '{\"type\":\"io.github.wulkanowy.ui.modules.Destination.Dashboard\"}', `date` INTEGER NOT NULL, `data` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "destination",
+ "columnName": "destination",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'{\"type\":\"io.github.wulkanowy.ui.modules.Destination.Dashboard\"}'"
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "data",
+ "columnName": "data",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AdminMessages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `version_name` INTEGER, `version_max` INTEGER, `target_register_host` TEXT, `target_flavor` TEXT, `destination_url` TEXT, `priority` TEXT NOT NULL, `type` TEXT NOT NULL, `is_dismissible` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "versionMin",
+ "columnName": "version_name",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "versionMax",
+ "columnName": "version_max",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetRegisterHost",
+ "columnName": "target_register_host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetFlavor",
+ "columnName": "target_flavor",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "destinationUrl",
+ "columnName": "destination_url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "priority",
+ "columnName": "priority",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDismissible",
+ "columnName": "is_dismissible",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '87455aae2b15baa976386c833afa9cd9')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
index 17fd7d696..87915a9ed 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
@@ -55,7 +55,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() {
companion object {
- const val VERSION_SCHEMA = 49
+ const val VERSION_SCHEMA = 50
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
Migration2(),
@@ -102,7 +102,8 @@ abstract class AppDatabase : RoomDatabase() {
Migration43(),
Migration44(),
Migration46(),
- Migration49()
+ Migration49(),
+ Migration50()
)
fun newInstance(
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/MobileDeviceDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/MobileDeviceDao.kt
index 081e859a5..96382cc10 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/MobileDeviceDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/MobileDeviceDao.kt
@@ -8,6 +8,6 @@ import kotlinx.coroutines.flow.Flow
@Dao
interface MobileDeviceDao : BaseDao {
- @Query("SELECT * FROM MobileDevices WHERE student_id = :userLoginId ORDER BY date DESC")
+ @Query("SELECT * FROM MobileDevices WHERE user_login_id = :userLoginId ORDER BY date DESC")
fun loadAll(userLoginId: Int): Flow>
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/MobileDevice.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/MobileDevice.kt
index 887e43239..89b04ccc8 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/MobileDevice.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/MobileDevice.kt
@@ -9,7 +9,7 @@ import java.time.Instant
@Entity(tableName = "MobileDevices")
data class MobileDevice(
- @ColumnInfo(name = "student_id")
+ @ColumnInfo(name = "user_login_id")
val userLoginId: Int,
@ColumnInfo(name = "device_id")
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration50.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration50.kt
new file mode 100644
index 000000000..d45a81570
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration50.kt
@@ -0,0 +1,21 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class Migration50 : Migration(49, 50) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("DROP TABLE IF EXISTS MobileDevices")
+ database.execSQL(
+ """
+ CREATE TABLE IF NOT EXISTS `MobileDevices` (
+ `user_login_id` INTEGER NOT NULL,
+ `device_id` INTEGER NOT NULL,
+ `name` TEXT NOT NULL,
+ `date` INTEGER NOT NULL,
+ `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)
+ """.trimIndent()
+ )
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/MobileDeviceMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/MobileDeviceMapper.kt
index b1e96a27b..1a1c501f6 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/MobileDeviceMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/MobileDeviceMapper.kt
@@ -1,14 +1,14 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.MobileDevice
-import io.github.wulkanowy.data.db.entities.Semester
+import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.pojos.MobileDeviceToken
import io.github.wulkanowy.sdk.pojo.Device as SdkDevice
import io.github.wulkanowy.sdk.pojo.Token as SdkToken
-fun List.mapToEntities(semester: Semester) = map {
+fun List.mapToEntities(student: Student) = map {
MobileDevice(
- userLoginId = semester.studentId,
+ userLoginId = student.userLoginId,
date = it.createDateZoned.toInstant(),
deviceId = it.id,
name = it.name
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/MobileDeviceRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/MobileDeviceRepository.kt
index eda40cac4..07c6959e3 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/MobileDeviceRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/MobileDeviceRepository.kt
@@ -39,12 +39,12 @@ class MobileDeviceRepository @Inject constructor(
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
it.isEmpty() || forceRefresh || isExpired
},
- query = { mobileDb.loadAll(student.userLoginId.takeIf { it != 0 } ?: student.studentId) },
+ query = { mobileDb.loadAll(student.userLoginId) },
fetch = {
sdk.init(student)
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getRegisteredDevices()
- .mapToEntities(semester)
+ .mapToEntities(student)
},
saveFetchResult = { old, new ->
mobileDb.deleteAll(old uniqueSubtract new)
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/MobileDeviceRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/MobileDeviceRepositoryTest.kt
index b9a958d43..6865aa7da 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/MobileDeviceRepositoryTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/MobileDeviceRepositoryTest.kt
@@ -56,8 +56,8 @@ class MobileDeviceRepositoryTest {
// prepare
coEvery { sdk.getRegisteredDevices() } returns remoteList
coEvery { mobileDeviceDb.loadAll(student.studentId) } returnsMany listOf(
- flowOf(remoteList.mapToEntities(semester)),
- flowOf(remoteList.mapToEntities(semester))
+ flowOf(remoteList.mapToEntities(student)),
+ flowOf(remoteList.mapToEntities(student))
)
coEvery { mobileDeviceDb.insertAll(any()) } returns listOf(1, 2, 3)
coEvery { mobileDeviceDb.deleteAll(any()) } just Runs
@@ -79,9 +79,9 @@ class MobileDeviceRepositoryTest {
// prepare
coEvery { sdk.getRegisteredDevices() } returns remoteList
coEvery { mobileDeviceDb.loadAll(1) } returnsMany listOf(
- flowOf(remoteList.dropLast(1).mapToEntities(semester)),
- flowOf(remoteList.dropLast(1).mapToEntities(semester)), // after fetch end before save result
- flowOf(remoteList.mapToEntities(semester))
+ flowOf(remoteList.dropLast(1).mapToEntities(student)),
+ flowOf(remoteList.dropLast(1).mapToEntities(student)), // after fetch end before save result
+ flowOf(remoteList.mapToEntities(student))
)
coEvery { mobileDeviceDb.insertAll(any()) } returns listOf(1, 2, 3)
coEvery { mobileDeviceDb.deleteAll(any()) } just Runs
@@ -96,7 +96,7 @@ class MobileDeviceRepositoryTest {
coVerify { mobileDeviceDb.loadAll(1) }
coVerify {
mobileDeviceDb.insertAll(match {
- it.size == 1 && it[0] == remoteList.mapToEntities(semester)[1]
+ it.size == 1 && it[0] == remoteList.mapToEntities(student)[1]
})
}
coVerify { mobileDeviceDb.deleteAll(match { it.isEmpty() }) }
@@ -107,9 +107,9 @@ class MobileDeviceRepositoryTest {
// prepare
coEvery { sdk.getRegisteredDevices() } returns remoteList.dropLast(1)
coEvery { mobileDeviceDb.loadAll(1) } returnsMany listOf(
- flowOf(remoteList.mapToEntities(semester)),
- flowOf(remoteList.mapToEntities(semester)), // after fetch end before save result
- flowOf(remoteList.dropLast(1).mapToEntities(semester))
+ flowOf(remoteList.mapToEntities(student)),
+ flowOf(remoteList.mapToEntities(student)), // after fetch end before save result
+ flowOf(remoteList.dropLast(1).mapToEntities(student))
)
coEvery { mobileDeviceDb.insertAll(any()) } returns listOf(1, 2, 3)
coEvery { mobileDeviceDb.deleteAll(any()) } just Runs
@@ -125,7 +125,7 @@ class MobileDeviceRepositoryTest {
coVerify { mobileDeviceDb.insertAll(match { it.isEmpty() }) }
coVerify {
mobileDeviceDb.deleteAll(match {
- it.size == 1 && it[0] == remoteList.mapToEntities(semester)[1]
+ it.size == 1 && it[0] == remoteList.mapToEntities(student)[1]
})
}
}
From fcc7dc0913227c595a2575326b80d3ba51ca15d4 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 9 Jul 2022 07:33:27 +0000
Subject: [PATCH 037/164] Bump fragment-ktx from 1.4.1 to 1.5.0 (#1915)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index b7a5c04b0..50c572ed0 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -195,7 +195,7 @@ dependencies {
implementation 'androidx.core:core-splashscreen:1.0.0-rc01'
implementation "androidx.activity:activity-ktx:1.4.0"
implementation "androidx.appcompat:appcompat:1.4.2"
- implementation "androidx.fragment:fragment-ktx:1.4.1"
+ implementation "androidx.fragment:fragment-ktx:1.5.0"
implementation "androidx.annotation:annotation:1.4.0"
implementation "androidx.preference:preference-ktx:1.2.0"
From 89a6a98bbf7e15e808b35bea3d8364c5e1cacdca Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 9 Jul 2022 07:33:46 +0000
Subject: [PATCH 038/164] Bump google-services from 4.3.10 to 4.3.13 (#1913)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 7949ceaac..b96c8582e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -15,7 +15,7 @@ buildscript {
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath 'com.android.tools.build:gradle:7.2.1'
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
- classpath 'com.google.gms:google-services:4.3.10'
+ classpath 'com.google.gms:google-services:4.3.13'
classpath 'com.huawei.agconnect:agcp:1.7.0.300'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.1'
classpath "com.github.triplet.gradle:play-publisher:3.6.0"
From 344e0d55ffb83c0acd75b1d2ed2755a7c9033329 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 9 Jul 2022 07:34:03 +0000
Subject: [PATCH 039/164] Bump lifecycle-livedata-ktx from 2.4.1 to 2.5.0
(#1911)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 50c572ed0..83e18e953 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -212,7 +212,7 @@ dependencies {
implementation "androidx.work:work-runtime-ktx:$work_manager"
playImplementation "androidx.work:work-gcm:$work_manager"
- implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1"
+ implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.0"
implementation "androidx.room:room-runtime:$room"
implementation "androidx.room:room-ktx:$room"
From 4b6277abf517162b695788d082126a7e25ba6953 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 9 Jul 2022 07:34:24 +0000
Subject: [PATCH 040/164] Bump activity-ktx from 1.4.0 to 1.5.0 (#1912)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 83e18e953..91c458761 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -193,7 +193,7 @@ dependencies {
implementation "androidx.core:core-ktx:1.8.0"
implementation 'androidx.core:core-splashscreen:1.0.0-rc01'
- implementation "androidx.activity:activity-ktx:1.4.0"
+ implementation "androidx.activity:activity-ktx:1.5.0"
implementation "androidx.appcompat:appcompat:1.4.2"
implementation "androidx.fragment:fragment-ktx:1.5.0"
implementation "androidx.annotation:annotation:1.4.0"
From f1c217b087e46faef8279ab9b0bd47d415c0745a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 12 Jul 2022 10:20:28 +0000
Subject: [PATCH 041/164] Bump kotlin_version from 1.7.0 to 1.7.10 (#1918)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index b96c8582e..71eb2def3 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,6 @@
buildscript {
ext {
- kotlin_version = '1.7.0'
+ kotlin_version = '1.7.10'
about_libraries = '10.3.1'
hilt_version = "2.42"
}
From bdb6c962ea2ac017b3a46c7d7f743b24a6fb7545 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 12 Jul 2022 10:20:42 +0000
Subject: [PATCH 042/164] Bump hianalytics from 6.5.0.300 to 6.6.0.300 (#1919)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 91c458761..588f8dccc 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -247,7 +247,7 @@ dependencies {
playImplementation 'com.google.android.play:core-ktx:1.8.1'
playImplementation 'com.google.android.gms:play-services-ads:21.0.0'
- hmsImplementation 'com.huawei.hms:hianalytics:6.5.0.300'
+ hmsImplementation 'com.huawei.hms:hianalytics:6.6.0.300'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.0.300'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
From 7c4f1c7b22a8a67df9c5575ab74b7651555e4b59 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Tue, 12 Jul 2022 12:23:55 +0200
Subject: [PATCH 043/164] Add auto refresh to reporting units (#1916)
---
.../repositories/ReportingUnitRepository.kt | 27 +++++++++++++------
1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/ReportingUnitRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/ReportingUnitRepository.kt
index b9caf978b..84055cef0 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/ReportingUnitRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/ReportingUnitRepository.kt
@@ -5,6 +5,8 @@ import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
+import io.github.wulkanowy.utils.AutoRefreshHelper
+import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.uniqueSubtract
import javax.inject.Inject
@@ -13,30 +15,39 @@ import javax.inject.Singleton
@Singleton
class ReportingUnitRepository @Inject constructor(
private val reportingUnitDb: ReportingUnitDao,
- private val sdk: Sdk
+ private val sdk: Sdk,
+ private val refreshHelper: AutoRefreshHelper,
) {
+ private val cacheKey = "reporting_unit"
+
suspend fun refreshReportingUnits(student: Student) {
val new = sdk.init(student).getReportingUnits().mapToEntities(student)
val old = reportingUnitDb.load(student.id.toInt())
reportingUnitDb.deleteAll(old.uniqueSubtract(new))
reportingUnitDb.insertAll(new.uniqueSubtract(old))
+
+ refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
}
suspend fun getReportingUnits(student: Student): List {
- return reportingUnitDb.load(student.id.toInt()).ifEmpty {
- refreshReportingUnits(student)
+ val cached = reportingUnitDb.load(student.id.toInt())
+ val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
+ return if (cached.isEmpty() || isExpired) {
+ refreshReportingUnits(student)
reportingUnitDb.load(student.id.toInt())
- }
+ } else cached
}
suspend fun getReportingUnit(student: Student, unitId: Int): ReportingUnit? {
- return reportingUnitDb.loadOne(student.id.toInt(), unitId) ?: run {
- refreshReportingUnits(student)
+ val cached = reportingUnitDb.loadOne(student.id.toInt(), unitId)
+ val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
- return reportingUnitDb.loadOne(student.id.toInt(), unitId)
- }
+ return if (cached == null || isExpired) {
+ refreshReportingUnits(student)
+ reportingUnitDb.loadOne(student.id.toInt(), unitId)
+ } else cached
}
}
From fd18583df2ce86969eeab953754c7f7680448d01 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 21 Jul 2022 21:28:20 +0000
Subject: [PATCH 044/164] Bump play-services-ads from 21.0.0 to 21.1.0 (#1922)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 588f8dccc..b51c87f10 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -245,7 +245,7 @@ dependencies {
playImplementation 'com.google.firebase:firebase-crashlytics:'
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:21.0.0'
+ playImplementation 'com.google.android.gms:play-services-ads:21.1.0'
hmsImplementation 'com.huawei.hms:hianalytics:6.6.0.300'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.0.300'
From 08c9539abee8d52ecd3b16738056333ba1aee665 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 21 Jul 2022 21:28:37 +0000
Subject: [PATCH 045/164] Bump coroutines from 1.6.3 to 1.6.4 (#1921)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index b51c87f10..0a848a44c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -180,7 +180,7 @@ ext {
room = "2.4.2"
chucker = "3.5.2"
mockk = "1.12.4"
- coroutines = "1.6.3"
+ coroutines = "1.6.4"
}
dependencies {
From dfc4553fc61540aae4bf84f28b4474f1469ab3c1 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 21 Jul 2022 21:28:53 +0000
Subject: [PATCH 046/164] Bump firebase-bom from 30.2.0 to 30.3.0 (#1920)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 0a848a44c..d5df65793 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -239,7 +239,7 @@ dependencies {
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.7.0'
- playImplementation platform('com.google.firebase:firebase-bom:30.2.0')
+ playImplementation platform('com.google.firebase:firebase-bom:30.3.0')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
From b9be85d99cc11c526431931bf927c52e9a1d446b Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 27 Jul 2022 10:09:28 +0000
Subject: [PATCH 047/164] Bump hilt_version from 2.42 to 2.43 (#1923)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 71eb2def3..bb9afab3b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,7 +2,7 @@ buildscript {
ext {
kotlin_version = '1.7.10'
about_libraries = '10.3.1'
- hilt_version = "2.42"
+ hilt_version = "2.43"
}
repositories {
mavenCentral()
From efa68f50447f3eb66240cebafb5d156a4e57d780 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 1 Aug 2022 21:16:46 +0000
Subject: [PATCH 048/164] Bump mockk from 1.12.4 to 1.12.5 (#1933)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index d5df65793..2f284d0a3 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -179,7 +179,7 @@ ext {
android_hilt = "1.0.0"
room = "2.4.2"
chucker = "3.5.2"
- mockk = "1.12.4"
+ mockk = "1.12.5"
coroutines = "1.6.4"
}
From cf7c6f78eaa7e4f6227b173d30b3bac6b4808539 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 1 Aug 2022 21:17:00 +0000
Subject: [PATCH 049/164] Bump lifecycle-livedata-ktx from 2.5.0 to 2.5.1
(#1932)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 2f284d0a3..2f4f7021c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -212,7 +212,7 @@ dependencies {
implementation "androidx.work:work-runtime-ktx:$work_manager"
playImplementation "androidx.work:work-gcm:$work_manager"
- implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.0"
+ implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
implementation "androidx.room:room-runtime:$room"
implementation "androidx.room:room-ktx:$room"
From d337be0f40c3e1becf59178ff813ff295eef7842 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 1 Aug 2022 21:17:20 +0000
Subject: [PATCH 050/164] Bump firebase-bom from 30.3.0 to 30.3.1 (#1931)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 2f4f7021c..80e3dab46 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -239,7 +239,7 @@ dependencies {
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.7.0'
- playImplementation platform('com.google.firebase:firebase-bom:30.3.0')
+ playImplementation platform('com.google.firebase:firebase-bom:30.3.1')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
From c23a90f1043fc19aa0b71095bb71d9625e4e2c63 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 1 Aug 2022 21:17:35 +0000
Subject: [PATCH 051/164] Bump fragment-ktx from 1.5.0 to 1.5.1 (#1930)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 80e3dab46..ac8df81b2 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -195,7 +195,7 @@ dependencies {
implementation 'androidx.core:core-splashscreen:1.0.0-rc01'
implementation "androidx.activity:activity-ktx:1.5.0"
implementation "androidx.appcompat:appcompat:1.4.2"
- implementation "androidx.fragment:fragment-ktx:1.5.0"
+ implementation "androidx.fragment:fragment-ktx:1.5.1"
implementation "androidx.annotation:annotation:1.4.0"
implementation "androidx.preference:preference-ktx:1.2.0"
From cf87339ac40aca6121a863829933cff8f6af935c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 1 Aug 2022 21:18:52 +0000
Subject: [PATCH 052/164] Bump hilt_version from 2.43 to 2.43.1 (#1927)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index bb9afab3b..c88cd35fc 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,7 +2,7 @@ buildscript {
ext {
kotlin_version = '1.7.10'
about_libraries = '10.3.1'
- hilt_version = "2.43"
+ hilt_version = "2.43.1"
}
repositories {
mavenCentral()
From 378ed0100f7847ee7a25b9479cb9f188a17a080e Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 1 Aug 2022 21:26:15 +0000
Subject: [PATCH 053/164] Bump huawei-publish-gradle-plugin from 1.3.3 to 1.3.4
(#1934)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index c88cd35fc..c4dc9c279 100644
--- a/build.gradle
+++ b/build.gradle
@@ -19,7 +19,7 @@ buildscript {
classpath 'com.huawei.agconnect:agcp:1.7.0.300'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.1'
classpath "com.github.triplet.gradle:play-publisher:3.6.0"
- classpath "ru.cian:huawei-publish-gradle-plugin:1.3.3"
+ classpath "ru.cian:huawei-publish-gradle-plugin:1.3.4"
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513"
classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0"
classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$about_libraries"
From 1175740ba22860f27075e12f2c56f4cf6710bc7f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 1 Aug 2022 21:26:34 +0000
Subject: [PATCH 054/164] Bump activity-ktx from 1.5.0 to 1.5.1 (#1926)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index ac8df81b2..4eaa79f16 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -193,7 +193,7 @@ dependencies {
implementation "androidx.core:core-ktx:1.8.0"
implementation 'androidx.core:core-splashscreen:1.0.0-rc01'
- implementation "androidx.activity:activity-ktx:1.5.0"
+ implementation "androidx.activity:activity-ktx:1.5.1"
implementation "androidx.appcompat:appcompat:1.4.2"
implementation "androidx.fragment:fragment-ktx:1.5.1"
implementation "androidx.annotation:annotation:1.4.0"
From b67ecbba4b74bb1336910fe20f0b8ad2754b787f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 1 Aug 2022 21:26:37 +0000
Subject: [PATCH 055/164] Bump room from 2.4.2 to 2.4.3 (#1928)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 4eaa79f16..28aa85848 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -177,7 +177,7 @@ huaweiPublish {
ext {
work_manager = "2.7.1"
android_hilt = "1.0.0"
- room = "2.4.2"
+ room = "2.4.3"
chucker = "3.5.2"
mockk = "1.12.5"
coroutines = "1.6.4"
From dc3a941e24d6cf920a9c52b1a9980e2f76e7230d Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 1 Aug 2022 21:36:28 +0000
Subject: [PATCH 056/164] Bump core-splashscreen from 1.0.0-rc01 to 1.0.0
(#1929)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 28aa85848..542dda109 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -192,7 +192,7 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
implementation "androidx.core:core-ktx:1.8.0"
- implementation 'androidx.core:core-splashscreen:1.0.0-rc01'
+ implementation 'androidx.core:core-splashscreen:1.0.0'
implementation "androidx.activity:activity-ktx:1.5.1"
implementation "androidx.appcompat:appcompat:1.4.2"
implementation "androidx.fragment:fragment-ktx:1.5.1"
From b4117aa62eb66497fc43a5ad7574fefc0207229e Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 3 Aug 2022 10:56:41 +0000
Subject: [PATCH 057/164] Bump flow-preferences from 1.7.0 to 1.8.0 (#1925)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 542dda109..a4549f08a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -237,7 +237,7 @@ dependencies {
implementation "io.coil-kt:coil:2.1.0"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
- implementation 'com.fredporciuncula:flow-preferences:1.7.0'
+ implementation 'com.fredporciuncula:flow-preferences:1.8.0'
playImplementation platform('com.google.firebase:firebase-bom:30.3.1')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
From 9339e7d9168a695656fb88c5678f008dfee2308e Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 10 Aug 2022 09:27:24 +0000
Subject: [PATCH 058/164] Bump gradle from 7.2.1 to 7.2.2 (#1942)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index c4dc9c279..35665b252 100644
--- a/build.gradle
+++ b/build.gradle
@@ -13,7 +13,7 @@ buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
- classpath 'com.android.tools.build:gradle:7.2.1'
+ classpath 'com.android.tools.build:gradle:7.2.2'
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.google.gms:google-services:4.3.13'
classpath 'com.huawei.agconnect:agcp:1.7.0.300'
From 96067946d034845495ae7ed074ad9a495cb1c494 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 10 Aug 2022 09:27:46 +0000
Subject: [PATCH 059/164] Bump firebase-bom from 30.3.1 to 30.3.2 (#1940)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index a4549f08a..f8cb8440c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -239,7 +239,7 @@ dependencies {
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
- playImplementation platform('com.google.firebase:firebase-bom:30.3.1')
+ playImplementation platform('com.google.firebase:firebase-bom:30.3.2')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
From ffc0cd840b37b38630ab2b5ca360b5805421ac0e Mon Sep 17 00:00:00 2001
From: Patryk <43276401+Zaptyp@users.noreply.github.com>
Date: Wed, 10 Aug 2022 11:28:22 +0200
Subject: [PATCH 060/164] Update workflow dependency (#1937)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Mikołaj Pich
---
.github/workflows/deploy-store.yml | 20 +++++----
.github/workflows/deploy-test.yml | 20 +++++----
.github/workflows/test.yml | 66 +++++++++++++++++++++++++++---
app/build.gradle | 16 ++++----
build.gradle | 2 +-
5 files changed, 92 insertions(+), 32 deletions(-)
diff --git a/.github/workflows/deploy-store.yml b/.github/workflows/deploy-store.yml
index 12338feff..cfb0fb523 100644
--- a/.github/workflows/deploy-store.yml
+++ b/.github/workflows/deploy-store.yml
@@ -1,4 +1,4 @@
-name: Deploy to app stores
+name: Deploy release
on:
release:
@@ -7,16 +7,17 @@ on:
jobs:
deploy-google-play:
- name: Deploy to google play
+ name: Google Play
runs-on: ubuntu-latest
timeout-minutes: 10
environment: google-play
steps:
- - uses: actions/checkout@v2
- - uses: actions/setup-java@v1
+ - uses: actions/checkout@v3
+ - uses: actions/setup-java@v2
with:
+ distribution: 'zulu'
java-version: 11
- - uses: actions/cache@v2
+ - uses: actions/cache@v3
with:
path: |
~/.gradle/caches
@@ -41,16 +42,17 @@ jobs:
run: ./gradlew publishPlayReleaseApps -PenableFirebase --stacktrace;
deploy-app-gallery:
- name: Deploy to AppGallery
+ name: AppGallery
runs-on: ubuntu-latest
timeout-minutes: 10
environment: app-gallery
steps:
- - uses: actions/checkout@v2
- - uses: actions/setup-java@v1
+ - uses: actions/checkout@v3
+ - uses: actions/setup-java@v2
with:
+ distribution: 'zulu'
java-version: 11
- - uses: actions/cache@v2
+ - uses: actions/cache@v3
with:
path: |
~/.gradle/caches
diff --git a/.github/workflows/deploy-test.yml b/.github/workflows/deploy-test.yml
index 88edca05d..20082590d 100644
--- a/.github/workflows/deploy-test.yml
+++ b/.github/workflows/deploy-test.yml
@@ -1,4 +1,4 @@
-name: Deploy to app tests
+name: Deploy DEV
on:
push:
@@ -18,11 +18,12 @@ jobs:
timeout-minutes: 10
environment: app-center
steps:
- - uses: actions/checkout@v2
- - uses: actions/setup-java@v1
+ - uses: actions/checkout@v3
+ - uses: actions/setup-java@v2
with:
+ distribution: 'zulu'
java-version: 11
- - uses: actions/cache@v2
+ - uses: actions/cache@v3
with:
path: |
~/.gradle/caches
@@ -66,7 +67,7 @@ jobs:
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
run: ./gradlew assembleFdroidDebug --stacktrace
- name: Upload apk to github artifacts
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: wulkanowyDEV-${{ env.RUN_NUMBER }}.apk
path: app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk
@@ -87,11 +88,12 @@ jobs:
environment: app-distribution
if: github.event_name != 'pull_request_target'
steps:
- - uses: actions/checkout@v2
- - uses: actions/setup-java@v1
+ - uses: actions/checkout@v3
+ - uses: actions/setup-java@v2
with:
+ distribution: 'zulu'
java-version: 11
- - uses: actions/cache@v2
+ - uses: actions/cache@v3
with:
path: |
~/.gradle/caches
@@ -131,7 +133,7 @@ jobs:
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
run: ./gradlew assemblePlayDebug -PenableFirebase --stacktrace
- name: Upload apk to github artifacts
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: wulkanowyDEV-${{ env.RUN_NUMBER }}-dev.apk
path: app/build/outputs/apk/play/debug/app-play-debug.apk
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index ee16041f6..3def08953 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -8,18 +8,20 @@ on:
branches: [ master, develop ]
jobs:
- unit-tests:
- name: Unit tests
+
+ tests-fdroid:
+ name: F-Droid
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: fkirc/skip-duplicate-actions@master
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: gradle/wrapper-validation-action@v1
- - uses: actions/setup-java@v1
+ - uses: actions/setup-java@v2
with:
+ distribution: 'zulu'
java-version: 11
- - uses: actions/cache@v2
+ - uses: actions/cache@v3
with:
path: |
~/.gradle/caches
@@ -29,6 +31,58 @@ jobs:
run: |
./gradlew testFdroidDebugUnitTest --stacktrace
./gradlew jacocoTestReport --stacktrace
- - uses: codecov/codecov-action@v1
+ - uses: codecov/codecov-action@v3
+ with:
+ flags: unit
+
+ tests-play:
+ name: Play
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - uses: fkirc/skip-duplicate-actions@master
+ - uses: actions/checkout@v3
+ - uses: gradle/wrapper-validation-action@v1
+ - uses: actions/setup-java@v2
+ with:
+ distribution: 'zulu'
+ java-version: 11
+ - uses: actions/cache@v3
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
+ - name: Unit tests
+ run: |
+ ./gradlew testPlayDebugUnitTest --stacktrace
+ ./gradlew jacocoTestReport --stacktrace
+ - uses: codecov/codecov-action@v3
+ with:
+ flags: unit
+
+ tests-hms:
+ name: HMS
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - uses: fkirc/skip-duplicate-actions@master
+ - uses: actions/checkout@v3
+ - uses: gradle/wrapper-validation-action@v1
+ - uses: actions/setup-java@v2
+ with:
+ distribution: 'zulu'
+ java-version: 11
+ - uses: actions/cache@v3
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
+ - name: Unit tests
+ run: |
+ ./gradlew testHmsDebugUnitTest --stacktrace
+ ./gradlew jacocoTestReport --stacktrace
+ - uses: codecov/codecov-action@v3
with:
flags: unit
diff --git a/app/build.gradle b/app/build.gradle
index f8cb8440c..78eebff8f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -30,14 +30,14 @@ android {
resValue "string", "app_name", "Wulkanowy"
manifestPlaceholders = [
- firebase_enabled: project.hasProperty("enableFirebase"),
- admob_project_id: ""
+ firebase_enabled: project.hasProperty("enableFirebase"),
+ admob_project_id: ""
]
javaCompileOptions {
annotationProcessorOptions {
arguments += [
- "room.schemaLocation": "$projectDir/schemas".toString(),
- "room.incremental" : "true"
+ "room.schemaLocation": "$projectDir/schemas".toString(),
+ "room.incremental" : "true"
]
}
}
@@ -96,8 +96,8 @@ android {
play {
dimension "platform"
manifestPlaceholders = [
- install_channel : "Google Play",
- admob_project_id: System.getenv("ADMOB_PROJECT_ID") ?: "ca-app-pub-3940256099942544~3347511713"
+ install_channel : "Google Play",
+ admob_project_id: System.getenv("ADMOB_PROJECT_ID") ?: "ca-app-pub-3940256099942544~3347511713"
]
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "\"${System.getenv("SINGLE_SUPPORT_AD_ID") ?: "ca-app-pub-3940256099942544/5354046379"}\""
buildConfigField "String", "DASHBOARD_TILE_AD_ID", "\"${System.getenv("DASHBOARD_TILE_AD_ID") ?: "ca-app-pub-3940256099942544/6300978111"}\""
@@ -126,6 +126,8 @@ android {
testOptions.unitTests {
includeAndroidResources = true
+ // workaround HMS test errors https://github.com/robolectric/robolectric/issues/2750
+ all { jvmArgs '-noverify' }
}
compileOptions {
@@ -184,7 +186,7 @@ ext {
}
dependencies {
- implementation "io.github.wulkanowy:sdk:16811fbe90"
+ implementation "io.github.wulkanowy:sdk:9032e33686"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
diff --git a/build.gradle b/build.gradle
index 35665b252..84ed29b95 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,7 +2,7 @@ buildscript {
ext {
kotlin_version = '1.7.10'
about_libraries = '10.3.1'
- hilt_version = "2.43.1"
+ hilt_version = "2.43.2"
}
repositories {
mavenCentral()
From c55fd9817991081e24ee9cf1a49fc28eb406c001 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 10 Aug 2022 09:37:53 +0000
Subject: [PATCH 061/164] Bump about_libraries from 10.3.1 to 10.4.0 (#1941)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 84ed29b95..bc4ca5199 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,7 @@
buildscript {
ext {
kotlin_version = '1.7.10'
- about_libraries = '10.3.1'
+ about_libraries = '10.4.0'
hilt_version = "2.43.2"
}
repositories {
From 5a884a4c56117a04fd21916c2c59c28f70d3439a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 10 Aug 2022 09:38:15 +0000
Subject: [PATCH 062/164] Bump agcp from 1.7.0.300 to 1.7.1.300 (#1938)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index bc4ca5199..98c9dfb84 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,7 +16,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:7.2.2'
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.google.gms:google-services:4.3.13'
- classpath 'com.huawei.agconnect:agcp:1.7.0.300'
+ classpath 'com.huawei.agconnect:agcp:1.7.1.300'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.1'
classpath "com.github.triplet.gradle:play-publisher:3.6.0"
classpath "ru.cian:huawei-publish-gradle-plugin:1.3.4"
From 274f9dde07249c79277cc6d5cde1452dfb40fc4f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 10 Aug 2022 09:48:02 +0000
Subject: [PATCH 063/164] Bump agconnect-crash from 1.7.0.300 to 1.7.1.300
(#1943)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 78eebff8f..52b2aad33 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -250,7 +250,7 @@ dependencies {
playImplementation 'com.google.android.gms:play-services-ads:21.1.0'
hmsImplementation 'com.huawei.hms:hianalytics:6.6.0.300'
- hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.0.300'
+ hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.1.300'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
From d64a21b50c2ddee1cce67a5cd02483504df1e1a7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 10 Aug 2022 09:56:20 +0000
Subject: [PATCH 064/164] Bump hianalytics from 6.6.0.300 to 6.7.0.300 (#1944)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 52b2aad33..1f68b65cc 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -249,7 +249,7 @@ dependencies {
playImplementation 'com.google.android.play:core-ktx:1.8.1'
playImplementation 'com.google.android.gms:play-services-ads:21.1.0'
- hmsImplementation 'com.huawei.hms:hianalytics:6.6.0.300'
+ hmsImplementation 'com.huawei.hms:hianalytics:6.7.0.300'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.1.300'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
From 793952cb4479d0838d8dedff5467bf99d60d3ce1 Mon Sep 17 00:00:00 2001
From: Patryk <43276401+Zaptyp@users.noreply.github.com>
Date: Sun, 14 Aug 2022 22:16:47 +0200
Subject: [PATCH 065/164] Fix typo in README DE.md (#1936)
* Update README.de.md
* Change in README-DE.md file
---
README.de.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.de.md b/README.de.md
index 3f806e9fd..b9e1d1ec1 100644
--- a/README.de.md
+++ b/README.de.md
@@ -51,7 +51,7 @@ Die aktuelle Version können Sie von der Google Play, F-Droid oder Huawei AppGal
alt="Explore it on AppGallery"
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
-Sie können auch ein [Entwicklungsversion herunterladen](https://wulkanowy.github.io/#download) das beinhaltet neue Funktionen, die für die nächste Version vorbereitet werden
+Sie können auch eine [Entwicklungsversion herunterladen](https://wulkanowy.github.io/#download) die beinhaltet neue Funktionen, die für die nächste Version vorbereitet werden
## Gebaut mit
From 9fe1151a043ba337816269fc0e485d2c356a7d34 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 19 Aug 2022 22:22:47 +0000
Subject: [PATCH 066/164] Bump fragment-ktx from 1.5.1 to 1.5.2 (#1947)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 1f68b65cc..eace462db 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -197,7 +197,7 @@ dependencies {
implementation 'androidx.core:core-splashscreen:1.0.0'
implementation "androidx.activity:activity-ktx:1.5.1"
implementation "androidx.appcompat:appcompat:1.4.2"
- implementation "androidx.fragment:fragment-ktx:1.5.1"
+ implementation "androidx.fragment:fragment-ktx:1.5.2"
implementation "androidx.annotation:annotation:1.4.0"
implementation "androidx.preference:preference-ktx:1.2.0"
From 08a3bd77bde75f066099f276d887b9d44615a7f7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 22 Aug 2022 07:00:10 +0000
Subject: [PATCH 067/164] Bump appcompat from 1.4.2 to 1.5.0 (#1946)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index eace462db..6d33ac476 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -196,7 +196,7 @@ dependencies {
implementation "androidx.core:core-ktx:1.8.0"
implementation 'androidx.core:core-splashscreen:1.0.0'
implementation "androidx.activity:activity-ktx:1.5.1"
- implementation "androidx.appcompat:appcompat:1.4.2"
+ implementation "androidx.appcompat:appcompat:1.5.0"
implementation "androidx.fragment:fragment-ktx:1.5.2"
implementation "androidx.annotation:annotation:1.4.0"
From 9d47127921d5a1d8bff07bb708e284f00ef10bd1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Mon, 22 Aug 2022 14:30:50 +0200
Subject: [PATCH 068/164] Add support for messages plus API (#1945)
---
app/build.gradle | 2 +-
.../51.json | 2409 +++++++++++++++++
.../io/github/wulkanowy/data/DataModule.kt | 4 +-
.../github/wulkanowy/data/db/AppDatabase.kt | 9 +-
.../wulkanowy/data/db/dao/MailboxDao.kt | 17 +
.../wulkanowy/data/db/dao/MessagesDao.kt | 8 +-
.../wulkanowy/data/db/dao/RecipientDao.kt | 5 +-
.../wulkanowy/data/db/dao/ReportingUnitDao.kt | 17 -
.../wulkanowy/data/db/entities/Mailbox.kt | 25 +
.../wulkanowy/data/db/entities/Message.kt | 27 +-
.../data/db/entities/MessageAttachment.kt | 7 +-
.../data/db/entities/MessageWithAttachment.kt | 2 +-
.../wulkanowy/data/db/entities/Recipient.kt | 31 +-
.../data/db/entities/ReportingUnit.kt | 32 -
.../data/db/migrations/Migration51.kt | 88 +
.../wulkanowy/data/mappers/MailboxMapper.kt | 18 +
.../wulkanowy/data/mappers/MessageMapper.kt | 46 +-
.../wulkanowy/data/mappers/RecipientMapper.kt | 17 +-
.../data/mappers/ReportingUnitMapper.kt | 16 -
.../data/repositories/MailboxRepository.kt | 48 +
.../data/repositories/MessageRepository.kt | 114 +-
.../data/repositories/RecipientRepository.kt | 37 +-
.../repositories/ReportingUnitRepository.kt | 53 -
.../notifications/NewMessageNotification.kt | 2 +-
.../services/sync/works/MessageWork.kt | 7 +-
.../services/sync/works/RecipientWork.kt | 15 +-
.../modules/dashboard/DashboardPresenter.kt | 4 +-
.../debug/notification/mock/message.kt | 13 +-
.../message/preview/MessagePreviewAdapter.kt | 26 +-
.../message/preview/MessagePreviewFragment.kt | 4 +-
.../preview/MessagePreviewPresenter.kt | 114 +-
.../message/preview/MessagePreviewView.kt | 2 +-
.../message/send/SendMessageActivity.kt | 31 +-
.../message/send/SendMessagePresenter.kt | 128 +-
.../modules/message/send/SendMessageView.kt | 12 +-
.../modules/message/tab/MessageTabAdapter.kt | 11 +-
.../message/tab/MessageTabPresenter.kt | 22 +-
.../main/res/layout/activity_send_message.xml | 3 +-
app/src/main/res/values/strings.xml | 5 +-
.../io/github/wulkanowy/TestEnityCreator.kt | 12 +
.../repositories/MessageRepositoryTest.kt | 116 +-
.../data/repositories/RecipientLocalTest.kt | 81 +-
42 files changed, 3065 insertions(+), 575 deletions(-)
create mode 100644 app/schemas/io.github.wulkanowy.data.db.AppDatabase/51.json
create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/dao/MailboxDao.kt
delete mode 100644 app/src/main/java/io/github/wulkanowy/data/db/dao/ReportingUnitDao.kt
create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/entities/Mailbox.kt
delete mode 100644 app/src/main/java/io/github/wulkanowy/data/db/entities/ReportingUnit.kt
create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration51.kt
create mode 100644 app/src/main/java/io/github/wulkanowy/data/mappers/MailboxMapper.kt
delete mode 100644 app/src/main/java/io/github/wulkanowy/data/mappers/ReportingUnitMapper.kt
create mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt
delete mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/ReportingUnitRepository.kt
diff --git a/app/build.gradle b/app/build.gradle
index 6d33ac476..0efb9c303 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -186,7 +186,7 @@ ext {
}
dependencies {
- implementation "io.github.wulkanowy:sdk:9032e33686"
+ implementation "io.github.wulkanowy:sdk:dbe87aac"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/51.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/51.json
new file mode 100644
index 000000000..271b8c90b
--- /dev/null
+++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/51.json
@@ -0,0 +1,2409 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 51,
+ "identityHash": "51f9cb1d80df003c03bb655c0162487c",
+ "entities": [
+ {
+ "tableName": "Students",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`scrapper_base_url` TEXT NOT NULL, `mobile_base_url` TEXT NOT NULL, `login_type` TEXT NOT NULL, `login_mode` TEXT NOT NULL, `certificate_key` TEXT NOT NULL, `private_key` TEXT NOT NULL, `is_parent` INTEGER NOT NULL, `email` TEXT NOT NULL, `password` TEXT NOT NULL, `symbol` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `user_login_id` INTEGER NOT NULL, `user_name` TEXT NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_short` TEXT NOT NULL, `school_name` TEXT NOT NULL, `class_name` TEXT NOT NULL, `class_id` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `registration_date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `nick` TEXT NOT NULL, `avatar_color` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "scrapperBaseUrl",
+ "columnName": "scrapper_base_url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mobileBaseUrl",
+ "columnName": "mobile_base_url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginType",
+ "columnName": "login_type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginMode",
+ "columnName": "login_mode",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "certificateKey",
+ "columnName": "certificate_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "privateKey",
+ "columnName": "private_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isParent",
+ "columnName": "is_parent",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "password",
+ "columnName": "password",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "symbol",
+ "columnName": "symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "user_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentName",
+ "columnName": "student_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolSymbol",
+ "columnName": "school_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolShortName",
+ "columnName": "school_short",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolName",
+ "columnName": "school_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "className",
+ "columnName": "class_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isCurrent",
+ "columnName": "is_current",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registrationDate",
+ "columnName": "registration_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "nick",
+ "columnName": "nick",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "avatarColor",
+ "columnName": "avatar_color",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_Students_email_symbol_student_id_school_id_class_id",
+ "unique": true,
+ "columnNames": [
+ "email",
+ "symbol",
+ "student_id",
+ "school_id",
+ "class_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Students_email_symbol_student_id_school_id_class_id` ON `${TABLE_NAME}` (`email`, `symbol`, `student_id`, `school_id`, `class_id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Semesters",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `kindergarten_diary_id` INTEGER NOT NULL DEFAULT 0, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "kindergartenDiaryId",
+ "columnName": "kindergarten_diary_id",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ },
+ {
+ "fieldPath": "diaryName",
+ "columnName": "diary_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolYear",
+ "columnName": "school_year",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterName",
+ "columnName": "semester_name",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unitId",
+ "columnName": "unit_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "current",
+ "columnName": "is_current",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id",
+ "unique": true,
+ "columnNames": [
+ "student_id",
+ "diary_id",
+ "kindergarten_diary_id",
+ "semester_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id` ON `${TABLE_NAME}` (`student_id`, `diary_id`, `kindergarten_diary_id`, `semester_id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Exams",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `group` TEXT NOT NULL, `type` TEXT NOT NULL, `description` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entryDate",
+ "columnName": "entry_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "group",
+ "columnName": "group",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Timetable",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `number` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `subjectOld` TEXT NOT NULL, `group` TEXT NOT NULL, `room` TEXT NOT NULL, `roomOld` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacherOld` TEXT NOT NULL, `info` TEXT NOT NULL, `student_plan` INTEGER NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectOld",
+ "columnName": "subjectOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "group",
+ "columnName": "group",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "room",
+ "columnName": "room",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "roomOld",
+ "columnName": "roomOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherOld",
+ "columnName": "teacherOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "info",
+ "columnName": "info",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isStudentPlan",
+ "columnName": "student_plan",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "changes",
+ "columnName": "changes",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "canceled",
+ "columnName": "canceled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Attendance",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `time_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `excused` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `excusable` INTEGER NOT NULL, `excuse_status` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "timeId",
+ "columnName": "time_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presence",
+ "columnName": "presence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "exemption",
+ "columnName": "exemption",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lateness",
+ "columnName": "lateness",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excused",
+ "columnName": "excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deleted",
+ "columnName": "deleted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excusable",
+ "columnName": "excusable",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excuseStatus",
+ "columnName": "excuse_status",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AttendanceSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `subject_id` INTEGER NOT NULL, `month` INTEGER NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `absence_excused` INTEGER NOT NULL, `absence_for_school_reasons` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `lateness_excused` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subject_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "month",
+ "columnName": "month",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presence",
+ "columnName": "presence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absenceExcused",
+ "columnName": "absence_excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absenceForSchoolReasons",
+ "columnName": "absence_for_school_reasons",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lateness",
+ "columnName": "lateness",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "latenessExcused",
+ "columnName": "lateness_excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "exemption",
+ "columnName": "exemption",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Grades",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `entry` TEXT NOT NULL, `value` REAL NOT NULL, `modifier` REAL NOT NULL, `comment` TEXT NOT NULL, `color` TEXT NOT NULL, `grade_symbol` TEXT NOT NULL, `description` TEXT NOT NULL, `weight` TEXT NOT NULL, `weightValue` REAL NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entry",
+ "columnName": "entry",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "modifier",
+ "columnName": "modifier",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "color",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gradeSymbol",
+ "columnName": "grade_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weightValue",
+ "columnName": "weightValue",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isRead",
+ "columnName": "is_read",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `position` INTEGER NOT NULL, `subject` TEXT NOT NULL, `predicted_grade` TEXT NOT NULL, `final_grade` TEXT NOT NULL, `proposed_points` TEXT NOT NULL, `final_points` TEXT NOT NULL, `points_sum` TEXT NOT NULL, `average` REAL NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_predicted_grade_notified` INTEGER NOT NULL, `is_final_grade_notified` INTEGER NOT NULL, `predicted_grade_last_change` INTEGER NOT NULL, `final_grade_last_change` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "position",
+ "columnName": "position",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "predictedGrade",
+ "columnName": "predicted_grade",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalGrade",
+ "columnName": "final_grade",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "proposedPoints",
+ "columnName": "proposed_points",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalPoints",
+ "columnName": "final_points",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pointsSum",
+ "columnName": "points_sum",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "average",
+ "columnName": "average",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPredictedGradeNotified",
+ "columnName": "is_predicted_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFinalGradeNotified",
+ "columnName": "is_final_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "predictedGradeLastChange",
+ "columnName": "predicted_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalGradeLastChange",
+ "columnName": "final_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradePartialStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `class_average` TEXT NOT NULL, `student_average` TEXT NOT NULL, `class_amounts` TEXT NOT NULL, `student_amounts` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classAverage",
+ "columnName": "class_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAverage",
+ "columnName": "student_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classAmounts",
+ "columnName": "class_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAmounts",
+ "columnName": "student_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesPointsStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `others` REAL NOT NULL, `student` REAL NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "others",
+ "columnName": "others",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "student",
+ "columnName": "student",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradeSemesterStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `amounts` TEXT NOT NULL, `student_grade` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "amounts",
+ "columnName": "amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentGrade",
+ "columnName": "student_grade",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Messages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`message_global_key` TEXT NOT NULL, `mailbox_key` TEXT NOT NULL, `message_id` INTEGER NOT NULL, `correspondents` TEXT NOT NULL, `subject` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `has_attachments` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `content` TEXT NOT NULL, `sender` TEXT, `recipients` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "messageGlobalKey",
+ "columnName": "message_global_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mailboxKey",
+ "columnName": "mailbox_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageId",
+ "columnName": "message_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "correspondents",
+ "columnName": "correspondents",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unread",
+ "columnName": "unread",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasAttachments",
+ "columnName": "has_attachments",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "sender",
+ "columnName": "sender",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "recipients",
+ "columnName": "recipients",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MessageAttachments",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`real_id` INTEGER NOT NULL, `message_global_key` TEXT NOT NULL, `url` TEXT NOT NULL, `filename` TEXT NOT NULL, PRIMARY KEY(`real_id`))",
+ "fields": [
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageGlobalKey",
+ "columnName": "message_global_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filename",
+ "columnName": "filename",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "real_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `category` TEXT NOT NULL, `category_type` INTEGER NOT NULL, `is_points_show` INTEGER NOT NULL, `points` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "categoryType",
+ "columnName": "category_type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPointsShow",
+ "columnName": "is_points_show",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "points",
+ "columnName": "points",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isRead",
+ "columnName": "is_read",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Homework",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `attachments` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_done` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `is_added_by_user` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entryDate",
+ "columnName": "entry_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "attachments",
+ "columnName": "attachments",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDone",
+ "columnName": "is_done",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Subjects",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "LuckyNumbers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "luckyNumber",
+ "columnName": "lucky_number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "CompletedLesson",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `topic` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `substitution` TEXT NOT NULL, `absence` TEXT NOT NULL, `resources` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "topic",
+ "columnName": "topic",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "substitution",
+ "columnName": "substitution",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "resources",
+ "columnName": "resources",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Mailboxes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`globalKey` TEXT NOT NULL, `fullName` TEXT NOT NULL, `userName` TEXT NOT NULL, `userLoginId` INTEGER NOT NULL, `studentName` TEXT NOT NULL, `schoolNameShort` TEXT NOT NULL, `type` TEXT NOT NULL, PRIMARY KEY(`globalKey`))",
+ "fields": [
+ {
+ "fieldPath": "globalKey",
+ "columnName": "globalKey",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "fullName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "userLoginId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentName",
+ "columnName": "studentName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolNameShort",
+ "columnName": "schoolNameShort",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "globalKey"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Recipients",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`mailboxGlobalKey` TEXT NOT NULL, `studentMailboxGlobalKey` TEXT NOT NULL, `fullName` TEXT NOT NULL, `userName` TEXT NOT NULL, `schoolShortName` TEXT NOT NULL, `type` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "mailboxGlobalKey",
+ "columnName": "mailboxGlobalKey",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentMailboxGlobalKey",
+ "columnName": "studentMailboxGlobalKey",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "fullName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolShortName",
+ "columnName": "schoolShortName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MobileDevices",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_login_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deviceId",
+ "columnName": "device_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Teachers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "shortName",
+ "columnName": "short_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "School",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT NOT NULL, `contact` TEXT NOT NULL, `headmaster` TEXT NOT NULL, `pedagogue` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "contact",
+ "columnName": "contact",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "headmaster",
+ "columnName": "headmaster",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pedagogue",
+ "columnName": "pedagogue",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Conferences",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `subject` TEXT NOT NULL, `agenda` TEXT NOT NULL, `present_on_conference` TEXT NOT NULL, `conference_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "agenda",
+ "columnName": "agenda",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presentOnConference",
+ "columnName": "present_on_conference",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "conferenceId",
+ "columnName": "conference_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableAdditional",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `repeat_id` BLOB DEFAULT NULL, `is_added_by_user` INTEGER NOT NULL DEFAULT 0)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "repeatId",
+ "columnName": "repeat_id",
+ "affinity": "BLOB",
+ "notNull": false,
+ "defaultValue": "NULL"
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "StudentInfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `full_name` TEXT NOT NULL, `first_name` TEXT NOT NULL, `second_name` TEXT NOT NULL, `surname` TEXT NOT NULL, `birth_date` INTEGER NOT NULL, `birth_place` TEXT NOT NULL, `gender` TEXT NOT NULL, `has_polish_citizenship` INTEGER NOT NULL, `family_name` TEXT NOT NULL, `parents_names` TEXT NOT NULL, `address` TEXT NOT NULL, `registered_address` TEXT NOT NULL, `correspondence_address` TEXT NOT NULL, `phone_number` TEXT NOT NULL, `cell_phone_number` TEXT NOT NULL, `email` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `first_guardian_full_name` TEXT, `first_guardian_kinship` TEXT, `first_guardian_address` TEXT, `first_guardian_phones` TEXT, `first_guardian_email` TEXT, `second_guardian_full_name` TEXT, `second_guardian_kinship` TEXT, `second_guardian_address` TEXT, `second_guardian_phones` TEXT, `second_guardian_email` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "full_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstName",
+ "columnName": "first_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "secondName",
+ "columnName": "second_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "surname",
+ "columnName": "surname",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthDate",
+ "columnName": "birth_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthPlace",
+ "columnName": "birth_place",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gender",
+ "columnName": "gender",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPolishCitizenship",
+ "columnName": "has_polish_citizenship",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "familyName",
+ "columnName": "family_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentsNames",
+ "columnName": "parents_names",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registeredAddress",
+ "columnName": "registered_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "correspondenceAddress",
+ "columnName": "correspondence_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "phoneNumber",
+ "columnName": "phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "cellPhoneNumber",
+ "columnName": "cell_phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstGuardian.fullName",
+ "columnName": "first_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.kinship",
+ "columnName": "first_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.address",
+ "columnName": "first_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.phones",
+ "columnName": "first_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.email",
+ "columnName": "first_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.fullName",
+ "columnName": "second_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.kinship",
+ "columnName": "second_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.address",
+ "columnName": "second_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.phones",
+ "columnName": "second_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.email",
+ "columnName": "second_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableHeaders",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "SchoolAnnouncements",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_login_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notifications",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `type` TEXT NOT NULL, `destination` TEXT NOT NULL DEFAULT '{\"type\":\"io.github.wulkanowy.ui.modules.Destination.Dashboard\"}', `date` INTEGER NOT NULL, `data` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "destination",
+ "columnName": "destination",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'{\"type\":\"io.github.wulkanowy.ui.modules.Destination.Dashboard\"}'"
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "data",
+ "columnName": "data",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AdminMessages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `version_name` INTEGER, `version_max` INTEGER, `target_register_host` TEXT, `target_flavor` TEXT, `destination_url` TEXT, `priority` TEXT NOT NULL, `type` TEXT NOT NULL, `is_dismissible` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "versionMin",
+ "columnName": "version_name",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "versionMax",
+ "columnName": "version_max",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetRegisterHost",
+ "columnName": "target_register_host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetFlavor",
+ "columnName": "target_flavor",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "destinationUrl",
+ "columnName": "destination_url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "priority",
+ "columnName": "priority",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDismissible",
+ "columnName": "is_dismissible",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '51f9cb1d80df003c03bb655c0162487c')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/wulkanowy/data/DataModule.kt b/app/src/main/java/io/github/wulkanowy/data/DataModule.kt
index cac3ffc23..22123cbec 100644
--- a/app/src/main/java/io/github/wulkanowy/data/DataModule.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/DataModule.kt
@@ -19,7 +19,6 @@ import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AppInfo
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
@@ -110,7 +109,6 @@ internal class DataModule {
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences =
PreferenceManager.getDefaultSharedPreferences(context)
- @OptIn(ExperimentalCoroutinesApi::class)
@Singleton
@Provides
fun provideFlowSharedPref(sharedPreferences: SharedPreferences) =
@@ -197,7 +195,7 @@ internal class DataModule {
@Singleton
@Provides
- fun provideReportingUnitDao(database: AppDatabase) = database.reportingUnitDao
+ fun provideMailboxesDao(database: AppDatabase) = database.mailboxDao
@Singleton
@Provides
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
index 87915a9ed..15b38805b 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
@@ -30,7 +30,7 @@ import javax.inject.Singleton
Subject::class,
LuckyNumber::class,
CompletedLesson::class,
- ReportingUnit::class,
+ Mailbox::class,
Recipient::class,
MobileDevice::class,
Teacher::class,
@@ -55,7 +55,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() {
companion object {
- const val VERSION_SCHEMA = 50
+ const val VERSION_SCHEMA = 51
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
Migration2(),
@@ -103,7 +103,8 @@ abstract class AppDatabase : RoomDatabase() {
Migration44(),
Migration46(),
Migration49(),
- Migration50()
+ Migration50(),
+ Migration51(),
)
fun newInstance(
@@ -154,7 +155,7 @@ abstract class AppDatabase : RoomDatabase() {
abstract val completedLessonsDao: CompletedLessonsDao
- abstract val reportingUnitDao: ReportingUnitDao
+ abstract val mailboxDao: MailboxDao
abstract val recipientDao: RecipientDao
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/MailboxDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/MailboxDao.kt
new file mode 100644
index 000000000..8589db311
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/MailboxDao.kt
@@ -0,0 +1,17 @@
+package io.github.wulkanowy.data.db.dao
+
+import androidx.room.Dao
+import androidx.room.Query
+import io.github.wulkanowy.data.db.entities.Mailbox
+import javax.inject.Singleton
+
+@Singleton
+@Dao
+interface MailboxDao : BaseDao {
+
+ @Query("SELECT * FROM Mailboxes WHERE userLoginId = :userLoginId ")
+ suspend fun loadAll(userLoginId: Int): List
+
+ @Query("SELECT * FROM Mailboxes WHERE userLoginId = :userLoginId AND studentName = :studentName ")
+ suspend fun load(userLoginId: Int, studentName: String): Mailbox?
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt
index 729ba6a68..8c730c9bc 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt
@@ -11,9 +11,9 @@ import kotlinx.coroutines.flow.Flow
interface MessagesDao : BaseDao {
@Transaction
- @Query("SELECT * FROM Messages WHERE student_id = :studentId AND message_id = :messageId")
- fun loadMessageWithAttachment(studentId: Int, messageId: Int): Flow
+ @Query("SELECT * FROM Messages WHERE message_global_key = :messageGlobalKey")
+ fun loadMessageWithAttachment(messageGlobalKey: String): Flow
- @Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder ORDER BY date DESC")
- fun loadAll(studentId: Int, folder: Int): Flow>
+ @Query("SELECT * FROM Messages WHERE mailbox_key = :mailboxKey AND folder_id = :folder ORDER BY date DESC")
+ fun loadAll(mailboxKey: String, folder: Int): Flow>
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/RecipientDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/RecipientDao.kt
index c2787ac3b..1956261eb 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/RecipientDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/RecipientDao.kt
@@ -2,6 +2,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
+import io.github.wulkanowy.data.db.entities.MailboxType
import io.github.wulkanowy.data.db.entities.Recipient
import javax.inject.Singleton
@@ -9,6 +10,6 @@ import javax.inject.Singleton
@Dao
interface RecipientDao : BaseDao {
- @Query("SELECT * FROM Recipients WHERE student_id = :studentId AND unit_id = :unitId AND role = :role")
- suspend fun loadAll(studentId: Int, unitId: Int, role: Int): List
+ @Query("SELECT * FROM Recipients WHERE type = :type AND studentMailboxGlobalKey = :studentMailboxGlobalKey")
+ suspend fun loadAll(type: MailboxType, studentMailboxGlobalKey: String): List
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/ReportingUnitDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/ReportingUnitDao.kt
deleted file mode 100644
index ca697eda8..000000000
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/ReportingUnitDao.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package io.github.wulkanowy.data.db.dao
-
-import androidx.room.Dao
-import androidx.room.Query
-import io.github.wulkanowy.data.db.entities.ReportingUnit
-import javax.inject.Singleton
-
-@Singleton
-@Dao
-interface ReportingUnitDao : BaseDao {
-
- @Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId")
- suspend fun load(studentId: Int): List
-
- @Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId AND real_id = :unitId")
- suspend fun loadOne(studentId: Int, unitId: Int): ReportingUnit?
-}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Mailbox.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Mailbox.kt
new file mode 100644
index 000000000..7c08e481d
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Mailbox.kt
@@ -0,0 +1,25 @@
+package io.github.wulkanowy.data.db.entities
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+@Entity(tableName = "Mailboxes")
+data class Mailbox(
+
+ @PrimaryKey
+ val globalKey: String,
+ val fullName: String,
+ val userName: String,
+ val userLoginId: Int,
+ val studentName: String,
+ val schoolNameShort: String,
+ val type: MailboxType,
+)
+
+enum class MailboxType {
+ STUDENT,
+ PARENT,
+ GUARDIAN,
+ EMPLOYEE,
+ UNKNOWN,
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt
index 8782bc765..77874e03d 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt
@@ -9,23 +9,16 @@ import java.time.Instant
@Entity(tableName = "Messages")
data class Message(
- @ColumnInfo(name = "student_id")
- val studentId: Long,
+ @ColumnInfo(name = "message_global_key")
+ val messageGlobalKey: String,
- @ColumnInfo(name = "real_id")
- val realId: Int,
+ @ColumnInfo(name = "mailbox_key")
+ val mailboxKey: String,
@ColumnInfo(name = "message_id")
val messageId: Int,
- @ColumnInfo(name = "sender_name")
- val sender: String,
-
- @ColumnInfo(name = "sender_id")
- val senderId: Int,
-
- @ColumnInfo(name = "recipient_name")
- val recipient: String,
+ val correspondents: String,
val subject: String,
@@ -36,8 +29,6 @@ data class Message(
var unread: Boolean,
- val removed: Boolean,
-
@ColumnInfo(name = "has_attachments")
val hasAttachments: Boolean
) : Serializable {
@@ -48,11 +39,7 @@ data class Message(
@ColumnInfo(name = "is_notified")
var isNotified: Boolean = true
- @ColumnInfo(name = "unread_by")
- var unreadBy: Int = 0
-
- @ColumnInfo(name = "read_by")
- var readBy: Int = 0
-
var content: String = ""
+ var sender: String? = null
+ var recipients: String? = null
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageAttachment.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageAttachment.kt
index d1886e910..93f042999 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageAttachment.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageAttachment.kt
@@ -12,11 +12,8 @@ data class MessageAttachment(
@ColumnInfo(name = "real_id")
val realId: Int,
- @ColumnInfo(name = "message_id")
- val messageId: Int,
-
- @ColumnInfo(name = "one_drive_id")
- val oneDriveId: String,
+ @ColumnInfo(name = "message_global_key")
+ val messageGlobalKey: String,
@ColumnInfo(name = "url")
val url: String,
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageWithAttachment.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageWithAttachment.kt
index 2e7af0f40..cd468215d 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageWithAttachment.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageWithAttachment.kt
@@ -7,6 +7,6 @@ data class MessageWithAttachment(
@Embedded
val message: Message,
- @Relation(parentColumn = "message_id", entityColumn = "message_id")
+ @Relation(parentColumn = "message_global_key", entityColumn = "message_global_key")
val attachments: List
)
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Recipient.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Recipient.kt
index 223322705..d09742cd2 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Recipient.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Recipient.kt
@@ -1,6 +1,5 @@
package io.github.wulkanowy.data.db.entities
-import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
@@ -8,32 +7,16 @@ import java.io.Serializable
@kotlinx.serialization.Serializable
@Entity(tableName = "Recipients")
data class Recipient(
-
- @ColumnInfo(name = "student_id")
- val studentId: Int,
-
- @ColumnInfo(name = "real_id")
- val realId: String,
-
- val name: String,
-
- @ColumnInfo(name = "real_name")
- val realName: String,
-
- @ColumnInfo(name = "login_id")
- val loginId: Int,
-
- @ColumnInfo(name = "unit_id")
- val unitId: Int,
-
- val role: Int,
-
- val hash: String
-
+ val mailboxGlobalKey: String,
+ val studentMailboxGlobalKey: String,
+ val fullName: String,
+ val userName: String,
+ val schoolShortName: String,
+ val type: MailboxType,
) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
- override fun toString() = name
+ override fun toString() = userName
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/ReportingUnit.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/ReportingUnit.kt
deleted file mode 100644
index 0570a2ffd..000000000
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/ReportingUnit.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package io.github.wulkanowy.data.db.entities
-
-import androidx.room.ColumnInfo
-import androidx.room.Entity
-import androidx.room.PrimaryKey
-import java.io.Serializable
-
-@Entity(tableName = "ReportingUnits")
-data class ReportingUnit(
-
- @ColumnInfo(name = "student_id")
- val studentId: Int,
-
- @ColumnInfo(name = "real_id")
- val unitId: Int,
-
- @ColumnInfo(name = "short")
- val shortName: String,
-
- @ColumnInfo(name = "sender_id")
- val senderId: Int,
-
- @ColumnInfo(name = "sender_name")
- val senderName: String,
-
- val roles: List
-
-) : Serializable {
-
- @PrimaryKey(autoGenerate = true)
- var id: Long = 0
-}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration51.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration51.kt
new file mode 100644
index 000000000..e78e2e3a7
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration51.kt
@@ -0,0 +1,88 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class Migration51 : Migration(50, 51) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ createMailboxTable(database)
+ recreateMessagesTable(database)
+ recreateMessageAttachmentsTable(database)
+ recreateRecipientsTable(database)
+ deleteReportingUnitTable(database)
+ }
+
+ private fun createMailboxTable(database: SupportSQLiteDatabase) {
+ database.execSQL("DROP TABLE IF EXISTS Mailboxes")
+ database.execSQL(
+ """
+ CREATE TABLE IF NOT EXISTS `Mailboxes` (
+ `globalKey` TEXT NOT NULL,
+ `fullName` TEXT NOT NULL,
+ `userName` TEXT NOT NULL,
+ `userLoginId` INTEGER NOT NULL,
+ `studentName` TEXT NOT NULL,
+ `schoolNameShort` TEXT NOT NULL,
+ `type` TEXT NOT NULL,
+ PRIMARY KEY(`globalKey`)
+ )""".trimIndent()
+ )
+ }
+
+ private fun recreateMessagesTable(database: SupportSQLiteDatabase) {
+ database.execSQL("DROP TABLE IF EXISTS Messages")
+ database.execSQL(
+ """
+ CREATE TABLE IF NOT EXISTS `Messages` (
+ `message_global_key` TEXT NOT NULL,
+ `mailbox_key` TEXT NOT NULL,
+ `message_id` INTEGER NOT NULL,
+ `correspondents` TEXT NOT NULL,
+ `subject` TEXT NOT NULL,
+ `date` INTEGER NOT NULL,
+ `folder_id` INTEGER NOT NULL,
+ `unread` INTEGER NOT NULL,
+ `has_attachments` INTEGER NOT NULL,
+ `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ `is_notified` INTEGER NOT NULL,
+ `content` TEXT NOT NULL,
+ `sender` TEXT, `recipients` TEXT
+ )""".trimIndent()
+ )
+ }
+
+ private fun recreateMessageAttachmentsTable(database: SupportSQLiteDatabase) {
+ database.execSQL("DROP TABLE IF EXISTS MessageAttachments")
+ database.execSQL(
+ """
+ CREATE TABLE IF NOT EXISTS `MessageAttachments` (
+ `real_id` INTEGER NOT NULL,
+ `message_global_key` TEXT NOT NULL,
+ `url` TEXT NOT NULL,
+ `filename` TEXT NOT NULL,
+ PRIMARY KEY(`real_id`)
+ )""".trimIndent()
+ )
+ }
+
+ private fun recreateRecipientsTable(database: SupportSQLiteDatabase) {
+ database.execSQL("DROP TABLE IF EXISTS Recipients")
+ database.execSQL(
+ """
+ CREATE TABLE IF NOT EXISTS `Recipients` (
+ `mailboxGlobalKey` TEXT NOT NULL,
+ `studentMailboxGlobalKey` TEXT NOT NULL,
+ `fullName` TEXT NOT NULL,
+ `userName` TEXT NOT NULL,
+ `schoolShortName` TEXT NOT NULL,
+ `type` TEXT NOT NULL,
+ `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+ )""".trimIndent()
+ )
+ }
+
+ private fun deleteReportingUnitTable(database: SupportSQLiteDatabase) {
+ database.execSQL("DROP TABLE IF EXISTS ReportingUnits")
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/MailboxMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/MailboxMapper.kt
new file mode 100644
index 000000000..2ccca1b90
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/MailboxMapper.kt
@@ -0,0 +1,18 @@
+package io.github.wulkanowy.data.mappers
+
+import io.github.wulkanowy.data.db.entities.Mailbox
+import io.github.wulkanowy.data.db.entities.MailboxType
+import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.sdk.pojo.Mailbox as SdkMailbox
+
+fun List.mapToEntities(student: Student) = map {
+ Mailbox(
+ globalKey = it.globalKey,
+ fullName = it.fullName,
+ userName = it.userName,
+ userLoginId = student.userLoginId,
+ studentName = it.studentName,
+ schoolNameShort = it.schoolNameShort,
+ type = MailboxType.valueOf(it.type.name),
+ )
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
index 13f0ab33e..2e7967f0e 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
@@ -1,40 +1,31 @@
package io.github.wulkanowy.data.mappers
-import io.github.wulkanowy.data.db.entities.Message
-import io.github.wulkanowy.data.db.entities.MessageAttachment
-import io.github.wulkanowy.data.db.entities.Recipient
-import io.github.wulkanowy.data.db.entities.Student
-import java.time.Instant
+import io.github.wulkanowy.data.db.entities.*
+import io.github.wulkanowy.sdk.pojo.MailboxType
import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
-fun List.mapToEntities(student: Student) = map {
+fun List.mapToEntities(mailbox: Mailbox) = map {
Message(
- studentId = student.id,
- realId = it.id ?: 0,
- messageId = it.messageId ?: 0,
- sender = it.sender?.name.orEmpty(),
- senderId = it.sender?.loginId ?: 0,
- recipient = it.recipients.singleOrNull()?.name ?: "Wielu adresatów",
+ messageGlobalKey = it.globalKey,
+ mailboxKey = mailbox.globalKey,
+ messageId = it.id,
+ correspondents = it.correspondents,
subject = it.subject.trim(),
- date = it.dateZoned?.toInstant() ?: Instant.now(),
+ date = it.dateZoned.toInstant(),
folderId = it.folderId,
- unread = it.unread ?: false,
- removed = it.removed,
+ unread = it.unread,
hasAttachments = it.hasAttachments
).apply {
content = it.content.orEmpty()
- unreadBy = it.unreadBy ?: 0
- readBy = it.readBy ?: 0
}
}
-fun List.mapToEntities() = map {
+fun List.mapToEntities(messageGlobalKey: String) = map {
MessageAttachment(
- realId = it.id,
- messageId = it.messageId,
- oneDriveId = it.oneDriveId,
+ messageGlobalKey = messageGlobalKey,
+ realId = it.url.hashCode(),
url = it.url,
filename = it.filename
)
@@ -42,12 +33,11 @@ fun List.mapToEntities() = map {
fun List.mapFromEntities() = map {
SdkRecipient(
- id = it.realId,
- name = it.realName,
- loginId = it.loginId,
- reportingUnitId = it.unitId,
- role = it.role,
- hash = it.hash,
- shortName = it.name
+ fullName = it.fullName,
+ userName = it.userName,
+ studentName = it.userName,
+ mailboxGlobalKey = it.mailboxGlobalKey,
+ schoolNameShort = it.schoolShortName,
+ type = MailboxType.valueOf(it.type.name),
)
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/RecipientMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/RecipientMapper.kt
index 80bddaab1..eb993a0f0 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/RecipientMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/RecipientMapper.kt
@@ -1,17 +1,16 @@
package io.github.wulkanowy.data.mappers
+import io.github.wulkanowy.data.db.entities.MailboxType
import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
-fun List.mapToEntities(userLoginId: Int) = map {
+fun List.mapToEntities(studentMailboxGlobalKey: String) = map {
Recipient(
- studentId = userLoginId,
- realId = it.id,
- realName = it.name,
- name = it.shortName,
- hash = it.hash,
- loginId = it.loginId,
- role = it.role,
- unitId = it.reportingUnitId ?: 0
+ mailboxGlobalKey = it.mailboxGlobalKey,
+ fullName = it.fullName,
+ userName = it.userName,
+ studentMailboxGlobalKey = studentMailboxGlobalKey,
+ schoolShortName = it.schoolNameShort,
+ type = MailboxType.valueOf(it.type.name),
)
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/ReportingUnitMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/ReportingUnitMapper.kt
deleted file mode 100644
index 6a21d59fc..000000000
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/ReportingUnitMapper.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package io.github.wulkanowy.data.mappers
-
-import io.github.wulkanowy.data.db.entities.ReportingUnit
-import io.github.wulkanowy.data.db.entities.Student
-import io.github.wulkanowy.sdk.pojo.ReportingUnit as SdkReportingUnit
-
-fun List.mapToEntities(student: Student) = map {
- ReportingUnit(
- studentId = student.id.toInt(),
- unitId = it.id,
- roles = it.roles,
- senderId = it.senderId,
- senderName = it.senderName,
- shortName = it.short
- )
-}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt
new file mode 100644
index 000000000..7f5974920
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt
@@ -0,0 +1,48 @@
+package io.github.wulkanowy.data.repositories
+
+import io.github.wulkanowy.data.db.dao.MailboxDao
+import io.github.wulkanowy.data.db.entities.Mailbox
+import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.data.mappers.mapToEntities
+import io.github.wulkanowy.sdk.Sdk
+import io.github.wulkanowy.utils.AutoRefreshHelper
+import io.github.wulkanowy.utils.getRefreshKey
+import io.github.wulkanowy.utils.init
+import io.github.wulkanowy.utils.uniqueSubtract
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class MailboxRepository @Inject constructor(
+ private val mailboxDao: MailboxDao,
+ private val sdk: Sdk,
+ private val refreshHelper: AutoRefreshHelper,
+) {
+ private val cacheKey = "mailboxes"
+
+ suspend fun refreshMailboxes(student: Student) {
+ val new = sdk.init(student).getMailboxes().mapToEntities(student)
+ val old = mailboxDao.loadAll(student.userLoginId)
+
+ mailboxDao.deleteAll(old uniqueSubtract new)
+ mailboxDao.insertAll(new uniqueSubtract old)
+
+ refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
+ }
+
+ suspend fun getMailbox(student: Student): Mailbox {
+ val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
+ val mailbox = mailboxDao.load(student.userLoginId, student.studentName)
+
+ return if (isExpired || mailbox == null) {
+ refreshMailboxes(student)
+ val newMailbox = mailboxDao.load(student.userLoginId, student.studentName)
+
+ requireNotNull(newMailbox) {
+ "Mailbox for ${student.userName} - ${student.studentName} not found!"
+ }
+
+ newMailbox
+ } else mailbox
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt
index 05fb97657..00cbffb84 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt
@@ -10,24 +10,24 @@ import io.github.wulkanowy.data.db.dao.MessagesDao
import io.github.wulkanowy.data.db.entities.*
import io.github.wulkanowy.data.enums.MessageFolder
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
+import io.github.wulkanowy.data.enums.MessageFolder.TRASHED
import io.github.wulkanowy.data.mappers.mapFromEntities
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.data.pojos.MessageDraft
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Folder
-import io.github.wulkanowy.sdk.pojo.SentMessage
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.first
import kotlinx.coroutines.sync.Mutex
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import timber.log.Timber
-import java.time.LocalDateTime.now
import javax.inject.Inject
import javax.inject.Singleton
@@ -49,7 +49,7 @@ class MessageRepository @Inject constructor(
@Suppress("UNUSED_PARAMETER")
fun getMessages(
student: Student,
- semester: Semester,
+ mailbox: Mailbox,
folder: MessageFolder,
forceRefresh: Boolean,
notify: Boolean = false,
@@ -62,42 +62,20 @@ class MessageRepository @Inject constructor(
)
it.isEmpty() || forceRefresh || isExpired
},
- query = { messagesDb.loadAll(student.id.toInt(), folder.id) },
+ query = { messagesDb.loadAll(mailbox.globalKey, folder.id) },
fetch = {
- sdk.init(student).getMessages(Folder.valueOf(folder.name), now().minusMonths(3), now())
- .mapToEntities(student)
+ sdk.init(student).getMessages(Folder.valueOf(folder.name)).mapToEntities(mailbox)
},
saveFetchResult = { old, new ->
messagesDb.deleteAll(old uniqueSubtract new)
messagesDb.insertAll((new uniqueSubtract old).onEach {
it.isNotified = !notify
})
- messagesDb.updateAll(getMessagesWithReadByChange(old, new, !notify))
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student, folder))
}
)
- private fun getMessagesWithReadByChange(
- old: List,
- new: List,
- setNotified: Boolean
- ): List {
- val oldMeta = old.map { Triple(it, it.readBy, it.unreadBy) }
- val newMeta = new.map { Triple(it, it.readBy, it.unreadBy) }
-
- val updatedItems = newMeta uniqueSubtract oldMeta
-
- return updatedItems.map {
- val oldItem = old.find { item -> item.messageId == it.first.messageId }
- it.first.apply {
- id = oldItem?.id ?: 0
- isNotified = oldItem?.isNotified ?: setNotified
- content = oldItem?.content.orEmpty()
- }
- }
- }
-
fun getMessage(
student: Student,
message: Message,
@@ -106,34 +84,34 @@ class MessageRepository @Inject constructor(
isResultEmpty = { it?.message?.content.isNullOrBlank() },
shouldFetch = {
checkNotNull(it) { "This message no longer exist!" }
- Timber.d("Message content in db empty: ${it.message.content.isEmpty()}")
- it.message.unread || it.message.content.isEmpty()
+ Timber.d("Message content in db empty: ${it.message.content.isBlank()}")
+ it.message.unread || it.message.content.isBlank()
},
- query = { messagesDb.loadMessageWithAttachment(student.id.toInt(), message.messageId) },
+ query = { messagesDb.loadMessageWithAttachment(message.messageGlobalKey) },
fetch = {
- sdk.init(student).getMessageDetails(
- messageId = it!!.message.messageId,
- folderId = message.folderId,
- read = markAsRead,
- id = message.realId
- ).let { details ->
- details.content to details.attachments.mapToEntities()
- }
+ sdk.init(student).getMessageDetails(it!!.message.messageGlobalKey)
},
- saveFetchResult = { old, (downloadedMessage, attachments) ->
+ saveFetchResult = { old, new ->
checkNotNull(old) { "Fetched message no longer exist!" }
- messagesDb.updateAll(listOf(old.message.apply {
- id = old.message.id
- unread = !markAsRead
- content = content.ifBlank { downloadedMessage }
- }))
- messageAttachmentDao.insertAttachments(attachments)
+ messagesDb.updateAll(
+ listOf(old.message.apply {
+ id = message.id
+ unread = !markAsRead
+ sender = new.sender
+ recipients = new.recipients.firstOrNull() ?: "Wielu adresoatów"
+ content = content.ifBlank { new.content }
+ })
+ )
+ messageAttachmentDao.insertAttachments(
+ items = new.attachments.mapToEntities(message.messageGlobalKey),
+ )
+
Timber.d("Message ${message.messageId} with blank content: ${old.message.content.isBlank()}, marked as read")
}
)
- fun getMessagesFromDatabase(student: Student): Flow> {
- return messagesDb.loadAll(student.id.toInt(), RECEIVED.id)
+ fun getMessagesFromDatabase(mailbox: Mailbox): Flow> {
+ return messagesDb.loadAll(mailbox.globalKey, RECEIVED.id)
}
suspend fun updateMessages(messages: List) {
@@ -145,32 +123,48 @@ class MessageRepository @Inject constructor(
subject: String,
content: String,
recipients: List,
- ): SentMessage = sdk.init(student).sendMessage(
- subject = subject,
- content = content,
- recipients = recipients.mapFromEntities()
- )
+ mailboxId: String,
+ ) {
+ sdk.init(student).sendMessage(
+ subject = subject,
+ content = content,
+ recipients = recipients.mapFromEntities(),
+ mailboxId = mailboxId,
+ )
+ }
- suspend fun deleteMessages(student: Student, messages: List) {
- val folderId = messages.first().folderId
- val isDeleted = sdk.init(student)
- .deleteMessages(messages = messages.map { it.messageId }, folderId = folderId)
+ suspend fun deleteMessages(student: Student, mailbox: Mailbox, messages: List) {
+ val firstMessage = messages.first()
+ sdk.init(student).deleteMessages(
+ messages = messages.map { it.messageGlobalKey },
+ removeForever = firstMessage.folderId == TRASHED.id,
+ )
- if (folderId != MessageFolder.TRASHED.id && isDeleted) {
+ if (firstMessage.folderId != TRASHED.id) {
val deletedMessages = messages.map {
- it.copy(folderId = MessageFolder.TRASHED.id)
+ it.copy(folderId = TRASHED.id)
.apply {
id = it.id
content = it.content
+ sender = it.sender
+ recipients = it.recipients
}
}
messagesDb.updateAll(deletedMessages)
} else messagesDb.deleteAll(messages)
+
+ getMessages(
+ student = student,
+ mailbox = mailbox,
+ folder = TRASHED,
+ forceRefresh = true,
+ ).first()
}
- suspend fun deleteMessage(student: Student, message: Message) =
- deleteMessages(student, listOf(message))
+ suspend fun deleteMessage(student: Student, mailbox: Mailbox, message: Message) {
+ deleteMessages(student, mailbox, listOf(message))
+ }
var draftMessage: MessageDraft?
get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_send_draft))
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/RecipientRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/RecipientRepository.kt
index 60e6f248f..e80f028e1 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/RecipientRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/RecipientRepository.kt
@@ -1,10 +1,7 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.RecipientDao
-import io.github.wulkanowy.data.db.entities.Message
-import io.github.wulkanowy.data.db.entities.Recipient
-import io.github.wulkanowy.data.db.entities.ReportingUnit
-import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.data.db.entities.*
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
@@ -23,9 +20,10 @@ class RecipientRepository @Inject constructor(
private val cacheKey = "recipient"
- suspend fun refreshRecipients(student: Student, unit: ReportingUnit, role: Int) {
- val new = sdk.init(student).getRecipients(unit.unitId, role).mapToEntities(unit.studentId)
- val old = recipientDb.loadAll(unit.studentId, unit.unitId, role)
+ suspend fun refreshRecipients(student: Student, mailbox: Mailbox, type: MailboxType) {
+ val new = sdk.init(student).getRecipients(mailbox.globalKey)
+ .mapToEntities(mailbox.globalKey)
+ val old = recipientDb.loadAll(type, mailbox.globalKey)
recipientDb.deleteAll(old uniqueSubtract new)
recipientDb.insertAll(new uniqueSubtract old)
@@ -33,18 +31,27 @@ class RecipientRepository @Inject constructor(
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
}
- suspend fun getRecipients(student: Student, unit: ReportingUnit, role: Int): List {
- val cached = recipientDb.loadAll(unit.studentId, unit.unitId, role)
+ suspend fun getRecipients(
+ student: Student,
+ mailbox: Mailbox,
+ type: MailboxType
+ ): List {
+ val cached = recipientDb.loadAll(type, mailbox.globalKey)
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
return if (cached.isEmpty() || isExpired) {
- refreshRecipients(student, unit, role)
- recipientDb.loadAll(unit.studentId, unit.unitId, role)
+ refreshRecipients(student, mailbox, type)
+ recipientDb.loadAll(type, mailbox.globalKey)
} else cached
}
- suspend fun getMessageRecipients(student: Student, message: Message): List {
- return sdk.init(student).getMessageRecipients(message.messageId, message.senderId)
- .mapToEntities(student.studentId)
- }
+ suspend fun getMessageSender(
+ student: Student,
+ mailbox: Mailbox,
+ message: Message
+ ): List = sdk.init(student)
+ .getMessageReplayDetails(message.messageGlobalKey)
+ .sender
+ .let(::listOf)
+ .mapToEntities(mailbox.globalKey)
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/ReportingUnitRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/ReportingUnitRepository.kt
deleted file mode 100644
index 84055cef0..000000000
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/ReportingUnitRepository.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-package io.github.wulkanowy.data.repositories
-
-import io.github.wulkanowy.data.db.dao.ReportingUnitDao
-import io.github.wulkanowy.data.db.entities.ReportingUnit
-import io.github.wulkanowy.data.db.entities.Student
-import io.github.wulkanowy.data.mappers.mapToEntities
-import io.github.wulkanowy.sdk.Sdk
-import io.github.wulkanowy.utils.AutoRefreshHelper
-import io.github.wulkanowy.utils.getRefreshKey
-import io.github.wulkanowy.utils.init
-import io.github.wulkanowy.utils.uniqueSubtract
-import javax.inject.Inject
-import javax.inject.Singleton
-
-@Singleton
-class ReportingUnitRepository @Inject constructor(
- private val reportingUnitDb: ReportingUnitDao,
- private val sdk: Sdk,
- private val refreshHelper: AutoRefreshHelper,
-) {
-
- private val cacheKey = "reporting_unit"
-
- suspend fun refreshReportingUnits(student: Student) {
- val new = sdk.init(student).getReportingUnits().mapToEntities(student)
- val old = reportingUnitDb.load(student.id.toInt())
-
- reportingUnitDb.deleteAll(old.uniqueSubtract(new))
- reportingUnitDb.insertAll(new.uniqueSubtract(old))
-
- refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
- }
-
- suspend fun getReportingUnits(student: Student): List {
- val cached = reportingUnitDb.load(student.id.toInt())
- val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
-
- return if (cached.isEmpty() || isExpired) {
- refreshReportingUnits(student)
- reportingUnitDb.load(student.id.toInt())
- } else cached
- }
-
- suspend fun getReportingUnit(student: Student, unitId: Int): ReportingUnit? {
- val cached = reportingUnitDb.loadOne(student.id.toInt(), unitId)
- val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
-
- return if (cached == null || isExpired) {
- refreshReportingUnits(student)
- reportingUnitDb.loadOne(student.id.toInt(), unitId)
- } else cached
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewMessageNotification.kt b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewMessageNotification.kt
index 5c3c52c5b..3b7bcff05 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewMessageNotification.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewMessageNotification.kt
@@ -21,7 +21,7 @@ class NewMessageNotification @Inject constructor(
val notificationDataList = items.map {
NotificationData(
title = context.getPlural(R.plurals.message_new_items, 1),
- content = "${it.sender}: ${it.subject}",
+ content = "${it.correspondents}: ${it.subject}",
destination = Destination.Message,
)
}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/MessageWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/MessageWork.kt
index 26fac1a2f..180568267 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/MessageWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/MessageWork.kt
@@ -3,6 +3,7 @@ package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
+import io.github.wulkanowy.data.repositories.MailboxRepository
import io.github.wulkanowy.data.repositories.MessageRepository
import io.github.wulkanowy.data.waitForResult
import io.github.wulkanowy.services.sync.notifications.NewMessageNotification
@@ -11,19 +12,21 @@ import javax.inject.Inject
class MessageWork @Inject constructor(
private val messageRepository: MessageRepository,
+ private val mailboxRepository: MailboxRepository,
private val newMessageNotification: NewMessageNotification,
) : Work {
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
+ val mailbox = mailboxRepository.getMailbox(student)
messageRepository.getMessages(
student = student,
- semester = semester,
+ mailbox = mailbox,
folder = RECEIVED,
forceRefresh = true,
notify = notify
).waitForResult()
- messageRepository.getMessagesFromDatabase(student).first()
+ messageRepository.getMessagesFromDatabase(mailbox).first()
.filter { !it.isNotified && it.unread }.let {
if (it.isNotEmpty()) newMessageNotification.notify(it, student)
messageRepository.updateMessages(it.onEach { message -> message.isNotified = true })
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/RecipientWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/RecipientWork.kt
index 425e68b91..b1322ada3 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/RecipientWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/RecipientWork.kt
@@ -1,23 +1,22 @@
package io.github.wulkanowy.services.sync.works
+import io.github.wulkanowy.data.db.entities.MailboxType
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.data.repositories.MailboxRepository
import io.github.wulkanowy.data.repositories.RecipientRepository
-import io.github.wulkanowy.data.repositories.ReportingUnitRepository
import javax.inject.Inject
class RecipientWork @Inject constructor(
- private val reportingUnitRepository: ReportingUnitRepository,
+ private val mailboxRepository: MailboxRepository,
private val recipientRepository: RecipientRepository
) : Work {
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
- reportingUnitRepository.refreshReportingUnits(student)
+ mailboxRepository.refreshMailboxes(student)
- reportingUnitRepository.getReportingUnits(student).let { units ->
- units.map {
- recipientRepository.refreshRecipients(student, it, 2)
- }
- }
+ val mailbox = mailboxRepository.getMailbox(student)
+
+ recipientRepository.refreshRecipients(student, mailbox, MailboxType.EMPLOYEE)
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
index 5d7c7df4b..350300937 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
@@ -25,6 +25,7 @@ class DashboardPresenter @Inject constructor(
private val gradeRepository: GradeRepository,
private val semesterRepository: SemesterRepository,
private val messageRepository: MessageRepository,
+ private val mailboxRepository: MailboxRepository,
private val attendanceSummaryRepository: AttendanceSummaryRepository,
private val timetableRepository: TimetableRepository,
private val homeworkRepository: HomeworkRepository,
@@ -227,6 +228,7 @@ class DashboardPresenter @Inject constructor(
private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) {
flow {
val semester = semesterRepository.getCurrentSemester(student)
+ val mailbox = mailboxRepository.getMailbox(student)
val selectedTiles = preferencesRepository.selectedDashboardTiles
val flowSuccess = flowOf(Resource.Success(null))
@@ -238,7 +240,7 @@ class DashboardPresenter @Inject constructor(
val messageFLow = messageRepository.getMessages(
student = student,
- semester = semester,
+ mailbox = mailbox,
folder = MessageFolder.RECEIVED,
forceRefresh = forceRefresh
).takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowSuccess
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/message.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/message.kt
index 53d439612..6ff26162b 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/message.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/message.kt
@@ -17,16 +17,13 @@ val debugMessageItems = listOf(
)
private fun generateMessage(sender: String, subject: String) = Message(
- sender = sender,
subject = subject,
- studentId = 0,
- realId = 0,
- messageId = 0,
- senderId = 0,
- recipient = "",
+ messageId = 123,
date = Instant.now(),
folderId = 0,
unread = true,
- removed = false,
- hasAttachments = false
+ hasAttachments = false,
+ messageGlobalKey = "",
+ correspondents = sender,
+ mailboxKey = "",
)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewAdapter.kt
index d75128be1..3c1c53d39 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewAdapter.kt
@@ -4,6 +4,8 @@ import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.core.text.HtmlCompat.FROM_HTML_MODE_COMPACT
+import androidx.core.text.parseAsHtml
import androidx.recyclerview.widget.RecyclerView
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Message
@@ -75,29 +77,25 @@ class MessagePreviewAdapter @Inject constructor() :
@SuppressLint("SetTextI18n")
private fun bindMessage(holder: MessageViewHolder, message: Message) {
val context = holder.binding.root.context
- val recipientCount = message.unreadBy + message.readBy
- val readText = when {
- recipientCount > 1 -> {
- context.getString(R.string.message_read_by, message.readBy, recipientCount)
- }
- message.readBy == 1 -> {
- context.getString(R.string.message_read, context.getString(R.string.all_yes))
- }
- else -> context.getString(R.string.message_read, context.getString(R.string.all_no))
+ val readTextValue = when {
+ !message.unread -> R.string.all_yes
+ else -> R.string.all_no
}
+ val readText = context.getString(R.string.message_read, context.getString(readTextValue))
with(holder.binding) {
- messagePreviewSubject.text =
- message.subject.ifBlank { root.context.getString(R.string.message_no_subject) }
- messagePreviewDate.text = root.context.getString(
+ messagePreviewSubject.text = message.subject.ifBlank {
+ context.getString(R.string.message_no_subject)
+ }
+ messagePreviewDate.text = context.getString(
R.string.message_date,
message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")
)
messagePreviewRead.text = readText
- messagePreviewContent.text = message.content
+ messagePreviewContent.text = message.content.parseAsHtml(FROM_HTML_MODE_COMPACT)
messagePreviewFromSender.text = message.sender
- messagePreviewToRecipient.text = message.recipient
+ messagePreviewToRecipient.text = message.recipients
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt
index 4b2685c6d..2a5523f4d 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt
@@ -135,8 +135,8 @@ class MessagePreviewFragment :
binding.messagePreviewRecycler.visibility = if (show) VISIBLE else GONE
}
- override fun showOptions(show: Boolean) {
- menuReplyButton?.isVisible = show
+ override fun showOptions(show: Boolean, isReplayable: Boolean) {
+ menuReplyButton?.isVisible = isReplayable
menuForwardButton?.isVisible = show
menuDeleteButton?.isVisible = show
menuShareButton?.isVisible = show
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt
index 39c337bf2..c011f41f3 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt
@@ -1,10 +1,12 @@
package io.github.wulkanowy.ui.modules.message.preview
import android.annotation.SuppressLint
+import androidx.core.text.parseAsHtml
import io.github.wulkanowy.data.*
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageAttachment
import io.github.wulkanowy.data.enums.MessageFolder
+import io.github.wulkanowy.data.repositories.MailboxRepository
import io.github.wulkanowy.data.repositories.MessageRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
@@ -19,6 +21,7 @@ class MessagePreviewPresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
private val messageRepository: MessageRepository,
+ private val mailboxRepository: MailboxRepository,
private val analytics: AnalyticsHelper
) : BasePresenter(errorHandler, studentRepository) {
@@ -52,7 +55,7 @@ class MessagePreviewPresenter @Inject constructor(
private fun loadData(messageToLoad: Message) {
flatResourceFlow {
- val student = studentRepository.getStudentById(messageToLoad.studentId)
+ val student = studentRepository.getCurrentStudent()
messageRepository.getMessage(student, messageToLoad, true)
}
.logResourceStatus("message ${messageToLoad.messageId} preview")
@@ -104,62 +107,69 @@ class MessagePreviewPresenter @Inject constructor(
}
fun onShare(): Boolean {
- message?.let {
- var text =
- "Temat: ${it.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }}\n" + when (it.sender.isNotEmpty()) {
- true -> "Od: ${it.sender}\n"
- false -> "Do: ${it.recipient}\n"
- } + "Data: ${it.date.toFormattedString("yyyy-MM-dd HH:mm:ss")}\n\n${it.content}"
+ val message = message ?: return false
+ val subject = message.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }
- attachments?.let { attachments ->
- if (attachments.isNotEmpty()) {
- text += "\n\nZałączniki:"
+ val text = buildString {
+ appendLine("Temat: $subject")
+ appendLine("Od: ${message.sender}")
+ appendLine("Do: ${message.recipients}")
+ appendLine("Data: ${message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")}")
- attachments.forEach { attachment ->
- text += "\n${attachment.filename}: ${attachment.url}"
- }
- }
+ appendLine()
+
+ appendLine(message.content.parseAsHtml())
+
+ if (!attachments.isNullOrEmpty()) {
+ appendLine()
+ appendLine("Załączniki:")
+
+ append(attachments.orEmpty().joinToString(separator = "\n") { attachment ->
+ "${attachment.filename}: ${attachment.url}"
+ })
}
-
- view?.shareText(
- text,
- "FW: ${it.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }}"
- )
- return true
}
- return false
+
+ view?.shareText(
+ subject = "FW: $subject",
+ text = text,
+ )
+ return true
}
@SuppressLint("NewApi")
fun onPrint(): Boolean {
- message?.let {
- val dateString = it.date.toFormattedString("yyyy-MM-dd HH:mm:ss")
- val infoContent = "Data wysłania
$dateString
" + when {
- it.sender.isNotEmpty() -> "Od
${it.sender}"
- else -> "Do
${it.recipient}"
- }
+ val message = message ?: return false
+ val subject = message.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }
- val messageContent = "${it.content}
"
- .replace(Regex("[\\n\\r]{2,}"), "")
- .replace(Regex("[\\n\\r]"), "
")
+ val dateString = message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")
- val jobName = "Wiadomość " + when {
- it.sender.isNotEmpty() -> "od ${it.sender}"
- else -> "do ${it.recipient}"
- } + " $dateString: ${it.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }} | Wulkanowy"
+ val infoContent = buildString {
+ append("
Data wysłania
$dateString")
- view?.apply {
- val html = printHTML
- .replace(
- "%SUBJECT%",
- it.subject.ifBlank { view?.messageNoSubjectString.orEmpty() })
- .replace("%CONTENT%", messageContent)
- .replace("%INFO%", infoContent)
- printDocument(html, jobName)
- }
- return true
+ append("Od
${message.sender}")
+ append("DO
${message.recipients}")
}
- return false
+ val messageContent = "${message.content}
"
+ .replace(Regex("[\\n\\r]{2,}"), "")
+ .replace(Regex("[\\n\\r]"), "
")
+
+ val jobName = buildString {
+ append("Wiadomość ")
+ append("od ${message.correspondents}")
+ append("do ${message.correspondents}")
+ append(" $dateString: $subject | Wulkanowy")
+ }
+
+ view?.apply {
+ val html = printHTML
+ .replace("%SUBJECT%", subject)
+ .replace("%CONTENT%", messageContent)
+ .replace("%INFO%", infoContent)
+ printDocument(html, jobName)
+ }
+
+ return true
}
private fun deleteMessage() {
@@ -168,16 +178,17 @@ class MessagePreviewPresenter @Inject constructor(
view?.run {
showContent(false)
showProgress(true)
- showOptions(false)
+ showOptions(show = false, isReplayable = false)
showErrorView(false)
}
- Timber.i("Delete message ${message?.id}")
+ Timber.i("Delete message ${message?.messageGlobalKey}")
presenterScope.launch {
runCatching {
- val student = studentRepository.getCurrentStudent()
- messageRepository.deleteMessage(student, message!!)
+ val student = studentRepository.getCurrentStudent(decryptPass = true)
+ val mailbox = mailboxRepository.getMailbox(student)
+ messageRepository.deleteMessage(student, mailbox, message!!)
}
.onFailure {
retryCallback = { onMessageDelete() }
@@ -211,7 +222,10 @@ class MessagePreviewPresenter @Inject constructor(
private fun initOptions() {
view?.apply {
- showOptions(message != null)
+ showOptions(
+ show = message != null,
+ isReplayable = message?.folderId != MessageFolder.SENT.id,
+ )
message?.let {
when (it.folderId == MessageFolder.TRASHED.id) {
true -> setDeletedOptionsLabels()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt
index 88fe77d94..c5a947939 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt
@@ -28,7 +28,7 @@ interface MessagePreviewView : BaseView {
fun setErrorRetryCallback(callback: () -> Unit)
- fun showOptions(show: Boolean)
+ fun showOptions(show: Boolean, isReplayable: Boolean)
fun setDeletedOptionsLabels()
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageActivity.kt
index 70f9a9b54..334e389e2 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageActivity.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageActivity.kt
@@ -6,6 +6,7 @@ import android.content.Context
import android.content.Intent
import android.graphics.Rect
import android.os.Bundle
+import android.text.Spanned
import android.view.Menu
import android.view.MenuItem
import android.view.TouchDelegate
@@ -13,11 +14,12 @@ import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
+import androidx.core.text.parseAsHtml
+import androidx.core.text.toHtml
import androidx.core.widget.doOnTextChanged
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Message
-import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.databinding.ActivitySendMessageBinding
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.utils.dpToPx
@@ -72,17 +74,32 @@ class SendMessageActivity : BaseActivity
formSubjectValue = binding.sendMessageSubject.text.toString()
- formContentValue = binding.sendMessageMessageContent.text.toString()
+ formContentValue =
+ binding.sendMessageMessageContent.text.toString().parseAsHtml().toString()
presenter.onAttachView(
view = this,
@@ -110,7 +127,7 @@ class SendMessageActivity : BaseActivity) {
@@ -165,7 +182,7 @@ class SendMessageActivity : BaseActivity "Re: "
+ true -> "RE: "
else -> "FW: "
} + message.subject
)
if (preferencesRepository.fillMessageContent || reply != true) {
- setContent(
- when (reply) {
- true -> "\n\n"
- else -> ""
- } + when (message.sender.isNotEmpty()) {
- true -> "Od: ${message.sender}\n"
- false -> "Do: ${message.recipient}\n"
- } + "Data: ${message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")}\n\n${message.content}"
- )
+ setContent(buildString {
+ if (reply == true) {
+ append("
")
+ }
+
+ append("Od: ${message.sender}
")
+ append("Do: ${message.recipients}
")
+ append("Data: ${message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")}
")
+ append(message.content)
+ })
}
}
}
@@ -111,21 +113,24 @@ class SendMessagePresenter @Inject constructor(
private fun loadData(message: Message?, reply: Boolean?) {
resourceFlow {
val student = studentRepository.getCurrentStudent()
- val semester = semesterRepository.getCurrentSemester(student)
- val unit = reportingUnitRepository.getReportingUnit(student, semester.unitId)
+ val mailbox = mailboxRepository.getMailbox(student)
Timber.i("Loading recipients started")
- val recipients = when {
- unit != null -> recipientRepository.getRecipients(student, unit, 2)
- else -> listOf()
- }.let { createChips(it) }
+ val recipients = createChips(
+ recipients = recipientRepository.getRecipients(
+ student = student,
+ mailbox = mailbox,
+ type = MailboxType.EMPLOYEE,
+ )
+ )
Timber.i("Loading recipients result: Success, fetched %d recipients", recipients.size)
Timber.i("Loading message recipients started")
val messageRecipients = when {
- message != null && reply == true -> recipientRepository.getMessageRecipients(
- student,
- message
+ message != null && reply == true -> recipientRepository.getMessageSender(
+ student = student,
+ message = message,
+ mailbox = mailbox,
)
else -> emptyList()
}.let { createChips(it) }
@@ -134,7 +139,7 @@ class SendMessagePresenter @Inject constructor(
messageRecipients.size
)
- Triple(unit, recipients, messageRecipients)
+ Triple(mailbox, recipients, messageRecipients)
}
.logResourceStatus("load recipients")
.onEach {
@@ -143,19 +148,14 @@ class SendMessagePresenter @Inject constructor(
showProgress(true)
showContent(false)
}
- is Resource.Success -> it.data.let { (reportingUnit, recipientChips, selectedRecipientChips) ->
+ is Resource.Success -> it.data.let { (mailbox, recipientChips, selectedRecipientChips) ->
view?.run {
- if (reportingUnit != null) {
- setReportingUnit(reportingUnit)
- setRecipients(recipientChips)
- if (selectedRecipientChips.isNotEmpty()) setSelectedRecipients(
- selectedRecipientChips
- )
- showContent(true)
- } else {
- Timber.i("Loading recipients result: Can't find the reporting unit")
- view?.showEmpty(true)
- }
+ setMailbox(getMailboxName(mailbox))
+ setRecipients(recipientChips)
+ if (selectedRecipientChips.isNotEmpty()) setSelectedRecipients(
+ selectedRecipientChips
+ )
+ showContent(true)
}
}
is Resource.Error -> {
@@ -171,7 +171,14 @@ class SendMessagePresenter @Inject constructor(
private fun sendMessage(subject: String, content: String, recipients: List) {
resourceFlow {
val student = studentRepository.getCurrentStudent()
- messageRepository.sendMessage(student, subject, content, recipients)
+ val mailbox = mailboxRepository.getMailbox(student)
+ messageRepository.sendMessage(
+ student = student,
+ subject = subject,
+ content = content,
+ recipients = recipients,
+ mailboxId = mailbox.globalKey,
+ )
}.logResourceStatus("sending message").onEach {
when (it) {
is Resource.Loading -> view?.run {
@@ -201,31 +208,44 @@ class SendMessagePresenter @Inject constructor(
}
private fun createChips(recipients: List): List {
- fun generateCorrectSummary(recipientRealName: String): String {
- val substring = recipientRealName.substringBeforeLast("-")
- return when {
- substring == recipientRealName -> recipientRealName
- substring.indexOf("(") != -1 -> {
- recipientRealName.indexOf("(")
- .let { recipientRealName.substring(if (it != -1) it else 0) }
- }
- substring.indexOf("[") != -1 -> {
- recipientRealName.indexOf("[")
- .let { recipientRealName.substring(if (it != -1) it else 0) }
- }
- else -> recipientRealName.substringAfter("-")
- }.trim()
- }
-
return recipients.map {
RecipientChipItem(
- title = it.name,
- summary = generateCorrectSummary(it.realName),
+ title = it.userName,
+ summary = buildString {
+ getMailboxType(it.type)?.let(::append)
+ if (isNotBlank()) append(" ")
+
+ append("(${it.schoolShortName})")
+ },
recipient = it
)
}
}
+ private fun getMailboxName(mailbox: Mailbox): String {
+ return buildString {
+ append(mailbox.userName)
+ append(" - ")
+ append(getMailboxType(mailbox.type))
+
+ if (mailbox.type == MailboxType.PARENT) {
+ append(" - ")
+ append(mailbox.studentName)
+ }
+
+ append(" - ")
+ append("(${mailbox.schoolNameShort})")
+ }
+ }
+
+ private fun getMailboxType(type: MailboxType): String? = when (type) {
+ MailboxType.STUDENT -> view?.mailboxStudent
+ MailboxType.PARENT -> view?.mailboxParent
+ MailboxType.GUARDIAN -> view?.mailboxGuardian
+ MailboxType.EMPLOYEE -> view?.mailboxEmployee
+ MailboxType.UNKNOWN -> null
+ }
+
fun onMessageContentChange() {
presenterScope.launch {
messageUpdateChannel.send(Unit)
@@ -263,7 +283,7 @@ class SendMessagePresenter @Inject constructor(
fun getRecipientsNames(): String {
return messageRepository.draftMessage?.recipients.orEmpty()
- .joinToString { it.recipient.name }
+ .joinToString { it.recipient.userName }
}
fun clearDraft() {
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageView.kt
index 21b42e3e4..1057114b8 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageView.kt
@@ -1,6 +1,6 @@
package io.github.wulkanowy.ui.modules.message.send
-import io.github.wulkanowy.data.db.entities.ReportingUnit
+import io.github.wulkanowy.data.db.entities.Mailbox
import io.github.wulkanowy.ui.base.BaseView
interface SendMessageView : BaseView {
@@ -18,9 +18,17 @@ interface SendMessageView : BaseView {
val messageSuccess: String
+ val mailboxStudent: String
+
+ val mailboxParent: String
+
+ val mailboxGuardian: String
+
+ val mailboxEmployee: String
+
fun initView()
- fun setReportingUnit(unit: ReportingUnit)
+ fun setMailbox(mailbox: String)
fun setRecipients(recipients: List)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt
index af0923b94..55f03ef84 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt
@@ -8,7 +8,6 @@ import androidx.core.view.isVisible
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import io.github.wulkanowy.R
-import io.github.wulkanowy.data.enums.MessageFolder
import io.github.wulkanowy.databinding.ItemMessageBinding
import io.github.wulkanowy.databinding.ItemMessageChipsBinding
import io.github.wulkanowy.utils.toFormattedString
@@ -88,12 +87,8 @@ class MessageTabAdapter @Inject constructor() :
with(holder.binding) {
val style = if (message.unread) Typeface.BOLD else Typeface.NORMAL
- messageItemAuthor.run {
- text = if (message.folderId == MessageFolder.SENT.id) {
- message.recipient
- } else {
- message.sender
- }
+ with(messageItemAuthor) {
+ text = message.correspondents
setTypeface(null, style)
}
messageItemSubject.run {
@@ -145,7 +140,7 @@ class MessageTabAdapter @Inject constructor() :
val newItem = new[newItemPosition]
return if (oldItem is MessageTabDataItem.MessageItem && newItem is MessageTabDataItem.MessageItem) {
- oldItem.message.id == newItem.message.id
+ oldItem.message.messageGlobalKey == newItem.message.messageGlobalKey
} else {
oldItem.viewType == newItem.viewType
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt
index 870b6433e..54711a689 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt
@@ -3,8 +3,8 @@ package io.github.wulkanowy.ui.modules.message.tab
import io.github.wulkanowy.data.*
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.enums.MessageFolder
+import io.github.wulkanowy.data.repositories.MailboxRepository
import io.github.wulkanowy.data.repositories.MessageRepository
-import io.github.wulkanowy.data.repositories.SemesterRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
@@ -26,7 +26,7 @@ class MessageTabPresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
private val messageRepository: MessageRepository,
- private val semesterRepository: SemesterRepository,
+ private val mailboxRepository: MailboxRepository,
private val analytics: AnalyticsHelper
) : BasePresenter(errorHandler, studentRepository) {
@@ -122,7 +122,8 @@ class MessageTabPresenter @Inject constructor(
runCatching {
val student = studentRepository.getCurrentStudent(true)
- messageRepository.deleteMessages(student, messageList)
+ val mailbox = mailboxRepository.getMailbox(student)
+ messageRepository.deleteMessages(student, mailbox, messageList)
}
.onFailure(errorHandler::dispatch)
.onSuccess { view?.showMessagesDeleted() }
@@ -159,7 +160,7 @@ class MessageTabPresenter @Inject constructor(
}
fun onMessageItemSelected(messageItem: MessageTabDataItem.MessageItem, position: Int) {
- Timber.i("Select message ${messageItem.message.id} item (position: $position)")
+ Timber.i("Select message ${messageItem.message.messageGlobalKey} item (position: $position)")
if (!isActionMode) {
view?.run {
@@ -206,8 +207,8 @@ class MessageTabPresenter @Inject constructor(
flatResourceFlow {
val student = studentRepository.getCurrentStudent()
- val semester = semesterRepository.getCurrentSemester(student)
- messageRepository.getMessages(student, semester, folder, forceRefresh)
+ val mailbox = mailboxRepository.getMailbox(student)
+ messageRepository.getMessages(student, mailbox, folder, forceRefresh)
}
.logResourceStatus("load $folder message")
.onResourceData {
@@ -333,7 +334,7 @@ class MessageTabPresenter @Inject constructor(
addAll(data.map { message ->
MessageTabDataItem.MessageItem(
message = message,
- isSelected = messagesToDelete.any { it.id == message.id },
+ isSelected = messagesToDelete.any { it.messageGlobalKey == message.messageGlobalKey },
isActionMode = isActionMode
)
})
@@ -345,10 +346,9 @@ class MessageTabPresenter @Inject constructor(
private fun calculateMatchRatio(message: Message, query: String): Int {
val subjectRatio = FuzzySearch.tokenSortPartialRatio(query.lowercase(), message.subject)
- val senderOrRecipientRatio = FuzzySearch.tokenSortPartialRatio(
+ val correspondentsRatio = FuzzySearch.tokenSortPartialRatio(
query.lowercase(),
- if (message.sender.isNotEmpty()) message.sender.lowercase()
- else message.recipient.lowercase()
+ message.correspondents
)
val dateRatio = listOf(
@@ -364,7 +364,7 @@ class MessageTabPresenter @Inject constructor(
return (subjectRatio.toDouble().pow(2)
- + senderOrRecipientRatio.toDouble().pow(2)
+ + correspondentsRatio.toDouble().pow(2)
+ dateRatio.toDouble().pow(2) * 2
).toInt()
}
diff --git a/app/src/main/res/layout/activity_send_message.xml b/app/src/main/res/layout/activity_send_message.xml
index 10b581f77..320782bdc 100644
--- a/app/src/main/res/layout/activity_send_message.xml
+++ b/app/src/main/res/layout/activity_send_message.xml
@@ -16,8 +16,7 @@
app:layout_constraintBottom_toTopOf="@id/sendMessageScroll"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- tools:targetApi="lollipop" />
+ app:layout_constraintTop_toTopOf="parent" />
Move to trash
Delete permanently
Message deleted successfully
+ student
+ parent
+ guardian
+ employee
Share
Print
Subject
@@ -300,7 +304,6 @@
Only unread
Only with attachments
Read: %s
- Read by: %1$d of %2$d people
- %1$d message
- %1$d messages
diff --git a/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt b/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt
index 225399306..ff0a53135 100644
--- a/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt
+++ b/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt
@@ -1,5 +1,7 @@
package io.github.wulkanowy
+import io.github.wulkanowy.data.db.entities.Mailbox
+import io.github.wulkanowy.data.db.entities.MailboxType
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
@@ -21,6 +23,16 @@ fun getSemesterEntity(diaryId: Int = 1, semesterId: Int = 1, start: LocalDate =
end = end
)
+fun getMailboxEntity() = Mailbox(
+ globalKey = "v4",
+ fullName = "",
+ userName = "",
+ userLoginId = 0,
+ studentName = "",
+ schoolNameShort = "",
+ type = MailboxType.UNKNOWN,
+)
+
fun getSemesterPojo(diaryId: Int, semesterId: Int, start: LocalDate, end: LocalDate, semesterName: Int = 1) = SdkSemester(
diaryId = diaryId,
kindergartenDiaryId = 0,
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
index 2a5d2e2b4..24306bfeb 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
@@ -10,12 +10,10 @@ import io.github.wulkanowy.data.db.entities.MessageWithAttachment
import io.github.wulkanowy.data.enums.MessageFolder
import io.github.wulkanowy.data.errorOrNull
import io.github.wulkanowy.data.toFirstResult
-import io.github.wulkanowy.getSemesterEntity
+import io.github.wulkanowy.getMailboxEntity
import io.github.wulkanowy.getStudentEntity
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Folder
-import io.github.wulkanowy.sdk.pojo.MessageDetails
-import io.github.wulkanowy.sdk.pojo.Sender
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.Status
import io.github.wulkanowy.utils.status
@@ -23,7 +21,6 @@ import io.mockk.*
import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking
@@ -60,7 +57,7 @@ class MessageRepositoryTest {
private val student = getStudentEntity()
- private val semester = getSemesterEntity()
+ private val mailbox = getMailboxEntity()
private lateinit var repository: MessageRepository
@@ -80,59 +77,18 @@ class MessageRepositoryTest {
)
}
- @Test
- fun `get messages when read by values was changed on already read message`() = runTest {
- every { messageDb.loadAll(any(), any()) } returns flow {
- val dbMessage = getMessageEntity(3, "", false).apply {
- unreadBy = 10
- readBy = 5
- isNotified = true
- }
- emit(listOf(dbMessage))
- }
- coEvery { sdk.getMessages(Folder.RECEIVED, any(), any()) } returns listOf(
- getMessageDto(messageId = 3, content = "", unread = false).copy(
- unreadBy = 5,
- readBy = 10,
- )
- )
- coEvery { messageDb.deleteAll(any()) } just Runs
- coEvery { messageDb.insertAll(any()) } returns listOf()
-
- repository.getMessages(
- student = student,
- semester = semester,
- folder = MessageFolder.RECEIVED,
- forceRefresh = true,
- notify = true, // all new messages will be marked as not notified
- ).toFirstResult().dataOrNull.orEmpty()
-
- coVerify(exactly = 1) { messageDb.deleteAll(emptyList()) }
- coVerify(exactly = 1) { messageDb.insertAll(emptyList()) }
- coVerify(exactly = 1) {
- messageDb.updateAll(withArg {
- assertEquals(1, it.size)
- assertEquals(5, it.single().unreadBy)
- assertEquals(10, it.single().readBy)
- })
- }
- }
-
@Test
fun `get messages when fetched completely new message without notify`() = runBlocking {
every { messageDb.loadAll(any(), any()) } returns flowOf(emptyList())
- coEvery { sdk.getMessages(Folder.RECEIVED, any(), any()) } returns listOf(
- getMessageDto(messageId = 4, content = "Test", unread = true).copy(
- unreadBy = 5,
- readBy = 10,
- )
+ coEvery { sdk.getMessages(Folder.RECEIVED, any()) } returns listOf(
+ getMessageDto()
)
coEvery { messageDb.deleteAll(any()) } just Runs
coEvery { messageDb.insertAll(any()) } returns listOf()
repository.getMessages(
student = student,
- semester = semester,
+ mailbox = mailbox,
folder = MessageFolder.RECEIVED,
forceRefresh = true,
notify = false,
@@ -151,7 +107,7 @@ class MessageRepositoryTest {
fun `throw error when message is not in the db`() {
val testMessage = getMessageEntity(1, "", false)
coEvery {
- messageDb.loadMessageWithAttachment(1, 1)
+ messageDb.loadMessageWithAttachment("v4")
} throws NoSuchElementException("No message in database")
runBlocking { repository.getMessage(student, testMessage).toFirstResult() }
@@ -162,7 +118,7 @@ class MessageRepositoryTest {
val testMessage = getMessageEntity(123, "Test", false)
val messageWithAttachment = MessageWithAttachment(testMessage, emptyList())
- coEvery { messageDb.loadMessageWithAttachment(1, testMessage.messageId) } returns flowOf(
+ coEvery { messageDb.loadMessageWithAttachment("v4") } returns flowOf(
messageWithAttachment
)
@@ -174,7 +130,7 @@ class MessageRepositoryTest {
}
@Test
- fun `get message when content in db is empty`() {
+ fun `get message when content in db is empty`() = runTest {
val testMessage = getMessageEntity(123, "", true)
val testMessageWithContent = testMessage.copy().apply { content = "Test" }
@@ -182,23 +138,19 @@ class MessageRepositoryTest {
val mWaWithContent = MessageWithAttachment(testMessageWithContent, emptyList())
coEvery {
- messageDb.loadMessageWithAttachment(
- 1,
- testMessage.messageId
- )
+ messageDb.loadMessageWithAttachment("v4")
} returnsMany listOf(flowOf(mWa), flowOf(mWaWithContent))
coEvery {
- sdk.getMessageDetails(
- messageId = testMessage.messageId,
- folderId = 1,
- read = false,
- id = testMessage.realId
- )
- } returns MessageDetails("Test", emptyList())
+ sdk.getMessageDetails("v4")
+ } returns mockk {
+ every { sender } returns ""
+ every { recipients } returns listOf("")
+ every { attachments } returns listOf()
+ }
coEvery { messageDb.updateAll(any()) } just Runs
coEvery { messageAttachmentDao.insertAttachments(any()) } returns listOf(1)
- val res = runBlocking { repository.getMessage(student, testMessage).toFirstResult() }
+ val res = repository.getMessage(student, testMessage).toFirstResult()
assertEquals(null, res.errorOrNull)
assertEquals(Status.SUCCESS, res.status)
@@ -211,7 +163,7 @@ class MessageRepositoryTest {
val testMessage = getMessageEntity(123, "", false)
coEvery {
- messageDb.loadMessageWithAttachment(1, testMessage.messageId)
+ messageDb.loadMessageWithAttachment("v4")
} throws UnknownHostException()
runBlocking { repository.getMessage(student, testMessage).toFirstResult() }
@@ -222,7 +174,7 @@ class MessageRepositoryTest {
val testMessage = getMessageEntity(123, "", true)
coEvery {
- messageDb.loadMessageWithAttachment(1, testMessage.messageId)
+ messageDb.loadMessageWithAttachment("v4")
} throws UnknownHostException()
runBlocking { repository.getMessage(student, testMessage).toList()[1] }
@@ -233,42 +185,30 @@ class MessageRepositoryTest {
content: String,
unread: Boolean
) = Message(
- studentId = 1,
- realId = 1,
+ messageGlobalKey = "v4",
+ mailboxKey = "",
+ correspondents = "",
messageId = messageId,
- sender = "",
- senderId = 0,
- recipient = "Wielu adresatów",
subject = "",
date = Instant.EPOCH,
folderId = 1,
unread = unread,
- removed = false,
hasAttachments = false
).apply {
this.content = content
- unreadBy = 1
- readBy = 1
}
- private fun getMessageDto(
- messageId: Int,
- content: String,
- unread: Boolean,
- ) = io.github.wulkanowy.sdk.pojo.Message(
- id = 1,
- messageId = messageId,
- sender = Sender("", "", 0, 0, 0, ""),
+ private fun getMessageDto() = io.github.wulkanowy.sdk.pojo.Message(
+ globalKey = "v4",
+ mailbox = "",
+ correspondents = "",
+ id = 4,
recipients = listOf(),
subject = "",
- content = content,
- date = Instant.EPOCH.atZone(ZoneOffset.UTC).toLocalDateTime(),
+ content = "Test",
dateZoned = Instant.EPOCH.atZone(ZoneOffset.UTC),
folderId = 1,
- unread = unread,
- unreadBy = 0,
- readBy = 0,
- removed = false,
+ unread = true,
hasAttachments = false,
)
}
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/RecipientLocalTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/RecipientLocalTest.kt
index 980abac0a..ae73a7958 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/RecipientLocalTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/RecipientLocalTest.kt
@@ -1,19 +1,15 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.RecipientDao
-import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.mappers.mapToEntities
+import io.github.wulkanowy.getMailboxEntity
import io.github.wulkanowy.getStudentEntity
import io.github.wulkanowy.sdk.Sdk
+import io.github.wulkanowy.sdk.pojo.MailboxType
import io.github.wulkanowy.utils.AutoRefreshHelper
-import io.mockk.MockKAnnotations
-import io.mockk.Runs
-import io.mockk.coEvery
-import io.mockk.coVerify
-import io.mockk.every
+import io.mockk.*
import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
-import io.mockk.just
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Before
@@ -36,9 +32,30 @@ class RecipientLocalTest {
private lateinit var recipientRepository: RecipientRepository
private val remoteList = listOf(
- SdkRecipient("2rPracownik", "Kowalski Jan", 3, 4, 2, "hash", "Kowalski Jan [KJ] - Pracownik (Fake123456)"),
- SdkRecipient("3rPracownik", "Kowalska Karolina", 4, 4, 2, "hash", "Kowalska Karolina [KK] - Pracownik (Fake123456)"),
- SdkRecipient("4rPracownik", "Krupa Stanisław", 5, 4, 1, "hash", "Krupa Stanisław [KS] - Uczeń (Fake123456)")
+ SdkRecipient(
+ mailboxGlobalKey = "2rPracownik",
+ userName = "Kowalski Jan",
+ fullName = "Kowalski Jan [KJ] - Pracownik (Fake123456)",
+ studentName = "",
+ schoolNameShort = "",
+ type = MailboxType.UNKNOWN,
+ ),
+ SdkRecipient(
+ mailboxGlobalKey = "3rPracownik",
+ userName = "Kowalska Karolina",
+ fullName = "Kowalska Karolina [KK] - Pracownik (Fake123456)",
+ studentName = "",
+ schoolNameShort = "",
+ type = MailboxType.UNKNOWN,
+ ),
+ SdkRecipient(
+ mailboxGlobalKey = "4rPracownik",
+ userName = "Krupa Stanisław",
+ fullName = "Krupa Stanisław [KS] - Uczeń (Fake123456)",
+ studentName = "",
+ schoolNameShort = "",
+ type = MailboxType.UNKNOWN,
+ )
)
@Before
@@ -52,39 +69,61 @@ class RecipientLocalTest {
@Test
fun `load recipients when items already in database`() {
// prepare
- coEvery { recipientDb.loadAll(4, 123, 7) } returnsMany listOf(
- remoteList.mapToEntities(4),
- remoteList.mapToEntities(4)
+ coEvery { recipientDb.loadAll(io.github.wulkanowy.data.db.entities.MailboxType.UNKNOWN, "v4") } returnsMany listOf(
+ remoteList.mapToEntities("v4"),
+ remoteList.mapToEntities("v4")
)
coEvery { recipientDb.insertAll(any()) } returns listOf(1, 2, 3)
coEvery { recipientDb.deleteAll(any()) } just Runs
// execute
- val res = runBlocking { recipientRepository.getRecipients(student, ReportingUnit(4, 123, "", 4, "", listOf()), 7) }
+ val res = runBlocking {
+ recipientRepository.getRecipients(
+ student = student,
+ mailbox = getMailboxEntity(),
+ type = io.github.wulkanowy.data.db.entities.MailboxType.UNKNOWN,
+ )
+ }
// verify
assertEquals(3, res.size)
- coVerify { recipientDb.loadAll(4, 123, 7) }
+ coVerify {
+ recipientDb.loadAll(
+ type = io.github.wulkanowy.data.db.entities.MailboxType.UNKNOWN,
+ studentMailboxGlobalKey = "v4"
+ )
+ }
}
@Test
fun `load recipients when database is empty`() {
// prepare
- coEvery { sdk.getRecipients(123, 7) } returns remoteList
- coEvery { recipientDb.loadAll(4, 123, 7) } returnsMany listOf(
+ coEvery { sdk.getRecipients("v4") } returns remoteList
+ coEvery {
+ recipientDb.loadAll(
+ io.github.wulkanowy.data.db.entities.MailboxType.UNKNOWN,
+ "v4"
+ )
+ } returnsMany listOf(
emptyList(),
- remoteList.mapToEntities(4)
+ remoteList.mapToEntities("v4")
)
coEvery { recipientDb.insertAll(any()) } returns listOf(1, 2, 3)
coEvery { recipientDb.deleteAll(any()) } just Runs
// execute
- val res = runBlocking { recipientRepository.getRecipients(student, ReportingUnit(4, 123, "", 4, "", listOf()), 7) }
+ val res = runBlocking {
+ recipientRepository.getRecipients(
+ student = student,
+ mailbox = getMailboxEntity(),
+ type = io.github.wulkanowy.data.db.entities.MailboxType.UNKNOWN,
+ )
+ }
// verify
assertEquals(3, res.size)
- coVerify { sdk.getRecipients(123, 7) }
- coVerify { recipientDb.loadAll(4, 123, 7) }
+ coVerify { sdk.getRecipients("v4") }
+ coVerify { recipientDb.loadAll(io.github.wulkanowy.data.db.entities.MailboxType.UNKNOWN, "v4") }
coVerify { recipientDb.insertAll(match { it.isEmpty() }) }
coVerify { recipientDb.deleteAll(match { it.isEmpty() }) }
}
From bc0689a30df9ac9c7b35a802256e1922dbbe8264 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 22 Aug 2022 13:28:27 +0000
Subject: [PATCH 069/164] Bump coil from 2.1.0 to 2.2.0 (#1949)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 0efb9c303..d86f5f430 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -236,7 +236,7 @@ dependencies {
implementation "at.favre.lib:slf4j-timber:1.0.1"
implementation 'com.github.bastienpaulfr:Treessence:1.0.5'
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
- implementation "io.coil-kt:coil:2.1.0"
+ implementation "io.coil-kt:coil:2.2.0"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
From d9e22af5ef0672de79b122af8dfca08b5743ca49 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 22 Aug 2022 13:28:58 +0000
Subject: [PATCH 070/164] Bump desugar_jdk_libs from 1.1.5 to 1.1.6 (#1948)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index d86f5f430..efa9b3e09 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -188,7 +188,7 @@ ext {
dependencies {
implementation "io.github.wulkanowy:sdk:dbe87aac"
- coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
+ coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.6'
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
From 71f1a55437e3b447b8d3e6b4fa87713c3f382027 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Borcz?=
Date: Mon, 22 Aug 2022 16:45:59 +0200
Subject: [PATCH 071/164] New Crowdin updates (#1895)
---
.../main/res/values-cs/preferences_values.xml | 2 +-
app/src/main/res/values-cs/strings.xml | 14 ++++++++++++--
.../main/res/values-de/preferences_values.xml | 2 +-
app/src/main/res/values-de/strings.xml | 14 ++++++++++++--
app/src/main/res/values-pl/strings.xml | 16 +++++++++++++---
app/src/main/res/values-ru/strings.xml | 14 ++++++++++++--
.../main/res/values-sk/preferences_values.xml | 2 +-
app/src/main/res/values-sk/strings.xml | 16 +++++++++++++---
app/src/main/res/values-uk/strings.xml | 14 ++++++++++++--
9 files changed, 77 insertions(+), 17 deletions(-)
diff --git a/app/src/main/res/values-cs/preferences_values.xml b/app/src/main/res/values-cs/preferences_values.xml
index c8731372f..23073adf1 100644
--- a/app/src/main/res/values-cs/preferences_values.xml
+++ b/app/src/main/res/values-cs/preferences_values.xml
@@ -34,7 +34,7 @@
- Abecedně
- Podle data
- - By average
+ - Podle průměru
- Dzienniczek+
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 11054a0e5..5f76bb6e1 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -77,6 +77,9 @@
Přihlásit se
Relace vypršela
Relace vypršela. Přihlaste se prosím znovu
+ Podpora aplikace
+ Líbí se Vám tato aplikace? Podpořte její vývoj tím, že povolíte neinvazivní reklamy, které můžete kdykoliv vypnout
+ Zapnout reklamy
Známka
Semestr %d
@@ -94,7 +97,7 @@
Předpokládaná známka
Vypočítaný průměr
Jak funguje vypočítaný průměr?
- Vypočítaný průměr je aritmetický průměr vypočítaný z průměrů předmětů. Umožňuje vám to znát přibližný konečný průměr. Vypočítává se způsobem zvoleným uživatelem v nastavení aplikaci. Doporučuje se vybrat příslušnou možnost. Důvodem je rozdílný výpočet školních průměrů. Pokud vaše škola navíc uvádí průměr předmětů na stránce deníku Vulcan, aplikace si je stáhne a tyto průměry nepočítá. To lze změnit vynucením výpočtu průměru v nastavení aplikaci.\n\nPrůměr známek pouze z vybraného semestru:\n1. Výpočet váženého průměru pro každý předmět v daném semestru\n2. Sčítání vypočítaných průměrů\n3. Výpočet aritmetického průměru součtených průměrů\n\nPrůměr průměrů z obou semestrů:\n1. Výpočet váženého průměru pro každý předmět v semestru 1 a 2\n2. Výpočet aritmetického průměru vypočítaných průměrů za semestry 1 a 2 pro každý předmět.\n3. Sčítání vypočítaných průměrů\n4. Výpočet aritmetického průměru sečtených průměrů\n\nPrůměr známek z celého roku:\n1. Výpočet váženého průměru za rok pro každý předmět. Konečný průměr v 1. semestru je nepodstatný.\n3. Sčítání vypočítaných průměrů\n4. Výpočet aritmetického průměru součtených průměrů
+ Vypočítaný průměr je aritmetický průměr vypočítaný z průměrů předmětů. Umožňuje vám to znát přibližný konečný průměr. Vypočítává se způsobem zvoleným uživatelem v nastavení aplikaci. Doporučuje se vybrat příslušnou možnost. Důvodem je rozdílný výpočet školních průměrů. Pokud vaše škola navíc uvádí průměr předmětů na stránce deníku Vulcan, aplikace si je stáhne a tyto průměry nepočítá. To lze změnit vynucením výpočtu průměru v nastavení aplikaci.\n\nPrůměr známek pouze z vybraného semestru:\n1. Výpočet váženého průměru pro každý předmět v daném semestru\n2. Sčítání vypočítaných průměrů\n3. Výpočet aritmetického průměru součtených průměrů\n\nPrůměr průměrů z obou semestrů:\n1. Výpočet váženého průměru pro každý předmět v semestru 1 a 2\n2. Výpočet aritmetického průměru vypočítaných průměrů za semestry 1 a 2 pro každý předmět.\n3. Sčítání vypočítaných průměrů\n4. Výpočet aritmetického průměru sečtených průměrů\n\nPrůměr známek z celého roku:\n1. Výpočet váženého průměru za rok pro každý předmět. Konečný průměr v 1. semestru je nepodstatný.\n2. Sčítání vypočítaných průměrů\n3. Výpočet aritmetického průměru součtených průměrů
Jak funguje konečný průměr?
Konečný průměr je aritmetický průměr vypočítaný ze všech aktuálně dostupných konečných známek v daném semestru.\n\nSchéma výpočtu se skládá z následujících kroků:\n1. Sčítání konečných známek zadaných učiteli\n2. Děleno počtem předmětů, pro které už byly uděleny známky
Konečný průměr
@@ -294,6 +297,10 @@
Přesunout do koše
Odstranit natrvalo
Zpráva byla úspěšně odstraněna
+ žák
+ rodič
+ opatrovník
+ pracovník
Sdílet
Vytisknout
Předmět
@@ -305,7 +312,6 @@
Pouze nepřečtené
Pouze s přílohami
Přečtena: %s
- Přečtena přes: %1$d z %2$d osob
- %1$d zpráva
- %1$d zprávy
@@ -721,6 +727,10 @@
Ochrana osobních údajů
Reklama se načítá
Děkujeme za vaši podporu, vraťte se později pro více reklam
+ Můžeme použít Vaše data k zobrazení reklam?
+ 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ů
+ Přizpůsobené reklamy
+ Nepřizpůsobené reklamy
Pokročilé
Vzhled a chování
Oznámení
diff --git a/app/src/main/res/values-de/preferences_values.xml b/app/src/main/res/values-de/preferences_values.xml
index 097e90e96..d9cac1959 100644
--- a/app/src/main/res/values-de/preferences_values.xml
+++ b/app/src/main/res/values-de/preferences_values.xml
@@ -34,7 +34,7 @@
- Alphabetisch
- Nach Datum
- - By average
+ - Nach Durchschnitt
- Dzienniczek+
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 86308aa19..ef79cee12 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -77,6 +77,9 @@
Anmelden
Die Sitzung ist abgelaufen
Die Sitzung ist abgelaufen, bitte loggen Sie sich erneut ein
+ Anwendungsunterstützung
+ Gefällt Ihnen diese App? Unterstützen Sie ihre Entwicklung, indem Sie nicht-invasive Werbung aktivieren, die Sie jederzeit deaktivieren können
+ Werbung aktivieren
Note
Semester %d
@@ -94,7 +97,7 @@
Vorhergesagte Note
Berechnender Durchschnitt
Wie funktioniert der berechnete Durchschnitt?
- Der berechnete Mittelwert ist das arithmetische Mittel, das aus den Durchschnittswerten der Probanden errechnet wird. Es erlaubt Ihnen, den ungefähre endgültigen Durchschnitt zu kennen. Sie wird auf eine vom Anwender in den Anwendungseinstellungen gewählte Weise berechnet. Es wird empfohlen, die entsprechende Option zu wählen. Das liegt daran, dass die Berechnung der Schuldurchschnitte unterschiedlich ist. Wenn Ihre Schule den Durchschnitt der Fächer auf der Vulcan-Seite angibt, lädt die Anwendung diese Fächer herunter und berechnet nicht den Durchschnitt. Dies kann geändert werden, indem die Berechnung des Durchschnitts in den Anwendungseinstellungen erzwungen wird. \n\nDurchschnitt der Noten nur aus dem ausgewählten Semester :\n1. Berechnung des gewichteten Durchschnitts für jedes Fach in einem bestimmten Semester\n2. Addition der berechneten Durchschnittswerte\n3. Berechnung des arithmetischen Mittels der summierten Durchschnitte\nDurchschnitt der Durchschnitte aus beiden Semestern:\n1. Berechnung des gewichteten Durchschnitts für jedes Fach in Semester 1 und 2\n2. Berechnung des arithmetischen Mittels der berechneten Durchschnitte für Semester 1 und 2 für jedes Fach. \n3. Hinzufügen von berechneten Durchschnittswerten\n4. Berechnung des arithmetischen Mittels der summierten Durchschnitte\nDurchschnitt der Noten aus dem ganzen Jahr:\n1. Berechnung des gewichteten Jahresdurchschnitts für jedes Fach. Der Abschlussdurchschnitt im 1. Semester ist irrelevant. \n3. Addition der berechneten Durchschnittswerte\n4. Berechnung des arithmetischen Mittels der summierten Mittelwerte
+ Der berechnete Mittelwert ist das arithmetische Mittel, das aus den Durchschnittswerten der Probanden errechnet wird. Es erlaubt Ihnen, den ungefähre endgültigen Durchschnitt zu kennen. Sie wird auf eine vom Anwender in den Anwendungseinstellungen gewählte Weise berechnet. Es wird empfohlen, die entsprechende Option zu wählen. Das liegt daran, dass die Berechnung der Schuldurchschnitte unterschiedlich ist. Wenn Ihre Schule den Durchschnitt der Fächer auf der Vulcan-Seite angibt, lädt die Anwendung diese Fächer herunter und berechnet nicht den Durchschnitt. Dies kann geändert werden, indem die Berechnung des Durchschnitts in den Anwendungseinstellungen erzwungen wird. \n\nDurchschnitt der Noten nur aus dem ausgewählten Semester :\n1. Berechnung des gewichteten Durchschnitts für jedes Fach in einem bestimmten Semester\n2. Addition der berechneten Durchschnittswerte\n3. Berechnung des arithmetischen Mittels der summierten Durchschnitte\nDurchschnitt der Durchschnitte aus beiden Semestern:\n1. Berechnung des gewichteten Durchschnitts für jedes Fach in Semester 1 und 2\n2. Berechnung des arithmetischen Mittels der berechneten Durchschnitte für Semester 1 und 2 für jedes Fach. \n3. Hinzufügen von berechneten Durchschnittswerten\n4. Berechnung des arithmetischen Mittels der summierten Durchschnitte\nDurchschnitt der Noten aus dem ganzen Jahr:\n1. Berechnung des gewichteten Jahresdurchschnitts für jedes Fach. Der Abschlussdurchschnitt im 1. Semester ist irrelevant. \n2. Addition der berechneten Durchschnittswerte\n3. Berechnung des arithmetischen Mittels der summierten Mittelwerte
Wie funktioniert der endgültige Durchschnitt?
Der Final Average ist das arithmetische Mittel, das aus allen derzeit verfügbaren Abschlussnoten des jeweiligen Semesters berechnet wird. \n\nDas Berechnungsschema besteht aus folgenden Schritten:\n1. Zusammenfassung der von den Lehrern gegebenen Abschlussnoten\n2. Division durch die Anzahl der Fächer, die bereits bewertet wurden
Finaler Durchschnitt
@@ -260,6 +263,10 @@
In Papierkorb verschieben
Dauerhaft löschen
Nachricht erfolgreich gelöscht
+ schüler
+ Eltern
+ Betreuer
+ Mitarbeiter
Teilen
Drucken
Thema
@@ -271,7 +278,6 @@
Nur ungelesen
Nur mit Anhängen
Lesen: %s
- Lesen von: %1$d von %2$d Personen
- %1$d Nachricht
- %1$d Nachrichten
@@ -633,6 +639,10 @@
Datenschutzerklärung
Anzeige wird geladen
Vielen Dank für Ihre Unterstützung, kommen Sie später wieder für weitere Anzeigen
+ Können wir Ihre Daten zur Anzeige von Werbung verwenden?
+ 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
+ Personalisierte Werbung
+ keine personalisierte Werbung
Erweitert
Aussehen & Verhalten
Benachrichtigungen
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 91e9fe7f3..566519e8c 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -77,6 +77,9 @@
Zaloguj się
Sesja wygasła
Sesja wygasła, zaloguj się ponownie
+ Wparcie aplikacji
+ Podoba Ci się ta aplikacja? Wspieraj jej rozwój poprzez włączenie nieinwazyjnych reklam, które możesz wyłączyć w dowolnym momencie
+ Włącz reklamy
Ocena
Semestr %d
@@ -94,7 +97,7 @@
Przewidywana ocena
Obliczona średnia
Jak działa obliczona średnia?
- Obliczona średnia jest średnią arytmetyczną obliczoną ze średnich przedmiotów. Pozwala ona na poznanie przybliżonej średniej końcowej. Jest obliczana w sposób wybrany przez użytkownika w ustawieniach aplikacji. Zaleca się wybranie odpowiedniej opcji. Dzieje się tak dlatego, że obliczanie średnich w szkołach różni się. Dodatkowo, jeśli twoja szkoła ma włączone średnie przedmiotów na stronie dziennika Vulcan, aplikacja pobiera je i ich nie oblicza. Można to zmienić, wymuszając obliczanie średniej w ustawieniach aplikacji.\n\nŚrednia ocen tylko z wybranego semestru:\n1. Obliczanie średniej arytmetycznej każdego przedmiotu w danym semestrze\n2. Zsumowanie obliczonych średnich\n3. Obliczanie średniej arytmetycznej zsumowanych średnich\n\nŚrednia ze średnich z obu semestrów:\n1.Obliczanie średniej arytmetycznej każdego przedmiotu w semestrze 1 i 2\n2. Obliczanie średniej arytmetycznej obliczonych średnich w semestrze 1 i 2 każdego przedmiotu.\n3. Zsumowanie obliczonych średnich\n4. Obliczanie średniej arytmetycznej zsumowanych średnich\n\nŚrednia wszystkich ocen z całego roku:\n1. Obliczanie średniej arytmetycznej z każdego przedmiotu w ciągu całego roku. Końcowa ocena w 1 semestrze jest bez znaczenia.\n3. Zsumowanie obliczonych średnich\n4. Obliczanie średniej arytmetycznej z zsumowanych średnich
+ Obliczona średnia jest średnią arytmetyczną obliczoną ze średnich przedmiotów. Pozwala ona na poznanie przybliżonej średniej końcowej. Jest obliczana w sposób wybrany przez użytkownika w ustawieniach aplikacji. Zaleca się wybranie odpowiedniej opcji. Dzieje się tak dlatego, że obliczanie średnich w szkołach różni się. Dodatkowo, jeśli twoja szkoła ma włączone średnie przedmiotów na stronie dziennika Vulcan, aplikacja pobiera je i ich nie oblicza. Można to zmienić, wymuszając obliczanie średniej w ustawieniach aplikacji.\n\nŚrednia ocen tylko z wybranego semestru:\n1. Obliczanie średniej arytmetycznej każdego przedmiotu w danym semestrze\n2. Zsumowanie obliczonych średnich\n3. Obliczanie średniej arytmetycznej zsumowanych średnich\n\nŚrednia ze średnich z obu semestrów:\n1.Obliczanie średniej arytmetycznej każdego przedmiotu w semestrze 1 i 2\n2. Obliczanie średniej arytmetycznej obliczonych średnich w semestrze 1 i 2 każdego przedmiotu.\n3. Zsumowanie obliczonych średnich\n4. Obliczanie średniej arytmetycznej zsumowanych średnich\n\nŚrednia wszystkich ocen z całego roku:\n1. Obliczanie średniej arytmetycznej z każdego przedmiotu w ciągu całego roku. Końcowa ocena w 1 semestrze jest bez znaczenia.\n2. Zsumowanie obliczonych średnich\n3. Obliczanie średniej arytmetycznej z zsumowanych średnich
Jak działa końcowa średnia?
Średnią końcową jest średnia arytmetyczna obliczona na podstawie wszystkich obecnie dostępnych ocen końcowych w danym semestrze.\n\nSchemat obliczeń składa się z następujących kroków:\n1. Sumowanie końcowych ocen wpisanych przez nauczycieli\n2. Dzielenie przez liczbę przedmiotów, z których oceny zostały już wystawione
Końcowa średnia
@@ -294,6 +297,10 @@
Przenieś do kosza
Usuń trwale
Wiadomość usunięta pomyślnie
+ uczeń
+ rodzic
+ opiekun
+ pracownik
Udostępnij
Drukuj
Temat
@@ -305,7 +312,6 @@
Tylko nieprzeczytane
Tylko z załącznikami
Przeczytana: %s
- Przeczytana przez: %1$d z %2$d osób
- %1$d wiadomość
- %1$d wiadomości
@@ -701,7 +707,7 @@
Przejdź do ustawień
Synchronizacja
Automatyczna aktualizacja
- Zawieszona na wakacjach
+ Wstrzymana podczas wakacji
Interwał aktualizacji
Tylko WiFi
Synchronizuj teraz
@@ -721,6 +727,10 @@
Polityka prywatności
Ładowanie reklamy
Dziękujemy za wsparcie, wróć później po więcej reklam
+ Czy możemy używać Twoich danych do wyświetlania reklam?
+ 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
+ Spersonalizowane reklamy
+ Niespersonalizowane reklamy
Zaawansowane
Wygląd i zachowanie
Powiadomienia
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 662e0934f..a3c5a62df 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -77,6 +77,9 @@
Войти
Сеанс истёк
Сеанс истёк, авторизуйтесь снова
+ Application support
+ Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time
+ Enable ads
Оценка
%d семестр
@@ -94,7 +97,7 @@
Ожидаемая оценка
Рассчитанная средняя оценка
Как работает \"Рассчитанная средняя оценка\"?
- Рассчитанная средняя оценка - это среднее арифметическое, рассчитанное на основе средних оценок по предметам. Это позволяет узнать приблизительную итоговую среднюю оценку. Она рассчитывается способом, выбранным пользователем в настройках приложения. Рекомендуется выбрать подходящий вариант, так как каждая школа по разному считает среднюю оценку. Кроме того, если ваша школа выставляет средние оценки по предметам на странице Vulcan, приложение просто загрузит их. Это можно изменить, заставив приложение считать среднюю оценку в настройках.\n\nСредняя из оценок выбранного семестра:\n1. Вычисление средневзвешенного значения по каждому предмету за семестр\n2.Суммирование вычисленных значений\n3. Вычисление среднего арифметического суммированных значений\n\nСредняя из средних оценок семестров:\n1.Расчет средневзвешенного значения для каждого предмета в семестрах. \n2. Вычисление среднего арифметического из средневзвешенных значений для каждого предмета в семестрах.\n3. Суммирование средних арифметических\n4. Вычисление среднего арифматического из суммированных значений\n\nСредняя из оценок со всего года:\n1. Расчет средневзвешенного значения по каждому предмету за год. Итоговое среднее значение за 1 семестр не имеет значения.\n2. Суммирование вычисленных средних\n4. Расчет среднего арифметического суммированных чисел
+ The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\nAverage of grades only from selected semester:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\nAverage of averages from both semesters:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\nAverage of grades from the whole year:\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n2. Adding calculated averages\n3. Calculating the arithmetic average of summed averages
Как работает \"Итоговая средняя оценка\"?
Итоговая средняя оценка - это среднее арифметическое, рассчитанное из всех имеющихся на данный момент итоговых оценок в семестре.\n\nРассчет происходит следующим образом:\n1. Суммирование итоговых оценок, выставленных преподавателями\n2. Полученная сумма делится на число предметов, по которым выставлены оценки
Итоговая средняя оценка
@@ -294,6 +297,10 @@
Перенести в корзину
Удалить навсегда
Письмо успешно удалено
+ student
+ parent
+ guardian
+ employee
Поделиться
Печать
Тема
@@ -305,7 +312,6 @@
Только непрочитанные
Только с вложениями
Прочитано: %s
- Прочитано: %1$d из %2$d человек
- %1$d сообщение
- %1$d сообщения
@@ -721,6 +727,10 @@
Политика конфиденциальности
Реклама загружается
Спасибо за вашу поддержку, возвращайтесь позже для дополнительной рекламы
+ Can we use your data to display ads?
+ 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
+ Personalized ads
+ Non-personalized ads
Расширенные
Внешний вид и поведение
Уведомления
diff --git a/app/src/main/res/values-sk/preferences_values.xml b/app/src/main/res/values-sk/preferences_values.xml
index ab0a43b64..e4331315a 100644
--- a/app/src/main/res/values-sk/preferences_values.xml
+++ b/app/src/main/res/values-sk/preferences_values.xml
@@ -34,7 +34,7 @@
- Abecedne
- Podľa dátumu
- - By average
+ - Podľa priemeru
- Dzienniczek+
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index 5ebd1e76b..6a4505d70 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -77,6 +77,9 @@
Prihlásiť sa
Relácia vypršala
Relácia vypršala. Prihláste sa prosím znovu
+ Podpora aplikácie
+ Páči sa Vám táto aplikácia? Podporte jej vývoj tým, že povolíte neinvazívne reklamy, ktoré môžete kedykoľvek vypnúť
+ Zapnúť reklamy
Známka
Semester %d
@@ -94,7 +97,7 @@
Predpokladaná známka
Vypočítaný priemer
Ako funguje vypočítaný priemer?
- Vypočítaný priemer je aritmetický priemer vypočítaný z priemerov predmetov. Umožňuje vám to poznať približný konečný priemer. Vypočítava sa spôsobom zvoleným užívateľom v nastaveniach aplikácii. Odporúča sa vybrať príslušnú možnosť. Dôvodom je rozdielny výpočet školských priemerov. Ak vaša škola navyše uvádza priemer predmetov na stránke denníka Vulcan, aplikácia si ich stiahne a tieto priemery nepočíta. To možno zmeniť vynútením výpočtu priemeru v nastavení aplikácii.\n\nPriemer známok iba z vybraného semestra:\n1. Výpočet váženého priemeru pre každý predmet v danom semestri\n2. Sčítanie vypočítaných priemerov\n3. Výpočet aritmetického priemeru součtených priemerov\n\nPriemer priemerov z oboch semestrov:\n1. Výpočet váženého priemeru pre každý predmet v semestri 1 a 2\n2. Výpočet aritmetického priemeru vypočítaných priemerov za semestre 1 a 2 pre každý predmet.\n3. Sčítanie vypočítaných priemerov\n4. Výpočet aritmetického priemeru součtených priemerov\n\nPriemer známok z celého roka:\n1. Výpočet váženého priemeru za rok pre každý predmet. Konečný priemer v 1. semestri je nepodstatný.\n3. Sčítanie vypočítaných priemerov\n4. Výpočet aritmetického priemeru součtených priemerov
+ Vypočítaný priemer je aritmetický priemer vypočítaný z priemerov predmetov. Umožňuje vám to poznať približný konečný priemer. Vypočítava sa spôsobom zvoleným užívateľom v nastaveniach aplikácii. Odporúča sa vybrať príslušnú možnosť. Dôvodom je rozdielny výpočet školských priemerov. Ak vaša škola navyše uvádza priemer predmetov na stránke denníka Vulcan, aplikácia si ich stiahne a tieto priemery nepočíta. To možno zmeniť vynútením výpočtu priemeru v nastavení aplikácii.\n\nPriemer známok iba z vybraného semestra:\n1. Výpočet váženého priemeru pre každý predmet v danom semestri\n2. Sčítanie vypočítaných priemerov\n3. Výpočet aritmetického priemeru součtených priemerov\n\nPriemer priemerov z oboch semestrov:\n1. Výpočet váženého priemeru pre každý predmet v semestri 1 a 2\n2. Výpočet aritmetického priemeru vypočítaných priemerov za semestre 1 a 2 pre každý predmet.\n3. Sčítanie vypočítaných priemerov\n4. Výpočet aritmetického priemeru součtených priemerov\n\nPriemer známok z celého roka:\n1. Výpočet váženého priemeru za rok pre každý predmet. Konečný priemer v 1. semestri je nepodstatný.\n2. Sčítanie vypočítaných priemerov\n3. Výpočet aritmetického priemeru součtených priemerov
Ako funguje konečný priemer?
Konečný priemer je aritmetický priemer vypočítaný zo všetkých aktuálne dostupných konečných známok v danom semestri.\n\nSchéma výpočtu sa skladá z nasledujúcich krokov:\n1. Sčítanie konečných známok zadaných učiteľmi\n2. Delené počtom predmetov, pre ktoré už boli vydané známky
Konečný priemer
@@ -110,7 +113,7 @@
Váš priemer: %1$s
Vaša známka: %1$s
Trieda
- Žiák
+ Žiak
- %d známka
- %d známky
@@ -294,6 +297,10 @@
Presunúť do koša
Odstrániť natrvalo
Správa bola úspešne odstránená
+ žiak
+ rodič
+ opatrovník
+ pracovník
Zdieľať
Vytlačiť
Predmet
@@ -305,7 +312,6 @@
Iba neprečítané
Iba s prílohami
Prečítaná: %s
- Prečítaná cez: %1$d z %2$d osôb
- %1$d správa
- %1$d správy
@@ -721,6 +727,10 @@
Ochrana osobných údajov
Reklama sa načítava
Ďakujeme za vašu podporu, vráťte sa neskôr pre viac reklám
+ Môžeme použiť Vaše údaje na zobrazenie reklám?
+ 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
+ Prispôsobené reklamy
+ Neprispôsobené reklamy
Pokročilé
Vzhľad a správanie
Oznámenia
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 0cc50dbe5..742e800f3 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -77,6 +77,9 @@
Увійти
Минув термін дії сесії
Минув термін дії сесії, авторизуйтеся знову
+ Application support
+ Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time
+ Enable ads
Оцінка
%d семестр
@@ -94,7 +97,7 @@
Передбачувана оцінка
Розрахована середня оцінка
Як працює \"Розрахована середня оцінка\"?
- Розрахована середня оцінка - це середнє арифметичне, обчислене з середніх оцінок з предметів.Це дозволяє дізнатися приблизну кінцеву середню оцінку.Вона розраховується способом, обраним користувачем у налаштуваннях програми.Рекомендується вибрати відповідний варіант, тому що кожна школа по різному розраховує середню оцінку.Крім того, якщо у вашій школі повідомляється середня оцінка з предметів на сторінці Vulcan, програма тільки завантажує ці оцінки.Це можна змінити шляхом примусового розрахунку середньоЇ оцінки в налаштуваннях програми.\n\nСередні оцінки тільки за обраний семестр:\n1. Розрахунок середньозваженого числа для кожного предмета в даному семестрі\n2. Сумування розрахованих числ\n3. Розрахунок середнього арифметичного з сумованих чисел\n\nСереднє значення з обох семестрів:\n1. Обчислення середньозваженого числа для кожного предмета у 1 та 2 семестрі\n2. Обчислення середнього арифметичного з розрахованих середньозважених числ за 1 та 2 семестри для кожного предмета.\n3. Додавання розрахованих середніх\n4. Розрахунок середнього арифметичного підсумованих середніх значень\n\nСереднє значення оцінок за весь рік: \n1. Розрахунок середньозваженого числа за рік для кожного предмета. Підсумковий середній показник у 1-му семестрі не має значення.\n2. Сумування розрахованих середніх\n3. Обчислення середнього арифметичного з суммованих середніх
+ The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\nAverage of grades only from selected semester:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\nAverage of averages from both semesters:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\nAverage of grades from the whole year:\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n2. Adding calculated averages\n3. Calculating the arithmetic average of summed averages
Як працює \"Підсумкова середня оцінка\"?
Підсумкове середнє значення - це середнє арифметичне, обчислене з усіх наявних наразі підсумкових оцінок у даному семестрі. \n\nСхема обчислення складається з таких кроків:\n1. Сумування підсумкових оцінок, виставленних викладачами\n2. Ділення на кількість предметів, з яких виставлені ці оцінки
Підсумкова середня оцінка
@@ -294,6 +297,10 @@
Перемістити до кошика
Видалити назавжди
Лист було успішно видалено
+ student
+ parent
+ guardian
+ employee
Поділитись
Друк
Тема
@@ -305,7 +312,6 @@
Лише непрочитані
Тільки з вкладеннями
Прочитаний: %s
- Прочитаний: %1$d з %2$d осіб
- %1$d лист
- %1$d листи
@@ -721,6 +727,10 @@
Політика конфіденційності
Реклама завантажується
Дякуємо за вашу підтримку, повертайтеся пізніше для більшої кількості реклам
+ Can we use your data to display ads?
+ 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
+ Personalized ads
+ Non-personalized ads
Додатково
Вигляд та поведінка
Сповіщення
From 09e07a17136cc7266706dc6a8764619cb2ab8277 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Mon, 22 Aug 2022 17:58:35 +0200
Subject: [PATCH 072/164] Version 1.7.0
---
app/build.gradle | 10 +++++-----
app/src/main/play/release-notes/pl-PL/default.txt | 8 ++++++--
2 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index efa9b3e09..e99e8773f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -23,8 +23,8 @@ android {
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 21
targetSdkVersion 32
- versionCode 108
- versionName "1.6.4"
+ versionCode 109
+ versionName "1.7.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "app_name", "Wulkanowy"
@@ -161,8 +161,8 @@ play {
defaultToAppBundles = false
track = 'production'
releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS
- userFraction = 0.50d
- updatePriority = 3
+ userFraction = 0.05d
+ updatePriority = 5
enabled.set(false)
}
@@ -186,7 +186,7 @@ ext {
}
dependencies {
- implementation "io.github.wulkanowy:sdk:dbe87aac"
+ implementation "io.github.wulkanowy:sdk:1.7.0"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.6'
diff --git a/app/src/main/play/release-notes/pl-PL/default.txt b/app/src/main/play/release-notes/pl-PL/default.txt
index b6340bb93..3eb42eb97 100644
--- a/app/src/main/play/release-notes/pl-PL/default.txt
+++ b/app/src/main/play/release-notes/pl-PL/default.txt
@@ -1,5 +1,9 @@
-Wersja 1.6.4
+Wersja 1.7.0
-- naprawiliśmy błąd ładowania frekwencji na GPE i Lubelskim Portalu Oświatowym
+- naprawiliśmy logowanie do aplikacji
+- dodaliśmy wsparcie nowego modułu Wiadomości Plus
+- dodaliśmy nową możliwość wsparcia naszego projektu przez opcjonalne reklamy
+- dodaliśmy sortowanie po średniej
+- naprawiliśmy też kilka usterek wpływających na komfort używania aplikacji
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
From de1bc4809fe93679e89b944e0feb9771e6d3a8cf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Tue, 23 Aug 2022 00:08:39 +0200
Subject: [PATCH 073/164] Fix ads translations (#1951)
---
.github/workflows/deploy-store.yml | 1 +
app/src/main/res/layout/dialog_ads_consent.xml | 12 ++++++------
app/src/main/res/values/strings.xml | 7 +++++++
app/src/play/res/xml/scheme_preferences_ads.xml | 8 ++++----
4 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/.github/workflows/deploy-store.yml b/.github/workflows/deploy-store.yml
index cfb0fb523..3ce618ca7 100644
--- a/.github/workflows/deploy-store.yml
+++ b/.github/workflows/deploy-store.yml
@@ -38,6 +38,7 @@ jobs:
ANDROID_PUBLISHER_CREDENTIALS: ${{ secrets.ANDROID_PUBLISHER_CREDENTIALS }}
ADMOB_PROJECT_ID: ${{ secrets.ADMOB_PROJECT_ID }}
SINGLE_SUPPORT_AD_ID: ${{ secrets.SINGLE_SUPPORT_AD_ID }}
+ DASHBOARD_TILE_AD_ID: ${{ secrets.DASHBOARD_TILE_AD_ID }}
SET_BUILD_TIMESTAMP: ${{ secrets.SET_BUILD_TIMESTAMP }}
run: ./gradlew publishPlayReleaseApps -PenableFirebase --stacktrace;
diff --git a/app/src/main/res/layout/dialog_ads_consent.xml b/app/src/main/res/layout/dialog_ads_consent.xml
index 395101627..816074783 100644
--- a/app/src/main/res/layout/dialog_ads_consent.xml
+++ b/app/src/main/res/layout/dialog_ads_consent.xml
@@ -15,7 +15,7 @@
android:insetRight="0dp"
android:insetBottom="0dp"
android:padding="0dp"
- android:text="Privacy Policy"
+ android:text="@string/pref_ads_privacy_policy"
android:textAllCaps="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -26,9 +26,9 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="17dp"
android:layout_marginTop="8dp"
- android:text="I am over 18 years old"
+ android:text="@string/pref_ads_over_18_years_old"
android:textColor="?android:textColorSecondary"
- android:textSize="14dp"
+ android:textSize="14sp"
app:layout_constraintTop_toBottomOf="@id/ads_consent_privacy" />
@@ -73,7 +73,7 @@
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
- android:text="Cancel"
+ android:text="@android:string/cancel"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0" />
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 2eee4cce4..bcd498036 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -714,6 +714,10 @@
Show arithmetic average when no weights provided
Support
+ Privacy Policy
+ Agreements
+ Consent to processing of data related to ads
+ Show ads in app
Watch single ad to support project
Consent to data processing
To view an advertisement you must agree to the data processing terms of our Privacy Policy
@@ -725,6 +729,9 @@
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
Personalized ads
Non-personalized ads
+ I am over 18 years old
+ Yes, personalized ads
+ Yes, non-personalized ads
Advanced
Appearance & Behavior
diff --git a/app/src/play/res/xml/scheme_preferences_ads.xml b/app/src/play/res/xml/scheme_preferences_ads.xml
index d5e93a355..4165561a7 100644
--- a/app/src/play/res/xml/scheme_preferences_ads.xml
+++ b/app/src/play/res/xml/scheme_preferences_ads.xml
@@ -2,18 +2,18 @@
+ app:title="@string/pref_ads_agreements">
+ app:title="@string/pref_ads_privacy_policy" />
+ app:title="@string/pref_ads_consent" />
+ app:title="@string/pref_ads_show_in_app" />
Date: Tue, 23 Aug 2022 00:54:19 +0200
Subject: [PATCH 074/164] New Crowdin updates (#1952)
---
app/src/main/res/values-cs/strings.xml | 7 +++++++
app/src/main/res/values-de/strings.xml | 7 +++++++
app/src/main/res/values-pl/strings.xml | 7 +++++++
app/src/main/res/values-ru/strings.xml | 7 +++++++
app/src/main/res/values-sk/strings.xml | 7 +++++++
app/src/main/res/values-uk/strings.xml | 7 +++++++
app/src/main/res/values/strings.xml | 4 ++--
7 files changed, 44 insertions(+), 2 deletions(-)
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 5f76bb6e1..d036e7e42 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -720,6 +720,10 @@
Odpovědět s historií zpráv
Vypočítat aritmetický průměr, pokud žádná známka nemá váhu
Podpora
+ Ochrana osobních údajů
+ Souhlasy
+ Souhlas se zpracováním údajů souvisejících s reklamami
+ Zobrazit reklamy v aplikaci
Podívejte se na jednu reklamu pro podporu projektu
Souhlas se zpracováním dat
Jestli chcete sledovat reklamu, musíte souhlasit s podmínkami zpracování údajů v našich Zásadách Ochrany Osobních Údajů
@@ -731,6 +735,9 @@
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ů
Přizpůsobené reklamy
Nepřizpůsobené reklamy
+ Mám ukončené 18 let
+ Ano, přizpůsobené reklamy
+ Ano, nepřizpůsobené reklamy
Pokročilé
Vzhled a chování
Oznámení
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index ef79cee12..4dfeee4f6 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -632,6 +632,10 @@
Antwort mit Nachrichtenhistorie
Arithmetisches Mittel anzeigen, wenn keine Gewichte angegeben sind
Unterstützung
+ Privacy Policy
+ Agreements
+ Consent to processing of data related to ads
+ Show ads in app
Einzelanzeige ansehen, um Projekt zu unterstützen
Einwilligung in die Datenverarbeitung
Um eine Anzeige zu sehen, müssen Sie mit den Datenverarbeitungsbedingungen unserer Datenschutzerklärung einverstanden sein
@@ -643,6 +647,9 @@
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
Personalisierte Werbung
keine personalisierte Werbung
+ I am over 18 years old
+ Yes, personalized ads
+ Yes, non-personalized ads
Erweitert
Aussehen & Verhalten
Benachrichtigungen
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 566519e8c..c9abbd022 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -720,6 +720,10 @@
Odpowiadaj z historią wiadomości
Licz średnią arytmetyczną, gdy żadna ocena nie ma wagi
Wsparcie
+ Polityka prywatności
+ Zgody
+ Zgoda na przetwarzanie danych związanych z reklamami
+ Pokazuj reklamy w aplikacji
Obejrzyj pojedynczą reklamę, aby wesprzeć projekt
Zgoda na przetwarzanie danych
Aby obejrzeć reklamę, musisz zaakceptować warunki przetwarzania danych zawarte w naszej Polityce Prywatności
@@ -731,6 +735,9 @@
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
Spersonalizowane reklamy
Niespersonalizowane reklamy
+ Mam ukończone 18 lat
+ Tak, spersonalizowane reklamy
+ Tak, niespersonalizowane reklamy
Zaawansowane
Wygląd i zachowanie
Powiadomienia
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index a3c5a62df..e1abb0293 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -720,6 +720,10 @@
Отвечать с историей сообщений
Показывать среднее арифметическое при отсутствии стоимости
Поддержка
+ Privacy Policy
+ Agreements
+ Consent to processing of data related to ads
+ Show ads in app
Посмотреть рекламу для поддержки проекта
Согласие на обработку данных
Для просмотра рекламы вы должны согласиться с условиями обработки данных нашей Политики конфиденциальности
@@ -731,6 +735,9 @@
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
Personalized ads
Non-personalized ads
+ I am over 18 years old
+ Yes, personalized ads
+ Yes, non-personalized ads
Расширенные
Внешний вид и поведение
Уведомления
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index 6a4505d70..1c6eae8c0 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -720,6 +720,10 @@
Odpovedať s históriou správ
Vypočítať aritmetický priemer, ak žiadna známka nemá váhu
Podpora
+ Ochrana osobných údajov
+ Súhlasy
+ Súhlas so spracovaním údajov súvisiacich s reklamami
+ Zobraziť reklamy v aplikácii
Pozrite sa na jednu reklamu pre podporu projektu
Súhlas so spracovaním dát
Ak chcete sledovať reklamu, musíte súhlasiť s podmienkami spracovania údajov v našich Zásadách Ochrany Osobných Údajov
@@ -731,6 +735,9 @@
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
Prispôsobené reklamy
Neprispôsobené reklamy
+ Mám ukončené 18 rokov
+ Áno, prispôsobené reklamy
+ Áno, neprispôsobené reklamy
Pokročilé
Vzhľad a správanie
Oznámenia
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 742e800f3..f90e78e7d 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -720,6 +720,10 @@
Відповісти з історією повідомлень
Вилічити середню аритметичну, якщо оцінка немає вартості
Підтримка
+ Privacy Policy
+ Agreements
+ Consent to processing of data related to ads
+ Show ads in app
Подивіться одну рекламу для підтримки проєкту
Згода в обробці даних
Щоб переглянути рекламу, ви повинні погодитися з умовами обробки даних нашої Політики конфіденційності
@@ -731,6 +735,9 @@
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
Personalized ads
Non-personalized ads
+ I am over 18 years old
+ Yes, personalized ads
+ Yes, non-personalized ads
Додатково
Вигляд та поведінка
Сповіщення
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index bcd498036..e4542547d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -714,8 +714,8 @@
Show arithmetic average when no weights provided
Support
- Privacy Policy
- Agreements
+ Privacy Policy
+ Agreements
Consent to processing of data related to ads
Show ads in app
Watch single ad to support project
From 10c36f19bf13234c758b2ac2e96d65a71df8e82c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Tue, 23 Aug 2022 00:56:12 +0200
Subject: [PATCH 075/164] Version 1.7.1
---
app/build.gradle | 6 +++---
app/src/main/play/release-notes/pl-PL/default.txt | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index e99e8773f..5fb07377a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -23,8 +23,8 @@ android {
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 21
targetSdkVersion 32
- versionCode 109
- versionName "1.7.0"
+ versionCode 110
+ versionName "1.7.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "app_name", "Wulkanowy"
@@ -161,7 +161,7 @@ play {
defaultToAppBundles = false
track = 'production'
releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS
- userFraction = 0.05d
+ userFraction = 0.95d
updatePriority = 5
enabled.set(false)
}
diff --git a/app/src/main/play/release-notes/pl-PL/default.txt b/app/src/main/play/release-notes/pl-PL/default.txt
index 3eb42eb97..4b6dcaf28 100644
--- a/app/src/main/play/release-notes/pl-PL/default.txt
+++ b/app/src/main/play/release-notes/pl-PL/default.txt
@@ -1,4 +1,4 @@
-Wersja 1.7.0
+Wersja 1.7.1
- naprawiliśmy logowanie do aplikacji
- dodaliśmy wsparcie nowego modułu Wiadomości Plus
From 70c2cb7dbf717c508bbec08b69931019b2430699 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 29 Aug 2022 13:30:00 +0000
Subject: [PATCH 076/164] Bump desugar_jdk_libs from 1.1.6 to 1.1.8 (#1957)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 5fb07377a..52ae02ddc 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -188,7 +188,7 @@ ext {
dependencies {
implementation "io.github.wulkanowy:sdk:1.7.0"
- coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.6'
+ coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
From f68a8e4215e719ecdfedeb72553ce58df1fcfbf7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 29 Aug 2022 13:30:28 +0000
Subject: [PATCH 077/164] Bump robolectric from 4.8.1 to 4.8.2 (#1956)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 52ae02ddc..1dba83c5d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -263,7 +263,7 @@ dependencies {
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines"
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
- testImplementation 'org.robolectric:robolectric:4.8.1'
+ testImplementation 'org.robolectric:robolectric:4.8.2'
testImplementation "androidx.test:runner:1.4.0"
testImplementation "androidx.test.ext:junit:1.1.3"
testImplementation "androidx.test:core:1.4.0"
From 5c17c38d1d16214db4cc423ffe8556e7b7c64d8b Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 29 Aug 2022 13:30:56 +0000
Subject: [PATCH 078/164] Bump mockk from 1.12.5 to 1.12.7 (#1955)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 1dba83c5d..10648c15f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -181,7 +181,7 @@ ext {
android_hilt = "1.0.0"
room = "2.4.3"
chucker = "3.5.2"
- mockk = "1.12.5"
+ mockk = "1.12.7"
coroutines = "1.6.4"
}
From 54372e0a55e8e903f868d4e47897e9c1a868b505 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 29 Aug 2022 13:40:14 +0000
Subject: [PATCH 079/164] Bump kotlinx-serialization-json from 1.3.3 to 1.4.0
(#1950)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 10648c15f..5977b347b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -190,7 +190,7 @@ dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
- implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3"
+ implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
implementation "androidx.core:core-ktx:1.8.0"
From f2cb3b4f9edd69a1936d3ccb52b3b8eab0e0e320 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Tue, 30 Aug 2022 09:06:29 +0200
Subject: [PATCH 080/164] Change message draft key in shared preferences
(#1959)
---
.../github/wulkanowy/data/repositories/MessageRepository.kt | 4 ++--
app/src/main/res/values/preferences_keys.xml | 3 +--
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt
index 00cbffb84..5a43da4e2 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt
@@ -167,10 +167,10 @@ class MessageRepository @Inject constructor(
}
var draftMessage: MessageDraft?
- get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_send_draft))
+ get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_draft))
?.let { json.decodeFromString(it) }
set(value) = sharedPrefProvider.putString(
- context.getString(R.string.pref_key_message_send_draft),
+ context.getString(R.string.pref_key_message_draft),
value?.let { json.encodeToString(it) }
)
}
diff --git a/app/src/main/res/values/preferences_keys.xml b/app/src/main/res/values/preferences_keys.xml
index f29080b33..80a71bc71 100644
--- a/app/src/main/res/values/preferences_keys.xml
+++ b/app/src/main/res/values/preferences_keys.xml
@@ -31,8 +31,7 @@
homework_fullscreen
subjects_without_grades
optional_arithmetic_average
- message_send_is_draft
- message_send_recipients
+ message_draft
last_sync_date
notifications_piggyback
notifications_piggyback_cancel_original
From 535206056d9b385a5cea1e15a53f0a1c7f37cb4d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Tue, 30 Aug 2022 09:07:07 +0200
Subject: [PATCH 081/164] Fix selecting student mailbox based on studentName
field (#1958)
---
app/build.gradle | 2 +-
.../wulkanowy/data/db/dao/MailboxDao.kt | 3 -
.../data/repositories/MailboxRepository.kt | 11 +-
.../repositories/MailboxRepositoryTest.kt | 132 ++++++++++++++++++
4 files changed, 141 insertions(+), 7 deletions(-)
create mode 100644 app/src/test/java/io/github/wulkanowy/data/repositories/MailboxRepositoryTest.kt
diff --git a/app/build.gradle b/app/build.gradle
index 5977b347b..62eb8e315 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -186,7 +186,7 @@ ext {
}
dependencies {
- implementation "io.github.wulkanowy:sdk:1.7.0"
+ implementation "io.github.wulkanowy:sdk:09e5215894"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/MailboxDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/MailboxDao.kt
index 8589db311..c44ecd0c2 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/MailboxDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/MailboxDao.kt
@@ -11,7 +11,4 @@ interface MailboxDao : BaseDao {
@Query("SELECT * FROM Mailboxes WHERE userLoginId = :userLoginId ")
suspend fun loadAll(userLoginId: Int): List
-
- @Query("SELECT * FROM Mailboxes WHERE userLoginId = :userLoginId AND studentName = :studentName ")
- suspend fun load(userLoginId: Int, studentName: String): Mailbox?
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt
index 7f5974920..8c1097bdb 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt
@@ -32,17 +32,22 @@ class MailboxRepository @Inject constructor(
suspend fun getMailbox(student: Student): Mailbox {
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
- val mailbox = mailboxDao.load(student.userLoginId, student.studentName)
+ val mailboxes = mailboxDao.loadAll(student.userLoginId)
+ val mailbox = mailboxes.filterByStudent(student)
return if (isExpired || mailbox == null) {
refreshMailboxes(student)
- val newMailbox = mailboxDao.load(student.userLoginId, student.studentName)
+ val newMailbox = mailboxDao.loadAll(student.userLoginId).filterByStudent(student)
requireNotNull(newMailbox) {
- "Mailbox for ${student.userName} - ${student.studentName} not found!"
+ "Mailbox for ${student.userName} - ${student.studentName} not found! Saved mailboxes: $mailboxes"
}
newMailbox
} else mailbox
}
+
+ private fun List.filterByStudent(student: Student): Mailbox? = find {
+ it.studentName.trim() == student.studentName.trim()
+ }
}
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/MailboxRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/MailboxRepositoryTest.kt
new file mode 100644
index 000000000..56e315638
--- /dev/null
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/MailboxRepositoryTest.kt
@@ -0,0 +1,132 @@
+package io.github.wulkanowy.data.repositories
+
+import io.github.wulkanowy.data.db.dao.MailboxDao
+import io.github.wulkanowy.data.db.entities.Mailbox
+import io.github.wulkanowy.data.db.entities.MailboxType
+import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.sdk.Sdk
+import io.github.wulkanowy.utils.AutoRefreshHelper
+import io.mockk.MockKAnnotations
+import io.mockk.Runs
+import io.mockk.coEvery
+import io.mockk.impl.annotations.MockK
+import io.mockk.impl.annotations.SpyK
+import io.mockk.just
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import java.time.Instant
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class MailboxRepositoryTest {
+
+ @SpyK
+ private var sdk = Sdk()
+
+ @MockK
+ private lateinit var mailboxDao: MailboxDao
+
+ @MockK
+ private lateinit var refreshHelper: AutoRefreshHelper
+
+ private lateinit var systemUnderTest: MailboxRepository
+
+ @Before
+ fun setUp() {
+ MockKAnnotations.init(this)
+
+ coEvery { refreshHelper.shouldBeRefreshed(any()) } returns false
+ coEvery { refreshHelper.updateLastRefreshTimestamp(any()) } just Runs
+ coEvery { mailboxDao.deleteAll(any()) } just Runs
+ coEvery { mailboxDao.insertAll(any()) } returns emptyList()
+ coEvery { mailboxDao.loadAll(any()) } returns emptyList()
+ coEvery { sdk.getMailboxes() } returns emptyList()
+
+ systemUnderTest = MailboxRepository(
+ mailboxDao = mailboxDao,
+ sdk = sdk,
+ refreshHelper = refreshHelper,
+ )
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun `get mailbox that doesn't exist`() = runTest {
+ val student = getStudentEntity(
+ userName = "Stanisław Kowalski",
+ studentName = "Jan Kowalski",
+ )
+ coEvery { sdk.getMailboxes() } returns emptyList()
+
+ systemUnderTest.getMailbox(student)
+ }
+
+ @Test
+ fun `get mailbox for user with additional spaces`() = runTest {
+ val student = getStudentEntity(
+ userName = " Stanisław Kowalski ",
+ studentName = " Jan Kowalski ",
+ )
+ val expectedMailbox = getMailboxEntity("Jan Kowalski ")
+ coEvery { mailboxDao.loadAll(any()) } returns listOf(
+ expectedMailbox,
+ )
+
+ val selectedMailbox = systemUnderTest.getMailbox(student)
+ assertEquals(expectedMailbox, selectedMailbox)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun `get mailbox for student with strange name`() = runTest {
+ val student = getStudentEntity(
+ userName = "Stanisław Kowalski",
+ studentName = "J**** K*****",
+ )
+ val expectedMailbox = getMailboxEntity("Jan Kowalski")
+ coEvery { mailboxDao.loadAll(any()) } returns listOf(
+ expectedMailbox,
+ )
+
+ systemUnderTest.getMailbox(student)
+ }
+
+ private fun getMailboxEntity(
+ studentName: String,
+ ) = Mailbox(
+ globalKey = "",
+ fullName = "",
+ userName = "",
+ userLoginId = 123,
+ studentName = studentName,
+ schoolNameShort = "",
+ type = MailboxType.STUDENT,
+ )
+
+ private fun getStudentEntity(
+ studentName: String,
+ userName: String,
+ ) = Student(
+ scrapperBaseUrl = "http://fakelog.cf",
+ email = "jan@fakelog.cf",
+ certificateKey = "",
+ classId = 0,
+ className = "",
+ isCurrent = false,
+ isParent = false,
+ loginMode = Sdk.Mode.API.name,
+ loginType = Sdk.ScrapperLoginType.STANDARD.name,
+ mobileBaseUrl = "",
+ password = "",
+ privateKey = "",
+ registrationDate = Instant.now(),
+ schoolName = "",
+ schoolShortName = "test",
+ schoolSymbol = "",
+ studentId = 1,
+ studentName = studentName,
+ symbol = "",
+ userLoginId = 1,
+ userName = userName,
+ )
+}
From eed091aad29b76ac3340e84ae90f4ffc01868491 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Tue, 30 Aug 2022 09:07:24 +0200
Subject: [PATCH 082/164] Update row in mailboxes table on primary key conflict
(#1954)
---
app/src/main/java/io/github/wulkanowy/data/db/dao/BaseDao.kt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/BaseDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/BaseDao.kt
index 048e9e3cd..056a5cbd1 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/BaseDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/BaseDao.kt
@@ -2,11 +2,12 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Delete
import androidx.room.Insert
+import androidx.room.OnConflictStrategy
import androidx.room.Update
interface BaseDao {
- @Insert
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(items: List): List
@Update
From bf34cb0c1e483b0253e12359c97e332404385e3b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Borcz?=
Date: Tue, 30 Aug 2022 12:11:32 +0200
Subject: [PATCH 083/164] New Crowdin updates (#1953)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Mikołaj Pich
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 62eb8e315..b70e77b73 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -186,7 +186,7 @@ ext {
}
dependencies {
- implementation "io.github.wulkanowy:sdk:09e5215894"
+ implementation "io.github.wulkanowy:sdk:a1bf69486b"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
From d139bd5b14a3b068f217f4ec107b5484f5539856 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Tue, 30 Aug 2022 13:34:10 +0200
Subject: [PATCH 084/164] Version 1.7.2
---
app/build.gradle | 8 ++++----
app/src/main/play/release-notes/pl-PL/default.txt | 8 ++------
2 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index b70e77b73..759199cad 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -23,8 +23,8 @@ android {
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 21
targetSdkVersion 32
- versionCode 110
- versionName "1.7.1"
+ versionCode 111
+ versionName "1.7.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "app_name", "Wulkanowy"
@@ -161,7 +161,7 @@ play {
defaultToAppBundles = false
track = 'production'
releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS
- userFraction = 0.95d
+ userFraction = 0.05d
updatePriority = 5
enabled.set(false)
}
@@ -186,7 +186,7 @@ ext {
}
dependencies {
- implementation "io.github.wulkanowy:sdk:a1bf69486b"
+ implementation "io.github.wulkanowy:sdk:1.7.2"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
diff --git a/app/src/main/play/release-notes/pl-PL/default.txt b/app/src/main/play/release-notes/pl-PL/default.txt
index 4b6dcaf28..69699208a 100644
--- a/app/src/main/play/release-notes/pl-PL/default.txt
+++ b/app/src/main/play/release-notes/pl-PL/default.txt
@@ -1,9 +1,5 @@
-Wersja 1.7.1
+Wersja 1.7.2
-- naprawiliśmy logowanie do aplikacji
-- dodaliśmy wsparcie nowego modułu Wiadomości Plus
-- dodaliśmy nową możliwość wsparcia naszego projektu przez opcjonalne reklamy
-- dodaliśmy sortowanie po średniej
-- naprawiliśmy też kilka usterek wpływających na komfort używania aplikacji
+- naprawiliśmy kilka błędów w obsłudze nowego modułu wiadomości
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
From 558db061f594b709e10a9766ae3cdfccbf8dbed1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Wed, 31 Aug 2022 18:31:12 +0200
Subject: [PATCH 085/164] Fix marking message as read (#1960)
* Fix marking message as read
* Update sdk
* Update sdk
* Fix tests
* Use many recipients strings instead of first recipient
---
app/build.gradle | 2 +-
.../wulkanowy/data/repositories/MessageRepository.kt | 9 ++++++---
.../wulkanowy/data/repositories/MessageRepositoryTest.kt | 2 +-
3 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 759199cad..ab8add505 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -186,7 +186,7 @@ ext {
}
dependencies {
- implementation "io.github.wulkanowy:sdk:1.7.2"
+ implementation "com.github.wulkanowy:sdk:006a238bda"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt
index 5a43da4e2..e7428762e 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt
@@ -64,7 +64,10 @@ class MessageRepository @Inject constructor(
},
query = { messagesDb.loadAll(mailbox.globalKey, folder.id) },
fetch = {
- sdk.init(student).getMessages(Folder.valueOf(folder.name)).mapToEntities(mailbox)
+ sdk.init(student).getMessages(
+ folder = Folder.valueOf(folder.name),
+ mailboxKey = mailbox.globalKey,
+ ).mapToEntities(mailbox)
},
saveFetchResult = { old, new ->
messagesDb.deleteAll(old uniqueSubtract new)
@@ -89,7 +92,7 @@ class MessageRepository @Inject constructor(
},
query = { messagesDb.loadMessageWithAttachment(message.messageGlobalKey) },
fetch = {
- sdk.init(student).getMessageDetails(it!!.message.messageGlobalKey)
+ sdk.init(student).getMessageDetails(it!!.message.messageGlobalKey, markAsRead)
},
saveFetchResult = { old, new ->
checkNotNull(old) { "Fetched message no longer exist!" }
@@ -98,7 +101,7 @@ class MessageRepository @Inject constructor(
id = message.id
unread = !markAsRead
sender = new.sender
- recipients = new.recipients.firstOrNull() ?: "Wielu adresoatów"
+ recipients = new.recipients.singleOrNull() ?: "Wielu adresatów"
content = content.ifBlank { new.content }
})
)
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
index 24306bfeb..4efc9c60a 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
@@ -141,7 +141,7 @@ class MessageRepositoryTest {
messageDb.loadMessageWithAttachment("v4")
} returnsMany listOf(flowOf(mWa), flowOf(mWaWithContent))
coEvery {
- sdk.getMessageDetails("v4")
+ sdk.getMessageDetails("v4", any())
} returns mockk {
every { sender } returns ""
every { recipients } returns listOf("")
From d566de0282eb5ac77688233aff677673c6ec15ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Wed, 31 Aug 2022 19:31:28 +0200
Subject: [PATCH 086/164] Version 1.7.3
---
app/build.gradle | 10 +++++-----
app/src/main/play/release-notes/pl-PL/default.txt | 2 +-
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index ab8add505..d4a9b9021 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -23,8 +23,8 @@ android {
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 21
targetSdkVersion 32
- versionCode 111
- versionName "1.7.2"
+ versionCode 112
+ versionName "1.7.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "app_name", "Wulkanowy"
@@ -160,8 +160,8 @@ kapt {
play {
defaultToAppBundles = false
track = 'production'
- releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS
- userFraction = 0.05d
+// releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS
+// userFraction = 0.05d
updatePriority = 5
enabled.set(false)
}
@@ -186,7 +186,7 @@ ext {
}
dependencies {
- implementation "com.github.wulkanowy:sdk:006a238bda"
+ implementation "io.github.wulkanowy:sdk:1.7.3"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
diff --git a/app/src/main/play/release-notes/pl-PL/default.txt b/app/src/main/play/release-notes/pl-PL/default.txt
index 69699208a..ac19bc99a 100644
--- a/app/src/main/play/release-notes/pl-PL/default.txt
+++ b/app/src/main/play/release-notes/pl-PL/default.txt
@@ -1,4 +1,4 @@
-Wersja 1.7.2
+Wersja 1.7.3
- naprawiliśmy kilka błędów w obsłudze nowego modułu wiadomości
From 6153c7b97d58f36383f05d4357194c9c3dcb7720 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Thu, 1 Sep 2022 14:55:00 +0200
Subject: [PATCH 087/164] Add support for match mailboxes with more different
names (#1961)
---
.../data/repositories/MailboxRepository.kt | 34 +++++++++-
.../repositories/MailboxRepositoryTest.kt | 62 ++++++++++++++++++-
2 files changed, 91 insertions(+), 5 deletions(-)
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt
index 8c1097bdb..ad4f669e2 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt
@@ -47,7 +47,37 @@ class MailboxRepository @Inject constructor(
} else mailbox
}
- private fun List.filterByStudent(student: Student): Mailbox? = find {
- it.studentName.trim() == student.studentName.trim()
+ private fun List.filterByStudent(student: Student): Mailbox? {
+ val normalizedStudentName = student.studentName.normalizeStudentName()
+
+ return find {
+ it.studentName.normalizeStudentName() == normalizedStudentName
+ } ?: singleOrNull {
+ it.studentName.getFirstAndLastPart() == normalizedStudentName.getFirstAndLastPart()
+ } ?: singleOrNull {
+ it.studentName.getUnauthorizedVersion() == normalizedStudentName
+ }
+ }
+
+ private fun String.normalizeStudentName(): String {
+ return trim().split(" ").joinToString(" ") { part ->
+ part.lowercase().replaceFirstChar { it.uppercase() }
+ }
+ }
+
+ private fun String.getFirstAndLastPart(): String {
+ val parts = normalizeStudentName().split(" ")
+
+ val endParts = parts.filterIndexed { i, _ ->
+ i == 0 || parts.size == i - 1
+ }
+ return endParts.joinToString(" ")
+ }
+
+ private fun String.getUnauthorizedVersion(): String {
+ return normalizeStudentName().split(" ")
+ .joinToString(" ") {
+ it.first() + "*".repeat(it.length - 1)
+ }
}
}
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/MailboxRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/MailboxRepositoryTest.kt
index 56e315638..300662f01 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/MailboxRepositoryTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/MailboxRepositoryTest.kt
@@ -77,20 +77,76 @@ class MailboxRepositoryTest {
assertEquals(expectedMailbox, selectedMailbox)
}
- @Test(expected = IllegalArgumentException::class)
- fun `get mailbox for student with strange name`() = runTest {
+ @Test
+ fun `get mailbox for unique non-authorized student`() = runTest {
val student = getStudentEntity(
userName = "Stanisław Kowalski",
- studentName = "J**** K*****",
+ studentName = "J** K*******",
)
val expectedMailbox = getMailboxEntity("Jan Kowalski")
coEvery { mailboxDao.loadAll(any()) } returns listOf(
expectedMailbox,
)
+ assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun `get mailbox for not-unique non-authorized student`() = runTest {
+ val student = getStudentEntity(
+ userName = "Stanisław Kowalski",
+ studentName = "J** K*******",
+ )
+ coEvery { mailboxDao.loadAll(any()) } returns listOf(
+ getMailboxEntity("Jan Kowalski"),
+ getMailboxEntity("Jan Kurowski"),
+ )
+
systemUnderTest.getMailbox(student)
}
+ @Test
+ fun `get mailbox for student with uppercase name`() = runTest {
+ val student = getStudentEntity(
+ userName = "Mochoń Julia",
+ studentName = "KLAUDIA MOCHOŃ",
+ )
+ val expectedMailbox = getMailboxEntity("Klaudia Mochoń")
+ coEvery { mailboxDao.loadAll(any()) } returns listOf(
+ expectedMailbox,
+ )
+
+ assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
+ }
+
+ @Test
+ fun `get mailbox for student with second name`() = runTest {
+ val student = getStudentEntity(
+ userName = "Fistaszek Karolina",
+ studentName = "Julia Fistaszek",
+ )
+ val expectedMailbox = getMailboxEntity("Julia Maria Fistaszek")
+ coEvery { mailboxDao.loadAll(any()) } returns listOf(
+ expectedMailbox,
+ )
+
+ assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
+ }
+
+ @Test
+ fun `get mailbox for student with second name and uppercase`() = runTest {
+ val student = getStudentEntity(
+ userName = "BEDNAREK KAMIL",
+ studentName = "ALEKSANDRA BEDNAREK",
+ )
+ val expectedMailbox = getMailboxEntity("Aleksandra Anna Bednarek")
+ coEvery { mailboxDao.loadAll(any()) } returns listOf(
+ expectedMailbox,
+ )
+
+ assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
+ }
+
private fun getMailboxEntity(
studentName: String,
) = Mailbox(
From e05abb3539c1d0d46d48f0c9528df2009a714723 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Thu, 1 Sep 2022 17:48:03 +0200
Subject: [PATCH 088/164] Fix showing empty view in grade details when there is
no grades (#1963)
---
.../ui/modules/grade/details/GradeDetailsPresenter.kt | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt
index 8cde5d6b9..4261c507d 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt
@@ -3,7 +3,6 @@ package io.github.wulkanowy.ui.modules.grade.details
import io.github.wulkanowy.data.*
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.enums.GradeExpandMode
-import io.github.wulkanowy.data.enums.GradeSortingMode
import io.github.wulkanowy.data.enums.GradeSortingMode.*
import io.github.wulkanowy.data.repositories.GradeRepository
import io.github.wulkanowy.data.repositories.PreferencesRepository
@@ -132,16 +131,17 @@ class GradeDetailsPresenter @Inject constructor(
}
.logResourceStatus("load grade details")
.onResourceData {
+ val gradeItems = createGradeItems(it)
view?.run {
enableSwipe(true)
showProgress(false)
showErrorView(false)
- showContent(it.isNotEmpty())
- showEmpty(it.isEmpty())
+ showContent(gradeItems.isNotEmpty())
+ showEmpty(gradeItems.isEmpty())
updateNewGradesAmount(it)
updateMarkAsDoneButton()
updateData(
- data = createGradeItems(it),
+ data = gradeItems,
expandMode = preferencesRepository.gradeExpandMode,
preferencesRepository.gradeColorTheme
)
From bc22808b0ea2ece030ff3e9ef24d5af231e22b93 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Thu, 1 Sep 2022 17:48:46 +0200
Subject: [PATCH 089/164] Add support for matching last kingergarten semester
if there is no any current (#1962)
---
.../wulkanowy/utils/SemesterExtension.kt | 3 +
.../utils/SemesterExtensionKtTest.kt | 72 +++++++++++++++++++
2 files changed, 75 insertions(+)
create mode 100644 app/src/test/java/io/github/wulkanowy/utils/SemesterExtensionKtTest.kt
diff --git a/app/src/main/java/io/github/wulkanowy/utils/SemesterExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/SemesterExtension.kt
index 6e11a8b2c..380d6bf6e 100644
--- a/app/src/main/java/io/github/wulkanowy/utils/SemesterExtension.kt
+++ b/app/src/main/java/io/github/wulkanowy/utils/SemesterExtension.kt
@@ -15,5 +15,8 @@ fun List.getCurrentOrLast(): Semester {
// when there is more than one current semester - find one with higher id
singleOrNull { semester -> semester.semesterId == maxByOrNull { it.semesterId }?.semesterId }?.let { return it }
+ // when there is no active kindergarten semester - get one from last year
+ singleOrNull { semester -> semester.schoolYear == maxByOrNull { it.schoolYear }?.schoolYear }?.let { return it }
+
throw IllegalArgumentException("Duplicated last semester! Semesters: ${joinToString(separator = "\n")}")
}
diff --git a/app/src/test/java/io/github/wulkanowy/utils/SemesterExtensionKtTest.kt b/app/src/test/java/io/github/wulkanowy/utils/SemesterExtensionKtTest.kt
new file mode 100644
index 000000000..b7d3ecc94
--- /dev/null
+++ b/app/src/test/java/io/github/wulkanowy/utils/SemesterExtensionKtTest.kt
@@ -0,0 +1,72 @@
+package io.github.wulkanowy.utils
+
+import io.github.wulkanowy.data.db.entities.Semester
+import io.github.wulkanowy.getSemesterEntity
+import org.junit.Test
+import java.time.LocalDate
+import kotlin.test.assertEquals
+
+class SemesterExtensionKtTest {
+
+ @Test(expected = IllegalArgumentException::class)
+ fun `get current semester when current is doubled`() {
+ val semesters = listOf(
+ getSemesterEntity(1, 1, LocalDate.now(), LocalDate.now()),
+ getSemesterEntity(1, 1, LocalDate.now(), LocalDate.now())
+ )
+
+ semesters.getCurrentOrLast()
+ }
+
+ @Test(expected = RuntimeException::class)
+ fun `get current semester when there is empty list`() {
+ val semesters = listOf()
+
+ semesters.getCurrentOrLast()
+ }
+
+ @Test
+ fun `get current kindergarten semester when there is no any current`() {
+ val semesters = listOf(
+ createSemesterEntity(
+ kindergartenDiaryId = 281,
+ schoolYear = 2020,
+ semesterId = 0,
+ start = LocalDate.of(2020, 9, 1),
+ end = LocalDate.of(2021, 8, 31),
+ ),
+ createSemesterEntity(
+ kindergartenDiaryId = 342,
+ schoolYear = 2021,
+ semesterId = 0,
+ start = LocalDate.of(2021, 9, 1),
+ end = LocalDate.of(2022, 8, 31),
+ ),
+ )
+
+ val res = semesters.getCurrentOrLast()
+
+ assertEquals(2021, res.schoolYear)
+ }
+
+ private fun createSemesterEntity(
+ diaryId: Int = 0,
+ kindergartenDiaryId: Int = 0,
+ semesterId: Int = 0,
+ schoolYear: Int = 0,
+ start: LocalDate = LocalDate.now(),
+ end: LocalDate = LocalDate.now().plusMonths(6),
+ ) = Semester(
+ studentId = 1,
+ diaryId = diaryId,
+ kindergartenDiaryId = kindergartenDiaryId,
+ semesterId = semesterId,
+ diaryName = "$semesterId",
+ schoolYear = schoolYear,
+ classId = 0,
+ semesterName = semesterId,
+ unitId = 1,
+ start = start,
+ end = end
+ )
+}
From e67066f3aea1f32c1470b7e43c90cb3da013027e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Thu, 1 Sep 2022 17:57:20 +0200
Subject: [PATCH 090/164] Version 1.7.4
---
app/build.gradle | 6 +++---
app/src/main/play/release-notes/pl-PL/default.txt | 3 ++-
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index d4a9b9021..e8902fddd 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -23,8 +23,8 @@ android {
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 21
targetSdkVersion 32
- versionCode 112
- versionName "1.7.3"
+ versionCode 113
+ versionName "1.7.4"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "app_name", "Wulkanowy"
@@ -186,7 +186,7 @@ ext {
}
dependencies {
- implementation "io.github.wulkanowy:sdk:1.7.3"
+ implementation "io.github.wulkanowy:sdk:1.7.4"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
diff --git a/app/src/main/play/release-notes/pl-PL/default.txt b/app/src/main/play/release-notes/pl-PL/default.txt
index ac19bc99a..7fe3b7099 100644
--- a/app/src/main/play/release-notes/pl-PL/default.txt
+++ b/app/src/main/play/release-notes/pl-PL/default.txt
@@ -1,5 +1,6 @@
-Wersja 1.7.3
+Wersja 1.7.4
- naprawiliśmy kilka błędów w obsłudze nowego modułu wiadomości
+- naprawiliśmy wyświetlanie napisu "Brak ocen", jesli uczeń nie zdobył w danym semestrze jeszcze żadnych ocen
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
From 157becb017f3502e54ff42ba4f0dbc1bbcd136c0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Fri, 2 Sep 2022 20:19:19 +0200
Subject: [PATCH 091/164] Fix matching mailboxes when there is more than one
space between words (#1964)
---
app/build.gradle | 2 +-
.../data/repositories/MailboxRepository.kt | 10 ++++++----
.../data/repositories/MailboxRepositoryTest.kt | 14 ++++++++++++++
3 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index e8902fddd..c9425d58f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -186,7 +186,7 @@ ext {
}
dependencies {
- implementation "io.github.wulkanowy:sdk:1.7.4"
+ implementation "io.github.wulkanowy:sdk:dcd8bd8b19"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt
index ad4f669e2..c571937ad 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt
@@ -60,16 +60,18 @@ class MailboxRepository @Inject constructor(
}
private fun String.normalizeStudentName(): String {
- return trim().split(" ").joinToString(" ") { part ->
- part.lowercase().replaceFirstChar { it.uppercase() }
- }
+ return trim().split(" ")
+ .filter { it.isNotBlank() }
+ .joinToString(" ") { part ->
+ part.lowercase().replaceFirstChar { it.uppercase() }
+ }
}
private fun String.getFirstAndLastPart(): String {
val parts = normalizeStudentName().split(" ")
val endParts = parts.filterIndexed { i, _ ->
- i == 0 || parts.size == i - 1
+ i == 0 || parts.size - 1 == i
}
return endParts.joinToString(" ")
}
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/MailboxRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/MailboxRepositoryTest.kt
index 300662f01..9198560fe 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/MailboxRepositoryTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/MailboxRepositoryTest.kt
@@ -91,6 +91,20 @@ class MailboxRepositoryTest {
assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
}
+ @Test
+ fun `get mailbox for unique non-authorized student but with spaces`() = runTest {
+ val student = getStudentEntity(
+ userName = "Stanisław Kowalski",
+ studentName = "J** K*******",
+ )
+ val expectedMailbox = getMailboxEntity("Jan Kowalski")
+ coEvery { mailboxDao.loadAll(any()) } returns listOf(
+ expectedMailbox,
+ )
+
+ assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
+ }
+
@Test(expected = IllegalArgumentException::class)
fun `get mailbox for not-unique non-authorized student`() = runTest {
val student = getStudentEntity(
From 86f8763e697b2976d3b73f9d9f78dc102789191d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Fri, 2 Sep 2022 21:30:30 +0200
Subject: [PATCH 092/164] Display lesson number in attendance notification if
subject is blank (#1965)
---
.../services/sync/notifications/NewAttendanceNotification.kt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewAttendanceNotification.kt b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewAttendanceNotification.kt
index 49842c9a6..99473a8ec 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewAttendanceNotification.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewAttendanceNotification.kt
@@ -8,7 +8,6 @@ import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.pojos.GroupNotificationData
import io.github.wulkanowy.data.pojos.NotificationData
import io.github.wulkanowy.ui.modules.Destination
-import io.github.wulkanowy.ui.modules.splash.SplashActivity
import io.github.wulkanowy.utils.descriptionRes
import io.github.wulkanowy.utils.getPlural
import io.github.wulkanowy.utils.toFormattedString
@@ -22,8 +21,9 @@ class NewAttendanceNotification @Inject constructor(
suspend fun notify(items: List, student: Student) {
val lines = items.filterNot { it.presence || it.name == "UNKNOWN" }
.map {
+ val lesson = it.subject.ifBlank { "Lekcja ${it.number}" }
val description = context.getString(it.descriptionRes)
- "${it.date.toFormattedString("dd.MM")} - ${it.subject}: $description"
+ "${it.date.toFormattedString("dd.MM")} - $lesson: $description"
}
.ifEmpty { return }
From 59f6f5c2120cfc5ea02bc7e3f1a7d85e6197be51 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Fri, 2 Sep 2022 21:31:27 +0200
Subject: [PATCH 093/164] Version 1.7.5
---
app/build.gradle | 8 ++++----
app/src/main/play/release-notes/pl-PL/default.txt | 3 ++-
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index c9425d58f..6584b0d28 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -23,8 +23,8 @@ android {
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 21
targetSdkVersion 32
- versionCode 113
- versionName "1.7.4"
+ versionCode 114
+ versionName "1.7.5"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "app_name", "Wulkanowy"
@@ -162,7 +162,7 @@ play {
track = 'production'
// releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS
// userFraction = 0.05d
- updatePriority = 5
+ updatePriority = 4
enabled.set(false)
}
@@ -186,7 +186,7 @@ ext {
}
dependencies {
- implementation "io.github.wulkanowy:sdk:dcd8bd8b19"
+ implementation "io.github.wulkanowy:sdk:1.7.5"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
diff --git a/app/src/main/play/release-notes/pl-PL/default.txt b/app/src/main/play/release-notes/pl-PL/default.txt
index 7fe3b7099..064401abd 100644
--- a/app/src/main/play/release-notes/pl-PL/default.txt
+++ b/app/src/main/play/release-notes/pl-PL/default.txt
@@ -1,6 +1,7 @@
-Wersja 1.7.4
+Wersja 1.7.5
- naprawiliśmy kilka błędów w obsłudze nowego modułu wiadomości
- naprawiliśmy wyświetlanie napisu "Brak ocen", jesli uczeń nie zdobył w danym semestrze jeszcze żadnych ocen
+- naprawiliśmy logowanie do aplikacji rodzicom będącym jednocześnie nauczycielami
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
From 73a7255d3a003e15de313387bcbf40c73fa17ae5 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 5 Sep 2022 19:49:30 +0000
Subject: [PATCH 094/164] Bump firebase-bom from 30.3.2 to 30.4.0 (#1968)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 6584b0d28..17a9fe42f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -241,7 +241,7 @@ dependencies {
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
- playImplementation platform('com.google.firebase:firebase-bom:30.3.2')
+ playImplementation platform('com.google.firebase:firebase-bom:30.4.0')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
From 46c29c438eb1a52824dff8d9b0d1d385c3366013 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 14 Sep 2022 11:17:19 +0000
Subject: [PATCH 095/164] Bump appcompat from 1.5.0 to 1.5.1 (#1975)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 17a9fe42f..41ead9f3e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -196,7 +196,7 @@ dependencies {
implementation "androidx.core:core-ktx:1.8.0"
implementation 'androidx.core:core-splashscreen:1.0.0'
implementation "androidx.activity:activity-ktx:1.5.1"
- implementation "androidx.appcompat:appcompat:1.5.0"
+ implementation "androidx.appcompat:appcompat:1.5.1"
implementation "androidx.fragment:fragment-ktx:1.5.2"
implementation "androidx.annotation:annotation:1.4.0"
From d3f869c6c2400a5b7fa427a45d89df0add4f5420 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 14 Sep 2022 11:18:09 +0000
Subject: [PATCH 096/164] Bump firebase-bom from 30.4.0 to 30.4.1 (#1971)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 41ead9f3e..c2dba71fb 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -241,7 +241,7 @@ dependencies {
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
- playImplementation platform('com.google.firebase:firebase-bom:30.4.0')
+ playImplementation platform('com.google.firebase:firebase-bom:30.4.1')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
From d5d45ed1baa7ec0c52abb0fba9e8bec67c6123e8 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 14 Sep 2022 11:18:29 +0000
Subject: [PATCH 097/164] Bump play-services-ads from 21.1.0 to 21.2.0 (#1972)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index c2dba71fb..7bd4ed15f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -247,7 +247,7 @@ dependencies {
playImplementation 'com.google.firebase:firebase-crashlytics:'
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:21.1.0'
+ playImplementation 'com.google.android.gms:play-services-ads:21.2.0'
hmsImplementation 'com.huawei.hms:hianalytics:6.7.0.300'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.1.300'
From a5c636853a9a15563caedf0f5bc90a3a9021d6fa Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 14 Sep 2022 11:19:05 +0000
Subject: [PATCH 098/164] Bump coil from 2.2.0 to 2.2.1 (#1973)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 7bd4ed15f..7b7251f89 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -236,7 +236,7 @@ dependencies {
implementation "at.favre.lib:slf4j-timber:1.0.1"
implementation 'com.github.bastienpaulfr:Treessence:1.0.5'
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
- implementation "io.coil-kt:coil:2.2.0"
+ implementation "io.coil-kt:coil:2.2.1"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
From afbfb9761fe61339f364f88ef8fde9d4703cb4e4 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 21 Sep 2022 20:38:55 +0000
Subject: [PATCH 099/164] Bump mockk from 1.12.7 to 1.12.8 (#1986)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 7b7251f89..67b4fd07d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -181,7 +181,7 @@ ext {
android_hilt = "1.0.0"
room = "2.4.3"
chucker = "3.5.2"
- mockk = "1.12.7"
+ mockk = "1.12.8"
coroutines = "1.6.4"
}
From 3625c5c5187786f781ea446433f09f13b809861d Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 21 Sep 2022 20:39:08 +0000
Subject: [PATCH 100/164] Bump firebase-bom from 30.4.1 to 30.5.0 (#1991)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 67b4fd07d..6f3f1e989 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -241,7 +241,7 @@ dependencies {
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
- playImplementation platform('com.google.firebase:firebase-bom:30.4.1')
+ playImplementation platform('com.google.firebase:firebase-bom:30.5.0')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
From 4f0519552e3dbce9e5cdecd10685ed1e85aca540 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 21 Sep 2022 20:39:29 +0000
Subject: [PATCH 101/164] Bump firebase-crashlytics-gradle from 2.9.1 to 2.9.2
(#1988)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 98c9dfb84..d98f6f27e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -17,7 +17,7 @@ buildscript {
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.google.gms:google-services:4.3.13'
classpath 'com.huawei.agconnect:agcp:1.7.1.300'
- classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.1'
+ classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2'
classpath "com.github.triplet.gradle:play-publisher:3.6.0"
classpath "ru.cian:huawei-publish-gradle-plugin:1.3.4"
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513"
From f1db993feedb35e746f309dfa0a11c4d0092a0c0 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 21 Sep 2022 20:40:36 +0000
Subject: [PATCH 102/164] Bump agconnect-crash from 1.7.1.300 to 1.7.2.300
(#1990)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 6f3f1e989..6fddc1a73 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -250,7 +250,7 @@ dependencies {
playImplementation 'com.google.android.gms:play-services-ads:21.2.0'
hmsImplementation 'com.huawei.hms:hianalytics:6.7.0.300'
- hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.1.300'
+ hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.2.300'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
From a1dc00af42c73255eeec65704df526c3c877aac4 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 21 Sep 2022 20:49:36 +0000
Subject: [PATCH 103/164] Bump agcp from 1.7.1.300 to 1.7.2.300 (#1989)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index d98f6f27e..942cf4b66 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,7 +16,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:7.2.2'
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.google.gms:google-services:4.3.13'
- classpath 'com.huawei.agconnect:agcp:1.7.1.300'
+ classpath 'com.huawei.agconnect:agcp:1.7.2.300'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2'
classpath "com.github.triplet.gradle:play-publisher:3.6.0"
classpath "ru.cian:huawei-publish-gradle-plugin:1.3.4"
From 5148ff291b7b5c7b2c33061e7e769325c9728aee Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 21 Sep 2022 20:59:41 +0000
Subject: [PATCH 104/164] Bump google-services from 4.3.13 to 4.3.14 (#1992)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 942cf4b66..53fcfda5e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -15,7 +15,7 @@ buildscript {
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath 'com.android.tools.build:gradle:7.2.2'
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
- classpath 'com.google.gms:google-services:4.3.13'
+ classpath 'com.google.gms:google-services:4.3.14'
classpath 'com.huawei.agconnect:agcp:1.7.2.300'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2'
classpath "com.github.triplet.gradle:play-publisher:3.6.0"
From 1bbd249275b97b145011fdd30355664984c03bcb Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 28 Sep 2022 20:25:58 +0000
Subject: [PATCH 105/164] Bump fragment-ktx from 1.5.2 to 1.5.3 (#1997)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 6fddc1a73..e67747d73 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -197,7 +197,7 @@ dependencies {
implementation 'androidx.core:core-splashscreen:1.0.0'
implementation "androidx.activity:activity-ktx:1.5.1"
implementation "androidx.appcompat:appcompat:1.5.1"
- implementation "androidx.fragment:fragment-ktx:1.5.2"
+ implementation "androidx.fragment:fragment-ktx:1.5.3"
implementation "androidx.annotation:annotation:1.4.0"
implementation "androidx.preference:preference-ktx:1.2.0"
From edbe45332ac522a6d3e78ad76a9d3af09edf5960 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 28 Sep 2022 20:27:43 +0000
Subject: [PATCH 106/164] Bump mockk from 1.12.8 to 1.13.1 (#1996)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index e67747d73..eaa81d233 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -181,7 +181,7 @@ ext {
android_hilt = "1.0.0"
room = "2.4.3"
chucker = "3.5.2"
- mockk = "1.12.8"
+ mockk = "1.13.1"
coroutines = "1.6.4"
}
From 8ca41b5ba348483bf9c10a2af927eb387526748e Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 28 Sep 2022 20:28:01 +0000
Subject: [PATCH 107/164] Bump hianalytics from 6.7.0.300 to 6.8.0.300 (#1995)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index eaa81d233..8d33323f3 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -249,7 +249,7 @@ dependencies {
playImplementation 'com.google.android.play:core-ktx:1.8.1'
playImplementation 'com.google.android.gms:play-services-ads:21.2.0'
- hmsImplementation 'com.huawei.hms:hianalytics:6.7.0.300'
+ hmsImplementation 'com.huawei.hms:hianalytics:6.8.0.300'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.2.300'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
From b271c12ebccd7bb6e8ddaf18f68ed09071f385d9 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 28 Sep 2022 20:28:31 +0000
Subject: [PATCH 108/164] Bump hilt_version from 2.43.2 to 2.44 (#1994)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 53fcfda5e..e308c579b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,7 +2,7 @@ buildscript {
ext {
kotlin_version = '1.7.10'
about_libraries = '10.4.0'
- hilt_version = "2.43.2"
+ hilt_version = "2.44"
}
repositories {
mavenCentral()
From 354f51dd707807c7c423b275df7ea4e672689443 Mon Sep 17 00:00:00 2001
From: Michael <5672750+mibac138@users.noreply.github.com>
Date: Wed, 28 Sep 2022 23:33:05 +0200
Subject: [PATCH 109/164] Fix student average calculation error in grade
statistics (#1981)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Mikołaj Pich
---
app/build.gradle | 2 +-
.../grade/summary/GradeSummaryAdapter.kt | 3 ++-
.../github/wulkanowy/utils/GradeExtension.kt | 24 ++++++++-----------
3 files changed, 13 insertions(+), 16 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 8d33323f3..1b745f0b6 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -186,7 +186,7 @@ ext {
}
dependencies {
- implementation "io.github.wulkanowy:sdk:1.7.5"
+ implementation "io.github.wulkanowy:sdk:2840d9d6d0"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryAdapter.kt
index 082c847e5..8dcade56e 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryAdapter.kt
@@ -10,6 +10,7 @@ import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.databinding.ItemGradeSummaryBinding
import io.github.wulkanowy.databinding.ScrollableHeaderGradeSummaryBinding
+import io.github.wulkanowy.sdk.scrapper.grades.isGradeValid
import io.github.wulkanowy.utils.calcFinalAverage
import java.util.Locale
import javax.inject.Inject
@@ -61,7 +62,7 @@ class GradeSummaryAdapter @Inject constructor(
if (items.isEmpty()) return
val context = binding.root.context
- val finalItemsCount = items.count { it.finalGrade.matches("[0-6][+-]?".toRegex()) }
+ val finalItemsCount = items.count { isGradeValid(it.finalGrade) }
val calculatedItemsCount = items.count { value -> value.average != 0.0 }
val allItemsCount = items.count { !it.subject.equals("zachowanie", true) }
val finalAverage = items.calcFinalAverage(
diff --git a/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt
index ff65d6376..61924d4e9 100644
--- a/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt
+++ b/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt
@@ -4,6 +4,7 @@ import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.enums.GradeColorTheme
+import io.github.wulkanowy.sdk.scrapper.grades.getGradeValueWithModifier
import io.github.wulkanowy.sdk.scrapper.grades.isGradeValid
fun List.calcAverage(isOptionalArithmeticAverage: Boolean): Double {
@@ -20,20 +21,15 @@ fun List.calcAverage(isOptionalArithmeticAverage: Boolean): Double {
}
fun List.calcFinalAverage(plusModifier: Double, minusModifier: Double) = asSequence()
- .mapNotNull {
- if (it.finalGrade.matches("[0-6][+-]?".toRegex())) {
- when {
- it.finalGrade.endsWith('+') -> {
- it.finalGrade.removeSuffix("+").toDouble() + plusModifier
- }
- it.finalGrade.endsWith('-') -> {
- it.finalGrade.removeSuffix("-").toDouble() - minusModifier
- }
- else -> {
- it.finalGrade.toDouble()
- }
- }
- } else null
+ .mapNotNull { summary ->
+ val (gradeValue, gradeModifier) = getGradeValueWithModifier(summary.finalGrade)
+ if (gradeValue == null || gradeModifier == null) return@mapNotNull null
+
+ when {
+ gradeModifier > 0 -> gradeValue + plusModifier
+ gradeModifier < 0 -> gradeValue - minusModifier
+ else -> gradeValue + 0.0
+ }
}
.average()
.let { if (it.isNaN()) 0.0 else it }
From a523850216a5d9dc82dc3fda9a73e94507c172f8 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 28 Sep 2022 23:34:06 +0200
Subject: [PATCH 110/164] Bump annotation from 1.4.0 to 1.5.0 (#1998)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 1b745f0b6..3127d55c5 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -198,7 +198,7 @@ dependencies {
implementation "androidx.activity:activity-ktx:1.5.1"
implementation "androidx.appcompat:appcompat:1.5.1"
implementation "androidx.fragment:fragment-ktx:1.5.3"
- implementation "androidx.annotation:annotation:1.4.0"
+ implementation "androidx.annotation:annotation:1.5.0"
implementation "androidx.preference:preference-ktx:1.2.0"
implementation "androidx.recyclerview:recyclerview:1.2.1"
From 8114a2376ee3f798e950b4a2deab3ad21c946f19 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 28 Sep 2022 21:43:45 +0000
Subject: [PATCH 111/164] Bump gradle from 7.2.2 to 7.3.0 (#1985)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index e308c579b..739d5752e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -13,7 +13,7 @@ buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
- classpath 'com.android.tools.build:gradle:7.2.2'
+ classpath 'com.android.tools.build:gradle:7.3.0'
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.google.gms:google-services:4.3.14'
classpath 'com.huawei.agconnect:agcp:1.7.2.300'
From 4dc80595ac9d47e8a07fe998e14dffcee83d5885 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 4 Oct 2022 07:49:22 +0000
Subject: [PATCH 112/164] Bump robolectric from 4.8.2 to 4.9 (#2007)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 3127d55c5..ef5b99500 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -263,7 +263,7 @@ dependencies {
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines"
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
- testImplementation 'org.robolectric:robolectric:4.8.2'
+ testImplementation 'org.robolectric:robolectric:4.9'
testImplementation "androidx.test:runner:1.4.0"
testImplementation "androidx.test.ext:junit:1.1.3"
testImplementation "androidx.test:core:1.4.0"
From 95a90a7a79f2b2ef0510baaf305257246997f6f4 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 4 Oct 2022 07:49:41 +0000
Subject: [PATCH 113/164] Bump mockk from 1.13.1 to 1.13.2 (#2006)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index ef5b99500..458f963fb 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -181,7 +181,7 @@ ext {
android_hilt = "1.0.0"
room = "2.4.3"
chucker = "3.5.2"
- mockk = "1.13.1"
+ mockk = "1.13.2"
coroutines = "1.6.4"
}
From c65303959072a7e4b009973ed593abfd7f6657c2 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 4 Oct 2022 07:50:05 +0000
Subject: [PATCH 114/164] Bump coil from 2.2.1 to 2.2.2 (#2004)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 458f963fb..cd4f6cc12 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -236,7 +236,7 @@ dependencies {
implementation "at.favre.lib:slf4j-timber:1.0.1"
implementation 'com.github.bastienpaulfr:Treessence:1.0.5'
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
- implementation "io.coil-kt:coil:2.2.1"
+ implementation "io.coil-kt:coil:2.2.2"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
From 37f7f21a033e03ccb976dc8c6c267ef68061cd25 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Tue, 4 Oct 2022 09:51:30 +0200
Subject: [PATCH 115/164] Reorder action buttons on the message preview screen
to hide the forward button in overflow menu (#2000)
---
.../res/menu/action_menu_message_preview.xml | 28 +++++++++----------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/app/src/main/res/menu/action_menu_message_preview.xml b/app/src/main/res/menu/action_menu_message_preview.xml
index 5011e2356..57cf05ddb 100644
--- a/app/src/main/res/menu/action_menu_message_preview.xml
+++ b/app/src/main/res/menu/action_menu_message_preview.xml
@@ -8,20 +8,6 @@
android:title="@string/message_reply"
app:iconTint="@color/material_on_surface_emphasis_medium"
app:showAsAction="ifRoom" />
-
-
+
+
From cd037f0ce0f2f2b0107af5114ed3c11f1d03388e Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 4 Oct 2022 07:58:58 +0000
Subject: [PATCH 116/164] Bump kotlin_version from 1.7.10 to 1.7.20 (#2003)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 739d5752e..fb58a44d2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,6 @@
buildscript {
ext {
- kotlin_version = '1.7.10'
+ kotlin_version = '1.7.20'
about_libraries = '10.4.0'
hilt_version = "2.44"
}
From 3f431022a5b5316babaa89951d13a67d5680299e Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 4 Oct 2022 08:08:21 +0000
Subject: [PATCH 117/164] Bump about_libraries from 10.4.0 to 10.5.0 (#2005)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index fb58a44d2..9f5b21f4d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,7 @@
buildscript {
ext {
kotlin_version = '1.7.20'
- about_libraries = '10.4.0'
+ about_libraries = '10.5.0'
hilt_version = "2.44"
}
repositories {
From ad487e680cf6907eba664d7922c12f184974f830 Mon Sep 17 00:00:00 2001
From: Daniel Olczyk <44818681+MRmlik12@users.noreply.github.com>
Date: Wed, 5 Oct 2022 22:25:09 +0200
Subject: [PATCH 118/164] Fix grade weight text truncation in grade dialog with
large font set (#2009)
---
app/src/main/res/layout/dialog_grade.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/src/main/res/layout/dialog_grade.xml b/app/src/main/res/layout/dialog_grade.xml
index 9c52c1d0b..94facb232 100644
--- a/app/src/main/res/layout/dialog_grade.xml
+++ b/app/src/main/res/layout/dialog_grade.xml
@@ -21,7 +21,7 @@
Date: Tue, 18 Oct 2022 19:39:16 +0000
Subject: [PATCH 119/164] Bump play-services-ads from 21.2.0 to 21.3.0 (#2016)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index cd4f6cc12..a0285de83 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -247,7 +247,7 @@ dependencies {
playImplementation 'com.google.firebase:firebase-crashlytics:'
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:21.2.0'
+ playImplementation 'com.google.android.gms:play-services-ads:21.3.0'
hmsImplementation 'com.huawei.hms:hianalytics:6.8.0.300'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.2.300'
From 1f11eea9b58e66ce9c7aa6aba7e1dd3ad3ad6078 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 18 Oct 2022 19:39:36 +0000
Subject: [PATCH 120/164] Bump gradle from 7.3.0 to 7.3.1 (#2015)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 9f5b21f4d..5b7b4abbb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -13,7 +13,7 @@ buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
- classpath 'com.android.tools.build:gradle:7.3.0'
+ classpath 'com.android.tools.build:gradle:7.3.1'
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.google.gms:google-services:4.3.14'
classpath 'com.huawei.agconnect:agcp:1.7.2.300'
From e20c232f8fd2797dd83fae0e6dbdeddde6b000d3 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 18 Oct 2022 19:39:54 +0000
Subject: [PATCH 121/164] Bump kotlinx-serialization-json from 1.4.0 to 1.4.1
(#2014)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index a0285de83..4ea25d7e2 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -190,7 +190,7 @@ dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
- implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.0"
+ implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
implementation "androidx.core:core-ktx:1.8.0"
From 4c24363599f8dc486a1d7b9a1507977439ef9982 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 18 Oct 2022 19:40:28 +0000
Subject: [PATCH 122/164] Bump about_libraries from 10.5.0 to 10.5.1 (#2012)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 5b7b4abbb..5131796bb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,7 @@
buildscript {
ext {
kotlin_version = '1.7.20'
- about_libraries = '10.5.0'
+ about_libraries = '10.5.1'
hilt_version = "2.44"
}
repositories {
From e91cd188044c94c1022f13f053d74cf243201d5c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 18 Oct 2022 19:41:15 +0000
Subject: [PATCH 123/164] Bump firebase-bom from 30.5.0 to 31.0.0 (#2013)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 4ea25d7e2..672a4becc 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -241,7 +241,7 @@ dependencies {
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
- playImplementation platform('com.google.firebase:firebase-bom:30.5.0')
+ playImplementation platform('com.google.firebase:firebase-bom:31.0.0')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
From a14c4b489bf1b413157500666c828fc4a178c7f5 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 26 Oct 2022 18:22:16 +0000
Subject: [PATCH 124/164] Bump material from 1.6.1 to 1.7.0 (#2022)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 672a4becc..8848a413b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -206,7 +206,7 @@ dependencies {
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
- implementation "com.google.android.material:material:1.6.1"
+ implementation "com.google.android.material:material:1.7.0"
implementation "com.github.wulkanowy:material-chips-input:2.3.1"
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
implementation 'com.github.lopspower:CircularImageView:4.2.0'
From 4a484dc2ce25472961f0842cb3e05575233b1c00 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 26 Oct 2022 18:22:34 +0000
Subject: [PATCH 125/164] Bump fragment-ktx from 1.5.3 to 1.5.4 (#2020)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 8848a413b..b15eb651d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -197,7 +197,7 @@ dependencies {
implementation 'androidx.core:core-splashscreen:1.0.0'
implementation "androidx.activity:activity-ktx:1.5.1"
implementation "androidx.appcompat:appcompat:1.5.1"
- implementation "androidx.fragment:fragment-ktx:1.5.3"
+ implementation "androidx.fragment:fragment-ktx:1.5.4"
implementation "androidx.annotation:annotation:1.5.0"
implementation "androidx.preference:preference-ktx:1.2.0"
From 49b383fbe51078cc375d972aea6b11458906a35f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 26 Oct 2022 18:22:53 +0000
Subject: [PATCH 126/164] Bump firebase-bom from 31.0.0 to 31.0.1 (#2019)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index b15eb651d..6211db2d8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -241,7 +241,7 @@ dependencies {
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
- playImplementation platform('com.google.firebase:firebase-bom:31.0.0')
+ playImplementation platform('com.google.firebase:firebase-bom:31.0.1')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
From 3925a6261b9d921f2ea4b0f051b7092af90d9930 Mon Sep 17 00:00:00 2001
From: Damian Czupryn <60961958+Daxxxis@users.noreply.github.com>
Date: Wed, 26 Oct 2022 22:27:37 +0200
Subject: [PATCH 127/164] Add missing CS and SK links in German README (#2018)
---
README.de.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.de.md b/README.de.md
index b9e1d1ec1..e03557a06 100644
--- a/README.de.md
+++ b/README.de.md
@@ -2,6 +2,10 @@
[English version of README](README.en.md)
+[Česká verze README](README.cs.md)
+
+[Slovenská verzia README](README.sk.md)
+
# Wulkanowy
[](https://github.com/wulkanowy/wulkanowy/actions)
From 22a4f509dcc49086ea51939d0b820a479a01aa32 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Thu, 27 Oct 2022 12:41:33 +0200
Subject: [PATCH 128/164] Add installation id to crashlytics and bug report
emails (#2024)
---
.../github/wulkanowy/utils/AnalyticsHelper.kt | 14 +++-------
.../github/wulkanowy/utils/AnalyticsHelper.kt | 26 ++++++++++++++-----
.../github/wulkanowy/utils/CrashLogUtils.kt | 9 ++-----
.../repositories/PreferencesRepository.kt | 24 ++++++++---------
.../github/wulkanowy/ui/base/ErrorDialog.kt | 10 ++++---
.../ui/modules/about/AboutFragment.kt | 7 ++++-
.../modules/login/form/LoginFormFragment.kt | 7 ++++-
.../LoginStudentSelectFragment.kt | 10 +++++--
.../login/symbol/LoginSymbolFragment.kt | 7 ++++-
app/src/main/res/values/strings.xml | 4 +--
.../github/wulkanowy/utils/AnalyticsHelper.kt | 26 ++++++++++++++-----
.../wulkanowy/utils/CrashlyticsUtils.kt | 3 ---
12 files changed, 90 insertions(+), 57 deletions(-)
diff --git a/app/src/fdroid/java/io/github/wulkanowy/utils/AnalyticsHelper.kt b/app/src/fdroid/java/io/github/wulkanowy/utils/AnalyticsHelper.kt
index 3bf7e1693..a3eed484a 100644
--- a/app/src/fdroid/java/io/github/wulkanowy/utils/AnalyticsHelper.kt
+++ b/app/src/fdroid/java/io/github/wulkanowy/utils/AnalyticsHelper.kt
@@ -8,15 +8,7 @@ import javax.inject.Singleton
@Suppress("UNUSED_PARAMETER")
class AnalyticsHelper @Inject constructor() {
- fun logEvent(name: String, vararg params: Pair) {
- // do nothing
- }
-
- fun setCurrentScreen(activity: Activity, name: String?) {
- // do nothing
- }
-
- fun popCurrentScreen(name: String?) {
- // do nothing
- }
+ fun logEvent(name: String, vararg params: Pair) = Unit
+ fun setCurrentScreen(activity: Activity, name: String?) = Unit
+ fun popCurrentScreen(name: String?) = Unit
}
diff --git a/app/src/hms/java/io/github/wulkanowy/utils/AnalyticsHelper.kt b/app/src/hms/java/io/github/wulkanowy/utils/AnalyticsHelper.kt
index 5d33825f1..1f78931ae 100644
--- a/app/src/hms/java/io/github/wulkanowy/utils/AnalyticsHelper.kt
+++ b/app/src/hms/java/io/github/wulkanowy/utils/AnalyticsHelper.kt
@@ -3,26 +3,38 @@ package io.github.wulkanowy.utils
import android.app.Activity
import android.content.Context
import android.os.Bundle
+import com.huawei.agconnect.crash.AGConnectCrash
import com.huawei.hms.analytics.HiAnalytics
import dagger.hilt.android.qualifiers.ApplicationContext
+import io.github.wulkanowy.data.repositories.PreferencesRepository
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AnalyticsHelper @Inject constructor(
- @ApplicationContext private val context: Context
+ @ApplicationContext private val context: Context,
+ preferencesRepository: PreferencesRepository,
+ appInfo: AppInfo,
) {
private val analytics by lazy { HiAnalytics.getInstance(context) }
+ private val connectCrash by lazy { AGConnectCrash.getInstance() }
+
+ init {
+ if (!appInfo.isDebug) {
+ connectCrash.setUserId(preferencesRepository.installationId)
+ }
+ }
+
fun logEvent(name: String, vararg params: Pair) {
Bundle().apply {
- params.forEach {
- if (it.second == null) return@forEach
- when (it.second) {
- is String, is String? -> putString(it.first, it.second as String)
- is Int, is Int? -> putInt(it.first, it.second as Int)
- is Boolean, is Boolean? -> putBoolean(it.first, it.second as Boolean)
+ params.forEach { (key, value) ->
+ if (value == null) return@forEach
+ when (value) {
+ is String -> putString(key, value)
+ is Int -> putInt(key, value)
+ is Boolean -> putBoolean(key, value)
}
}
analytics.onEvent(name, this)
diff --git a/app/src/hms/java/io/github/wulkanowy/utils/CrashLogUtils.kt b/app/src/hms/java/io/github/wulkanowy/utils/CrashLogUtils.kt
index b0c34f413..377e83666 100644
--- a/app/src/hms/java/io/github/wulkanowy/utils/CrashLogUtils.kt
+++ b/app/src/hms/java/io/github/wulkanowy/utils/CrashLogUtils.kt
@@ -3,6 +3,7 @@ package io.github.wulkanowy.utils
import android.util.Log
import com.huawei.agconnect.crash.AGConnectCrash
import fr.bipi.tressence.base.FormatterPriorityTree
+import fr.bipi.tressence.common.StackTraceRecorder
class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) {
@@ -22,16 +23,10 @@ class CrashLogExceptionTree : FormatterPriorityTree(Log.ERROR, ExceptionFilter)
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
if (skipLog(priority, tag, message, t)) return
- // Disabled due to a bug in the Huawei library
-
- /*connectCrash.setCustomKey("priority", priority)
- connectCrash.setCustomKey("tag", tag.orEmpty())
- connectCrash.setCustomKey("message", message)
-
if (t != null) {
connectCrash.recordException(t)
} else {
connectCrash.recordException(StackTraceRecorder(format(priority, tag, message)))
- }*/
+ }
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt
index 486538e0c..afc262868 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt
@@ -10,17 +10,16 @@ import io.github.wulkanowy.R
import io.github.wulkanowy.data.enums.*
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.time.Instant
+import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
-@OptIn(ExperimentalCoroutinesApi::class)
@Singleton
class PreferencesRepository @Inject constructor(
@ApplicationContext val context: Context,
@@ -316,6 +315,16 @@ class PreferencesRepository @Inject constructor(
putBoolean(context.getString(R.string.pref_key_ads_enabled), value)
}
+ var installationId: String
+ get() = sharedPref.getString(PREF_KEY_INSTALLATION_ID, null).orEmpty()
+ private set(value) = sharedPref.edit { putString(PREF_KEY_INSTALLATION_ID, value) }
+
+ init {
+ if (installationId.isEmpty()) {
+ installationId = UUID.randomUUID().toString()
+ }
+ }
+
private fun getLong(id: Int, default: Int) = getLong(context.getString(id), default)
private fun getLong(id: String, default: Int) =
@@ -331,23 +340,14 @@ class PreferencesRepository @Inject constructor(
private fun getBoolean(id: String, default: Int) =
sharedPref.getBoolean(id, context.resources.getBoolean(default))
- private fun getBoolean(id: Int, default: Boolean) =
- sharedPref.getBoolean(context.getString(id), default)
-
private companion object {
-
+ private const val PREF_KEY_INSTALLATION_ID = "installation_id"
private const val PREF_KEY_DASHBOARD_ITEMS_POSITION = "dashboard_items_position"
-
private const val PREF_KEY_IN_APP_REVIEW_COUNT = "in_app_review_count"
-
private const val PREF_KEY_IN_APP_REVIEW_DATE = "in_app_review_date"
-
private const val PREF_KEY_IN_APP_REVIEW_DONE = "in_app_review_done"
-
private const val PREF_KEY_APP_SUPPORT_SHOWN = "app_support_shown"
-
private const val PREF_KEY_PERSONALIZED_ADS_ENABLED = "personalized_ads_enabled"
-
private const val PREF_KEY_ADMIN_DISMISSED_MESSAGE_IDS = "admin_message_dismissed_ids"
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/ErrorDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/base/ErrorDialog.kt
index 48c003b7e..e979fa8af 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/base/ErrorDialog.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/base/ErrorDialog.kt
@@ -4,7 +4,6 @@ import android.app.Dialog
import android.content.ClipData
import android.content.ClipboardManager
import android.os.Bundle
-import android.view.LayoutInflater
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
import androidx.appcompat.app.AlertDialog
@@ -15,6 +14,7 @@ import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
+import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.databinding.DialogErrorBinding
import io.github.wulkanowy.utils.*
import javax.inject.Inject
@@ -25,6 +25,9 @@ class ErrorDialog : DialogFragment() {
@Inject
lateinit var appInfo: AppInfo
+ @Inject
+ lateinit var preferencesRepository: PreferencesRepository
+
companion object {
private const val ARGUMENT_KEY = "error"
@@ -36,7 +39,7 @@ class ErrorDialog : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val error = requireArguments().getSerializable(ARGUMENT_KEY) as Throwable
- val binding = DialogErrorBinding.inflate(LayoutInflater.from(context))
+ val binding = DialogErrorBinding.inflate(layoutInflater)
binding.bindErrorDetails(error)
return getAlertDialog(binding, error).apply {
@@ -99,7 +102,8 @@ class ErrorDialog : DialogFragment() {
R.string.about_feedback_template,
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
appInfo.systemVersion.toString(),
- "${appInfo.versionName}-${appInfo.buildFlavor}"
+ "${appInfo.versionName}-${appInfo.buildFlavor}",
+ preferencesRepository.installationId,
) + "\n" + content,
onActivityNotFound = {
requireContext().openInternetBrowser(
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt
index 701656b55..d7f39e303 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt
@@ -6,6 +6,7 @@ import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
+import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.databinding.FragmentAboutBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.about.contributor.ContributorFragment
@@ -30,6 +31,9 @@ class AboutFragment : BaseFragment(R.layout.fragment_about
@Inject
lateinit var appInfo: AppInfo
+ @Inject
+ lateinit var preferencesRepository: PreferencesRepository
+
override val versionRes: Triple?
get() = context?.run {
val buildTimestamp =
@@ -185,7 +189,8 @@ class AboutFragment : BaseFragment(R.layout.fragment_about
R.string.about_feedback_template,
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
appInfo.systemVersion.toString(),
- "${appInfo.versionName}-${appInfo.buildFlavor}"
+ "${appInfo.versionName}-${appInfo.buildFlavor}",
+ preferencesRepository.installationId,
),
onActivityNotFound = {
requireContext().openInternetBrowser(
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt
index d31f5cf0f..463e192de 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt
@@ -10,6 +10,7 @@ import androidx.core.widget.doOnTextChanged
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
+import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.databinding.FragmentLoginFormBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.login.LoginActivity
@@ -32,6 +33,9 @@ class LoginFormFragment : BaseFragment(R.layout.fragme
@Inject
lateinit var appInfo: AppInfo
+ @Inject
+ lateinit var preferencesRepository: PreferencesRepository
+
companion object {
fun newInstance() = LoginFormFragment()
}
@@ -260,8 +264,9 @@ class LoginFormFragment : BaseFragment(R.layout.fragme
R.string.login_email_text,
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
appInfo.systemVersion.toString(),
- appInfo.versionName,
+ "${appInfo.versionName}-${appInfo.buildFlavor}",
"$formHostValue/$formHostSymbol",
+ preferencesRepository.installationId,
lastError
)
)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt
index 6c910fe03..c42a4e9d1 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt
@@ -9,6 +9,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
+import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.databinding.FragmentLoginStudentSelectBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.login.LoginActivity
@@ -32,6 +33,9 @@ class LoginStudentSelectFragment :
@Inject
lateinit var appInfo: AppInfo
+ @Inject
+ lateinit var preferencesRepository: PreferencesRepository
+
companion object {
const val ARG_STUDENTS = "STUDENTS"
@@ -111,10 +115,12 @@ class LoginStudentSelectFragment :
email = "wulkanowyinc@gmail.com",
subject = requireContext().getString(R.string.login_email_subject),
body = requireContext().getString(
- R.string.login_email_text, appInfo.systemModel,
+ R.string.login_email_text,
+ "${appInfo.systemManufacturer} ${appInfo.systemModel}",
appInfo.systemVersion.toString(),
- appInfo.versionName,
+ "${appInfo.versionName}-${appInfo.buildFlavor}",
"Select users to log in",
+ preferencesRepository.installationId,
lastError
)
)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt
index 58bdf6cef..36c40d156 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt
@@ -13,6 +13,7 @@ import androidx.core.widget.doOnTextChanged
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
+import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.databinding.FragmentLoginSymbolBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.login.LoginActivity
@@ -34,6 +35,9 @@ class LoginSymbolFragment :
@Inject
lateinit var appInfo: AppInfo
+ @Inject
+ lateinit var preferencesRepository: PreferencesRepository
+
companion object {
private const val SAVED_LOGIN_DATA = "LOGIN_DATA"
@@ -159,8 +163,9 @@ class LoginSymbolFragment :
R.string.login_email_text,
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
appInfo.systemVersion.toString(),
- appInfo.versionName,
+ "${appInfo.versionName}-${appInfo.buildFlavor}",
"$host/${binding.loginSymbolName.text}",
+ preferencesRepository.installationId,
lastError
)
)
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e4542547d..48376d216 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -71,7 +71,7 @@
Discord
Send email
Zgłoszenie: Problemy z logowaniem
- Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\nDodatkowe informacje: %4$s\nOstatni błąd: %5$s\n\nNazwa szkoły i miejscowość:
+ Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\nDodatkowe informacje: %4$s\nIdentyfikator instalacji: %5$s\nOstatni błąd: %6$s\n\nNazwa szkoły i miejscowość:
Make sure you select the correct UONET+ register variation!
I forgot my password
Recover your account
@@ -512,7 +512,7 @@
Visit the website and help develop the application
Licenses
Licenses of libraries used in the application
- Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\n\nTreść zgłoszenia:
+ Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\nIdentyfikator instalacji: %4$s\nTreść zgłoszenia:
diff --git a/app/src/play/java/io/github/wulkanowy/utils/AnalyticsHelper.kt b/app/src/play/java/io/github/wulkanowy/utils/AnalyticsHelper.kt
index b65325790..3215fa20c 100644
--- a/app/src/play/java/io/github/wulkanowy/utils/AnalyticsHelper.kt
+++ b/app/src/play/java/io/github/wulkanowy/utils/AnalyticsHelper.kt
@@ -4,25 +4,37 @@ import android.app.Activity
import android.content.Context
import android.os.Bundle
import com.google.firebase.analytics.FirebaseAnalytics
+import com.google.firebase.crashlytics.FirebaseCrashlytics
import dagger.hilt.android.qualifiers.ApplicationContext
+import io.github.wulkanowy.data.repositories.PreferencesRepository
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AnalyticsHelper @Inject constructor(
- @ApplicationContext private val context: Context
+ @ApplicationContext private val context: Context,
+ preferencesRepository: PreferencesRepository,
+ appInfo: AppInfo,
) {
private val analytics by lazy { FirebaseAnalytics.getInstance(context) }
+ private val crashlytics by lazy { FirebaseCrashlytics.getInstance() }
+
+ init {
+ if (!appInfo.isDebug) {
+ crashlytics.setUserId(preferencesRepository.installationId)
+ }
+ }
+
fun logEvent(name: String, vararg params: Pair) {
Bundle().apply {
- params.forEach {
- if (it.second == null) return@forEach
- when (it.second) {
- is String, is String? -> putString(it.first, it.second.toString())
- is Int, is Int? -> putInt(it.first, it.second as Int)
- is Boolean, is Boolean? -> putBoolean(it.first, it.second as Boolean)
+ params.forEach { (key, value) ->
+ if (value == null) return@forEach
+ when (value) {
+ is String -> putString(key, value)
+ is Int -> putInt(key, value)
+ is Boolean -> putBoolean(key, value)
}
}
analytics.logEvent(name, this)
diff --git a/app/src/play/java/io/github/wulkanowy/utils/CrashlyticsUtils.kt b/app/src/play/java/io/github/wulkanowy/utils/CrashlyticsUtils.kt
index 410fddf16..f980bc4bb 100644
--- a/app/src/play/java/io/github/wulkanowy/utils/CrashlyticsUtils.kt
+++ b/app/src/play/java/io/github/wulkanowy/utils/CrashlyticsUtils.kt
@@ -23,9 +23,6 @@ class CrashLogExceptionTree : FormatterPriorityTree(Log.ERROR, ExceptionFilter)
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
if (skipLog(priority, tag, message, t)) return
- crashlytics.setCustomKey("priority", priority)
- crashlytics.setCustomKey("tag", tag.orEmpty())
- crashlytics.setCustomKey("message", message)
if (t != null) {
crashlytics.recordException(t)
} else {
From 7bee10d5ce0aa85becaa5a5b2a8ecd752ae0b1cf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Fri, 28 Oct 2022 11:08:40 +0200
Subject: [PATCH 129/164] Hide room view in timetable item if there is no room
in API (#2026)
---
.../github/wulkanowy/ui/modules/timetable/TimetableAdapter.kt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableAdapter.kt
index d6917672a..2f0d697fc 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableAdapter.kt
@@ -191,7 +191,7 @@ class TimetableAdapter @Inject constructor() :
)
} else {
timetableItemDescription.visibility = GONE
- timetableItemRoom.visibility = VISIBLE
+ timetableItemRoom.isVisible = lesson.room.isNotBlank() || lesson.roomOld.isNotBlank()
timetableItemGroup.isVisible = item.showGroupsInPlan && lesson.group.isNotBlank()
timetableItemTeacher.visibility = VISIBLE
}
From 515a3973b74048daba05783609b5530b59279938 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Fri, 28 Oct 2022 11:09:38 +0200
Subject: [PATCH 130/164] Use text color, font face and red dot to
differentiate unread messages (#2027)
---
.../modules/message/tab/MessageTabAdapter.kt | 33 ++++++++++++++-----
app/src/main/res/drawable/ic_circle.xml | 10 ++++++
app/src/main/res/layout/item_message.xml | 22 +++++++++++--
3 files changed, 54 insertions(+), 11 deletions(-)
create mode 100644 app/src/main/res/drawable/ic_circle.xml
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt
index 55f03ef84..234d17eb2 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt
@@ -1,15 +1,18 @@
package io.github.wulkanowy.ui.modules.message.tab
+import android.content.res.ColorStateList
import android.graphics.Typeface
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.CompoundButton
import androidx.core.view.isVisible
+import androidx.core.widget.ImageViewCompat
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import io.github.wulkanowy.R
import io.github.wulkanowy.databinding.ItemMessageBinding
import io.github.wulkanowy.databinding.ItemMessageChipsBinding
+import io.github.wulkanowy.utils.getThemeAttrColor
import io.github.wulkanowy.utils.toFormattedString
import javax.inject.Inject
@@ -85,21 +88,35 @@ class MessageTabAdapter @Inject constructor() :
val message = item.message
with(holder.binding) {
- val style = if (message.unread) Typeface.BOLD else Typeface.NORMAL
+ val normalFont = Typeface.create("sans-serif", Typeface.NORMAL)
+ val boldFont = Typeface.create("sans-serif-black", Typeface.NORMAL)
+
+ val primaryColor = root.context.getThemeAttrColor(android.R.attr.textColorPrimary)
+ val secondaryColor = root.context.getThemeAttrColor(android.R.attr.textColorSecondary)
+
+ val currentFont = if (message.unread) boldFont else normalFont
+ val currentTextColor = if (message.unread) primaryColor else secondaryColor
with(messageItemAuthor) {
text = message.correspondents
- setTypeface(null, style)
+ setTextColor(currentTextColor)
+ typeface = currentFont
}
- messageItemSubject.run {
+ with(messageItemSubject) {
text = message.subject.ifBlank { context.getString(R.string.message_no_subject) }
- setTypeface(null, style)
+ setTextColor(currentTextColor)
+ typeface = currentFont
}
- messageItemDate.run {
+ with(messageItemDate) {
text = message.date.toFormattedString()
- setTypeface(null, style)
+ setTextColor(currentTextColor)
+ typeface = currentFont
}
- messageItemAttachmentIcon.isVisible = message.hasAttachments
+ with(messageItemAttachmentIcon) {
+ ImageViewCompat.setImageTintList(this, ColorStateList.valueOf(currentTextColor))
+ isVisible = message.hasAttachments
+ }
+ messageItemUnreadIndicator.isVisible = message.unread
root.setOnClickListener {
holder.bindingAdapterPosition.let {
@@ -111,7 +128,7 @@ class MessageTabAdapter @Inject constructor() :
root.setOnLongClickListener {
onLongItemClickListener(item)
- return@setOnLongClickListener true
+ true
}
with(messageItemCheckbox) {
diff --git a/app/src/main/res/drawable/ic_circle.xml b/app/src/main/res/drawable/ic_circle.xml
new file mode 100644
index 000000000..d2932fe62
--- /dev/null
+++ b/app/src/main/res/drawable/ic_circle.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_message.xml b/app/src/main/res/layout/item_message.xml
index c25faacc8..39fbaad01 100644
--- a/app/src/main/res/layout/item_message.xml
+++ b/app/src/main/res/layout/item_message.xml
@@ -30,6 +30,7 @@
android:layout_marginEnd="10dp"
android:ellipsize="end"
android:singleLine="true"
+ android:textColor="?android:textColorSecondary"
android:textSize="15sp"
app:layout_constraintEnd_toStartOf="@+id/messageItemDate"
app:layout_constraintStart_toEndOf="@id/messageItemCheckbox"
@@ -40,10 +41,13 @@
android:id="@+id/messageItemDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginEnd="8dp"
android:gravity="end"
+ android:textColor="?android:textColorSecondary"
android:textSize="13sp"
- app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/messageItemUnreadIndicator"
app:layout_constraintTop_toTopOf="parent"
+ app:layout_goneMarginEnd="0dp"
tools:text="@tools:sample/date/ddmmyy" />
+
+
From c5e2b18695c2a1f58afd407d399d927d03573dd1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Fri, 28 Oct 2022 11:10:05 +0200
Subject: [PATCH 131/164] Fix SSL certificate out-of-date detection (#2028)
---
.../java/io/github/wulkanowy/utils/ExceptionExtension.kt | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt
index 43cecd400..a4c2537ac 100644
--- a/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt
+++ b/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt
@@ -15,16 +15,17 @@ import java.net.ConnectException
import java.net.SocketException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
+import java.security.cert.CertPathValidatorException
import java.security.cert.CertificateExpiredException
import java.security.cert.CertificateNotYetValidException
import javax.net.ssl.SSLHandshakeException
fun Resources.getErrorString(error: Throwable): String = when (error) {
is UnknownHostException -> R.string.error_no_internet
+ is ConnectException,
is SocketException,
is SocketTimeoutException,
is InterruptedIOException,
- is ConnectException,
is StreamResetException -> R.string.error_timeout
is NotLoggedInException -> R.string.error_login_failed
is PasswordChangeRequiredException -> R.string.error_password_change_required
@@ -42,10 +43,10 @@ fun Resources.getErrorString(error: Throwable): String = when (error) {
fun Throwable.isShouldBeReported(): Boolean = when (this) {
is UnknownHostException,
+ is ConnectException,
is SocketException,
is SocketTimeoutException,
is InterruptedIOException,
- is ConnectException,
is StreamResetException,
is ServiceUnavailableException,
is FeatureDisabledException,
@@ -70,5 +71,6 @@ private fun Throwable?.isCausedByCertificateNotValidNow(): Boolean {
private fun Throwable?.isCertificateNotValidNow(): Boolean {
val isNotYetValid = this is CertificateNotYetValidException
val isExpired = this is CertificateExpiredException
- return isNotYetValid || isExpired
+ val isInvalidPath = this is CertPathValidatorException
+ return isNotYetValid || isExpired || isInvalidPath
}
From ffd5addadb3f1250f438ad3cea2e2889649e31b8 Mon Sep 17 00:00:00 2001
From: Damian Czupryn <60961958+Daxxxis@users.noreply.github.com>
Date: Fri, 28 Oct 2022 11:10:35 +0200
Subject: [PATCH 132/164] Add Crowdin badges to README (#2025)
---
README.cs.md | 1 +
README.de.md | 1 +
README.en.md | 1 +
README.md | 1 +
README.sk.md | 1 +
5 files changed, 5 insertions(+)
diff --git a/README.cs.md b/README.cs.md
index 5c1e5ea71..0d6da9c36 100644
--- a/README.cs.md
+++ b/README.cs.md
@@ -13,6 +13,7 @@
[](https://discord.gg/vccAQBr)
[](https://f-droid.org/packages/io.github.wulkanowy/)
[](https://github.com/wulkanowy/wulkanowy/releases)
+[](https://translate.wulkanowy.net.pl)
Neoficiální klient deníku VULCAN UONET+ pro žáka a rodiče
diff --git a/README.de.md b/README.de.md
index e03557a06..9c25bad65 100644
--- a/README.de.md
+++ b/README.de.md
@@ -13,6 +13,7 @@
[](https://discord.gg/vccAQBr)
[](https://f-droid.org/packages/io.github.wulkanowy/)
[](https://github.com/wulkanowy/wulkanowy/releases)
+[](https://translate.wulkanowy.net.pl)
Inoffizieller Android VULCAN UONET+ Registrierungsclient für Schüler und ihre Eltern
diff --git a/README.en.md b/README.en.md
index 1ac2a6721..708d30bdb 100644
--- a/README.en.md
+++ b/README.en.md
@@ -13,6 +13,7 @@
[](https://discord.gg/vccAQBr)
[](https://f-droid.org/packages/io.github.wulkanowy/)
[](https://github.com/wulkanowy/wulkanowy/releases)
+[](https://translate.wulkanowy.net.pl)
Unofficial android VULCAN UONET+ register client for both students and their parents
diff --git a/README.md b/README.md
index e7c7d4c5e..86b83552a 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@
[](https://discord.gg/vccAQBr)
[](https://f-droid.org/packages/io.github.wulkanowy/)
[](https://github.com/wulkanowy/wulkanowy/releases)
+[](https://translate.wulkanowy.net.pl)
Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
diff --git a/README.sk.md b/README.sk.md
index 2f3ba41dd..d318936aa 100644
--- a/README.sk.md
+++ b/README.sk.md
@@ -13,6 +13,7 @@
[](https://discord.gg/vccAQBr)
[](https://f-droid.org/packages/io.github.wulkanowy/)
[](https://github.com/wulkanowy/wulkanowy/releases)
+[](https://translate.wulkanowy.net.pl)
Neoficiálny klient denníka VULCAN UONET+ pre žiaka a rodičov
From b269360ecb852bfaf9eb3b97c762e7e7c689c9e1 Mon Sep 17 00:00:00 2001
From: Damian Czupryn <60961958+Daxxxis@users.noreply.github.com>
Date: Sun, 30 Oct 2022 03:00:39 +0100
Subject: [PATCH 133/164] Langs placement in README adjustments (#2029)
---
README.cs.md | 10 ++--------
README.de.md | 8 +-------
README.en.md | 8 +-------
README.md | 8 +-------
README.sk.md | 10 ++--------
5 files changed, 7 insertions(+), 37 deletions(-)
diff --git a/README.cs.md b/README.cs.md
index 0d6da9c36..2b0dc12ea 100644
--- a/README.cs.md
+++ b/README.cs.md
@@ -1,10 +1,4 @@
-[English version of README](README.en.md)
-
-[Deutsche Version von README](README.de.md)
-
-[Polska wersja README](README.md)
-
-[Slovenská verzia README](README.sk.md)
+Česká verze / [Deutsche Version](README.de.md) / [English version](README.en.md) / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md)
# Wulkanowy
@@ -58,7 +52,7 @@ Aktuální verzi si můžete stáhnout z Google Play, F-Droid nebo Huawei AppGal
Můžete si také stáhnout [vývojovou verzi](https://wulkanowy.github.io/#download), která zahrnuje nové funkce připravované pro příští vydání
-## Postaveno s
+## Postaveno s pomocí
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
diff --git a/README.de.md b/README.de.md
index 9c25bad65..6df10ecd0 100644
--- a/README.de.md
+++ b/README.de.md
@@ -1,10 +1,4 @@
-[Polska wersja README](README.md)
-
-[English version of README](README.en.md)
-
-[Česká verze README](README.cs.md)
-
-[Slovenská verzia README](README.sk.md)
+[Česká verze](README.cs.md) / Deutsche Version / [English version](README.en.md) / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md)
# Wulkanowy
diff --git a/README.en.md b/README.en.md
index 708d30bdb..417b74de0 100644
--- a/README.en.md
+++ b/README.en.md
@@ -1,10 +1,4 @@
-[Polska wersja README](README.md)
-
-[Deutsche Version von README](README.de.md)
-
-[Česká verze README](README.cs.md)
-
-[Slovenská verzia README](README.sk.md)
+[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / English version / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md)
# Wulkanowy
diff --git a/README.md b/README.md
index 86b83552a..75b6cfca2 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,4 @@
-[English version of README](README.en.md)
-
-[Deutsche Version von README](README.de.md)
-
-[Česká verze README](README.cs.md)
-
-[Slovenská verzia README](README.sk.md)
+[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / [English version](README.en.md) / Polska wersja / [Slovenská verzia](README.sk.md)
# Wulkanowy
diff --git a/README.sk.md b/README.sk.md
index d318936aa..240f8835c 100644
--- a/README.sk.md
+++ b/README.sk.md
@@ -1,10 +1,4 @@
-[English version of README](README.en.md)
-
-[Deutsche Version von README](README.de.md)
-
-[Polska wersja README](README.md)
-
-[Česká verze README](README.cs.md)
+[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / [English version](README.en.md) / [Polska wersja](README.md) / Slovenská verzia
# Wulkanowy
@@ -58,7 +52,7 @@ Aktuálnu verziu si môžete stiahnuť z Google Play, F-Droid alebo Huawei AppGa
Môžete si tiež stiahnuť [vývojovú verziu](https://wulkanowy.github.io/#download), ktorá zahrňuje nové funkcie pripravované pre budúce vydanie
-## Postavené s
+## Postavené s pomocou
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
From d924902dacac95123477dd6410c62430785aaa3c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 1 Nov 2022 19:49:56 +0000
Subject: [PATCH 134/164] Bump CircularImageView from 4.2.0 to 4.3.0 (#2036)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 6211db2d8..d7fcfa8f7 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -209,7 +209,7 @@ dependencies {
implementation "com.google.android.material:material:1.7.0"
implementation "com.github.wulkanowy:material-chips-input:2.3.1"
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
- implementation 'com.github.lopspower:CircularImageView:4.2.0'
+ implementation 'com.github.lopspower:CircularImageView:4.3.0'
implementation "androidx.work:work-runtime-ktx:$work_manager"
playImplementation "androidx.work:work-gcm:$work_manager"
From 4113bd9b538428cb6465cc3380b4b4d2f25ba9b1 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 1 Nov 2022 19:50:17 +0000
Subject: [PATCH 135/164] Bump agconnect-crash from 1.7.2.300 to 1.7.3.300
(#2035)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index d7fcfa8f7..c250e7ead 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -250,7 +250,7 @@ dependencies {
playImplementation 'com.google.android.gms:play-services-ads:21.3.0'
hmsImplementation 'com.huawei.hms:hianalytics:6.8.0.300'
- hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.2.300'
+ hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.3.300'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
From 86fe2b61cb9c158e53682974c11484343141e003 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 1 Nov 2022 19:50:37 +0000
Subject: [PATCH 136/164] Bump agcp from 1.7.2.300 to 1.7.3.300 (#2034)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 5131796bb..fa66d9304 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,7 +16,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.google.gms:google-services:4.3.14'
- classpath 'com.huawei.agconnect:agcp:1.7.2.300'
+ classpath 'com.huawei.agconnect:agcp:1.7.3.300'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2'
classpath "com.github.triplet.gradle:play-publisher:3.6.0"
classpath "ru.cian:huawei-publish-gradle-plugin:1.3.4"
From 02cd4e4e06850b95a845b45db8c2b7f0194061ad Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 1 Nov 2022 19:50:59 +0000
Subject: [PATCH 137/164] Bump sonarqube-gradle-plugin from 3.4.0.2513 to
3.5.0.2730 (#2033)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index fa66d9304..3773dbc38 100644
--- a/build.gradle
+++ b/build.gradle
@@ -20,7 +20,7 @@ buildscript {
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2'
classpath "com.github.triplet.gradle:play-publisher:3.6.0"
classpath "ru.cian:huawei-publish-gradle-plugin:1.3.4"
- classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513"
+ classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.5.0.2730"
classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0"
classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$about_libraries"
}
From 21fe20924643fa4c6db0aa05b2bbee30d48ba071 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 1 Nov 2022 19:51:28 +0000
Subject: [PATCH 138/164] Bump firebase-bom from 31.0.1 to 31.0.2 (#2032)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index c250e7ead..a8f68884e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -241,7 +241,7 @@ dependencies {
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
- playImplementation platform('com.google.firebase:firebase-bom:31.0.1')
+ playImplementation platform('com.google.firebase:firebase-bom:31.0.2')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
From 62b7d42a73d0f422b02995f049449966020f0df6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Borcz?=
Date: Tue, 1 Nov 2022 20:57:05 +0100
Subject: [PATCH 139/164] New Crowdin updates (#1966)
---
app/src/main/res/values-de/strings.xml | 14 +-
.../res/values-es-rES/preferences_values.xml | 65 ++
app/src/main/res/values-es-rES/strings.xml | 715 ++++++++++++++++++
app/src/main/res/values-uk/strings.xml | 38 +-
4 files changed, 806 insertions(+), 26 deletions(-)
create mode 100644 app/src/main/res/values-es-rES/preferences_values.xml
create mode 100644 app/src/main/res/values-es-rES/strings.xml
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 4dfeee4f6..7b544258a 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -632,10 +632,10 @@
Antwort mit Nachrichtenhistorie
Arithmetisches Mittel anzeigen, wenn keine Gewichte angegeben sind
Unterstützung
- Privacy Policy
- Agreements
- Consent to processing of data related to ads
- Show ads in app
+ Datenschutz-Bestimmungen
+ Vereinbarungen
+ Zustimmung zur Verarbeitung von Daten im Zusammenhang mit Anzeigen
+ Anzeigen in der App anzeigen
Einzelanzeige ansehen, um Projekt zu unterstützen
Einwilligung in die Datenverarbeitung
Um eine Anzeige zu sehen, müssen Sie mit den Datenverarbeitungsbedingungen unserer Datenschutzerklärung einverstanden sein
@@ -647,9 +647,9 @@
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
Personalisierte Werbung
keine personalisierte Werbung
- I am over 18 years old
- Yes, personalized ads
- Yes, non-personalized ads
+ Ich bin über 18 Jahre alt
+ Ja, personalisierte Werbung
+ Ja, nicht personalisierte Werbung
Erweitert
Aussehen & Verhalten
Benachrichtigungen
diff --git a/app/src/main/res/values-es-rES/preferences_values.xml b/app/src/main/res/values-es-rES/preferences_values.xml
new file mode 100644
index 000000000..ac2b6e9e5
--- /dev/null
+++ b/app/src/main/res/values-es-rES/preferences_values.xml
@@ -0,0 +1,65 @@
+
+
+
+ - Light
+ - Dark
+ - Black (AMOLED)
+
+
+ - System language
+ - Polski
+ - English
+ - Pусский
+ - Українська
+ - Deutsch
+ - Čeština
+ - Slovenčina
+
+
+ - 15 minutes
+ - 30 minutes
+ - 1 hour
+ - 2 hours
+ - 6 hours
+ - 12 hours
+ - 24 hours
+
+
+ - 0,00
+ - 0,25
+ - 0,33
+ - 0,5
+ - 0,75
+
+
+ - Alphabetically
+ - By date
+ - By average
+
+
+ - Dzienniczek+
+ - Wulkanowy
+ - Grade colors in register
+
+
+ - Up to 1 at once
+ - Always expanded
+ - Unlimited expansions
+
+
+ - Average of grades only from selected semester
+ - Average of averages from both semesters
+ - Average of grades from the whole year
+
+
+ - Lucky number
+ - Unread messages
+ - Attendance
+ - Lessons
+ - Grades
+ - Homework
+ - School announcements
+ - Exams
+ - Conferences
+
+
diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml
new file mode 100644
index 000000000..aecc720b7
--- /dev/null
+++ b/app/src/main/res/values-es-rES/strings.xml
@@ -0,0 +1,715 @@
+
+
+
+ Login
+ Wulkanowy
+ Grades
+ Attendance
+ Exams
+ Timetable
+ Settings
+ More
+ About
+ Log viewer
+ Debug
+ Notification debug
+ Contributors
+ Licenses
+ Messages
+ New message
+ New homework
+ Notes and achievements
+ Homework
+ Accounts manager
+ Select account
+ Account details
+ Student info
+ Dashboard
+ Notifications center
+
+ Semester %1$d, %2$d/%3$d
+
+ Sign in with the student or parent account
+ Enter the symbol from the register page for account: <b>%1$s</b>
+ Username
+ Email
+ Login, PESEL or e-mail
+ Password
+ UONET+ register variant
+ Mobile API
+ Scraper
+ Hybrid
+ Token
+ PIN
+ Symbol
+ Sign in
+ Password too short
+ Login details are incorrect
+ %1$s. Make sure the correct UONET+ register variation is selected below
+ Invalid PIN
+ Invalid token
+ Token expired
+ Invalid email
+ Use the assigned login instead of email
+ Use the assigned login or email in @%1$s
+ Invalid symbol
+ Student not found. Validate the symbol and the chosen variation of the UONET+ register
+ Selected student is already logged in
+ The symbol can be found on the register page in Uczeń → Dostęp Mobilny → Zarejestruj urządzenie mobilne.\n\nMake sure that you have set the appropriate register variant in the UONET+ register variant field on the previous screen
+ Select students to log in to the application
+ Other options
+ In this mode, a lucky number does not work, a class grade stats, summary of attendance, excuse for absence, completed lessons, school information and preview of the list of registered devices
+ This mode displays the same data as it appears on the register website
+ The combination of the best features of the other two modes. It works faster than scraper and provides features not available in the Mobile API mode. It is in the experimental phase
+ Privacy policy
+ Trouble signing in? Contact us!
+ Email
+ Discord
+ Send email
+ Make sure you select the correct UONET+ register variation!
+ I forgot my password
+ Recover your account
+ Recover
+ Student is already signed in
+ Standard
+
+ Account manager
+ Log in
+ Session expired
+ Session expired, log in again
+ Application support
+ Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time
+ Enable ads
+
+ Grade
+ Semester %d
+ Change semester
+ No grades
+ Weight
+ Weight: %s
+ Comment
+ Number of new ratings: %1$d
+ Average: %1$.2f
+ Points: %s
+ No average
+ Total points
+ Final grade
+ Predicted grade
+ Calculated average
+ How does Calculated Average work?
+ The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\nAverage of grades only from selected semester:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\nAverage of averages from both semesters:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\nAverage of grades from the whole year:\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n2. Adding calculated averages\n3. Calculating the arithmetic average of summed averages
+ How does the Final Average work?
+ The Final Average is the arithmetic average calculated from all currently available final grades in the given semester.\n\nThe calculation scheme consists of the following steps:\n1. Summing up the final grades given by teachers\n2. Divide by the number of subjects that have already been graded
+ Final average
+ from %1$d of %2$d subjects
+ Summary
+ Class
+ Mark as read
+ Partial
+ Semester
+ Points
+ Legend
+ Class average: %1$s
+ Your average: %1$s
+ Your grade: %1$s
+ Class
+ Student
+
+ - %d grade
+ - %d grades
+
+
+ - New grade
+ - New grades
+
+
+ - New predicted grade
+ - New predicted grades
+
+
+ - New final grade
+ - New final grades
+
+
+ - You received %1$d grade
+ - You received %1$d grades
+
+
+ - You received %1$d predicted grade
+ - You received %1$d predicted grades
+
+
+ - You received %1$d final grade
+ - You received %1$d final grades
+
+
+ Lesson
+ Room
+ Group
+ Hours
+ Changes
+ No lessons this day
+ %s min
+ %s sec
+ %1$s left
+ in %1$s
+ Finished
+ Now: %s
+ Next: %s
+ Later: %s
+ %1$s lesson %2$d - %3$s
+ Change of room from %1$s to %2$s
+ Change of teacher from %1$s to %2$s
+ Change of subject from %1$s to %2$s
+
+ - Timetable change
+ - Timetable changes
+
+
+ - %1$s - %2$d change in timetable
+ - %1$s - %2$d changes in timetable
+
+
+ - %1$d change in timetable
+ - %1$d changes in timetable
+
+
+ - %d change
+ - %d changes
+
+
+ Completed lessons
+ Show completed lessons
+ No info about completed lessons
+ Topic
+ Absence
+ Resources
+
+ Additional lessons
+ Show additional lessons
+ No info about additional lessons
+ New lesson
+ New additional lesson
+ Additional lesson added successfully
+ Additional lesson deleted successfully
+ Repeat weekly
+ Delete additional lesson
+ Just this lesson
+ All in the series
+ Start time
+ End time
+ End time must be greater than start time
+
+ Attendance summary
+ Absent for school reasons
+ Excused absence
+ Unexcused absence
+ Exemption
+ Excused lateness
+ Unexcused lateness
+ Present
+ Deleted
+ Unknown
+ Number of lesson
+ No entries
+ Absence reason (optional)
+ Send
+ Absence excuse request sent successfully!
+ You must select at least one absence!
+ Excuse
+
+ - New attendance
+ - New attendance
+
+
+ - %1$d new attendance
+ - %1$d attendance
+
+
+ - %d attendance
+ - %d attendance
+
+
+ Total
+
+ No exams this week
+ Type
+ Entry date
+
+ - New exam
+ - New exams
+
+
+ - %d new exam
+ - %d new exams
+
+
+ - %d exam
+ - %d exams
+
+
+ Inbox
+ Sent
+ Trash
+ (no subject)
+ No messages
+ From:
+ To:
+ Date: %1$s
+ Reply
+ Forward
+ Select all
+ Unselect all
+ Move to trash
+ Delete permanently
+ Message deleted successfully
+ student
+ parent
+ guardian
+ employee
+ Share
+ Print
+ Subject
+ Content
+ Message sent successfully
+ Message does not exist
+ You need to choose at least 1 recipient
+ The message content must be at least 3 characters
+ Only unread
+ Only with attachments
+ Read: %s
+
+ - %1$d message
+ - %1$d messages
+
+
+ - New message
+ - New messages
+
+ Do you want to restore draft message?
+ Do you want to restore draft message with recipients: %s?
+
+ - You received %1$d message
+ - You received %1$d messages
+
+
+ - %1$d selected
+ - %1$d selected
+
+ Messages deleted
+
+ No info about notes
+ Points
+
+ - %d note
+ - %d notes
+
+
+ - New note
+ - New notes
+
+
+ - You received %1$d note
+ - You received %1$d notes
+
+
+
+ - %d praise
+ - %d praises
+
+
+ - New praise
+ - New praises
+
+
+ - You received %1$d praise
+ - You received %1$d praises
+
+
+
+ - %d neutral note
+ - %d neutral notes
+
+
+ - New neutral note
+ - New neutral notes
+
+
+ - You received %1$d neutral note
+ - You received %1$d neutral notes
+
+
+ No info about homework
+ Mark as done
+ Mark as undone
+ Add homework
+ Homework added successfully
+ Homework deleted successfully
+ Attachments
+
+ - New homework
+ - New homework
+
+
+ - You received %d new homework
+ - You received %d new homework
+
+
+ - %d homework
+ - %d homework
+
+
+ Lucky number
+ Today\'s lucky number is
+ No info about the lucky number
+ Lucky number for today
+ Today\'s lucky number is: %s
+ Show history
+
+ Lucky number history
+ No info about lucky numbers
+
+ Mobile devices
+ No devices
+ Deregister
+ Device removed
+ QR code
+ Token
+ Symbol
+ PIN
+
+ School and teachers
+
+ School
+ No info about school
+ School name
+ School address
+ Telephone
+ Name of headmaster
+ Name of pedagogue
+ Show on map
+ Call
+
+ Teachers
+ No info about teachers
+ No subject
+
+ Conferences
+ No info about conferences
+
+ - %d conference
+ - %d conferences
+
+
+ - New conference
+ - New conferences
+
+
+ - You have %1$d new conference
+ - You have %1$d new conferences
+
+ Present at conference
+ Agenda
+
+ School announcements
+ No school announcements
+
+ - %d school announcement
+ - %d school announcements
+
+
+ - New school announcement
+ - New school announcements
+
+
+ - You have %1$d new school announcement
+ - You have %1$d new school announcements
+
+
+ Add account
+ Logout
+ Do you want to log out this student?
+ Student logout
+ Student account
+ Parent account
+ Edit data
+ Accounts manager
+ Select student
+ Family
+ Contact
+ Residence details
+ Personal information
+
+ App version
+ Contributors
+ List of Wulkanowy developers
+ Report a bug
+ Send a bug report via e-mail
+ FAQ
+ Read Frequently Asked Questions
+ Discord server
+ Join the Wulkanowy community
+ Facebook fanpage
+ Twitter page
+ Follow us on twitter
+ Like our facebook fanpage
+ Privacy policy
+ Rules for collecting personal data
+ System settings
+ Open system settings
+ Homepage
+ Visit the website and help develop the application
+ Licenses
+ Licenses of libraries used in the application
+
+ License
+
+ Avatar
+ See more on GitHub
+
+ No info about student or student family
+ Name
+ Second name
+ Gender
+ Polish citizenship
+ Family name
+ Mother\'s and father\'s names
+ Phone
+ Cellphone
+ E-mail
+ Address of residence
+ Address of registration
+ Correspondence address
+ Surname and first name
+ Degree of kinship
+ Address
+ Phones
+ Male
+ Female
+ Last name
+ Guardian
+
+ Nick
+ Add nick
+ Choose avatar color
+
+ Share logs
+ Refresh
+
+ Lessons
+ (Tomorrow)
+ (Today and tomorrow)
+ In a moment:
+ Soon:
+ First:
+ Now:
+ End of lessons
+ Next:
+ Later:
+
+ - %1$d more lesson
+ - %1$d more lessons
+
+ until %1$s
+ No upcoming lessons
+ An error occurred while loading the lessons
+ Homework
+ No homework to do
+ An error occurred while loading the homework
+
+ - %1$d more homework
+ - %1$d more homework
+
+ due %1$s
+ Last grades
+ No new grades
+ An error occurred while loading the grades
+ School announcements
+ No current announcements
+ An error occurred while loading the announcements
+
+ - %1$d more announcement
+ - %1$d more announcements
+
+ Exams
+ No upcoming exams
+ An error occurred while loading the exams
+
+ - %1$d more exam
+ - %1$d more exams
+
+ Conferences
+ No upcoming conferences
+ An error occurred while loading the conferences
+
+ - %1$d more conference
+ - %1$d more conferences
+
+ An error occurred while loading data
+ None
+
+ Check for updates
+ Before reporting a bug, check first if an update with the bug fix is available
+
+ Content
+ Retry
+ Description
+ No description
+ Teacher
+ Date
+ Entry date
+ Color
+ Details
+ Category
+ Close
+ No data
+ Subject
+ Prev
+ Next
+ Search
+ Search…
+ Yes
+ No
+ Save
+ Title
+ Add
+ Copied
+ Undo
+ Change
+ Add to calendar
+
+ No lessons
+ Choose theme
+ Light
+ Dark
+ System Theme
+
+ App
+ Default view
+ Calculated average options
+ Force average calculation by app
+ Show presence
+ Theme
+ Grades expanding
+ Mark current lesson
+ Show groups next to subjects
+ Show chart list in class grades
+ Show subjects without grades
+ Grades color scheme
+ Subjects sorting
+ Language
+ Notifications
+ Other
+ Show notifications
+ Show upcoming lesson notifications
+ Make upcoming lesson notification persistent
+ Turn off when notification is not showing in your watch/band
+ Open system notification settings
+ Fix synchronization & notifications issues
+ Your device may have data synchronization issues and with notifications.\n\nTo fix them, you need to add Wulkanowy to the autostart and turn off battery optimization/saving in the phone settings.
+ Show debug notifications
+ Synchronization is disabled
+ Official app notifications
+ Capture official app notifications
+ Remove official app notifications after capture
+ Capture notifications
+ With this feature you can gain a substitute of push notifications like in the official app. All you need to do is allow Wulkanowy to receive all notifications in your system settings.\n\nHow it works?\nWhen you get a notification in Dziennik VULCAN, Wulkanowy will be notified (that\'s what these extra permissions are for) and will trigger a sync so that can send its own notification.\n\nFOR ADVANCED USERS ONLY
+ Upcoming lesson notifications
+ You must allow the Wulkanowy app to set alarms and reminders in your system settings to use this feature.
+ Go to settings
+ Synchronization
+ Automatic update
+ Suspended on holidays
+ Updates interval
+ Wi-Fi only
+ Sync now
+ Synced!
+ Sync failed
+ Sync in progress
+ Last full sync: %s
+ Value of the plus
+ Value of the minus
+ Reply with message history
+ Show arithmetic average when no weights provided
+ Support
+ Privacy Policy
+ Agreements
+ Consent to processing of data related to ads
+ Show ads in app
+ Watch single ad to support project
+ Consent to data processing
+ To view an advertisement you must agree to the data processing terms of our Privacy Policy
+ Agree
+ Privacy policy
+ Ad is loading
+ Thank you for your support, come back later for more ads
+ Can we use your data to display ads?
+ 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
+ Personalized ads
+ Non-personalized ads
+ I am over 18 years old
+ Yes, personalized ads
+ Yes, non-personalized ads
+ Advanced
+ Appearance & Behavior
+ Notifications
+ Synchronization
+ Advertisements
+ Grades
+ Dashboard
+ Tiles visibility
+ Attendance
+ Timetable
+ Grades
+ Calculated average
+ Messages
+ Appearance & Behavior
+ Languages, themes, subjects sorting
+ App notifications, fix problems
+ Notifications
+ Synchronization
+ Automatic update, synchronization interval
+ Plus and minus values, average calculation
+ Advanced
+ App version, contributors, social portals
+ Displaying advertisements, project support
+
+ New grades
+ New homework
+ New conferences
+ New exams
+ Lucky number
+ New messages
+ New notes
+ New school announcements
+ Push notifications
+ Upcoming lessons
+ Debug
+ Timetable change
+ New attendance
+
+ Black
+ Red
+ Blue
+ Green
+ Purple
+ No color
+
+ Download of updates has started…
+ An update has just been downloaded.
+ Restart
+ Update failed! Wulkanowy may not function properly. Consider updating
+
+ No internet connection
+ An error occurred. Check your device clock
+ Connection to register failed. Servers can be overloaded. Please try again later
+ Loading data failed. Please try again later
+ Register password change required
+ Maintenance underway UONET + register. Try again later
+ Unknown UONET + register error. Try again later
+ Unknown application error. Please try again later
+ An unexpected error occurred
+ Feature disabled by your school
+ Feature not available. Login in a mode other than Mobile API
+ This field is required
+
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index f90e78e7d..2c104ecbf 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -77,9 +77,9 @@
Увійти
Минув термін дії сесії
Минув термін дії сесії, авторизуйтеся знову
- Application support
- Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time
- Enable ads
+ Підтримка додатків
+ Вам подобається цей додаток? Підтримуйте його розвиток, увімкнувши неінвазивну рекламу, яку ви можете будь-коли вимкнути
+ Увімкнути рекламу
Оцінка
%d семестр
@@ -97,7 +97,7 @@
Передбачувана оцінка
Розрахована середня оцінка
Як працює \"Розрахована середня оцінка\"?
- The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\nAverage of grades only from selected semester:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\nAverage of averages from both semesters:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\nAverage of grades from the whole year:\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n2. Adding calculated averages\n3. Calculating the arithmetic average of summed averages
+ Розрахована середня оцінка - це середнє арифметичне, обчислене з середніх оцінок з предметів.Це дозволяє дізнатися приблизну кінцеву середню оцінку.Вона розраховується способом, обраним користувачем у налаштуваннях програми.Рекомендується вибрати відповідний варіант, тому що кожна школа по різному розраховує середню оцінку.Крім того, якщо у вашій школі повідомляється середня оцінка з предметів на сторінці Vulcan, програма тільки завантажує ці оцінки.Це можна змінити шляхом примусового розрахунку середньоЇ оцінки в налаштуваннях програми.\n\nСередні оцінки тільки за обраний семестр:\n1. Розрахунок середньозваженого числа для кожного предмета в даному семестрі\n2. Сумування розрахованих числ\n3. Розрахунок середнього арифметичного з сумованих чисел\n\nСереднє значення з обох семестрів:\n1. Обчислення середньозваженого числа для кожного предмета у 1 та 2 семестрі\n2. Обчислення середнього арифметичного з розрахованих середньозважених числ за 1 та 2 семестри для кожного предмета.\n3. Додавання розрахованих середніх\n4. Розрахунок середнього арифметичного підсумованих середніх значень\n\nСереднє значення оцінок за весь рік: \n1. Розрахунок середньозваженого числа за рік для кожного предмета. Підсумковий середній показник у 1-му семестрі не має значення.\n2. Сумування розрахованих середніх\n3. Обчислення середнього арифметичного з суммованих середніх
Як працює \"Підсумкова середня оцінка\"?
Підсумкове середнє значення - це середнє арифметичне, обчислене з усіх наявних наразі підсумкових оцінок у даному семестрі. \n\nСхема обчислення складається з таких кроків:\n1. Сумування підсумкових оцінок, виставленних викладачами\n2. Ділення на кількість предметів, з яких виставлені ці оцінки
Підсумкова середня оцінка
@@ -297,10 +297,10 @@
Перемістити до кошика
Видалити назавжди
Лист було успішно видалено
- student
- parent
- guardian
- employee
+ студент
+ батькові
+ опікун
+ працівник
Поділитись
Друк
Тема
@@ -720,10 +720,10 @@
Відповісти з історією повідомлень
Вилічити середню аритметичну, якщо оцінка немає вартості
Підтримка
- Privacy Policy
- Agreements
- Consent to processing of data related to ads
- Show ads in app
+ Політика конфіденційності
+ Угоди
+ Згода на обробку даних, пов’язаних з оголошеннями
+ Показувати рекламу в додатку
Подивіться одну рекламу для підтримки проєкту
Згода в обробці даних
Щоб переглянути рекламу, ви повинні погодитися з умовами обробки даних нашої Політики конфіденційності
@@ -731,13 +731,13 @@
Політика конфіденційності
Реклама завантажується
Дякуємо за вашу підтримку, повертайтеся пізніше для більшої кількості реклам
- Can we use your data to display ads?
- 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
- Personalized ads
- Non-personalized ads
- I am over 18 years old
- Yes, personalized ads
- Yes, non-personalized ads
+ Чи можемо ми використовувати ваші дані для відбивання реклами?
+ Ви можете змінити свій вибір в будь-який час в налаштуваннях додатку. Ми можемо використовувати ваші дані для відбивання оголошень, адаптованої до вас або, використовуючи менше ваших даних, відбивати неперсоналізовані оголошення. Перегляньте нашу Політику конфіденційності для деталей
+ Персоналізовані оголошення
+ Неперсоналізована реклама
+ Мені більше 18 років
+ Так, персоналізована реклама
+ Так, неперсоналізована реклама
Додатково
Вигляд та поведінка
Сповіщення
From 50b6d380b6e7c9c5537ddcce698e9b8c00c9db0d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Borcz?=
Date: Wed, 2 Nov 2022 16:44:05 +0100
Subject: [PATCH 140/164] Fix unexpected error in support ad when no internet
(#2030)
---
.../ui/modules/settings/ads/AdsPresenter.kt | 21 ++++++++++++-----
.../io/github/wulkanowy/utils/AdsHelper.kt | 23 +++++++++++++++++++
2 files changed, 38 insertions(+), 6 deletions(-)
diff --git a/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsPresenter.kt b/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsPresenter.kt
index 772d616d7..28c98e3c3 100644
--- a/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsPresenter.kt
+++ b/app/src/play/java/io/github/wulkanowy/ui/modules/settings/ads/AdsPresenter.kt
@@ -31,13 +31,22 @@ class AdsPresenter @Inject constructor(
view?.showLoadingSupportAd(true)
presenterScope.launch {
runCatching { adsHelper.getSupportAd() }
- .onFailure(errorHandler::dispatch)
- .onSuccess { it?.let { view?.showAd(it) } }
+ .onFailure {
+ errorHandler.dispatch(it)
- view?.run {
- showLoadingSupportAd(false)
- showWatchAdOncePerVisit(true)
- }
+ view?.run {
+ showLoadingSupportAd(false)
+ showWatchAdOncePerVisit(false)
+ }
+ }
+ .onSuccess {
+ it?.let { view?.showAd(it) }
+
+ view?.run {
+ showLoadingSupportAd(false)
+ showWatchAdOncePerVisit(true)
+ }
+ }
}
}
diff --git a/app/src/play/java/io/github/wulkanowy/utils/AdsHelper.kt b/app/src/play/java/io/github/wulkanowy/utils/AdsHelper.kt
index c536e2218..d5f65b46d 100644
--- a/app/src/play/java/io/github/wulkanowy/utils/AdsHelper.kt
+++ b/app/src/play/java/io/github/wulkanowy/utils/AdsHelper.kt
@@ -1,8 +1,12 @@
package io.github.wulkanowy.utils
import android.content.Context
+import android.net.ConnectivityManager
+import android.net.NetworkCapabilities
+import android.os.Build
import android.os.Bundle
import android.view.View
+import androidx.core.content.getSystemService
import com.google.ads.mediation.admob.AdMobAdapter
import com.google.android.gms.ads.*
import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd
@@ -10,6 +14,7 @@ import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAdLoa
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.BuildConfig
import io.github.wulkanowy.data.repositories.PreferencesRepository
+import java.net.UnknownHostException
import javax.inject.Inject
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
@@ -28,6 +33,10 @@ class AdsHelper @Inject constructor(
}
suspend fun getSupportAd(): RewardedInterstitialAd? {
+ if (!context.isInternetConnected()) {
+ throw UnknownHostException()
+ }
+
val extra = Bundle().apply { putString("npa", "1") }
val adRequest = AdRequest.Builder()
.apply {
@@ -84,4 +93,18 @@ class AdsHelper @Inject constructor(
}
}
+@Suppress("DEPRECATION")
+private fun Context.isInternetConnected(): Boolean {
+ val connectivityManager = getSystemService() ?: return false
+
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ val currentNetwork = connectivityManager.activeNetwork
+ val networkCapabilities = connectivityManager.getNetworkCapabilities(currentNetwork)
+
+ networkCapabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) == true
+ } else {
+ connectivityManager.activeNetworkInfo?.isConnected == true
+ }
+}
+
data class AdBanner(val view: View)
From 1257dc63d3c081ec75dffebfebf2fdc14dacd18f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 14 Nov 2022 18:21:17 +0000
Subject: [PATCH 141/164] Bump runner from 1.4.0 to 1.5.1 (#2047)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index a8f68884e..7142d92fb 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -264,7 +264,7 @@ dependencies {
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
testImplementation 'org.robolectric:robolectric:4.9'
- testImplementation "androidx.test:runner:1.4.0"
+ testImplementation "androidx.test:runner:1.5.1"
testImplementation "androidx.test.ext:junit:1.1.3"
testImplementation "androidx.test:core:1.4.0"
testImplementation "androidx.room:room-testing:$room"
From 66ff14f719bf021b83b43e09e5bca726a843d088 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 14 Nov 2022 18:21:35 +0000
Subject: [PATCH 142/164] Bump agcp from 1.7.3.300 to 1.7.3.301 (#2046)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 3773dbc38..ccce1c433 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,7 +16,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.google.gms:google-services:4.3.14'
- classpath 'com.huawei.agconnect:agcp:1.7.3.300'
+ classpath 'com.huawei.agconnect:agcp:1.7.3.301'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2'
classpath "com.github.triplet.gradle:play-publisher:3.6.0"
classpath "ru.cian:huawei-publish-gradle-plugin:1.3.4"
From fded5007c14ecbec95680e5b9c5960cab3e77927 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 14 Nov 2022 18:22:25 +0000
Subject: [PATCH 143/164] Bump firebase-bom from 31.0.2 to 31.0.3 (#2041)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 7142d92fb..40f571714 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -241,7 +241,7 @@ dependencies {
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
- playImplementation platform('com.google.firebase:firebase-bom:31.0.2')
+ playImplementation platform('com.google.firebase:firebase-bom:31.0.3')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
From 885319a8854f22cfa91dd097db8492599d09fd25 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 14 Nov 2022 18:36:20 +0000
Subject: [PATCH 144/164] Bump hilt_version from 2.44 to 2.44.1 (#2044)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index ccce1c433..6f3ac4d63 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,7 +2,7 @@ buildscript {
ext {
kotlin_version = '1.7.20'
about_libraries = '10.5.1'
- hilt_version = "2.44"
+ hilt_version = "2.44.1"
}
repositories {
mavenCentral()
From d6385e8cdd06b3636568b32aab5c0064e8bbd8cc Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 14 Nov 2022 20:31:02 +0000
Subject: [PATCH 145/164] Bump core from 1.4.0 to 1.5.0 (#2045)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 40f571714..1edcc753e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -266,7 +266,7 @@ dependencies {
testImplementation 'org.robolectric:robolectric:4.9'
testImplementation "androidx.test:runner:1.5.1"
testImplementation "androidx.test.ext:junit:1.1.3"
- testImplementation "androidx.test:core:1.4.0"
+ testImplementation "androidx.test:core:1.5.0"
testImplementation "androidx.room:room-testing:$room"
testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
kaptTest "com.google.dagger:hilt-android-compiler:$hilt_version"
From b8296ac02f94e17e972c74980bcf480352abaef6 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 14 Nov 2022 20:31:26 +0000
Subject: [PATCH 146/164] Bump kotlin_version from 1.7.20 to 1.7.21 (#2042)
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 6f3ac4d63..e8e1052b6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,6 @@
buildscript {
ext {
- kotlin_version = '1.7.20'
+ kotlin_version = '1.7.21'
about_libraries = '10.5.1'
hilt_version = "2.44.1"
}
From 4d49e956b881125354b86228a12c50e49ea6fd8c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 14 Nov 2022 20:48:12 +0000
Subject: [PATCH 147/164] Bump junit from 1.1.3 to 1.1.4 (#2043)
---
app/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index 1edcc753e..11f055ea8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -265,7 +265,7 @@ dependencies {
testImplementation 'org.robolectric:robolectric:4.9'
testImplementation "androidx.test:runner:1.5.1"
- testImplementation "androidx.test.ext:junit:1.1.3"
+ testImplementation "androidx.test.ext:junit:1.1.4"
testImplementation "androidx.test:core:1.5.0"
testImplementation "androidx.room:room-testing:$room"
testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
From db4f172fb83bd4ca4a3f7219ae5e6f40f87d5727 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Wed, 16 Nov 2022 12:54:55 +0100
Subject: [PATCH 148/164] Fix unread status in sent messages (#2048)
---
app/build.gradle | 2 +-
.../52.json | 2421 +++++++++++++++++
.../github/wulkanowy/data/db/AppDatabase.kt | 3 +-
.../wulkanowy/data/db/entities/Message.kt | 6 +
.../wulkanowy/data/mappers/MessageMapper.kt | 4 +-
.../debug/notification/mock/message.kt | 2 +
.../message/preview/MessagePreviewAdapter.kt | 16 +-
app/src/main/res/values/strings.xml | 1 +
.../repositories/MessageRepositoryTest.kt | 6 +-
9 files changed, 2451 insertions(+), 10 deletions(-)
create mode 100644 app/schemas/io.github.wulkanowy.data.db.AppDatabase/52.json
diff --git a/app/build.gradle b/app/build.gradle
index 11f055ea8..99672f1f9 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -186,7 +186,7 @@ ext {
}
dependencies {
- implementation "io.github.wulkanowy:sdk:2840d9d6d0"
+ implementation "io.github.wulkanowy:sdk:701016eda2"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/52.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/52.json
new file mode 100644
index 000000000..129d1917b
--- /dev/null
+++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/52.json
@@ -0,0 +1,2421 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 52,
+ "identityHash": "8742176f26afcc81279d4a073dca2949",
+ "entities": [
+ {
+ "tableName": "Students",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`scrapper_base_url` TEXT NOT NULL, `mobile_base_url` TEXT NOT NULL, `login_type` TEXT NOT NULL, `login_mode` TEXT NOT NULL, `certificate_key` TEXT NOT NULL, `private_key` TEXT NOT NULL, `is_parent` INTEGER NOT NULL, `email` TEXT NOT NULL, `password` TEXT NOT NULL, `symbol` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `user_login_id` INTEGER NOT NULL, `user_name` TEXT NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_short` TEXT NOT NULL, `school_name` TEXT NOT NULL, `class_name` TEXT NOT NULL, `class_id` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `registration_date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `nick` TEXT NOT NULL, `avatar_color` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "scrapperBaseUrl",
+ "columnName": "scrapper_base_url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mobileBaseUrl",
+ "columnName": "mobile_base_url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginType",
+ "columnName": "login_type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginMode",
+ "columnName": "login_mode",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "certificateKey",
+ "columnName": "certificate_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "privateKey",
+ "columnName": "private_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isParent",
+ "columnName": "is_parent",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "password",
+ "columnName": "password",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "symbol",
+ "columnName": "symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "user_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentName",
+ "columnName": "student_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolSymbol",
+ "columnName": "school_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolShortName",
+ "columnName": "school_short",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolName",
+ "columnName": "school_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "className",
+ "columnName": "class_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isCurrent",
+ "columnName": "is_current",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registrationDate",
+ "columnName": "registration_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "nick",
+ "columnName": "nick",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "avatarColor",
+ "columnName": "avatar_color",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_Students_email_symbol_student_id_school_id_class_id",
+ "unique": true,
+ "columnNames": [
+ "email",
+ "symbol",
+ "student_id",
+ "school_id",
+ "class_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Students_email_symbol_student_id_school_id_class_id` ON `${TABLE_NAME}` (`email`, `symbol`, `student_id`, `school_id`, `class_id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Semesters",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `kindergarten_diary_id` INTEGER NOT NULL DEFAULT 0, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "kindergartenDiaryId",
+ "columnName": "kindergarten_diary_id",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ },
+ {
+ "fieldPath": "diaryName",
+ "columnName": "diary_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolYear",
+ "columnName": "school_year",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterName",
+ "columnName": "semester_name",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unitId",
+ "columnName": "unit_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "current",
+ "columnName": "is_current",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id",
+ "unique": true,
+ "columnNames": [
+ "student_id",
+ "diary_id",
+ "kindergarten_diary_id",
+ "semester_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id` ON `${TABLE_NAME}` (`student_id`, `diary_id`, `kindergarten_diary_id`, `semester_id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Exams",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `group` TEXT NOT NULL, `type` TEXT NOT NULL, `description` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entryDate",
+ "columnName": "entry_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "group",
+ "columnName": "group",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Timetable",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `number` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `subjectOld` TEXT NOT NULL, `group` TEXT NOT NULL, `room` TEXT NOT NULL, `roomOld` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacherOld` TEXT NOT NULL, `info` TEXT NOT NULL, `student_plan` INTEGER NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectOld",
+ "columnName": "subjectOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "group",
+ "columnName": "group",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "room",
+ "columnName": "room",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "roomOld",
+ "columnName": "roomOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherOld",
+ "columnName": "teacherOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "info",
+ "columnName": "info",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isStudentPlan",
+ "columnName": "student_plan",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "changes",
+ "columnName": "changes",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "canceled",
+ "columnName": "canceled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Attendance",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `time_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `excused` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `excusable` INTEGER NOT NULL, `excuse_status` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "timeId",
+ "columnName": "time_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presence",
+ "columnName": "presence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "exemption",
+ "columnName": "exemption",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lateness",
+ "columnName": "lateness",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excused",
+ "columnName": "excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deleted",
+ "columnName": "deleted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excusable",
+ "columnName": "excusable",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excuseStatus",
+ "columnName": "excuse_status",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AttendanceSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `subject_id` INTEGER NOT NULL, `month` INTEGER NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `absence_excused` INTEGER NOT NULL, `absence_for_school_reasons` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `lateness_excused` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subject_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "month",
+ "columnName": "month",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presence",
+ "columnName": "presence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absenceExcused",
+ "columnName": "absence_excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absenceForSchoolReasons",
+ "columnName": "absence_for_school_reasons",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lateness",
+ "columnName": "lateness",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "latenessExcused",
+ "columnName": "lateness_excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "exemption",
+ "columnName": "exemption",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Grades",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `entry` TEXT NOT NULL, `value` REAL NOT NULL, `modifier` REAL NOT NULL, `comment` TEXT NOT NULL, `color` TEXT NOT NULL, `grade_symbol` TEXT NOT NULL, `description` TEXT NOT NULL, `weight` TEXT NOT NULL, `weightValue` REAL NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entry",
+ "columnName": "entry",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "modifier",
+ "columnName": "modifier",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "color",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gradeSymbol",
+ "columnName": "grade_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weightValue",
+ "columnName": "weightValue",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isRead",
+ "columnName": "is_read",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `position` INTEGER NOT NULL, `subject` TEXT NOT NULL, `predicted_grade` TEXT NOT NULL, `final_grade` TEXT NOT NULL, `proposed_points` TEXT NOT NULL, `final_points` TEXT NOT NULL, `points_sum` TEXT NOT NULL, `average` REAL NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_predicted_grade_notified` INTEGER NOT NULL, `is_final_grade_notified` INTEGER NOT NULL, `predicted_grade_last_change` INTEGER NOT NULL, `final_grade_last_change` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "position",
+ "columnName": "position",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "predictedGrade",
+ "columnName": "predicted_grade",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalGrade",
+ "columnName": "final_grade",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "proposedPoints",
+ "columnName": "proposed_points",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalPoints",
+ "columnName": "final_points",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pointsSum",
+ "columnName": "points_sum",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "average",
+ "columnName": "average",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPredictedGradeNotified",
+ "columnName": "is_predicted_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFinalGradeNotified",
+ "columnName": "is_final_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "predictedGradeLastChange",
+ "columnName": "predicted_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalGradeLastChange",
+ "columnName": "final_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradePartialStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `class_average` TEXT NOT NULL, `student_average` TEXT NOT NULL, `class_amounts` TEXT NOT NULL, `student_amounts` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classAverage",
+ "columnName": "class_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAverage",
+ "columnName": "student_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classAmounts",
+ "columnName": "class_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAmounts",
+ "columnName": "student_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesPointsStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `others` REAL NOT NULL, `student` REAL NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "others",
+ "columnName": "others",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "student",
+ "columnName": "student",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradeSemesterStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `amounts` TEXT NOT NULL, `student_grade` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "amounts",
+ "columnName": "amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentGrade",
+ "columnName": "student_grade",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Messages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`message_global_key` TEXT NOT NULL, `mailbox_key` TEXT NOT NULL, `message_id` INTEGER NOT NULL, `correspondents` TEXT NOT NULL, `subject` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `read_by` INTEGER, `unread_by` INTEGER, `has_attachments` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `content` TEXT NOT NULL, `sender` TEXT, `recipients` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "messageGlobalKey",
+ "columnName": "message_global_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mailboxKey",
+ "columnName": "mailbox_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageId",
+ "columnName": "message_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "correspondents",
+ "columnName": "correspondents",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unread",
+ "columnName": "unread",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "readBy",
+ "columnName": "read_by",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "unreadBy",
+ "columnName": "unread_by",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hasAttachments",
+ "columnName": "has_attachments",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "sender",
+ "columnName": "sender",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "recipients",
+ "columnName": "recipients",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MessageAttachments",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`real_id` INTEGER NOT NULL, `message_global_key` TEXT NOT NULL, `url` TEXT NOT NULL, `filename` TEXT NOT NULL, PRIMARY KEY(`real_id`))",
+ "fields": [
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageGlobalKey",
+ "columnName": "message_global_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filename",
+ "columnName": "filename",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "real_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `category` TEXT NOT NULL, `category_type` INTEGER NOT NULL, `is_points_show` INTEGER NOT NULL, `points` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "categoryType",
+ "columnName": "category_type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPointsShow",
+ "columnName": "is_points_show",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "points",
+ "columnName": "points",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isRead",
+ "columnName": "is_read",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Homework",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `attachments` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_done` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `is_added_by_user` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entryDate",
+ "columnName": "entry_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "attachments",
+ "columnName": "attachments",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDone",
+ "columnName": "is_done",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Subjects",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "LuckyNumbers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "luckyNumber",
+ "columnName": "lucky_number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "CompletedLesson",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `topic` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `substitution` TEXT NOT NULL, `absence` TEXT NOT NULL, `resources` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "topic",
+ "columnName": "topic",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "substitution",
+ "columnName": "substitution",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "resources",
+ "columnName": "resources",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Mailboxes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`globalKey` TEXT NOT NULL, `fullName` TEXT NOT NULL, `userName` TEXT NOT NULL, `userLoginId` INTEGER NOT NULL, `studentName` TEXT NOT NULL, `schoolNameShort` TEXT NOT NULL, `type` TEXT NOT NULL, PRIMARY KEY(`globalKey`))",
+ "fields": [
+ {
+ "fieldPath": "globalKey",
+ "columnName": "globalKey",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "fullName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "userLoginId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentName",
+ "columnName": "studentName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolNameShort",
+ "columnName": "schoolNameShort",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "globalKey"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Recipients",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`mailboxGlobalKey` TEXT NOT NULL, `studentMailboxGlobalKey` TEXT NOT NULL, `fullName` TEXT NOT NULL, `userName` TEXT NOT NULL, `schoolShortName` TEXT NOT NULL, `type` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "mailboxGlobalKey",
+ "columnName": "mailboxGlobalKey",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentMailboxGlobalKey",
+ "columnName": "studentMailboxGlobalKey",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "fullName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolShortName",
+ "columnName": "schoolShortName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MobileDevices",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_login_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deviceId",
+ "columnName": "device_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Teachers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "shortName",
+ "columnName": "short_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "School",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT NOT NULL, `contact` TEXT NOT NULL, `headmaster` TEXT NOT NULL, `pedagogue` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "contact",
+ "columnName": "contact",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "headmaster",
+ "columnName": "headmaster",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pedagogue",
+ "columnName": "pedagogue",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Conferences",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `subject` TEXT NOT NULL, `agenda` TEXT NOT NULL, `present_on_conference` TEXT NOT NULL, `conference_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "agenda",
+ "columnName": "agenda",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presentOnConference",
+ "columnName": "present_on_conference",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "conferenceId",
+ "columnName": "conference_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableAdditional",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `repeat_id` BLOB DEFAULT NULL, `is_added_by_user` INTEGER NOT NULL DEFAULT 0)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "repeatId",
+ "columnName": "repeat_id",
+ "affinity": "BLOB",
+ "notNull": false,
+ "defaultValue": "NULL"
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "StudentInfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `full_name` TEXT NOT NULL, `first_name` TEXT NOT NULL, `second_name` TEXT NOT NULL, `surname` TEXT NOT NULL, `birth_date` INTEGER NOT NULL, `birth_place` TEXT NOT NULL, `gender` TEXT NOT NULL, `has_polish_citizenship` INTEGER NOT NULL, `family_name` TEXT NOT NULL, `parents_names` TEXT NOT NULL, `address` TEXT NOT NULL, `registered_address` TEXT NOT NULL, `correspondence_address` TEXT NOT NULL, `phone_number` TEXT NOT NULL, `cell_phone_number` TEXT NOT NULL, `email` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `first_guardian_full_name` TEXT, `first_guardian_kinship` TEXT, `first_guardian_address` TEXT, `first_guardian_phones` TEXT, `first_guardian_email` TEXT, `second_guardian_full_name` TEXT, `second_guardian_kinship` TEXT, `second_guardian_address` TEXT, `second_guardian_phones` TEXT, `second_guardian_email` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "full_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstName",
+ "columnName": "first_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "secondName",
+ "columnName": "second_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "surname",
+ "columnName": "surname",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthDate",
+ "columnName": "birth_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthPlace",
+ "columnName": "birth_place",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gender",
+ "columnName": "gender",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPolishCitizenship",
+ "columnName": "has_polish_citizenship",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "familyName",
+ "columnName": "family_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentsNames",
+ "columnName": "parents_names",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registeredAddress",
+ "columnName": "registered_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "correspondenceAddress",
+ "columnName": "correspondence_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "phoneNumber",
+ "columnName": "phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "cellPhoneNumber",
+ "columnName": "cell_phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstGuardian.fullName",
+ "columnName": "first_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.kinship",
+ "columnName": "first_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.address",
+ "columnName": "first_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.phones",
+ "columnName": "first_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.email",
+ "columnName": "first_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.fullName",
+ "columnName": "second_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.kinship",
+ "columnName": "second_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.address",
+ "columnName": "second_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.phones",
+ "columnName": "second_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.email",
+ "columnName": "second_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableHeaders",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "SchoolAnnouncements",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_login_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notifications",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `type` TEXT NOT NULL, `destination` TEXT NOT NULL DEFAULT '{\"type\":\"io.github.wulkanowy.ui.modules.Destination.Dashboard\"}', `date` INTEGER NOT NULL, `data` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "destination",
+ "columnName": "destination",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'{\"type\":\"io.github.wulkanowy.ui.modules.Destination.Dashboard\"}'"
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "data",
+ "columnName": "data",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AdminMessages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `version_name` INTEGER, `version_max` INTEGER, `target_register_host` TEXT, `target_flavor` TEXT, `destination_url` TEXT, `priority` TEXT NOT NULL, `type` TEXT NOT NULL, `is_dismissible` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "versionMin",
+ "columnName": "version_name",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "versionMax",
+ "columnName": "version_max",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetRegisterHost",
+ "columnName": "target_register_host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetFlavor",
+ "columnName": "target_flavor",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "destinationUrl",
+ "columnName": "destination_url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "priority",
+ "columnName": "priority",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDismissible",
+ "columnName": "is_dismissible",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '8742176f26afcc81279d4a073dca2949')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
index 15b38805b..e61ffe844 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
@@ -47,6 +47,7 @@ import javax.inject.Singleton
AutoMigration(from = 44, to = 45),
AutoMigration(from = 46, to = 47),
AutoMigration(from = 47, to = 48),
+ AutoMigration(from = 51, to = 52),
],
version = AppDatabase.VERSION_SCHEMA,
exportSchema = true
@@ -55,7 +56,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() {
companion object {
- const val VERSION_SCHEMA = 51
+ const val VERSION_SCHEMA = 52
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
Migration2(),
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt
index 77874e03d..323b00bec 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt
@@ -29,6 +29,12 @@ data class Message(
var unread: Boolean,
+ @ColumnInfo(name = "read_by")
+ val readBy: Int?,
+
+ @ColumnInfo(name = "unread_by")
+ val unreadBy: Int?,
+
@ColumnInfo(name = "has_attachments")
val hasAttachments: Boolean
) : Serializable {
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
index 2e7967f0e..c329607f4 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
@@ -16,7 +16,9 @@ fun List.mapToEntities(mailbox: Mailbox) = map {
date = it.dateZoned.toInstant(),
folderId = it.folderId,
unread = it.unread,
- hasAttachments = it.hasAttachments
+ unreadBy = it.unreadBy,
+ readBy = it.readBy,
+ hasAttachments = it.hasAttachments,
).apply {
content = it.content.orEmpty()
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/message.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/message.kt
index 6ff26162b..e31bd84a9 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/message.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/message.kt
@@ -22,6 +22,8 @@ private fun generateMessage(sender: String, subject: String) = Message(
date = Instant.now(),
folderId = 0,
unread = true,
+ readBy = 2,
+ unreadBy = 2,
hasAttachments = false,
messageGlobalKey = "",
correspondents = sender,
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewAdapter.kt
index 3c1c53d39..d3c6b95c7 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewAdapter.kt
@@ -1,6 +1,5 @@
package io.github.wulkanowy.ui.modules.message.preview
-import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -74,15 +73,20 @@ class MessagePreviewAdapter @Inject constructor() :
}
}
- @SuppressLint("SetTextI18n")
private fun bindMessage(holder: MessageViewHolder, message: Message) {
val context = holder.binding.root.context
+ val recipientCount = (message.unreadBy ?: 0) + (message.readBy ?: 0)
+ val isReceived = message.unreadBy == null
- val readTextValue = when {
- !message.unread -> R.string.all_yes
- else -> R.string.all_no
+ val readText = when {
+ recipientCount > 1 -> {
+ context.getString(R.string.message_read_by, message.readBy, recipientCount)
+ }
+ message.readBy == 1 || (isReceived && !message.unread) -> {
+ context.getString(R.string.message_read, context.getString(R.string.all_yes))
+ }
+ else -> context.getString(R.string.message_read, context.getString(R.string.all_no))
}
- val readText = context.getString(R.string.message_read, context.getString(readTextValue))
with(holder.binding) {
messagePreviewSubject.text = message.subject.ifBlank {
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 48376d216..e65a27fcc 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -304,6 +304,7 @@
Only unread
Only with attachments
Read: %s
+ Read by: %1$d of %2$d people
- %1$d message
- %1$d messages
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
index 4efc9c60a..9fc83a23b 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
@@ -193,7 +193,9 @@ class MessageRepositoryTest {
date = Instant.EPOCH,
folderId = 1,
unread = unread,
- hasAttachments = false
+ readBy = 1,
+ unreadBy = 1,
+ hasAttachments = false,
).apply {
this.content = content
}
@@ -209,6 +211,8 @@ class MessageRepositoryTest {
dateZoned = Instant.EPOCH.atZone(ZoneOffset.UTC),
folderId = 1,
unread = true,
+ readBy = 1,
+ unreadBy = 1,
hasAttachments = false,
)
}
From 51a1097bb4af2373bcd14ac8189e66f1cb606229 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Wed, 16 Nov 2022 13:46:47 +0100
Subject: [PATCH 149/164] Add mailbox chooser to messages (#2002)
---
.../53.json | 2439 +++++++++++++++++
.../github/wulkanowy/data/db/AppDatabase.kt | 3 +-
.../wulkanowy/data/db/dao/MailboxDao.kt | 8 +-
.../wulkanowy/data/db/dao/MessagesDao.kt | 3 +
.../wulkanowy/data/db/entities/Mailbox.kt | 11 +-
.../wulkanowy/data/db/entities/Message.kt | 3 +
.../data/db/migrations/Migration53.kt | 57 +
.../wulkanowy/data/mappers/MailboxMapper.kt | 4 +-
.../wulkanowy/data/mappers/MessageMapper.kt | 7 +-
.../data/repositories/MailboxRepository.kt | 85 -
.../data/repositories/MessageRepository.kt | 67 +-
.../data/repositories/RecipientRepository.kt | 24 +-
.../messages/GetMailboxByStudentUseCase.kt | 52 +
.../notifications/NewMessageNotification.kt | 1 -
.../services/sync/works/MessageWork.kt | 6 +-
.../services/sync/works/RecipientWork.kt | 15 +-
.../modules/dashboard/DashboardPresenter.kt | 3 +-
.../debug/notification/mock/message.kt | 1 +
.../mailboxchooser/MailboxChooserAdapter.kt | 81 +
.../mailboxchooser/MailboxChooserDialog.kt | 75 +
.../mailboxchooser/MailboxChooserItem.kt | 9 +
.../mailboxchooser/MailboxChooserPresenter.kt | 38 +
.../mailboxchooser/MailboxChooserView.kt | 13 +
.../preview/MessagePreviewPresenter.kt | 6 +-
.../message/send/SendMessageActivity.kt | 16 +
.../message/send/SendMessagePresenter.kt | 107 +-
.../modules/message/send/SendMessageView.kt | 1 +
.../modules/message/tab/MessageTabAdapter.kt | 32 +-
.../modules/message/tab/MessageTabDataItem.kt | 1 +
.../modules/message/tab/MessageTabFragment.kt | 20 +
.../message/tab/MessageTabPresenter.kt | 39 +-
.../ui/modules/message/tab/MessageTabView.kt | 3 +
.../io/github/wulkanowy/utils/RefreshUtils.kt | 5 +-
.../main/res/layout/activity_send_message.xml | 20 +-
.../res/layout/dialog_mailbox_chooser.xml | 40 +
.../main/res/layout/item_mailbox_chooser.xml | 43 +
.../main/res/layout/item_message_chips.xml | 23 +-
app/src/main/res/values/strings.xml | 2 +
.../io/github/wulkanowy/TestEnityCreator.kt | 4 +-
.../repositories/MessageRepositoryTest.kt | 24 +-
.../GetMailboxByStudentUseCaseTest.kt} | 53 +-
41 files changed, 3209 insertions(+), 235 deletions(-)
create mode 100644 app/schemas/io.github.wulkanowy.data.db.AppDatabase/53.json
create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration53.kt
delete mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt
create mode 100644 app/src/main/java/io/github/wulkanowy/domain/messages/GetMailboxByStudentUseCase.kt
create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserAdapter.kt
create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserDialog.kt
create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserItem.kt
create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserPresenter.kt
create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserView.kt
create mode 100644 app/src/main/res/layout/dialog_mailbox_chooser.xml
create mode 100644 app/src/main/res/layout/item_mailbox_chooser.xml
rename app/src/test/java/io/github/wulkanowy/{data/repositories/MailboxRepositoryTest.kt => domain/GetMailboxByStudentUseCaseTest.kt} (77%)
diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/53.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/53.json
new file mode 100644
index 000000000..985617872
--- /dev/null
+++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/53.json
@@ -0,0 +1,2439 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 53,
+ "identityHash": "1dc96a366125ec9f8567da87cdc9c863",
+ "entities": [
+ {
+ "tableName": "Students",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`scrapper_base_url` TEXT NOT NULL, `mobile_base_url` TEXT NOT NULL, `login_type` TEXT NOT NULL, `login_mode` TEXT NOT NULL, `certificate_key` TEXT NOT NULL, `private_key` TEXT NOT NULL, `is_parent` INTEGER NOT NULL, `email` TEXT NOT NULL, `password` TEXT NOT NULL, `symbol` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `user_login_id` INTEGER NOT NULL, `user_name` TEXT NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_short` TEXT NOT NULL, `school_name` TEXT NOT NULL, `class_name` TEXT NOT NULL, `class_id` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `registration_date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `nick` TEXT NOT NULL, `avatar_color` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "scrapperBaseUrl",
+ "columnName": "scrapper_base_url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mobileBaseUrl",
+ "columnName": "mobile_base_url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginType",
+ "columnName": "login_type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginMode",
+ "columnName": "login_mode",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "certificateKey",
+ "columnName": "certificate_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "privateKey",
+ "columnName": "private_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isParent",
+ "columnName": "is_parent",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "password",
+ "columnName": "password",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "symbol",
+ "columnName": "symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "user_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentName",
+ "columnName": "student_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolSymbol",
+ "columnName": "school_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolShortName",
+ "columnName": "school_short",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolName",
+ "columnName": "school_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "className",
+ "columnName": "class_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isCurrent",
+ "columnName": "is_current",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registrationDate",
+ "columnName": "registration_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "nick",
+ "columnName": "nick",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "avatarColor",
+ "columnName": "avatar_color",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_Students_email_symbol_student_id_school_id_class_id",
+ "unique": true,
+ "columnNames": [
+ "email",
+ "symbol",
+ "student_id",
+ "school_id",
+ "class_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Students_email_symbol_student_id_school_id_class_id` ON `${TABLE_NAME}` (`email`, `symbol`, `student_id`, `school_id`, `class_id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Semesters",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `kindergarten_diary_id` INTEGER NOT NULL DEFAULT 0, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "kindergartenDiaryId",
+ "columnName": "kindergarten_diary_id",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ },
+ {
+ "fieldPath": "diaryName",
+ "columnName": "diary_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolYear",
+ "columnName": "school_year",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterName",
+ "columnName": "semester_name",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unitId",
+ "columnName": "unit_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "current",
+ "columnName": "is_current",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id",
+ "unique": true,
+ "columnNames": [
+ "student_id",
+ "diary_id",
+ "kindergarten_diary_id",
+ "semester_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id` ON `${TABLE_NAME}` (`student_id`, `diary_id`, `kindergarten_diary_id`, `semester_id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Exams",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `group` TEXT NOT NULL, `type` TEXT NOT NULL, `description` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entryDate",
+ "columnName": "entry_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "group",
+ "columnName": "group",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Timetable",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `number` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `subjectOld` TEXT NOT NULL, `group` TEXT NOT NULL, `room` TEXT NOT NULL, `roomOld` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacherOld` TEXT NOT NULL, `info` TEXT NOT NULL, `student_plan` INTEGER NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectOld",
+ "columnName": "subjectOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "group",
+ "columnName": "group",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "room",
+ "columnName": "room",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "roomOld",
+ "columnName": "roomOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherOld",
+ "columnName": "teacherOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "info",
+ "columnName": "info",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isStudentPlan",
+ "columnName": "student_plan",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "changes",
+ "columnName": "changes",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "canceled",
+ "columnName": "canceled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Attendance",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `time_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `excused` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `excusable` INTEGER NOT NULL, `excuse_status` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "timeId",
+ "columnName": "time_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presence",
+ "columnName": "presence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "exemption",
+ "columnName": "exemption",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lateness",
+ "columnName": "lateness",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excused",
+ "columnName": "excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deleted",
+ "columnName": "deleted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excusable",
+ "columnName": "excusable",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excuseStatus",
+ "columnName": "excuse_status",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AttendanceSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `subject_id` INTEGER NOT NULL, `month` INTEGER NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `absence_excused` INTEGER NOT NULL, `absence_for_school_reasons` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `lateness_excused` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subject_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "month",
+ "columnName": "month",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presence",
+ "columnName": "presence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absenceExcused",
+ "columnName": "absence_excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absenceForSchoolReasons",
+ "columnName": "absence_for_school_reasons",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lateness",
+ "columnName": "lateness",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "latenessExcused",
+ "columnName": "lateness_excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "exemption",
+ "columnName": "exemption",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Grades",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `entry` TEXT NOT NULL, `value` REAL NOT NULL, `modifier` REAL NOT NULL, `comment` TEXT NOT NULL, `color` TEXT NOT NULL, `grade_symbol` TEXT NOT NULL, `description` TEXT NOT NULL, `weight` TEXT NOT NULL, `weightValue` REAL NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entry",
+ "columnName": "entry",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "modifier",
+ "columnName": "modifier",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "color",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gradeSymbol",
+ "columnName": "grade_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weightValue",
+ "columnName": "weightValue",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isRead",
+ "columnName": "is_read",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `position` INTEGER NOT NULL, `subject` TEXT NOT NULL, `predicted_grade` TEXT NOT NULL, `final_grade` TEXT NOT NULL, `proposed_points` TEXT NOT NULL, `final_points` TEXT NOT NULL, `points_sum` TEXT NOT NULL, `average` REAL NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_predicted_grade_notified` INTEGER NOT NULL, `is_final_grade_notified` INTEGER NOT NULL, `predicted_grade_last_change` INTEGER NOT NULL, `final_grade_last_change` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "position",
+ "columnName": "position",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "predictedGrade",
+ "columnName": "predicted_grade",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalGrade",
+ "columnName": "final_grade",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "proposedPoints",
+ "columnName": "proposed_points",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalPoints",
+ "columnName": "final_points",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pointsSum",
+ "columnName": "points_sum",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "average",
+ "columnName": "average",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPredictedGradeNotified",
+ "columnName": "is_predicted_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFinalGradeNotified",
+ "columnName": "is_final_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "predictedGradeLastChange",
+ "columnName": "predicted_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalGradeLastChange",
+ "columnName": "final_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradePartialStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `class_average` TEXT NOT NULL, `student_average` TEXT NOT NULL, `class_amounts` TEXT NOT NULL, `student_amounts` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classAverage",
+ "columnName": "class_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAverage",
+ "columnName": "student_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classAmounts",
+ "columnName": "class_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAmounts",
+ "columnName": "student_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesPointsStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `others` REAL NOT NULL, `student` REAL NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "others",
+ "columnName": "others",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "student",
+ "columnName": "student",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradeSemesterStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `amounts` TEXT NOT NULL, `student_grade` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "amounts",
+ "columnName": "amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentGrade",
+ "columnName": "student_grade",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Messages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`email` TEXT NOT NULL, `message_global_key` TEXT NOT NULL, `mailbox_key` TEXT NOT NULL, `message_id` INTEGER NOT NULL, `correspondents` TEXT NOT NULL, `subject` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `read_by` INTEGER, `unread_by` INTEGER, `has_attachments` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `content` TEXT NOT NULL, `sender` TEXT, `recipients` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageGlobalKey",
+ "columnName": "message_global_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mailboxKey",
+ "columnName": "mailbox_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageId",
+ "columnName": "message_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "correspondents",
+ "columnName": "correspondents",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unread",
+ "columnName": "unread",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "readBy",
+ "columnName": "read_by",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "unreadBy",
+ "columnName": "unread_by",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hasAttachments",
+ "columnName": "has_attachments",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "sender",
+ "columnName": "sender",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "recipients",
+ "columnName": "recipients",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MessageAttachments",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`real_id` INTEGER NOT NULL, `message_global_key` TEXT NOT NULL, `url` TEXT NOT NULL, `filename` TEXT NOT NULL, PRIMARY KEY(`real_id`))",
+ "fields": [
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageGlobalKey",
+ "columnName": "message_global_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filename",
+ "columnName": "filename",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "real_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `category` TEXT NOT NULL, `category_type` INTEGER NOT NULL, `is_points_show` INTEGER NOT NULL, `points` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "categoryType",
+ "columnName": "category_type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPointsShow",
+ "columnName": "is_points_show",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "points",
+ "columnName": "points",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isRead",
+ "columnName": "is_read",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Homework",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `attachments` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_done` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `is_added_by_user` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entryDate",
+ "columnName": "entry_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "attachments",
+ "columnName": "attachments",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDone",
+ "columnName": "is_done",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Subjects",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "LuckyNumbers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "luckyNumber",
+ "columnName": "lucky_number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "CompletedLesson",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `topic` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `substitution` TEXT NOT NULL, `absence` TEXT NOT NULL, `resources` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "topic",
+ "columnName": "topic",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "substitution",
+ "columnName": "substitution",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "resources",
+ "columnName": "resources",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Mailboxes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`globalKey` TEXT NOT NULL, `email` TEXT NOT NULL, `symbol` TEXT NOT NULL, `schoolId` TEXT NOT NULL, `fullName` TEXT NOT NULL, `userName` TEXT NOT NULL, `studentName` TEXT NOT NULL, `schoolNameShort` TEXT NOT NULL, `type` TEXT NOT NULL, PRIMARY KEY(`globalKey`))",
+ "fields": [
+ {
+ "fieldPath": "globalKey",
+ "columnName": "globalKey",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "symbol",
+ "columnName": "symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolId",
+ "columnName": "schoolId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "fullName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentName",
+ "columnName": "studentName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolNameShort",
+ "columnName": "schoolNameShort",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "globalKey"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Recipients",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`mailboxGlobalKey` TEXT NOT NULL, `studentMailboxGlobalKey` TEXT NOT NULL, `fullName` TEXT NOT NULL, `userName` TEXT NOT NULL, `schoolShortName` TEXT NOT NULL, `type` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "mailboxGlobalKey",
+ "columnName": "mailboxGlobalKey",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentMailboxGlobalKey",
+ "columnName": "studentMailboxGlobalKey",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "fullName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolShortName",
+ "columnName": "schoolShortName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MobileDevices",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_login_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deviceId",
+ "columnName": "device_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Teachers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "shortName",
+ "columnName": "short_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "School",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT NOT NULL, `contact` TEXT NOT NULL, `headmaster` TEXT NOT NULL, `pedagogue` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "contact",
+ "columnName": "contact",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "headmaster",
+ "columnName": "headmaster",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pedagogue",
+ "columnName": "pedagogue",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Conferences",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `subject` TEXT NOT NULL, `agenda` TEXT NOT NULL, `present_on_conference` TEXT NOT NULL, `conference_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "agenda",
+ "columnName": "agenda",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presentOnConference",
+ "columnName": "present_on_conference",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "conferenceId",
+ "columnName": "conference_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableAdditional",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `repeat_id` BLOB DEFAULT NULL, `is_added_by_user` INTEGER NOT NULL DEFAULT 0)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "repeatId",
+ "columnName": "repeat_id",
+ "affinity": "BLOB",
+ "notNull": false,
+ "defaultValue": "NULL"
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "StudentInfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `full_name` TEXT NOT NULL, `first_name` TEXT NOT NULL, `second_name` TEXT NOT NULL, `surname` TEXT NOT NULL, `birth_date` INTEGER NOT NULL, `birth_place` TEXT NOT NULL, `gender` TEXT NOT NULL, `has_polish_citizenship` INTEGER NOT NULL, `family_name` TEXT NOT NULL, `parents_names` TEXT NOT NULL, `address` TEXT NOT NULL, `registered_address` TEXT NOT NULL, `correspondence_address` TEXT NOT NULL, `phone_number` TEXT NOT NULL, `cell_phone_number` TEXT NOT NULL, `email` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `first_guardian_full_name` TEXT, `first_guardian_kinship` TEXT, `first_guardian_address` TEXT, `first_guardian_phones` TEXT, `first_guardian_email` TEXT, `second_guardian_full_name` TEXT, `second_guardian_kinship` TEXT, `second_guardian_address` TEXT, `second_guardian_phones` TEXT, `second_guardian_email` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "full_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstName",
+ "columnName": "first_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "secondName",
+ "columnName": "second_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "surname",
+ "columnName": "surname",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthDate",
+ "columnName": "birth_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthPlace",
+ "columnName": "birth_place",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gender",
+ "columnName": "gender",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPolishCitizenship",
+ "columnName": "has_polish_citizenship",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "familyName",
+ "columnName": "family_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentsNames",
+ "columnName": "parents_names",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registeredAddress",
+ "columnName": "registered_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "correspondenceAddress",
+ "columnName": "correspondence_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "phoneNumber",
+ "columnName": "phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "cellPhoneNumber",
+ "columnName": "cell_phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstGuardian.fullName",
+ "columnName": "first_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.kinship",
+ "columnName": "first_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.address",
+ "columnName": "first_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.phones",
+ "columnName": "first_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.email",
+ "columnName": "first_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.fullName",
+ "columnName": "second_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.kinship",
+ "columnName": "second_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.address",
+ "columnName": "second_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.phones",
+ "columnName": "second_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.email",
+ "columnName": "second_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableHeaders",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "SchoolAnnouncements",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_login_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notifications",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `type` TEXT NOT NULL, `destination` TEXT NOT NULL DEFAULT '{\"type\":\"io.github.wulkanowy.ui.modules.Destination.Dashboard\"}', `date` INTEGER NOT NULL, `data` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "destination",
+ "columnName": "destination",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'{\"type\":\"io.github.wulkanowy.ui.modules.Destination.Dashboard\"}'"
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "data",
+ "columnName": "data",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AdminMessages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `version_name` INTEGER, `version_max` INTEGER, `target_register_host` TEXT, `target_flavor` TEXT, `destination_url` TEXT, `priority` TEXT NOT NULL, `type` TEXT NOT NULL, `is_dismissible` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "versionMin",
+ "columnName": "version_name",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "versionMax",
+ "columnName": "version_max",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetRegisterHost",
+ "columnName": "target_register_host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetFlavor",
+ "columnName": "target_flavor",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "destinationUrl",
+ "columnName": "destination_url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "priority",
+ "columnName": "priority",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDismissible",
+ "columnName": "is_dismissible",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1dc96a366125ec9f8567da87cdc9c863')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
index e61ffe844..792611a81 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
@@ -56,7 +56,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() {
companion object {
- const val VERSION_SCHEMA = 52
+ const val VERSION_SCHEMA = 53
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
Migration2(),
@@ -106,6 +106,7 @@ abstract class AppDatabase : RoomDatabase() {
Migration49(),
Migration50(),
Migration51(),
+ Migration53(),
)
fun newInstance(
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/MailboxDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/MailboxDao.kt
index c44ecd0c2..084192a07 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/MailboxDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/MailboxDao.kt
@@ -3,12 +3,16 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Mailbox
+import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@Dao
interface MailboxDao : BaseDao {
- @Query("SELECT * FROM Mailboxes WHERE userLoginId = :userLoginId ")
- suspend fun loadAll(userLoginId: Int): List
+ @Query("SELECT * FROM Mailboxes WHERE email = :email")
+ suspend fun loadAll(email: String): List
+
+ @Query("SELECT * FROM Mailboxes WHERE email = :email AND symbol = :symbol AND schoolId = :schoolId")
+ fun loadAll(email: String, symbol: String, schoolId: String): Flow>
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt
index 8c730c9bc..1709f7636 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt
@@ -16,4 +16,7 @@ interface MessagesDao : BaseDao {
@Query("SELECT * FROM Messages WHERE mailbox_key = :mailboxKey AND folder_id = :folder ORDER BY date DESC")
fun loadAll(mailboxKey: String, folder: Int): Flow>
+
+ @Query("SELECT * FROM Messages WHERE email = :email AND folder_id = :folder ORDER BY date DESC")
+ fun loadAll(folder: Int, email: String): Flow>
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Mailbox.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Mailbox.kt
index 7c08e481d..e65e213dd 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Mailbox.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Mailbox.kt
@@ -1,20 +1,27 @@
package io.github.wulkanowy.data.db.entities
+import android.os.Parcelable
import androidx.room.Entity
import androidx.room.PrimaryKey
+import kotlinx.parcelize.Parcelize
+@Parcelize
@Entity(tableName = "Mailboxes")
data class Mailbox(
@PrimaryKey
val globalKey: String,
+
+ val email: String,
+ val symbol: String,
+ val schoolId: String,
+
val fullName: String,
val userName: String,
- val userLoginId: Int,
val studentName: String,
val schoolNameShort: String,
val type: MailboxType,
-)
+) : java.io.Serializable, Parcelable
enum class MailboxType {
STUDENT,
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt
index 323b00bec..d1356b33d 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt
@@ -9,6 +9,9 @@ import java.time.Instant
@Entity(tableName = "Messages")
data class Message(
+ @ColumnInfo(name = "email")
+ val email: String,
+
@ColumnInfo(name = "message_global_key")
val messageGlobalKey: String,
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration53.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration53.kt
new file mode 100644
index 000000000..12624a51a
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration53.kt
@@ -0,0 +1,57 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class Migration53 : Migration(52, 53) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ createMailboxTable(database)
+ recreateMessagesTable(database)
+ }
+
+ private fun createMailboxTable(database: SupportSQLiteDatabase) {
+ database.execSQL("DROP TABLE IF EXISTS Mailboxes")
+ database.execSQL(
+ """
+ CREATE TABLE IF NOT EXISTS `Mailboxes` (
+ `globalKey` TEXT NOT NULL,
+ `email` TEXT NOT NULL,
+ `symbol` TEXT NOT NULL,
+ `schoolId` TEXT NOT NULL,
+ `fullName` TEXT NOT NULL,
+ `userName` TEXT NOT NULL,
+ `studentName` TEXT NOT NULL,
+ `schoolNameShort` TEXT NOT NULL,
+ `type` TEXT NOT NULL,
+ PRIMARY KEY(`globalKey`)
+ )""".trimIndent()
+ )
+ }
+
+ private fun recreateMessagesTable(database: SupportSQLiteDatabase) {
+ database.execSQL("DROP TABLE IF EXISTS Messages")
+ database.execSQL(
+ """
+ CREATE TABLE IF NOT EXISTS `Messages` (
+ `email` TEXT NOT NULL,
+ `message_global_key` TEXT NOT NULL,
+ `mailbox_key` TEXT NOT NULL,
+ `message_id` INTEGER NOT NULL,
+ `correspondents` TEXT NOT NULL,
+ `subject` TEXT NOT NULL,
+ `date` INTEGER NOT NULL,
+ `folder_id` INTEGER NOT NULL,
+ `unread` INTEGER NOT NULL,
+ `read_by` INTEGER,
+ `unread_by` INTEGER,
+ `has_attachments` INTEGER NOT NULL,
+ `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ `is_notified` INTEGER NOT NULL,
+ `content` TEXT NOT NULL,
+ `sender` TEXT,
+ `recipients` TEXT
+ )""".trimIndent()
+ )
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/MailboxMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/MailboxMapper.kt
index 2ccca1b90..0cf547770 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/MailboxMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/MailboxMapper.kt
@@ -10,9 +10,11 @@ fun List.mapToEntities(student: Student) = map {
globalKey = it.globalKey,
fullName = it.fullName,
userName = it.userName,
- userLoginId = student.userLoginId,
studentName = it.studentName,
schoolNameShort = it.schoolNameShort,
type = MailboxType.valueOf(it.type.name),
+ email = student.email,
+ symbol = student.symbol,
+ schoolId = student.schoolSymbol,
)
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
index c329607f4..8825c5744 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
@@ -6,10 +6,13 @@ import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
-fun List.mapToEntities(mailbox: Mailbox) = map {
+fun List.mapToEntities(student: Student, mailbox: Mailbox?, allMailboxes: List) = map {
Message(
messageGlobalKey = it.globalKey,
- mailboxKey = mailbox.globalKey,
+ mailboxKey = mailbox?.globalKey ?: allMailboxes.find { box ->
+ box.fullName == it.mailbox
+ }?.globalKey!!,
+ email = student.email,
messageId = it.id,
correspondents = it.correspondents,
subject = it.subject.trim(),
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt
deleted file mode 100644
index c571937ad..000000000
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/MailboxRepository.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-package io.github.wulkanowy.data.repositories
-
-import io.github.wulkanowy.data.db.dao.MailboxDao
-import io.github.wulkanowy.data.db.entities.Mailbox
-import io.github.wulkanowy.data.db.entities.Student
-import io.github.wulkanowy.data.mappers.mapToEntities
-import io.github.wulkanowy.sdk.Sdk
-import io.github.wulkanowy.utils.AutoRefreshHelper
-import io.github.wulkanowy.utils.getRefreshKey
-import io.github.wulkanowy.utils.init
-import io.github.wulkanowy.utils.uniqueSubtract
-import javax.inject.Inject
-import javax.inject.Singleton
-
-@Singleton
-class MailboxRepository @Inject constructor(
- private val mailboxDao: MailboxDao,
- private val sdk: Sdk,
- private val refreshHelper: AutoRefreshHelper,
-) {
- private val cacheKey = "mailboxes"
-
- suspend fun refreshMailboxes(student: Student) {
- val new = sdk.init(student).getMailboxes().mapToEntities(student)
- val old = mailboxDao.loadAll(student.userLoginId)
-
- mailboxDao.deleteAll(old uniqueSubtract new)
- mailboxDao.insertAll(new uniqueSubtract old)
-
- refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
- }
-
- suspend fun getMailbox(student: Student): Mailbox {
- val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
- val mailboxes = mailboxDao.loadAll(student.userLoginId)
- val mailbox = mailboxes.filterByStudent(student)
-
- return if (isExpired || mailbox == null) {
- refreshMailboxes(student)
- val newMailbox = mailboxDao.loadAll(student.userLoginId).filterByStudent(student)
-
- requireNotNull(newMailbox) {
- "Mailbox for ${student.userName} - ${student.studentName} not found! Saved mailboxes: $mailboxes"
- }
-
- newMailbox
- } else mailbox
- }
-
- private fun List.filterByStudent(student: Student): Mailbox? {
- val normalizedStudentName = student.studentName.normalizeStudentName()
-
- return find {
- it.studentName.normalizeStudentName() == normalizedStudentName
- } ?: singleOrNull {
- it.studentName.getFirstAndLastPart() == normalizedStudentName.getFirstAndLastPart()
- } ?: singleOrNull {
- it.studentName.getUnauthorizedVersion() == normalizedStudentName
- }
- }
-
- private fun String.normalizeStudentName(): String {
- return trim().split(" ")
- .filter { it.isNotBlank() }
- .joinToString(" ") { part ->
- part.lowercase().replaceFirstChar { it.uppercase() }
- }
- }
-
- private fun String.getFirstAndLastPart(): String {
- val parts = normalizeStudentName().split(" ")
-
- val endParts = parts.filterIndexed { i, _ ->
- i == 0 || parts.size - 1 == i
- }
- return endParts.joinToString(" ")
- }
-
- private fun String.getUnauthorizedVersion(): String {
- return normalizeStudentName().split(" ")
- .joinToString(" ") {
- it.first() + "*".repeat(it.length - 1)
- }
- }
-}
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt
index e7428762e..f8be4296d 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt
@@ -5,6 +5,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.R
import io.github.wulkanowy.data.Resource
import io.github.wulkanowy.data.db.SharedPrefProvider
+import io.github.wulkanowy.data.db.dao.MailboxDao
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
import io.github.wulkanowy.data.db.dao.MessagesDao
import io.github.wulkanowy.data.db.entities.*
@@ -15,6 +16,8 @@ import io.github.wulkanowy.data.mappers.mapFromEntities
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.data.pojos.MessageDraft
+import io.github.wulkanowy.data.toFirstResult
+import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Folder
import io.github.wulkanowy.utils.AutoRefreshHelper
@@ -40,16 +43,18 @@ class MessageRepository @Inject constructor(
private val refreshHelper: AutoRefreshHelper,
private val sharedPrefProvider: SharedPrefProvider,
private val json: Json,
+ private val mailboxDao: MailboxDao,
+ private val getMailboxByStudentUseCase: GetMailboxByStudentUseCase,
) {
private val saveFetchResultMutex = Mutex()
- private val cacheKey = "message"
+ private val messagesCacheKey = "message"
+ private val mailboxCacheKey = "mailboxes"
- @Suppress("UNUSED_PARAMETER")
fun getMessages(
student: Student,
- mailbox: Mailbox,
+ mailbox: Mailbox?,
folder: MessageFolder,
forceRefresh: Boolean,
notify: Boolean = false,
@@ -58,16 +63,20 @@ class MessageRepository @Inject constructor(
isResultEmpty = { it.isEmpty() },
shouldFetch = {
val isExpired = refreshHelper.shouldBeRefreshed(
- key = getRefreshKey(cacheKey, student, folder)
+ key = getRefreshKey(messagesCacheKey, mailbox, folder)
)
it.isEmpty() || forceRefresh || isExpired
},
- query = { messagesDb.loadAll(mailbox.globalKey, folder.id) },
+ query = {
+ if (mailbox == null) {
+ messagesDb.loadAll(folder.id, student.email)
+ } else messagesDb.loadAll(mailbox.globalKey, folder.id)
+ },
fetch = {
sdk.init(student).getMessages(
folder = Folder.valueOf(folder.name),
- mailboxKey = mailbox.globalKey,
- ).mapToEntities(mailbox)
+ mailboxKey = mailbox?.globalKey,
+ ).mapToEntities(student, mailbox, mailboxDao.loadAll(student.email))
},
saveFetchResult = { old, new ->
messagesDb.deleteAll(old uniqueSubtract new)
@@ -75,7 +84,9 @@ class MessageRepository @Inject constructor(
it.isNotified = !notify
})
- refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student, folder))
+ refreshHelper.updateLastRefreshTimestamp(
+ getRefreshKey(messagesCacheKey, mailbox, folder)
+ )
}
)
@@ -90,7 +101,9 @@ class MessageRepository @Inject constructor(
Timber.d("Message content in db empty: ${it.message.content.isBlank()}")
it.message.unread || it.message.content.isBlank()
},
- query = { messagesDb.loadMessageWithAttachment(message.messageGlobalKey) },
+ query = {
+ messagesDb.loadMessageWithAttachment(message.messageGlobalKey)
+ },
fetch = {
sdk.init(student).getMessageDetails(it!!.message.messageGlobalKey, markAsRead)
},
@@ -113,8 +126,10 @@ class MessageRepository @Inject constructor(
}
)
- fun getMessagesFromDatabase(mailbox: Mailbox): Flow> {
- return messagesDb.loadAll(mailbox.globalKey, RECEIVED.id)
+ fun getMessagesFromDatabase(student: Student, mailbox: Mailbox?): Flow> {
+ return if (mailbox == null) {
+ messagesDb.loadAll(RECEIVED.id, student.email)
+ } else messagesDb.loadAll(mailbox.globalKey, RECEIVED.id)
}
suspend fun updateMessages(messages: List) {
@@ -136,7 +151,7 @@ class MessageRepository @Inject constructor(
)
}
- suspend fun deleteMessages(student: Student, mailbox: Mailbox, messages: List) {
+ suspend fun deleteMessages(student: Student, mailbox: Mailbox?, messages: List) {
val firstMessage = messages.first()
sdk.init(student).deleteMessages(
messages = messages.map { it.messageGlobalKey },
@@ -169,6 +184,34 @@ class MessageRepository @Inject constructor(
deleteMessages(student, mailbox, listOf(message))
}
+ suspend fun getMailboxes(student: Student, forceRefresh: Boolean) = networkBoundResource(
+ mutex = saveFetchResultMutex,
+ isResultEmpty = { it.isEmpty() },
+ shouldFetch = {
+ val isExpired = refreshHelper.shouldBeRefreshed(
+ key = getRefreshKey(mailboxCacheKey, student),
+ )
+ it.isEmpty() || isExpired || forceRefresh
+ },
+ query = { mailboxDao.loadAll(student.email, student.symbol, student.schoolSymbol) },
+ fetch = { sdk.init(student).getMailboxes().mapToEntities(student) },
+ saveFetchResult = { old, new ->
+ mailboxDao.deleteAll(old uniqueSubtract new)
+ mailboxDao.insertAll(new uniqueSubtract old)
+
+ refreshHelper.updateLastRefreshTimestamp(getRefreshKey(mailboxCacheKey, student))
+ }
+ )
+
+ suspend fun getMailboxByStudent(student: Student): Mailbox? {
+ val mailbox = getMailboxByStudentUseCase(student)
+
+ return if (mailbox == null) {
+ getMailboxes(student, forceRefresh = true).toFirstResult()
+ getMailboxByStudentUseCase(student)
+ } else mailbox
+ }
+
var draftMessage: MessageDraft?
get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_draft))
?.let { json.decodeFromString(it) }
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/RecipientRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/RecipientRepository.kt
index e80f028e1..79984ce6d 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/RecipientRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/RecipientRepository.kt
@@ -33,9 +33,11 @@ class RecipientRepository @Inject constructor(
suspend fun getRecipients(
student: Student,
- mailbox: Mailbox,
- type: MailboxType
+ mailbox: Mailbox?,
+ type: MailboxType,
): List {
+ mailbox ?: return emptyList()
+
val cached = recipientDb.loadAll(type, mailbox.globalKey)
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
@@ -47,11 +49,15 @@ class RecipientRepository @Inject constructor(
suspend fun getMessageSender(
student: Student,
- mailbox: Mailbox,
- message: Message
- ): List = sdk.init(student)
- .getMessageReplayDetails(message.messageGlobalKey)
- .sender
- .let(::listOf)
- .mapToEntities(mailbox.globalKey)
+ mailbox: Mailbox?,
+ message: Message,
+ ): List {
+ mailbox ?: return emptyList()
+
+ return sdk.init(student)
+ .getMessageReplayDetails(message.messageGlobalKey)
+ .sender
+ .let(::listOf)
+ .mapToEntities(mailbox.globalKey)
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/domain/messages/GetMailboxByStudentUseCase.kt b/app/src/main/java/io/github/wulkanowy/domain/messages/GetMailboxByStudentUseCase.kt
new file mode 100644
index 000000000..d96794e51
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/domain/messages/GetMailboxByStudentUseCase.kt
@@ -0,0 +1,52 @@
+package io.github.wulkanowy.domain.messages
+
+import io.github.wulkanowy.data.db.dao.MailboxDao
+import io.github.wulkanowy.data.db.entities.Mailbox
+import io.github.wulkanowy.data.db.entities.Student
+import javax.inject.Inject
+
+class GetMailboxByStudentUseCase @Inject constructor(
+ private val mailboxDao: MailboxDao,
+) {
+
+ suspend operator fun invoke(student: Student): Mailbox? {
+ return mailboxDao.loadAll(student.email)
+ .filterByStudent(student)
+ }
+
+ private fun List.filterByStudent(student: Student): Mailbox? {
+ val normalizedStudentName = student.studentName.normalizeStudentName()
+
+ return find {
+ it.studentName.normalizeStudentName() == normalizedStudentName
+ } ?: singleOrNull {
+ it.studentName.getFirstAndLastPart() == normalizedStudentName.getFirstAndLastPart()
+ } ?: singleOrNull {
+ it.studentName.getUnauthorizedVersion() == normalizedStudentName
+ }
+ }
+
+ private fun String.normalizeStudentName(): String {
+ return trim().split(" ")
+ .filter { it.isNotBlank() }
+ .joinToString(" ") { part ->
+ part.lowercase().replaceFirstChar { it.uppercase() }
+ }
+ }
+
+ private fun String.getFirstAndLastPart(): String {
+ val parts = normalizeStudentName().split(" ")
+
+ val endParts = parts.filterIndexed { i, _ ->
+ i == 0 || parts.size - 1 == i
+ }
+ return endParts.joinToString(" ")
+ }
+
+ private fun String.getUnauthorizedVersion(): String {
+ return normalizeStudentName().split(" ")
+ .joinToString(" ") {
+ it.first() + "*".repeat(it.length - 1)
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewMessageNotification.kt b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewMessageNotification.kt
index 3b7bcff05..45523d51e 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewMessageNotification.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/notifications/NewMessageNotification.kt
@@ -8,7 +8,6 @@ import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.pojos.GroupNotificationData
import io.github.wulkanowy.data.pojos.NotificationData
import io.github.wulkanowy.ui.modules.Destination
-import io.github.wulkanowy.ui.modules.splash.SplashActivity
import io.github.wulkanowy.utils.getPlural
import javax.inject.Inject
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/MessageWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/MessageWork.kt
index 180568267..c7824e61f 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/MessageWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/MessageWork.kt
@@ -3,7 +3,6 @@ package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
-import io.github.wulkanowy.data.repositories.MailboxRepository
import io.github.wulkanowy.data.repositories.MessageRepository
import io.github.wulkanowy.data.waitForResult
import io.github.wulkanowy.services.sync.notifications.NewMessageNotification
@@ -12,12 +11,11 @@ import javax.inject.Inject
class MessageWork @Inject constructor(
private val messageRepository: MessageRepository,
- private val mailboxRepository: MailboxRepository,
private val newMessageNotification: NewMessageNotification,
) : Work {
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
- val mailbox = mailboxRepository.getMailbox(student)
+ val mailbox = messageRepository.getMailboxByStudent(student)
messageRepository.getMessages(
student = student,
mailbox = mailbox,
@@ -26,7 +24,7 @@ class MessageWork @Inject constructor(
notify = notify
).waitForResult()
- messageRepository.getMessagesFromDatabase(mailbox).first()
+ messageRepository.getMessagesFromDatabase(student, mailbox).first()
.filter { !it.isNotified && it.unread }.let {
if (it.isNotEmpty()) newMessageNotification.notify(it, student)
messageRepository.updateMessages(it.onEach { message -> message.isNotified = true })
diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/RecipientWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/RecipientWork.kt
index b1322ada3..90b20651d 100644
--- a/app/src/main/java/io/github/wulkanowy/services/sync/works/RecipientWork.kt
+++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/RecipientWork.kt
@@ -1,22 +1,23 @@
package io.github.wulkanowy.services.sync.works
+import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.entities.MailboxType
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
-import io.github.wulkanowy.data.repositories.MailboxRepository
+import io.github.wulkanowy.data.repositories.MessageRepository
import io.github.wulkanowy.data.repositories.RecipientRepository
+import io.github.wulkanowy.data.toFirstResult
import javax.inject.Inject
class RecipientWork @Inject constructor(
- private val mailboxRepository: MailboxRepository,
+ private val messageRepository: MessageRepository,
private val recipientRepository: RecipientRepository
) : Work {
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
- mailboxRepository.refreshMailboxes(student)
-
- val mailbox = mailboxRepository.getMailbox(student)
-
- recipientRepository.refreshRecipients(student, mailbox, MailboxType.EMPLOYEE)
+ val mailboxes = messageRepository.getMailboxes(student, forceRefresh = true).toFirstResult()
+ mailboxes.dataOrNull?.forEach {
+ recipientRepository.refreshRecipients(student, it, MailboxType.EMPLOYEE)
+ }
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
index 350300937..cb92b0043 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
@@ -25,7 +25,6 @@ class DashboardPresenter @Inject constructor(
private val gradeRepository: GradeRepository,
private val semesterRepository: SemesterRepository,
private val messageRepository: MessageRepository,
- private val mailboxRepository: MailboxRepository,
private val attendanceSummaryRepository: AttendanceSummaryRepository,
private val timetableRepository: TimetableRepository,
private val homeworkRepository: HomeworkRepository,
@@ -228,7 +227,7 @@ class DashboardPresenter @Inject constructor(
private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) {
flow {
val semester = semesterRepository.getCurrentSemester(student)
- val mailbox = mailboxRepository.getMailbox(student)
+ val mailbox = messageRepository.getMailboxByStudent(student)
val selectedTiles = preferencesRepository.selectedDashboardTiles
val flowSuccess = flowOf(Resource.Success(null))
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/message.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/message.kt
index e31bd84a9..27d8613a3 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/message.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/notification/mock/message.kt
@@ -19,6 +19,7 @@ val debugMessageItems = listOf(
private fun generateMessage(sender: String, subject: String) = Message(
subject = subject,
messageId = 123,
+ email = "",
date = Instant.now(),
folderId = 0,
unread = true,
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserAdapter.kt
new file mode 100644
index 000000000..59f6d288d
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserAdapter.kt
@@ -0,0 +1,81 @@
+package io.github.wulkanowy.ui.modules.message.mailboxchooser
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.core.view.isVisible
+import androidx.recyclerview.widget.DiffUtil.ItemCallback
+import androidx.recyclerview.widget.ListAdapter
+import androidx.recyclerview.widget.RecyclerView
+import io.github.wulkanowy.R
+import io.github.wulkanowy.data.db.entities.Mailbox
+import io.github.wulkanowy.data.db.entities.MailboxType
+import io.github.wulkanowy.databinding.ItemMailboxChooserBinding
+import javax.inject.Inject
+
+class MailboxChooserAdapter @Inject constructor() :
+ ListAdapter(Differ) {
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
+ ItemMailboxChooserBinding.inflate(
+ LayoutInflater.from(parent.context), parent, false
+ )
+ )
+
+ override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
+ holder.bind(getItem(position))
+ }
+
+ class ItemViewHolder(
+ private val binding: ItemMailboxChooserBinding,
+ ) : RecyclerView.ViewHolder(binding.root) {
+
+ fun bind(item: MailboxChooserItem) {
+ with(binding) {
+ mailboxItemName.text = item.mailbox?.getFirstLine()
+ ?: root.resources.getString(R.string.message_chip_all_mailboxes)
+ mailboxItemSchool.text = item.mailbox?.getSecondLine()
+ mailboxItemSchool.isVisible = !item.isAll
+
+ root.setOnClickListener { item.onClickListener(item.mailbox) }
+ }
+ }
+
+ private fun Mailbox.getFirstLine() = buildString {
+ if (studentName.isNotBlank() && studentName != userName) {
+ append(studentName)
+ append(" - ")
+ }
+ append(userName)
+ }
+
+ private fun Mailbox.getSecondLine() = buildString {
+ append(schoolNameShort)
+ append(" - ")
+ append(getMailboxType(type))
+ }
+
+ private fun getMailboxType(type: MailboxType): String = when (type) {
+ MailboxType.STUDENT -> R.string.message_mailbox_type_student
+ MailboxType.PARENT -> R.string.message_mailbox_type_parent
+ MailboxType.GUARDIAN -> R.string.message_mailbox_type_guardian
+ MailboxType.EMPLOYEE -> R.string.message_mailbox_type_employee
+ MailboxType.UNKNOWN -> null
+ }.let { it?.let { it1 -> binding.root.resources.getString(it1) }.orEmpty() }
+ }
+
+ private object Differ : ItemCallback() {
+ override fun areItemsTheSame(
+ oldItem: MailboxChooserItem,
+ newItem: MailboxChooserItem
+ ): Boolean {
+ return oldItem.mailbox?.globalKey == newItem.mailbox?.globalKey
+ }
+
+ override fun areContentsTheSame(
+ oldItem: MailboxChooserItem,
+ newItem: MailboxChooserItem
+ ): Boolean {
+ return oldItem == newItem
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserDialog.kt
new file mode 100644
index 000000000..222412ef1
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserDialog.kt
@@ -0,0 +1,75 @@
+package io.github.wulkanowy.ui.modules.message.mailboxchooser
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.os.bundleOf
+import androidx.fragment.app.setFragmentResult
+import dagger.hilt.android.AndroidEntryPoint
+import io.github.wulkanowy.data.db.entities.Mailbox
+import io.github.wulkanowy.databinding.DialogMailboxChooserBinding
+import io.github.wulkanowy.ui.base.BaseDialogFragment
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class MailboxChooserDialog : BaseDialogFragment(), MailboxChooserView {
+
+ @Inject
+ lateinit var presenter: MailboxChooserPresenter
+
+ @Inject
+ lateinit var mailboxAdapter: MailboxChooserAdapter
+
+ companion object {
+ const val LISTENER_KEY = "mailbox_selected"
+ const val MAILBOX_KEY = "selected_mailbox"
+ const val REQUIRED_KEY = "is_mailbox_required"
+
+ fun newInstance(mailboxes: List, isMailboxRequired: Boolean, folder: String) =
+ MailboxChooserDialog().apply {
+ arguments = bundleOf(
+ MAILBOX_KEY to mailboxes.toTypedArray(),
+ REQUIRED_KEY to isMailboxRequired,
+ LISTENER_KEY to folder,
+ )
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setStyle(STYLE_NO_TITLE, 0)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ) = DialogMailboxChooserBinding.inflate(inflater).apply { binding = this }.root
+
+ @Suppress("UNCHECKED_CAST")
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ presenter.onAttachView(
+ view = this,
+ requireMailbox = requireArguments().getBoolean(REQUIRED_KEY, false),
+ mailboxes = requireArguments().getParcelableArray(MAILBOX_KEY).orEmpty()
+ .toList() as List,
+ )
+ }
+
+ override fun initView() {
+ binding.accountQuickDialogRecycler.adapter = mailboxAdapter
+ }
+
+ override fun submitData(items: List) {
+ mailboxAdapter.submitList(items)
+ }
+
+ override fun onMailboxSelected(item: Mailbox?) {
+ setFragmentResult(
+ requestKey = requireArguments().getString(LISTENER_KEY).orEmpty(),
+ result = bundleOf(MAILBOX_KEY to item),
+ )
+ dismiss()
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserItem.kt
new file mode 100644
index 000000000..6923cf085
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserItem.kt
@@ -0,0 +1,9 @@
+package io.github.wulkanowy.ui.modules.message.mailboxchooser
+
+import io.github.wulkanowy.data.db.entities.Mailbox
+
+data class MailboxChooserItem(
+ val mailbox: Mailbox? = null,
+ val isAll: Boolean = false,
+ val onClickListener: (Mailbox?) -> Unit,
+)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserPresenter.kt
new file mode 100644
index 000000000..5bd7c84ab
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserPresenter.kt
@@ -0,0 +1,38 @@
+package io.github.wulkanowy.ui.modules.message.mailboxchooser
+
+import io.github.wulkanowy.data.db.entities.Mailbox
+import io.github.wulkanowy.data.repositories.StudentRepository
+import io.github.wulkanowy.ui.base.BasePresenter
+import io.github.wulkanowy.ui.base.ErrorHandler
+import timber.log.Timber
+import javax.inject.Inject
+
+class MailboxChooserPresenter @Inject constructor(
+ errorHandler: ErrorHandler,
+ studentRepository: StudentRepository
+) : BasePresenter(errorHandler, studentRepository) {
+
+ fun onAttachView(view: MailboxChooserView, mailboxes: List, requireMailbox: Boolean) {
+ super.onAttachView(view)
+
+ view.initView()
+ Timber.i("Mailbox chooser view was initialized")
+ view.submitData(getMailboxItems(mailboxes, requireMailbox))
+ }
+
+ private fun getMailboxItems(
+ mailboxes: List,
+ requireMailbox: Boolean,
+ ): List = buildList {
+ if (!requireMailbox) {
+ add(MailboxChooserItem(isAll = true, onClickListener = ::onMailboxSelect))
+ }
+ addAll(mailboxes.map {
+ MailboxChooserItem(mailbox = it, isAll = false, onClickListener = ::onMailboxSelect)
+ })
+ }
+
+ fun onMailboxSelect(item: Mailbox?) {
+ view?.onMailboxSelected(item)
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserView.kt
new file mode 100644
index 000000000..2e20ee815
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/mailboxchooser/MailboxChooserView.kt
@@ -0,0 +1,13 @@
+package io.github.wulkanowy.ui.modules.message.mailboxchooser
+
+import io.github.wulkanowy.data.db.entities.Mailbox
+import io.github.wulkanowy.ui.base.BaseView
+
+interface MailboxChooserView : BaseView {
+
+ fun initView()
+
+ fun submitData(items: List)
+
+ fun onMailboxSelected(item: Mailbox?)
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt
index c011f41f3..fd75f6f3a 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt
@@ -6,7 +6,6 @@ import io.github.wulkanowy.data.*
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageAttachment
import io.github.wulkanowy.data.enums.MessageFolder
-import io.github.wulkanowy.data.repositories.MailboxRepository
import io.github.wulkanowy.data.repositories.MessageRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
@@ -21,7 +20,6 @@ class MessagePreviewPresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
private val messageRepository: MessageRepository,
- private val mailboxRepository: MailboxRepository,
private val analytics: AnalyticsHelper
) : BasePresenter(errorHandler, studentRepository) {
@@ -187,8 +185,8 @@ class MessagePreviewPresenter @Inject constructor(
presenterScope.launch {
runCatching {
val student = studentRepository.getCurrentStudent(decryptPass = true)
- val mailbox = mailboxRepository.getMailbox(student)
- messageRepository.deleteMessage(student, mailbox, message!!)
+ val mailbox = messageRepository.getMailboxByStudent(student)
+ messageRepository.deleteMessage(student, mailbox!!, message!!)
}
.onFailure {
retryCallback = { onMessageDelete() }
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageActivity.kt
index 334e389e2..b5f687bd4 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageActivity.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageActivity.kt
@@ -19,9 +19,13 @@ import androidx.core.text.toHtml
import androidx.core.widget.doOnTextChanged
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
+import io.github.wulkanowy.data.db.entities.Mailbox
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.databinding.ActivitySendMessageBinding
import io.github.wulkanowy.ui.base.BaseActivity
+import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog
+import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog.Companion.MAILBOX_KEY
+import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog.Companion.LISTENER_KEY
import io.github.wulkanowy.utils.dpToPx
import io.github.wulkanowy.utils.hideSoftInput
import io.github.wulkanowy.utils.showSoftInput
@@ -100,6 +104,7 @@ class SendMessageActivity : BaseActivity
+ presenter.onMailboxSelected(bundle.getSerializable(MAILBOX_KEY) as? Mailbox)
+ }
}
@SuppressLint("ClickableViewAccessibility")
@@ -205,6 +213,14 @@ class SendMessageActivity : BaseActivity) {
+ MailboxChooserDialog.newInstance(
+ mailboxes = mailboxes,
+ isMailboxRequired = true,
+ folder = LISTENER_KEY,
+ ).show(supportFragmentManager, "chooser")
+ }
+
override fun popView() {
finish()
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt
index 6c07ee6ad..5ab8f8fc9 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt
@@ -1,15 +1,15 @@
package io.github.wulkanowy.ui.modules.message.send
-import io.github.wulkanowy.data.Resource
+import io.github.wulkanowy.data.*
import io.github.wulkanowy.data.db.entities.Mailbox
import io.github.wulkanowy.data.db.entities.MailboxType
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.Recipient
-import io.github.wulkanowy.data.logResourceStatus
-import io.github.wulkanowy.data.onResourceNotLoading
import io.github.wulkanowy.data.pojos.MessageDraft
-import io.github.wulkanowy.data.repositories.*
-import io.github.wulkanowy.data.resourceFlow
+import io.github.wulkanowy.data.repositories.MessageRepository
+import io.github.wulkanowy.data.repositories.PreferencesRepository
+import io.github.wulkanowy.data.repositories.RecipientRepository
+import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.AnalyticsHelper
@@ -28,7 +28,6 @@ class SendMessagePresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
private val messageRepository: MessageRepository,
- private val mailboxRepository: MailboxRepository,
private val recipientRepository: RecipientRepository,
private val preferencesRepository: PreferencesRepository,
private val analytics: AnalyticsHelper
@@ -36,10 +35,19 @@ class SendMessagePresenter @Inject constructor(
private val messageUpdateChannel = Channel()
+ private var message: Message? = null
+ private var isReplay: Boolean? = null
+
+ private var mailboxes: List = emptyList()
+ private var selectedMailbox: Mailbox? = null
+
fun onAttachView(view: SendMessageView, reason: String?, message: Message?, reply: Boolean?) {
super.onAttachView(view)
view.initView()
initializeSubjectStream()
+ this.message = message
+ this.isReplay = reply
+
Timber.i("Send message view was initialized")
loadData(message, reply)
with(view) {
@@ -110,16 +118,31 @@ class SendMessagePresenter @Inject constructor(
return false
}
+ fun onOpenMailboxChooser() {
+ view?.showMailboxChooser(mailboxes)
+ }
+
+ fun onMailboxSelected(mailbox: Mailbox?) {
+ selectedMailbox = mailbox
+
+ loadData(message, isReplay)
+ }
+
private fun loadData(message: Message?, reply: Boolean?) {
resourceFlow {
val student = studentRepository.getCurrentStudent()
- val mailbox = mailboxRepository.getMailbox(student)
+
+ if (selectedMailbox == null && mailboxes.isEmpty()) {
+ selectedMailbox = messageRepository.getMailboxByStudent(student)
+ mailboxes = messageRepository.getMailboxes(student, false).toFirstResult()
+ .dataOrNull.orEmpty()
+ }
Timber.i("Loading recipients started")
val recipients = createChips(
recipients = recipientRepository.getRecipients(
student = student,
- mailbox = mailbox,
+ mailbox = selectedMailbox,
type = MailboxType.EMPLOYEE,
)
)
@@ -130,7 +153,7 @@ class SendMessagePresenter @Inject constructor(
message != null && reply == true -> recipientRepository.getMessageSender(
student = student,
message = message,
- mailbox = mailbox,
+ mailbox = selectedMailbox,
)
else -> emptyList()
}.let { createChips(it) }
@@ -139,39 +162,42 @@ class SendMessagePresenter @Inject constructor(
messageRecipients.size
)
- Triple(mailbox, recipients, messageRecipients)
+ recipients to messageRecipients
}
.logResourceStatus("load recipients")
- .onEach {
- when (it) {
- is Resource.Loading -> view?.run {
- showProgress(true)
- showContent(false)
- }
- is Resource.Success -> it.data.let { (mailbox, recipientChips, selectedRecipientChips) ->
- view?.run {
- setMailbox(getMailboxName(mailbox))
- setRecipients(recipientChips)
- if (selectedRecipientChips.isNotEmpty()) setSelectedRecipients(
- selectedRecipientChips
- )
- showContent(true)
- }
- }
- is Resource.Error -> {
- view?.showContent(true)
- errorHandler.dispatch(it.error)
+ .onResourceLoading {
+ view?.run {
+ showProgress(true)
+ showContent(false)
+ }
+ }
+ .onResourceNotLoading {
+ view?.run { showProgress(false) }
+ }
+ .onResourceError {
+ view?.showContent(true)
+ errorHandler.dispatch(it)
+ }
+ .onResourceSuccess {
+ it.let { (recipientChips, selectedRecipientChips) ->
+ view?.run {
+ setMailbox(getMailboxName(selectedMailbox))
+ setRecipients(recipientChips)
+ if (selectedRecipientChips.isNotEmpty()) setSelectedRecipients(
+ selectedRecipientChips
+ )
+ showContent(true)
}
}
- }.onResourceNotLoading {
- view?.run { showProgress(false) }
- }.launch()
+ }
+ .launch()
}
private fun sendMessage(subject: String, content: String, recipients: List) {
+ val mailbox = selectedMailbox ?: return
+
resourceFlow {
val student = studentRepository.getCurrentStudent()
- val mailbox = mailboxRepository.getMailbox(student)
messageRepository.sendMessage(
student = student,
subject = subject,
@@ -222,18 +248,21 @@ class SendMessagePresenter @Inject constructor(
}
}
- private fun getMailboxName(mailbox: Mailbox): String {
+ private fun getMailboxName(mailbox: Mailbox?): String {
+ mailbox ?: return ""
+
+ // username - accountType [\n student name - ] (school short name)
return buildString {
append(mailbox.userName)
append(" - ")
append(getMailboxType(mailbox.type))
+ appendLine()
if (mailbox.type == MailboxType.PARENT) {
- append(" - ")
append(mailbox.studentName)
+ append(" - ")
}
- append(" - ")
append("(${mailbox.schoolNameShort})")
}
}
@@ -267,9 +296,9 @@ class SendMessagePresenter @Inject constructor(
private fun saveDraftMessage() {
messageRepository.draftMessage = MessageDraft(
- view?.formRecipientsData!!,
- view?.formSubjectValue!!,
- view?.formContentValue!!
+ recipients = view?.formRecipientsData!!,
+ subject = view?.formSubjectValue!!,
+ content = view?.formContentValue!!,
)
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageView.kt
index 1057114b8..e27a09d60 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessageView.kt
@@ -61,4 +61,5 @@ interface SendMessageView : BaseView {
fun getMessageBackupDialogStringWithRecipients(recipients: String): String
fun clearDraft()
+ fun showMailboxChooser(mailboxes: List)
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt
index 234d17eb2..6df6153c5 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabAdapter.kt
@@ -12,6 +12,7 @@ import androidx.recyclerview.widget.RecyclerView
import io.github.wulkanowy.R
import io.github.wulkanowy.databinding.ItemMessageBinding
import io.github.wulkanowy.databinding.ItemMessageChipsBinding
+import io.github.wulkanowy.utils.getCompatColor
import io.github.wulkanowy.utils.getThemeAttrColor
import io.github.wulkanowy.utils.toFormattedString
import javax.inject.Inject
@@ -19,13 +20,15 @@ import javax.inject.Inject
class MessageTabAdapter @Inject constructor() :
RecyclerView.Adapter() {
- var onItemClickListener: (MessageTabDataItem.MessageItem, position: Int) -> Unit = { _, _ -> }
+ lateinit var onItemClickListener: (MessageTabDataItem.MessageItem, position: Int) -> Unit
- var onLongItemClickListener: (MessageTabDataItem.MessageItem) -> Unit = {}
+ lateinit var onLongItemClickListener: (MessageTabDataItem.MessageItem) -> Unit
- var onHeaderClickListener: (CompoundButton, Boolean) -> Unit = { _, _ -> }
+ lateinit var onHeaderClickListener: (CompoundButton, Boolean) -> Unit
- var onChangesDetectedListener = {}
+ lateinit var onMailboxClickListener: () -> Unit
+
+ lateinit var onChangesDetectedListener: () -> Unit
private var items = mutableListOf()
@@ -49,12 +52,12 @@ class MessageTabAdapter @Inject constructor() :
val inflater = LayoutInflater.from(parent.context)
return when (MessageItemViewType.values()[viewType]) {
- MessageItemViewType.MESSAGE -> ItemViewHolder(
- ItemMessageBinding.inflate(inflater, parent, false)
- )
MessageItemViewType.FILTERS -> HeaderViewHolder(
ItemMessageChipsBinding.inflate(inflater, parent, false)
)
+ MessageItemViewType.MESSAGE -> ItemViewHolder(
+ ItemMessageBinding.inflate(inflater, parent, false)
+ )
}
}
@@ -69,6 +72,20 @@ class MessageTabAdapter @Inject constructor() :
val item = items[position] as MessageTabDataItem.FilterHeader
with(holder.binding) {
+ chipMailbox.text = item.selectedMailbox
+ ?: root.context.getString(R.string.message_chip_all_mailboxes)
+ chipMailbox.chipBackgroundColor = ColorStateList.valueOf(
+ if (item.selectedMailbox == null) {
+ root.context.getCompatColor(R.color.mtrl_choice_chip_background_color)
+ } else root.context.getThemeAttrColor(android.R.attr.colorPrimary, 64)
+ )
+ chipMailbox.setTextColor(
+ if (item.selectedMailbox == null) {
+ root.context.getThemeAttrColor(android.R.attr.textColorPrimary)
+ } else root.context.getThemeAttrColor(android.R.attr.colorPrimary)
+ )
+ chipMailbox.setOnClickListener { onMailboxClickListener() }
+
if (item.onlyUnread == null) {
chipUnread.isVisible = false
} else {
@@ -77,6 +94,7 @@ class MessageTabAdapter @Inject constructor() :
chipUnread.setOnCheckedChangeListener(onHeaderClickListener)
}
chipUnread.isEnabled = item.isEnabled
+
chipAttachments.isEnabled = item.isEnabled
chipAttachments.isChecked = item.onlyWithAttachments
chipAttachments.setOnCheckedChangeListener(onHeaderClickListener)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabDataItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabDataItem.kt
index 634dfc0e7..c0bd4170e 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabDataItem.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabDataItem.kt
@@ -11,6 +11,7 @@ sealed class MessageTabDataItem(val viewType: MessageItemViewType) {
) : MessageTabDataItem(MessageItemViewType.MESSAGE)
data class FilterHeader(
+ val selectedMailbox: String?,
val onlyUnread: Boolean?,
val onlyWithAttachments: Boolean,
val isEnabled: Boolean
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt
index 654b0e226..5d608ad3b 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt
@@ -10,15 +10,18 @@ import android.widget.CompoundButton
import androidx.appcompat.view.ActionMode
import androidx.appcompat.widget.SearchView
import androidx.core.view.updatePadding
+import androidx.fragment.app.setFragmentResultListener
import androidx.recyclerview.widget.LinearLayoutManager
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
+import io.github.wulkanowy.data.db.entities.Mailbox
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.enums.MessageFolder
import io.github.wulkanowy.databinding.FragmentMessageTabBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.message.MessageFragment
+import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog
import io.github.wulkanowy.ui.modules.message.preview.MessagePreviewFragment
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
import io.github.wulkanowy.utils.dpToPx
@@ -104,6 +107,7 @@ class MessageTabFragment : BaseFragment(R.layout.frag
onItemClickListener = presenter::onMessageItemSelected
onLongItemClickListener = presenter::onMessageItemLongSelected
onHeaderClickListener = ::onChipChecked
+ onMailboxClickListener = presenter::onMailboxFilterSelected
onChangesDetectedListener = ::resetListPosition
}
@@ -123,6 +127,12 @@ class MessageTabFragment : BaseFragment(R.layout.frag
messageTabErrorRetry.setOnClickListener { presenter.onRetry() }
messageTabErrorDetails.setOnClickListener { presenter.onDetailsClick() }
}
+
+ setFragmentResultListener(requireArguments().getString(MESSAGE_TAB_FOLDER_ID)!!) { _, bundle ->
+ presenter.onMailboxSelected(
+ mailbox = bundle.getSerializable(MailboxChooserDialog.MAILBOX_KEY) as? Mailbox,
+ )
+ }
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@@ -246,6 +256,16 @@ class MessageTabFragment : BaseFragment(R.layout.frag
)
}
+ override fun showMailboxChooser(mailboxes: List) {
+ (activity as? MainActivity)?.showDialogFragment(
+ MailboxChooserDialog.newInstance(
+ mailboxes = mailboxes,
+ isMailboxRequired = false,
+ folder = requireArguments().getString(MESSAGE_TAB_FOLDER_ID)!!,
+ )
+ )
+ }
+
override fun hideKeyboard() {
activity?.hideSoftInput()
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt
index 54711a689..ea142db2b 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt
@@ -1,9 +1,9 @@
package io.github.wulkanowy.ui.modules.message.tab
import io.github.wulkanowy.data.*
+import io.github.wulkanowy.data.db.entities.Mailbox
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.enums.MessageFolder
-import io.github.wulkanowy.data.repositories.MailboxRepository
import io.github.wulkanowy.data.repositories.MessageRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
@@ -26,7 +26,6 @@ class MessageTabPresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
private val messageRepository: MessageRepository,
- private val mailboxRepository: MailboxRepository,
private val analytics: AnalyticsHelper
) : BasePresenter(errorHandler, studentRepository) {
@@ -36,6 +35,9 @@ class MessageTabPresenter @Inject constructor(
private var lastSearchQuery = ""
+ private var mailboxes: List = emptyList()
+ private var selectedMailbox: Mailbox? = null
+
private var messages = emptyList()
private val searchChannel = Channel()
@@ -122,8 +124,7 @@ class MessageTabPresenter @Inject constructor(
runCatching {
val student = studentRepository.getCurrentStudent(true)
- val mailbox = mailboxRepository.getMailbox(student)
- messageRepository.deleteMessages(student, mailbox, messageList)
+ messageRepository.deleteMessages(student, selectedMailbox, messageList)
}
.onFailure(errorHandler::dispatch)
.onSuccess { view?.showMessagesDeleted() }
@@ -202,13 +203,28 @@ class MessageTabPresenter @Inject constructor(
}
}
+ fun onMailboxFilterSelected() {
+ view?.showMailboxChooser(mailboxes)
+ }
+
+ fun onMailboxSelected(mailbox: Mailbox?) {
+ selectedMailbox = mailbox
+ loadData(false)
+ }
+
private fun loadData(forceRefresh: Boolean) {
Timber.i("Loading $folder message data started")
flatResourceFlow {
val student = studentRepository.getCurrentStudent()
- val mailbox = mailboxRepository.getMailbox(student)
- messageRepository.getMessages(student, mailbox, folder, forceRefresh)
+
+ if (selectedMailbox == null && mailboxes.isEmpty()) {
+ selectedMailbox = messageRepository.getMailboxByStudent(student)
+ mailboxes = messageRepository.getMailboxes(student, forceRefresh).toFirstResult()
+ .dataOrNull.orEmpty()
+ }
+
+ messageRepository.getMessages(student, selectedMailbox, folder, forceRefresh)
}
.logResourceStatus("load $folder message")
.onResourceData {
@@ -327,7 +343,16 @@ class MessageTabPresenter @Inject constructor(
MessageTabDataItem.FilterHeader(
onlyUnread = onlyUnread.takeIf { folder != MessageFolder.SENT },
onlyWithAttachments = onlyWithAttachments,
- isEnabled = !isActionMode
+ isEnabled = !isActionMode,
+ selectedMailbox = selectedMailbox?.let {
+ buildString {
+ if (it.studentName.isNotBlank() && it.studentName != it.userName) {
+ append(it.studentName)
+ append(" - ")
+ }
+ append(it.userName)
+ }
+ },
)
)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabView.kt
index bfa43b209..6ece6621b 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabView.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabView.kt
@@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.message.tab
+import io.github.wulkanowy.data.db.entities.Mailbox
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.ui.base.BaseView
@@ -46,4 +47,6 @@ interface MessageTabView : BaseView {
fun showActionMode(show: Boolean)
fun showRecyclerBottomPadding(show: Boolean)
+
+ fun showMailboxChooser(mailboxes: List)
}
diff --git a/app/src/main/java/io/github/wulkanowy/utils/RefreshUtils.kt b/app/src/main/java/io/github/wulkanowy/utils/RefreshUtils.kt
index c69fec65c..93e67be01 100644
--- a/app/src/main/java/io/github/wulkanowy/utils/RefreshUtils.kt
+++ b/app/src/main/java/io/github/wulkanowy/utils/RefreshUtils.kt
@@ -4,6 +4,7 @@ import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.SharedPrefProvider
+import io.github.wulkanowy.data.db.entities.Mailbox
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.enums.MessageFolder
@@ -25,8 +26,8 @@ fun getRefreshKey(name: String, student: Student): String {
return "${name}_${student.userLoginId}"
}
-fun getRefreshKey(name: String, student: Student, folder: MessageFolder): String {
- return "${name}_${student.id}_${folder.id}"
+fun getRefreshKey(name: String, mailbox: Mailbox?, folder: MessageFolder): String {
+ return "${name}_${mailbox?.globalKey ?: "all"}_${folder.id}"
}
class AutoRefreshHelper @Inject constructor(
diff --git a/app/src/main/res/layout/activity_send_message.xml b/app/src/main/res/layout/activity_send_message.xml
index 320782bdc..a8041d61c 100644
--- a/app/src/main/res/layout/activity_send_message.xml
+++ b/app/src/main/res/layout/activity_send_message.xml
@@ -55,17 +55,29 @@
android:id="@+id/sendMessageFrom"
android:layout_width="0dp"
android:layout_height="58dp"
- android:layout_marginStart="16dp"
- android:layout_marginLeft="16dp"
- android:layout_marginEnd="16dp"
- android:layout_marginRight="16dp"
+ android:layout_marginStart="8dp"
+ android:background="?selectableItemBackground"
android:gravity="center_vertical"
+ android:paddingStart="8dp"
+ android:paddingEnd="32dp"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/sendMessageFromHint"
app:layout_constraintTop_toTopOf="parent"
tools:text="Jan Kowalski" />
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_mailbox_chooser.xml b/app/src/main/res/layout/item_mailbox_chooser.xml
new file mode 100644
index 000000000..7c93199bc
--- /dev/null
+++ b/app/src/main/res/layout/item_mailbox_chooser.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_message_chips.xml b/app/src/main/res/layout/item_message_chips.xml
index 481a94835..da2e20311 100644
--- a/app/src/main/res/layout/item_message_chips.xml
+++ b/app/src/main/res/layout/item_message_chips.xml
@@ -1,21 +1,30 @@
-
+ app:layout_constraintTop_toTopOf="parent"
+ app:singleLine="true">
+
+
-
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e65a27fcc..e365a00ca 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -301,6 +301,7 @@
Message does not exist
You need to choose at least 1 recipient
The message content must be at least 3 characters
+ Wszystkie skrzynki
Only unread
Only with attachments
Read: %s
@@ -324,6 +325,7 @@
- %1$d selected
Messages deleted
+ Choose mailbox
diff --git a/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt b/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt
index ff0a53135..84a0cb405 100644
--- a/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt
+++ b/app/src/test/java/io/github/wulkanowy/TestEnityCreator.kt
@@ -27,7 +27,9 @@ fun getMailboxEntity() = Mailbox(
globalKey = "v4",
fullName = "",
userName = "",
- userLoginId = 0,
+ email = "test",
+ symbol = "powiatwulkanowy",
+ schoolId = "123456",
studentName = "",
schoolNameShort = "",
type = MailboxType.UNKNOWN,
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
index 9fc83a23b..9a2c22fd6 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/MessageRepositoryTest.kt
@@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories
import android.content.Context
import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.SharedPrefProvider
+import io.github.wulkanowy.data.db.dao.MailboxDao
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
import io.github.wulkanowy.data.db.dao.MessagesDao
import io.github.wulkanowy.data.db.entities.Message
@@ -10,6 +11,7 @@ import io.github.wulkanowy.data.db.entities.MessageWithAttachment
import io.github.wulkanowy.data.enums.MessageFolder
import io.github.wulkanowy.data.errorOrNull
import io.github.wulkanowy.data.toFirstResult
+import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase
import io.github.wulkanowy.getMailboxEntity
import io.github.wulkanowy.getStudentEntity
import io.github.wulkanowy.sdk.Sdk
@@ -55,6 +57,12 @@ class MessageRepositoryTest {
@MockK
private lateinit var sharedPrefProvider: SharedPrefProvider
+ @MockK
+ private lateinit var mailboxDao: MailboxDao
+
+ @MockK
+ private lateinit var getMailboxByStudentUseCase: GetMailboxByStudentUseCase
+
private val student = getStudentEntity()
private val mailbox = getMailboxEntity()
@@ -74,26 +82,33 @@ class MessageRepositoryTest {
refreshHelper = refreshHelper,
sharedPrefProvider = sharedPrefProvider,
json = Json,
+ mailboxDao = mailboxDao,
+ getMailboxByStudentUseCase = getMailboxByStudentUseCase,
)
}
@Test
fun `get messages when fetched completely new message without notify`() = runBlocking {
- every { messageDb.loadAll(any(), any()) } returns flowOf(emptyList())
+ coEvery { mailboxDao.loadAll(any()) } returns listOf(mailbox)
+ every { messageDb.loadAll(mailbox.globalKey, any()) } returns flowOf(emptyList())
coEvery { sdk.getMessages(Folder.RECEIVED, any()) } returns listOf(
- getMessageDto()
+ getMessageDto().copy(
+ unreadBy = 5,
+ readBy = 10,
+ )
)
coEvery { messageDb.deleteAll(any()) } just Runs
coEvery { messageDb.insertAll(any()) } returns listOf()
- repository.getMessages(
+ val res = repository.getMessages(
student = student,
mailbox = mailbox,
folder = MessageFolder.RECEIVED,
forceRefresh = true,
notify = false,
- ).toFirstResult().dataOrNull.orEmpty()
+ ).toFirstResult()
+ assertEquals(null, res.errorOrNull)
coVerify(exactly = 1) { messageDb.deleteAll(withArg { checkEquals(emptyList()) }) }
coVerify {
messageDb.insertAll(withArg {
@@ -187,6 +202,7 @@ class MessageRepositoryTest {
) = Message(
messageGlobalKey = "v4",
mailboxKey = "",
+ email = "",
correspondents = "",
messageId = messageId,
subject = "",
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/MailboxRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/domain/GetMailboxByStudentUseCaseTest.kt
similarity index 77%
rename from app/src/test/java/io/github/wulkanowy/data/repositories/MailboxRepositoryTest.kt
rename to app/src/test/java/io/github/wulkanowy/domain/GetMailboxByStudentUseCaseTest.kt
index 9198560fe..96a84a5a6 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/MailboxRepositoryTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/domain/GetMailboxByStudentUseCaseTest.kt
@@ -1,65 +1,52 @@
-package io.github.wulkanowy.data.repositories
+package io.github.wulkanowy.domain
import io.github.wulkanowy.data.db.dao.MailboxDao
import io.github.wulkanowy.data.db.entities.Mailbox
import io.github.wulkanowy.data.db.entities.MailboxType
import io.github.wulkanowy.data.db.entities.Student
+import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase
import io.github.wulkanowy.sdk.Sdk
-import io.github.wulkanowy.utils.AutoRefreshHelper
import io.mockk.MockKAnnotations
import io.mockk.Runs
import io.mockk.coEvery
import io.mockk.impl.annotations.MockK
-import io.mockk.impl.annotations.SpyK
import io.mockk.just
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
-import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import java.time.Instant
+import kotlin.test.assertEquals
+import kotlin.test.assertNull
@OptIn(ExperimentalCoroutinesApi::class)
-class MailboxRepositoryTest {
-
- @SpyK
- private var sdk = Sdk()
+class GetMailboxByStudentUseCaseTest {
@MockK
private lateinit var mailboxDao: MailboxDao
- @MockK
- private lateinit var refreshHelper: AutoRefreshHelper
-
- private lateinit var systemUnderTest: MailboxRepository
+ private lateinit var systemUnderTest: GetMailboxByStudentUseCase
@Before
fun setUp() {
MockKAnnotations.init(this)
- coEvery { refreshHelper.shouldBeRefreshed(any()) } returns false
- coEvery { refreshHelper.updateLastRefreshTimestamp(any()) } just Runs
coEvery { mailboxDao.deleteAll(any()) } just Runs
coEvery { mailboxDao.insertAll(any()) } returns emptyList()
coEvery { mailboxDao.loadAll(any()) } returns emptyList()
- coEvery { sdk.getMailboxes() } returns emptyList()
- systemUnderTest = MailboxRepository(
- mailboxDao = mailboxDao,
- sdk = sdk,
- refreshHelper = refreshHelper,
- )
+ systemUnderTest = GetMailboxByStudentUseCase(mailboxDao = mailboxDao)
}
- @Test(expected = IllegalArgumentException::class)
+ @Test
fun `get mailbox that doesn't exist`() = runTest {
val student = getStudentEntity(
userName = "Stanisław Kowalski",
studentName = "Jan Kowalski",
)
- coEvery { sdk.getMailboxes() } returns emptyList()
+ coEvery { mailboxDao.loadAll(any()) } returns emptyList()
- systemUnderTest.getMailbox(student)
+ assertNull(systemUnderTest(student))
}
@Test
@@ -73,7 +60,7 @@ class MailboxRepositoryTest {
expectedMailbox,
)
- val selectedMailbox = systemUnderTest.getMailbox(student)
+ val selectedMailbox = systemUnderTest(student)
assertEquals(expectedMailbox, selectedMailbox)
}
@@ -88,7 +75,7 @@ class MailboxRepositoryTest {
expectedMailbox,
)
- assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
+ assertEquals(expectedMailbox, systemUnderTest(student))
}
@Test
@@ -102,10 +89,10 @@ class MailboxRepositoryTest {
expectedMailbox,
)
- assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
+ assertEquals(expectedMailbox, systemUnderTest(student))
}
- @Test(expected = IllegalArgumentException::class)
+ @Test
fun `get mailbox for not-unique non-authorized student`() = runTest {
val student = getStudentEntity(
userName = "Stanisław Kowalski",
@@ -116,7 +103,7 @@ class MailboxRepositoryTest {
getMailboxEntity("Jan Kurowski"),
)
- systemUnderTest.getMailbox(student)
+ assertNull(systemUnderTest(student))
}
@Test
@@ -130,7 +117,7 @@ class MailboxRepositoryTest {
expectedMailbox,
)
- assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
+ assertEquals(expectedMailbox, systemUnderTest(student))
}
@Test
@@ -144,7 +131,7 @@ class MailboxRepositoryTest {
expectedMailbox,
)
- assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
+ assertEquals(expectedMailbox, systemUnderTest(student))
}
@Test
@@ -158,7 +145,7 @@ class MailboxRepositoryTest {
expectedMailbox,
)
- assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
+ assertEquals(expectedMailbox, systemUnderTest(student))
}
private fun getMailboxEntity(
@@ -167,7 +154,9 @@ class MailboxRepositoryTest {
globalKey = "",
fullName = "",
userName = "",
- userLoginId = 123,
+ email = "",
+ schoolId = "",
+ symbol = "",
studentName = studentName,
schoolNameShort = "",
type = MailboxType.STUDENT,
From d3e276d6fc79d4806befce5c9f43826b4f4ec4bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Borcz?=
Date: Wed, 16 Nov 2022 20:13:48 +0100
Subject: [PATCH 150/164] New Crowdin updates (#2049)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Mikołaj Pich
---
app/src/main/res/values-cs/strings.xml | 5 +-
app/src/main/res/values-de/strings.xml | 3 +
app/src/main/res/values-es-rES/strings.xml | 3 +
app/src/main/res/values-pl/strings.xml | 3 +
app/src/main/res/values-ru/strings.xml | 41 +++++-----
app/src/main/res/values-sk/strings.xml | 5 +-
app/src/main/res/values-uk/strings.xml | 25 +++---
app/src/main/res/values/strings.xml | 92 +---------------------
8 files changed, 55 insertions(+), 122 deletions(-)
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index d036e7e42..f41cb17f9 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -309,9 +309,11 @@
Zpráva neexistuje
Musíte vybrat alespoň 1 příjemce
Obsah zprávy musí mít alespoň 3 znaky
+ Všechny poštovní schránky
Pouze nepřečtené
Pouze s přílohami
Přečtena: %s
+ Přečtena přes: %1$d z %2$d osob
- %1$d zpráva
- %1$d zprávy
@@ -339,6 +341,7 @@
- %1$d vybraných
Zprávy odstraněné
+ Vyberte poštovní schránku
Žádné informace o poznámkách
Body
@@ -735,7 +738,7 @@
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ů
Přizpůsobené reklamy
Nepřizpůsobené reklamy
- Mám ukončené 18 let
+ Je mi více než 18 let
Ano, přizpůsobené reklamy
Ano, nepřizpůsobené reklamy
Pokročilé
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 7b544258a..6107fbb96 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -275,9 +275,11 @@
Nachricht nicht vorhanden
Sie müssen mindestens 1 Empfänger auswählen.
Der Inhalt der Nachricht muss mindestens 3 Zeichen lang sein.
+ All mailboxes
Nur ungelesen
Nur mit Anhängen
Lesen: %s
+ Read by: %1$d of %2$d people
- %1$d Nachricht
- %1$d Nachrichten
@@ -297,6 +299,7 @@
- %1$d ausgewählt
Nachrichten gelöscht
+ Choose mailbox
Keine Informationen über Eintragen
Punkte
diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml
index aecc720b7..95a00a602 100644
--- a/app/src/main/res/values-es-rES/strings.xml
+++ b/app/src/main/res/values-es-rES/strings.xml
@@ -275,9 +275,11 @@
Message does not exist
You need to choose at least 1 recipient
The message content must be at least 3 characters
+ All mailboxes
Only unread
Only with attachments
Read: %s
+ Read by: %1$d of %2$d people
- %1$d message
- %1$d messages
@@ -297,6 +299,7 @@
- %1$d selected
Messages deleted
+ Choose mailbox
No info about notes
Points
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index c9abbd022..f612d826d 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -309,9 +309,11 @@
Wiadomość nie istnieje
Musisz wybrać co najmniej 1 adresata
Treść wiadomości musi zawierać co najmniej 3 znaki
+ Wszystkie skrzynki
Tylko nieprzeczytane
Tylko z załącznikami
Przeczytana: %s
+ Przeczytana przez: %1$d z %2$d osób
- %1$d wiadomość
- %1$d wiadomości
@@ -339,6 +341,7 @@
- %1$d wybranych
Wiadomości zostały usunięte
+ Wybierz skrzynkę
Brak informacji o uwagach
Punkty
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index e1abb0293..195371fd0 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -77,9 +77,9 @@
Войти
Сеанс истёк
Сеанс истёк, авторизуйтесь снова
- Application support
- Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time
- Enable ads
+ Поддержка приложения
+ Вам нравится это приложение? Поддержите его разработку, включив неинвазивную рекламу, которую можно отключить в любое время
+ Включить рекламу
Оценка
%d семестр
@@ -97,7 +97,7 @@
Ожидаемая оценка
Рассчитанная средняя оценка
Как работает \"Рассчитанная средняя оценка\"?
- The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\nAverage of grades only from selected semester:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\nAverage of averages from both semesters:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\nAverage of grades from the whole year:\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n2. Adding calculated averages\n3. Calculating the arithmetic average of summed averages
+ Рассчитанная средняя оценка - это среднее арифметическое, рассчитанное на основе средних оценок по предметам. Это позволяет узнать приблизительную итоговую среднюю оценку. Она рассчитывается способом, выбранным пользователем в настройках приложения. Рекомендуется выбрать подходящий вариант, так как каждая школа по разному считает среднюю оценку. Кроме того, если ваша школа выставляет средние оценки по предметам на странице Vulcan, приложение просто загрузит их. Это можно изменить, заставив приложение считать среднюю оценку в настройках.\n\nСредняя из оценок выбранного семестра:\n1. Вычисление средневзвешенного значения по каждому предмету за семестр\n2.Суммирование вычисленных значений\n3. Вычисление среднего арифметического суммированных значений\n\nСредняя из средних оценок семестров:\n1.Расчет средневзвешенного значения для каждого предмета в семестрах. \n2. Вычисление среднего арифметического из средневзвешенных значений для каждого предмета в семестрах.\n3. Суммирование средних арифметических\n4. Вычисление среднего арифматического из суммированных значений\n\nСредняя из оценок со всего года:\n1. Расчет средневзвешенного значения по каждому предмету за год. Итоговое среднее значение за 1 семестр не имеет значения.\n2. Суммирование вычисленных средних\n3. Расчет среднего арифметического суммированных чисел
Как работает \"Итоговая средняя оценка\"?
Итоговая средняя оценка - это среднее арифметическое, рассчитанное из всех имеющихся на данный момент итоговых оценок в семестре.\n\nРассчет происходит следующим образом:\n1. Суммирование итоговых оценок, выставленных преподавателями\n2. Полученная сумма делится на число предметов, по которым выставлены оценки
Итоговая средняя оценка
@@ -297,10 +297,10 @@
Перенести в корзину
Удалить навсегда
Письмо успешно удалено
- student
- parent
- guardian
- employee
+ ученик
+ родитель
+ опекун
+ работник
Поделиться
Печать
Тема
@@ -309,9 +309,11 @@
Письма не существует
Вы должны выбрать как минимум одного получателя
Текст сообщения должен содержать как минимум 3 знака
+ Все почтовые ящики
Только непрочитанные
Только с вложениями
Прочитано: %s
+ Прочитано: %1$d из %2$d человек
- %1$d сообщение
- %1$d сообщения
@@ -339,6 +341,7 @@
- %1$d выбрано
Сообщение удалено
+ Выбрать почтовый ящик
Нет записей о замечаниях и свершениях
Баллы
@@ -720,10 +723,10 @@
Отвечать с историей сообщений
Показывать среднее арифметическое при отсутствии стоимости
Поддержка
- Privacy Policy
- Agreements
- Consent to processing of data related to ads
- Show ads in app
+ Политика приватности
+ Соглашения
+ Согласие на обработку данных, связанных с объявлениями
+ Показать рекламу в приложении
Посмотреть рекламу для поддержки проекта
Согласие на обработку данных
Для просмотра рекламы вы должны согласиться с условиями обработки данных нашей Политики конфиденциальности
@@ -731,13 +734,13 @@
Политика конфиденциальности
Реклама загружается
Спасибо за вашу поддержку, возвращайтесь позже для дополнительной рекламы
- Can we use your data to display ads?
- 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
- Personalized ads
- Non-personalized ads
- I am over 18 years old
- Yes, personalized ads
- Yes, non-personalized ads
+ Можем ли мы использовать ваши данные для показа рекламы?
+ Вы можете изменить свой выбор в любое время в настройках приложения. Мы можем использовать ваши данные для показа объявлений в соответствии с вашими пожеланиями или, используя меньше данных, отображать неперсональную рекламу. Пожалуйста, ознакомьтесь с нашей политикой конфиденциальности для подробностей
+ Персонализированная реклама
+ Неперсонализированная реклама
+ Я старше 18 лет
+ Да, персонализировать рекламу
+ Да, не персонализировать рекламу
Расширенные
Внешний вид и поведение
Уведомления
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index 1c6eae8c0..9fd06bcbe 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -309,9 +309,11 @@
Správa neexistuje
Musíte vybrať aspoň 1 príjemca
Obsah správy musí mať aspoň 3 znaky
+ Všetky poštové schránky
Iba neprečítané
Iba s prílohami
Prečítaná: %s
+ Prečítaná cez: %1$d z %2$d osôb
- %1$d správa
- %1$d správy
@@ -339,6 +341,7 @@
- %1$d vybraných
Správy odstránené
+ Vyberte poštovú schránku
Žiadne informácie o poznámkach
Body
@@ -735,7 +738,7 @@
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
Prispôsobené reklamy
Neprispôsobené reklamy
- Mám ukončené 18 rokov
+ Mám viac ako 18 rokov
Áno, prispôsobené reklamy
Áno, neprispôsobené reklamy
Pokročilé
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 2c104ecbf..2d3bf3724 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -77,8 +77,8 @@
Увійти
Минув термін дії сесії
Минув термін дії сесії, авторизуйтеся знову
- Підтримка додатків
- Вам подобається цей додаток? Підтримуйте його розвиток, увімкнувши неінвазивну рекламу, яку ви можете будь-коли вимкнути
+ Підтримка додатку
+ Вам подобається цей додаток? Підтримайте його розвиток, увімкнувши неінвазивну рекламу, яку ви можете відключити в будь-який час
Увімкнути рекламу
Оцінка
@@ -97,7 +97,7 @@
Передбачувана оцінка
Розрахована середня оцінка
Як працює \"Розрахована середня оцінка\"?
- Розрахована середня оцінка - це середнє арифметичне, обчислене з середніх оцінок з предметів.Це дозволяє дізнатися приблизну кінцеву середню оцінку.Вона розраховується способом, обраним користувачем у налаштуваннях програми.Рекомендується вибрати відповідний варіант, тому що кожна школа по різному розраховує середню оцінку.Крім того, якщо у вашій школі повідомляється середня оцінка з предметів на сторінці Vulcan, програма тільки завантажує ці оцінки.Це можна змінити шляхом примусового розрахунку середньоЇ оцінки в налаштуваннях програми.\n\nСередні оцінки тільки за обраний семестр:\n1. Розрахунок середньозваженого числа для кожного предмета в даному семестрі\n2. Сумування розрахованих числ\n3. Розрахунок середнього арифметичного з сумованих чисел\n\nСереднє значення з обох семестрів:\n1. Обчислення середньозваженого числа для кожного предмета у 1 та 2 семестрі\n2. Обчислення середнього арифметичного з розрахованих середньозважених числ за 1 та 2 семестри для кожного предмета.\n3. Додавання розрахованих середніх\n4. Розрахунок середнього арифметичного підсумованих середніх значень\n\nСереднє значення оцінок за весь рік: \n1. Розрахунок середньозваженого числа за рік для кожного предмета. Підсумковий середній показник у 1-му семестрі не має значення.\n2. Сумування розрахованих середніх\n3. Обчислення середнього арифметичного з суммованих середніх
+ Розрахована середня оцінка - це середнє арифметичне, обчислене з середніх оцінок з предметів. Це дозволяє дізнатися приблизну кінцеву середню оцінку. Вона розраховується спосібом, обраним користувачем у налаштуваннях програми. Рекомендується вибрати відповідний варіант, тому що кожна школа по різному розраховує середню оцінку. Крім того, якщо у вашій школі повідомляється середня оцінка з предметів на сторінці Vulcan, програма тільки завантажує ці оцінки і не розраховує їх самостійно. Це можна змінити шляхом примусового розрахунку середньоЇ оцінки в налаштуваннях програми.\n\nСередні оцінки тільки за обраний семестр:\n1. Розрахунок середньозваженого числа для кожного предмета в даному семестрі\n2. Сумування розрахованих числ\n3. Розрахунок середнього арифметичного з сумованих чисел\n\nСереднє значення з обох семестрів:\n1. Обчислення середньозваженого числа для кожного предмета у 1 та 2 семестрі\n2. Обчислення середнього арифметичного з розрахованих середньозважених числ за 1 та 2 семестри для кожного предмета.\n3. Додавання розрахованих середніх\n4. Розрахунок середнього арифметичного підсумованих середніх значень\n\nСереднє значення оцінок за весь рік: \n1. Розрахунок середньозваженого числа за рік для кожного предмета. Підсумковий середній показник у 1-му семестрі не має значення.\n2. Сумування розрахованих середніх\n3. Обчислення середнього арифметичного з суммованих середніх
Як працює \"Підсумкова середня оцінка\"?
Підсумкове середнє значення - це середнє арифметичне, обчислене з усіх наявних наразі підсумкових оцінок у даному семестрі. \n\nСхема обчислення складається з таких кроків:\n1. Сумування підсумкових оцінок, виставленних викладачами\n2. Ділення на кількість предметів, з яких виставлені ці оцінки
Підсумкова середня оцінка
@@ -220,7 +220,7 @@
Всі в серії
Час початку
Час завершення
- Час завершення має бути більшим, ніж час початку
+ Час завершення має бути пізніше часу початку
Підсумок відвідуваності
Відсутність зі шкільних причин
@@ -297,8 +297,8 @@
Перемістити до кошика
Видалити назавжди
Лист було успішно видалено
- студент
- батькові
+ учень
+ родич
опікун
працівник
Поділитись
@@ -309,9 +309,11 @@
Такого листа не існує
Необхідно обрати принаймні 1 адресата
Зміст листа повинен складатися принаймні з 3 знаків
+ Усі поштові скриньки
Лише непрочитані
Тільки з вкладеннями
Прочитаний: %s
+ Прочитано: %1$d з %2$d осіб
- %1$d лист
- %1$d листи
@@ -338,7 +340,8 @@
- %1$d вибрано
- %1$d вибрано
- Листи видалені
+ Листи видалено
+ Вибрати поштову скриньку
Немає інформації о зауваженнях
Бали
@@ -722,7 +725,7 @@
Підтримка
Політика конфіденційності
Угоди
- Згода на обробку даних, пов’язаних з оголошеннями
+ Згода на обробку даних, пов\'язаних з рекламою
Показувати рекламу в додатку
Подивіться одну рекламу для підтримки проєкту
Згода в обробці даних
@@ -731,9 +734,9 @@
Політика конфіденційності
Реклама завантажується
Дякуємо за вашу підтримку, повертайтеся пізніше для більшої кількості реклам
- Чи можемо ми використовувати ваші дані для відбивання реклами?
- Ви можете змінити свій вибір в будь-який час в налаштуваннях додатку. Ми можемо використовувати ваші дані для відбивання оголошень, адаптованої до вас або, використовуючи менше ваших даних, відбивати неперсоналізовані оголошення. Перегляньте нашу Політику конфіденційності для деталей
- Персоналізовані оголошення
+ Чи можемо ми використовувати ваші дані для висвітлювання реклами?
+ Ви можете змінити свій вибір в будь-який час в налаштуваннях додатку. Ми можемо використовувати ваші дані для висвітлювання реклами, адаптованої до вас або, використовуючи менше ваших даних, висвітлювати неперсоналізовану рекламу. Перегляньте нашу Політику конфіденційності для подробиць
+ Персоналізована реклама
Неперсоналізована реклама
Мені більше 18 років
Так, персоналізована реклама
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e365a00ca..71d1767ed 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -26,15 +26,11 @@
Student info
Dashboard
Notifications center
-
-
Semester %1$d, %2$d/%3$d
-
-
Sign in with the student or parent account
- Enter the symbol from the register page for account: <b>%1$s</b>
+ Enter the symbol from the register page for account: <b>%1$s</b>
Username
Email
Login, PESEL or e-mail
@@ -78,8 +74,6 @@
Recover
Student is already signed in
Standard
-
-
Account manager
Log in
@@ -88,8 +82,6 @@
Application support
Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time
Enable ads
-
-
Grade
Semester %d
@@ -152,8 +144,6 @@
- You received %1$d final grade
- You received %1$d final grades
-
-
Lesson
Room
@@ -189,8 +179,6 @@
- %d change
- %d changes
-
-
Completed lessons
Show completed lessons
@@ -198,8 +186,6 @@
Topic
Absence
Resources
-
-
Additional lessons
Show additional lessons
@@ -215,8 +201,6 @@
Start time
End time
End time must be greater than start time
-
-
Attendance summary
Absent for school reasons
@@ -249,12 +233,8 @@
- %d attendance
- %d attendance
-
-
Total
-
-
No exams this week
Type
@@ -271,8 +251,6 @@
- %d exam
- %d exams
-
-
Inbox
Sent
@@ -301,7 +279,7 @@
Message does not exist
You need to choose at least 1 recipient
The message content must be at least 3 characters
- Wszystkie skrzynki
+ All mailboxes
Only unread
Only with attachments
Read: %s
@@ -326,8 +304,6 @@
Messages deleted
Choose mailbox
-
-
No info about notes
Points
@@ -343,7 +319,6 @@
- You received %1$d note
- You received %1$d notes
-
- %d praise
@@ -357,7 +332,6 @@
- You received %1$d praise
- You received %1$d praises
-
- %d neutral note
@@ -371,8 +345,6 @@
- You received %1$d neutral note
- You received %1$d neutral notes
-
-
No info about homework
Mark as done
@@ -393,8 +365,6 @@
- %d homework
- %d homework
-
-
Lucky number
Today\'s lucky number is
@@ -402,13 +372,9 @@
Lucky number for today
Today\'s lucky number is: %s
Show history
-
-
Lucky number history
No info about lucky numbers
-
-
Mobile devices
No devices
@@ -418,12 +384,8 @@
Token
Symbol
PIN
-
-
School and teachers
-
-
School
No info about school
@@ -434,14 +396,10 @@
Name of pedagogue
Show on map
Call
-
-
Teachers
No info about teachers
No subject
-
-
Conferences
No info about conferences
@@ -459,7 +417,6 @@
Present at conference
Agenda
-
School announcements
No school announcements
@@ -475,8 +432,6 @@
- You have %1$d new school announcement
- You have %1$d new school announcements
-
-
Add account
Logout
@@ -491,8 +446,6 @@
Contact
Residence details
Personal information
-
-
App version
Contributors
@@ -516,17 +469,11 @@
Licenses
Licenses of libraries used in the application
Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\nIdentyfikator instalacji: %4$s\nTreść zgłoszenia:
-
-
License
-
-
Avatar
See more on GitHub
-
-
No info about student or student family
Name
@@ -549,19 +496,13 @@
Female
Last name
Guardian
-
-
Nick
Add nick
Choose avatar color
-
-
Share logs
Refresh
-
-
Lessons
(Tomorrow)
@@ -580,7 +521,6 @@
until %1$s
No upcoming lessons
An error occurred while loading the lessons
-
Homework
No homework to do
An error occurred while loading the homework
@@ -589,11 +529,9 @@
- %1$d more homework
due %1$s
-
Last grades
No new grades
An error occurred while loading the grades
-
School announcements
No current announcements
An error occurred while loading the announcements
@@ -601,7 +539,6 @@
- %1$d more announcement
- %1$d more announcements
-
Exams
No upcoming exams
An error occurred while loading the exams
@@ -609,7 +546,6 @@
- %1$d more exam
- %1$d more exams
-
Conferences
No upcoming conferences
An error occurred while loading the conferences
@@ -617,16 +553,11 @@
- %1$d more conference
- %1$d more conferences
-
An error occurred while loading data
None
-
-
Check for updates
Before reporting a bug, check first if an update with the bug fix is available
-
-
Content
Retry
@@ -654,16 +585,12 @@
Undo
Change
Add to calendar
-
-
No lessons
Choose theme
Light
Dark
System Theme
-
-
App
Default view
@@ -679,7 +606,6 @@
Grades color scheme
Subjects sorting
Language
-
Notifications
Other
Show notifications
@@ -699,7 +625,6 @@
Upcoming lesson notifications
You must allow the Wulkanowy app to set alarms and reminders in your system settings to use this feature.
Go to settings
-
Synchronization
Automatic update
Suspended on holidays
@@ -710,12 +635,10 @@
Sync failed
Sync in progress
Last full sync: %s
-
Value of the plus
Value of the minus
Reply with message history
Show arithmetic average when no weights provided
-
Support
Privacy Policy
Agreements
@@ -735,13 +658,11 @@
I am over 18 years old
Yes, personalized ads
Yes, non-personalized ads
-
Advanced
Appearance & Behavior
Notifications
Synchronization
Advertisements
-
Grades
Dashboard
Tiles visibility
@@ -750,7 +671,6 @@
Grades
Calculated average
Messages
-
Appearance & Behavior
Languages, themes, subjects sorting
App notifications, fix problems
@@ -761,8 +681,6 @@
Advanced
App version, contributors, social portals
Displaying advertisements, project support
-
-
New grades
New homework
@@ -777,8 +695,6 @@
Debug
Timetable change
New attendance
-
-
Black
Red
@@ -786,15 +702,11 @@
Green
Purple
No color
-
-
Download of updates has started…
An update has just been downloaded.
Restart
Update failed! Wulkanowy may not function properly. Consider updating
-
-
No internet connection
An error occurred. Check your device clock
From 2d83218f618fcb927e9a6247817623ed5562e301 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Wed, 16 Nov 2022 20:31:02 +0100
Subject: [PATCH 151/164] Version 1.8.0
---
app/build.gradle | 10 +++++-----
app/src/main/play/release-notes/pl-PL/default.txt | 10 ++++++----
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 99672f1f9..62a5a21fb 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -23,8 +23,8 @@ android {
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 21
targetSdkVersion 32
- versionCode 114
- versionName "1.7.5"
+ versionCode 115
+ versionName "1.8.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "app_name", "Wulkanowy"
@@ -160,8 +160,8 @@ kapt {
play {
defaultToAppBundles = false
track = 'production'
-// releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS
-// userFraction = 0.05d
+ releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS
+ userFraction = 0.25d
updatePriority = 4
enabled.set(false)
}
@@ -186,7 +186,7 @@ ext {
}
dependencies {
- implementation "io.github.wulkanowy:sdk:701016eda2"
+ implementation "io.github.wulkanowy:sdk:1.8.0"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
diff --git a/app/src/main/play/release-notes/pl-PL/default.txt b/app/src/main/play/release-notes/pl-PL/default.txt
index 064401abd..996d5eebc 100644
--- a/app/src/main/play/release-notes/pl-PL/default.txt
+++ b/app/src/main/play/release-notes/pl-PL/default.txt
@@ -1,7 +1,9 @@
-Wersja 1.7.5
+Wersja 1.8.0
-- naprawiliśmy kilka błędów w obsłudze nowego modułu wiadomości
-- naprawiliśmy wyświetlanie napisu "Brak ocen", jesli uczeń nie zdobył w danym semestrze jeszcze żadnych ocen
-- naprawiliśmy logowanie do aplikacji rodzicom będącym jednocześnie nauczycielami
+- naprawiliśmy liczenie średniej ucznia w ocenach klasy dla wykresu "Wszystkie"
+- zmieniliśmy kolejność przycisków akcji w podglądzie wiadomości
+- ulepszyliśmy oznaczenie nieodczytanych wiadomości
+- naprawiliśmy pokazywanie informacji o odczytanej wiadomości w wysłanych
+- dodaliśmy opcję ręcznego wybierania skrzynki pocztowej
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
From 6c115fb915cfcc29c1a25e3f94476c473a4e1ed2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Fri, 18 Nov 2022 16:32:04 +0100
Subject: [PATCH 152/164] Fallback to subject name from timetable when
attendance item doesn't have it (#2052)
* Fallback to subject name from timetable when attendance item doesn't have it
* Fix tests
* Add some unit tests
---
.../java/io/github/wulkanowy/data/Resource.kt | 2 +-
.../wulkanowy/data/db/dao/TimetableDao.kt | 3 +
.../data/mappers/AttendanceMapper.kt | 9 +-
.../data/repositories/AttendanceRepository.kt | 11 +-
.../data/mappers/AttendanceMapperKtTest.kt | 143 ++++++++++++++++++
.../repositories/AttendanceRepositoryTest.kt | 27 ++--
6 files changed, 180 insertions(+), 15 deletions(-)
create mode 100644 app/src/test/java/io/github/wulkanowy/data/mappers/AttendanceMapperKtTest.kt
diff --git a/app/src/main/java/io/github/wulkanowy/data/Resource.kt b/app/src/main/java/io/github/wulkanowy/data/Resource.kt
index 44f8a1b48..6b611e477 100644
--- a/app/src/main/java/io/github/wulkanowy/data/Resource.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/Resource.kt
@@ -49,8 +49,8 @@ fun Resource.mapData(block: (T) -> U) = when (this) {
fun Flow>.logResourceStatus(name: String, showData: Boolean = false) = onEach {
val description = when (it) {
- is Resource.Loading -> "started"
is Resource.Intermediate -> "intermediate data received" + if (showData) " (data: `${it.data}`)" else ""
+ is Resource.Loading -> "started"
is Resource.Success -> "success" + if (showData) " (data: `${it.data}`)" else ""
is Resource.Error -> "exception occurred: ${it.error}"
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/TimetableDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/TimetableDao.kt
index 5e6eec668..b4b7379f2 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/dao/TimetableDao.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/TimetableDao.kt
@@ -13,4 +13,7 @@ interface TimetableDao : BaseDao {
@Query("SELECT * FROM Timetable WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow>
+
+ @Query("SELECT * FROM Timetable WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
+ fun load(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): List
}
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/AttendanceMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/AttendanceMapper.kt
index 46e67fdaa..c0ed0c8c2 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/AttendanceMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/AttendanceMapper.kt
@@ -3,17 +3,22 @@ package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.Semester
+import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.sdk.pojo.Attendance as SdkAttendance
import io.github.wulkanowy.sdk.pojo.AttendanceSummary as SdkAttendanceSummary
-fun List.mapToEntities(semester: Semester) = map {
+fun List.mapToEntities(semester: Semester, lessons: List) = map {
Attendance(
studentId = semester.studentId,
diaryId = semester.diaryId,
date = it.date,
timeId = it.timeId,
number = it.number,
- subject = it.subject,
+ subject = it.subject.ifBlank {
+ lessons.find { lesson ->
+ lesson.date == it.date && lesson.number == it.number
+ }?.subject.orEmpty()
+ },
name = it.name,
presence = it.presence,
absence = it.absence,
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceRepository.kt
index 9aa6562a6..fd5d8bd16 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/AttendanceRepository.kt
@@ -1,6 +1,7 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.AttendanceDao
+import io.github.wulkanowy.data.db.dao.TimetableDao
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
@@ -9,8 +10,10 @@ import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Absent
import io.github.wulkanowy.utils.*
+import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.withContext
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
@@ -20,6 +23,7 @@ import javax.inject.Singleton
@Singleton
class AttendanceRepository @Inject constructor(
private val attendanceDb: AttendanceDao,
+ private val timetableDb: TimetableDao,
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
@@ -48,10 +52,15 @@ class AttendanceRepository @Inject constructor(
attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)
},
fetch = {
+ val lessons = withContext(Dispatchers.IO) {
+ timetableDb.load(
+ semester.diaryId, semester.studentId, start.monday, end.sunday
+ )
+ }
sdk.init(student)
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getAttendance(start.monday, end.sunday, semester.semesterId)
- .mapToEntities(semester)
+ .mapToEntities(semester, lessons)
},
saveFetchResult = { old, new ->
attendanceDb.deleteAll(old uniqueSubtract new)
diff --git a/app/src/test/java/io/github/wulkanowy/data/mappers/AttendanceMapperKtTest.kt b/app/src/test/java/io/github/wulkanowy/data/mappers/AttendanceMapperKtTest.kt
new file mode 100644
index 000000000..a35e5d303
--- /dev/null
+++ b/app/src/test/java/io/github/wulkanowy/data/mappers/AttendanceMapperKtTest.kt
@@ -0,0 +1,143 @@
+package io.github.wulkanowy.data.mappers
+
+import io.github.wulkanowy.data.db.entities.Semester
+import io.github.wulkanowy.data.db.entities.Timetable
+import io.github.wulkanowy.sdk.pojo.Attendance
+import io.github.wulkanowy.sdk.scrapper.attendance.SentExcuse
+import org.junit.Test
+import java.time.Instant
+import java.time.LocalDate
+import kotlin.test.assertEquals
+
+class AttendanceMapperTest {
+
+ @Test
+ fun `map attendance when fallback is not necessary`() {
+ val attendance = listOf(
+ getSdkAttendance(1, LocalDate.of(2022, 11, 17), "Oryginalna 1"),
+ getSdkAttendance(2, LocalDate.of(2022, 11, 17), "Oryginalna 2"),
+ )
+ val lessons = listOf(
+ getEntityTimetable(1, LocalDate.of(2022, 11, 17), "Pierwsza"),
+ getEntityTimetable(2, LocalDate.of(2022, 11, 17), "Druga"),
+ )
+
+ val result = attendance.mapToEntities(getEntitySemester(), lessons)
+ assertEquals("Oryginalna 1", result[0].subject)
+ assertEquals("Oryginalna 2", result[1].subject)
+ }
+
+ @Test
+ fun `map attendance when fallback is not always necessary`() {
+ val attendance = listOf(
+ getSdkAttendance(1, LocalDate.of(2022, 11, 17), "Oryginalna 1"),
+ getSdkAttendance(2, LocalDate.of(2022, 11, 17), ""),
+ )
+ val lessons = listOf(
+ getEntityTimetable(1, LocalDate.of(2022, 11, 17), "Pierwsza"),
+ getEntityTimetable(2, LocalDate.of(2022, 11, 17), "Druga"),
+ )
+
+ val result = attendance.mapToEntities(getEntitySemester(), lessons)
+ assertEquals("Oryginalna 1", result[0].subject)
+ assertEquals("Druga", result[1].subject)
+ }
+
+ @Test
+ fun `map attendance when fallback is sometimes empty`() {
+ val attendance = listOf(
+ getSdkAttendance(1, LocalDate.of(2022, 11, 17), "Oryginalna 1"),
+ getSdkAttendance(2, LocalDate.of(2022, 11, 17), ""),
+ )
+ val lessons = listOf(
+ getEntityTimetable(1, LocalDate.of(2022, 11, 17), "Pierwsza"),
+ )
+
+ val result = attendance.mapToEntities(getEntitySemester(), lessons)
+ assertEquals("Oryginalna 1", result[0].subject)
+ assertEquals("", result[1].subject)
+ }
+
+ @Test
+ fun `map attendance when fallback is empty`() {
+ val attendance = listOf(
+ getSdkAttendance(1, LocalDate.of(2022, 11, 17), ""),
+ getSdkAttendance(2, LocalDate.of(2022, 11, 17), ""),
+ )
+ val lessons = listOf(
+ getEntityTimetable(1, LocalDate.of(2022, 11, 18), "Pierwsza"),
+ getEntityTimetable(2, LocalDate.of(2022, 10, 17), "Druga"),
+ )
+
+ val result = attendance.mapToEntities(getEntitySemester(), lessons)
+ assertEquals("", result[0].subject)
+ assertEquals("", result[1].subject)
+ }
+
+ @Test
+ fun `map attendance with all subject fallback`() {
+ val attendance = listOf(
+ getSdkAttendance(1, LocalDate.of(2022, 11, 17)),
+ getSdkAttendance(2, LocalDate.of(2022, 11, 17)),
+ )
+ val lessons = listOf(
+ getEntityTimetable(1, LocalDate.of(2022, 11, 17), "Pierwsza"),
+ getEntityTimetable(2, LocalDate.of(2022, 11, 17), "Druga"),
+ )
+
+ val result = attendance.mapToEntities(getEntitySemester(), lessons)
+ assertEquals("Pierwsza", result[0].subject)
+ assertEquals("Druga", result[1].subject)
+ }
+
+ private fun getSdkAttendance(number: Int, date: LocalDate, subject: String = "") = Attendance(
+ number = number,
+ name = "ABSENCE",
+ subject = subject,
+ date = date,
+ timeId = 1,
+ categoryId = 1,
+ deleted = false,
+ excuseStatus = SentExcuse.Status.WAITING,
+ excusable = false,
+ absence = false,
+ excused = false,
+ exemption = false,
+ lateness = false,
+ presence = false,
+ )
+
+ private fun getEntityTimetable(number: Int, date: LocalDate, subject: String = "") = Timetable(
+ number = number,
+ start = Instant.now(),
+ end = Instant.now(),
+ date = date,
+ subject = subject,
+ subjectOld = "",
+ group = "",
+ room = "",
+ roomOld = "",
+ teacher = "",
+ teacherOld = "",
+ info = "",
+ changes = false,
+ canceled = false,
+ studentId = 0,
+ diaryId = 0,
+ isStudentPlan = false,
+ )
+
+ private fun getEntitySemester() = Semester(
+ studentId = 0,
+ diaryId = 0,
+ kindergartenDiaryId = 0,
+ diaryName = "",
+ schoolYear = 0,
+ semesterId = 0,
+ semesterName = 0,
+ start = LocalDate.now(),
+ end = LocalDate.now(),
+ classId = 0,
+ unitId = 0
+ )
+}
diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/AttendanceRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/AttendanceRepositoryTest.kt
index 7d22f7265..896491ef0 100644
--- a/app/src/test/java/io/github/wulkanowy/data/repositories/AttendanceRepositoryTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/repositories/AttendanceRepositoryTest.kt
@@ -2,6 +2,7 @@ package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.dao.AttendanceDao
+import io.github.wulkanowy.data.db.dao.TimetableDao
import io.github.wulkanowy.data.errorOrNull
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.toFirstResult
@@ -29,6 +30,9 @@ class AttendanceRepositoryTest {
@MockK
private lateinit var attendanceDb: AttendanceDao
+ @MockK
+ private lateinit var timetableDb: TimetableDao
+
@MockK(relaxUnitFun = true)
private lateinit var refreshHelper: AutoRefreshHelper
@@ -51,8 +55,9 @@ class AttendanceRepositoryTest {
fun setUp() {
MockKAnnotations.init(this)
every { refreshHelper.shouldBeRefreshed(any()) } returns false
+ coEvery { timetableDb.load(any(), any(), any(), any()) } returns emptyList()
- attendanceRepository = AttendanceRepository(attendanceDb, sdk, refreshHelper)
+ attendanceRepository = AttendanceRepository(attendanceDb, timetableDb, sdk, refreshHelper)
}
@Test
@@ -60,8 +65,8 @@ class AttendanceRepositoryTest {
// prepare
coEvery { sdk.getAttendance(startDate, endDate, 1) } returns remoteList
coEvery { attendanceDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
- flowOf(remoteList.mapToEntities(semester)),
- flowOf(remoteList.mapToEntities(semester))
+ flowOf(remoteList.mapToEntities(semester, emptyList())),
+ flowOf(remoteList.mapToEntities(semester, emptyList()))
)
coEvery { attendanceDb.insertAll(any()) } returns listOf(1, 2, 3)
coEvery { attendanceDb.deleteAll(any()) } just Runs
@@ -83,9 +88,9 @@ class AttendanceRepositoryTest {
// prepare
coEvery { sdk.getAttendance(startDate, endDate, 1) } returns remoteList
coEvery { attendanceDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
- flowOf(remoteList.dropLast(1).mapToEntities(semester)),
- flowOf(remoteList.dropLast(1).mapToEntities(semester)), // after fetch end before save result
- flowOf(remoteList.mapToEntities(semester))
+ flowOf(remoteList.dropLast(1).mapToEntities(semester, emptyList())),
+ flowOf(remoteList.dropLast(1).mapToEntities(semester, emptyList())), // after fetch end before save result
+ flowOf(remoteList.mapToEntities(semester, emptyList()))
)
coEvery { attendanceDb.insertAll(any()) } returns listOf(1, 2, 3)
coEvery { attendanceDb.deleteAll(any()) } just Runs
@@ -100,7 +105,7 @@ class AttendanceRepositoryTest {
coVerify { attendanceDb.loadAll(1, 1, startDate, endDate) }
coVerify {
attendanceDb.insertAll(match {
- it.size == 1 && it[0] == remoteList.mapToEntities(semester)[1]
+ it.size == 1 && it[0] == remoteList.mapToEntities(semester, emptyList())[1]
})
}
coVerify { attendanceDb.deleteAll(match { it.isEmpty() }) }
@@ -111,9 +116,9 @@ class AttendanceRepositoryTest {
// prepare
coEvery { sdk.getAttendance(startDate, endDate, 1) } returns remoteList.dropLast(1)
coEvery { attendanceDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
- flowOf(remoteList.mapToEntities(semester)),
- flowOf(remoteList.mapToEntities(semester)), // after fetch end before save result
- flowOf(remoteList.dropLast(1).mapToEntities(semester))
+ flowOf(remoteList.mapToEntities(semester, emptyList())),
+ flowOf(remoteList.mapToEntities(semester, emptyList())), // after fetch end before save result
+ flowOf(remoteList.dropLast(1).mapToEntities(semester, emptyList()))
)
coEvery { attendanceDb.insertAll(any()) } returns listOf(1, 2, 3)
coEvery { attendanceDb.deleteAll(any()) } just Runs
@@ -129,7 +134,7 @@ class AttendanceRepositoryTest {
coVerify { attendanceDb.insertAll(match { it.isEmpty() }) }
coVerify {
attendanceDb.deleteAll(match {
- it.size == 1 && it[0] == remoteList.mapToEntities(semester)[1]
+ it.size == 1 && it[0] == remoteList.mapToEntities(semester, emptyList())[1]
})
}
}
From b16036774460ab500303ab7cb8093ee1584aa8ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Sat, 19 Nov 2022 08:52:35 +0100
Subject: [PATCH 153/164] Add support for reversed student name mailbox
matching (#2051)
* Add support for reversed student name mailbox matching
* Add additional log stmt to mailbox matching in all mailbox load
* Revert changes in mapper
---
.../github/wulkanowy/data/mappers/MessageMapper.kt | 2 +-
.../domain/messages/GetMailboxByStudentUseCase.kt | 10 ++++++++++
.../domain/GetMailboxByStudentUseCaseTest.kt | 12 ++++++++++++
3 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
index 8825c5744..87111dd4d 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
@@ -6,7 +6,7 @@ import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
-fun List.mapToEntities(student: Student, mailbox: Mailbox?, allMailboxes: List) = map {
+fun List.mapToEntities(student: Student, mailbox: Mailbox?, allMailboxes: List): List = map {
Message(
messageGlobalKey = it.globalKey,
mailboxKey = mailbox?.globalKey ?: allMailboxes.find { box ->
diff --git a/app/src/main/java/io/github/wulkanowy/domain/messages/GetMailboxByStudentUseCase.kt b/app/src/main/java/io/github/wulkanowy/domain/messages/GetMailboxByStudentUseCase.kt
index d96794e51..a696d9b2f 100644
--- a/app/src/main/java/io/github/wulkanowy/domain/messages/GetMailboxByStudentUseCase.kt
+++ b/app/src/main/java/io/github/wulkanowy/domain/messages/GetMailboxByStudentUseCase.kt
@@ -21,6 +21,8 @@ class GetMailboxByStudentUseCase @Inject constructor(
it.studentName.normalizeStudentName() == normalizedStudentName
} ?: singleOrNull {
it.studentName.getFirstAndLastPart() == normalizedStudentName.getFirstAndLastPart()
+ } ?: singleOrNull {
+ it.studentName.getReversedName() == normalizedStudentName
} ?: singleOrNull {
it.studentName.getUnauthorizedVersion() == normalizedStudentName
}
@@ -43,6 +45,14 @@ class GetMailboxByStudentUseCase @Inject constructor(
return endParts.joinToString(" ")
}
+ private fun String.getReversedName(): String {
+ val parts = normalizeStudentName().split(" ")
+
+ return parts
+ .asReversed()
+ .joinToString(" ")
+ }
+
private fun String.getUnauthorizedVersion(): String {
return normalizeStudentName().split(" ")
.joinToString(" ") {
diff --git a/app/src/test/java/io/github/wulkanowy/domain/GetMailboxByStudentUseCaseTest.kt b/app/src/test/java/io/github/wulkanowy/domain/GetMailboxByStudentUseCaseTest.kt
index 96a84a5a6..029800266 100644
--- a/app/src/test/java/io/github/wulkanowy/domain/GetMailboxByStudentUseCaseTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/domain/GetMailboxByStudentUseCaseTest.kt
@@ -64,6 +64,18 @@ class GetMailboxByStudentUseCaseTest {
assertEquals(expectedMailbox, selectedMailbox)
}
+ @Test
+ fun `get mailbox for user with reversed name`() = runTest {
+ val student = getStudentEntity(
+ userName = "Kowalski Jan",
+ studentName = "Jan Kowalski",
+ )
+ val expectedMailbox = getMailboxEntity("Kowalski Jan")
+ coEvery { mailboxDao.loadAll(any()) } returns listOf(expectedMailbox)
+
+ assertEquals(expectedMailbox, systemUnderTest(student))
+ }
+
@Test
fun `get mailbox for unique non-authorized student`() = runTest {
val student = getStudentEntity(
From 650cbd5a10f8d6e27242f7306daa546cab7ed4ad Mon Sep 17 00:00:00 2001
From: Damian Czupryn <60961958+Daxxxis@users.noreply.github.com>
Date: Sat, 19 Nov 2022 14:11:26 +0100
Subject: [PATCH 154/164] Add info about optional ads in README (#2054)
---
README.cs.md | 2 +-
README.de.md | 4 ++--
README.en.md | 2 +-
README.md | 2 +-
README.sk.md | 2 +-
5 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/README.cs.md b/README.cs.md
index 2b0dc12ea..d3d4e2557 100644
--- a/README.cs.md
+++ b/README.cs.md
@@ -34,7 +34,7 @@ Neoficiální klient deníku VULCAN UONET+ pro žáka a rodiče
* podpora více účtů s možností přejmenování žáků
* tmavý a černý (AMOLED) motiv
* offline režim
-* žádné reklamy
+* volitelné reklamy na podporu projektu
## Stáhnout
diff --git a/README.de.md b/README.de.md
index 6df10ecd0..853abd13e 100644
--- a/README.de.md
+++ b/README.de.md
@@ -21,7 +21,7 @@ Inoffizieller Android VULCAN UONET+ Registrierungsclient für Schüler und ihre
* Prozentsatz der Anwesenheit
* Prüfungen
* Stundenplan
- * Unterricht abgeschlossen
+ * abgeschlossene Unterrichtsstunden
* Nachrichten
* Hausaufgaben
* Anmerkungen
@@ -34,7 +34,7 @@ Inoffizieller Android VULCAN UONET+ Registrierungsclient für Schüler und ihre
* Unterstützung für mehrere Konten mit der Möglichkeit, den Namen des Schülers zu ändern
* dunkles und schwarzes (AMOLED) Thema
* Offline-Modus
-* keine Werbung
+* optionale Werbungen, die es uns ermöglichen das Projekt zu unterstützen
## Herunterladen
diff --git a/README.en.md b/README.en.md
index 417b74de0..7877bf377 100644
--- a/README.en.md
+++ b/README.en.md
@@ -34,7 +34,7 @@ Unofficial android VULCAN UONET+ register client for both students and their par
* support for multiple accounts with the ability to rename students
* dark and black (AMOLED) theme
* offline mode
-* no ads
+* optional ads which allow to support the project
## Download
diff --git a/README.md b/README.md
index 75b6cfca2..09480e7d7 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@ Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
* obsługa wielu kont wraz z możliwością zmiany nazwy ucznia
* ciemny i czarny (AMOLED) motyw
* tryb offline
-* brak reklam
+* opcjonalne reklamy umożliwiające wsparcie projektu
## Pobierz
diff --git a/README.sk.md b/README.sk.md
index 240f8835c..64786556e 100644
--- a/README.sk.md
+++ b/README.sk.md
@@ -34,7 +34,7 @@ Neoficiálny klient denníka VULCAN UONET+ pre žiaka a rodičov
* podpora viacerých účtov s možnosťou premenovania žiakov
* tmavý a čierny (AMOLED) motív
* offline režim
-* žiadne reklamy
+* voliteľné reklamy na podporu projektu
## Stiahnuť
From fdce2cf477cc98d4035431e1419e046d1db6d2d8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Sat, 19 Nov 2022 22:50:51 +0100
Subject: [PATCH 155/164] Improve error handling in horizontal tile on
dashboard (#2053)
---
.../wulkanowy/data/mappers/MessageMapper.kt | 10 +-
.../data/repositories/MessageRepository.kt | 14 +-
.../ui/modules/dashboard/DashboardItem.kt | 19 ++-
.../modules/dashboard/DashboardPresenter.kt | 82 ++++++-----
.../dashboard/adapters/DashboardAdapter.kt | 136 ++++++++++--------
.../wulkanowy/utils/ContextExtension.kt | 7 +
app/src/main/res/drawable/ic_error_filled.xml | 9 ++
.../item_dashboard_horizontal_group.xml | 53 ++++++-
8 files changed, 228 insertions(+), 102 deletions(-)
create mode 100644 app/src/main/res/drawable/ic_error_filled.xml
diff --git a/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt b/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
index 87111dd4d..120eb183a 100644
--- a/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/mappers/MessageMapper.kt
@@ -6,12 +6,18 @@ import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
-fun List.mapToEntities(student: Student, mailbox: Mailbox?, allMailboxes: List): List = map {
+fun List.mapToEntities(
+ student: Student,
+ mailbox: Mailbox?,
+ allMailboxes: List
+): List = map {
Message(
messageGlobalKey = it.globalKey,
mailboxKey = mailbox?.globalKey ?: allMailboxes.find { box ->
box.fullName == it.mailbox
- }?.globalKey!!,
+ }?.globalKey.let { mailboxKey ->
+ requireNotNull(mailboxKey) { "Can't find ${it.mailbox} in $allMailboxes" }
+ },
email = student.email,
messageId = it.id,
correspondents = it.correspondents,
diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt
index f8be4296d..f95b8dbec 100644
--- a/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/repositories/MessageRepository.kt
@@ -3,7 +3,7 @@ package io.github.wulkanowy.data.repositories
import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.R
-import io.github.wulkanowy.data.Resource
+import io.github.wulkanowy.data.*
import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.db.dao.MailboxDao
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
@@ -14,9 +14,7 @@ import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
import io.github.wulkanowy.data.enums.MessageFolder.TRASHED
import io.github.wulkanowy.data.mappers.mapFromEntities
import io.github.wulkanowy.data.mappers.mapToEntities
-import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.data.pojos.MessageDraft
-import io.github.wulkanowy.data.toFirstResult
import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Folder
@@ -194,7 +192,9 @@ class MessageRepository @Inject constructor(
it.isEmpty() || isExpired || forceRefresh
},
query = { mailboxDao.loadAll(student.email, student.symbol, student.schoolSymbol) },
- fetch = { sdk.init(student).getMailboxes().mapToEntities(student) },
+ fetch = {
+ sdk.init(student).getMailboxes().mapToEntities(student)
+ },
saveFetchResult = { old, new ->
mailboxDao.deleteAll(old uniqueSubtract new)
mailboxDao.insertAll(new uniqueSubtract old)
@@ -207,7 +207,11 @@ class MessageRepository @Inject constructor(
val mailbox = getMailboxByStudentUseCase(student)
return if (mailbox == null) {
- getMailboxes(student, forceRefresh = true).toFirstResult()
+ getMailboxes(student, forceRefresh = true)
+ .onResourceError { throw it }
+ .onResourceSuccess { Timber.i("Found ${it.size} new mailboxes") }
+ .waitForResult()
+
getMailboxByStudentUseCase(student)
} else mailbox
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardItem.kt
index e220ae236..d019dea68 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardItem.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardItem.kt
@@ -33,18 +33,27 @@ sealed class DashboardItem(val type: Type) {
}
data class HorizontalGroup(
- val unreadMessagesCount: Int? = null,
- val attendancePercentage: Double? = null,
- val luckyNumber: Int? = null,
+ val unreadMessagesCount: Cell? = null,
+ val attendancePercentage: Cell? = null,
+ val luckyNumber: Cell? = null,
override val error: Throwable? = null,
override val isLoading: Boolean = false
) : DashboardItem(Type.HORIZONTAL_GROUP) {
+ data class Cell(
+ val data: T?,
+ val error: Boolean,
+ val isLoading: Boolean,
+ ) {
+ val isHidden: Boolean
+ get() = data == null && !error && !isLoading
+ }
+
override val isDataLoaded
- get() = unreadMessagesCount != null || attendancePercentage != null || luckyNumber != null
+ get() = unreadMessagesCount?.isLoading == false || attendancePercentage?.isLoading == false || luckyNumber?.isLoading == false
val isFullDataLoaded
- get() = luckyNumber != -1 && attendancePercentage != -1.0 && unreadMessagesCount != -1
+ get() = luckyNumber?.isLoading != true && attendancePercentage?.isLoading != true && unreadMessagesCount?.isLoading != true
}
data class Grades(
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
index cb92b0043..22b0d267e 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt
@@ -226,50 +226,71 @@ class DashboardPresenter @Inject constructor(
private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) {
flow {
- val semester = semesterRepository.getCurrentSemester(student)
- val mailbox = messageRepository.getMailboxByStudent(student)
val selectedTiles = preferencesRepository.selectedDashboardTiles
-
val flowSuccess = flowOf(Resource.Success(null))
+
val luckyNumberFlow = luckyNumberRepository.getLuckyNumber(student, forceRefresh)
.mapResourceData {
it ?: LuckyNumber(0, LocalDate.now(), 0)
}
+ .onResourceError { errorHandler.dispatch(it) }
.takeIf { DashboardItem.Tile.LUCKY_NUMBER in selectedTiles } ?: flowSuccess
- val messageFLow = messageRepository.getMessages(
- student = student,
- mailbox = mailbox,
- folder = MessageFolder.RECEIVED,
- forceRefresh = forceRefresh
- ).takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowSuccess
+ val messageFLow = flatResourceFlow {
+ val mailbox = messageRepository.getMailboxByStudent(student)
- val attendanceFlow = attendanceSummaryRepository.getAttendanceSummary(
- student = student,
- semester = semester,
- subjectId = -1,
- forceRefresh = forceRefresh
- ).takeIf { DashboardItem.Tile.ATTENDANCE in selectedTiles } ?: flowSuccess
+ messageRepository.getMessages(
+ student = student,
+ mailbox = mailbox,
+ folder = MessageFolder.RECEIVED,
+ forceRefresh = forceRefresh
+ )
+ }
+ .onResourceError { errorHandler.dispatch(it) }
+ .takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowSuccess
+
+ val attendanceFlow = flatResourceFlow {
+ val semester = semesterRepository.getCurrentSemester(student)
+ attendanceSummaryRepository.getAttendanceSummary(
+ student = student,
+ semester = semester,
+ subjectId = -1,
+ forceRefresh = forceRefresh
+ )
+ }
+ .onResourceError { errorHandler.dispatch(it) }
+ .takeIf { DashboardItem.Tile.ATTENDANCE in selectedTiles } ?: flowSuccess
emitAll(
combine(
- luckyNumberFlow,
- messageFLow,
- attendanceFlow
+ flow = luckyNumberFlow,
+ flow2 = messageFLow,
+ flow3 = attendanceFlow,
) { luckyNumberResource, messageResource, attendanceResource ->
val resList = listOf(luckyNumberResource, messageResource, attendanceResource)
- resList.firstNotNullOfOrNull { it.errorOrNull }?.let { throw it }
- val isLoading = resList.any { it is Resource.Loading }
-
- val luckyNumber = luckyNumberResource.dataOrNull?.luckyNumber
- val messageCount = messageResource.dataOrNull?.count { it.unread }
- val attendancePercentage = attendanceResource.dataOrNull?.calculatePercentage()
DashboardItem.HorizontalGroup(
- isLoading = isLoading,
- attendancePercentage = if (attendancePercentage == 0.0 && isLoading) -1.0 else attendancePercentage,
- unreadMessagesCount = if (messageCount == 0 && isLoading) -1 else messageCount,
- luckyNumber = if (luckyNumber == 0 && isLoading) -1 else luckyNumber
+ isLoading = resList.any { it is Resource.Loading },
+ error = resList.map { it.errorOrNull }.let { errors ->
+ if (errors.all { it != null }) {
+ errors.firstOrNull()
+ } else null
+ },
+ attendancePercentage = DashboardItem.HorizontalGroup.Cell(
+ data = attendanceResource.dataOrNull?.calculatePercentage(),
+ error = attendanceResource.errorOrNull != null,
+ isLoading = attendanceResource is Resource.Loading,
+ ),
+ unreadMessagesCount = DashboardItem.HorizontalGroup.Cell(
+ data = messageResource.dataOrNull?.count { it.unread },
+ error = messageResource.errorOrNull != null,
+ isLoading = messageResource is Resource.Loading,
+ ),
+ luckyNumber = DashboardItem.HorizontalGroup.Cell(
+ data = luckyNumberResource.dataOrNull?.luckyNumber,
+ error = luckyNumberResource.errorOrNull != null,
+ isLoading = luckyNumberResource is Resource.Loading,
+ )
)
})
}
@@ -280,11 +301,8 @@ class DashboardPresenter @Inject constructor(
if (it.isLoading) {
Timber.i("Loading horizontal group data started")
-
- if (it.isFullDataLoaded) {
- firstLoadedItemList += DashboardItem.Type.HORIZONTAL_GROUP
- }
} else {
+ firstLoadedItemList += DashboardItem.Type.HORIZONTAL_GROUP
Timber.i("Loading horizontal group result: Success")
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardAdapter.kt
index a3c423a8b..2c06e45fd 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardAdapter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/adapters/DashboardAdapter.kt
@@ -171,81 +171,105 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter {
+ updateMarginsRelative(
+ end = if (isAttendanceHidden && isMessagesHidden && !isLuckyNumberHidden) {
+ 0
+ } else context.dpToPx(8f).toInt()
+ )
+ }
+ }
+ }
+
+ private fun ItemDashboardHorizontalGroupBinding.bindMessages(
+ item: DashboardItem.HorizontalGroup,
+ isWideErrorShow: Boolean
+ ) {
+ dashboardHorizontalGroupItemMessageError.isVisible = item.unreadMessagesCount?.error == true
+ with(dashboardHorizontalGroupItemMessageValue) {
+ isVisible = item.unreadMessagesCount?.error != true
+ text = item.unreadMessagesCount?.data.toString()
+ }
+ with(dashboardHorizontalGroupItemMessageContainer) {
+ isVisible = item.unreadMessagesCount?.isHidden == false && !isWideErrorShow
+ setOnClickListener { onMessageTileClickListener() }
+ }
+ }
+
+ private fun ItemDashboardHorizontalGroupBinding.bindAttendance(
+ item: DashboardItem.HorizontalGroup,
+ isWideErrorShow: Boolean
+ ) {
+ val attendancePercentage = item.attendancePercentage?.data
val attendanceColor = when {
attendancePercentage == null || attendancePercentage == .0 -> {
- context.getThemeAttrColor(R.attr.colorOnSurface)
+ root.context.getThemeAttrColor(R.attr.colorOnSurface)
}
attendancePercentage <= ATTENDANCE_SECOND_WARNING_THRESHOLD -> {
- context.getThemeAttrColor(R.attr.colorPrimary)
+ root.context.getThemeAttrColor(R.attr.colorPrimary)
}
attendancePercentage <= ATTENDANCE_FIRST_WARNING_THRESHOLD -> {
- context.getThemeAttrColor(R.attr.colorTimetableChange)
+ root.context.getThemeAttrColor(R.attr.colorTimetableChange)
}
- else -> context.getThemeAttrColor(R.attr.colorOnSurface)
+ else -> root.context.getThemeAttrColor(R.attr.colorOnSurface)
}
val attendanceString = if (attendancePercentage == null || attendancePercentage == .0) {
- context.getString(R.string.dashboard_horizontal_group_no_data)
+ root.context.getString(R.string.dashboard_horizontal_group_no_data)
} else {
"%.2f%%".format(attendancePercentage)
}
- with(binding.dashboardHorizontalGroupItemAttendanceValue) {
+ dashboardHorizontalGroupItemAttendanceError.isVisible =
+ item.attendancePercentage?.error == true
+ with(dashboardHorizontalGroupItemAttendanceValue) {
+ isVisible = item.attendancePercentage?.error != true
text = attendanceString
setTextColor(attendanceColor)
}
-
- with(binding) {
- dashboardHorizontalGroupItemMessageValue.text = unreadMessagesCount.toString()
- dashboardHorizontalGroupItemLuckyValue.text = if (luckyNumber == 0) {
- context.getString(R.string.dashboard_horizontal_group_no_data)
- } else luckyNumber?.toString()
-
- dashboardHorizontalGroupItemInfoContainer.isVisible = error != null || isLoadingVisible
- dashboardHorizontalGroupItemInfoProgress.isVisible = isLoadingVisible
- dashboardHorizontalGroupItemInfoErrorText.isVisible = error != null
-
- with(dashboardHorizontalGroupItemLuckyContainer) {
- isVisible = luckyNumber != null && luckyNumber != -1 && !isLoadingVisible
- setOnClickListener { onLuckyNumberTileClickListener() }
-
- updateLayoutParams {
- updateMarginsRelative(
- end = if (attendancePercentage == null && unreadMessagesCount == null && luckyNumber != null) {
- 0
- } else {
- context.dpToPx(8f).toInt()
- }
- )
+ with(dashboardHorizontalGroupItemAttendanceContainer) {
+ isVisible = item.attendancePercentage?.isHidden == false && !isWideErrorShow
+ setOnClickListener { onAttendanceTileClickListener() }
+ updateLayoutParams {
+ matchConstraintPercentWidth = when {
+ item.luckyNumber?.isHidden == true && item.unreadMessagesCount?.isHidden == true -> 1.0f
+ item.luckyNumber?.isHidden == true || item.unreadMessagesCount?.isHidden == true -> 0.5f
+ else -> 0.4f
}
}
-
- with(dashboardHorizontalGroupItemAttendanceContainer) {
- isVisible =
- attendancePercentage != null && attendancePercentage != -1.0 && !isLoadingVisible
- updateLayoutParams {
- matchConstraintPercentWidth = when {
- luckyNumber == null && unreadMessagesCount == null -> 1.0f
- luckyNumber == null || unreadMessagesCount == null -> 0.5f
- else -> 0.4f
- }
- }
- setOnClickListener { onAttendanceTileClickListener() }
- }
-
- with(dashboardHorizontalGroupItemMessageContainer) {
- isVisible =
- unreadMessagesCount != null && unreadMessagesCount != -1 && !isLoadingVisible
- setOnClickListener { onMessageTileClickListener() }
- }
}
}
diff --git a/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt
index dd91d36d4..cc4c5aaa4 100644
--- a/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt
+++ b/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt
@@ -2,9 +2,11 @@ package io.github.wulkanowy.utils
import android.annotation.SuppressLint
import android.content.Context
+import android.content.res.ColorStateList
import android.graphics.*
import android.text.TextPaint
import android.util.DisplayMetrics.DENSITY_DEFAULT
+import android.widget.ImageView
import androidx.annotation.*
import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
@@ -12,6 +14,7 @@ import androidx.core.graphics.applyCanvas
import androidx.core.graphics.drawable.RoundedBitmapDrawable
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
import androidx.core.graphics.drawable.toBitmap
+import androidx.core.widget.ImageViewCompat
@ColorInt
@@ -85,3 +88,7 @@ fun Context.createNameInitialsDrawable(
return RoundedBitmapDrawableFactory.create(this.resources, bitmap)
.apply { isCircular = true }
}
+
+fun ImageView.setTint(@ColorInt color: Int) {
+ ImageViewCompat.setImageTintList(this, ColorStateList.valueOf(color))
+}
diff --git a/app/src/main/res/drawable/ic_error_filled.xml b/app/src/main/res/drawable/ic_error_filled.xml
new file mode 100644
index 000000000..61b575dc6
--- /dev/null
+++ b/app/src/main/res/drawable/ic_error_filled.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/item_dashboard_horizontal_group.xml b/app/src/main/res/layout/item_dashboard_horizontal_group.xml
index 1d43d5115..0c59d1ebf 100644
--- a/app/src/main/res/layout/item_dashboard_horizontal_group.xml
+++ b/app/src/main/res/layout/item_dashboard_horizontal_group.xml
@@ -37,9 +37,25 @@
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
+ app:layout_goneMarginEnd="16dp"
app:tint="?colorOnSurface"
tools:ignore="ContentDescription" />
+
+
+
+
+ tools:text="16"
+ tools:visibility="visible" />
@@ -145,9 +178,25 @@
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
+ app:layout_goneMarginEnd="16dp"
app:tint="?colorOnSurface"
tools:ignore="ContentDescription" />
+
+
-
\ No newline at end of file
+
From 9c60ce688b48226e7ffe44f5029a89de8744f7b0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Sun, 20 Nov 2022 00:05:34 +0100
Subject: [PATCH 156/164] Version 1.8.1
---
app/build.gradle | 8 ++++----
app/src/main/play/release-notes/pl-PL/default.txt | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 62a5a21fb..f6a82ad20 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -23,8 +23,8 @@ android {
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 21
targetSdkVersion 32
- versionCode 115
- versionName "1.8.0"
+ versionCode 116
+ versionName "1.8.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "app_name", "Wulkanowy"
@@ -161,7 +161,7 @@ play {
defaultToAppBundles = false
track = 'production'
releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS
- userFraction = 0.25d
+ userFraction = 0.10d
updatePriority = 4
enabled.set(false)
}
@@ -186,7 +186,7 @@ ext {
}
dependencies {
- implementation "io.github.wulkanowy:sdk:1.8.0"
+ implementation "io.github.wulkanowy:sdk:1.8.1"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
diff --git a/app/src/main/play/release-notes/pl-PL/default.txt b/app/src/main/play/release-notes/pl-PL/default.txt
index 996d5eebc..7b2fda861 100644
--- a/app/src/main/play/release-notes/pl-PL/default.txt
+++ b/app/src/main/play/release-notes/pl-PL/default.txt
@@ -1,4 +1,4 @@
-Wersja 1.8.0
+Wersja 1.8.1
- naprawiliśmy liczenie średniej ucznia w ocenach klasy dla wykresu "Wszystkie"
- zmieniliśmy kolejność przycisków akcji w podglądzie wiadomości
From 277ffd22be786cfa429ea1d61827e8cb62d1ea56 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Borcz?=
Date: Wed, 14 Dec 2022 22:41:57 +0100
Subject: [PATCH 157/164] Fix app name in french (#2072)
---
app/build.gradle | 2 +-
gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 59821 bytes
gradle/wrapper/gradle-wrapper.properties | 2 +-
3 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index f6a82ad20..fdb844aca 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -237,7 +237,7 @@ dependencies {
implementation 'com.github.bastienpaulfr:Treessence:1.0.5'
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
implementation "io.coil-kt:coil:2.2.2"
- implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
+ implementation "io.github.wulkanowy:AppKillerManager:3.0.1"
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..41d9927a4d4fb3f96a785543079b8df6723c946b 100644
GIT binary patch
delta 8958
zcmbPmk$LT9<_#=XtSSLBqeCZiTItn?SJsGx%l_Z@#_)7XgUOT&thbhl-9GCmma$Mp
zfJLb5qCf^y%MuQsGWFS>Y3bK)MlyX}a4V|6>bmw?EPjKcDQaeE;{|{qNta^Uwc%ez2Wk%|ZKT3nj()HRa+?G@o^z
z#a{33#%(0TcbX$H!*E`x+8lid*+u?#Xa*<_c|Vv{-}1ZvRL)q!RQ$u*6yi^R!yp?
zR(({#&Y!G!=k)FOQ$FhLi9W^dfF5oWYsIVdY#^byTbI
z>C-JGGcw&xd6wN?F?-i$&j;sD%
zWqivkZTK8;_hjbH)witH7tgNy7Ub~Kz*i`L#mg;jr&p(aOgWlWbj!bfl7@Ha#9f!3
zXzg;pX13(0n@Y{4skVEICoXxKDn4nF!A;L)%L<-!8^^HJ>dp(gwXyj2#2M30J&o{N
z^{peV`pIWs-|pqN*9KnRaK*y#oA9+uuNGX3>oPsMF=+0s#Ip)ElRk&eE3q)FS(@s8aqVMtZj)|dU
zW7=#<<25FZneESbA`3a^hkal;CYp2jESK4$(1U7n^P10cZA)0)WVS{7MxV|}t&pV;
zOzO)xbu?RFT}jw-?Z3w
z?MRhZb?kp!E>ySv0soK1P3j-iS?iC*ckJLX;0(+SJJxZ1*0kW+hWVF+w}v=u?Q@-+
zA;eLdopsA7+T&IH&4>FRzUP{EWXXX`FJF|V`?&jO1v^=WJvrpZ_vzEkuBlt5C%HX1
z73rv4@K<$OhF$&3o!4A*ckhr{@zN*1#6rqc@ANtMlUr9PczNrun-Ul#E2n=^k8hd%w!nl`a;OYACRm-@!QWJ6tF@vB<9
zRtXjFYwEf?!#Vxj%Gk46(&@p`XHMRGQhD7V|7Xm!=elQ888=n;EtBnCS2REEcB}Xi
zy-#Np|C^XbCVb^xv$OQvtZv1PD|+~xg1W-l9#$4wE(vIAF3i)IawawPivRs^q5GlL
zIdk(KdwgVGxb92tl=9cd(s?rKf6A0cb+&L{Q!03_H{<33*?lVvPPHVeF7u5(y)1Xm
z?o8RA4LLhJ=FjGf(6IYjS?YPDtMRZWN8sDwz3;cZNR14d)+!MD{Y=_)gYz{uEnik1
z3m4Y3IdAT=Xky!ylIdkFRkQDxEZ@UuzL8P;d6Gl@&u_8otgHSm`CuFJVaaUH^)%s_KVBXFSNP-g;l@IiSBDQ4vb^?p-c>(eL;Hh`RPz!3OFwF)vNQTs76`{S
z{60GCh2uegCM#vzea##j=5hVhajN~wzd)(GGF|ceT(_m$gEq~G-`mipBQ|eYx><
zn|9>zyq4ayLhf+ZErC5RWp!p9cxo-BzM+CgaaNY!yhB2>)}K)F`Qlw|yYT9Fr%&?j
z_pf_p|7V$2TCXdA_{17Do%u!!kIH|0?$XH_GgEo(zAlciv_ezC)WFxWafcrr{%2e<
zjX!a}`rBLg_8b+CxcF$EUGxG~0lqm0OPP{0p00n*YOC+8dr(MKFi41R((HMrmaY#U
zu)M13|6gvTZaKlVR*ZK||G$?T49f!^u8ggeX^&!3U9?!`(&h>Et>NoGP1|>;sC42X
zrfsG(4H%EhChg*~g~Gv2fnJ
ztNqCyHk`44gbzPrnxwakU2*cVRFztD#UCtJugI;^vp<=qpu3i1(vs+l-rHCuu3Elv
zKa%`nad2Z`A^+8DYmZd>-0A)MWGcUZXVxADc8^n)Cc7pvTX@89U93)T*AUXGf4iow
zhVi#bi%N-oFY9OX$+3MC3;#Rgb6~neTRcL(8)I#Q*yRRkbpXJX3dU4vp3@;avYl
zp!Bpr$l=H}_L1AFMEezt)l+!mfOrf>jS)*
zS-2P&I5-#>7#tbaJa}-tmWhEul8u2uck*&4+xojq*Yf{3t-K_ba=KlGCD8e5LeLkc
z%PjAgoemJ&rh7B@YW)*l@mU@wvnpP;+MlXOE6em=xzP8radFx6+H=)qY2VM^m*3Bz
zlW@~PrcyFZNF*(_LgTWfEUV=?X^#ZQ<4VneUw`yzn@O1-G>E$O{Qb_SCTphmX@|W$
zq*s1tnz~ti>-*1IYdzStW8&6FMf;v#8J;;+Ze5Z={MEl|<#!*=+rS?ZB_4P2=|26M
zwykd>OV?fbuqrI!(60v{4?91MR8+m}yVxpf<3?xKV_tr-d-ASo9jZR9y{_o$hMm#R
z<|%*vuqe*jaP4p1+sj%KRjYR$PF!_d-nw-8&z8hh?3b3WG@4nT`_3|?a0XY~
z-&iHJE6zH*H`ycCbZ6~`ll+I5@vO5tc}ARzXYwf>GD&
z!mSGnE~{%)UYho5^<2%#$HEprz3DXVt;_~XPQyahaNnLsO`O7-!fcb&@*Yj=Q*C?6
zC_8gU+iN46B#HMG)xkH#%jzd5KKd`Q)ic%SlJwLC;`&WnN*p$C+2WksR8+)nwQ!2A
z<6_B#KQ1-1pYC`3za~Un^Vn0_ZC&0b=FOoy)=0GFY?4cI)THS?vANzh-D?RTF_OiKq?@gYewZF`p
z;;^GK$F9D+tlq7#CGbB3QkoQCaAXKO)6%(5lz~B9pMgPPvY?ghlVeK9j{gW?rUY?Qm+_KjDXjHa%b|&|=sOetfQ3tQF
z^l)XpzE*p6TiN!t+qQ14-kP!R|IYk0BTu%*e|Gg1?`Kz^xBag3zxdrwbN~JS4jgs~
zc|2>)WjQKN_R!
z+k4KtVx?dCXQRw%*?XLpc*ZVf~dI*Upz(*&bPKQa9Nz{bSZ#xo6xdPtJY{)sN3M
z$-AI=BGqdBQ@6QN6?6aW37GZul8Nu4{s%|^{;P%p;F0*0}9iOsPw(i}O
ziF&=dy}SS3dHg(1lH=u;HvOs3jONyzPwZ8ea(`;P?6T{f<(Jv&+K&~^HRJrwJLkh@
zUHeIwOfqYB`rWSBe(bLm{|C`aF)M>-_v{H?J~!ss^K#Gn|9P3SO7?ZF|MuC`D*p8Q
zlaF6l^sgw{JO94+UtXmPzfJZ9E|1%orN6&k$oRg>S$30u3;YECP00A1`16+P74z&r
zg1z|{H5IuZ{RxcR8lGXdY_oUGMeVb4|8^Xk|KYRU+;va7Q}t)m?fAx+<$_*raFSg{?w;kr)8}>Z)Rr-}K^OmzNhrA3}ubHh|egE2?uama=u8rPq
zvi9b-t(n26RcF86zApV#{=O@F?yTXOeR1BZFl)K4Z&wU`^Ex>9uh@H+M_t$c{>dlY
z$E&K=SX`d-EMm{{RqA89t;p53|m(R9gm>&MeFqqChk>t|=C`tjbHBggla@2kq=WwKqauf1fJ
zwiE%t_;+$)b$?{hyITo!4sy|QWbw%kl6Pe(J)?DdhGb1Jiq
z4w=~MtXh9|)|DT6Jm&rKX;D>P+WIp#a9L+>`g|+EM)}H$b8WY3+*kP59iDce^Q!u3
zA*uVk+Y{el(alVX5v~`ndJvL)0WRQ
zIn1S1*%@JUFLPzXjFhk6BkSjGySg;(Pa^x|0Mi-L{x?@uv+63$-Bql!((V3nwY3Z9
zt;ke=e52;0W`*wtwuVU?-W;n-I4{PWx9!oy03}7i1__z-yj{Ckx;Gm?=3B95o$j=o
zPgO3r+!gh{CAnwS+UrLj30~eN+Nj?1gx#)I*5gU!u{$#To>6g=d0J)t?i@Esu2*V2
z6OnuC{Y^vEMwf2Q1E*haIy7y`?Fzo%4FTRNS3fdoems5uCU@y0u?E}Z^mR55+3uKD
zN$UBzt>%nVB`Vfv)z(Q*MaOJ+VwdT>3{=R{ENJ1?}xdp?$xUte-zKTPQ43
zuqFE7{d!rk<*%199d0_>EpGhviOrnL>OcRdSCxL%pSCP&)~rCyXGQKRa%+Ui8rFM?MvAC1Pv#>C~Oh)Ums~`QX+4DJ9dV
zZt}h>sjO(t=;O6>EEyUcI^LMK{}BCwbEsX@^)}c(dI<-Ogio=6mL!
z)Sn+ko8LcoY;La*2z@WTU~kk6S;HS1_6(w%OkJX~V&mf*gU&uktP|L&S#74>agcG>
zC+9yK4j%up<6!>>$7cEZr^hEK6^r{x)n9$E{^Mgd`-A>ce?;tc&tB*K$96ycgZWF>
zWwGK~mCZMg`W6HRCIxQLPE&2VI78N@H+S~Jj0-({4LW^I3Tlztjc&|X#n)7(bE9{&
zddAnq6FB%;RvVWvPxa_td?@$T4w1ub_1*h(Ka~I2%~sz(Kc(unXRF8Cx%CIcHYPl&
zpM2oK`_KF){}vv!f0RDMY)({i;ao}aWs-NBEyEf=Z~l|q%y&tg_aEo~D-WJ01iibf
z*BZ4Vc&_xpi1Kwy59SGnnGPzS*!Q--UA$KBVrT#PvAYMHOy-BkNgqF(G4v*Qaxg=$NIwH}UJj7<5P*_Nhpw+RJU
z>s@O;y*tJ8LXY#75IL4zSISmCJ@~Fdhw1l?k10+z52y4`T@+!kTZMnoqBXo?s$Gj-
zwn$B>idZ)1VUNCb@YLM3pSW(Yybi6jN<8#n{>R!CC)_@6Rh8W8ET|o9>3QL=OzD}7
zZ)^MOkDq1qJjnLHDbD1_^gr6o^}6x<8<}6Sc5?1j7V$m0(V#-E^z_NBeTFam?kDe=
zyLX~Qm&y08)YClwbdz{v>e4^F|H;}MFLL1gsn~8K)*_jE=jI%&e_+qG*xvK=C5fd*
zTUQ;d7wfJ#GEXSA-g9#AT1(!#$P>@@7v5a?F`oCI^#A(159&SM>CBmt9Hgd^+o5_m
zR;wsrhBDjbsg)b@x0vvk9e=dd@udC#D?j4d{zuC!J}NXd=tssM`R4e<{$uN<{>0lQ
ze#rh~wXED)bnQW9J)@X6MGHkvMedONvg&m14x54{r(b_ss%x__$~b1$5qjKrvtS)$_WL|$fk
zO0QU$eeTafrCz#6~ke+z6HCt@?+Pxod$qOqdhq@&E~@Tg5kT%X0p{;Er@G4EE#sSy23XW3}kE
zRR4{0ZG_Kg=FRY!Um2opzxH%y+nxO5mx?kLx+E_-f2{Z3^|j~ZO5JB4$a(I<{anPp
z*t&kjwA%+~7j>2XGWYaXDq&sox=md@Lg(@Gn8f{RVw(k-((b!Wsad;Ca{E!{;H4XK
z%q9m;k^ji6=JxD)-A1Y2Nj-L^D{sHH_;mUD(e%B{Q~i_fa68hl$#u4qH^StQr@=3Zt>@~+)X>-*4lj7;b>Zzn*JHDfaLfY>Cfxf
zCjL$9@mm_lka|Tw@b;Q{Kf~q)>l&@66`+OF^mMX5+k#p|2TUee0O~(`@-Vu1u!q52k*0nrFX#Yudke
z(@X=GPYNl{G2gUx=83A$r8-Strl5O;_{qhO0|fT+Lrz*SEb+%{IfJ?emvs-7(MVZQirH6&gPj
zT&orR)Np;XI`fKk0rNAsJ##9`AFFJ9A#=-F)#b@jhQ0lHD$Bk{`_=I(e_{V3eTKJjza(z;KfZqT!2`$r3radZd9{1ypPz3scb<&W-dLZ$EHuNuS97Hfc@$nk6$scqOwk>~t4?&d_{&*k|S8$=@!ob$R8T
zlJr$IXy=vbC!QXAq5jgWr^CeEL!I~Ut4)rxb_t%{GVRj(3nDc>>%X$tG*5|tJvGm5
zE&t=m%=;2&-Hem^z`EyYs;F~_fyd^);D-wfi`F&tJ#Q}7Oy#AXYSB}iG&9_dsW%zYh?@a$?QgtEzweE)hg^DH-4&jwAy{m*yrFkMXTl4UdO%D
z{=jO(f8Vov`DKp-!4IN8y;Cm9TPt>f?WN86<(WYTtaCpq=w@(Nq^?-;)=FMp;^(xS
z?H>eM=5QU3VPMo>P<3_p)SKIwRb0%jcr_)NFSyJv&VS)%39IfR?Ui%xb(V%7o^UeVY9b+&ukqh45LG1nVdzo>e(_1VpUUz$T;n}!fTs*xJ%*%gg2Ar(3yK-RpScs~`ffO{
z$8y1L>H0|q$(!?7gTvzc4{p;dxLNNSzjXbm-|Hf{U1YVD}ojiG^?uUY$O-(tR}X!ZZbL!MVMzV91c$}g(yl4kraY4KjJ=YIE<
zqI!OT@)_3{Sbv8s_!Z(&&m2|hxVLFvr@p5ZujE_l7tvaVr>3*4^scRqX8qi(Rr;y^
zpuz3C_ZPljW+LOLKXG^Bj4-8ZS*ns(-!2Y)5w_LgwW{c&L+#V86(b((oqTTMht-8n
z?|pxt(BRK-&)nKQXTtBwpB2;j8vhH<_^BaM+mOawzvZexwyG`5%r-&4{$^xydiae}+CL@ekgf
z^J)0euGRUEG=1O1yQ!&PROf>G#hRZ&|qLZawjAcEank
z8y4nIxOXY;b^RPJ=BR&S>P}4mt~qAqI){k}=jU2F6w7YA{ju}&Lyoo|bEpI{Ys{O1h4>vyKn^oWXtuW#@=Z*K8
zvlzFCGh}!(Y>aZq;#Ii9w&YEdx?Z#Xx~7%iE)+lb!n5G3j^Fm@2i_j%xIF)Wy*=xK
zdNzgsGXMT8{gfg9;8t7l=i@V`PtayMTYO{f^k8%52kg-^wFTYFV7+UuWHVi_`j|Pvn-Ke!{WwiT0TQYo*SO
z8}`ODDOI&31+2fOZvSh7zlz#D#xM4^K7}oQi)1=7cS_bmWYGj|E*G!)?ahCqzFdDKu-|O*>TL?o
zPZZ8{|L?l4inpHgXQ`Icp@_ycg^asbOuV~gUhS6VzgNy$napwt{NnlLZ_b6OHm&O(
ztt`>~C4FK4{NFM$Pp|V?6_+7om|woW7)hd*E6&pc_-KPp1ZEW6jR@y@cB)^1kZH0
z=Aa)o|Kv|qPmNjSaY9D$w#W464@7)!D=y(Ml0W`U^moQLgV>w%{`;wiPd#O5?(*I$
ztV*N#h~}him3o;r{m(w#JjK&?xKZ_hXXk4%q1bsH!M9^LWm{M5Dw%L^?|iYT&*Duz
z!rvd?_VfCR{-#TRvIUEOpVT;8U(av%ZQ?Ua2f6PVJS&W5oM*nxYSP@j;kT1Tp`h-u
z8!JSvMh5*j5&Nvp_)w7Cnqc=wxf>c=QZJTBT)Q8{rgJto{@u>0%cg{{X!^Q~Sy^B4
z$1~-N-{j@CS4#feF=<(`sM&hQom*SPK3rO}XsO2Ihe`{ccL=TEkf?GM)%BbBqK%Wg
zzHw!B@I2EKrA}SDlhs!=xX(2?dwz1G+3~902-W3F!=l=Zj@nn5epspNHHE{mo#jJ`
z%LRrY_7o}q>AN^}K3BSRrHWR~{CtXW^6Z7l0qYM7bf*_N_8r}KIohV1JGeVLSn~Sv
ztP6Km&t-Xi`o*K-62|#AWlkJDUi^XQ=bWR(K^>_#c$&Q{ekI1l?7!1qTvVjj{EtW7
z-omnUru?@`tG62Bo5nsuBgkJztOMc>Ah#Yb2VWD@YWj5l?#3_Y1MdB21dReucDN(8IUtI$5xOcO?6$WI${Ym)
z0xW6lcA8wMBRYAnlhoulw*|Nm)=Z05O1!DE5RKF_3>9&Q2)bwBf9lHN9X;Yy{+-=7&Um7bW~cwT9;_j3cLrVEoB&+AQ&
gc_1)(_j4(xWtS&kf1buvb#=1+3vV{x>!5H30K|+;4gdfE
delta 8722
zcmZ2`nR&uR<_#=Xtd=<A22h#!CTC;u*7}a*FjIYPB48
zax%;nQc!GRSu*zx-)zOr#;@P#G*$)Vu65u0dTQ1D2-l@Ia-1$6`|XguH~(VTT6f#m
z^5248YxC30Z{F3>G@O6_-?{R?_kQpD{@eH5-{%Y48P^=Lf0oFslQ-$ko(a;kXN#Ek
z_0)?kQI(k}c&MXgu~EvB%Ay|k?d>0w-o>BM)_?eH=^dHp&-f%c_xQM($DKPn_j7@G
z+`+}WQ}+n1Pnr~dx`Ou|=fkZ&zjg`4o!@j%;c;(;@cKPFWxhYs_4yGtZ{J#(z&(3q
z4EHq8z9{hS@ze5C72@}FlP9e8cwl>HPxztVP8IbW^7R}Kn-yz3+=T7UNXsW?s;kt5
z9J9Kkf0@%>?crk~Kd&Dx4o3yAMkGcAUX{2o+5Baj+J*&>H&nUwz6fi1F3oysrrNUQ
zbIk6FMNFA}^H;*Hi@KYyn=PB+bGGwK*>>T}sXk&`&p21v^Q%=`Usqk?Z1nPz}n@J$v?Ta5mq%t|Td7
z^Y<0aGVQ1M_)f=Ny;eCd_RD8Y)+uF|RX(=O^2#*Xn>B6nnv7-6zdeQOT~{tzw#{Nk
z*Sm>Z`7$pia?USF^|2?+F=V!BlGHRQd|%irp)^hCZzss}?`
z*I7?Hvvd8fj|>rE`oTa=w5D(N`Omk+Ke)2SADS*&
z!x}&JgDGqLaZA?w2h3G%7Cnfr2syajQ1hWR*S_xeoGh~@t$M5R!>-Q3?J0x9uGNtb
z`BndT9PFR@TK&h$mid}LEbA6Nu&G=5AiToo;Nu_lTbu50_;+8)Z${>2p0kN%hvX~o
zZ0eu5K>dR?=l<{y?0*6ePW~~u$^NmvOAOPDmK9;zxkpy{o?huUd;9B?SzZgWjxX{v
z;cVGuYMMGzSLN&ang{zIzUP{EXvu*~neR)N`?~vQ1UuafFKL8|s@j?Q$9fJ-
z-Q48%;Fq`0#h45Ao0oQ4(ld=QnO`jGQqq)#5D|^-BXX_5M
zO`5tbrFTx?{2J33mFLGz)2E+W{_T^)qRQ#BE_7`!_+^%GQ*G+RW3z-(%Z~+#Jv$;%
zq?7OY;MT05)crf^roUdfP3A&O@ya~buT#>WJ8dd{op8$NQr|Z3(zX-zhFK=7mcCdN
zR$>O&BX<~UV^h~tXw565Z$uryE%uCjEU%dLx@|$J<
zST}b2J-hJJ#B^f%*Q{%MD$mX0R@}Ivh0iHyQaani%0kU00S(QDdKw~UQdO_`-wzkM
zAG&v&-}XY^hs+DN{m7kSeQj2HX-54^iSme#JGieg6{PFWxOqT!-wK1Smc*mWeWOn=
z%bm45^Q~oj&K{4sv&$kh%uM&}I+5IZ;Gsf`#&^y8-y^uKSetXfOAceyAF9
zdAc9>2|E^Ttsj~!0sB>NUv56}_NDKWZ(nqZs;kT|nlI|Fv;I)?C~x^ihEocG^|7&k
zC0t?;OPqQob^O6%&5BtmkGwCa{8={kXsy>Gm%S^?}nKre!rB;a_t^_e$7BDNhIX
zT@2+%X1#Dc=+AUZ*>+#FV1jMxr^uFHujO1K**>3hdMEF`(>&N{M*Pl(Sv+EWmv>JO
ztCfr~>-zdtGNfd%E7;&}KE~>E%8dAKU*%1|~6ur+I3xS86)OvrcUhJv=vm$##%>TMEdp4jX9!tNVwd>dtBA1Rb|vwWMhEH81f`<;H17Mm2aq@
zTO4oG$oNs@TX+4Vh8+#ju|D!mKEI|Xntu~$@(=R+I;qV5b^|OWppbQ
z`)&HD@XO_O2Re34FUq$6C@22?0Yl`Q!MR3yi{?g>LCv&f?F-}03GSJZF0
z#PgHsnFjb(MZEd@%$zN{vf4v-mj>=~CoK_(lr(V)~
zw^UXsPpYZNqWSA`ue9}#1XKJCRNHPTPLDgDxLv;O;XBoYMU&m8ZrR3oFW!9ZH-~@n
z0p83kTnr2x91IK$jttG|8B=SR7#Jkk7#Jomb+VJo;l9Q%BGMJ2$$InCLe9XRiAOSm
zzA#;8dB5!TLLHq+&LZ`{J$Z9y&6~N|`hD@e&BnXy|NZ;HnjqWHb7bQ5L`%m+*EV*e
z*sFmP9?xoIxmKEEAQ9Rh9`kWiosvY*QRRR0qW$hxJ>2ogFxKKh-|a6))_tgrTPpf8
zq4jijX!iPtmRq&fUOF7g^KA93`w!ObF4lOHJoQ@3_Qyr{#qAE4y<1eZGNS(bs<4DZ
zzaD(N9Q-g+QT4X(Vyjzzd!1a>y8L|i3(K9`8(d
z)b2U$e|QI=akCdy7X68
z`l%%w!}F`QO-Qw7&k1$%xpQDjr^vb)1`|yZ6YdoHn$qg1ul!eU;z1!M(Cd=mM
zpK?ExXW;W+ezDog7M{I!mjqV;uG;t4f&!B061iObprc66R#b3SC38Yrc{;!i}~PnoE?r!p7y
zbA4ucHJo)yF80{K6Oq)l
z{~LM5(hKt&EUf1IsH;A1{pfv1jGCX;$E51byN|vxD%^11Qgph(%Ch-(kt_>)f3c&c
zz___Oj~9wCFgWWnFepqGw340N?aEiLzIo5d4>yz)d1fmMo$$Ib-C?6AhY(Mr&@{HF
zud0=vZfT#-N>9Gv8ZA0~+qG+#x?*$IPTjUhbSjIl>)NYP+pp!7UAhrFAw960@?bf<~-
zl1R(GzK^RIu4nCuT6Ue~rR*Oy$r$MepO@4ZPk6n-b7=
z^|ufA3cr}wwVS-Z@*~!<>tkBxJ>8b+*)^@l-g8b;-7@`Cb?U*Xi{6Af{@T4`q5G`;
zpRY>2zx+c=ZLj9MO}!ag79M|dV{zQ$Wmg4EgEWngibP%Cu`jRs^S175^`=|%Zr=*o
zUmJb-*|hF$S8{J32)R?z(bx87Gp
zZsT>M*obddReSfTEf?Ee!#;Vt;>AoO-<-Z9XQ!2{xw~bX7&=bS?YbunQ}MZ%0r3wq;NL_C-FzGT#a>ue-T#E2qlQpDJr@k3C8~9evqw*~!4b
z+Sq$bj$KdOQTfH-@}=OY%6BtDZ$wU>d);--oPfhtud_bKPF%9*@U#P+GpD3#_O5S_
zHn=&l@6et~rt_N8CzsyQt(w5uF}q>yx03Mb2R0>?+fH6yfBeni3YL9ugQUfd2&in9
zVbk2Koa_4L-z;AT^#wciF6A!E`S7WPlc%eAx7pFjnbOuX-Fz0U-7A03Jg0f3z#Cc4
z8OwSnu8Q+i>dV{O+h;qwXUUN43gIH~*x`*F4Ja)Ni;fW)@$;
z6_>n*alsOw-5dFDY(Cl$?V~N`xm1Nopn365$BRq{A8om_gIQ~H@#@SHtCJ?FrJHc4M2;2e*lT4yfPkbD5WZMmNmqQctMH($@~)4FRNRxG{rs-kg91$W682iems8_wT)J5AlDVYl1Lk@=kBo~WoFJf>FH-Q)+jZtnPijJ`?2KA
znWgn*{X(a2XP)}G=$=h__0#eW`YpU(cdvU0AGYii|Mfw=ms>4&nfe|R)?(+}O{8-Ms*
zE_S>>>0xZxNxjwQB{+W?TIe0lx_HPqOni0o+E)<;Oq$W#^aYIO&RdvX`iu8(*z)$5
zf^+M<^k09muw8gLv}CK_`=#2YQVSgCu6xd({McBlH1(pdRjl{*ms|SRUHqYJ_5OMP
zt3QVOA|EqKop^Kv~{WPwT
zHgf%!6DQEjT=Mk%r?*!1eeW;)RH%=5e*UxggbjDH#e4U!_&m49|PHV)f^qv^+V$
z`taBpM%it`5A~M(-*B^iv&}8}xG9TY$2VL`iP&-W?ev6*=f8h;oMX0G@i}nc?3ZuV
zMU^&}b49Bh+GwuUc#i)=vlRc!KdE&cnU7bRid~nSW^neUTv;URx#K?)=h``MfBA>Q
ze%0sjgrIjf6}JX0aZdeMu;_Gd=8n@1#r4+bHG8KYyUmanK5NEB`FDnT#)sc7ljOhc
zrlUF4d53w@cO8x1)&5-CV%w^Dq&!|C
z6P?sxi%CtlrbY1Uy`Q3*c(^HJrVU5Q%C|Kx+r?4${&4XxSN*;Sj}1U
zMym1Mo8>L*7pqTmnENDhW6sQT{>s-5Je8a~|LOCRe{BqP^{c8aPlyy*?wM;jcmK)r
z+>7%)Kfe|9dV0!r?tW#lk6pH^r}oWOm5%)O@{g_J?7zRJ&OfIA;!o|r#&h;l?nD}y
z9Z&HIxH!SX-8%Hi0y8(BwC=|RMLVqc%2n6g+VEt)eCD6zx%EnY7ll@`7EbAuI?Sm5
z(ciQ#^7;Ia=S%;wE
zw>+PRtA70(c*mxAi?CV02GjDV%OC#H-1vX~5!w1{FXg}Z&;5U>oS{|S|DVri|IK_(
zYv<0Lmf$vb=Z`b{A8fV@Uw5iJ-0hGQ`dbL
zd>DLl?#o5SJFTmn#SL8-9|@BWwEWtZpW3wG^xcy&U)#91P7JfoeR@aRWBb^LCy7
z^z3CNn=Wry`t48yvt_)y$;3k)`;CPK?`?u8e*FU{dr4{Fy+aY$T>fk$+*`2+V$hCcVNFqpLX%arFZHqrpx)2
zt;+USU6gryN`?GZ75lg|cIuDCPx)T2dj2oVNWsFb*CQ)-+qU{v+g?9~S9gNr&62u3
z1(qG`P=B<-cX6Ld@adSm$PkkyM=mMl?OWWoe#(|O<)p>$4kRu}GS;6w{fX*|iQ(%n
z-_ci3*}u7Mxlwqsk<^40xnbYqv(IsyOwPNg;+l6V&hpvS9E+vW3UXj5vN*74Df)!uNJ*kQ
zgD=`&9F`Ew>!v@$>b=lcgr~|X2iVatz=)Z;+p#1$gOof{ro@MGrXc*
zPso1?4GrTD`pDp0+v4?3QZ?POWDUb}trJnc#uUB{sRA|EWWc#{2!k5-=4HpT-(0a^oLCOmxsR%
z#15SKw*?(i{y$vBXtn#Awade8j#kUBJ+F^^r~j>e&+)v)t&?B6
zoQQrC|LNUgljULDnam~YzF#)cdop`VLBq3mJU>%blspfuv#WSyc{A^xtw52|+9jVA
z9#n=buj)6t&8Ovdn|13hM?uCCy~ghE7jB9y{VCF{_&6f{qLf$SRM*}Y<^i*!R!lDo
zlHVF^ugZ9#u8N)Er`~~e_55o4oM!IfR?}tjvGd-3*h2BcADO$1!D=6C1lq1;i0dvs
zpBxsm-TwKkzh77-q!L>v>R+1c^{uv~<6YAk-4eUIyn1nO_D$R8^1WexL#bw_`hjcf
zFUIwHnd}N*{5xXt@6NczH(#4t3H{LbJ+|8|(a!I)NmfPgvHpUm47_OzDw*nSYL)6)
zZC+%rtZR5?EW1F{HT7Qmialq8uU1Xb>I-^mJ7cBOvz?;BR~Ik0;lI$t#N@(y)_vu(
zY=tO`E)O-ayNgo<;?FF0+7j;kzV^ZoDV95>43EBUk=p$H@S@p?{oR62<{GtATP$an
zYR=eHWyN({tl{+0FATOEv*+@k=1;ulT_1mJ&pI9LV*W(G9P^1b$2Hen-1zc%rrsL!
zLpuD8kNd6TJ&VoWBZ(ga?{>bZ76qDzwNuZ=tKh>q~Q8Pn#@FNX?!t&U`xhcFonb
zxejYJVqQxx63tb-udue}M*&}b-?`r#?;g*PY0Bf`kzEumk~M8XJm;A!%*y5~CVYKt
z>(O8DWG}xW{6hE#m6yvE)7#mqe3p7tPAbq1@Q)8otc_3&{AVulEc=Ir?Zo1m#;%9G
z&Re(w!?iOrzcNNO=lODPi3`#_XS3}N=dq;wxg~upkCN0m?w2%tSvBDs!&+Sh^&fF-
zq~6}KKKNgNr%qgC@9bra2f7&^h6=2eJ1@;}Xic$r{lyefHYttim#)9?)L=MS)RlL}
z!lq&Bqi0QXisw#jH&EgVpY)t%(u`@mJ;_qFvh_T|XT=s&7YUy_I>~STvH$5WBA?%A
zVEpU#<#<8PobrY}?d>a;tljkDY;(x=&gixk`_BFsFx^twb?xA5*WM47G5hzGPB>To
z=?B}B!Y2!sF>k4>?=aiOdyzHw(>)uH*=#G9idEJc=j>%Q`@(-A`c@XRe}Jcl_N`Y(
zyfiLYIjpswD1Y?G?I^xWKJ9P$Y#uGK@XD86U?zD(RgUZNnhR|i<`(&&3^F3gz1aqk0-MqeA8+8BXh1d|3OTJ+=0JhVRi16CY(Fo9m)J6
z^GxN3m*an%veyeE7wnR$)?2vtOKw2*#`~;aVt>ii6x(LRFL90fM-;FYC
za>0qcO=1$i7BW>E27FyCb3ERUE^V3De
z<+kId;u?vZdMEv~t`509o<6?%MtwoQ_g*n{n0t1r>obN@(K~*2?-kE4jL8w#ER1h>
zalgH?o?*v-56R?JhZPsM`3b*J72T{<)G%S*@=g}kPrtp=t}ixdd9qt{s@55?1@*7*
zJ&Ckl&2{{tr6|{g(9L4Z6Puq*UHnz-Qzc*QQ%8<{ESHuZRyrH_@vo51|KOZIMoF*J
zKO8+jF|EFF@w?P0pZ%v@6Es)UwOQ)3%vs&1$$#w(^Hcq)Oxi_t5sv$V>I7JiO@3}~
z;`A#>?f?G1us?AxCNYd_
z!oR*c{_5C{N1yn=aQ(3rbo{LKH!$(Vu{kUAkDNPaS+4vy(s7@F`qOxYcJ=8DbEp1q
zpZaLR)g^!1)s(K7{JLEjwIuKji4Y!{amCp5E)f+_EYw^!!(On~z)#=F&Hpm;YE3tg2P^p?HGY
zXNy@Ug#&thmh80AeD9-w_GMJpt*3fRvo+uR>aw~#SLzhA$FvLkLt{%LGGhy3vgZHp
z4>siIw$)^a|Dq8xUzUT{%p$fGxWJmKf+wjSkCb-JP0cw0u$#Nxc+b~U{tU3X4e
zY98PTw_=QHj$2VPss3){Yre+AQr)(1N+aLc?>%bwEnVz-n$V7t=e9gPpZT1Wy+pDsWD|On#1(q$rN42Wj;7h*7Uvhv+H
zCZi~@OhYu!!eL(L5-VeRBML3#Nkd$usZ!GhHa3{OW!vlVrtY#|PF-9u<=tD~%^#
zcqlOW-~%b9%T<#bDiNkNPbf`3Z~+n^H(p3FbzYkM
Date: Mon, 5 Dec 2022 15:45:07 +0100
Subject: [PATCH 158/164] Fix a typo in excuse message subject (#2071)
---
.../wulkanowy/ui/modules/message/send/SendMessagePresenter.kt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt
index 5ab8f8fc9..e776e9941 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt
+++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt
@@ -55,7 +55,7 @@ class SendMessagePresenter @Inject constructor(
view.showMessageBackupDialog()
}
reason?.let {
- setSubject("Usprawiedliwenie")
+ setSubject("Usprawiedliwienie")
setContent(it)
}
message?.let {
From c34c63c128d50e6ef2ffecbf234c125e2f042289 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Tue, 20 Dec 2022 16:06:55 +0100
Subject: [PATCH 159/164] Add support for new ADFS light instances (#2084)
* Update known symbols
* Update resman host details
* Add adfslight from tomaszowmazowiecki
* Bump sdk to 1.8.2-SNAPSHOT
* Add migration 54 with tests
* Close db in migration tests
* Run tests workflow on every pull request
---
.github/workflows/test.yml | 1 -
app/build.gradle | 2 +-
.../54.json | 2439 +++++++++++++++++
.../github/wulkanowy/data/db/AppDatabase.kt | 3 +-
.../data/db/migrations/Migration54.kt | 26 +
app/src/main/res/values/api_hosts.xml | 9 +-
app/src/main/res/values/api_symbols.xml | 666 ++++-
.../db/migrations/AbstractMigrationTest.kt | 7 +-
.../data/db/migrations/Migration12Test.kt | 9 +-
.../data/db/migrations/Migration13Test.kt | 5 +
.../data/db/migrations/Migration27Test.kt | 12 +-
.../data/db/migrations/Migration35Test.kt | 4 +-
.../data/db/migrations/Migration54Test.kt | 130 +
build.gradle | 1 +
14 files changed, 3150 insertions(+), 164 deletions(-)
create mode 100644 app/schemas/io.github.wulkanowy.data.db.AppDatabase/54.json
create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration54.kt
create mode 100644 app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration54Test.kt
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 3def08953..13875078a 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -5,7 +5,6 @@ on:
branches: [ master, develop ]
tags: [ '*' ]
pull_request:
- branches: [ master, develop ]
jobs:
diff --git a/app/build.gradle b/app/build.gradle
index fdb844aca..b0865896e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -186,7 +186,7 @@ ext {
}
dependencies {
- implementation "io.github.wulkanowy:sdk:1.8.1"
+ implementation "io.github.wulkanowy:sdk:1.8.2-SNAPSHOT"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/54.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/54.json
new file mode 100644
index 000000000..7b41672b9
--- /dev/null
+++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/54.json
@@ -0,0 +1,2439 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 54,
+ "identityHash": "1dc96a366125ec9f8567da87cdc9c863",
+ "entities": [
+ {
+ "tableName": "Students",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`scrapper_base_url` TEXT NOT NULL, `mobile_base_url` TEXT NOT NULL, `login_type` TEXT NOT NULL, `login_mode` TEXT NOT NULL, `certificate_key` TEXT NOT NULL, `private_key` TEXT NOT NULL, `is_parent` INTEGER NOT NULL, `email` TEXT NOT NULL, `password` TEXT NOT NULL, `symbol` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `user_login_id` INTEGER NOT NULL, `user_name` TEXT NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_short` TEXT NOT NULL, `school_name` TEXT NOT NULL, `class_name` TEXT NOT NULL, `class_id` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `registration_date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `nick` TEXT NOT NULL, `avatar_color` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "scrapperBaseUrl",
+ "columnName": "scrapper_base_url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mobileBaseUrl",
+ "columnName": "mobile_base_url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginType",
+ "columnName": "login_type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginMode",
+ "columnName": "login_mode",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "certificateKey",
+ "columnName": "certificate_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "privateKey",
+ "columnName": "private_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isParent",
+ "columnName": "is_parent",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "password",
+ "columnName": "password",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "symbol",
+ "columnName": "symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "user_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentName",
+ "columnName": "student_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolSymbol",
+ "columnName": "school_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolShortName",
+ "columnName": "school_short",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolName",
+ "columnName": "school_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "className",
+ "columnName": "class_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isCurrent",
+ "columnName": "is_current",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registrationDate",
+ "columnName": "registration_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "nick",
+ "columnName": "nick",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "avatarColor",
+ "columnName": "avatar_color",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_Students_email_symbol_student_id_school_id_class_id",
+ "unique": true,
+ "columnNames": [
+ "email",
+ "symbol",
+ "student_id",
+ "school_id",
+ "class_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Students_email_symbol_student_id_school_id_class_id` ON `${TABLE_NAME}` (`email`, `symbol`, `student_id`, `school_id`, `class_id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Semesters",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `kindergarten_diary_id` INTEGER NOT NULL DEFAULT 0, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "kindergartenDiaryId",
+ "columnName": "kindergarten_diary_id",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ },
+ {
+ "fieldPath": "diaryName",
+ "columnName": "diary_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolYear",
+ "columnName": "school_year",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterName",
+ "columnName": "semester_name",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unitId",
+ "columnName": "unit_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "current",
+ "columnName": "is_current",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id",
+ "unique": true,
+ "columnNames": [
+ "student_id",
+ "diary_id",
+ "kindergarten_diary_id",
+ "semester_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id` ON `${TABLE_NAME}` (`student_id`, `diary_id`, `kindergarten_diary_id`, `semester_id`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Exams",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `group` TEXT NOT NULL, `type` TEXT NOT NULL, `description` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entryDate",
+ "columnName": "entry_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "group",
+ "columnName": "group",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Timetable",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `number` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `subjectOld` TEXT NOT NULL, `group` TEXT NOT NULL, `room` TEXT NOT NULL, `roomOld` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacherOld` TEXT NOT NULL, `info` TEXT NOT NULL, `student_plan` INTEGER NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectOld",
+ "columnName": "subjectOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "group",
+ "columnName": "group",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "room",
+ "columnName": "room",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "roomOld",
+ "columnName": "roomOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherOld",
+ "columnName": "teacherOld",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "info",
+ "columnName": "info",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isStudentPlan",
+ "columnName": "student_plan",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "changes",
+ "columnName": "changes",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "canceled",
+ "columnName": "canceled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Attendance",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `time_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `excused` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `excusable` INTEGER NOT NULL, `excuse_status` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "timeId",
+ "columnName": "time_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presence",
+ "columnName": "presence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "exemption",
+ "columnName": "exemption",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lateness",
+ "columnName": "lateness",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excused",
+ "columnName": "excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deleted",
+ "columnName": "deleted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excusable",
+ "columnName": "excusable",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "excuseStatus",
+ "columnName": "excuse_status",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AttendanceSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `subject_id` INTEGER NOT NULL, `month` INTEGER NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `absence_excused` INTEGER NOT NULL, `absence_for_school_reasons` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `lateness_excused` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subject_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "month",
+ "columnName": "month",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presence",
+ "columnName": "presence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absenceExcused",
+ "columnName": "absence_excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absenceForSchoolReasons",
+ "columnName": "absence_for_school_reasons",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lateness",
+ "columnName": "lateness",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "latenessExcused",
+ "columnName": "lateness_excused",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "exemption",
+ "columnName": "exemption",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Grades",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `entry` TEXT NOT NULL, `value` REAL NOT NULL, `modifier` REAL NOT NULL, `comment` TEXT NOT NULL, `color` TEXT NOT NULL, `grade_symbol` TEXT NOT NULL, `description` TEXT NOT NULL, `weight` TEXT NOT NULL, `weightValue` REAL NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entry",
+ "columnName": "entry",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "modifier",
+ "columnName": "modifier",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "color",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gradeSymbol",
+ "columnName": "grade_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weightValue",
+ "columnName": "weightValue",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isRead",
+ "columnName": "is_read",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesSummary",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `position` INTEGER NOT NULL, `subject` TEXT NOT NULL, `predicted_grade` TEXT NOT NULL, `final_grade` TEXT NOT NULL, `proposed_points` TEXT NOT NULL, `final_points` TEXT NOT NULL, `points_sum` TEXT NOT NULL, `average` REAL NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_predicted_grade_notified` INTEGER NOT NULL, `is_final_grade_notified` INTEGER NOT NULL, `predicted_grade_last_change` INTEGER NOT NULL, `final_grade_last_change` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "position",
+ "columnName": "position",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "predictedGrade",
+ "columnName": "predicted_grade",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalGrade",
+ "columnName": "final_grade",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "proposedPoints",
+ "columnName": "proposed_points",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalPoints",
+ "columnName": "final_points",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pointsSum",
+ "columnName": "points_sum",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "average",
+ "columnName": "average",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPredictedGradeNotified",
+ "columnName": "is_predicted_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFinalGradeNotified",
+ "columnName": "is_final_grade_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "predictedGradeLastChange",
+ "columnName": "predicted_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "finalGradeLastChange",
+ "columnName": "final_grade_last_change",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradePartialStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `class_average` TEXT NOT NULL, `student_average` TEXT NOT NULL, `class_amounts` TEXT NOT NULL, `student_amounts` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classAverage",
+ "columnName": "class_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAverage",
+ "columnName": "student_average",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classAmounts",
+ "columnName": "class_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentAmounts",
+ "columnName": "student_amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradesPointsStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `others` REAL NOT NULL, `student` REAL NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "others",
+ "columnName": "others",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "student",
+ "columnName": "student",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "GradeSemesterStatistics",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `amounts` TEXT NOT NULL, `student_grade` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "amounts",
+ "columnName": "amounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentGrade",
+ "columnName": "student_grade",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Messages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`email` TEXT NOT NULL, `message_global_key` TEXT NOT NULL, `mailbox_key` TEXT NOT NULL, `message_id` INTEGER NOT NULL, `correspondents` TEXT NOT NULL, `subject` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `read_by` INTEGER, `unread_by` INTEGER, `has_attachments` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `content` TEXT NOT NULL, `sender` TEXT, `recipients` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageGlobalKey",
+ "columnName": "message_global_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mailboxKey",
+ "columnName": "mailbox_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageId",
+ "columnName": "message_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "correspondents",
+ "columnName": "correspondents",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unread",
+ "columnName": "unread",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "readBy",
+ "columnName": "read_by",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "unreadBy",
+ "columnName": "unread_by",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hasAttachments",
+ "columnName": "has_attachments",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "sender",
+ "columnName": "sender",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "recipients",
+ "columnName": "recipients",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MessageAttachments",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`real_id` INTEGER NOT NULL, `message_global_key` TEXT NOT NULL, `url` TEXT NOT NULL, `filename` TEXT NOT NULL, PRIMARY KEY(`real_id`))",
+ "fields": [
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageGlobalKey",
+ "columnName": "message_global_key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filename",
+ "columnName": "filename",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "real_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `category` TEXT NOT NULL, `category_type` INTEGER NOT NULL, `is_points_show` INTEGER NOT NULL, `points` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "categoryType",
+ "columnName": "category_type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isPointsShow",
+ "columnName": "is_points_show",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "points",
+ "columnName": "points",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isRead",
+ "columnName": "is_read",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Homework",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `attachments` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_done` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `is_added_by_user` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "semesterId",
+ "columnName": "semester_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "entryDate",
+ "columnName": "entry_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "attachments",
+ "columnName": "attachments",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDone",
+ "columnName": "is_done",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Subjects",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "realId",
+ "columnName": "real_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "LuckyNumbers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "luckyNumber",
+ "columnName": "lucky_number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "CompletedLesson",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `topic` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `substitution` TEXT NOT NULL, `absence` TEXT NOT NULL, `resources` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "number",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "topic",
+ "columnName": "topic",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacher",
+ "columnName": "teacher",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherSymbol",
+ "columnName": "teacher_symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "substitution",
+ "columnName": "substitution",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "absence",
+ "columnName": "absence",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "resources",
+ "columnName": "resources",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Mailboxes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`globalKey` TEXT NOT NULL, `email` TEXT NOT NULL, `symbol` TEXT NOT NULL, `schoolId` TEXT NOT NULL, `fullName` TEXT NOT NULL, `userName` TEXT NOT NULL, `studentName` TEXT NOT NULL, `schoolNameShort` TEXT NOT NULL, `type` TEXT NOT NULL, PRIMARY KEY(`globalKey`))",
+ "fields": [
+ {
+ "fieldPath": "globalKey",
+ "columnName": "globalKey",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "symbol",
+ "columnName": "symbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolId",
+ "columnName": "schoolId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "fullName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentName",
+ "columnName": "studentName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolNameShort",
+ "columnName": "schoolNameShort",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "globalKey"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Recipients",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`mailboxGlobalKey` TEXT NOT NULL, `studentMailboxGlobalKey` TEXT NOT NULL, `fullName` TEXT NOT NULL, `userName` TEXT NOT NULL, `schoolShortName` TEXT NOT NULL, `type` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "mailboxGlobalKey",
+ "columnName": "mailboxGlobalKey",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentMailboxGlobalKey",
+ "columnName": "studentMailboxGlobalKey",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "fullName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "schoolShortName",
+ "columnName": "schoolShortName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "MobileDevices",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_login_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deviceId",
+ "columnName": "device_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Teachers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "shortName",
+ "columnName": "short_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "School",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT NOT NULL, `contact` TEXT NOT NULL, `headmaster` TEXT NOT NULL, `pedagogue` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "classId",
+ "columnName": "class_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "contact",
+ "columnName": "contact",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "headmaster",
+ "columnName": "headmaster",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pedagogue",
+ "columnName": "pedagogue",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Conferences",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `subject` TEXT NOT NULL, `agenda` TEXT NOT NULL, `present_on_conference` TEXT NOT NULL, `conference_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "agenda",
+ "columnName": "agenda",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "presentOnConference",
+ "columnName": "present_on_conference",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "conferenceId",
+ "columnName": "conference_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableAdditional",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `repeat_id` BLOB DEFAULT NULL, `is_added_by_user` INTEGER NOT NULL DEFAULT 0)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "start",
+ "columnName": "start",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "end",
+ "columnName": "end",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "repeatId",
+ "columnName": "repeat_id",
+ "affinity": "BLOB",
+ "notNull": false,
+ "defaultValue": "NULL"
+ },
+ {
+ "fieldPath": "isAddedByUser",
+ "columnName": "is_added_by_user",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "0"
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "StudentInfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `full_name` TEXT NOT NULL, `first_name` TEXT NOT NULL, `second_name` TEXT NOT NULL, `surname` TEXT NOT NULL, `birth_date` INTEGER NOT NULL, `birth_place` TEXT NOT NULL, `gender` TEXT NOT NULL, `has_polish_citizenship` INTEGER NOT NULL, `family_name` TEXT NOT NULL, `parents_names` TEXT NOT NULL, `address` TEXT NOT NULL, `registered_address` TEXT NOT NULL, `correspondence_address` TEXT NOT NULL, `phone_number` TEXT NOT NULL, `cell_phone_number` TEXT NOT NULL, `email` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `first_guardian_full_name` TEXT, `first_guardian_kinship` TEXT, `first_guardian_address` TEXT, `first_guardian_phones` TEXT, `first_guardian_email` TEXT, `second_guardian_full_name` TEXT, `second_guardian_kinship` TEXT, `second_guardian_address` TEXT, `second_guardian_phones` TEXT, `second_guardian_email` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullName",
+ "columnName": "full_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstName",
+ "columnName": "first_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "secondName",
+ "columnName": "second_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "surname",
+ "columnName": "surname",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthDate",
+ "columnName": "birth_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthPlace",
+ "columnName": "birth_place",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gender",
+ "columnName": "gender",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPolishCitizenship",
+ "columnName": "has_polish_citizenship",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "familyName",
+ "columnName": "family_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentsNames",
+ "columnName": "parents_names",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registeredAddress",
+ "columnName": "registered_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "correspondenceAddress",
+ "columnName": "correspondence_address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "phoneNumber",
+ "columnName": "phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "cellPhoneNumber",
+ "columnName": "cell_phone_number",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "firstGuardian.fullName",
+ "columnName": "first_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.kinship",
+ "columnName": "first_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.address",
+ "columnName": "first_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.phones",
+ "columnName": "first_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "firstGuardian.email",
+ "columnName": "first_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.fullName",
+ "columnName": "second_guardian_full_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.kinship",
+ "columnName": "second_guardian_kinship",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.address",
+ "columnName": "second_guardian_address",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.phones",
+ "columnName": "second_guardian_phones",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secondGuardian.email",
+ "columnName": "second_guardian_email",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimetableHeaders",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "diaryId",
+ "columnName": "diary_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "SchoolAnnouncements",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_login_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "userLoginId",
+ "columnName": "user_login_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "subject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotified",
+ "columnName": "is_notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Notifications",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`student_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `type` TEXT NOT NULL, `destination` TEXT NOT NULL DEFAULT '{\"type\":\"io.github.wulkanowy.ui.modules.Destination.Dashboard\"}', `date` INTEGER NOT NULL, `data` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "studentId",
+ "columnName": "student_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "destination",
+ "columnName": "destination",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'{\"type\":\"io.github.wulkanowy.ui.modules.Destination.Dashboard\"}'"
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "data",
+ "columnName": "data",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AdminMessages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `version_name` INTEGER, `version_max` INTEGER, `target_register_host` TEXT, `target_flavor` TEXT, `destination_url` TEXT, `priority` TEXT NOT NULL, `type` TEXT NOT NULL, `is_dismissible` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "versionMin",
+ "columnName": "version_name",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "versionMax",
+ "columnName": "version_max",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetRegisterHost",
+ "columnName": "target_register_host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetFlavor",
+ "columnName": "target_flavor",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "destinationUrl",
+ "columnName": "destination_url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "priority",
+ "columnName": "priority",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDismissible",
+ "columnName": "is_dismissible",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1dc96a366125ec9f8567da87cdc9c863')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
index 792611a81..cfb53485f 100644
--- a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
+++ b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt
@@ -56,7 +56,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() {
companion object {
- const val VERSION_SCHEMA = 53
+ const val VERSION_SCHEMA = 54
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
Migration2(),
@@ -107,6 +107,7 @@ abstract class AppDatabase : RoomDatabase() {
Migration50(),
Migration51(),
Migration53(),
+ Migration54(),
)
fun newInstance(
diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration54.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration54.kt
new file mode 100644
index 000000000..678bd32f2
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration54.kt
@@ -0,0 +1,26 @@
+package io.github.wulkanowy.data.db.migrations
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class Migration54 : Migration(53, 54) {
+
+ override fun migrate(database: SupportSQLiteDatabase) {
+ migrateResman(database)
+ removeTomaszowMazowieckiStudents(database)
+ }
+
+ private fun migrateResman(database: SupportSQLiteDatabase) {
+ database.execSQL("""
+ UPDATE Students SET
+ scrapper_base_url = 'https://vulcan.net.pl',
+ login_type = 'ADFSLightScoped',
+ symbol = 'rzeszowprojekt'
+ WHERE scrapper_base_url = 'https://resman.pl'
+ """.trimIndent())
+ }
+
+ private fun removeTomaszowMazowieckiStudents(database: SupportSQLiteDatabase) {
+ database.execSQL("DELETE FROM Students WHERE symbol = 'tomaszowmazowiecki'")
+ }
+}
diff --git a/app/src/main/res/values/api_hosts.xml b/app/src/main/res/values/api_hosts.xml
index 8413d68e4..a2a08db67 100644
--- a/app/src/main/res/values/api_hosts.xml
+++ b/app/src/main/res/values/api_hosts.xml
@@ -6,8 +6,9 @@
- Gdańska Platforma Edukacyjna
- Lubelski Portal Oświatowy
- EduNet Miasta Tarnowa
- - ResMan Rzeszów
- Platforma Edukacyjna Koszalina
+ - Gmina-miasto Tomaszów Mazowiecki - System zarządzania oświatą
+ - ResMan Rzeszów
- Rawa Mazowiecka - Platforma vEdukacja
- Zduńska Wola - e-Urząd
- Sieradz - Portal oświatowy
@@ -27,7 +28,6 @@
- https://edu.gdansk.pl
- https://edu.lublin.eu
- https://umt.tarnow.pl
- - https://resman.pl
- https://eduportal.koszalin.pl
- https://vulcan.net.pl/?login
- https://vulcan.net.pl/?login
@@ -40,6 +40,8 @@
- https://vulcan.net.pl/?login
- https://vulcan.net.pl/?login
- https://vulcan.net.pl/?login
+ - https://vulcan.net.pl/?login
+ - https://vulcan.net.pl/?login
- http://fakelog.cf/?email
@@ -48,8 +50,9 @@
- gdansk
- lublin
- tarnow
- - rzeszow
- koszalin
+ - tomaszowmazowieckiprojekt
+ - rzeszowprojekt
- rawamazowiecka
- zdunskawola
- sieradz
diff --git a/app/src/main/res/values/api_symbols.xml b/app/src/main/res/values/api_symbols.xml
index 6f9b1739d..4b61db48d 100644
--- a/app/src/main/res/values/api_symbols.xml
+++ b/app/src/main/res/values/api_symbols.xml
@@ -4,13 +4,11 @@
- Andrychów
- Augustów
- Baranów Sandomierski
- - Bartoszyce
- Będzin
- Bełchatów
- Bełżyce
- Biała Podlaska
- Biała Rawska
- - Białogard
- Biały Bór
- Białystok
- Biecz
@@ -18,11 +16,9 @@
- Bielsko-Biała
- Bierawa
- Bierutów
- - Biskupice
- Blachownia
- Błaszki
- Błonie
- - Bochnia
- Bogatynia
- Boguchwała
- Boguty-Pianki
@@ -45,6 +41,7 @@
- Chełmża
- Chocianów
- Chodzież
+ - Chojnice
- Chojnów
- Chorzów
- Ciechanów
@@ -58,7 +55,9 @@
- Dąbrowa Górnicza
- Dąbrowa Tarnowska
- Dębica
+ - Dębno
- Dobrzeń Wielki
+ - Dobrzeń Wielki 2
- Dobrzyń Nad Wisłą
- Dolnośląskie
- Duszniki-Zdrój
@@ -76,6 +75,9 @@
- Głogów Małopolski
- Głowno
- Głubczyce
+ - Głubczyce 2
+ - Głuchołazy
+ - Gmina Abramów
- Gmina Adamówka
- Gmina Aleksandrów Kujawski
- Gmina Aleksandrów Łódzki
@@ -87,14 +89,17 @@
- Gmina Bądkowo
- Gmina Bałtów
- Gmina Baranów
- - Gmina Barciany
- Gmina Barcin
+ - Gmina Barczewo
- Gmina Baruchowo
+ - Gmina Batorz
- Gmina Będzino
- Gmina Bełchatów
+ - Gmina Besko
- Gmina Białaczów
- Gmina Białe Błota
- - Gmina Bielsk Podlaski
+ - Gmina Białopole
+ - Gmina Bielsk
- Gmina Bircza
- Gmina Błażowa
- Gmina Błędów
@@ -104,7 +109,6 @@
- Gmina Bobrowniki
- Gmina Bodzentyn
- Gmina Bogoria
- - Gmina Bojanów
- Gmina Bojanowo
- Gmina Bojszowy
- Gmina Bolesławiec
@@ -113,10 +117,14 @@
- Gmina Borów
- Gmina Borowa
- Gmina Borzęcin
+ - Gmina Borzytuchom
+ - Gmina Bralin
- Gmina Branice
- Gmina Braniewo
+ - Gmina Brańszczyk
- Gmina Brąszewice
- Gmina Brenna
+ - Gmina Brok
- Gmina Brzeg Dolny
- Gmina Brzeziny
- Gmina Brzeźnio
@@ -125,13 +133,14 @@
- Gmina Brzuze
- Gmina Brzyska
- Gmina Buczek
- - Gmina Buczkowice
- Gmina Budzów
- Gmina Budzyń
+ - Gmina Bukowina Tatrzańska
- Gmina Bukowsko
- Gmina Byczyna
- Gmina Bystra-Sidzina
- - Gmina Bytoń
+ - Gmina Cegłów
+ - Gmina Cekcyn
- Gmina Ceków-Kolonia
- Gmina Celestynów
- Gmina Cewice
@@ -139,16 +148,25 @@
- Gmina Chełm
- Gmina Chełmiec
- Gmina Chełmno
+ - Gmina Chłopice
- Gmina Chmielnik
+ - Gmina Chociwel
- Gmina Chocz
- Gmina Chodel
+ - Gmina Chodów
- Gmina Chojnice
- Gmina Chojnów
+ - Gmina Chotcza
+ - Gmina Chrząstowice
- Gmina Chrzypsko Wielkie
- Gmina Chybie
- Gmina Ciasna
+ - Gmina Ciechanów
- Gmina Ciechocin
+ - Gmina Cielądz
+ - Gmina Cieszanów
- Gmina Ciężkowice
+ - Gmina Cisek
- Gmina Cisna
- Gmina Cmolas
- Gmina Cyców
@@ -156,19 +174,26 @@
- Gmina Czarna
- Gmina Czarnków
- Gmina Czarny Dunajec
+ - Gmina Czastary
- Gmina Czechowice-Dziedzice
- Gmina Czernichów
- Gmina Czerniejewo
+ - Gmina Czerniewice
+ - Gmina Czernikowo
- Gmina Czerwionka-Leszczyny
- - Gmina Czerwonka
+ - Gmina Czerwonak
- Gmina Człuchów
- Gmina Czosnów
+ - Gmina Dąbrowa Zielona
+ - Gmina Dąbrowice
- Gmina Damasławek
- Gmina Damnica
- Gmina Darłowo
- Gmina Dębe Wielkie
- Gmina Dębica
- Gmina Dębno
+ - Gmina Dębowa Kłoda
+ - Gmina Debrzno
- Gmina Dłutów
- Gmina Dobczyce
- Gmina Dobra
@@ -176,19 +201,31 @@
- Gmina Dobrodzień
- Gmina Dobroń
- Gmina Dobrzany
+ - Gmina Dobrzyca
- Gmina Dobrzyniewo Duże
+ - Gmina Dolsk
- Gmina Dominowo
- Gmina Dorohusk
+ - Gmina Doruchów
+ - Gmina Dragacz
+ - Gmina Drawsko
+ - Gmina Drużbice
- Gmina Drzewica
- Gmina Dubiecko
+ - Gmina Dubienka
- Gmina Dukla
- Gmina Dwikozy
+ - Gmina Dydnia
- Gmina Dynów
- Gmina Dziadowa Kłoda
- Gmina Działoszyce
+ - Gmina Dziemiany
- Gmina Dzierżoniów
+ - Gmina Dzwola
- Gmina Elbląg
- - Gmina Fajsławice
+ - Gmina Ełk
+ - Gmina Fredropol
+ - Gmina Garbatka-Letnisko
- Gmina Garbów
- Gmina Garwolin
- Gmina Gąsawa
@@ -198,29 +235,37 @@
- Gmina Gdów
- Gmina Gielniów
- Gmina Gierałtowice
- - Gmina Glinojeck
- Gmina Głogów
+ - Gmina Głogówek
- Gmina Głuchów
+ - Gmina Głusk
- Gmina Głuszyca
- Gmina Gniew
+ - Gmina Gniewino
- Gmina Gniewoszów
- Gmina Gniezno
- Gmina Goczałkowice-Zdrój
- Gmina Godkowo
- Gmina Godów
- Gmina Godziesze Wielkie
+ - Gmina Godziszów
- Gmina Gołańcz
+ - Gmina Gołcza
- Gmina Goleszów
- Gmina Golina
- Gmina Golub-Dobrzyń
+ - Gmina Gołuchów
+ - Gmina Gomunice
- Gmina Goraj
- Gmina Gorlice
- Gmina Górno
+ - Gmina Górzyca
- Gmina Gościeradów
- Gmina Gostyń
- Gmina Gostynin
- Gmina Goszczyn
- Gmina Gózd
+ - Gmina Grabica
- Gmina Grabów
- Gmina Grabowiec
- Gmina Grabów Nad Pilicą
@@ -239,45 +284,52 @@
- Gmina Grudziądz
- Gmina Gruta
- Gmina Grybów
+ - Gmina Gryfice
+ - Gmina Grzmiąca
- Gmina Haczów
- Gmina Halinów
- Gmina Hańsk
- Gmina Harasiuki
- Gmina Hażlach
- Gmina Herby
+ - Gmina Horodło
- Gmina Hrubieszów
- Gmina Huszlew
- Gmina Hyżne
- Gmina Imielno
- Gmina Inowrocław
+ - Gmina Irządze
- Gmina Istebna
+ - Gmina Iwanowice
- Gmina Iwierzyce
- Gmina Iwonicz-Zdrój
- Gmina Izabelin
- Gmina Izbica
- - Gmina Jadów
+ - Gmina Izbicko
+ - Gmina Jabłoń
- Gmina Jaktorów
+ - Gmina Jakubów
- Gmina Janikowo
+ - Gmina Janów
- Gmina Janowiec
- Gmina Janów Podlaski
- - Gmina Jaraczewo
+ - Gmina Jarczów
- Gmina Jarocin
- Gmina Jasienica Rosielna
+ - Gmina Jaśliska
- Gmina Jasło
- Gmina Jastków
- Gmina Jastrowie
- Gmina Jastrząb
- Gmina Jedlicze
- - Gmina Jedlińsk
- - Gmina Jedlnia-Letnisko
- Gmina Jejkowice
- Gmina Jemielnica
- - Gmina Jemielno
- Gmina Jerzmanowa
- Gmina Jeżewo
- Gmina Jeziora Wielkie
- Gmina Jeziorzany
- Gmina Jeżowe
+ - Gmina Joniec
- Gmina Jordanów
- Gmina Józefów
- Gmina Józefów Nad Wisłą
@@ -285,14 +337,18 @@
- Gmina Kąkolewnica
- Gmina Kamień
- Gmina Kamienica
- - Gmina Kamieniec
+ - Gmina Kamiennik
- Gmina Kamionka
- Gmina Karczmiska
- Gmina Kargowa
+ - Gmina Karlino
+ - Gmina Karniewo
- Gmina Kawęczyn
- Gmina Kazimierz Biskupi
- Gmina Kępice
+ - Gmina Kęsowo
- Gmina Kiełczygłów
+ - Gmina Kietrz
- Gmina Kikół
- Gmina Kiszkowo
- Gmina Kleczew
@@ -307,22 +363,30 @@
- Gmina Klucze
- Gmina Kluczewsko
- Gmina Kobiele Wielkie
+ - Gmina Kobylanka
- Gmina Kochanowice
- Gmina Kock
- Gmina Kodrąb
- Gmina Kołaczyce
- Gmina Kołbaskowo
+ - Gmina Kołbiel
- Gmina Kołczygłowy
+ - Gmina Kołobrzeg
- Gmina Koluszki
- Gmina Komańcza
+ - Gmina Komarówka Podlaska
- Gmina Komorniki
- Gmina Komprachcice
- Gmina Konarzyny
- Gmina Kondratowice
+ - Gmina Koneck
- Gmina Koniusza
- Gmina Konopiska
- Gmina Końskowola
+ - Gmina Konstantynów
- Gmina Koprzywnica
+ - Gmina Korfantów
+ - Gmina Kórnik
- Gmina Korsze
- Gmina Korycin
- Gmina Korzenna
@@ -332,10 +396,14 @@
- Gmina Kościerzyna
- Gmina Kosów Lacki
- Gmina Kostrzyn
- - Gmina Koszyce
+ - Gmina Koszęcin
- Gmina Kotla
- Gmina Kotuń
+ - Gmina Kowiesy
+ - Gmina Koziegłowy
- Gmina Kozłów
+ - Gmina Kramsk
+ - Gmina Kraśniczyn
- Gmina Kraśnik
- Gmina Krasnobród
- Gmina Krasnystaw
@@ -345,12 +413,16 @@
- Gmina Krośnice
- Gmina Krupski Młyn
- Gmina Kruszwica
+ - Gmina Krynice
- Gmina Krynki
- Gmina Krzanowice
- Gmina Krzemieniewo
+ - Gmina Krzeszów
- Gmina Krzymów
+ - Gmina Krzywcza
- Gmina Krzywiń
- Gmina Krzyżanowice
+ - Gmina Ksawerów
- Gmina Książ Wielki
- Gmina Kunice
- Gmina Kunów
@@ -360,15 +432,19 @@
- Gmina Kwilcz
- Gmina Łabowa
- Gmina Łabunie
+ - Gmina Łączna
+ - Gmina Lądek
- Gmina Łambinowice
- Gmina Lanckorona
+ - Gmina Łańcut
+ - Gmina Łapanów
- Gmina Łapsze Niżne
- Gmina Łasin
- Gmina Łaskarzew
- Gmina Lasowice Wielkie
- Gmina Łaszczów
- - Gmina Laszki
- Gmina Latowicz
+ - Gmina Łaziska
- Gmina Łazy
- Gmina Łęczyca
- Gmina Łęczyce
@@ -378,11 +454,14 @@
- Gmina Lelów
- Gmina Leśna
- Gmina Leśna Podlaska
+ - Gmina Leśniowice
- Gmina Lesznowola
- Gmina Leżajsk
- Gmina Lichnowy
- Gmina Limanowa
- Gmina Linia
+ - Gmina Liniewo
+ - Gmina Lipiany
- Gmina Lipinki
- Gmina Lipnik
- Gmina Lipowa
@@ -390,43 +469,51 @@
- Gmina Liszki
- Gmina Liw
- Gmina Łobez
+ - Gmina Łochów
- Gmina Łodygowice
- Gmina Łomazy
+ - Gmina Łomianki
+ - Gmina Łoniów
- Gmina Łopiennik Górny
- Gmina Łopuszno
+ - Gmina Łosice
- Gmina Lubań
- Gmina Lubartów
- Gmina Lubasz
+ - Gmina Lubawka
- Gmina Lubenia
- Gmina Łubianka
- Gmina Lubicz
+ - Gmina Lubień
- Gmina Lubiewo
- Gmina Lubin
- Gmina Łubniany
- Gmina Lubochnia
- - Gmina Lubomia
- Gmina Luboń
+ - Gmina Lubsza
+ - Gmina Lubycza Królewska
- Gmina Łuków
- Gmina Łukowica
- Gmina Lutowiska
+ - Gmina Lututów
- Gmina Luzino
- Gmina Łużna
- Gmina Łysomice
+ - Gmina Maciejowice
- Gmina Magnuszew
+ - Gmina Majdan Królewski
- Gmina Maków Podhalański
- - Gmina Mała Wieś
- Gmina Malbork
- Gmina Małdyty
- Gmina Małkinia Górna
- Gmina Marcinowice
- Gmina Margonin
- Gmina Marianowo
- - Gmina Markusy
- - Gmina Masłów
+ - Gmina Markuszów
+ - Gmina Męcinka
- Gmina Medyka
- Gmina Mełgiew
- Gmina Michałów
- - Gmina Michałowo
- Gmina Miedziana Góra
- Gmina Miedźna
- Gmina Miedźno
@@ -435,7 +522,10 @@
- Gmina Międzyrzec Podlaski
- Gmina Międzyzdroje
- Gmina Miejsce Piastowe
+ - Gmina Miękinia
- Gmina Mielec
+ - Gmina Mielno
+ - Gmina Mieszkowice
- Gmina Milanów
- Gmina Milejów
- Gmina Milicz
@@ -444,21 +534,26 @@
- Gmina Miłosław
- Gmina Milówka
- Gmina Mińsk Mazowiecki
+ - Gmina Mirów
- Gmina Mirsk
- Gmina Młynary
+ - Gmina Modliborzyce
- Gmina Mogielnica
- Gmina Mogilany
+ - Gmina Mogilno
+ - Gmina Morawica
- Gmina Mordy
- Gmina Moryń
- Gmina Mrocza
- Gmina Mrozy
+ - Gmina Mściwojów
+ - Gmina Mstów
- Gmina Mszana
- Gmina Mszana Dolna
- Gmina Murów
- Gmina Mycielin
- - Gmina Mysłakowice
+ - Gmina Mykanów
- Gmina Myślibórz
- - Gmina Nadarzyn
- Gmina Namysłów
- Gmina Nasielsk
- Gmina Nawojowa
@@ -469,23 +564,25 @@
- Gmina Niedrzwica Duża
- Gmina Niedźwiada
- Gmina Niedźwiedź
- - Gmina Niegosławice
- - Gmina Niwiska
+ - Gmina Nowa Karczma
- Gmina Nowa Ruda
- Gmina Nowa Wieś Lęborska
+ - Gmina Nowe
- Gmina Nowe Miasto
- Gmina Nowe Miasto Nad Wartą
- - Gmina Nowogród Bobrzański
+ - Gmina Nowogród
- Gmina Nowosolna
- Gmina Nowy Kawęczyn
+ - Gmina Nowy Korczyn
- Gmina Nowy Staw
- Gmina Nowy Targ
- Gmina Nowy Tomyśl
+ - Gmina Nozdrzec
- Gmina Nur
- Gmina Obrazów
- Gmina Ochotnica Dolna
- Gmina Ogrodzieniec
- - Gmina Olecko
+ - Gmina Olszanica
- Gmina Olsztynek
- Gmina Olszyna
- Gmina Opatowiec
@@ -495,11 +592,15 @@
- Gmina Osiek Jasielski
- Gmina Osiek Mały
- Gmina Osielsko
+ - Gmina Osina
+ - Gmina Osjaków
+ - Gmina Ostroróg
- Gmina Ostrów
- Gmina Ostrówek
- Gmina Ostrów Lubelski
- Gmina Ostrów Mazowiecka
- Gmina Ostrów Wielkopolski
+ - Gmina Otmuchów
- Gmina Otyń
- Gmina Ożarów
- Gmina Ożarowice
@@ -507,27 +608,32 @@
- Gmina Ozorków
- Gmina Pabianice
- Gmina Pacanów
+ - Gmina Pacyna
- Gmina Paczków
- Gmina Padew Narodowa
- - Gmina Pajęczno
- Gmina Pakosław
- Gmina Pakosławice
- Gmina Pałecznica
- Gmina Panki
- Gmina Parchowo
- Gmina Parczew
- - Gmina Pawłosiów
+ - Gmina Pasłęk
+ - Gmina Pątnów
- Gmina Pawłowice
- Gmina Pawłowiczki
+ - Gmina Pawonków
- Gmina Pęcław
- Gmina Pelplin
+ - Gmina Pępowo
- Gmina Piaski
- Gmina Piątnica
- - Gmina Piecki
- Gmina Piekoszów
+ - Gmina Pieniężno
- Gmina Pilchowice
+ - Gmina Pińczów
- Gmina Pionki
- - Gmina Piotrków Trybunalski
+ - Gmina Płaska
+ - Gmina Platerówka
- Gmina Pleśna
- Gmina Pleszew
- Gmina Płońsk
@@ -535,6 +641,7 @@
- Gmina Poczesna
- Gmina Podedwórze
- Gmina Podegrodzie
+ - Gmina Podgórzyn
- Gmina Pokój
- Gmina Połajewo
- Gmina Połaniec
@@ -543,16 +650,18 @@
- Gmina Police
- Gmina Polkowice
- Gmina Pomiechówek
+ - Gmina Poniatowa
- Gmina Popielów
- Gmina Popów
- - Gmina Poraj
- Gmina Potęgowo
+ - Gmina Potok Wielki
- Gmina Praszka
- - Gmina Prażmów
- Gmina Prochowice
- Gmina Promna
- Gmina Prószków
+ - Gmina Prusice
- Gmina Pruszcz Gdański
+ - Gmina Przechlewo
- Gmina Przecław
- Gmina Przedecz
- Gmina Przemęt
@@ -562,7 +671,9 @@
- Gmina Przodkowo
- Gmina Przykona
- Gmina Przyłęk
+ - Gmina Przyrów
- Gmina Przystajń
+ - Gmina Przytoczna
- Gmina Puchaczów
- Gmina Puck
- Gmina Puławy
@@ -570,10 +681,10 @@
- Gmina Puszcza Mariańska
- Gmina Pysznica
- Gmina Pyzdry
+ - Gmina Raba Wyżna
- Gmina Rachanie
- Gmina Raciechowice
- - Gmina Racławice
- - Gmina Radecznica
+ - Gmina Radgoszcz
- Gmina Radków
- Gmina Radłów
- Gmina Radomin
@@ -581,16 +692,29 @@
- Gmina Radomyśl Nad Sanem
- Gmina Radoszyce
- Gmina Radwanice
+ - Gmina Radymno
+ - Gmina Radziejów
- Gmina Radziłów
+ - Gmina Rajgród
+ - Gmina Raków
+ - Gmina Rakszawa
- Gmina Rawa Mazowiecka
+ - Gmina Regnów
- Gmina Reńska Wieś
+ - Gmina Rogóźno
+ - Gmina Rokitno
+ - Gmina Ropa
- Gmina Rossosz
- Gmina Rozprza
- Gmina Ruciane-Nida
- Gmina Ruda-Huta
- Gmina Rudna
- Gmina Rudniki
+ - Gmina Rudnik Nad Sanem
+ - Gmina Rudziniec
- Gmina Rusiec
+ - Gmina Rusinów
+ - Gmina Rybczewice
- Gmina Rychliki
- Gmina Rychtal
- Gmina Ryczywół
@@ -598,32 +722,39 @@
- Gmina Rypin
- Gmina Rytro
- Gmina Rytwiany
- - Gmina Rząśnia
- Gmina Rzeczyca
- Gmina Rzepiennik Strzyżewski
- Gmina Rzepin
+ - Gmina Rzezawa
- Gmina Rzgów
- Gmina Sadki
- Gmina Sadowne
- Gmina Samborzec
- Gmina Sanok
+ - Gmina Sawin
- Gmina Ścinawa
- Gmina Sędziejowice
+ - Gmina Sejny
+ - Gmina Sękowa
- Gmina Sępopol
- Gmina Serokomla
- Gmina Sianów
- Gmina Sicienko
- Gmina Sieciechów
- Gmina Siedlce
+ - Gmina Siedliszcze
- Gmina Siemiatycze
+ - Gmina Siemień
- Gmina Siemyśl
- Gmina Siennica
- Gmina Siennica Różana
- Gmina Sienno
- Gmina Siepraw
- Gmina Sieradz
+ - Gmina Sieraków
- Gmina Sierakowice
- Gmina Siewierz
+ - Gmina Sitkówka-Nowiny
- Gmina Sitno
- Gmina Skarżysko Kościelne
- Gmina Skępe
@@ -631,16 +762,22 @@
- Gmina Skoczów
- Gmina Skoki
- Gmina Skołyszyn
+ - Gmina Skrwilno
- Gmina Skrzyszów
- Gmina Skulsk
+ - Gmina Skwierzyna
- Gmina Sława
+ - Gmina Śliwice
- Gmina Słopnice
+ - Gmina Słubice
- Gmina Słupca
- Gmina Słupia
+ - Gmina Słupia (Konecka)
+ - Gmina Śmigiel
- Gmina Sobienie-Jeziory
+ - Gmina Sobolew
- Gmina Sobótka
- Gmina Sokółka
- - Gmina Sokoły
- Gmina Solina
- Gmina Sośnicowice
- Gmina Sośnie
@@ -655,11 +792,16 @@
- Gmina Stare Miasto
- Gmina Stare Pole
- Gmina Starogard Gdański
+ - Gmina Stary Brus
+ - Gmina Stary Dzierzgoń
+ - Gmina Stary Targ
- Gmina Stawiszyn
+ - Gmina Stepnica
- Gmina Stoczek Łukowski
- Gmina Stopnica
- Gmina Strawczyn
- Gmina Stryków
+ - Gmina Stryszawa
- Gmina Stryszów
- Gmina Strzałkowo
- Gmina Strzelce Opolskie
@@ -668,38 +810,43 @@
- Gmina Strzyżewice
- Gmina Stupsk
- Gmina Subkowy
+ - Gmina Suchań
- Gmina Suchedniów
- Gmina Suchożebry
- Gmina Suchy Las
- Gmina Sulechów
- Gmina Sulęcin
+ - Gmina Sulejów
- Gmina Sulików
- Gmina Sulmierzyce
- Gmina Sułów
- Gmina Susiec
- - Gmina Świerklaniec
+ - Gmina Świercze
+ - Gmina Świerczów
+ - Gmina Świerklany
- Gmina Świerzawa
- Gmina Świeszyno
- Gmina Świlcza
- Gmina Szadek
- Gmina Szaflary
- Gmina Szastarka
+ - Gmina Szczawin Kościelny
- Gmina Szczebrzeszyn
- Gmina Szczekociny
- Gmina Szczerców
- - Gmina Szczutowo
- Gmina Szczytna
- Gmina Szczytniki
- - Gmina Szemud
+ - Gmina Szczytno
- Gmina Szerzyny
- Gmina Szlichtyngowa
+ - Gmina Szreńsk
+ - Gmina Szudziałowo
- Gmina Szydłów
- Gmina Tarłów
- Gmina Tarnów
- Gmina Tarnowiec
- Gmina Tarnów Opolski
- Gmina Teresin
- - Gmina Terespol
- Gmina Tereszpol
- Gmina Tłuchowo
- Gmina Tłuszcz
@@ -709,12 +856,15 @@
- Gmina Toszek
- Gmina Trąbki Wielkie
- Gmina Trzebiatów
+ - Gmina Trzebielino
- Gmina Trzebinia
- - Gmina Trzeszczany
- Gmina Trzyciąż
+ - Gmina Trzydnik Duży
- Gmina Tuchów
+ - Gmina Tułowice
- Gmina Turośń Kościelna
- Gmina Tuszów Narodowy
+ - Gmina Tworóg
- Gmina Tyczyn
- Gmina Tymbark
- Gmina Tyrawa Wołoska
@@ -723,15 +873,21 @@
- Gmina Ulan-Majorat
- Gmina Ulanów
- Gmina Ułęż
+ - Gmina Ulhówek
- Gmina Urszulin
- Gmina Urzędów
+ - Gmina Uście Gorlickie
- Gmina Uścimów
- Gmina Wąchock
+ - Gmina Wądroże Wielkie
- Gmina Wągrowiec
+ - Gmina Walce
- Gmina Wąpielsk
- Gmina Wasilków
+ - Gmina Wąsosz
- Gmina Wąwolnica
- Gmina Wejherowo
+ - Gmina Werbkowice
- Gmina Wiązów
- Gmina Wiązowna
- Gmina Wicko
@@ -739,16 +895,21 @@
- Gmina Wielbark
- Gmina Wieleń
- Gmina Wielgie
+ - Gmina Wielgomłyny
- Gmina Wieliszew
- Gmina Wielka Nieszawka
- Gmina Wieniawa
- Gmina Wieprz
- Gmina Wieruszów
+ - Gmina Wierzbinek
- Gmina Wierzbno
+ - Gmina Wierzchlas
- Gmina Wierzchosławice
- Gmina Wietrzychowice
- Gmina Wijewo
+ - Gmina Wilczyce
- Gmina Wilczyn
+ - Gmina Wilkołaz
- Gmina Wilków
- Gmina Wilkowice
- Gmina Winnica
@@ -759,12 +920,14 @@
- Gmina Witkowo
- Gmina Władysławów
- Gmina Wleń
+ - Gmina Włocławek
- Gmina Włodawa
- Gmina Włoszczowa
- Gmina Wodzierady
- Gmina Wodzisław
- Gmina Wojcieszków
- Gmina Wojnicz
+ - Gmina Wojsławice
- Gmina Wola Krzysztoporska
- Gmina Wolanów
- Gmina Wolbrom
@@ -775,15 +938,18 @@
- Gmina Wręczyca Wielka
- Gmina Wronki
- Gmina Wyrzysk
- - Gmina Zabierzów
+ - Gmina Wysokie
- Gmina Żabno
- Gmina Żagań
- - Gmina Zagórz
+ - Gmina Zagórów
- Gmina Zaklików
- Gmina Zakroczym
- Gmina Zakrzówek
+ - Gmina Zalesie
- Gmina Zaleszany
+ - Gmina Załuski
- Gmina Zamość
+ - Gmina Żarnów
- Gmina Żarnowiec
- Gmina Żarów
- Gmina Zarszyn
@@ -795,20 +961,26 @@
- Gmina Zbójno
- Gmina Zbrosławice
- Gmina Zduńska Wola
- - Gmina Zduny
- Gmina Zdzieszowice
+ - Gmina Zębowice
- Gmina Zebrzydowice
+ - Gmina Żegocina
- Gmina Żelazków
+ - Gmina Zembrzyce
- Gmina Zgierz
- Gmina Zgorzelec
- Gmina Ziębice
- Gmina Zielonki
- Gmina Zławieś Wielka
+ - Gmina Złota
+ - Gmina Złotniki Kujawskie
- Gmina Żmudź
- Gmina Żnin
- Gmina Żółkiewka
- Gmina Żołynia
- Gmina Żukowice
+ - Gmina Żurawica
+ - Gmina Żyraków
- Gmina Żyrzyn
- Gmina Żytno
- Gniezno
@@ -817,19 +989,19 @@
- Góra
- Góra Kalwaria
- Gorlice
+ - Górzno
- Gorzów Śląski
- Gorzów Wielkopolski
- Gostynin
- Grajewo
- Grodzisk Mazowiecki
- - Gronowo Elbląskie
- Grudziądz
+ - Grybów
- Gryfino
- Gryfów Śląski
- Hel
- Hrubieszów
- Inowrocław
- - Iwanowice
- Izbica Kujawska
- Jabłonowo Pomorskie
- Janowiec Wielkopolski
@@ -839,7 +1011,6 @@
- Jasło
- Jastrzębie-Zdrój
- Jawor
- - Jaworzno
- Jedlina-Zdrój
- Jelcz-Laskowice
- Jelenia Góra
@@ -860,9 +1031,9 @@
- Kępno
- Kętrzyn
- Kielce
- - Kiełczygłów
- Kłodawa
- Kłodzko
+ - Kluczbork
- Knurów
- Kobyłka
- Koło
@@ -892,11 +1063,13 @@
- Krzeszowice
- Krzyż Wielkopolski
- Książ Wielkopolski
- - Kudowa-Zdrój
- Kujawsko-Pomorskie
+ - Kutno
- Kuźnia Raciborska
+ - Kwidzyn
- Łabiszyn
- Lądek-Zdrój
+ - Łańcut
- Łapy
- Łask
- Łaskarzew
@@ -908,10 +1081,10 @@
- Legnica
- Leszno
- Lewin Brzeski
+ - Lewin Brzeski 2
- Leżajsk
- Limanowa
- Lipno
- - Lipsko
- Łódź
- Łódzkie
- Łowicz
@@ -928,11 +1101,8 @@
- Lwówek Śląski
- Malbork
- Małopolskie
- - Marciszów
- Marki
- - Masłowice
- Mazowieckie
- - Miastko
- Michałowice
- Miechów
- Międzyrzec Podlaski
@@ -940,6 +1110,7 @@
- Mielec
- Milanówek
- Mińsk Mazowiecki
+ - Mniszków
- Mosina
- Mrągowo
- Mrągowski
@@ -949,18 +1120,17 @@
- Mysłowice
- Myszków
- Nakło Nad Notecią
- - Nasielsk
- Niemodlin
- Niepołomice
- Nisko
- Nowa Dęba
- Nowa Sarzyna
+ - Nowa Sól
- Nowe Miasteczko
- Nowe Skalmierzyce
- Nowogard
- Nowogród Bobrzański
- Nowogrodziec
- - Nowosolna
- Nowy Dwór Mazowiecki
- Nowy Sącz
- Nowy Targ
@@ -974,6 +1144,8 @@
- Opoczno
- Opole
- Opole Lubelskie
+ - Opolskie
+ - Orzesze
- Osieczna
- Osiecznica
- Ostróda
@@ -991,13 +1163,16 @@
- Piekary Śląskie
- Pieńsk
- Piła
+ - Pilzno
- Piotrków Trybunalski
- Pisz
- Płock
- Płońsk
- Pniewy
+ - Pobiedziska
- Podkarpackie
- Podkowa Leśna
+ - Podlaskie
- Połczyn-Zdrój
- Pomorskie
- Poniec
@@ -1006,7 +1181,7 @@
- Powiat augustowski
- Powiat będziński
- Powiat bełchatowski
- - Powiat białobrzeski
+ - Powiat białostocki
- Powiat bialski
- Powiat bielski
- Powiat bieszczadzki
@@ -1032,6 +1207,7 @@
- Powiat człuchowski
- Powiat dąbrowski
- Powiat dębicki
+ - Powiat drawski
- Powiat działdowski
- Powiat dzierżoniowski
- Powiat elbląski
@@ -1046,10 +1222,11 @@
- Powiat goleniowski
- Powiat golubsko-dobrzyński
- Powiat gorlicki
+ - Powiat górowski
- Powiat gorzowski
- Powiat gostyński
+ - Powiat grajewski
- Powiat grójecki
- - Powiat grudziądzki
- Powiat gryficki
- Powiat gryfiński
- Powiat hajnowski
@@ -1064,6 +1241,7 @@
- Powiat jędrzejowski
- Powiat jeleniogórski
- Powiat kaliski
+ - Powiat kamiennogórski
- Powiat kamieński
- Powiat kartuski
- Powiat kazimierski
@@ -1088,6 +1266,7 @@
- Powiat krośnieński
- Powiat krotoszyński
- Powiat kutnowski
+ - Powiat łańcucki
- Powiat łaski
- Powiat lęborski
- Powiat łęczycki
@@ -1102,6 +1281,7 @@
- Powiat lipski
- Powiat łobeski
- Powiat łódzki wschodni
+ - Powiat łosicki
- Powiat łowicki
- Powiat lubaczowski
- Powiat lubański
@@ -1122,9 +1302,11 @@
- Powiat myślenicki
- Powiat myszkowski
- Powiat nakielski
+ - Powiat namysłowski
- Powiat nidzicki
- Powiat niżański
- Powiat nowodworski
+ - Powiat nowomiejski
- Powiat nowosądecki
- Powiat nowosolski
- Powiat nowotarski
@@ -1160,7 +1342,6 @@
- Powiat proszowicki
- Powiat prudnicki
- Powiat pruszkowski
- - Powiat przasnyski
- Powiat przemyski
- Powiat przeworski
- Powiat przysuski
@@ -1183,6 +1364,7 @@
- Powiat rzeszowski
- Powiat sandomierski
- Powiat sanocki
+ - Powiat sejneński
- Powiat sępoleński
- Powiat siedlecki
- Powiat siemiatycki
@@ -1210,6 +1392,7 @@
- Powiat świdnicki
- Powiat świdwiński
- Powiat świebodziński
+ - Powiat świecki
- Powiat szamotulski
- Powiat szczycieński
- Powiat sztumski
@@ -1228,6 +1411,7 @@
- Powiat wągrowiecki
- Powiat wałecki
- Powiat warszawski zachodni
+ - Powiat węgorzewski
- Powiat węgrowski
- Powiat wejherowski
- Powiat wielicki
@@ -1247,7 +1431,6 @@
- Powiat wyszkowski
- Powiat ząbkowicki
- Powiat żagański
- - Powiat zambrowski
- Powiat zamojski
- Powiat żarski
- Powiat zawierciański
@@ -1258,34 +1441,33 @@
- Powiat złotoryjski
- Powiat złotowski
- Powiat żniński
- - Powiat żuromiński
- Powiat żyrardowski
- Powiat żywiecki
- Poznań
- - Prostki
- Proszowice
- Prudnik
+ - Pruszcz Gdański
- Pruszków
- Przasnysz
- Przemyśl
- Przeworsk
- Przysucha
- Pszczyna
- - Pszów
- Puck
- Puławy
+ - Pułtusk
+ - Puszczykowo
- Pyskowice
- Rabka-Zdrój
- Raciąż
- Racibórz
- - Raciechowice
- Radom
- Radomsko
+ - Radomyśl Wielki
- Radymno
- Radziejów
- Radzionków
- Radzyń Podlaski
- - Raków
- Rawa Mazowiecka
- Rawicz
- Reda
@@ -1299,6 +1481,7 @@
- Rymanów
- Rypin
- Rzeszów
+ - Rzeszów projekt
- Sandomierz
- Sanok
- Sędziszów Małopolski
@@ -1306,7 +1489,6 @@
- Siedlce
- Siemianowice Śląskie
- Siemiatycze
- - Sieniawa
- Sieradz
- Skarżysko-Kamienna
- Skawina
@@ -1325,17 +1507,15 @@
- Środa Śląska
- Środa Wielkopolska
- Starachowice
+ - Stargard
- Starogard Gdański
- Stary Sącz
- Staszów
- Stronie Śląskie
- - Strzegom
- Strzyżów
- - Suchy Las
- Sulejówek
- Sułkowice
- Sulmierzyce
- - Suwalski
- Swarzędz
- Świdnica
- Świdnik
@@ -1358,8 +1538,10 @@
- Terespol
- Tomaszów Lubelski
- Tomaszów Mazowiecki
+ - Tomaszów Mazowiecki projekt
- Toruń
- Trzcianka
+ - Trzcińsko-Zdrój
- Trzebnica
- Trzemeszno
- Tuliszków
@@ -1372,7 +1554,7 @@
- Ustrzyki Dolne
- Wadowice
- Wągrowiec
- - Wałbrzych
+ - Wałcz
- Warmińsko-Mazurskie
- Warszawa
- Wąsosz
@@ -1381,7 +1563,7 @@
- Więcbork
- Wieliczka
- Wielkopolskie
- - Wizna
+ - Wieluń
- Władysławowo
- Włocławek
- Włodawa
@@ -1410,6 +1592,7 @@
- Zielona Góra
- Zielonka
- Złotoryja
+ - Złotów
- Żory
- Zwoleń
- Żyrardów
@@ -1418,13 +1601,11 @@
- andrychow
- augustow
- baranowsandomierski
- - bartoszyce
- bedzin
- belchatow
- belzyce
- bialapodlaska
- bialarawska
- - bialogard
- bialybor
- bialystok
- biecz
@@ -1432,11 +1613,9 @@
- bielskobiala
- bierawa
- bierutow
- - biskupice
- blachownia
- blaszki
- blonie
- - bochnia
- bogatynia
- boguchwala
- bogutypianki
@@ -1459,6 +1638,7 @@
- chelmza
- chocianow
- chodziez
+ - chojnice
- chojnow
- chorzow
- ciechanow
@@ -1472,7 +1652,9 @@
- dabrowagornicza
- dabrowatarnowska
- debica
+ - debno
- dobrzenwielki
+ - dobrzenwielki2
- dobrzynnadwisla
- dolnoslaskie
- dusznikizdroj
@@ -1490,6 +1672,9 @@
- glogowmalopolski
- glowno
- glubczyce
+ - glubczyce2
+ - glucholazy
+ - gminaabramow
- gminaadamowka
- gminaaleksandrowkujawski
- gminaaleksandrowlodzki
@@ -1501,14 +1686,17 @@
- gminabadkowo
- gminabaltow
- gminabaranow
- - gminabarciany
- gminabarcin
+ - gminabarczewo
- gminabaruchowo
+ - gminabatorz
- gminabedzino
- gminabelchatow
+ - gminabesko
- gminabialaczow
- gminabialeblota
- - gminabielskpodlaski
+ - gminabialopole
+ - gminabielsk
- gminabircza
- gminablazowa
- gminabledow
@@ -1518,7 +1706,6 @@
- gminabobrowniki
- gminabodzentyn
- gminabogoria
- - gminabojanow
- gminabojanowo
- gminabojszowy
- gminaboleslawiec
@@ -1527,10 +1714,14 @@
- gminaborow
- gminaborowa
- gminaborzecin
+ - gminaborzytuchom
+ - gminabralin
- gminabranice
- gminabraniewo
+ - gminabranszczyk
- gminabraszewice
- gminabrenna
+ - gminabrok
- gminabrzegdolny
- gminabrzeziny
- gminabrzeznio
@@ -1539,13 +1730,14 @@
- gminabrzuze
- gminabrzyska
- gminabuczek
- - gminabuczkowice
- gminabudzow
- gminabudzyn
+ - gminabukowinatatrzanska
- gminabukowsko
- gminabyczyna
- gminabystrasidzina
- - gminabyton
+ - gminaceglow
+ - gminacekcyn
- gminacekowkolonia
- gminacelestynow
- gminacewice
@@ -1553,16 +1745,25 @@
- gminachelm
- gminachelmiec
- gminachelmno
+ - gminachlopice
- gminachmielnik
+ - gminachociwel
- gminachocz
- gminachodel
+ - gminachodow
- gminachojnice
- gminachojnow
+ - gminachotcza
+ - gminachrzastowice
- gminachrzypskowielkie
- gminachybie
- gminaciasna
+ - gminaciechanow
- gminaciechocin
+ - gminacieladz
+ - gminacieszanow
- gminaciezkowice
+ - gminacisek
- gminacisna
- gminacmolas
- gminacycow
@@ -1570,19 +1771,26 @@
- gminaczarna
- gminaczarnkow
- gminaczarnydunajec
+ - gminaczastary
- gminaczechowicedziedzice
- gminaczernichow
- gminaczerniejewo
+ - gminaczerniewice
+ - gminaczernikowo
- gminaczerwionkaleszczyny
- - gminaczerwonka
+ - gminaczerwonak
- gminaczluchow
- gminaczosnow
+ - gminadabrowazielona
+ - gminadabrowice
- gminadamaslawek
- gminadamnica
- gminadarlowo
- gminadebewielkie
- gminadebica
- gminadebno
+ - gminadebowakloda
+ - gminadebrzno
- gminadlutow
- gminadobczyce
- gminadobra
@@ -1590,19 +1798,31 @@
- gminadobrodzien
- gminadobron
- gminadobrzany
+ - gminadobrzyca
- gminadobrzyniewoduze
+ - gminadolsk
- gminadominowo
- gminadorohusk
+ - gminadoruchow
+ - gminadragacz
+ - gminadrawsko
+ - gminadruzbice
- gminadrzewica
- gminadubiecko
+ - gminadubienka
- gminadukla
- gminadwikozy
+ - gminadydnia
- gminadynow
- gminadziadowakloda
- gminadzialoszyce
+ - gminadziemiany
- gminadzierzoniow
+ - gminadzwola
- gminaelblag
- - gminafajslawice
+ - gminaelk
+ - gminafredropol
+ - gminagarbatkaletnisko
- gminagarbow
- gminagarwolin
- gminagasawa
@@ -1612,29 +1832,37 @@
- gminagdow
- gminagielniow
- gminagieraltowice
- - gminaglinojeck
- gminaglogow
+ - gminaglogowek
- gminagluchow
+ - gminaglusk
- gminagluszyca
- gminagniew
+ - gminagniewino
- gminagniewoszow
- gminagniezno
- gminagoczalkowicezdroj
- gminagodkowo
- gminagodow
- gminagodzieszewielkie
+ - gminagodziszow
- gminagolancz
+ - gminagolcza
- gminagoleszow
- gminagolina
- gminagolubdobrzyn
+ - gminagoluchow
+ - gminagomunice
- gminagoraj
- gminagorlice
- gminagorno
+ - gminagorzyca
- gminagoscieradow
- gminagostyn
- gminagostynin
- gminagoszczyn
- gminagozd
+ - gminagrabica
- gminagrabow
- gminagrabowiec
- gminagrabownadpilica
@@ -1653,45 +1881,52 @@
- gminagrudziadz
- gminagruta
- gminagrybow
+ - gminagryfice
+ - gminagrzmiaca
- gminahaczow
- gminahalinow
- gminahansk
- gminaharasiuki
- gminahazlach
- gminaherby
+ - gminahorodlo
- gminahrubieszow
- gminahuszlew
- gminahyzne
- gminaimielno
- gminainowroclaw
+ - gminairzadze
- gminaistebna
+ - gminaiwanowice
- gminaiwierzyce
- gminaiwoniczzdroj
- gminaizabelin
- gminaizbica
- - gminajadow
+ - gminaizbicko
+ - gminajablon
- gminajaktorow
+ - gminajakubow
- gminajanikowo
+ - gminajanow
- gminajanowiec
- gminajanowpodlaski
- - gminajaraczewo
+ - gminajarczow
- gminajarocin
- gminajasienicarosielna
+ - gminajasliska
- gminajaslo
- gminajastkow
- gminajastrowie
- gminajastrzab
- gminajedlicze
- - gminajedlinsk
- - gminajedlnialetnisko
- gminajejkowice
- gminajemielnica
- - gminajemielno
- gminajerzmanowa
- gminajezewo
- gminajeziorawielkie
- gminajeziorzany
- gminajezowe
+ - gminajoniec
- gminajordanow
- gminajozefow
- gminajozefownadwisla
@@ -1699,14 +1934,18 @@
- gminakakolewnica
- gminakamien
- gminakamienica
- - gminakamieniec
+ - gminakamiennik
- gminakamionka
- gminakarczmiska
- gminakargowa
+ - gminakarlino
+ - gminakarniewo
- gminakaweczyn
- gminakazimierzbiskupi
- gminakepice
+ - gminakesowo
- gminakielczyglow
+ - gminakietrz
- gminakikol
- gminakiszkowo
- gminakleczew
@@ -1721,22 +1960,30 @@
- gminaklucze
- gminakluczewsko
- gminakobielewielkie
+ - gminakobylanka
- gminakochanowice
- gminakock
- gminakodrab
- gminakolaczyce
- gminakolbaskowo
+ - gminakolbiel
- gminakolczyglowy
+ - gminakolobrzeg
- gminakoluszki
- gminakomancza
+ - gminakomarowkapodlaska
- gminakomorniki
- gminakomprachcice
- gminakonarzyny
- gminakondratowice
+ - gminakoneck
- gminakoniusza
- gminakonopiska
- gminakonskowola
+ - gminakonstantynow
- gminakoprzywnica
+ - gminakorfantow
+ - gminakornik
- gminakorsze
- gminakorycin
- gminakorzenna
@@ -1746,10 +1993,14 @@
- gminakoscierzyna
- gminakosowlacki
- gminakostrzyn
- - gminakoszyce
+ - gminakoszecin
- gminakotla
- gminakotun
+ - gminakowiesy
+ - gminakozieglowy
- gminakozlow
+ - gminakramsk
+ - gminakrasniczyn
- gminakrasnik
- gminakrasnobrod
- gminakrasnystaw
@@ -1759,12 +2010,16 @@
- gminakrosnice
- gminakrupskimlyn
- gminakruszwica
+ - gminakrynice
- gminakrynki
- gminakrzanowice
- gminakrzemieniewo
+ - gminakrzeszow
- gminakrzymow
+ - gminakrzywcza
- gminakrzywin
- gminakrzyzanowice
+ - gminaksawerow
- gminaksiazwielki
- gminakunice
- gminakunow
@@ -1774,15 +2029,19 @@
- gminakwilcz
- gminalabowa
- gminalabunie
+ - gminalaczna
+ - gminaladek
- gminalambinowice
- gminalanckorona
+ - gminalancut
+ - gminalapanow
- gminalapszenizne
- gminalasin
- gminalaskarzew
- gminalasowicewielkie
- gminalaszczow
- - gminalaszki
- gminalatowicz
+ - gminalaziska
- gminalazy
- gminaleczyca
- gminaleczyce
@@ -1792,11 +2051,14 @@
- gminalelow
- gminalesna
- gminalesnapodlaska
+ - gminalesniowice
- gminalesznowola
- gminalezajsk
- gminalichnowy
- gminalimanowa
- gminalinia
+ - gminaliniewo
+ - gminalipiany
- gminalipinki
- gminalipnik
- gminalipowa
@@ -1804,43 +2066,51 @@
- gminaliszki
- gminaliw
- gminalobez
+ - gminalochow
- gminalodygowice
- gminalomazy
+ - gminalomianki
+ - gminaloniow
- gminalopiennikgorny
- gminalopuszno
+ - gminalosice
- gminaluban
- gminalubartow
- gminalubasz
+ - gminalubawka
- gminalubenia
- gminalubianka
- gminalubicz
+ - gminalubien
- gminalubiewo
- gminalubin
- gminalubniany
- gminalubochnia
- - gminalubomia
- gminalubon
+ - gminalubsza
+ - gminalubyczakrolewska
- gminalukow
- gminalukowica
- gminalutowiska
+ - gminalututow
- gminaluzino
- gminaluzna
- gminalysomice
+ - gminamaciejowice
- gminamagnuszew
+ - gminamajdankrolewski
- gminamakowpodhalanski
- - gminamalawies
- gminamalbork
- gminamaldyty
- gminamalkiniagorna
- gminamarcinowice
- gminamargonin
- gminamarianowo
- - gminamarkusy
- - gminamaslow
+ - gminamarkuszow
+ - gminamecinka
- gminamedyka
- gminamelgiew
- gminamichalow
- - gminamichalowo
- gminamiedzianagora
- gminamiedzna
- gminamiedzno
@@ -1849,7 +2119,10 @@
- gminamiedzyrzecpodlaski
- gminamiedzyzdroje
- gminamiejscepiastowe
+ - gminamiekinia
- gminamielec
+ - gminamielno
+ - gminamieszkowice
- gminamilanow
- gminamilejow
- gminamilicz
@@ -1858,21 +2131,26 @@
- gminamiloslaw
- gminamilowka
- gminaminskmazowiecki
+ - gminamirow
- gminamirsk
- gminamlynary
+ - gminamodliborzyce
- gminamogielnica
- gminamogilany
+ - gminamogilno
+ - gminamorawica
- gminamordy
- gminamoryn
- gminamrocza
- gminamrozy
+ - gminamsciwojow
+ - gminamstow
- gminamszana
- gminamszanadolna
- gminamurow
- gminamycielin
- - gminamyslakowice
+ - gminamykanow
- gminamysliborz
- - gminanadarzyn
- gminanamyslow
- gminanasielsk
- gminanawojowa
@@ -1883,23 +2161,25 @@
- gminaniedrzwicaduza
- gminaniedzwiada
- gminaniedzwiedz
- - gminaniegoslawice
- - gminaniwiska
+ - gminanowakarczma
- gminanowaruda
- gminanowawiesleborska
+ - gminanowe
- gminanowemiasto
- gminanowemiastonadwarta
- - gminanowogrodbobrzanski
+ - gminanowogrod
- gminanowosolna
- gminanowykaweczyn
+ - gminanowykorczyn
- gminanowystaw
- gminanowytarg
- gminanowytomysl
+ - gminanozdrzec
- gminanur
- gminaobrazow
- gminaochotnicadolna
- gminaogrodzieniec
- - gminaolecko
+ - gminaolszanica
- gminaolsztynek
- gminaolszyna
- gminaopatowiec
@@ -1909,11 +2189,15 @@
- gminaosiekjasielski
- gminaosiekmaly
- gminaosielsko
+ - gminaosina
+ - gminaosjakow
+ - gminaostrorog
- gminaostrow
- gminaostrowek
- gminaostrowlubelski
- gminaostrowmazowiecka
- gminaostrowwielkopolski
+ - gminaotmuchow
- gminaotyn
- gminaozarow
- gminaozarowice
@@ -1921,27 +2205,32 @@
- gminaozorkow
- gminapabianice
- gminapacanow
+ - gminapacyna
- gminapaczkow
- gminapadewnarodowa
- - gminapajeczno
- gminapakoslaw
- gminapakoslawice
- gminapalecznica
- gminapanki
- gminaparchowo
- gminaparczew
- - gminapawlosiow
+ - gminapaslek
+ - gminapatnow
- gminapawlowice
- gminapawlowiczki
+ - gminapawonkow
- gminapeclaw
- gminapelplin
+ - gminapepowo
- gminapiaski
- gminapiatnica
- - gminapiecki
- gminapiekoszow
+ - gminapieniezno
- gminapilchowice
+ - gminapinczow
- gminapionki
- - gminapiotrkowtrybunalski
+ - gminaplaska
+ - gminaplaterowka
- gminaplesna
- gminapleszew
- gminaplonsk
@@ -1949,6 +2238,7 @@
- gminapoczesna
- gminapodedworze
- gminapodegrodzie
+ - gminapodgorzyn
- gminapokoj
- gminapolajewo
- gminapolaniec
@@ -1957,16 +2247,18 @@
- gminapolice
- gminapolkowice
- gminapomiechowek
+ - gminaponiatowa
- gminapopielow
- gminapopow
- - gminaporaj
- gminapotegowo
+ - gminapotokwielki
- gminapraszka
- - gminaprazmow
- gminaprochowice
- gminapromna
- gminaproszkow
+ - gminaprusice
- gminapruszczgdanski
+ - gminaprzechlewo
- gminaprzeclaw
- gminaprzedecz
- gminaprzemet
@@ -1976,7 +2268,9 @@
- gminaprzodkowo
- gminaprzykona
- gminaprzylek
+ - gminaprzyrow
- gminaprzystajn
+ - gminaprzytoczna
- gminapuchaczow
- gminapuck
- gminapulawy
@@ -1984,10 +2278,10 @@
- gminapuszczamarianska
- gminapysznica
- gminapyzdry
+ - gminarabawyzna
- gminarachanie
- gminaraciechowice
- - gminaraclawice
- - gminaradecznica
+ - gminaradgoszcz
- gminaradkow
- gminaradlow
- gminaradomin
@@ -1995,16 +2289,29 @@
- gminaradomyslnadsanem
- gminaradoszyce
- gminaradwanice
+ - gminaradymno
+ - gminaradziejow
- gminaradzilow
+ - gminarajgrod
+ - gminarakow
+ - gminarakszawa
- gminarawamazowiecka
+ - gminaregnow
- gminarenskawies
+ - gminarogozno
+ - gminarokitno
+ - gminaropa
- gminarossosz
- gminarozprza
- gminarucianenida
- gminarudahuta
- gminarudna
- gminarudniki
+ - gminarudniknadsanem
+ - gminarudziniec
- gminarusiec
+ - gminarusinow
+ - gminarybczewice
- gminarychliki
- gminarychtal
- gminaryczywol
@@ -2012,32 +2319,39 @@
- gminarypin
- gminarytro
- gminarytwiany
- - gminarzasnia
- gminarzeczyca
- gminarzepiennikstrzyzewski
- gminarzepin
+ - gminarzezawa
- gminarzgow
- gminasadki
- gminasadowne
- gminasamborzec
- gminasanok
+ - gminasawin
- gminascinawa
- gminasedziejowice
+ - gminasejny
+ - gminasekowa
- gminasepopol
- gminaserokomla
- gminasianow
- gminasicienko
- gminasieciechow
- gminasiedlce
+ - gminasiedliszcze
- gminasiemiatycze
+ - gminasiemien
- gminasiemysl
- gminasiennica
- gminasiennicarozana
- gminasienno
- gminasiepraw
- gminasieradz
+ - gminasierakow
- gminasierakowice
- gminasiewierz
+ - gminasitkowkanowiny
- gminasitno
- gminaskarzyskokoscielne
- gminaskepe
@@ -2045,16 +2359,22 @@
- gminaskoczow
- gminaskoki
- gminaskolyszyn
+ - gminaskrwilno
- gminaskrzyszow
- gminaskulsk
+ - gminaskwierzyna
- gminaslawa
+ - gminasliwice
- gminaslopnice
+ - gminaslubice
- gminaslupca
- gminaslupia
+ - gminaslupiakonecka
+ - gminasmigiel
- gminasobieniejeziory
+ - gminasobolew
- gminasobotka
- gminasokolka
- - gminasokoly
- gminasolina
- gminasosnicowice
- gminasosnie
@@ -2069,11 +2389,16 @@
- gminastaremiasto
- gminastarepole
- gminastarogardgdanski
+ - gminastarybrus
+ - gminastarydzierzgon
+ - gminastarytarg
- gminastawiszyn
+ - gminastepnica
- gminastoczeklukowski
- gminastopnica
- gminastrawczyn
- gminastrykow
+ - gminastryszawa
- gminastryszow
- gminastrzalkowo
- gminastrzelceopolskie
@@ -2082,38 +2407,43 @@
- gminastrzyzewice
- gminastupsk
- gminasubkowy
+ - gminasuchan
- gminasuchedniow
- gminasuchozebry
- gminasuchylas
- gminasulechow
- gminasulecin
+ - gminasulejow
- gminasulikow
- gminasulmierzyce
- gminasulow
- gminasusiec
- - gminaswierklaniec
+ - gminaswiercze
+ - gminaswierczow
+ - gminaswierklany
- gminaswierzawa
- gminaswieszyno
- gminaswilcza
- gminaszadek
- gminaszaflary
- gminaszastarka
+ - gminaszczawinkoscielny
- gminaszczebrzeszyn
- gminaszczekociny
- gminaszczercow
- - gminaszczutowo
- gminaszczytna
- gminaszczytniki
- - gminaszemud
+ - gminaszczytno
- gminaszerzyny
- gminaszlichtyngowa
+ - gminaszrensk
+ - gminaszudzialowo
- gminaszydlow
- gminatarlow
- gminatarnow
- gminatarnowiec
- gminatarnowopolski
- gminateresin
- - gminaterespol
- gminatereszpol
- gminatluchowo
- gminatluszcz
@@ -2123,12 +2453,15 @@
- gminatoszek
- gminatrabkiwielkie
- gminatrzebiatow
+ - gminatrzebielino
- gminatrzebinia
- - gminatrzeszczany
- gminatrzyciaz
+ - gminatrzydnikduzy
- gminatuchow
+ - gminatulowice
- gminaturosnkoscielna
- gminatuszownarodowy
+ - gminatworog
- gminatyczyn
- gminatymbark
- gminatyrawawoloska
@@ -2137,15 +2470,21 @@
- gminaulanmajorat
- gminaulanow
- gminaulez
+ - gminaulhowek
- gminaurszulin
- gminaurzedow
+ - gminausciegorlickie
- gminauscimow
- gminawachock
+ - gminawadrozewielkie
- gminawagrowiec
+ - gminawalce
- gminawapielsk
- gminawasilkow
+ - gminawasosz
- gminawawolnica
- gminawejherowo
+ - gminawerbkowice
- gminawiazow
- gminawiazowna
- gminawicko
@@ -2153,16 +2492,21 @@
- gminawielbark
- gminawielen
- gminawielgie
+ - gminawielgomlyny
- gminawieliszew
- gminawielkanieszawka
- gminawieniawa
- gminawieprz
- gminawieruszow
+ - gminawierzbinek
- gminawierzbno
+ - gminawierzchlas
- gminawierzchoslawice
- gminawietrzychowice
- gminawijewo
+ - gminawilczyce
- gminawilczyn
+ - gminawilkolaz
- gminawilkow
- gminawilkowice
- gminawinnica
@@ -2173,12 +2517,14 @@
- gminawitkowo
- gminawladyslawow
- gminawlen
+ - gminawloclawek
- gminawlodawa
- gminawloszczowa
- gminawodzierady
- gminawodzislaw
- gminawojcieszkow
- gminawojnicz
+ - gminawojslawice
- gminawolakrzysztoporska
- gminawolanow
- gminawolbrom
@@ -2189,15 +2535,18 @@
- gminawreczycawielka
- gminawronki
- gminawyrzysk
- - gminazabierzow
+ - gminawysokie
- gminazabno
- gminazagan
- - gminazagorz
+ - gminazagorow
- gminazaklikow
- gminazakroczym
- gminazakrzowek
+ - gminazalesie
- gminazaleszany
+ - gminazaluski
- gminazamosc
+ - gminazarnow
- gminazarnowiec
- gminazarow
- gminazarszyn
@@ -2209,20 +2558,26 @@
- gminazbojno
- gminazbroslawice
- gminazdunskawola
- - gminazduny
- gminazdzieszowice
+ - gminazebowice
- gminazebrzydowice
+ - gminazegocina
- gminazelazkow
+ - gminazembrzyce
- gminazgierz
- gminazgorzelec
- gminaziebice
- gminazielonki
- gminazlawieswielka
+ - gminazlota
+ - gminazlotnikikujawskie
- gminazmudz
- gminaznin
- gminazolkiewka
- gminazolynia
- gminazukowice
+ - gminazurawica
+ - gminazyrakow
- gminazyrzyn
- gminazytno
- gniezno
@@ -2231,19 +2586,19 @@
- gora
- gorakalwaria
- gorlice
+ - gorzno
- gorzowslaski
- gorzowwielkopolski
- gostynin
- grajewo
- grodziskmazowiecki
- - gronowoelblaskie
- grudziadz
+ - grybow
- gryfino
- gryfowslaski
- hel
- hrubieszow
- inowroclaw
- - iwanowice
- izbicakujawska
- jablonowopomorskie
- janowiecwielkopolski
@@ -2253,7 +2608,6 @@
- jaslo
- jastrzebiezdroj
- jawor
- - jaworzno
- jedlinazdroj
- jelczlaskowice
- jeleniagora
@@ -2274,9 +2628,9 @@
- kepno
- ketrzyn
- kielce
- - kielczyglow
- klodawa
- klodzko
+ - kluczbork
- knurow
- kobylka
- kolo
@@ -2306,11 +2660,13 @@
- krzeszowice
- krzyzwielkopolski
- ksiazwielkopolski
- - kudowazdroj
- kujawskopomorskie
+ - kutno
- kuzniaraciborska
+ - kwidzyn
- labiszyn
- ladekzdroj
+ - lancut
- lapy
- lask
- laskarzew
@@ -2322,10 +2678,10 @@
- legnica
- leszno
- lewinbrzeski
+ - lewinbrzeski2
- lezajsk
- limanowa
- lipno
- - lipsko
- lodz
- lodzkie
- lowicz
@@ -2342,11 +2698,8 @@
- lwowekslaski
- malbork
- malopolskie
- - marciszow
- marki
- - maslowice
- mazowieckie
- - miastko
- michalowice
- miechow
- miedzyrzecpodlaski
@@ -2354,6 +2707,7 @@
- mielec
- milanowek
- minskmazowiecki
+ - mniszkow
- mosina
- mragowo
- mragowski
@@ -2363,18 +2717,17 @@
- myslowice
- myszkow
- naklonadnotecia
- - nasielsk
- niemodlin
- niepolomice
- nisko
- nowadeba
- nowasarzyna
+ - nowasol
- nowemiasteczko
- noweskalmierzyce
- nowogard
- nowogrodbobrzanski
- nowogrodziec
- - nowosolna
- nowydwormazowiecki
- nowysacz
- nowytarg
@@ -2388,6 +2741,8 @@
- opoczno
- opole
- opolelubelskie
+ - opolskie
+ - orzesze
- osieczna
- osiecznica
- ostroda
@@ -2405,13 +2760,16 @@
- piekaryslaskie
- piensk
- pila
+ - pilzno
- piotrkowtrybunalski
- pisz
- plock
- plonsk
- pniewy
+ - pobiedziska
- podkarpackie
- podkowalesna
+ - podlaskie
- polczynzdroj
- pomorskie
- poniec
@@ -2420,7 +2778,7 @@
- powiataugustowski
- powiatbedzinski
- powiatbelchatowski
- - powiatbialobrzeski
+ - powiatbialostocki
- powiatbialski
- powiatbielski
- powiatbieszczadzki
@@ -2446,6 +2804,7 @@
- powiatczluchowski
- powiatdabrowski
- powiatdebicki
+ - powiatdrawski
- powiatdzialdowski
- powiatdzierzoniowski
- powiatelblaski
@@ -2460,10 +2819,11 @@
- powiatgoleniowski
- powiatgolubskodobrzynski
- powiatgorlicki
+ - powiatgorowski
- powiatgorzowski
- powiatgostynski
+ - powiatgrajewski
- powiatgrojecki
- - powiatgrudziadzki
- powiatgryficki
- powiatgryfinski
- powiathajnowski
@@ -2478,6 +2838,7 @@
- powiatjedrzejowski
- powiatjeleniogorski
- powiatkaliski
+ - powiatkamiennogorski
- powiatkamienski
- powiatkartuski
- powiatkazimierski
@@ -2502,6 +2863,7 @@
- powiatkrosnienski
- powiatkrotoszynski
- powiatkutnowski
+ - powiatlancucki
- powiatlaski
- powiatleborski
- powiatleczycki
@@ -2516,6 +2878,7 @@
- powiatlipski
- powiatlobeski
- powiatlodzkiwschodni
+ - powiatlosicki
- powiatlowicki
- powiatlubaczowski
- powiatlubanski
@@ -2536,9 +2899,11 @@
- powiatmyslenicki
- powiatmyszkowski
- powiatnakielski
+ - powiatnamyslowski
- powiatnidzicki
- powiatnizanski
- powiatnowodworski
+ - powiatnowomiejski
- powiatnowosadecki
- powiatnowosolski
- powiatnowotarski
@@ -2574,7 +2939,6 @@
- powiatproszowicki
- powiatprudnicki
- powiatpruszkowski
- - powiatprzasnyski
- powiatprzemyski
- powiatprzeworski
- powiatprzysuski
@@ -2597,6 +2961,7 @@
- powiatrzeszowski
- powiatsandomierski
- powiatsanocki
+ - powiatsejnenski
- powiatsepolenski
- powiatsiedlecki
- powiatsiemiatycki
@@ -2624,6 +2989,7 @@
- powiatswidnicki
- powiatswidwinski
- powiatswiebodzinski
+ - powiatswiecki
- powiatszamotulski
- powiatszczycienski
- powiatsztumski
@@ -2642,6 +3008,7 @@
- powiatwagrowiecki
- powiatwalecki
- powiatwarszawskizachodni
+ - powiatwegorzewski
- powiatwegrowski
- powiatwejherowski
- powiatwielicki
@@ -2661,7 +3028,6 @@
- powiatwyszkowski
- powiatzabkowicki
- powiatzaganski
- - powiatzambrowski
- powiatzamojski
- powiatzarski
- powiatzawiercianski
@@ -2672,34 +3038,33 @@
- powiatzlotoryjski
- powiatzlotowski
- powiatzninski
- - powiatzurominski
- powiatzyrardowski
- powiatzywiecki
- poznan
- - prostki
- proszowice
- prudnik
+ - pruszczgdanski
- pruszkow
- przasnysz
- przemysl
- przeworsk
- przysucha
- pszczyna
- - pszow
- puck
- pulawy
+ - pultusk
+ - puszczykowo
- pyskowice
- rabkazdroj
- raciaz
- raciborz
- - raciechowice
- radom
- radomsko
+ - radomyslwielki
- radymno
- radziejow
- radzionkow
- radzynpodlaski
- - rakow
- rawamazowiecka
- rawicz
- reda
@@ -2713,6 +3078,7 @@
- rymanow
- rypin
- rzeszow
+ - rzeszowprojekt
- sandomierz
- sanok
- sedziszowmalopolski
@@ -2720,7 +3086,6 @@
- siedlce
- siemianowiceslaskie
- siemiatycze
- - sieniawa
- sieradz
- skarzyskokamienna
- skawina
@@ -2739,17 +3104,15 @@
- srodaslaska
- srodawielkopolska
- starachowice
+ - stargard
- starogardgdanski
- starysacz
- staszow
- stronieslaskie
- - strzegom
- strzyzow
- - suchylas
- sulejowek
- sulkowice
- sulmierzyce
- - suwalski
- swarzedz
- swidnica
- swidnik
@@ -2772,8 +3135,10 @@
- terespol
- tomaszowlubelski
- tomaszowmazowiecki
+ - tomaszowmazowieckiprojekt
- torun
- trzcianka
+ - trzcinskozdroj
- trzebnica
- trzemeszno
- tuliszkow
@@ -2786,7 +3151,7 @@
- ustrzykidolne
- wadowice
- wagrowiec
- - walbrzych
+ - walcz
- warminskomazurskie
- warszawa
- wasosz
@@ -2795,7 +3160,7 @@
- wiecbork
- wieliczka
- wielkopolskie
- - wizna
+ - wielun
- wladyslawowo
- wloclawek
- wlodawa
@@ -2824,6 +3189,7 @@
- zielonagora
- zielonka
- zlotoryja
+ - zlotow
- zory
- zwolen
- zyrardow
diff --git a/app/src/test/java/io/github/wulkanowy/data/db/migrations/AbstractMigrationTest.kt b/app/src/test/java/io/github/wulkanowy/data/db/migrations/AbstractMigrationTest.kt
index cc31d8933..18249ba8b 100644
--- a/app/src/test/java/io/github/wulkanowy/data/db/migrations/AbstractMigrationTest.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/db/migrations/AbstractMigrationTest.kt
@@ -3,6 +3,7 @@ package io.github.wulkanowy.data.db.migrations
import android.content.Context
import androidx.preference.PreferenceManager
import androidx.room.Room
+import androidx.room.migration.Migration
import androidx.room.testing.MigrationTestHelper
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
import androidx.test.core.app.ApplicationProvider
@@ -16,7 +17,7 @@ abstract class AbstractMigrationTest {
val dbName = "migration-test"
- val context: Context get() = ApplicationProvider.getApplicationContext()
+ private val context: Context get() = ApplicationProvider.getApplicationContext()
@get:Rule
val helper: MigrationTestHelper = MigrationTestHelper(
@@ -25,6 +26,10 @@ abstract class AbstractMigrationTest {
FrameworkSQLiteOpenHelperFactory()
)
+ fun runMigrationsAndValidate(migration: Migration) {
+ helper.runMigrationsAndValidate(dbName, migration.endVersion, true, migration).close()
+ }
+
fun getMigratedRoomDatabase(): AppDatabase {
val database = Room.databaseBuilder(
ApplicationProvider.getApplicationContext(),
diff --git a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration12Test.kt b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration12Test.kt
index a02904733..f614c8ca9 100644
--- a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration12Test.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration12Test.kt
@@ -33,7 +33,7 @@ class Migration12Test : AbstractMigrationTest() {
close()
}
- helper.runMigrationsAndValidate(dbName, 12, true, Migration12())
+ runMigrationsAndValidate(Migration12())
val db = getMigratedRoomDatabase()
val students = runBlocking { db.studentDao.loadAll() }
@@ -49,6 +49,7 @@ class Migration12Test : AbstractMigrationTest() {
assertEquals(2, studentId)
assertEquals(6, classId)
}
+ db.close()
}
@Test
@@ -62,7 +63,7 @@ class Migration12Test : AbstractMigrationTest() {
close()
}
- helper.runMigrationsAndValidate(dbName, 12, true, Migration12())
+ runMigrationsAndValidate(Migration12())
val db = getMigratedRoomDatabase()
val students = runBlocking { db.studentDao.loadAll() }
@@ -73,6 +74,7 @@ class Migration12Test : AbstractMigrationTest() {
assertEquals(2, studentId)
assertEquals(1, classId)
}
+ db.close()
}
@Test
@@ -88,7 +90,7 @@ class Migration12Test : AbstractMigrationTest() {
close()
}
- helper.runMigrationsAndValidate(dbName, 12, true, Migration12())
+ runMigrationsAndValidate(Migration12())
val db = getMigratedRoomDatabase()
val students = runBlocking { db.studentDao.loadAll() }
@@ -107,6 +109,7 @@ class Migration12Test : AbstractMigrationTest() {
assertEquals(studentId, 3)
assertEquals(true, isCurrent)
}
+ db.close()
}
private fun createStudent(db: SupportSQLiteDatabase, studentId: Int, isCurrent: Boolean) {
diff --git a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration13Test.kt b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration13Test.kt
index bdfb4137d..b0c03fb11 100644
--- a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration13Test.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration13Test.kt
@@ -57,6 +57,8 @@ class Migration13Test : AbstractMigrationTest() {
assertEquals("C", className)
assertEquals("Publiczna szkoła Wulkanowego-fejka nr 2 w fakelog.cf", schoolName)
}
+
+ db.close()
}
@Test
@@ -85,6 +87,8 @@ class Migration13Test : AbstractMigrationTest() {
assertEquals("", className)
assertEquals("Publiczna szkoła Wulkanowego-fejka nr 1 w fakelog.cf", schoolName)
}
+
+ db.close()
}
@Test
@@ -148,6 +152,7 @@ class Migration13Test : AbstractMigrationTest() {
assertFalse(semesters[2].second)
assertTrue(semesters[3].second)
}
+ db.close()
}
private fun getSemesters(db: SupportSQLiteDatabase, query: String): List> {
diff --git a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration27Test.kt b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration27Test.kt
index 8e744f27a..19eda9ba8 100644
--- a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration27Test.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration27Test.kt
@@ -27,7 +27,7 @@ class Migration27Test : AbstractMigrationTest() {
close()
}
- helper.runMigrationsAndValidate(dbName, 27, true, Migration27())
+ runMigrationsAndValidate(Migration27())
val db = getMigratedRoomDatabase()
val students = runBlocking { db.studentDao.loadAll() }
@@ -39,6 +39,8 @@ class Migration27Test : AbstractMigrationTest() {
assertEquals(123, userLoginId)
assertEquals("Student Jan", userName)
}
+
+ db.close()
}
@Test
@@ -49,7 +51,7 @@ class Migration27Test : AbstractMigrationTest() {
close()
}
- helper.runMigrationsAndValidate(dbName, 27, true, Migration27())
+ runMigrationsAndValidate(Migration27())
val db = getMigratedRoomDatabase()
val students = runBlocking { db.studentDao.loadAll() }
@@ -61,6 +63,8 @@ class Migration27Test : AbstractMigrationTest() {
assertEquals(2, userLoginId)
assertEquals("Unit Jan", userName)
}
+
+ db.close()
}
@Test
@@ -73,7 +77,7 @@ class Migration27Test : AbstractMigrationTest() {
close()
}
- helper.runMigrationsAndValidate(dbName, 27, true, Migration27())
+ runMigrationsAndValidate(Migration27())
val db = getMigratedRoomDatabase()
val students = runBlocking { db.studentDao.loadAll() }
@@ -90,6 +94,8 @@ class Migration27Test : AbstractMigrationTest() {
assertEquals(333, userLoginId)
assertEquals("Unit Tomasz", userName)
}
+
+ db.close()
}
private fun createStudent(db: SupportSQLiteDatabase, id: Long, userLoginId: Int, studentName: String) {
diff --git a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration35Test.kt b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration35Test.kt
index 883cdb81c..79c24f2e6 100644
--- a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration35Test.kt
+++ b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration35Test.kt
@@ -29,7 +29,7 @@ class Migration35Test : AbstractMigrationTest() {
close()
}
- helper.runMigrationsAndValidate(dbName, 35, true, Migration35(AppInfo()))
+ runMigrationsAndValidate(Migration35(AppInfo()))
val db = getMigratedRoomDatabase()
val students = runBlocking { db.studentDao.loadAll() }
@@ -38,6 +38,8 @@ class Migration35Test : AbstractMigrationTest() {
assertTrue { students[0].avatarColor in AppInfo().defaultColorsForAvatar }
assertTrue { students[1].avatarColor in AppInfo().defaultColorsForAvatar }
+
+ db.close()
}
private fun createStudent(db: SupportSQLiteDatabase, id: Long) {
diff --git a/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration54Test.kt b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration54Test.kt
new file mode 100644
index 000000000..1855e0d50
--- /dev/null
+++ b/app/src/test/java/io/github/wulkanowy/data/db/migrations/Migration54Test.kt
@@ -0,0 +1,130 @@
+package io.github.wulkanowy.data.db.migrations
+
+import android.content.ContentValues
+import android.database.sqlite.SQLiteDatabase
+import android.os.Build
+import androidx.sqlite.db.SupportSQLiteDatabase
+import dagger.hilt.android.testing.HiltAndroidTest
+import dagger.hilt.android.testing.HiltTestApplication
+import io.github.wulkanowy.sdk.Sdk
+import io.github.wulkanowy.sdk.Sdk.ScrapperLoginType.*
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+import kotlin.random.Random
+import kotlin.test.assertEquals
+
+@HiltAndroidTest
+@RunWith(RobolectricTestRunner::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+@Config(sdk = [Build.VERSION_CODES.O_MR1], application = HiltTestApplication::class)
+class Migration54Test : AbstractMigrationTest() {
+
+ @Test
+ fun `don't touch unrelated students`() = runTest {
+ with(helper.createDatabase(dbName, 53)) {
+ createStudent(1, STANDARD, "vulcan.net.pl", "rzeszow", "Jan Michniewicz")
+ createStudent(2, ADFSLight, "umt.tarnow.pl", "tarnow", "Joanna Marcinkiewicz")
+ close()
+ }
+
+ runMigrationsAndValidate(Migration54())
+ val db = getMigratedRoomDatabase()
+ val students = db.studentDao.loadAll()
+
+ assertEquals(2, students.size)
+ with(students[0]) {
+ assertEquals(STANDARD.name, loginType)
+ assertEquals("https://vulcan.net.pl", scrapperBaseUrl)
+ assertEquals("rzeszow", symbol)
+ }
+ with(students[1]) {
+ assertEquals(ADFSLight.name, loginType)
+ assertEquals("https://umt.tarnow.pl", scrapperBaseUrl)
+ assertEquals("tarnow", symbol)
+ }
+ db.close()
+ }
+
+ @Test
+ fun `remove tomaszow mazowiecki students`() = runTest {
+ with(helper.createDatabase(dbName, 53)) {
+ createStudent(1, STANDARD, "vulcan.net.pl", "rzeszow", "Jan Michniewicz")
+ createStudent(2, STANDARD, "vulcan.net.pl", "tomaszowmazowiecki", "Joanna Stec")
+ createStudent(3, STANDARD, "vulcan.net.pl", "tomaszowmazowiecki", "Kacper Morawiecki")
+ close()
+ }
+
+ runMigrationsAndValidate(Migration54())
+ val db = getMigratedRoomDatabase()
+ val students = db.studentDao.loadAll()
+ assertEquals(1, students.size)
+ with(students[0]) {
+ assertEquals("rzeszow", symbol)
+ }
+ db.close()
+ }
+
+ @Test
+ fun `migrate resman students`() = runTest {
+ with(helper.createDatabase(dbName, 53)) {
+ createStudent(1, ADFSLight, "resman.pl", "rzeszow", "Joanna Stec")
+ createStudent(2, ADFSLight, "resman.pl", "rzeszow", "Kacper Morawiecki")
+ createStudent(3, STANDARD, "vulcan.net.pl", "rzeszow", "Jan Michniewicz")
+ close()
+ }
+ runMigrationsAndValidate(Migration54())
+ val db = getMigratedRoomDatabase()
+ val students = db.studentDao.loadAll()
+ assertEquals(3, students.size)
+ with(students[0]) {
+ assertEquals(ADFSLightScoped.name, loginType)
+ assertEquals("https://vulcan.net.pl", scrapperBaseUrl)
+ assertEquals("rzeszowprojekt", symbol)
+ }
+ with(students[1]) {
+ assertEquals(ADFSLightScoped.name, loginType)
+ assertEquals("https://vulcan.net.pl", scrapperBaseUrl)
+ assertEquals("rzeszowprojekt", symbol)
+ }
+ db.close()
+ }
+
+ private fun SupportSQLiteDatabase.createStudent(
+ id: Long,
+ loginType: Sdk.ScrapperLoginType,
+ host: String,
+ symbol: String,
+ studentName: String,
+ ) {
+ insert("Students", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply {
+ put("scrapper_base_url", "https://$host")
+ put("mobile_base_url", "")
+ put("login_type", loginType.name)
+ put("login_mode", "SCRAPPER")
+ put("certificate_key", "")
+ put("private_key", "")
+ put("is_parent", false)
+ put("email", "jan@fakelog.cf")
+ put("password", "******")
+ put("symbol", symbol)
+ put("student_id", Random.nextInt())
+ put("user_login_id", id)
+ put("user_name", studentName)
+ put("student_name", studentName)
+ put("school_id", "123")
+ put("school_short", "")
+ put("school_name", "")
+ put("class_name", "")
+ put("class_id", Random.nextInt())
+ put("is_current", false)
+ put("registration_date", "0")
+ put("id", id)
+ put("nick", "")
+ put("avatar_color", "")
+ })
+ }
+}
diff --git a/build.gradle b/build.gradle
index e8e1052b6..174a3cb6d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -31,6 +31,7 @@ allprojects {
mavenCentral()
google()
maven { url "https://jitpack.io" }
+ maven { url "https://s01.oss.sonatype.org/content/repositories/snapshots/" }
maven { url "https://developer.huawei.com/repo/" }
}
}
From 2fa26c37a95a0fa34765c6de73121eb26dffe094 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Pich?=
Date: Tue, 20 Dec 2022 21:55:46 +0100
Subject: [PATCH 160/164] Revert "Fix app name in french (#2072)"
This reverts commit 277ffd22be786cfa429ea1d61827e8cb62d1ea56.
---
app/build.gradle | 2 +-
gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 59536 bytes
gradle/wrapper/gradle-wrapper.properties | 2 +-
3 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index b0865896e..6b496d85a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -237,7 +237,7 @@ dependencies {
implementation 'com.github.bastienpaulfr:Treessence:1.0.5'
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
implementation "io.coil-kt:coil:2.2.2"
- implementation "io.github.wulkanowy:AppKillerManager:3.0.1"
+ implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 41d9927a4d4fb3f96a785543079b8df6723c946b..7454180f2ae8848c63b8b4dea2cb829da983f2fa 100644
GIT binary patch
delta 8722
zcmZ2`nR&uR<_#=Xtd=<A22h#!CTC;u*7}a*FjIYPB48
zax%;nQc!GRSu*zx-)zOr#;@P#G*$)Vu65u0dTQ1D2-l@Ia-1$6`|XguH~(VTT6f#m
z^5248YxC30Z{F3>G@O6_-?{R?_kQpD{@eH5-{%Y48P^=Lf0oFslQ-$ko(a;kXN#Ek
z_0)?kQI(k}c&MXgu~EvB%Ay|k?d>0w-o>BM)_?eH=^dHp&-f%c_xQM($DKPn_j7@G
z+`+}WQ}+n1Pnr~dx`Ou|=fkZ&zjg`4o!@j%;c;(;@cKPFWxhYs_4yGtZ{J#(z&(3q
z4EHq8z9{hS@ze5C72@}FlP9e8cwl>HPxztVP8IbW^7R}Kn-yz3+=T7UNXsW?s;kt5
z9J9Kkf0@%>?crk~Kd&Dx4o3yAMkGcAUX{2o+5Baj+J*&>H&nUwz6fi1F3oysrrNUQ
zbIk6FMNFA}^H;*Hi@KYyn=PB+bGGwK*>>T}sXk&`&p21v^Q%=`Usqk?Z1nPz}n@J$v?Ta5mq%t|Td7
z^Y<0aGVQ1M_)f=Ny;eCd_RD8Y)+uF|RX(=O^2#*Xn>B6nnv7-6zdeQOT~{tzw#{Nk
z*Sm>Z`7$pia?USF^|2?+F=V!BlGHRQd|%irp)^hCZzss}?`
z*I7?Hvvd8fj|>rE`oTa=w5D(N`Omk+Ke)2SADS*&
z!x}&JgDGqLaZA?w2h3G%7Cnfr2syajQ1hWR*S_xeoGh~@t$M5R!>-Q3?J0x9uGNtb
z`BndT9PFR@TK&h$mid}LEbA6Nu&G=5AiToo;Nu_lTbu50_;+8)Z${>2p0kN%hvX~o
zZ0eu5K>dR?=l<{y?0*6ePW~~u$^NmvOAOPDmK9;zxkpy{o?huUd;9B?SzZgWjxX{v
z;cVGuYMMGzSLN&ang{zIzUP{EXvu*~neR)N`?~vQ1UuafFKL8|s@j?Q$9fJ-
z-Q48%;Fq`0#h45Ao0oQ4(ld=QnO`jGQqq)#5D|^-BXX_5M
zO`5tbrFTx?{2J33mFLGz)2E+W{_T^)qRQ#BE_7`!_+^%GQ*G+RW3z-(%Z~+#Jv$;%
zq?7OY;MT05)crf^roUdfP3A&O@ya~buT#>WJ8dd{op8$NQr|Z3(zX-zhFK=7mcCdN
zR$>O&BX<~UV^h~tXw565Z$uryE%uCjEU%dLx@|$J<
zST}b2J-hJJ#B^f%*Q{%MD$mX0R@}Ivh0iHyQaani%0kU00S(QDdKw~UQdO_`-wzkM
zAG&v&-}XY^hs+DN{m7kSeQj2HX-54^iSme#JGieg6{PFWxOqT!-wK1Smc*mWeWOn=
z%bm45^Q~oj&K{4sv&$kh%uM&}I+5IZ;Gsf`#&^y8-y^uKSetXfOAceyAF9
zdAc9>2|E^Ttsj~!0sB>NUv56}_NDKWZ(nqZs;kT|nlI|Fv;I)?C~x^ihEocG^|7&k
zC0t?;OPqQob^O6%&5BtmkGwCa{8={kXsy>Gm%S^?}nKre!rB;a_t^_e$7BDNhIX
zT@2+%X1#Dc=+AUZ*>+#FV1jMxr^uFHujO1K**>3hdMEF`(>&N{M*Pl(Sv+EWmv>JO
ztCfr~>-zdtGNfd%E7;&}KE~>E%8dAKU*%1|~6ur+I3xS86)OvrcUhJv=vm$##%>TMEdp4jX9!tNVwd>dtBA1Rb|vwWMhEH81f`<;H17Mm2aq@
zTO4oG$oNs@TX+4Vh8+#ju|D!mKEI|Xntu~$@(=R+I;qV5b^|OWppbQ
z`)&HD@XO_O2Re34FUq$6C@22?0Yl`Q!MR3yi{?g>LCv&f?F-}03GSJZF0
z#PgHsnFjb(MZEd@%$zN{vf4v-mj>=~CoK_(lr(V)~
zw^UXsPpYZNqWSA`ue9}#1XKJCRNHPTPLDgDxLv;O;XBoYMU&m8ZrR3oFW!9ZH-~@n
z0p83kTnr2x91IK$jttG|8B=SR7#Jkk7#Jomb+VJo;l9Q%BGMJ2$$InCLe9XRiAOSm
zzA#;8dB5!TLLHq+&LZ`{J$Z9y&6~N|`hD@e&BnXy|NZ;HnjqWHb7bQ5L`%m+*EV*e
z*sFmP9?xoIxmKEEAQ9Rh9`kWiosvY*QRRR0qW$hxJ>2ogFxKKh-|a6))_tgrTPpf8
zq4jijX!iPtmRq&fUOF7g^KA93`w!ObF4lOHJoQ@3_Qyr{#qAE4y<1eZGNS(bs<4DZ
zzaD(N9Q-g+QT4X(Vyjzzd!1a>y8L|i3(K9`8(d
z)b2U$e|QI=akCdy7X68
z`l%%w!}F`QO-Qw7&k1$%xpQDjr^vb)1`|yZ6YdoHn$qg1ul!eU;z1!M(Cd=mM
zpK?ExXW;W+ezDog7M{I!mjqV;uG;t4f&!B061iObprc66R#b3SC38Yrc{;!i}~PnoE?r!p7y
zbA4ucHJo)yF80{K6Oq)l
z{~LM5(hKt&EUf1IsH;A1{pfv1jGCX;$E51byN|vxD%^11Qgph(%Ch-(kt_>)f3c&c
zz___Oj~9wCFgWWnFepqGw340N?aEiLzIo5d4>yz)d1fmMo$$Ib-C?6AhY(Mr&@{HF
zud0=vZfT#-N>9Gv8ZA0~+qG+#x?*$IPTjUhbSjIl>)NYP+pp!7UAhrFAw960@?bf<~-
zl1R(GzK^RIu4nCuT6Ue~rR*Oy$r$MepO@4ZPk6n-b7=
z^|ufA3cr}wwVS-Z@*~!<>tkBxJ>8b+*)^@l-g8b;-7@`Cb?U*Xi{6Af{@T4`q5G`;
zpRY>2zx+c=ZLj9MO}!ag79M|dV{zQ$Wmg4EgEWngibP%Cu`jRs^S175^`=|%Zr=*o
zUmJb-*|hF$S8{J32)R?z(bx87Gp
zZsT>M*obddReSfTEf?Ee!#;Vt;>AoO-<-Z9XQ!2{xw~bX7&=bS?YbunQ}MZ%0r3wq;NL_C-FzGT#a>ue-T#E2qlQpDJr@k3C8~9evqw*~!4b
z+Sq$bj$KdOQTfH-@}=OY%6BtDZ$wU>d);--oPfhtud_bKPF%9*@U#P+GpD3#_O5S_
zHn=&l@6et~rt_N8CzsyQt(w5uF}q>yx03Mb2R0>?+fH6yfBeni3YL9ugQUfd2&in9
zVbk2Koa_4L-z;AT^#wciF6A!E`S7WPlc%eAx7pFjnbOuX-Fz0U-7A03Jg0f3z#Cc4
z8OwSnu8Q+i>dV{O+h;qwXUUN43gIH~*x`*F4Ja)Ni;fW)@$;
z6_>n*alsOw-5dFDY(Cl$?V~N`xm1Nopn365$BRq{A8om_gIQ~H@#@SHtCJ?FrJHc4M2;2e*lT4yfPkbD5WZMmNmqQctMH($@~)4FRNRxG{rs-kg91$W682iems8_wT)J5AlDVYl1Lk@=kBo~WoFJf>FH-Q)+jZtnPijJ`?2KA
znWgn*{X(a2XP)}G=$=h__0#eW`YpU(cdvU0AGYii|Mfw=ms>4&nfe|R)?(+}O{8-Ms*
zE_S>>>0xZxNxjwQB{+W?TIe0lx_HPqOni0o+E)<;Oq$W#^aYIO&RdvX`iu8(*z)$5
zf^+M<^k09muw8gLv}CK_`=#2YQVSgCu6xd({McBlH1(pdRjl{*ms|SRUHqYJ_5OMP
zt3QVOA|EqKop^Kv~{WPwT
zHgf%!6DQEjT=Mk%r?*!1eeW;)RH%=5e*UxggbjDH#e4U!_&m49|PHV)f^qv^+V$
z`taBpM%it`5A~M(-*B^iv&}8}xG9TY$2VL`iP&-W?ev6*=f8h;oMX0G@i}nc?3ZuV
zMU^&}b49Bh+GwuUc#i)=vlRc!KdE&cnU7bRid~nSW^neUTv;URx#K?)=h``MfBA>Q
ze%0sjgrIjf6}JX0aZdeMu;_Gd=8n@1#r4+bHG8KYyUmanK5NEB`FDnT#)sc7ljOhc
zrlUF4d53w@cO8x1)&5-CV%w^Dq&!|C
z6P?sxi%CtlrbY1Uy`Q3*c(^HJrVU5Q%C|Kx+r?4${&4XxSN*;Sj}1U
zMym1Mo8>L*7pqTmnENDhW6sQT{>s-5Je8a~|LOCRe{BqP^{c8aPlyy*?wM;jcmK)r
z+>7%)Kfe|9dV0!r?tW#lk6pH^r}oWOm5%)O@{g_J?7zRJ&OfIA;!o|r#&h;l?nD}y
z9Z&HIxH!SX-8%Hi0y8(BwC=|RMLVqc%2n6g+VEt)eCD6zx%EnY7ll@`7EbAuI?Sm5
z(ciQ#^7;Ia=S%;wE
zw>+PRtA70(c*mxAi?CV02GjDV%OC#H-1vX~5!w1{FXg}Z&;5U>oS{|S|DVri|IK_(
zYv<0Lmf$vb=Z`b{A8fV@Uw5iJ-0hGQ`dbL
zd>DLl?#o5SJFTmn#SL8-9|@BWwEWtZpW3wG^xcy&U)#91P7JfoeR@aRWBb^LCy7
z^z3CNn=Wry`t48yvt_)y$;3k)`;CPK?`?u8e*FU{dr4{Fy+aY$T>fk$+*`2+V$hCcVNFqpLX%arFZHqrpx)2
zt;+USU6gryN`?GZ75lg|cIuDCPx)T2dj2oVNWsFb*CQ)-+qU{v+g?9~S9gNr&62u3
z1(qG`P=B<-cX6Ld@adSm$PkkyM=mMl?OWWoe#(|O<)p>$4kRu}GS;6w{fX*|iQ(%n
z-_ci3*}u7Mxlwqsk<^40xnbYqv(IsyOwPNg;+l6V&hpvS9E+vW3UXj5vN*74Df)!uNJ*kQ
zgD=`&9F`Ew>!v@$>b=lcgr~|X2iVatz=)Z;+p#1$gOof{ro@MGrXc*
zPso1?4GrTD`pDp0+v4?3QZ?POWDUb}trJnc#uUB{sRA|EWWc#{2!k5-=4HpT-(0a^oLCOmxsR%
z#15SKw*?(i{y$vBXtn#Awade8j#kUBJ+F^^r~j>e&+)v)t&?B6
zoQQrC|LNUgljULDnam~YzF#)cdop`VLBq3mJU>%blspfuv#WSyc{A^xtw52|+9jVA
z9#n=buj)6t&8Ovdn|13hM?uCCy~ghE7jB9y{VCF{_&6f{qLf$SRM*}Y<^i*!R!lDo
zlHVF^ugZ9#u8N)Er`~~e_55o4oM!IfR?}tjvGd-3*h2BcADO$1!D=6C1lq1;i0dvs
zpBxsm-TwKkzh77-q!L>v>R+1c^{uv~<6YAk-4eUIyn1nO_D$R8^1WexL#bw_`hjcf
zFUIwHnd}N*{5xXt@6NczH(#4t3H{LbJ+|8|(a!I)NmfPgvHpUm47_OzDw*nSYL)6)
zZC+%rtZR5?EW1F{HT7Qmialq8uU1Xb>I-^mJ7cBOvz?;BR~Ik0;lI$t#N@(y)_vu(
zY=tO`E)O-ayNgo<;?FF0+7j;kzV^ZoDV95>43EBUk=p$H@S@p?{oR62<{GtATP$an
zYR=eHWyN({tl{+0FATOEv*+@k=1;ulT_1mJ&pI9LV*W(G9P^1b$2Hen-1zc%rrsL!
zLpuD8kNd6TJ&VoWBZ(ga?{>bZ76qDzwNuZ=tKh>q~Q8Pn#@FNX?!t&U`xhcFonb
zxejYJVqQxx63tb-udue}M*&}b-?`r#?;g*PY0Bf`kzEumk~M8XJm;A!%*y5~CVYKt
z>(O8DWG}xW{6hE#m6yvE)7#mqe3p7tPAbq1@Q)8otc_3&{AVulEc=Ir?Zo1m#;%9G
z&Re(w!?iOrzcNNO=lODPi3`#_XS3}N=dq;wxg~upkCN0m?w2%tSvBDs!&+Sh^&fF-
zq~6}KKKNgNr%qgC@9bra2f7&^h6=2eJ1@;}Xic$r{lyefHYttim#)9?)L=MS)RlL}
z!lq&Bqi0QXisw#jH&EgVpY)t%(u`@mJ;_qFvh_T|XT=s&7YUy_I>~STvH$5WBA?%A
zVEpU#<#<8PobrY}?d>a;tljkDY;(x=&gixk`_BFsFx^twb?xA5*WM47G5hzGPB>To
z=?B}B!Y2!sF>k4>?=aiOdyzHw(>)uH*=#G9idEJc=j>%Q`@(-A`c@XRe}Jcl_N`Y(
zyfiLYIjpswD1Y?G?I^xWKJ9P$Y#uGK@XD86U?zD(RgUZNnhR|i<`(&&3^F3gz1aqk0-MqeA8+8BXh1d|3OTJ+=0JhVRi16CY(Fo9m)J6
z^GxN3m*an%veyeE7wnR$)?2vtOKw2*#`~;aVt>ii6x(LRFL90fM-;FYC
za>0qcO=1$i7BW>E27FyCb3ERUE^V3De
z<+kId;u?vZdMEv~t`509o<6?%MtwoQ_g*n{n0t1r>obN@(K~*2?-kE4jL8w#ER1h>
zalgH?o?*v-56R?JhZPsM`3b*J72T{<)G%S*@=g}kPrtp=t}ixdd9qt{s@55?1@*7*
zJ&Ckl&2{{tr6|{g(9L4Z6Puq*UHnz-Qzc*QQ%8<{ESHuZRyrH_@vo51|KOZIMoF*J
zKO8+jF|EFF@w?P0pZ%v@6Es)UwOQ)3%vs&1$$#w(^Hcq)Oxi_t5sv$V>I7JiO@3}~
z;`A#>?f?G1us?AxCNYd_
z!oR*c{_5C{N1yn=aQ(3rbo{LKH!$(Vu{kUAkDNPaS+4vy(s7@F`qOxYcJ=8DbEp1q
zpZaLR)g^!1)s(K7{JLEjwIuKji4Y!{amCp5E)f+_EYw^!!(On~z)#=F&Hpm;YE3tg2P^p?HGY
zXNy@Ug#&thmh80AeD9-w_GMJpt*3fRvo+uR>aw~#SLzhA$FvLkLt{%LGGhy3vgZHp
z4>siIw$)^a|Dq8xUzUT{%p$fGxWJmKf+wjSkCb-JP0cw0u$#Nxc+b~U{tU3X4e
zY98PTw_=QHj$2VPss3){Yre+AQr)(1N+aLc?>%bwEnVz-n$V7t=e9gPpZT1Wy+pDsWD|On#1(q$rN42Wj;7h*7Uvhv+H
zCZi~@OhYu!!eL(L5-VeRBML3#Nkd$usZ!GhHa3{OW!vlVrtY#|PF-9u<=tD~%^#
zcqlOW-~%b9%T<#bDiNkNPbf`3Z~+n^H(p3FbzYkMY3bK)MlyX}a4V|6>bmw?EPjKcDQaeE;{|{qNta^Uwc%ez2Wk%|ZKT3nj()HRa+?G@o^z
z#a{33#%(0TcbX$H!*E`x+8lid*+u?#Xa*<_c|Vv{-}1ZvRL)q!RQ$u*6yi^R!yp?
zR(({#&Y!G!=k)FOQ$FhLi9W^dfF5oWYsIVdY#^byTbI
z>C-JGGcw&xd6wN?F?-i$&j;sD%
zWqivkZTK8;_hjbH)witH7tgNy7Ub~Kz*i`L#mg;jr&p(aOgWlWbj!bfl7@Ha#9f!3
zXzg;pX13(0n@Y{4skVEICoXxKDn4nF!A;L)%L<-!8^^HJ>dp(gwXyj2#2M30J&o{N
z^{peV`pIWs-|pqN*9KnRaK*y#oA9+uuNGX3>oPsMF=+0s#Ip)ElRk&eE3q)FS(@s8aqVMtZj)|dU
zW7=#<<25FZneESbA`3a^hkal;CYp2jESK4$(1U7n^P10cZA)0)WVS{7MxV|}t&pV;
zOzO)xbu?RFT}jw-?Z3w
z?MRhZb?kp!E>ySv0soK1P3j-iS?iC*ckJLX;0(+SJJxZ1*0kW+hWVF+w}v=u?Q@-+
zA;eLdopsA7+T&IH&4>FRzUP{EWXXX`FJF|V`?&jO1v^=WJvrpZ_vzEkuBlt5C%HX1
z73rv4@K<$OhF$&3o!4A*ckhr{@zN*1#6rqc@ANtMlUr9PczNrun-Ul#E2n=^k8hd%w!nl`a;OYACRm-@!QWJ6tF@vB<9
zRtXjFYwEf?!#Vxj%Gk46(&@p`XHMRGQhD7V|7Xm!=elQ888=n;EtBnCS2REEcB}Xi
zy-#Np|C^XbCVb^xv$OQvtZv1PD|+~xg1W-l9#$4wE(vIAF3i)IawawPivRs^q5GlL
zIdk(KdwgVGxb92tl=9cd(s?rKf6A0cb+&L{Q!03_H{<33*?lVvPPHVeF7u5(y)1Xm
z?o8RA4LLhJ=FjGf(6IYjS?YPDtMRZWN8sDwz3;cZNR14d)+!MD{Y=_)gYz{uEnik1
z3m4Y3IdAT=Xky!ylIdkFRkQDxEZ@UuzL8P;d6Gl@&u_8otgHSm`CuFJVaaUH^)%s_KVBXFSNP-g;l@IiSBDQ4vb^?p-c>(eL;Hh`RPz!3OFwF)vNQTs76`{S
z{60GCh2uegCM#vzea##j=5hVhajN~wzd)(GGF|ceT(_m$gEq~G-`mipBQ|eYx><
zn|9>zyq4ayLhf+ZErC5RWp!p9cxo-BzM+CgaaNY!yhB2>)}K)F`Qlw|yYT9Fr%&?j
z_pf_p|7V$2TCXdA_{17Do%u!!kIH|0?$XH_GgEo(zAlciv_ezC)WFxWafcrr{%2e<
zjX!a}`rBLg_8b+CxcF$EUGxG~0lqm0OPP{0p00n*YOC+8dr(MKFi41R((HMrmaY#U
zu)M13|6gvTZaKlVR*ZK||G$?T49f!^u8ggeX^&!3U9?!`(&h>Et>NoGP1|>;sC42X
zrfsG(4H%EhChg*~g~Gv2fnJ
ztNqCyHk`44gbzPrnxwakU2*cVRFztD#UCtJugI;^vp<=qpu3i1(vs+l-rHCuu3Elv
zKa%`nad2Z`A^+8DYmZd>-0A)MWGcUZXVxADc8^n)Cc7pvTX@89U93)T*AUXGf4iow
zhVi#bi%N-oFY9OX$+3MC3;#Rgb6~neTRcL(8)I#Q*yRRkbpXJX3dU4vp3@;avYl
zp!Bpr$l=H}_L1AFMEezt)l+!mfOrf>jS)*
zS-2P&I5-#>7#tbaJa}-tmWhEul8u2uck*&4+xojq*Yf{3t-K_ba=KlGCD8e5LeLkc
z%PjAgoemJ&rh7B@YW)*l@mU@wvnpP;+MlXOE6em=xzP8radFx6+H=)qY2VM^m*3Bz
zlW@~PrcyFZNF*(_LgTWfEUV=?X^#ZQ<4VneUw`yzn@O1-G>E$O{Qb_SCTphmX@|W$
zq*s1tnz~ti>-*1IYdzStW8&6FMf;v#8J;;+Ze5Z={MEl|<#!*=+rS?ZB_4P2=|26M
zwykd>OV?fbuqrI!(60v{4?91MR8+m}yVxpf<3?xKV_tr-d-ASo9jZR9y{_o$hMm#R
z<|%*vuqe*jaP4p1+sj%KRjYR$PF!_d-nw-8&z8hh?3b3WG@4nT`_3|?a0XY~
z-&iHJE6zH*H`ycCbZ6~`ll+I5@vO5tc}ARzXYwf>GD&
z!mSGnE~{%)UYho5^<2%#$HEprz3DXVt;_~XPQyahaNnLsO`O7-!fcb&@*Yj=Q*C?6
zC_8gU+iN46B#HMG)xkH#%jzd5KKd`Q)ic%SlJwLC;`&WnN*p$C+2WksR8+)nwQ!2A
z<6_B#KQ1-1pYC`3za~Un^Vn0_ZC&0b=FOoy)=0GFY?4cI)THS?vANzh-D?RTF_OiKq?@gYewZF`p
z;;^GK$F9D+tlq7#CGbB3QkoQCaAXKO)6%(5lz~B9pMgPPvY?ghlVeK9j{gW?rUY?Qm+_KjDXjHa%b|&|=sOetfQ3tQF
z^l)XpzE*p6TiN!t+qQ14-kP!R|IYk0BTu%*e|Gg1?`Kz^xBag3zxdrwbN~JS4jgs~
zc|2>)WjQKN_R!
z+k4KtVx?dCXQRw%*?XLpc*ZVf~dI*Upz(*&bPKQa9Nz{bSZ#xo6xdPtJY{)sN3M
z$-AI=BGqdBQ@6QN6?6aW37GZul8Nu4{s%|^{;P%p;F0*0}9iOsPw(i}O
ziF&=dy}SS3dHg(1lH=u;HvOs3jONyzPwZ8ea(`;P?6T{f<(Jv&+K&~^HRJrwJLkh@
zUHeIwOfqYB`rWSBe(bLm{|C`aF)M>-_v{H?J~!ss^K#Gn|9P3SO7?ZF|MuC`D*p8Q
zlaF6l^sgw{JO94+UtXmPzfJZ9E|1%orN6&k$oRg>S$30u3;YECP00A1`16+P74z&r
zg1z|{H5IuZ{RxcR8lGXdY_oUGMeVb4|8^Xk|KYRU+;va7Q}t)m?fAx+<$_*raFSg{?w;kr)8}>Z)Rr-}K^OmzNhrA3}ubHh|egE2?uama=u8rPq
zvi9b-t(n26RcF86zApV#{=O@F?yTXOeR1BZFl)K4Z&wU`^Ex>9uh@H+M_t$c{>dlY
z$E&K=SX`d-EMm{{RqA89t;p53|m(R9gm>&MeFqqChk>t|=C`tjbHBggla@2kq=WwKqauf1fJ
zwiE%t_;+$)b$?{hyITo!4sy|QWbw%kl6Pe(J)?DdhGb1Jiq
z4w=~MtXh9|)|DT6Jm&rKX;D>P+WIp#a9L+>`g|+EM)}H$b8WY3+*kP59iDce^Q!u3
zA*uVk+Y{el(alVX5v~`ndJvL)0WRQ
zIn1S1*%@JUFLPzXjFhk6BkSjGySg;(Pa^x|0Mi-L{x?@uv+63$-Bql!((V3nwY3Z9
zt;ke=e52;0W`*wtwuVU?-W;n-I4{PWx9!oy03}7i1__z-yj{Ckx;Gm?=3B95o$j=o
zPgO3r+!gh{CAnwS+UrLj30~eN+Nj?1gx#)I*5gU!u{$#To>6g=d0J)t?i@Esu2*V2
z6OnuC{Y^vEMwf2Q1E*haIy7y`?Fzo%4FTRNS3fdoems5uCU@y0u?E}Z^mR55+3uKD
zN$UBzt>%nVB`Vfv)z(Q*MaOJ+VwdT>3{=R{ENJ1?}xdp?$xUte-zKTPQ43
zuqFE7{d!rk<*%199d0_>EpGhviOrnL>OcRdSCxL%pSCP&)~rCyXGQKRa%+Ui8rFM?MvAC1Pv#>C~Oh)Ums~`QX+4DJ9dV
zZt}h>sjO(t=;O6>EEyUcI^LMK{}BCwbEsX@^)}c(dI<-Ogio=6mL!
z)Sn+ko8LcoY;La*2z@WTU~kk6S;HS1_6(w%OkJX~V&mf*gU&uktP|L&S#74>agcG>
zC+9yK4j%up<6!>>$7cEZr^hEK6^r{x)n9$E{^Mgd`-A>ce?;tc&tB*K$96ycgZWF>
zWwGK~mCZMg`W6HRCIxQLPE&2VI78N@H+S~Jj0-({4LW^I3Tlztjc&|X#n)7(bE9{&
zddAnq6FB%;RvVWvPxa_td?@$T4w1ub_1*h(Ka~I2%~sz(Kc(unXRF8Cx%CIcHYPl&
zpM2oK`_KF){}vv!f0RDMY)({i;ao}aWs-NBEyEf=Z~l|q%y&tg_aEo~D-WJ01iibf
z*BZ4Vc&_xpi1Kwy59SGnnGPzS*!Q--UA$KBVrT#PvAYMHOy-BkNgqF(G4v*Qaxg=$NIwH}UJj7<5P*_Nhpw+RJU
z>s@O;y*tJ8LXY#75IL4zSISmCJ@~Fdhw1l?k10+z52y4`T@+!kTZMnoqBXo?s$Gj-
zwn$B>idZ)1VUNCb@YLM3pSW(Yybi6jN<8#n{>R!CC)_@6Rh8W8ET|o9>3QL=OzD}7
zZ)^MOkDq1qJjnLHDbD1_^gr6o^}6x<8<}6Sc5?1j7V$m0(V#-E^z_NBeTFam?kDe=
zyLX~Qm&y08)YClwbdz{v>e4^F|H;}MFLL1gsn~8K)*_jE=jI%&e_+qG*xvK=C5fd*
zTUQ;d7wfJ#GEXSA-g9#AT1(!#$P>@@7v5a?F`oCI^#A(159&SM>CBmt9Hgd^+o5_m
zR;wsrhBDjbsg)b@x0vvk9e=dd@udC#D?j4d{zuC!J}NXd=tssM`R4e<{$uN<{>0lQ
ze#rh~wXED)bnQW9J)@X6MGHkvMedONvg&m14x54{r(b_ss%x__$~b1$5qjKrvtS)$_WL|$fk
zO0QU$eeTafrCz#6~ke+z6HCt@?+Pxod$qOqdhq@&E~@Tg5kT%X0p{;Er@G4EE#sSy23XW3}kE
zRR4{0ZG_Kg=FRY!Um2opzxH%y+nxO5mx?kLx+E_-f2{Z3^|j~ZO5JB4$a(I<{anPp
z*t&kjwA%+~7j>2XGWYaXDq&sox=md@Lg(@Gn8f{RVw(k-((b!Wsad;Ca{E!{;H4XK
z%q9m;k^ji6=JxD)-A1Y2Nj-L^D{sHH_;mUD(e%B{Q~i_fa68hl$#u4qH^StQr@=3Zt>@~+)X>-*4lj7;b>Zzn*JHDfaLfY>Cfxf
zCjL$9@mm_lka|Tw@b;Q{Kf~q)>l&@66`+OF^mMX5+k#p|2TUee0O~(`@-Vu1u!q52k*0nrFX#Yudke
z(@X=GPYNl{G2gUx=83A$r8-Strl5O;_{qhO0|fT+Lrz*SEb+%{IfJ?emvs-7(MVZQirH6&gPj
zT&orR)Np;XI`fKk0rNAsJ##9`AFFJ9A#=-F)#b@jhQ0lHD$Bk{`_=I(e_{V3eTKJjza(z;KfZqT!2`$r3radZd9{1ypPz3scb<&W-dLZ$EHuNuS97Hfc@$nk6$scqOwk>~t4?&d_{&*k|S8$=@!ob$R8T
zlJr$IXy=vbC!QXAq5jgWr^CeEL!I~Ut4)rxb_t%{GVRj(3nDc>>%X$tG*5|tJvGm5
zE&t=m%=;2&-Hem^z`EyYs;F~_fyd^);D-wfi`F&tJ#Q}7Oy#AXYSB}iG&9_dsW%zYh?@a$?QgtEzweE)hg^DH-4&jwAy{m*yrFkMXTl4UdO%D
z{=jO(f8Vov`DKp-!4IN8y;Cm9TPt>f?WN86<(WYTtaCpq=w@(Nq^?-;)=FMp;^(xS
z?H>eM=5QU3VPMo>P<3_p)SKIwRb0%jcr_)NFSyJv&VS)%39IfR?Ui%xb(V%7o^UeVY9b+&ukqh45LG1nVdzo>e(_