diff --git a/.github/workflows/build-nightly-apk.yml b/.github/workflows/build-nightly-apk.yml
index bca267be..0951149e 100644
--- a/.github/workflows/build-nightly-apk.yml
+++ b/.github/workflows/build-nightly-apk.yml
@@ -51,10 +51,11 @@ jobs:
androidHome: ${{ env.ANDROID_HOME }}
androidSdkRoot: ${{ env.ANDROID_SDK_ROOT }}
steps:
- - name: Setup JDK 1.8
- uses: actions/setup-java@v1
+ - name: Setup JDK 11
+ uses: actions/setup-java@v2
with:
- java-version: 1.8
+ distribution: 'temurin'
+ java-version: '11'
- name: Setup Android SDK
uses: android-actions/setup-android@v2
- name: Clean build artifacts
@@ -63,7 +64,9 @@ jobs:
rm -rf app/build/outputs/apk/*
rm -rf app/build/outputs/bundle/*
- name: Assemble official release with Gradle
- run: ./gradlew assembleOfficialRelease
+ uses: gradle/gradle-build-action@v2
+ with:
+ arguments: assembleOfficialRelease
sign:
name: Sign APK
runs-on: self-hosted
diff --git a/.github/workflows/build-release-aab-play.yml b/.github/workflows/build-release-aab-play.yml
index c5bfb2ea..eb6923bb 100644
--- a/.github/workflows/build-release-aab-play.yml
+++ b/.github/workflows/build-release-aab-play.yml
@@ -43,10 +43,11 @@ jobs:
androidHome: ${{ env.ANDROID_HOME }}
androidSdkRoot: ${{ env.ANDROID_SDK_ROOT }}
steps:
- - name: Setup JDK 1.8
- uses: actions/setup-java@v1
+ - name: Setup JDK 11
+ uses: actions/setup-java@v2
with:
- java-version: 1.8
+ distribution: 'temurin'
+ java-version: '11'
- name: Setup Android SDK
uses: android-actions/setup-android@v2
- name: Clean build artifacts
@@ -55,7 +56,9 @@ jobs:
rm -rf app/build/outputs/apk/*
rm -rf app/build/outputs/bundle/*
- name: Bundle play release with Gradle
- run: ./gradlew bundlePlayRelease
+ uses: gradle/gradle-build-action@v2
+ with:
+ arguments: bundlePlayRelease
sign:
name: Sign App Bundle
runs-on: self-hosted
@@ -110,15 +113,15 @@ jobs:
with:
serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }}
packageName: pl.szczodrzynski.edziennik
- releaseFile: ${{ needs.sign.outputs.signedReleaseFile }}
+ releaseFiles: ${{ needs.sign.outputs.signedReleaseFile }}
releaseName: ${{ steps.changelog.outputs.appVersionName }}
track: ${{ secrets.PLAY_RELEASE_TRACK }}
- userFraction: 1.0
whatsNewDirectory: ${{ steps.changelog.outputs.changelogDir }}
+ status: completed
- name: Upload workflow artifact
uses: actions/upload-artifact@v2
- if: true
+ if: always()
with:
name: ${{ steps.changelog.outputs.appVersionName }}
path: |
diff --git a/.github/workflows/build-release-apk.yml b/.github/workflows/build-release-apk.yml
index 169704c1..5ca055b9 100644
--- a/.github/workflows/build-release-apk.yml
+++ b/.github/workflows/build-release-apk.yml
@@ -43,10 +43,11 @@ jobs:
androidHome: ${{ env.ANDROID_HOME }}
androidSdkRoot: ${{ env.ANDROID_SDK_ROOT }}
steps:
- - name: Setup JDK 1.8
- uses: actions/setup-java@v1
+ - name: Setup JDK 11
+ uses: actions/setup-java@v2
with:
- java-version: 1.8
+ distribution: 'temurin'
+ java-version: '11'
- name: Setup Android SDK
uses: android-actions/setup-android@v2
- name: Clean build artifacts
@@ -55,7 +56,9 @@ jobs:
rm -rf app/build/outputs/apk/*
rm -rf app/build/outputs/bundle/*
- name: Assemble official release with Gradle
- run: ./gradlew assembleOfficialRelease
+ uses: gradle/gradle-build-action@v2
+ with:
+ arguments: assembleOfficialRelease
sign:
name: Sign APK
runs-on: self-hosted
diff --git a/.gitignore b/.gitignore
index 07e9f679..375b15e2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -265,3 +265,4 @@ fabric.properties
# End of https://www.toptal.com/developers/gitignore/api/android,androidstudio,gradle,java,kotlin
signatures/
+.idea/*.xml
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 29204aff..c8ff3936 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -1,8 +1,17 @@
+
+
+
+
+
+
+
+
+
@@ -15,6 +24,7 @@
xmlns:android
+
^$
@@ -25,6 +35,7 @@
xmlns:.*
+
^$
@@ -36,6 +47,7 @@
.*:id
+
http://schemas.android.com/apk/res/android
@@ -46,6 +58,7 @@
.*:name
+
http://schemas.android.com/apk/res/android
@@ -56,6 +69,7 @@
name
+
^$
@@ -66,6 +80,7 @@
style
+
^$
@@ -76,6 +91,7 @@
.*
+
^$
@@ -87,6 +103,7 @@
.*
+
http://schemas.android.com/apk/res/android
@@ -98,6 +115,7 @@
.*
+
.*
diff --git a/.idea/copyright/Antoni.xml b/.idea/copyright/Antoni.xml
new file mode 100644
index 00000000..438a39d6
--- /dev/null
+++ b/.idea/copyright/Antoni.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/dictionaries/Kuba.xml b/.idea/dictionaries/Kuba.xml
index 7910687c..7959d9aa 100644
--- a/.idea/dictionaries/Kuba.xml
+++ b/.idea/dictionaries/Kuba.xml
@@ -5,6 +5,8 @@
ciasteczko
csrf
edziennik
+ eggfall
+ elearning
gson
hebe
idziennik
@@ -12,6 +14,7 @@
synergia
szczodrzyński
szkolny
+ usos
\ No newline at end of file
diff --git a/.idea/discord.xml b/.idea/discord.xml
deleted file mode 100644
index a04e4e5f..00000000
--- a/.idea/discord.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
deleted file mode 100644
index 0dd4b354..00000000
--- a/.idea/kotlinc.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
deleted file mode 100644
index e497da99..00000000
--- a/.idea/runConfigurations.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 72c03e94..0ceae1a1 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,6 +1,7 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
+apply plugin: 'kotlin-parcelize'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
@@ -30,11 +31,21 @@ android {
cppFlags "-std=c++11"
}
}
+
+ kapt {
+ arguments {
+ arg("room.schemaLocation", "$projectDir/schemas")
+ }
+ }
}
buildTypes {
debug {
+ getIsDefault().set(true)
minifyEnabled = false
+ manifestPlaceholders = [
+ buildTimestamp: 0
+ ]
}
release {
minifyEnabled = true
@@ -45,23 +56,34 @@ android {
}
flavorDimensions "platform"
productFlavors {
- main {
- versionName gitInfo.versionHuman
+ unofficial {
+ getIsDefault().set(true)
+ versionName "${release.versionName}-${gitInfo.versionSuffix}"
}
official {}
play {}
}
variantFilter { variant ->
def flavors = variant.flavors*.name
- setIgnore(variant.buildType.name == "debug" && !flavors.contains("main"))
+ setIgnore(variant.buildType.name == "debug" && !flavors.contains("unofficial") || flavors.contains("main"))
+ }
+ sourceSets {
+ unofficial {
+ java.srcDirs = ["src/main/java", "src/play-not/java"]
+ manifest.srcFile("src/play-not/AndroidManifest.xml")
+ }
+ official {
+ java.srcDirs = ["src/main/java", "src/play-not/java"]
+ manifest.srcFile("src/play-not/AndroidManifest.xml")
+ }
+ play {
+ java.srcDirs = ["src/main/java", "src/play/java"]
+ }
}
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
- lintOptions {
- checkReleaseBuilds = false
- }
buildFeatures {
dataBinding = true
viewBinding = true
@@ -75,7 +97,9 @@ android {
jvmTarget = "1.8"
}
packagingOptions {
- exclude 'META-INF/library-core_release.kotlin_module'
+ resources {
+ excludes += ['META-INF/library-core_release.kotlin_module']
+ }
}
externalNativeBuild {
cmake {
@@ -83,6 +107,9 @@ android {
version "3.10.2"
}
}
+ lint {
+ checkReleaseBuilds false
+ }
}
tasks.whenTaskAdded { task ->
@@ -117,28 +144,30 @@ dependencies {
// Language cores
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ implementation "androidx.multidex:multidex:2.0.1"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
// Android Jetpack
- implementation "androidx.appcompat:appcompat:1.2.0"
+ implementation "androidx.appcompat:appcompat:1.5.1"
implementation "androidx.cardview:cardview:1.0.0"
- implementation "androidx.constraintlayout:constraintlayout:2.0.4"
- implementation "androidx.core:core-ktx:1.3.2"
- implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.0"
- implementation "androidx.navigation:navigation-fragment-ktx:2.3.4"
- implementation "androidx.recyclerview:recyclerview:1.1.0"
- implementation "androidx.room:room-runtime:2.2.6"
- implementation "androidx.work:work-runtime-ktx:2.5.0"
- kapt "androidx.room:room-compiler:2.2.6"
+ implementation "androidx.constraintlayout:constraintlayout:2.1.4"
+ implementation "androidx.core:core-ktx:1.9.0"
+ implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
+ implementation "androidx.navigation:navigation-fragment-ktx:2.5.2"
+ implementation "androidx.recyclerview:recyclerview:1.2.1"
+ implementation "androidx.room:room-runtime:2.4.3"
+ implementation "androidx.room:room-ktx:2.4.3"
+ implementation "androidx.work:work-runtime-ktx:2.7.1"
+ kapt "androidx.room:room-compiler:2.4.3"
// Google design libs
- implementation "com.google.android.material:material:1.3.0"
- implementation "com.google.android:flexbox:2.0.1"
+ implementation "com.google.android.material:material:1.6.1"
+ implementation "com.google.android.flexbox:flexbox:3.0.0"
// Play Services/Firebase
- implementation "com.google.android.gms:play-services-wearable:17.0.0"
- implementation "com.google.firebase:firebase-core:18.0.2"
- implementation "com.google.firebase:firebase-crashlytics:17.4.0"
+ implementation "com.google.android.gms:play-services-wearable:17.1.0"
+ implementation("com.google.firebase:firebase-core") { version { strictly "19.0.2" } }
+ implementation "com.google.firebase:firebase-crashlytics:18.2.13"
implementation("com.google.firebase:firebase-messaging") { version { strictly "20.1.3" } }
// OkHttp, Retrofit, Gson, Jsoup
@@ -146,20 +175,22 @@ dependencies {
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
implementation "com.squareup.retrofit2:converter-scalars:2.9.0"
- implementation 'com.google.code.gson:gson:2.8.6'
- implementation "org.jsoup:jsoup:1.13.1"
+ implementation 'com.google.code.gson:gson:2.8.8'
+ implementation 'org.jsoup:jsoup:1.14.3'
implementation "pl.droidsonroids:jspoon:1.3.2"
implementation "pl.droidsonroids.retrofit2:converter-jspoon:1.3.2"
// Szkolny.eu libraries/forks
- implementation "eu.szkolny:agendacalendarview:1799f8ef47"
+ implementation "eu.szkolny:android-snowfall:1ca9ea2da3"
+ implementation "eu.szkolny:agendacalendarview:1.0.4"
implementation "eu.szkolny:cafebar:5bf0c618de"
implementation "eu.szkolny.fslogin:lib:2.0.0"
implementation "eu.szkolny:material-about-library:1d5ebaf47c"
implementation "eu.szkolny:mhttp:af4b62e6e9"
implementation "eu.szkolny:nachos:0e5dfcaceb"
implementation "eu.szkolny.selective-dao:annotation:27f8f3f194"
- implementation "eu.szkolny:ssl-provider:1.0.0"
+ officialImplementation "eu.szkolny:ssl-provider:1.0.0"
+ unofficialImplementation "eu.szkolny:ssl-provider:1.0.0"
implementation "pl.szczodrzynski:navlib:0.8.0"
implementation "pl.szczodrzynski:numberslidingpicker:2921225f76"
implementation "pl.szczodrzynski:recyclertablayout:700f980584"
@@ -167,34 +198,34 @@ dependencies {
kapt "eu.szkolny.selective-dao:codegen:27f8f3f194"
// Iconics & related
- implementation "com.mikepenz:iconics-core:5.3.0-b01"
- implementation "com.mikepenz:iconics-views:5.3.0-b01"
+ implementation "com.mikepenz:iconics-core:5.3.2"
+ implementation "com.mikepenz:iconics-views:5.3.2"
implementation "com.mikepenz:community-material-typeface:5.8.55.0-kotlin@aar"
- implementation "eu.szkolny:szkolny-font:1.3"
+ implementation "eu.szkolny:szkolny-font:77e33acc2a"
// Other dependencies
implementation "cat.ereza:customactivityoncrash:2.3.0"
- implementation "com.applandeo:material-calendar-view:1.5.0"
+ implementation "com.android.volley:volley:1.2.1"
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
- implementation "com.github.antonKozyriatskyi:CircularProgressIndicator:1.2.2"
- implementation "com.github.bassaer:chatmessageview:2.0.1"
- implementation "com.github.CanHub:Android-Image-Cropper:2.2.2"
- implementation "com.github.ChuckerTeam.Chucker:library:3.0.1"
- implementation "com.github.jetradarmobile:android-snowfall:1.2.0"
- implementation "com.github.wulkanowy.uonet-request-signer:hebe-jvm:a99ca50a31"
- implementation("com.heinrichreimersoftware:material-intro") { version { strictly "1.5.8" } }
- implementation "com.hypertrack:hyperlog:0.0.10"
+ implementation "com.github.Applandeo:Material-Calendar-View:15de569cbc" // https://github.com/Applandeo/Material-Calendar-View
+ implementation "com.github.CanHub:Android-Image-Cropper:2.2.2" // https://github.com/CanHub/Android-Image-Cropper
+ implementation "com.github.ChuckerTeam.Chucker:library:3.5.2" // https://github.com/ChuckerTeam/chucker
+ implementation "com.github.antonKozyriatskyi:CircularProgressIndicator:1.2.2" // https://github.com/antonKozyriatskyi/CircularProgressIndicator
+ implementation "com.github.bassaer:chatmessageview:2.0.1" // https://github.com/bassaer/ChatMessageView
+ implementation "com.github.hypertrack:hyperlog-android:0.0.10" // https://github.com/hypertrack/hyperlog-android
+ implementation "com.github.smuyyh:JsonViewer:V1.0.6" // https://github.com/smuyyh/JsonViewer
+ implementation "com.github.underwindfall.PowerPermission:powerpermission-coroutines:1.4.0" // https://github.com/underwindfall/PowerPermission
+ implementation "com.github.underwindfall.PowerPermission:powerpermission:1.4.0" // https://github.com/underwindfall/PowerPermission
+ implementation "com.github.wulkanowy.uonet-request-signer:hebe-jvm:a99ca50a31" // https://github.com/wulkanowy/uonet-request-signer
implementation "com.jaredrummler:colorpicker:1.1.0"
- implementation "com.qifan.powerpermission:powerpermission-coroutines:1.3.0"
- implementation "com.qifan.powerpermission:powerpermission:1.3.0"
- implementation "com.yuyh.json:jsonviewer:1.0.6"
implementation "io.coil-kt:coil:1.1.1"
implementation "me.dm7.barcodescanner:zxing:1.9.8"
implementation "me.grantland:autofittextview:0.2.1"
implementation "me.leolin:ShortcutBadger:1.1.22@aar"
implementation "org.greenrobot:eventbus:3.2.0"
+ implementation("com.heinrichreimersoftware:material-intro") { version { strictly "1.5.8" } }
implementation("pl.droidsonroids.gif:android-gif-drawable") { version { strictly "1.2.15" } }
// Debug-only dependencies
- debugImplementation "com.amitshekhar.android:debug-db:1.0.5"
+ debugImplementation "com.github.amitshekhariitbhu.Android-Debug-Database:debug-db:v1.0.6"
}
diff --git a/app/git-info.gradle b/app/git-info.gradle
index 2ddd8c2d..3577f668 100644
--- a/app/git-info.gradle
+++ b/app/git-info.gradle
@@ -97,18 +97,17 @@ private def buildGitInfo() {
def tag = getLastTag(repo, git, head)
def tagName = tag[1]
def tagRevCount = tag[2]
- def versionName = tagName.replace("v", "")
def result = [
- hash : head.objectId.name,
- branch : repo.branch,
- dirty : dirty,
- remotes : remotes,
- unstaged : status.uncommittedChanges.join("; "),
- tag : tagName,
- revCount : tagRevCount,
- version : """$tagName-$tagRevCount-g${head.objectId.name.substring(0, 8)}""" + (dirty ? ".dirty" : ""),
- versionHuman: """$versionName-${repo.branch.replace("/", "_")}""" + (dirty ? ".dirty" : "")
+ hash : head.objectId.name,
+ branch : repo.branch,
+ dirty : dirty,
+ remotes : remotes,
+ unstaged : status.uncommittedChanges.join("; "),
+ tag : tagName,
+ revCount : tagRevCount,
+ version : """$tagName-$tagRevCount-g${head.objectId.name.substring(0, 8)}""" + (dirty ? ".dirty" : ""),
+ versionSuffix : """${repo.branch.replace("/", "_")}""" + (dirty ? ".dirty" : "")
]
return result
}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 4d84d11d..8618f020 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -22,18 +22,24 @@
-keep class android.support.v7.widget.** { *; }
-keep class pl.szczodrzynski.edziennik.utils.models.** { *; }
+-keep class pl.szczodrzynski.edziennik.data.db.enums.* { *; }
-keep class pl.szczodrzynski.edziennik.data.db.entity.Event { *; }
-keep class pl.szczodrzynski.edziennik.data.db.full.EventFull { *; }
-keep class pl.szczodrzynski.edziennik.data.db.entity.FeedbackMessage { *; }
--keep class pl.szczodrzynski.edziennik.ui.modules.home.HomeCardModel { *; }
+-keep class pl.szczodrzynski.edziennik.data.db.entity.Note { *; }
+-keep class pl.szczodrzynski.edziennik.ui.home.HomeCardModel { *; }
-keepclassmembers class pl.szczodrzynski.edziennik.ui.widgets.WidgetConfig { public *; }
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.timetable.WidgetTimetableProvider
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.notifications.WidgetNotificationsProvider
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.luckynumber.WidgetLuckyNumberProvider
+-keep class pl.szczodrzynski.edziennik.config.AppData { *; }
+-keep class pl.szczodrzynski.edziennik.config.AppData$** { *; }
+-keep class pl.szczodrzynski.edziennik.utils.managers.TextStylingManager$HtmlMode { *; }
-keepnames class androidx.appcompat.view.menu.MenuBuilder { setHeaderTitleInt(java.lang.CharSequence); }
--keepclassmembernames class androidx.appcompat.view.menu.StandardMenuPopup { private *; }
-keepnames class androidx.appcompat.view.menu.MenuPopupHelper { showPopup(int, int, boolean, boolean); }
+-keepclassmembernames class androidx.appcompat.view.menu.StandardMenuPopup { private *; }
+-keepclassmembernames class androidx.appcompat.view.menu.MenuItemImpl { private *; }
-keepclassmembernames class com.mikepenz.materialdrawer.widget.MiniDrawerSliderView { private *; }
@@ -66,7 +72,7 @@
-keepclassmembers class pl.szczodrzynski.edziennik.data.api.szkolny.request.** { *; }
-keepclassmembers class pl.szczodrzynski.edziennik.data.api.szkolny.response.** { *; }
--keepclassmembernames class pl.szczodrzynski.edziennik.ui.modules.login.LoginInfo$Platform { *; }
+-keepclassmembernames class pl.szczodrzynski.edziennik.ui.login.LoginInfo$Platform { *; }
-keepclassmembernames class pl.szczodrzynski.fslogin.realm.RealmData { *; }
-keepclassmembernames class pl.szczodrzynski.fslogin.realm.RealmData$Type { *; }
diff --git a/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/100.json b/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/100.json
new file mode 100644
index 00000000..1bbdcf44
--- /dev/null
+++ b/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/100.json
@@ -0,0 +1,2320 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 100,
+ "identityHash": "4c141460d807d32d00faad4fb3c12522",
+ "entities": [
+ {
+ "tableName": "grades",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `gradeId` INTEGER NOT NULL, `gradeName` TEXT NOT NULL, `gradeType` INTEGER NOT NULL, `gradeValue` REAL NOT NULL, `gradeWeight` REAL NOT NULL, `gradeColor` INTEGER NOT NULL, `gradeCategory` TEXT, `gradeDescription` TEXT, `gradeComment` TEXT, `gradeSemester` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `gradeValueMax` REAL, `gradeClassAverage` REAL, `gradeParentId` INTEGER, `gradeIsImprovement` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `gradeId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "gradeId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "gradeName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "gradeType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "gradeValue",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "gradeWeight",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "gradeColor",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "gradeCategory",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "gradeDescription",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "gradeComment",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "semester",
+ "columnName": "gradeSemester",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "valueMax",
+ "columnName": "gradeValueMax",
+ "affinity": "REAL",
+ "notNull": false
+ },
+ {
+ "fieldPath": "classAverage",
+ "columnName": "gradeClassAverage",
+ "affinity": "REAL",
+ "notNull": false
+ },
+ {
+ "fieldPath": "parentId",
+ "columnName": "gradeParentId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isImprovement",
+ "columnName": "gradeIsImprovement",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "gradeId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_grades_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_grades_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "teachers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `teacherLoginId` TEXT, `teacherName` TEXT, `teacherSurname` TEXT, `teacherType` INTEGER NOT NULL, `teacherTypeDescription` TEXT, `teacherSubjects` TEXT NOT NULL, PRIMARY KEY(`profileId`, `teacherId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginId",
+ "columnName": "teacherLoginId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "teacherName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "surname",
+ "columnName": "teacherSurname",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "teacherType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeDescription",
+ "columnName": "teacherTypeDescription",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "subjects",
+ "columnName": "teacherSubjects",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "teacherId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "teacherAbsence",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherAbsenceId` INTEGER NOT NULL, `teacherAbsenceType` INTEGER NOT NULL, `teacherAbsenceName` TEXT, `teacherAbsenceDateFrom` TEXT NOT NULL, `teacherAbsenceDateTo` TEXT NOT NULL, `teacherAbsenceTimeFrom` TEXT, `teacherAbsenceTimeTo` TEXT, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `teacherAbsenceId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "teacherAbsenceId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "teacherAbsenceType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "teacherAbsenceName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "dateFrom",
+ "columnName": "teacherAbsenceDateFrom",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "dateTo",
+ "columnName": "teacherAbsenceDateTo",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "timeFrom",
+ "columnName": "teacherAbsenceTimeFrom",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "timeTo",
+ "columnName": "teacherAbsenceTimeTo",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "teacherAbsenceId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_teacherAbsence_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_teacherAbsence_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "teacherAbsenceTypes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherAbsenceTypeId` INTEGER NOT NULL, `teacherAbsenceTypeName` TEXT NOT NULL, PRIMARY KEY(`profileId`, `teacherAbsenceTypeId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "teacherAbsenceTypeId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "teacherAbsenceTypeName",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "teacherAbsenceTypeId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "subjects",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `subjectLongName` TEXT, `subjectShortName` TEXT, `subjectColor` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `subjectId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "longName",
+ "columnName": "subjectLongName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "shortName",
+ "columnName": "subjectShortName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "subjectColor",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "subjectId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "notices",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `noticeId` INTEGER NOT NULL, `noticeType` INTEGER NOT NULL, `noticeSemester` INTEGER NOT NULL, `noticeText` TEXT NOT NULL, `noticeCategory` TEXT, `noticePoints` REAL, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `noticeId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "noticeId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "noticeType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semester",
+ "columnName": "noticeSemester",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "noticeText",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "noticeCategory",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "points",
+ "columnName": "noticePoints",
+ "affinity": "REAL",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "noticeId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_notices_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_notices_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "teams",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teamId` INTEGER NOT NULL, `teamType` INTEGER NOT NULL, `teamName` TEXT, `teamCode` TEXT, `teamTeacherId` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `teamId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "teamType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "teamName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "code",
+ "columnName": "teamCode",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teamTeacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "teamId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "attendances",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `attendanceId` INTEGER NOT NULL, `attendanceBaseType` INTEGER NOT NULL, `attendanceTypeName` TEXT NOT NULL, `attendanceTypeShort` TEXT NOT NULL, `attendanceTypeSymbol` TEXT NOT NULL, `attendanceTypeColor` INTEGER, `attendanceDate` TEXT NOT NULL, `attendanceTime` TEXT, `attendanceSemester` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `attendanceLessonTopic` TEXT, `attendanceLessonNumber` INTEGER, `attendanceIsCounted` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `attendanceId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "attendanceId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "baseType",
+ "columnName": "attendanceBaseType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeName",
+ "columnName": "attendanceTypeName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeShort",
+ "columnName": "attendanceTypeShort",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeSymbol",
+ "columnName": "attendanceTypeSymbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeColor",
+ "columnName": "attendanceTypeColor",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "attendanceDate",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "startTime",
+ "columnName": "attendanceTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "semester",
+ "columnName": "attendanceSemester",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lessonTopic",
+ "columnName": "attendanceLessonTopic",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lessonNumber",
+ "columnName": "attendanceLessonNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isCounted",
+ "columnName": "attendanceIsCounted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "attendanceId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_attendances_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_attendances_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "events",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `eventId` INTEGER NOT NULL, `eventDate` TEXT NOT NULL, `eventTime` TEXT, `eventTopic` TEXT NOT NULL, `eventColor` INTEGER, `eventType` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `teamId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `eventAddedManually` INTEGER NOT NULL, `eventSharedBy` TEXT, `eventSharedByName` TEXT, `eventBlacklisted` INTEGER NOT NULL, `eventIsDone` INTEGER NOT NULL, `eventIsDownloaded` INTEGER NOT NULL, `homeworkBody` TEXT, `attachmentIds` TEXT, `attachmentNames` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `eventId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "eventId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "eventDate",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "time",
+ "columnName": "eventTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "topic",
+ "columnName": "eventTopic",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "eventColor",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "eventType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teamId",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedManually",
+ "columnName": "eventAddedManually",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "sharedBy",
+ "columnName": "eventSharedBy",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sharedByName",
+ "columnName": "eventSharedByName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "blacklisted",
+ "columnName": "eventBlacklisted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDone",
+ "columnName": "eventIsDone",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDownloaded",
+ "columnName": "eventIsDownloaded",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "homeworkBody",
+ "columnName": "homeworkBody",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachmentIds",
+ "columnName": "attachmentIds",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachmentNames",
+ "columnName": "attachmentNames",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "eventId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_events_profileId_eventDate_eventTime",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "eventDate",
+ "eventTime"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_events_profileId_eventDate_eventTime` ON `${TABLE_NAME}` (`profileId`, `eventDate`, `eventTime`)"
+ },
+ {
+ "name": "index_events_profileId_eventType",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "eventType"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_events_profileId_eventType` ON `${TABLE_NAME}` (`profileId`, `eventType`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "eventTypes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `eventType` INTEGER NOT NULL, `eventTypeName` TEXT NOT NULL, `eventTypeColor` INTEGER NOT NULL, `eventTypeOrder` INTEGER NOT NULL, `eventTypeSource` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `eventType`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "eventType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "eventTypeName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "eventTypeColor",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "order",
+ "columnName": "eventTypeOrder",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "source",
+ "columnName": "eventTypeSource",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "eventType"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "loginStores",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`loginStoreId` INTEGER NOT NULL, `loginStoreType` INTEGER NOT NULL, `loginStoreMode` INTEGER NOT NULL, `loginStoreData` TEXT NOT NULL, PRIMARY KEY(`loginStoreId`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "loginStoreId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "loginStoreType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mode",
+ "columnName": "loginStoreMode",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "data",
+ "columnName": "loginStoreData",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "loginStoreId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "profiles",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `loginStoreId` INTEGER NOT NULL, `loginStoreType` INTEGER NOT NULL, `name` TEXT NOT NULL, `subname` TEXT, `studentNameLong` TEXT NOT NULL, `studentNameShort` TEXT NOT NULL, `accountName` TEXT, `studentData` TEXT NOT NULL, `image` TEXT, `empty` INTEGER NOT NULL, `archived` INTEGER NOT NULL, `syncEnabled` INTEGER NOT NULL, `enableSharedEvents` INTEGER NOT NULL, `registration` INTEGER NOT NULL, `userCode` TEXT NOT NULL, `archiveId` INTEGER, `studentNumber` INTEGER NOT NULL, `studentClassName` TEXT, `studentSchoolYearStart` INTEGER NOT NULL, `dateSemester1Start` TEXT NOT NULL, `dateSemester2Start` TEXT NOT NULL, `dateYearEnd` TEXT NOT NULL, `disabledNotifications` TEXT, `lastReceiversSync` INTEGER NOT NULL, PRIMARY KEY(`profileId`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginStoreId",
+ "columnName": "loginStoreId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginStoreType",
+ "columnName": "loginStoreType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subname",
+ "columnName": "subname",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "studentNameLong",
+ "columnName": "studentNameLong",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentNameShort",
+ "columnName": "studentNameShort",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountName",
+ "columnName": "accountName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "studentData",
+ "columnName": "studentData",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "image",
+ "columnName": "image",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "empty",
+ "columnName": "empty",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "archived",
+ "columnName": "archived",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "syncEnabled",
+ "columnName": "syncEnabled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unused1",
+ "columnName": "enableSharedEvents",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registration",
+ "columnName": "registration",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userCode",
+ "columnName": "userCode",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "archiveId",
+ "columnName": "archiveId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "studentNumber",
+ "columnName": "studentNumber",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentClassName",
+ "columnName": "studentClassName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "studentSchoolYearStart",
+ "columnName": "studentSchoolYearStart",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "dateSemester1Start",
+ "columnName": "dateSemester1Start",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "dateSemester2Start",
+ "columnName": "dateSemester2Start",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "dateYearEnd",
+ "columnName": "dateYearEnd",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "disabledNotifications",
+ "columnName": "disabledNotifications",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lastReceiversSync",
+ "columnName": "lastReceiversSync",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "luckyNumbers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `luckyNumberDate` INTEGER NOT NULL, `luckyNumber` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `luckyNumberDate`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "luckyNumberDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "luckyNumber",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "luckyNumberDate"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "announcements",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `announcementId` INTEGER NOT NULL, `announcementSubject` TEXT NOT NULL, `announcementText` TEXT, `announcementStartDate` TEXT, `announcementEndDate` TEXT, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `announcementIdString` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `announcementId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "announcementId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "announcementSubject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "announcementText",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "startDate",
+ "columnName": "announcementStartDate",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "endDate",
+ "columnName": "announcementEndDate",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "idString",
+ "columnName": "announcementIdString",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "announcementId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_announcements_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_announcements_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "gradeCategories",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `categoryId` INTEGER NOT NULL, `weight` REAL NOT NULL, `color` INTEGER NOT NULL, `text` TEXT, `columns` TEXT, `valueFrom` REAL NOT NULL, `valueTo` REAL NOT NULL, `type` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `categoryId`, `type`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "categoryId",
+ "columnName": "categoryId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "color",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "columns",
+ "columnName": "columns",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "valueFrom",
+ "columnName": "valueFrom",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "valueTo",
+ "columnName": "valueTo",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "categoryId",
+ "type"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "feedbackMessages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `received` INTEGER NOT NULL, `text` TEXT NOT NULL, `senderName` TEXT NOT NULL, `deviceId` TEXT, `deviceName` TEXT, `devId` INTEGER, `devImage` TEXT, `sentTime` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "messageId",
+ "columnName": "messageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "received",
+ "columnName": "received",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "senderName",
+ "columnName": "senderName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deviceId",
+ "columnName": "deviceId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "deviceName",
+ "columnName": "deviceName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "devId",
+ "columnName": "devId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "devImage",
+ "columnName": "devImage",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sentTime",
+ "columnName": "sentTime",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "messageId"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "messages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `messageId` INTEGER NOT NULL, `messageType` INTEGER NOT NULL, `messageSubject` TEXT NOT NULL, `messageBody` TEXT, `senderId` INTEGER, `addedDate` INTEGER NOT NULL, `messageIsPinned` INTEGER NOT NULL, `hasAttachments` INTEGER NOT NULL, `attachmentIds` TEXT, `attachmentNames` TEXT, `attachmentSizes` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `messageId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "messageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "messageType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "messageSubject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "body",
+ "columnName": "messageBody",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "senderId",
+ "columnName": "senderId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isStarred",
+ "columnName": "messageIsPinned",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasAttachments",
+ "columnName": "hasAttachments",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "attachmentIds",
+ "columnName": "attachmentIds",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachmentNames",
+ "columnName": "attachmentNames",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachmentSizes",
+ "columnName": "attachmentSizes",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "messageId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_messages_profileId_messageType",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "messageType"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_messages_profileId_messageType` ON `${TABLE_NAME}` (`profileId`, `messageType`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "messageRecipients",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `messageRecipientId` INTEGER NOT NULL, `messageRecipientReplyId` INTEGER NOT NULL, `messageRecipientReadDate` INTEGER NOT NULL, `messageId` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `messageRecipientId`, `messageId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "messageRecipientId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "replyId",
+ "columnName": "messageRecipientReplyId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "readDate",
+ "columnName": "messageRecipientReadDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageId",
+ "columnName": "messageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "messageRecipientId",
+ "messageId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "debugLogs",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `text` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "endpointTimers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `endpointId` INTEGER NOT NULL, `endpointLastSync` INTEGER, `endpointNextSync` INTEGER NOT NULL, `endpointViewId` INTEGER, PRIMARY KEY(`profileId`, `endpointId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "endpointId",
+ "columnName": "endpointId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastSync",
+ "columnName": "endpointLastSync",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "nextSync",
+ "columnName": "endpointNextSync",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "featureType",
+ "columnName": "endpointViewId",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "endpointId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "lessonRanges",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `lessonRangeNumber` INTEGER NOT NULL, `lessonRangeStart` TEXT NOT NULL, `lessonRangeEnd` TEXT NOT NULL, PRIMARY KEY(`profileId`, `lessonRangeNumber`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lessonNumber",
+ "columnName": "lessonRangeNumber",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "startTime",
+ "columnName": "lessonRangeStart",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "endTime",
+ "columnName": "lessonRangeEnd",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "lessonRangeNumber"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "notifications",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `text` TEXT NOT NULL, `textLong` TEXT, `type` INTEGER NOT NULL, `profileId` INTEGER, `profileName` TEXT, `posted` INTEGER NOT NULL, `viewId` INTEGER, `extras` TEXT, `addedDate` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "textLong",
+ "columnName": "textLong",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileName",
+ "columnName": "profileName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "posted",
+ "columnName": "posted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "navTarget",
+ "columnName": "viewId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "extras",
+ "columnName": "extras",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "classrooms",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`profileId`, `id`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "noticeTypes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`profileId`, `id`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "attendanceTypes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `baseType` INTEGER NOT NULL, `typeName` TEXT NOT NULL, `typeShort` TEXT NOT NULL, `typeSymbol` TEXT NOT NULL, `typeColor` INTEGER, PRIMARY KEY(`profileId`, `id`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "baseType",
+ "columnName": "baseType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeName",
+ "columnName": "typeName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeShort",
+ "columnName": "typeShort",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeSymbol",
+ "columnName": "typeSymbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeColor",
+ "columnName": "typeColor",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "timetable",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `type` INTEGER NOT NULL, `date` TEXT, `lessonNumber` INTEGER, `startTime` TEXT, `endTime` TEXT, `subjectId` INTEGER, `teacherId` INTEGER, `teamId` INTEGER, `classroom` TEXT, `oldDate` TEXT, `oldLessonNumber` INTEGER, `oldStartTime` TEXT, `oldEndTime` TEXT, `oldSubjectId` INTEGER, `oldTeacherId` INTEGER, `oldTeamId` INTEGER, `oldClassroom` TEXT, `isExtra` INTEGER NOT NULL, `ownerId` INTEGER NOT NULL, `color` INTEGER, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `id`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lessonNumber",
+ "columnName": "lessonNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "startTime",
+ "columnName": "startTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "endTime",
+ "columnName": "endTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teamId",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "classroom",
+ "columnName": "classroom",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldDate",
+ "columnName": "oldDate",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldLessonNumber",
+ "columnName": "oldLessonNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldStartTime",
+ "columnName": "oldStartTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldEndTime",
+ "columnName": "oldEndTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldSubjectId",
+ "columnName": "oldSubjectId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldTeacherId",
+ "columnName": "oldTeacherId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldTeamId",
+ "columnName": "oldTeamId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldClassroom",
+ "columnName": "oldClassroom",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isExtra",
+ "columnName": "isExtra",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "ownerId",
+ "columnName": "ownerId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "color",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_timetable_profileId_type_date",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "type",
+ "date"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_timetable_profileId_type_date` ON `${TABLE_NAME}` (`profileId`, `type`, `date`)"
+ },
+ {
+ "name": "index_timetable_profileId_type_oldDate",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "type",
+ "oldDate"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_timetable_profileId_type_oldDate` ON `${TABLE_NAME}` (`profileId`, `type`, `oldDate`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "config",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `key` TEXT NOT NULL, `value` TEXT, PRIMARY KEY(`profileId`, `key`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "key",
+ "columnName": "key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "key"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "librusLessons",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `lessonId` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `teamId` INTEGER, PRIMARY KEY(`profileId`, `lessonId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lessonId",
+ "columnName": "lessonId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teamId",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "lessonId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_librusLessons_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_librusLessons_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "timetableManual",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `repeatBy` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `date` INTEGER, `weekDay` INTEGER, `lessonNumber` INTEGER, `startTime` TEXT, `endTime` TEXT, `subjectId` INTEGER, `teacherId` INTEGER, `teamId` INTEGER, `classroom` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "repeatBy",
+ "columnName": "repeatBy",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "weekDay",
+ "columnName": "weekDay",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lessonNumber",
+ "columnName": "lessonNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "startTime",
+ "columnName": "startTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "endTime",
+ "columnName": "endTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teamId",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "classroom",
+ "columnName": "classroom",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_timetableManual_profileId_date",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "date"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_timetableManual_profileId_date` ON `${TABLE_NAME}` (`profileId`, `date`)"
+ },
+ {
+ "name": "index_timetableManual_profileId_weekDay",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "weekDay"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_timetableManual_profileId_weekDay` ON `${TABLE_NAME}` (`profileId`, `weekDay`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "notes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `noteId` INTEGER NOT NULL, `noteOwnerType` TEXT, `noteOwnerId` INTEGER, `noteReplacesOriginal` INTEGER NOT NULL, `noteTopic` TEXT, `noteBody` TEXT NOT NULL, `noteColor` INTEGER, `noteSharedBy` TEXT, `noteSharedByName` TEXT, `addedDate` INTEGER NOT NULL, PRIMARY KEY(`noteId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "noteId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "ownerType",
+ "columnName": "noteOwnerType",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "ownerId",
+ "columnName": "noteOwnerId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "replacesOriginal",
+ "columnName": "noteReplacesOriginal",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "topic",
+ "columnName": "noteTopic",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "body",
+ "columnName": "noteBody",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "noteColor",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sharedBy",
+ "columnName": "noteSharedBy",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sharedByName",
+ "columnName": "noteSharedByName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "noteId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_notes_profileId_noteOwnerType_noteOwnerId",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "noteOwnerType",
+ "noteOwnerId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_notes_profileId_noteOwnerType_noteOwnerId` ON `${TABLE_NAME}` (`profileId`, `noteOwnerType`, `noteOwnerId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "metadata",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `metadataId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `thingType` INTEGER NOT NULL, `thingId` INTEGER NOT NULL, `seen` INTEGER NOT NULL, `notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "metadataId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thingType",
+ "columnName": "thingType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thingId",
+ "columnName": "thingId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "seen",
+ "columnName": "seen",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notified",
+ "columnName": "notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "metadataId"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_metadata_profileId_thingType_thingId",
+ "unique": true,
+ "columnNames": [
+ "profileId",
+ "thingType",
+ "thingId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_metadata_profileId_thingType_thingId` ON `${TABLE_NAME}` (`profileId`, `thingType`, `thingId`)"
+ }
+ ],
+ "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, '4c141460d807d32d00faad4fb3c12522')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/97.json b/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/97.json
new file mode 100644
index 00000000..37b6d0f4
--- /dev/null
+++ b/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/97.json
@@ -0,0 +1,2293 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 97,
+ "identityHash": "08a8998e311e4e62a9e9554132b5c011",
+ "entities": [
+ {
+ "tableName": "grades",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `gradeId` INTEGER NOT NULL, `gradeName` TEXT NOT NULL, `gradeType` INTEGER NOT NULL, `gradeValue` REAL NOT NULL, `gradeWeight` REAL NOT NULL, `gradeColor` INTEGER NOT NULL, `gradeCategory` TEXT, `gradeDescription` TEXT, `gradeComment` TEXT, `gradeSemester` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `gradeValueMax` REAL, `gradeClassAverage` REAL, `gradeParentId` INTEGER, `gradeIsImprovement` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `gradeId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "gradeId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "gradeName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "gradeType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "gradeValue",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "gradeWeight",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "gradeColor",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "gradeCategory",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "gradeDescription",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "gradeComment",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "semester",
+ "columnName": "gradeSemester",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "valueMax",
+ "columnName": "gradeValueMax",
+ "affinity": "REAL",
+ "notNull": false
+ },
+ {
+ "fieldPath": "classAverage",
+ "columnName": "gradeClassAverage",
+ "affinity": "REAL",
+ "notNull": false
+ },
+ {
+ "fieldPath": "parentId",
+ "columnName": "gradeParentId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isImprovement",
+ "columnName": "gradeIsImprovement",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "gradeId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_grades_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_grades_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "teachers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `teacherLoginId` TEXT, `teacherName` TEXT, `teacherSurname` TEXT, `teacherType` INTEGER NOT NULL, `teacherTypeDescription` TEXT, `teacherSubjects` TEXT NOT NULL, PRIMARY KEY(`profileId`, `teacherId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginId",
+ "columnName": "teacherLoginId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "teacherName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "surname",
+ "columnName": "teacherSurname",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "teacherType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeDescription",
+ "columnName": "teacherTypeDescription",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "subjects",
+ "columnName": "teacherSubjects",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "teacherId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "teacherAbsence",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherAbsenceId` INTEGER NOT NULL, `teacherAbsenceType` INTEGER NOT NULL, `teacherAbsenceName` TEXT, `teacherAbsenceDateFrom` TEXT NOT NULL, `teacherAbsenceDateTo` TEXT NOT NULL, `teacherAbsenceTimeFrom` TEXT, `teacherAbsenceTimeTo` TEXT, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `teacherAbsenceId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "teacherAbsenceId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "teacherAbsenceType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "teacherAbsenceName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "dateFrom",
+ "columnName": "teacherAbsenceDateFrom",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "dateTo",
+ "columnName": "teacherAbsenceDateTo",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "timeFrom",
+ "columnName": "teacherAbsenceTimeFrom",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "timeTo",
+ "columnName": "teacherAbsenceTimeTo",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "teacherAbsenceId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_teacherAbsence_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_teacherAbsence_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "teacherAbsenceTypes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherAbsenceTypeId` INTEGER NOT NULL, `teacherAbsenceTypeName` TEXT NOT NULL, PRIMARY KEY(`profileId`, `teacherAbsenceTypeId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "teacherAbsenceTypeId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "teacherAbsenceTypeName",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "teacherAbsenceTypeId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "subjects",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `subjectLongName` TEXT, `subjectShortName` TEXT, `subjectColor` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `subjectId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "longName",
+ "columnName": "subjectLongName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "shortName",
+ "columnName": "subjectShortName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "subjectColor",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "subjectId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "notices",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `noticeId` INTEGER NOT NULL, `noticeType` INTEGER NOT NULL, `noticeSemester` INTEGER NOT NULL, `noticeText` TEXT NOT NULL, `noticeCategory` TEXT, `noticePoints` REAL, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `noticeId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "noticeId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "noticeType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semester",
+ "columnName": "noticeSemester",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "noticeText",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "noticeCategory",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "points",
+ "columnName": "noticePoints",
+ "affinity": "REAL",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "noticeId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_notices_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_notices_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "teams",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teamId` INTEGER NOT NULL, `teamType` INTEGER NOT NULL, `teamName` TEXT, `teamCode` TEXT, `teamTeacherId` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `teamId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "teamType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "teamName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "code",
+ "columnName": "teamCode",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teamTeacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "teamId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "attendances",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `attendanceId` INTEGER NOT NULL, `attendanceBaseType` INTEGER NOT NULL, `attendanceTypeName` TEXT NOT NULL, `attendanceTypeShort` TEXT NOT NULL, `attendanceTypeSymbol` TEXT NOT NULL, `attendanceTypeColor` INTEGER, `attendanceDate` TEXT NOT NULL, `attendanceTime` TEXT, `attendanceSemester` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `attendanceLessonTopic` TEXT, `attendanceLessonNumber` INTEGER, `attendanceIsCounted` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `attendanceId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "attendanceId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "baseType",
+ "columnName": "attendanceBaseType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeName",
+ "columnName": "attendanceTypeName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeShort",
+ "columnName": "attendanceTypeShort",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeSymbol",
+ "columnName": "attendanceTypeSymbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeColor",
+ "columnName": "attendanceTypeColor",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "attendanceDate",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "startTime",
+ "columnName": "attendanceTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "semester",
+ "columnName": "attendanceSemester",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lessonTopic",
+ "columnName": "attendanceLessonTopic",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lessonNumber",
+ "columnName": "attendanceLessonNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isCounted",
+ "columnName": "attendanceIsCounted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "attendanceId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_attendances_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_attendances_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "events",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `eventId` INTEGER NOT NULL, `eventDate` TEXT NOT NULL, `eventTime` TEXT, `eventTopic` TEXT NOT NULL, `eventColor` INTEGER, `eventType` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `teamId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `eventAddedManually` INTEGER NOT NULL, `eventSharedBy` TEXT, `eventSharedByName` TEXT, `eventBlacklisted` INTEGER NOT NULL, `eventIsDone` INTEGER NOT NULL, `eventIsDownloaded` INTEGER NOT NULL, `homeworkBody` TEXT, `attachmentIds` TEXT, `attachmentNames` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `eventId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "eventId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "eventDate",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "time",
+ "columnName": "eventTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "topic",
+ "columnName": "eventTopic",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "eventColor",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "eventType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teamId",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedManually",
+ "columnName": "eventAddedManually",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "sharedBy",
+ "columnName": "eventSharedBy",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sharedByName",
+ "columnName": "eventSharedByName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "blacklisted",
+ "columnName": "eventBlacklisted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDone",
+ "columnName": "eventIsDone",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDownloaded",
+ "columnName": "eventIsDownloaded",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "homeworkBody",
+ "columnName": "homeworkBody",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachmentIds",
+ "columnName": "attachmentIds",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachmentNames",
+ "columnName": "attachmentNames",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "eventId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_events_profileId_eventDate_eventTime",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "eventDate",
+ "eventTime"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_events_profileId_eventDate_eventTime` ON `${TABLE_NAME}` (`profileId`, `eventDate`, `eventTime`)"
+ },
+ {
+ "name": "index_events_profileId_eventType",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "eventType"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_events_profileId_eventType` ON `${TABLE_NAME}` (`profileId`, `eventType`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "eventTypes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `eventType` INTEGER NOT NULL, `eventTypeName` TEXT NOT NULL, `eventTypeColor` INTEGER NOT NULL, `eventTypeOrder` INTEGER NOT NULL, `eventTypeSource` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `eventType`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "eventType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "eventTypeName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "eventTypeColor",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "order",
+ "columnName": "eventTypeOrder",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "source",
+ "columnName": "eventTypeSource",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "eventType"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "loginStores",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`loginStoreId` INTEGER NOT NULL, `loginStoreType` INTEGER NOT NULL, `loginStoreMode` INTEGER NOT NULL, `loginStoreData` TEXT NOT NULL, PRIMARY KEY(`loginStoreId`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "loginStoreId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "loginStoreType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mode",
+ "columnName": "loginStoreMode",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "data",
+ "columnName": "loginStoreData",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "loginStoreId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "profiles",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `loginStoreId` INTEGER NOT NULL, `loginStoreType` INTEGER NOT NULL, `name` TEXT NOT NULL, `subname` TEXT, `studentNameLong` TEXT NOT NULL, `studentNameShort` TEXT NOT NULL, `accountName` TEXT, `studentData` TEXT NOT NULL, `image` TEXT, `empty` INTEGER NOT NULL, `archived` INTEGER NOT NULL, `archiveId` INTEGER, `syncEnabled` INTEGER NOT NULL, `enableSharedEvents` INTEGER NOT NULL, `registration` INTEGER NOT NULL, `userCode` TEXT NOT NULL, `studentNumber` INTEGER NOT NULL, `studentClassName` TEXT, `studentSchoolYearStart` INTEGER NOT NULL, `dateSemester1Start` TEXT NOT NULL, `dateSemester2Start` TEXT NOT NULL, `dateYearEnd` TEXT NOT NULL, `disabledNotifications` TEXT, `lastReceiversSync` INTEGER NOT NULL, PRIMARY KEY(`profileId`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginStoreId",
+ "columnName": "loginStoreId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginStoreType",
+ "columnName": "loginStoreType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subname",
+ "columnName": "subname",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "studentNameLong",
+ "columnName": "studentNameLong",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentNameShort",
+ "columnName": "studentNameShort",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountName",
+ "columnName": "accountName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "studentData",
+ "columnName": "studentData",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "image",
+ "columnName": "image",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "empty",
+ "columnName": "empty",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "archived",
+ "columnName": "archived",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "archiveId",
+ "columnName": "archiveId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "syncEnabled",
+ "columnName": "syncEnabled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "enableSharedEvents",
+ "columnName": "enableSharedEvents",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registration",
+ "columnName": "registration",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userCode",
+ "columnName": "userCode",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentNumber",
+ "columnName": "studentNumber",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentClassName",
+ "columnName": "studentClassName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "studentSchoolYearStart",
+ "columnName": "studentSchoolYearStart",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "dateSemester1Start",
+ "columnName": "dateSemester1Start",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "dateSemester2Start",
+ "columnName": "dateSemester2Start",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "dateYearEnd",
+ "columnName": "dateYearEnd",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "disabledNotifications",
+ "columnName": "disabledNotifications",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lastReceiversSync",
+ "columnName": "lastReceiversSync",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "luckyNumbers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `luckyNumberDate` INTEGER NOT NULL, `luckyNumber` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `luckyNumberDate`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "luckyNumberDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "luckyNumber",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "luckyNumberDate"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "announcements",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `announcementId` INTEGER NOT NULL, `announcementSubject` TEXT NOT NULL, `announcementText` TEXT, `announcementStartDate` TEXT, `announcementEndDate` TEXT, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `announcementIdString` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `announcementId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "announcementId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "announcementSubject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "announcementText",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "startDate",
+ "columnName": "announcementStartDate",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "endDate",
+ "columnName": "announcementEndDate",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "idString",
+ "columnName": "announcementIdString",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "announcementId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_announcements_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_announcements_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "gradeCategories",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `categoryId` INTEGER NOT NULL, `weight` REAL NOT NULL, `color` INTEGER NOT NULL, `text` TEXT, `columns` TEXT, `valueFrom` REAL NOT NULL, `valueTo` REAL NOT NULL, `type` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `categoryId`, `type`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "categoryId",
+ "columnName": "categoryId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "color",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "columns",
+ "columnName": "columns",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "valueFrom",
+ "columnName": "valueFrom",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "valueTo",
+ "columnName": "valueTo",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "categoryId",
+ "type"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "feedbackMessages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `received` INTEGER NOT NULL, `text` TEXT NOT NULL, `senderName` TEXT NOT NULL, `deviceId` TEXT, `deviceName` TEXT, `devId` INTEGER, `devImage` TEXT, `sentTime` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "messageId",
+ "columnName": "messageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "received",
+ "columnName": "received",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "senderName",
+ "columnName": "senderName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deviceId",
+ "columnName": "deviceId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "deviceName",
+ "columnName": "deviceName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "devId",
+ "columnName": "devId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "devImage",
+ "columnName": "devImage",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sentTime",
+ "columnName": "sentTime",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "messageId"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "messages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `messageId` INTEGER NOT NULL, `messageType` INTEGER NOT NULL, `messageSubject` TEXT NOT NULL, `messageBody` TEXT, `senderId` INTEGER, `addedDate` INTEGER NOT NULL, `messageIsPinned` INTEGER NOT NULL, `hasAttachments` INTEGER NOT NULL, `attachmentIds` TEXT, `attachmentNames` TEXT, `attachmentSizes` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `messageId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "messageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "messageType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "messageSubject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "body",
+ "columnName": "messageBody",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "senderId",
+ "columnName": "senderId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isStarred",
+ "columnName": "messageIsPinned",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasAttachments",
+ "columnName": "hasAttachments",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "attachmentIds",
+ "columnName": "attachmentIds",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachmentNames",
+ "columnName": "attachmentNames",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachmentSizes",
+ "columnName": "attachmentSizes",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "messageId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_messages_profileId_messageType",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "messageType"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_messages_profileId_messageType` ON `${TABLE_NAME}` (`profileId`, `messageType`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "messageRecipients",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `messageRecipientId` INTEGER NOT NULL, `messageRecipientReplyId` INTEGER NOT NULL, `messageRecipientReadDate` INTEGER NOT NULL, `messageId` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `messageRecipientId`, `messageId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "messageRecipientId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "replyId",
+ "columnName": "messageRecipientReplyId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "readDate",
+ "columnName": "messageRecipientReadDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageId",
+ "columnName": "messageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "messageRecipientId",
+ "messageId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "debugLogs",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `text` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "endpointTimers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `endpointId` INTEGER NOT NULL, `endpointLastSync` INTEGER, `endpointNextSync` INTEGER NOT NULL, `endpointViewId` INTEGER, PRIMARY KEY(`profileId`, `endpointId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "endpointId",
+ "columnName": "endpointId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastSync",
+ "columnName": "endpointLastSync",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "nextSync",
+ "columnName": "endpointNextSync",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "viewId",
+ "columnName": "endpointViewId",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "endpointId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "lessonRanges",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `lessonRangeNumber` INTEGER NOT NULL, `lessonRangeStart` TEXT NOT NULL, `lessonRangeEnd` TEXT NOT NULL, PRIMARY KEY(`profileId`, `lessonRangeNumber`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lessonNumber",
+ "columnName": "lessonRangeNumber",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "startTime",
+ "columnName": "lessonRangeStart",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "endTime",
+ "columnName": "lessonRangeEnd",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "lessonRangeNumber"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "notifications",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `text` TEXT NOT NULL, `textLong` TEXT, `type` INTEGER NOT NULL, `profileId` INTEGER, `profileName` TEXT, `posted` INTEGER NOT NULL, `viewId` INTEGER, `extras` TEXT, `addedDate` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "textLong",
+ "columnName": "textLong",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileName",
+ "columnName": "profileName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "posted",
+ "columnName": "posted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "viewId",
+ "columnName": "viewId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "extras",
+ "columnName": "extras",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "classrooms",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`profileId`, `id`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "noticeTypes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`profileId`, `id`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "attendanceTypes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `baseType` INTEGER NOT NULL, `typeName` TEXT NOT NULL, `typeShort` TEXT NOT NULL, `typeSymbol` TEXT NOT NULL, `typeColor` INTEGER, PRIMARY KEY(`profileId`, `id`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "baseType",
+ "columnName": "baseType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeName",
+ "columnName": "typeName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeShort",
+ "columnName": "typeShort",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeSymbol",
+ "columnName": "typeSymbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeColor",
+ "columnName": "typeColor",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "timetable",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `type` INTEGER NOT NULL, `date` TEXT, `lessonNumber` INTEGER, `startTime` TEXT, `endTime` TEXT, `subjectId` INTEGER, `teacherId` INTEGER, `teamId` INTEGER, `classroom` TEXT, `oldDate` TEXT, `oldLessonNumber` INTEGER, `oldStartTime` TEXT, `oldEndTime` TEXT, `oldSubjectId` INTEGER, `oldTeacherId` INTEGER, `oldTeamId` INTEGER, `oldClassroom` TEXT, `isExtra` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `id`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lessonNumber",
+ "columnName": "lessonNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "startTime",
+ "columnName": "startTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "endTime",
+ "columnName": "endTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teamId",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "classroom",
+ "columnName": "classroom",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldDate",
+ "columnName": "oldDate",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldLessonNumber",
+ "columnName": "oldLessonNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldStartTime",
+ "columnName": "oldStartTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldEndTime",
+ "columnName": "oldEndTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldSubjectId",
+ "columnName": "oldSubjectId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldTeacherId",
+ "columnName": "oldTeacherId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldTeamId",
+ "columnName": "oldTeamId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldClassroom",
+ "columnName": "oldClassroom",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isExtra",
+ "columnName": "isExtra",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_timetable_profileId_type_date",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "type",
+ "date"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_timetable_profileId_type_date` ON `${TABLE_NAME}` (`profileId`, `type`, `date`)"
+ },
+ {
+ "name": "index_timetable_profileId_type_oldDate",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "type",
+ "oldDate"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_timetable_profileId_type_oldDate` ON `${TABLE_NAME}` (`profileId`, `type`, `oldDate`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "config",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `key` TEXT NOT NULL, `value` TEXT, PRIMARY KEY(`profileId`, `key`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "key",
+ "columnName": "key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "key"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "librusLessons",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `lessonId` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `teamId` INTEGER, PRIMARY KEY(`profileId`, `lessonId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lessonId",
+ "columnName": "lessonId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teamId",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "lessonId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_librusLessons_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_librusLessons_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "timetableManual",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `repeatBy` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `date` INTEGER, `weekDay` INTEGER, `lessonNumber` INTEGER, `startTime` TEXT, `endTime` TEXT, `subjectId` INTEGER, `teacherId` INTEGER, `teamId` INTEGER, `classroom` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "repeatBy",
+ "columnName": "repeatBy",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "weekDay",
+ "columnName": "weekDay",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lessonNumber",
+ "columnName": "lessonNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "startTime",
+ "columnName": "startTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "endTime",
+ "columnName": "endTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teamId",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "classroom",
+ "columnName": "classroom",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_timetableManual_profileId_date",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "date"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_timetableManual_profileId_date` ON `${TABLE_NAME}` (`profileId`, `date`)"
+ },
+ {
+ "name": "index_timetableManual_profileId_weekDay",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "weekDay"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_timetableManual_profileId_weekDay` ON `${TABLE_NAME}` (`profileId`, `weekDay`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "notes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `noteId` INTEGER NOT NULL, `noteOwnerType` TEXT, `noteOwnerId` INTEGER, `noteReplacesOriginal` INTEGER NOT NULL, `noteTopic` TEXT, `noteBody` TEXT NOT NULL, `noteColor` INTEGER, `noteSharedBy` TEXT, `noteSharedByName` TEXT, `addedDate` INTEGER NOT NULL, PRIMARY KEY(`noteId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "noteId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "ownerType",
+ "columnName": "noteOwnerType",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "ownerId",
+ "columnName": "noteOwnerId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "replacesOriginal",
+ "columnName": "noteReplacesOriginal",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "topic",
+ "columnName": "noteTopic",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "body",
+ "columnName": "noteBody",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "noteColor",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sharedBy",
+ "columnName": "noteSharedBy",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sharedByName",
+ "columnName": "noteSharedByName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "noteId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_notes_profileId_noteOwnerType_noteOwnerId",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "noteOwnerType",
+ "noteOwnerId"
+ ],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_notes_profileId_noteOwnerType_noteOwnerId` ON `${TABLE_NAME}` (`profileId`, `noteOwnerType`, `noteOwnerId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "metadata",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `metadataId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `thingType` INTEGER NOT NULL, `thingId` INTEGER NOT NULL, `seen` INTEGER NOT NULL, `notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "metadataId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thingType",
+ "columnName": "thingType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thingId",
+ "columnName": "thingId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "seen",
+ "columnName": "seen",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notified",
+ "columnName": "notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "metadataId"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_metadata_profileId_thingType_thingId",
+ "unique": true,
+ "columnNames": [
+ "profileId",
+ "thingType",
+ "thingId"
+ ],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_metadata_profileId_thingType_thingId` ON `${TABLE_NAME}` (`profileId`, `thingType`, `thingId`)"
+ }
+ ],
+ "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, '08a8998e311e4e62a9e9554132b5c011')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/98.json b/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/98.json
new file mode 100644
index 00000000..1a291aef
--- /dev/null
+++ b/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/98.json
@@ -0,0 +1,2314 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 98,
+ "identityHash": "2612ebba9802eedc7ebc69724606a23c",
+ "entities": [
+ {
+ "tableName": "grades",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `gradeId` INTEGER NOT NULL, `gradeName` TEXT NOT NULL, `gradeType` INTEGER NOT NULL, `gradeValue` REAL NOT NULL, `gradeWeight` REAL NOT NULL, `gradeColor` INTEGER NOT NULL, `gradeCategory` TEXT, `gradeDescription` TEXT, `gradeComment` TEXT, `gradeSemester` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `gradeValueMax` REAL, `gradeClassAverage` REAL, `gradeParentId` INTEGER, `gradeIsImprovement` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `gradeId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "gradeId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "gradeName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "gradeType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "gradeValue",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "gradeWeight",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "gradeColor",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "gradeCategory",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "gradeDescription",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "gradeComment",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "semester",
+ "columnName": "gradeSemester",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "valueMax",
+ "columnName": "gradeValueMax",
+ "affinity": "REAL",
+ "notNull": false
+ },
+ {
+ "fieldPath": "classAverage",
+ "columnName": "gradeClassAverage",
+ "affinity": "REAL",
+ "notNull": false
+ },
+ {
+ "fieldPath": "parentId",
+ "columnName": "gradeParentId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isImprovement",
+ "columnName": "gradeIsImprovement",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "gradeId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_grades_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_grades_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "teachers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `teacherLoginId` TEXT, `teacherName` TEXT, `teacherSurname` TEXT, `teacherType` INTEGER NOT NULL, `teacherTypeDescription` TEXT, `teacherSubjects` TEXT NOT NULL, PRIMARY KEY(`profileId`, `teacherId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginId",
+ "columnName": "teacherLoginId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "teacherName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "surname",
+ "columnName": "teacherSurname",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "teacherType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeDescription",
+ "columnName": "teacherTypeDescription",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "subjects",
+ "columnName": "teacherSubjects",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "teacherId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "teacherAbsence",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherAbsenceId` INTEGER NOT NULL, `teacherAbsenceType` INTEGER NOT NULL, `teacherAbsenceName` TEXT, `teacherAbsenceDateFrom` TEXT NOT NULL, `teacherAbsenceDateTo` TEXT NOT NULL, `teacherAbsenceTimeFrom` TEXT, `teacherAbsenceTimeTo` TEXT, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `teacherAbsenceId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "teacherAbsenceId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "teacherAbsenceType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "teacherAbsenceName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "dateFrom",
+ "columnName": "teacherAbsenceDateFrom",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "dateTo",
+ "columnName": "teacherAbsenceDateTo",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "timeFrom",
+ "columnName": "teacherAbsenceTimeFrom",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "timeTo",
+ "columnName": "teacherAbsenceTimeTo",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "teacherAbsenceId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_teacherAbsence_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_teacherAbsence_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "teacherAbsenceTypes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherAbsenceTypeId` INTEGER NOT NULL, `teacherAbsenceTypeName` TEXT NOT NULL, PRIMARY KEY(`profileId`, `teacherAbsenceTypeId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "teacherAbsenceTypeId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "teacherAbsenceTypeName",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "teacherAbsenceTypeId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "subjects",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `subjectLongName` TEXT, `subjectShortName` TEXT, `subjectColor` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `subjectId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "longName",
+ "columnName": "subjectLongName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "shortName",
+ "columnName": "subjectShortName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "subjectColor",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "subjectId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "notices",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `noticeId` INTEGER NOT NULL, `noticeType` INTEGER NOT NULL, `noticeSemester` INTEGER NOT NULL, `noticeText` TEXT NOT NULL, `noticeCategory` TEXT, `noticePoints` REAL, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `noticeId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "noticeId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "noticeType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semester",
+ "columnName": "noticeSemester",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "noticeText",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "noticeCategory",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "points",
+ "columnName": "noticePoints",
+ "affinity": "REAL",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "noticeId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_notices_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_notices_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "teams",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teamId` INTEGER NOT NULL, `teamType` INTEGER NOT NULL, `teamName` TEXT, `teamCode` TEXT, `teamTeacherId` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `teamId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "teamType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "teamName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "code",
+ "columnName": "teamCode",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teamTeacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "teamId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "attendances",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `attendanceId` INTEGER NOT NULL, `attendanceBaseType` INTEGER NOT NULL, `attendanceTypeName` TEXT NOT NULL, `attendanceTypeShort` TEXT NOT NULL, `attendanceTypeSymbol` TEXT NOT NULL, `attendanceTypeColor` INTEGER, `attendanceDate` TEXT NOT NULL, `attendanceTime` TEXT, `attendanceSemester` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `attendanceLessonTopic` TEXT, `attendanceLessonNumber` INTEGER, `attendanceIsCounted` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `attendanceId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "attendanceId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "baseType",
+ "columnName": "attendanceBaseType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeName",
+ "columnName": "attendanceTypeName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeShort",
+ "columnName": "attendanceTypeShort",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeSymbol",
+ "columnName": "attendanceTypeSymbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeColor",
+ "columnName": "attendanceTypeColor",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "attendanceDate",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "startTime",
+ "columnName": "attendanceTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "semester",
+ "columnName": "attendanceSemester",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lessonTopic",
+ "columnName": "attendanceLessonTopic",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lessonNumber",
+ "columnName": "attendanceLessonNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isCounted",
+ "columnName": "attendanceIsCounted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "attendanceId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_attendances_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_attendances_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "events",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `eventId` INTEGER NOT NULL, `eventDate` TEXT NOT NULL, `eventTime` TEXT, `eventTopic` TEXT NOT NULL, `eventColor` INTEGER, `eventType` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `teamId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `eventAddedManually` INTEGER NOT NULL, `eventSharedBy` TEXT, `eventSharedByName` TEXT, `eventBlacklisted` INTEGER NOT NULL, `eventIsDone` INTEGER NOT NULL, `eventIsDownloaded` INTEGER NOT NULL, `homeworkBody` TEXT, `attachmentIds` TEXT, `attachmentNames` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `eventId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "eventId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "eventDate",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "time",
+ "columnName": "eventTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "topic",
+ "columnName": "eventTopic",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "eventColor",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "eventType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teamId",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedManually",
+ "columnName": "eventAddedManually",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "sharedBy",
+ "columnName": "eventSharedBy",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sharedByName",
+ "columnName": "eventSharedByName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "blacklisted",
+ "columnName": "eventBlacklisted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDone",
+ "columnName": "eventIsDone",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDownloaded",
+ "columnName": "eventIsDownloaded",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "homeworkBody",
+ "columnName": "homeworkBody",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachmentIds",
+ "columnName": "attachmentIds",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachmentNames",
+ "columnName": "attachmentNames",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "eventId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_events_profileId_eventDate_eventTime",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "eventDate",
+ "eventTime"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_events_profileId_eventDate_eventTime` ON `${TABLE_NAME}` (`profileId`, `eventDate`, `eventTime`)"
+ },
+ {
+ "name": "index_events_profileId_eventType",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "eventType"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_events_profileId_eventType` ON `${TABLE_NAME}` (`profileId`, `eventType`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "eventTypes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `eventType` INTEGER NOT NULL, `eventTypeName` TEXT NOT NULL, `eventTypeColor` INTEGER NOT NULL, `eventTypeOrder` INTEGER NOT NULL, `eventTypeSource` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `eventType`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "eventType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "eventTypeName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "eventTypeColor",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "order",
+ "columnName": "eventTypeOrder",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "source",
+ "columnName": "eventTypeSource",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "eventType"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "loginStores",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`loginStoreId` INTEGER NOT NULL, `loginStoreType` INTEGER NOT NULL, `loginStoreMode` INTEGER NOT NULL, `loginStoreData` TEXT NOT NULL, PRIMARY KEY(`loginStoreId`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "loginStoreId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "loginStoreType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mode",
+ "columnName": "loginStoreMode",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "data",
+ "columnName": "loginStoreData",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "loginStoreId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "profiles",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `loginStoreId` INTEGER NOT NULL, `loginStoreType` INTEGER NOT NULL, `name` TEXT NOT NULL, `subname` TEXT, `studentNameLong` TEXT NOT NULL, `studentNameShort` TEXT NOT NULL, `accountName` TEXT, `studentData` TEXT NOT NULL, `image` TEXT, `empty` INTEGER NOT NULL, `archived` INTEGER NOT NULL, `archiveId` INTEGER, `syncEnabled` INTEGER NOT NULL, `enableSharedEvents` INTEGER NOT NULL, `registration` INTEGER NOT NULL, `userCode` TEXT NOT NULL, `studentNumber` INTEGER NOT NULL, `studentClassName` TEXT, `studentSchoolYearStart` INTEGER NOT NULL, `dateSemester1Start` TEXT NOT NULL, `dateSemester2Start` TEXT NOT NULL, `dateYearEnd` TEXT NOT NULL, `disabledNotifications` TEXT, `lastReceiversSync` INTEGER NOT NULL, PRIMARY KEY(`profileId`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginStoreId",
+ "columnName": "loginStoreId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginStoreType",
+ "columnName": "loginStoreType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subname",
+ "columnName": "subname",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "studentNameLong",
+ "columnName": "studentNameLong",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentNameShort",
+ "columnName": "studentNameShort",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountName",
+ "columnName": "accountName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "studentData",
+ "columnName": "studentData",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "image",
+ "columnName": "image",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "empty",
+ "columnName": "empty",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "archived",
+ "columnName": "archived",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "archiveId",
+ "columnName": "archiveId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "syncEnabled",
+ "columnName": "syncEnabled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "enableSharedEvents",
+ "columnName": "enableSharedEvents",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registration",
+ "columnName": "registration",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userCode",
+ "columnName": "userCode",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentNumber",
+ "columnName": "studentNumber",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentClassName",
+ "columnName": "studentClassName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "studentSchoolYearStart",
+ "columnName": "studentSchoolYearStart",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "dateSemester1Start",
+ "columnName": "dateSemester1Start",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "dateSemester2Start",
+ "columnName": "dateSemester2Start",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "dateYearEnd",
+ "columnName": "dateYearEnd",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "disabledNotifications",
+ "columnName": "disabledNotifications",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lastReceiversSync",
+ "columnName": "lastReceiversSync",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "luckyNumbers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `luckyNumberDate` INTEGER NOT NULL, `luckyNumber` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `luckyNumberDate`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "luckyNumberDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "luckyNumber",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "luckyNumberDate"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "announcements",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `announcementId` INTEGER NOT NULL, `announcementSubject` TEXT NOT NULL, `announcementText` TEXT, `announcementStartDate` TEXT, `announcementEndDate` TEXT, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `announcementIdString` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `announcementId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "announcementId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "announcementSubject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "announcementText",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "startDate",
+ "columnName": "announcementStartDate",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "endDate",
+ "columnName": "announcementEndDate",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "idString",
+ "columnName": "announcementIdString",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "announcementId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_announcements_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_announcements_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "gradeCategories",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `categoryId` INTEGER NOT NULL, `weight` REAL NOT NULL, `color` INTEGER NOT NULL, `text` TEXT, `columns` TEXT, `valueFrom` REAL NOT NULL, `valueTo` REAL NOT NULL, `type` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `categoryId`, `type`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "categoryId",
+ "columnName": "categoryId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "color",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "columns",
+ "columnName": "columns",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "valueFrom",
+ "columnName": "valueFrom",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "valueTo",
+ "columnName": "valueTo",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "categoryId",
+ "type"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "feedbackMessages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `received` INTEGER NOT NULL, `text` TEXT NOT NULL, `senderName` TEXT NOT NULL, `deviceId` TEXT, `deviceName` TEXT, `devId` INTEGER, `devImage` TEXT, `sentTime` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "messageId",
+ "columnName": "messageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "received",
+ "columnName": "received",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "senderName",
+ "columnName": "senderName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deviceId",
+ "columnName": "deviceId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "deviceName",
+ "columnName": "deviceName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "devId",
+ "columnName": "devId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "devImage",
+ "columnName": "devImage",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sentTime",
+ "columnName": "sentTime",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "messageId"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "messages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `messageId` INTEGER NOT NULL, `messageType` INTEGER NOT NULL, `messageSubject` TEXT NOT NULL, `messageBody` TEXT, `senderId` INTEGER, `addedDate` INTEGER NOT NULL, `messageIsPinned` INTEGER NOT NULL, `hasAttachments` INTEGER NOT NULL, `attachmentIds` TEXT, `attachmentNames` TEXT, `attachmentSizes` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `messageId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "messageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "messageType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "messageSubject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "body",
+ "columnName": "messageBody",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "senderId",
+ "columnName": "senderId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isStarred",
+ "columnName": "messageIsPinned",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasAttachments",
+ "columnName": "hasAttachments",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "attachmentIds",
+ "columnName": "attachmentIds",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachmentNames",
+ "columnName": "attachmentNames",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachmentSizes",
+ "columnName": "attachmentSizes",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "messageId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_messages_profileId_messageType",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "messageType"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_messages_profileId_messageType` ON `${TABLE_NAME}` (`profileId`, `messageType`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "messageRecipients",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `messageRecipientId` INTEGER NOT NULL, `messageRecipientReplyId` INTEGER NOT NULL, `messageRecipientReadDate` INTEGER NOT NULL, `messageId` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `messageRecipientId`, `messageId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "messageRecipientId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "replyId",
+ "columnName": "messageRecipientReplyId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "readDate",
+ "columnName": "messageRecipientReadDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageId",
+ "columnName": "messageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "messageRecipientId",
+ "messageId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "debugLogs",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `text` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "endpointTimers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `endpointId` INTEGER NOT NULL, `endpointLastSync` INTEGER, `endpointNextSync` INTEGER NOT NULL, `endpointViewId` INTEGER, PRIMARY KEY(`profileId`, `endpointId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "endpointId",
+ "columnName": "endpointId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastSync",
+ "columnName": "endpointLastSync",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "nextSync",
+ "columnName": "endpointNextSync",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "viewId",
+ "columnName": "endpointViewId",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "endpointId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "lessonRanges",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `lessonRangeNumber` INTEGER NOT NULL, `lessonRangeStart` TEXT NOT NULL, `lessonRangeEnd` TEXT NOT NULL, PRIMARY KEY(`profileId`, `lessonRangeNumber`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lessonNumber",
+ "columnName": "lessonRangeNumber",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "startTime",
+ "columnName": "lessonRangeStart",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "endTime",
+ "columnName": "lessonRangeEnd",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "lessonRangeNumber"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "notifications",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `text` TEXT NOT NULL, `textLong` TEXT, `type` INTEGER NOT NULL, `profileId` INTEGER, `profileName` TEXT, `posted` INTEGER NOT NULL, `viewId` INTEGER, `extras` TEXT, `addedDate` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "textLong",
+ "columnName": "textLong",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileName",
+ "columnName": "profileName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "posted",
+ "columnName": "posted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "viewId",
+ "columnName": "viewId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "extras",
+ "columnName": "extras",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "classrooms",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`profileId`, `id`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "noticeTypes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`profileId`, `id`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "attendanceTypes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `baseType` INTEGER NOT NULL, `typeName` TEXT NOT NULL, `typeShort` TEXT NOT NULL, `typeSymbol` TEXT NOT NULL, `typeColor` INTEGER, PRIMARY KEY(`profileId`, `id`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "baseType",
+ "columnName": "baseType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeName",
+ "columnName": "typeName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeShort",
+ "columnName": "typeShort",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeSymbol",
+ "columnName": "typeSymbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeColor",
+ "columnName": "typeColor",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "timetable",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `type` INTEGER NOT NULL, `date` TEXT, `lessonNumber` INTEGER, `startTime` TEXT, `endTime` TEXT, `subjectId` INTEGER, `teacherId` INTEGER, `teamId` INTEGER, `classroom` TEXT, `oldDate` TEXT, `oldLessonNumber` INTEGER, `oldStartTime` TEXT, `oldEndTime` TEXT, `oldSubjectId` INTEGER, `oldTeacherId` INTEGER, `oldTeamId` INTEGER, `oldClassroom` TEXT, `isExtra` INTEGER NOT NULL, `color` INTEGER, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `id`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lessonNumber",
+ "columnName": "lessonNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "startTime",
+ "columnName": "startTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "endTime",
+ "columnName": "endTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teamId",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "classroom",
+ "columnName": "classroom",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldDate",
+ "columnName": "oldDate",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldLessonNumber",
+ "columnName": "oldLessonNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldStartTime",
+ "columnName": "oldStartTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldEndTime",
+ "columnName": "oldEndTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldSubjectId",
+ "columnName": "oldSubjectId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldTeacherId",
+ "columnName": "oldTeacherId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldTeamId",
+ "columnName": "oldTeamId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldClassroom",
+ "columnName": "oldClassroom",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isExtra",
+ "columnName": "isExtra",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "color",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_timetable_profileId_type_date",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "type",
+ "date"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_timetable_profileId_type_date` ON `${TABLE_NAME}` (`profileId`, `type`, `date`)"
+ },
+ {
+ "name": "index_timetable_profileId_type_oldDate",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "type",
+ "oldDate"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_timetable_profileId_type_oldDate` ON `${TABLE_NAME}` (`profileId`, `type`, `oldDate`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "config",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `key` TEXT NOT NULL, `value` TEXT, PRIMARY KEY(`profileId`, `key`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "key",
+ "columnName": "key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "key"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "librusLessons",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `lessonId` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `teamId` INTEGER, PRIMARY KEY(`profileId`, `lessonId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lessonId",
+ "columnName": "lessonId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teamId",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "lessonId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_librusLessons_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_librusLessons_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "timetableManual",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `repeatBy` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `date` INTEGER, `weekDay` INTEGER, `lessonNumber` INTEGER, `startTime` TEXT, `endTime` TEXT, `subjectId` INTEGER, `teacherId` INTEGER, `teamId` INTEGER, `classroom` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "repeatBy",
+ "columnName": "repeatBy",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "weekDay",
+ "columnName": "weekDay",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lessonNumber",
+ "columnName": "lessonNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "startTime",
+ "columnName": "startTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "endTime",
+ "columnName": "endTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teamId",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "classroom",
+ "columnName": "classroom",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_timetableManual_profileId_date",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "date"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_timetableManual_profileId_date` ON `${TABLE_NAME}` (`profileId`, `date`)"
+ },
+ {
+ "name": "index_timetableManual_profileId_weekDay",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "weekDay"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_timetableManual_profileId_weekDay` ON `${TABLE_NAME}` (`profileId`, `weekDay`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "notes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `noteId` INTEGER NOT NULL, `noteOwnerType` TEXT, `noteOwnerId` INTEGER, `noteReplacesOriginal` INTEGER NOT NULL, `noteTopic` TEXT, `noteBody` TEXT NOT NULL, `noteColor` INTEGER, `noteSharedBy` TEXT, `noteSharedByName` TEXT, `addedDate` INTEGER NOT NULL, PRIMARY KEY(`noteId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "noteId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "ownerType",
+ "columnName": "noteOwnerType",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "ownerId",
+ "columnName": "noteOwnerId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "replacesOriginal",
+ "columnName": "noteReplacesOriginal",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "topic",
+ "columnName": "noteTopic",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "body",
+ "columnName": "noteBody",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "noteColor",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sharedBy",
+ "columnName": "noteSharedBy",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sharedByName",
+ "columnName": "noteSharedByName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "noteId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_notes_profileId_noteOwnerType_noteOwnerId",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "noteOwnerType",
+ "noteOwnerId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_notes_profileId_noteOwnerType_noteOwnerId` ON `${TABLE_NAME}` (`profileId`, `noteOwnerType`, `noteOwnerId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "metadata",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `metadataId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `thingType` INTEGER NOT NULL, `thingId` INTEGER NOT NULL, `seen` INTEGER NOT NULL, `notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "metadataId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thingType",
+ "columnName": "thingType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thingId",
+ "columnName": "thingId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "seen",
+ "columnName": "seen",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notified",
+ "columnName": "notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "metadataId"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_metadata_profileId_thingType_thingId",
+ "unique": true,
+ "columnNames": [
+ "profileId",
+ "thingType",
+ "thingId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_metadata_profileId_thingType_thingId` ON `${TABLE_NAME}` (`profileId`, `thingType`, `thingId`)"
+ }
+ ],
+ "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, '2612ebba9802eedc7ebc69724606a23c')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/99.json b/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/99.json
new file mode 100644
index 00000000..7db65929
--- /dev/null
+++ b/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/99.json
@@ -0,0 +1,2314 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 99,
+ "identityHash": "2612ebba9802eedc7ebc69724606a23c",
+ "entities": [
+ {
+ "tableName": "grades",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `gradeId` INTEGER NOT NULL, `gradeName` TEXT NOT NULL, `gradeType` INTEGER NOT NULL, `gradeValue` REAL NOT NULL, `gradeWeight` REAL NOT NULL, `gradeColor` INTEGER NOT NULL, `gradeCategory` TEXT, `gradeDescription` TEXT, `gradeComment` TEXT, `gradeSemester` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `gradeValueMax` REAL, `gradeClassAverage` REAL, `gradeParentId` INTEGER, `gradeIsImprovement` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `gradeId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "gradeId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "gradeName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "gradeType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "gradeValue",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "gradeWeight",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "gradeColor",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "gradeCategory",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "gradeDescription",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "gradeComment",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "semester",
+ "columnName": "gradeSemester",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "valueMax",
+ "columnName": "gradeValueMax",
+ "affinity": "REAL",
+ "notNull": false
+ },
+ {
+ "fieldPath": "classAverage",
+ "columnName": "gradeClassAverage",
+ "affinity": "REAL",
+ "notNull": false
+ },
+ {
+ "fieldPath": "parentId",
+ "columnName": "gradeParentId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isImprovement",
+ "columnName": "gradeIsImprovement",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "gradeId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_grades_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_grades_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "teachers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `teacherLoginId` TEXT, `teacherName` TEXT, `teacherSurname` TEXT, `teacherType` INTEGER NOT NULL, `teacherTypeDescription` TEXT, `teacherSubjects` TEXT NOT NULL, PRIMARY KEY(`profileId`, `teacherId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginId",
+ "columnName": "teacherLoginId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "teacherName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "surname",
+ "columnName": "teacherSurname",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "teacherType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeDescription",
+ "columnName": "teacherTypeDescription",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "subjects",
+ "columnName": "teacherSubjects",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "teacherId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "teacherAbsence",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherAbsenceId` INTEGER NOT NULL, `teacherAbsenceType` INTEGER NOT NULL, `teacherAbsenceName` TEXT, `teacherAbsenceDateFrom` TEXT NOT NULL, `teacherAbsenceDateTo` TEXT NOT NULL, `teacherAbsenceTimeFrom` TEXT, `teacherAbsenceTimeTo` TEXT, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `teacherAbsenceId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "teacherAbsenceId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "teacherAbsenceType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "teacherAbsenceName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "dateFrom",
+ "columnName": "teacherAbsenceDateFrom",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "dateTo",
+ "columnName": "teacherAbsenceDateTo",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "timeFrom",
+ "columnName": "teacherAbsenceTimeFrom",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "timeTo",
+ "columnName": "teacherAbsenceTimeTo",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "teacherAbsenceId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_teacherAbsence_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_teacherAbsence_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "teacherAbsenceTypes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherAbsenceTypeId` INTEGER NOT NULL, `teacherAbsenceTypeName` TEXT NOT NULL, PRIMARY KEY(`profileId`, `teacherAbsenceTypeId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "teacherAbsenceTypeId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "teacherAbsenceTypeName",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "teacherAbsenceTypeId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "subjects",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `subjectLongName` TEXT, `subjectShortName` TEXT, `subjectColor` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `subjectId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "longName",
+ "columnName": "subjectLongName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "shortName",
+ "columnName": "subjectShortName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "subjectColor",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "subjectId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "notices",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `noticeId` INTEGER NOT NULL, `noticeType` INTEGER NOT NULL, `noticeSemester` INTEGER NOT NULL, `noticeText` TEXT NOT NULL, `noticeCategory` TEXT, `noticePoints` REAL, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `noticeId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "noticeId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "noticeType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "semester",
+ "columnName": "noticeSemester",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "noticeText",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "noticeCategory",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "points",
+ "columnName": "noticePoints",
+ "affinity": "REAL",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "noticeId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_notices_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_notices_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "teams",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teamId` INTEGER NOT NULL, `teamType` INTEGER NOT NULL, `teamName` TEXT, `teamCode` TEXT, `teamTeacherId` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `teamId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "teamType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "teamName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "code",
+ "columnName": "teamCode",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teamTeacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "teamId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "attendances",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `attendanceId` INTEGER NOT NULL, `attendanceBaseType` INTEGER NOT NULL, `attendanceTypeName` TEXT NOT NULL, `attendanceTypeShort` TEXT NOT NULL, `attendanceTypeSymbol` TEXT NOT NULL, `attendanceTypeColor` INTEGER, `attendanceDate` TEXT NOT NULL, `attendanceTime` TEXT, `attendanceSemester` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `attendanceLessonTopic` TEXT, `attendanceLessonNumber` INTEGER, `attendanceIsCounted` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `attendanceId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "attendanceId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "baseType",
+ "columnName": "attendanceBaseType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeName",
+ "columnName": "attendanceTypeName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeShort",
+ "columnName": "attendanceTypeShort",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeSymbol",
+ "columnName": "attendanceTypeSymbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeColor",
+ "columnName": "attendanceTypeColor",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "attendanceDate",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "startTime",
+ "columnName": "attendanceTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "semester",
+ "columnName": "attendanceSemester",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lessonTopic",
+ "columnName": "attendanceLessonTopic",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lessonNumber",
+ "columnName": "attendanceLessonNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isCounted",
+ "columnName": "attendanceIsCounted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "attendanceId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_attendances_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_attendances_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "events",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `eventId` INTEGER NOT NULL, `eventDate` TEXT NOT NULL, `eventTime` TEXT, `eventTopic` TEXT NOT NULL, `eventColor` INTEGER, `eventType` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `teamId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `eventAddedManually` INTEGER NOT NULL, `eventSharedBy` TEXT, `eventSharedByName` TEXT, `eventBlacklisted` INTEGER NOT NULL, `eventIsDone` INTEGER NOT NULL, `eventIsDownloaded` INTEGER NOT NULL, `homeworkBody` TEXT, `attachmentIds` TEXT, `attachmentNames` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `eventId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "eventId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "eventDate",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "time",
+ "columnName": "eventTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "topic",
+ "columnName": "eventTopic",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "eventColor",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "eventType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teamId",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedManually",
+ "columnName": "eventAddedManually",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "sharedBy",
+ "columnName": "eventSharedBy",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sharedByName",
+ "columnName": "eventSharedByName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "blacklisted",
+ "columnName": "eventBlacklisted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDone",
+ "columnName": "eventIsDone",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDownloaded",
+ "columnName": "eventIsDownloaded",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "homeworkBody",
+ "columnName": "homeworkBody",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachmentIds",
+ "columnName": "attachmentIds",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachmentNames",
+ "columnName": "attachmentNames",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "eventId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_events_profileId_eventDate_eventTime",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "eventDate",
+ "eventTime"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_events_profileId_eventDate_eventTime` ON `${TABLE_NAME}` (`profileId`, `eventDate`, `eventTime`)"
+ },
+ {
+ "name": "index_events_profileId_eventType",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "eventType"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_events_profileId_eventType` ON `${TABLE_NAME}` (`profileId`, `eventType`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "eventTypes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `eventType` INTEGER NOT NULL, `eventTypeName` TEXT NOT NULL, `eventTypeColor` INTEGER NOT NULL, `eventTypeOrder` INTEGER NOT NULL, `eventTypeSource` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `eventType`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "eventType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "eventTypeName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "eventTypeColor",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "order",
+ "columnName": "eventTypeOrder",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "source",
+ "columnName": "eventTypeSource",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "eventType"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "loginStores",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`loginStoreId` INTEGER NOT NULL, `loginStoreType` INTEGER NOT NULL, `loginStoreMode` INTEGER NOT NULL, `loginStoreData` TEXT NOT NULL, PRIMARY KEY(`loginStoreId`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "loginStoreId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "loginStoreType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mode",
+ "columnName": "loginStoreMode",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "data",
+ "columnName": "loginStoreData",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "loginStoreId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "profiles",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `loginStoreId` INTEGER NOT NULL, `loginStoreType` INTEGER NOT NULL, `name` TEXT NOT NULL, `subname` TEXT, `studentNameLong` TEXT NOT NULL, `studentNameShort` TEXT NOT NULL, `accountName` TEXT, `studentData` TEXT NOT NULL, `image` TEXT, `empty` INTEGER NOT NULL, `archived` INTEGER NOT NULL, `archiveId` INTEGER, `syncEnabled` INTEGER NOT NULL, `enableSharedEvents` INTEGER NOT NULL, `registration` INTEGER NOT NULL, `userCode` TEXT NOT NULL, `studentNumber` INTEGER NOT NULL, `studentClassName` TEXT, `studentSchoolYearStart` INTEGER NOT NULL, `dateSemester1Start` TEXT NOT NULL, `dateSemester2Start` TEXT NOT NULL, `dateYearEnd` TEXT NOT NULL, `disabledNotifications` TEXT, `lastReceiversSync` INTEGER NOT NULL, PRIMARY KEY(`profileId`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginStoreId",
+ "columnName": "loginStoreId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "loginStoreType",
+ "columnName": "loginStoreType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subname",
+ "columnName": "subname",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "studentNameLong",
+ "columnName": "studentNameLong",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentNameShort",
+ "columnName": "studentNameShort",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountName",
+ "columnName": "accountName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "studentData",
+ "columnName": "studentData",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "image",
+ "columnName": "image",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "empty",
+ "columnName": "empty",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "archived",
+ "columnName": "archived",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "archiveId",
+ "columnName": "archiveId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "syncEnabled",
+ "columnName": "syncEnabled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "enableSharedEvents",
+ "columnName": "enableSharedEvents",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "registration",
+ "columnName": "registration",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userCode",
+ "columnName": "userCode",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentNumber",
+ "columnName": "studentNumber",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "studentClassName",
+ "columnName": "studentClassName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "studentSchoolYearStart",
+ "columnName": "studentSchoolYearStart",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "dateSemester1Start",
+ "columnName": "dateSemester1Start",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "dateSemester2Start",
+ "columnName": "dateSemester2Start",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "dateYearEnd",
+ "columnName": "dateYearEnd",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "disabledNotifications",
+ "columnName": "disabledNotifications",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lastReceiversSync",
+ "columnName": "lastReceiversSync",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "luckyNumbers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `luckyNumberDate` INTEGER NOT NULL, `luckyNumber` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `luckyNumberDate`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "luckyNumberDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "number",
+ "columnName": "luckyNumber",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "luckyNumberDate"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "announcements",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `announcementId` INTEGER NOT NULL, `announcementSubject` TEXT NOT NULL, `announcementText` TEXT, `announcementStartDate` TEXT, `announcementEndDate` TEXT, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `announcementIdString` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `announcementId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "announcementId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "announcementSubject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "announcementText",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "startDate",
+ "columnName": "announcementStartDate",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "endDate",
+ "columnName": "announcementEndDate",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "idString",
+ "columnName": "announcementIdString",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "announcementId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_announcements_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_announcements_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "gradeCategories",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `categoryId` INTEGER NOT NULL, `weight` REAL NOT NULL, `color` INTEGER NOT NULL, `text` TEXT, `columns` TEXT, `valueFrom` REAL NOT NULL, `valueTo` REAL NOT NULL, `type` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `categoryId`, `type`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "categoryId",
+ "columnName": "categoryId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "color",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "columns",
+ "columnName": "columns",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "valueFrom",
+ "columnName": "valueFrom",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "valueTo",
+ "columnName": "valueTo",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "categoryId",
+ "type"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "feedbackMessages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `received` INTEGER NOT NULL, `text` TEXT NOT NULL, `senderName` TEXT NOT NULL, `deviceId` TEXT, `deviceName` TEXT, `devId` INTEGER, `devImage` TEXT, `sentTime` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "messageId",
+ "columnName": "messageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "received",
+ "columnName": "received",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "senderName",
+ "columnName": "senderName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "deviceId",
+ "columnName": "deviceId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "deviceName",
+ "columnName": "deviceName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "devId",
+ "columnName": "devId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "devImage",
+ "columnName": "devImage",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sentTime",
+ "columnName": "sentTime",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "messageId"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "messages",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `messageId` INTEGER NOT NULL, `messageType` INTEGER NOT NULL, `messageSubject` TEXT NOT NULL, `messageBody` TEXT, `senderId` INTEGER, `addedDate` INTEGER NOT NULL, `messageIsPinned` INTEGER NOT NULL, `hasAttachments` INTEGER NOT NULL, `attachmentIds` TEXT, `attachmentNames` TEXT, `attachmentSizes` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `messageId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "messageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "messageType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subject",
+ "columnName": "messageSubject",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "body",
+ "columnName": "messageBody",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "senderId",
+ "columnName": "senderId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isStarred",
+ "columnName": "messageIsPinned",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasAttachments",
+ "columnName": "hasAttachments",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "attachmentIds",
+ "columnName": "attachmentIds",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachmentNames",
+ "columnName": "attachmentNames",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachmentSizes",
+ "columnName": "attachmentSizes",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "messageId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_messages_profileId_messageType",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "messageType"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_messages_profileId_messageType` ON `${TABLE_NAME}` (`profileId`, `messageType`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "messageRecipients",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `messageRecipientId` INTEGER NOT NULL, `messageRecipientReplyId` INTEGER NOT NULL, `messageRecipientReadDate` INTEGER NOT NULL, `messageId` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `messageRecipientId`, `messageId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "messageRecipientId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "replyId",
+ "columnName": "messageRecipientReplyId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "readDate",
+ "columnName": "messageRecipientReadDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "messageId",
+ "columnName": "messageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "messageRecipientId",
+ "messageId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "debugLogs",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `text` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "endpointTimers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `endpointId` INTEGER NOT NULL, `endpointLastSync` INTEGER, `endpointNextSync` INTEGER NOT NULL, `endpointViewId` INTEGER, PRIMARY KEY(`profileId`, `endpointId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "endpointId",
+ "columnName": "endpointId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastSync",
+ "columnName": "endpointLastSync",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "nextSync",
+ "columnName": "endpointNextSync",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "viewId",
+ "columnName": "endpointViewId",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "endpointId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "lessonRanges",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `lessonRangeNumber` INTEGER NOT NULL, `lessonRangeStart` TEXT NOT NULL, `lessonRangeEnd` TEXT NOT NULL, PRIMARY KEY(`profileId`, `lessonRangeNumber`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lessonNumber",
+ "columnName": "lessonRangeNumber",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "startTime",
+ "columnName": "lessonRangeStart",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "endTime",
+ "columnName": "lessonRangeEnd",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "lessonRangeNumber"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "notifications",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `text` TEXT NOT NULL, `textLong` TEXT, `type` INTEGER NOT NULL, `profileId` INTEGER, `profileName` TEXT, `posted` INTEGER NOT NULL, `viewId` INTEGER, `extras` TEXT, `addedDate` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "textLong",
+ "columnName": "textLong",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileName",
+ "columnName": "profileName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "posted",
+ "columnName": "posted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "viewId",
+ "columnName": "viewId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "extras",
+ "columnName": "extras",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "classrooms",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`profileId`, `id`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "noticeTypes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`profileId`, `id`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "attendanceTypes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `baseType` INTEGER NOT NULL, `typeName` TEXT NOT NULL, `typeShort` TEXT NOT NULL, `typeSymbol` TEXT NOT NULL, `typeColor` INTEGER, PRIMARY KEY(`profileId`, `id`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "baseType",
+ "columnName": "baseType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeName",
+ "columnName": "typeName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeShort",
+ "columnName": "typeShort",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeSymbol",
+ "columnName": "typeSymbol",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "typeColor",
+ "columnName": "typeColor",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "timetable",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `type` INTEGER NOT NULL, `date` TEXT, `lessonNumber` INTEGER, `startTime` TEXT, `endTime` TEXT, `subjectId` INTEGER, `teacherId` INTEGER, `teamId` INTEGER, `classroom` TEXT, `oldDate` TEXT, `oldLessonNumber` INTEGER, `oldStartTime` TEXT, `oldEndTime` TEXT, `oldSubjectId` INTEGER, `oldTeacherId` INTEGER, `oldTeamId` INTEGER, `oldClassroom` TEXT, `isExtra` INTEGER NOT NULL, `color` INTEGER, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `id`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lessonNumber",
+ "columnName": "lessonNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "startTime",
+ "columnName": "startTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "endTime",
+ "columnName": "endTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teamId",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "classroom",
+ "columnName": "classroom",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldDate",
+ "columnName": "oldDate",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldLessonNumber",
+ "columnName": "oldLessonNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldStartTime",
+ "columnName": "oldStartTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldEndTime",
+ "columnName": "oldEndTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldSubjectId",
+ "columnName": "oldSubjectId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldTeacherId",
+ "columnName": "oldTeacherId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldTeamId",
+ "columnName": "oldTeamId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "oldClassroom",
+ "columnName": "oldClassroom",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isExtra",
+ "columnName": "isExtra",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "color",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "keep",
+ "columnName": "keep",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_timetable_profileId_type_date",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "type",
+ "date"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_timetable_profileId_type_date` ON `${TABLE_NAME}` (`profileId`, `type`, `date`)"
+ },
+ {
+ "name": "index_timetable_profileId_type_oldDate",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "type",
+ "oldDate"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_timetable_profileId_type_oldDate` ON `${TABLE_NAME}` (`profileId`, `type`, `oldDate`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "config",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `key` TEXT NOT NULL, `value` TEXT, PRIMARY KEY(`profileId`, `key`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "key",
+ "columnName": "key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "key"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "librusLessons",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `lessonId` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `teamId` INTEGER, PRIMARY KEY(`profileId`, `lessonId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lessonId",
+ "columnName": "lessonId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "teamId",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "profileId",
+ "lessonId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_librusLessons_profileId",
+ "unique": false,
+ "columnNames": [
+ "profileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_librusLessons_profileId` ON `${TABLE_NAME}` (`profileId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "timetableManual",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `repeatBy` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `date` INTEGER, `weekDay` INTEGER, `lessonNumber` INTEGER, `startTime` TEXT, `endTime` TEXT, `subjectId` INTEGER, `teacherId` INTEGER, `teamId` INTEGER, `classroom` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "repeatBy",
+ "columnName": "repeatBy",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "weekDay",
+ "columnName": "weekDay",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lessonNumber",
+ "columnName": "lessonNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "startTime",
+ "columnName": "startTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "endTime",
+ "columnName": "endTime",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "subjectId",
+ "columnName": "subjectId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teacherId",
+ "columnName": "teacherId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "teamId",
+ "columnName": "teamId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "classroom",
+ "columnName": "classroom",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_timetableManual_profileId_date",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "date"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_timetableManual_profileId_date` ON `${TABLE_NAME}` (`profileId`, `date`)"
+ },
+ {
+ "name": "index_timetableManual_profileId_weekDay",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "weekDay"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_timetableManual_profileId_weekDay` ON `${TABLE_NAME}` (`profileId`, `weekDay`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "notes",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `noteId` INTEGER NOT NULL, `noteOwnerType` TEXT, `noteOwnerId` INTEGER, `noteReplacesOriginal` INTEGER NOT NULL, `noteTopic` TEXT, `noteBody` TEXT NOT NULL, `noteColor` INTEGER, `noteSharedBy` TEXT, `noteSharedByName` TEXT, `addedDate` INTEGER NOT NULL, PRIMARY KEY(`noteId`))",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "noteId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "ownerType",
+ "columnName": "noteOwnerType",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "ownerId",
+ "columnName": "noteOwnerId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "replacesOriginal",
+ "columnName": "noteReplacesOriginal",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "topic",
+ "columnName": "noteTopic",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "body",
+ "columnName": "noteBody",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "color",
+ "columnName": "noteColor",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sharedBy",
+ "columnName": "noteSharedBy",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sharedByName",
+ "columnName": "noteSharedByName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "addedDate",
+ "columnName": "addedDate",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "noteId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_notes_profileId_noteOwnerType_noteOwnerId",
+ "unique": false,
+ "columnNames": [
+ "profileId",
+ "noteOwnerType",
+ "noteOwnerId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_notes_profileId_noteOwnerType_noteOwnerId` ON `${TABLE_NAME}` (`profileId`, `noteOwnerType`, `noteOwnerId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "metadata",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `metadataId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `thingType` INTEGER NOT NULL, `thingId` INTEGER NOT NULL, `seen` INTEGER NOT NULL, `notified` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "profileId",
+ "columnName": "profileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "metadataId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thingType",
+ "columnName": "thingType",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thingId",
+ "columnName": "thingId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "seen",
+ "columnName": "seen",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notified",
+ "columnName": "notified",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "metadataId"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_metadata_profileId_thingType_thingId",
+ "unique": true,
+ "columnNames": [
+ "profileId",
+ "thingType",
+ "thingId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_metadata_profileId_thingType_thingId` ON `${TABLE_NAME}` (`profileId`, `thingType`, `thingId`)"
+ }
+ ],
+ "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, '2612ebba9802eedc7ebc69724606a23c')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index af4b653a..da531480 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,7 +3,6 @@
xmlns:tools="http://schemas.android.com/tools"
package="pl.szczodrzynski.edziennik">
-
@@ -13,7 +12,7 @@
-
+
@@ -43,6 +42,7 @@
android:configChanges="orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTop"
+ android:exported="true"
android:theme="@style/SplashTheme">
@@ -66,6 +66,7 @@
android:configChanges="orientation|keyboardHidden"
android:excludeFromRecents="true"
android:noHistory="true"
+ android:exported="true"
android:theme="@style/AppTheme.Dark.NoDisplay">
@@ -73,7 +74,8 @@
+ android:label="@string/widget_timetable_title"
+ android:exported="true">
@@ -88,10 +90,12 @@
android:configChanges="orientation|keyboardHidden"
android:excludeFromRecents="true"
android:noHistory="true"
+ android:exported="true"
android:theme="@style/AppTheme.Dark.NoDisplay" />
+ android:label="@string/widget_notifications_title"
+ android:exported="true">
@@ -104,7 +108,8 @@
android:permission="android.permission.BIND_REMOTEVIEWS" />
+ android:label="@string/widget_lucky_number_title"
+ android:exported="true">
@@ -121,31 +126,47 @@
/ ____ \ (__| |_| |\ V /| | |_| | __/\__ \
/_/ \_\___|\__|_| \_/ |_|\__|_|\___||___/
-->
-
-
-
-
-
-
-
+
+
+
+
+ android:enabled="true"
+ android:exported="true">
-
+
diff --git a/app/src/main/assets/pl-changelog.html b/app/src/main/assets/pl-changelog.html
index 2219ad8c..af4aaca4 100644
--- a/app/src/main/assets/pl-changelog.html
+++ b/app/src/main/assets/pl-changelog.html
@@ -1,15 +1,10 @@
-Wersja 4.7, 2021-04-07
+Wersja 4.13.6, 2023-03-24
- - Szkolny.eu jest teraz open source! Zapraszamy na stronę https://szkolny.eu/ po więcej ważnych informacji.
- - Poprawiono wybieranie obrazków (tła nagłówka, tła aplikacji oraz profilu) z dowolnego źródła.
- - Ukończono tłumaczenie na język angielski. @MarcinK50
- - Dodano ekran informacji o kompilacji w Ustawieniach.
- - Zaktualizowano ekran licencji open source.
- - Naprawiono zatrzymanie aplikacji na Androidzie 4.4 i starszych.
- - Naprawiono problemy z połączeniem internetowym na Androidzie 4.4 i starszych.
- - Zoptymalizowano wielkość aplikacji.
+ - Naprawiono pobieranie załączników na Androidzie 13 i nowszym.
+ - Dodano opcję odświeżenia planu lekcji na wybrany tydzień.
+ - Usunięto błędy logowania. @BxOxSxS
Dzięki za korzystanie ze Szkolnego!
-© [Kuba Szczodrzyński](@kuba2k2), [Kacper Ziubryniewicz](@kapi2289) 2021
+© [Kuba Szczodrzyński](@kuba2k2) 2023
diff --git a/app/src/main/cpp/szkolny-signing.cpp b/app/src/main/cpp/szkolny-signing.cpp
index f2b1cf8a..9ae8f745 100644
--- a/app/src/main/cpp/szkolny-signing.cpp
+++ b/app/src/main/cpp/szkolny-signing.cpp
@@ -9,7 +9,7 @@
/*secret password - removed for source code publication*/
static toys AES_IV[16] = {
- 0xda, 0x9f, 0xd4, 0x2b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ 0x6d, 0xa5, 0x32, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt
index a9186d94..74e23d88 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt
@@ -12,6 +12,7 @@ import android.graphics.drawable.Icon
import android.os.Build
import android.provider.Settings
import android.util.Log
+import android.widget.Toast
import androidx.appcompat.app.AppCompatDelegate
import androidx.multidex.MultiDexApplication
import androidx.work.Configuration
@@ -26,50 +27,88 @@ import com.google.firebase.messaging.FirebaseMessaging
import com.google.gson.Gson
import com.hypertrack.hyperlog.HyperLog
import com.mikepenz.iconics.Iconics
-import eu.szkolny.sslprovider.SSLProvider
-import eu.szkolny.sslprovider.enableSupportedTls
import im.wangchao.mhttp.MHttp
-import kotlinx.coroutines.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import me.leolin.shortcutbadger.ShortcutBadger
import okhttp3.OkHttpClient
import org.greenrobot.eventbus.EventBus
+import pl.szczodrzynski.edziennik.config.AppData
import pl.szczodrzynski.edziennik.config.Config
import pl.szczodrzynski.edziennik.data.api.events.ProfileListEmptyEvent
+import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.Profile
+import pl.szczodrzynski.edziennik.data.db.enums.LoginType
+import pl.szczodrzynski.edziennik.ext.DAY
+import pl.szczodrzynski.edziennik.ext.MS
+import pl.szczodrzynski.edziennik.ext.putExtras
+import pl.szczodrzynski.edziennik.ext.setLanguage
+import pl.szczodrzynski.edziennik.network.SSLProviderInstaller
import pl.szczodrzynski.edziennik.network.cookie.DumbCookieJar
import pl.szczodrzynski.edziennik.sync.SyncWorker
import pl.szczodrzynski.edziennik.sync.UpdateWorker
-import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity
-import pl.szczodrzynski.edziennik.utils.*
+import pl.szczodrzynski.edziennik.ui.base.CrashActivity
+import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
+import pl.szczodrzynski.edziennik.utils.DebugLogFormat
+import pl.szczodrzynski.edziennik.utils.PermissionChecker
+import pl.szczodrzynski.edziennik.utils.Themes
+import pl.szczodrzynski.edziennik.utils.Utils
import pl.szczodrzynski.edziennik.utils.Utils.d
-import pl.szczodrzynski.edziennik.utils.managers.*
-import timber.log.Timber
+import pl.szczodrzynski.edziennik.utils.managers.AttendanceManager
+import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager
+import pl.szczodrzynski.edziennik.utils.managers.BuildManager
+import pl.szczodrzynski.edziennik.utils.managers.EventManager
+import pl.szczodrzynski.edziennik.utils.managers.GradesManager
+import pl.szczodrzynski.edziennik.utils.managers.MessageManager
+import pl.szczodrzynski.edziennik.utils.managers.NoteManager
+import pl.szczodrzynski.edziennik.utils.managers.NotificationChannelsManager
+import pl.szczodrzynski.edziennik.utils.managers.PermissionManager
+import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager
+import pl.szczodrzynski.edziennik.utils.managers.TimetableManager
+import pl.szczodrzynski.edziennik.utils.managers.UpdateManager
+import pl.szczodrzynski.edziennik.utils.managers.UserActionManager
import java.util.concurrent.TimeUnit
import kotlin.coroutines.CoroutineContext
+import kotlin.system.exitProcess
class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
companion object {
@Volatile
lateinit var db: AppDb
+ private set
lateinit var config: Config
+ // private set // for LabFragment
lateinit var profile: Profile
+ private set
+ lateinit var data: AppData
+ private set
val profileId
get() = profile.id
+ var enableChucker = false
var debugMode = false
var devMode = false
}
- val notificationChannelsManager by lazy { NotificationChannelsManager(this) }
- val userActionManager by lazy { UserActionManager(this) }
- val gradesManager by lazy { GradesManager(this) }
- val timetableManager by lazy { TimetableManager(this) }
- val eventManager by lazy { EventManager(this) }
- val permissionManager by lazy { PermissionManager(this) }
+ val api by lazy { SzkolnyApi(this) }
val attendanceManager by lazy { AttendanceManager(this) }
+ val availabilityManager by lazy { AvailabilityManager(this) }
val buildManager by lazy { BuildManager(this) }
+ val eventManager by lazy { EventManager(this) }
+ val gradesManager by lazy { GradesManager(this) }
+ val messageManager by lazy { MessageManager(this) }
+ val noteManager by lazy { NoteManager(this) }
+ val notificationChannelsManager by lazy { NotificationChannelsManager(this) }
+ val permissionManager by lazy { PermissionManager(this) }
+ val textStylingManager by lazy { TextStylingManager(this) }
+ val timetableManager by lazy { TimetableManager(this) }
+ val updateManager by lazy { UpdateManager(this) }
+ val userActionManager by lazy { UserActionManager(this) }
val db
get() = App.db
@@ -79,6 +118,8 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
get() = App.profile
val profileId
get() = App.profileId
+ val data
+ get() = App.data
private val job = Job()
override val coroutineContext: CoroutineContext
@@ -109,15 +150,15 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
.connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
- .enableSupportedTls(enableCleartext = true)
+
+ SSLProviderInstaller.enableSupportedTls(builder, enableCleartext = true)
if (devMode) {
- HyperLog.initialize(this)
- HyperLog.setLogLevel(Log.VERBOSE)
- HyperLog.setLogFormat(DebugLogFormat(this))
- val chuckerCollector = ChuckerCollector(this, true, RetentionManager.Period.ONE_HOUR)
- val chuckerInterceptor = ChuckerInterceptor(this, chuckerCollector)
- builder.addInterceptor(chuckerInterceptor)
+ if (enableChucker) {
+ val chuckerCollector = ChuckerCollector(this, true, RetentionManager.Period.ONE_HOUR)
+ val chuckerInterceptor = ChuckerInterceptor(this, chuckerCollector)
+ builder.addInterceptor(chuckerInterceptor)
+ }
}
http = builder.build()
@@ -167,14 +208,23 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
Iconics.respectFontBoundsDefault = true
// initialize companion object values
+ AppData.read(this)
App.db = AppDb(this)
App.config = Config(App.db)
- App.profile = Profile(0, 0, 0, "")
debugMode = BuildConfig.DEBUG
- devMode = config.debugMode || debugMode
+ devMode = config.devMode ?: debugMode
+ enableChucker = config.enableChucker ?: devMode
+
+ if (devMode) {
+ HyperLog.initialize(this)
+ HyperLog.setLogLevel(Log.VERBOSE)
+ HyperLog.setLogFormat(DebugLogFormat(this))
+ }
if (!profileLoadById(config.lastProfileId)) {
- db.profileDao().firstId?.let { profileLoadById(it) }
+ val success = db.profileDao().firstId?.let { profileLoadById(it) }
+ if (success != true)
+ profileLoad(Profile(0, 0, LoginType.TEMPLATE, ""))
}
buildHttp()
@@ -185,23 +235,13 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
}
Signing.getCert(this)
+ Utils.initializeStorageDir(this)
launch {
withContext(Dispatchers.Default) {
config.migrate(this@App)
- SSLProvider.install(
- applicationContext,
- downloadIfNeeded = true,
- supportTls13 = false,
- onFinish = {
- buildHttp()
- },
- onError = {
- Timber.e("Failed to install SSLProvider: $it")
- it.printStackTrace()
- }
- )
+ SSLProviderInstaller.install(applicationContext, this@App::buildHttp)
if (config.devModePassword != null)
checkDevModePassword()
@@ -223,35 +263,35 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
.setShortLabel(getString(R.string.shortcut_timetable)).setLongLabel(getString(R.string.shortcut_timetable))
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_timetable))
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
- .putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE))
+ .putExtras("fragmentId" to NavTarget.TIMETABLE))
.build()
val shortcutAgenda = ShortcutInfo.Builder(this@App, "item_agenda")
.setShortLabel(getString(R.string.shortcut_agenda)).setLongLabel(getString(R.string.shortcut_agenda))
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_agenda))
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
- .putExtra("fragmentId", MainActivity.DRAWER_ITEM_AGENDA))
+ .putExtras("fragmentId" to NavTarget.AGENDA))
.build()
val shortcutGrades = ShortcutInfo.Builder(this@App, "item_grades")
.setShortLabel(getString(R.string.shortcut_grades)).setLongLabel(getString(R.string.shortcut_grades))
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_grades))
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
- .putExtra("fragmentId", MainActivity.DRAWER_ITEM_GRADES))
+ .putExtras("fragmentId" to NavTarget.GRADES))
.build()
val shortcutHomework = ShortcutInfo.Builder(this@App, "item_homeworks")
.setShortLabel(getString(R.string.shortcut_homework)).setLongLabel(getString(R.string.shortcut_homework))
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_homework))
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
- .putExtra("fragmentId", MainActivity.DRAWER_ITEM_HOMEWORK))
+ .putExtras("fragmentId" to NavTarget.HOMEWORK))
.build()
val shortcutMessages = ShortcutInfo.Builder(this@App, "item_messages")
.setShortLabel(getString(R.string.shortcut_messages)).setLongLabel(getString(R.string.shortcut_messages))
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_messages))
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
- .putExtra("fragmentId", MainActivity.DRAWER_ITEM_MESSAGES))
+ .putExtras("fragmentId" to NavTarget.MESSAGES))
.build()
shortcutManager.dynamicShortcuts = listOf(
@@ -377,10 +417,28 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
}
}
+ fun profileLoad(profile: Profile) {
+ App.profile = profile
+ App.config.lastProfileId = profile.id
+ try {
+ App.data = AppData.get(profile.loginStoreType)
+ d("App", "Loaded AppData: ${App.data}")
+ // apply newly-added config overrides, if not changed by the user yet
+ for ((key, value) in App.data.configOverrides) {
+ val config = App.profile.config
+ if (!config.has(key))
+ config.set(key, value)
+ }
+ } catch (e: Exception) {
+ Log.e("App", "Cannot load AppData", e)
+ Toast.makeText(this, R.string.app_cannot_load_data, Toast.LENGTH_LONG).show()
+ exitProcess(0)
+ }
+ }
+
private fun profileLoadById(profileId: Int): Boolean {
db.profileDao().getByIdNow(profileId)?.also {
- App.profile = it
- App.config.lastProfileId = it.id
+ profileLoad(it)
return true
}
return false
@@ -411,6 +469,8 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
}
fun profileSave() = profileSave(profile)
fun profileSave(profile: Profile) {
+ if (profile.id == profileId)
+ App.profile = profile
launch(Dispatchers.Default) {
App.db.profileDao().add(profile)
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/Binding.kt b/app/src/main/java/pl/szczodrzynski/edziennik/Binding.kt
index 3dc9d0a6..fba06502 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/Binding.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/Binding.kt
@@ -4,8 +4,11 @@
package pl.szczodrzynski.edziennik
import android.graphics.Paint
+import android.view.View
import android.widget.TextView
+import androidx.core.view.isVisible
import androidx.databinding.BindingAdapter
+import pl.szczodrzynski.edziennik.ext.dp
object Binding {
@JvmStatic
@@ -17,4 +20,64 @@ object Binding {
textView.paintFlags = textView.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
}
}
+
+ @JvmStatic
+ @BindingAdapter("android:isVisible")
+ fun isVisible(view: View, isVisible: Boolean) {
+ view.isVisible = isVisible
+ }
+
+ private fun resizeDrawable(textView: TextView, index: Int, size: Int) {
+ val drawables = textView.compoundDrawables
+ drawables[index]?.setBounds(0, 0, size, size)
+ textView.setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3])
+ }
+
+ @JvmStatic
+ @BindingAdapter("android:drawableLeftAutoSize")
+ fun drawableLeftAutoSize(textView: TextView, enable: Boolean) = resizeDrawable(
+ textView,
+ index = 0,
+ size = textView.textSize.toInt(),
+ )
+
+ @JvmStatic
+ @BindingAdapter("android:drawableRightAutoSize")
+ fun drawableRightAutoSize(textView: TextView, enable: Boolean) = resizeDrawable(
+ textView,
+ index = 2,
+ size = textView.textSize.toInt(),
+ )
+
+ @JvmStatic
+ @BindingAdapter("android:drawableLeftSize")
+ fun drawableLeftSize(textView: TextView, sizeDp: Int) = resizeDrawable(
+ textView,
+ index = 0,
+ size = sizeDp.dp,
+ )
+
+ @JvmStatic
+ @BindingAdapter("android:drawableTopSize")
+ fun drawableTopSize(textView: TextView, sizeDp: Int) = resizeDrawable(
+ textView,
+ index = 1,
+ size = sizeDp.dp,
+ )
+
+ @JvmStatic
+ @BindingAdapter("android:drawableRightSize")
+ fun drawableRightSize(textView: TextView, sizeDp: Int) = resizeDrawable(
+ textView,
+ index = 2,
+ size = sizeDp.dp,
+ )
+
+ @JvmStatic
+ @BindingAdapter("android:drawableBottomSize")
+ fun drawableBottomSize(textView: TextView, sizeDp: Int) = resizeDrawable(
+ textView,
+ index = 3,
+ size = sizeDp.dp,
+ )
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt
deleted file mode 100644
index a07634a1..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt
+++ /dev/null
@@ -1,1289 +0,0 @@
-package pl.szczodrzynski.edziennik
-
-import android.content.ClipData
-import android.content.ClipboardManager
-import android.content.Context
-import android.content.Intent
-import android.content.res.ColorStateList
-import android.content.res.Resources
-import android.database.Cursor
-import android.graphics.PorterDuff
-import android.graphics.PorterDuffColorFilter
-import android.graphics.Rect
-import android.graphics.Typeface
-import android.graphics.drawable.Drawable
-import android.os.Build
-import android.os.Bundle
-import android.text.*
-import android.text.style.ForegroundColorSpan
-import android.text.style.StrikethroughSpan
-import android.text.style.StyleSpan
-import android.util.*
-import android.util.Base64
-import android.util.Base64.NO_WRAP
-import android.util.Base64.encodeToString
-import android.view.View
-import android.view.WindowManager
-import android.widget.*
-import androidx.annotation.*
-import androidx.core.database.getIntOrNull
-import androidx.core.database.getLongOrNull
-import androidx.core.database.getStringOrNull
-import androidx.core.util.forEach
-import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.Observer
-import androidx.recyclerview.widget.RecyclerView
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
-import androidx.viewpager.widget.ViewPager
-import com.google.android.material.button.MaterialButton
-import com.google.android.material.datepicker.CalendarConstraints
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.google.gson.*
-import com.google.gson.JsonArray
-import com.google.gson.JsonObject
-import im.wangchao.mhttp.Response
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-import okhttp3.RequestBody
-import okio.Buffer
-import pl.szczodrzynski.edziennik.data.api.*
-import pl.szczodrzynski.edziennik.data.api.models.ApiError
-import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApiException
-import pl.szczodrzynski.edziennik.data.api.szkolny.response.ApiResponse
-import pl.szczodrzynski.edziennik.data.db.entity.Notification
-import pl.szczodrzynski.edziennik.data.db.entity.Profile
-import pl.szczodrzynski.edziennik.data.db.entity.Teacher
-import pl.szczodrzynski.edziennik.data.db.entity.Team
-import pl.szczodrzynski.edziennik.utils.models.Time
-import java.io.InterruptedIOException
-import java.io.PrintWriter
-import java.io.StringWriter
-import java.math.BigInteger
-import java.net.ConnectException
-import java.net.SocketTimeoutException
-import java.net.UnknownHostException
-import java.nio.charset.Charset
-import java.security.MessageDigest
-import java.text.SimpleDateFormat
-import java.util.*
-import java.util.zip.CRC32
-import javax.crypto.Mac
-import javax.crypto.spec.SecretKeySpec
-import javax.net.ssl.SSLException
-import kotlin.Pair
-
-
-fun List.byId(id: Long) = firstOrNull { it.id == id }
-fun List.byNameFirstLast(nameFirstLast: String) = firstOrNull { it.name + " " + it.surname == nameFirstLast }
-fun List.byNameLastFirst(nameLastFirst: String) = firstOrNull { it.surname + " " + it.name == nameLastFirst }
-fun List.byNameFDotLast(nameFDotLast: String) = firstOrNull { it.name + "." + it.surname == nameFDotLast }
-fun List.byNameFDotSpaceLast(nameFDotSpaceLast: String) = firstOrNull { it.name + ". " + it.surname == nameFDotSpaceLast }
-
-fun JsonObject?.get(key: String): JsonElement? = this?.get(key)
-
-fun JsonObject?.getBoolean(key: String): Boolean? = get(key)?.let { if (!it.isJsonPrimitive) null else it.asBoolean }
-fun JsonObject?.getString(key: String): String? = get(key)?.let { if (!it.isJsonPrimitive) null else it.asString }
-fun JsonObject?.getInt(key: String): Int? = get(key)?.let { if (!it.isJsonPrimitive) null else it.asInt }
-fun JsonObject?.getLong(key: String): Long? = get(key)?.let { if (!it.isJsonPrimitive) null else it.asLong }
-fun JsonObject?.getFloat(key: String): Float? = get(key)?.let { if(!it.isJsonPrimitive) null else it.asFloat }
-fun JsonObject?.getChar(key: String): Char? = get(key)?.let { if(!it.isJsonPrimitive) null else it.asCharacter }
-fun JsonObject?.getJsonObject(key: String): JsonObject? = get(key)?.let { if (it.isJsonObject) it.asJsonObject else null }
-fun JsonObject?.getJsonArray(key: String): JsonArray? = get(key)?.let { if (it.isJsonArray) it.asJsonArray else null }
-
-fun JsonObject?.getBoolean(key: String, defaultValue: Boolean): Boolean = get(key)?.let { if (!it.isJsonPrimitive) defaultValue else it.asBoolean } ?: defaultValue
-fun JsonObject?.getString(key: String, defaultValue: String): String = get(key)?.let { if (!it.isJsonPrimitive) defaultValue else it.asString } ?: defaultValue
-fun JsonObject?.getInt(key: String, defaultValue: Int): Int = get(key)?.let { if (!it.isJsonPrimitive) defaultValue else it.asInt } ?: defaultValue
-fun JsonObject?.getLong(key: String, defaultValue: Long): Long = get(key)?.let { if (!it.isJsonPrimitive) defaultValue else it.asLong } ?: defaultValue
-fun JsonObject?.getFloat(key: String, defaultValue: Float): Float = get(key)?.let { if(!it.isJsonPrimitive) defaultValue else it.asFloat } ?: defaultValue
-fun JsonObject?.getChar(key: String, defaultValue: Char): Char = get(key)?.let { if(!it.isJsonPrimitive) defaultValue else it.asCharacter } ?: defaultValue
-fun JsonObject?.getJsonObject(key: String, defaultValue: JsonObject): JsonObject = get(key)?.let { if (it.isJsonObject) it.asJsonObject else defaultValue } ?: defaultValue
-fun JsonObject?.getJsonArray(key: String, defaultValue: JsonArray): JsonArray = get(key)?.let { if (it.isJsonArray) it.asJsonArray else defaultValue } ?: defaultValue
-
-fun JsonArray.getBoolean(key: Int): Boolean? = if (key >= size()) null else get(key)?.let { if (!it.isJsonPrimitive) null else it.asBoolean }
-fun JsonArray.getString(key: Int): String? = if (key >= size()) null else get(key)?.let { if (!it.isJsonPrimitive) null else it.asString }
-fun JsonArray.getInt(key: Int): Int? = if (key >= size()) null else get(key)?.let { if (!it.isJsonPrimitive) null else it.asInt }
-fun JsonArray.getLong(key: Int): Long? = if (key >= size()) null else get(key)?.let { if (!it.isJsonPrimitive) null else it.asLong }
-fun JsonArray.getFloat(key: Int): Float? = if (key >= size()) null else get(key)?.let { if(!it.isJsonPrimitive) null else it.asFloat }
-fun JsonArray.getChar(key: Int): Char? = if (key >= size()) null else get(key)?.let { if(!it.isJsonPrimitive) null else it.asCharacter }
-fun JsonArray.getJsonObject(key: Int): JsonObject? = if (key >= size()) null else get(key)?.let { if (it.isJsonObject) it.asJsonObject else null }
-fun JsonArray.getJsonArray(key: Int): JsonArray? = if (key >= size()) null else get(key)?.let { if (it.isJsonArray) it.asJsonArray else null }
-
-fun String.toJsonObject(): JsonObject? = try { JsonParser().parse(this).asJsonObject } catch (ignore: Exception) { null }
-
-operator fun JsonObject.set(key: String, value: JsonElement) = this.add(key, value)
-operator fun JsonObject.set(key: String, value: Boolean) = this.addProperty(key, value)
-operator fun JsonObject.set(key: String, value: String?) = this.addProperty(key, value)
-operator fun JsonObject.set(key: String, value: Number) = this.addProperty(key, value)
-operator fun JsonObject.set(key: String, value: Char) = this.addProperty(key, value)
-
-operator fun Profile.set(key: String, value: JsonElement) = this.studentData.add(key, value)
-operator fun Profile.set(key: String, value: Boolean) = this.studentData.addProperty(key, value)
-operator fun Profile.set(key: String, value: String?) = this.studentData.addProperty(key, value)
-operator fun Profile.set(key: String, value: Number) = this.studentData.addProperty(key, value)
-operator fun Profile.set(key: String, value: Char) = this.studentData.addProperty(key, value)
-
-fun JsonArray.asJsonObjectList() = this.mapNotNull { it.asJsonObject }
-
-fun CharSequence?.isNotNullNorEmpty(): Boolean {
- return this != null && this.isNotEmpty()
-}
-
-fun Collection?.isNotNullNorEmpty(): Boolean {
- return this != null && this.isNotEmpty()
-}
-
-fun CharSequence?.isNotNullNorBlank(): Boolean {
- return this != null && this.isNotBlank()
-}
-
-fun currentTimeUnix() = System.currentTimeMillis() / 1000
-
-fun Bundle?.getInt(key: String, defaultValue: Int): Int {
- return this?.getInt(key, defaultValue) ?: defaultValue
-}
-fun Bundle?.getLong(key: String, defaultValue: Long): Long {
- return this?.getLong(key, defaultValue) ?: defaultValue
-}
-fun Bundle?.getFloat(key: String, defaultValue: Float): Float {
- return this?.getFloat(key, defaultValue) ?: defaultValue
-}
-fun Bundle?.getString(key: String, defaultValue: String): String {
- return this?.getString(key, defaultValue) ?: defaultValue
-}
-
-fun Bundle?.getIntOrNull(key: String): Int? {
- return this?.get(key) as? Int
-}
-fun Bundle?.get(key: String): T? {
- return this?.get(key) as? T?
-}
-
-/**
- * ` The quick BROWN_fox Jumps OveR THE LAZy-DOG. `
- *
- * converts to
- *
- * `The Quick Brown_fox Jumps Over The Lazy-Dog.`
- */
-fun String?.fixName(): String {
- return this?.fixWhiteSpaces()?.toProperCase() ?: ""
-}
-
-/**
- * `The quick BROWN_fox Jumps OveR THE LAZy-DOG.`
- *
- * converts to
- *
- * `The Quick Brown_fox Jumps Over The Lazy-Dog.`
- */
-fun String.toProperCase(): String = changeStringCase(this)
-
-/**
- * `John Smith` -> `Smith John`
- *
- * `JOHN SMith` -> `SMith JOHN`
- */
-fun String.swapFirstLastName(): String {
- return this.split(" ").let {
- if (it.size > 1)
- it[1]+" "+it[0]
- else
- it[0]
- }
-}
-
-fun String.splitName(): Pair? {
- return this.split(" ").let {
- if (it.size >= 2) Pair(it[0], it[1])
- else null
- }
-}
-
-fun changeStringCase(s: String): String {
- val delimiters = " '-/"
- val sb = StringBuilder()
- var capNext = true
- for (ch in s.toCharArray()) {
- var c = ch
- c = if (capNext)
- Character.toUpperCase(c)
- else
- Character.toLowerCase(c)
- sb.append(c)
- capNext = delimiters.indexOf(c) >= 0
- }
- return sb.toString()
-}
-
-fun buildFullName(firstName: String?, lastName: String?): String {
- return "$firstName $lastName".fixName()
-}
-
-fun String.getShortName(): String {
- return split(" ").let {
- if (it.size > 1)
- "${it[0]} ${it[1][0]}."
- else
- it[0]
- }
-}
-
-/**
- * "John Smith" -> "JS"
- *
- * "JOHN SMith" -> "JS"
- *
- * "John" -> "J"
- *
- * "John " -> "J"
- *
- * "John Smith " -> "JS"
- *
- * " " -> ""
- *
- * " " -> ""
- */
-fun String?.getNameInitials(): String {
- if (this.isNullOrBlank()) return ""
- return this.toUpperCase().fixWhiteSpaces().split(" ").take(2).map { it[0] }.joinToString("")
-}
-
-fun List.join(delimiter: String): String {
- return concat(delimiter).toString()
-}
-
-fun colorFromName(name: String?): Int {
- val i = (name ?: "").crc32()
- return when ((i / 10 % 16 + 1).toInt()) {
- 13 -> 0xffF44336
- 4 -> 0xffF50057
- 2 -> 0xffD500F9
- 9 -> 0xff6200EA
- 5 -> 0xffFFAB00
- 1 -> 0xff304FFE
- 6 -> 0xff40C4FF
- 14 -> 0xff26A69A
- 15 -> 0xff00C853
- 7 -> 0xffFFD600
- 3 -> 0xffFF3D00
- 8 -> 0xffDD2C00
- 10 -> 0xff795548
- 12 -> 0xff2979FF
- 11 -> 0xffFF6D00
- else -> 0xff64DD17
- }.toInt()
-}
-
-fun colorFromCssName(name: String): Int {
- return when (name) {
- "red" -> 0xffff0000
- "green" -> 0xff008000
- "blue" -> 0xff0000ff
- "violet" -> 0xffee82ee
- "brown" -> 0xffa52a2a
- "orange" -> 0xffffa500
- "black" -> 0xff000000
- "white" -> 0xffffffff
- else -> -1L
- }.toInt()
-}
-
-fun List.filterOutArchived() = this.filter { !it.archived }
-
-fun Response?.getUnixDate(): Long {
- val rfcDate = this?.headers()?.get("date") ?: return currentTimeUnix()
- val pattern = "EEE, dd MMM yyyy HH:mm:ss Z"
- val format = SimpleDateFormat(pattern, Locale.ENGLISH)
- return format.parse(rfcDate).time / 1000
-}
-
-const val MINUTE = 60L
-const val HOUR = 60L*MINUTE
-const val DAY = 24L*HOUR
-const val WEEK = 7L*DAY
-const val MONTH = 30L*DAY
-const val YEAR = 365L*DAY
-const val MS = 1000L
-
-fun LongSparseArray.values(): List {
- val result = mutableListOf()
- forEach { _, value ->
- result += value
- }
- return result
-}
-
-fun SparseArray<*>.keys(): List {
- val result = mutableListOf()
- forEach { key, _ ->
- result += key
- }
- return result
-}
-fun SparseArray.values(): List {
- val result = mutableListOf()
- forEach { _, value ->
- result += value
- }
- return result
-}
-
-fun SparseIntArray.keys(): List {
- val result = mutableListOf()
- forEach { key, _ ->
- result += key
- }
- return result
-}
-fun SparseIntArray.values(): List {
- val result = mutableListOf()
- forEach { _, value ->
- result += value
- }
- return result
-}
-
-fun List>.keys(): List {
- val result = mutableListOf()
- forEach { pair ->
- result += pair.first
- }
- return result
-}
-fun List>.values(): List {
- val result = mutableListOf()
- forEach { pair ->
- result += pair.second
- }
- return result
-}
-
-fun List.toSparseArray(destination: SparseArray, key: (T) -> Int) {
- forEach {
- destination.put(key(it), it)
- }
-}
-fun List.toSparseArray(destination: LongSparseArray, key: (T) -> Long) {
- forEach {
- destination.put(key(it), it)
- }
-}
-
-fun List.toSparseArray(key: (T) -> Int): SparseArray {
- val result = SparseArray()
- toSparseArray(result, key)
- return result
-}
-fun List.toSparseArray(key: (T) -> Long): LongSparseArray {
- val result = LongSparseArray()
- toSparseArray(result, key)
- return result
-}
-
-fun SparseArray.singleOrNull(predicate: (T) -> Boolean): T? {
- forEach { _, value ->
- if (predicate(value))
- return value
- }
- return null
-}
-fun LongSparseArray.singleOrNull(predicate: (T) -> Boolean): T? {
- forEach { _, value ->
- if (predicate(value))
- return value
- }
- return null
-}
-
-fun String.fixWhiteSpaces() = buildString(length) {
- var wasWhiteSpace = true
- for (c in this@fixWhiteSpaces) {
- if (c.isWhitespace()) {
- if (!wasWhiteSpace) {
- append(c)
- wasWhiteSpace = true
- }
- } else {
- append(c)
- wasWhiteSpace = false
- }
- }
-}.trimEnd()
-
-fun List.getById(id: Long): Team? {
- return singleOrNull { it.id == id }
-}
-fun LongSparseArray.getById(id: Long): Team? {
- forEach { _, value ->
- if (value.id == id)
- return value
- }
- return null
-}
-
-operator fun MatchResult.get(group: Int): String {
- if (group >= groupValues.size)
- return ""
- return groupValues[group]
-}
-
-fun Context.setLanguage(language: String) {
- val locale = Locale(language.toLowerCase(Locale.ROOT))
- val configuration = resources.configuration
- Locale.setDefault(locale)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- configuration.setLocale(locale)
- }
- configuration.locale = locale
- resources.updateConfiguration(configuration, resources.displayMetrics)
-}
-
-/*
- Code copied from android-28/java.util.Locale.initDefault()
- */
-fun initDefaultLocale() {
- run {
- // user.locale gets priority
- /*val languageTag: String? = System.getProperty("user.locale", "")
- if (languageTag.isNotNullNorEmpty()) {
- return@run Locale(languageTag)
- }*/
-
- // user.locale is empty
- val language: String? = System.getProperty("user.language", "pl")
- val region: String? = System.getProperty("user.region")
- val country: String?
- val variant: String?
- // for compatibility, check for old user.region property
- if (region != null) {
- // region can be of form country, country_variant, or _variant
- val i = region.indexOf('_')
- if (i >= 0) {
- country = region.substring(0, i)
- variant = region.substring(i + 1)
- } else {
- country = region
- variant = ""
- }
- } else {
- country = System.getProperty("user.country", "")
- variant = System.getProperty("user.variant", "")
- }
- return@run Locale(language)
- }.let {
- Locale.setDefault(it)
- }
-}
-
-fun String.crc16(): Int {
- var crc = 0xFFFF
- for (aBuffer in this) {
- crc = crc.ushr(8) or (crc shl 8) and 0xffff
- crc = crc xor (aBuffer.toInt() and 0xff) // byte to int, trunc sign
- crc = crc xor (crc and 0xff shr 4)
- crc = crc xor (crc shl 12 and 0xffff)
- crc = crc xor (crc and 0xFF shl 5 and 0xffff)
- }
- crc = crc and 0xffff
- return crc + 32768
-}
-
-fun String.crc32(): Long {
- val crc = CRC32()
- crc.update(toByteArray())
- return crc.value
-}
-
-fun String.hmacSHA1(password: String): String {
- val key = SecretKeySpec(password.toByteArray(), "HmacSHA1")
-
- val mac = Mac.getInstance("HmacSHA1").apply {
- init(key)
- update(this@hmacSHA1.toByteArray())
- }
-
- return encodeToString(mac.doFinal(), NO_WRAP)
-}
-
-fun String.md5(): String {
- val md = MessageDigest.getInstance("MD5")
- return BigInteger(1, md.digest(toByteArray())).toString(16).padStart(32, '0')
-}
-
-fun String.sha1Hex(): String {
- val md = MessageDigest.getInstance("SHA-1")
- md.update(toByteArray())
- return md.digest().joinToString("") { "%02x".format(it) }
-}
-
-fun String.sha256(): ByteArray {
- val md = MessageDigest.getInstance("SHA-256")
- md.update(toByteArray())
- return md.digest()
-}
-
-fun RequestBody.bodyToString(): String {
- val buffer = Buffer()
- writeTo(buffer)
- return buffer.readUtf8()
-}
-
-fun Long.formatDate(format: String = "yyyy-MM-dd HH:mm:ss"): String = SimpleDateFormat(format).format(this)
-
-fun CharSequence?.asColoredSpannable(colorInt: Int): Spannable {
- val spannable = SpannableString(this)
- spannable.setSpan(ForegroundColorSpan(colorInt), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
- return spannable
-}
-fun CharSequence?.asStrikethroughSpannable(): Spannable {
- val spannable = SpannableString(this)
- spannable.setSpan(StrikethroughSpan(), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
- return spannable
-}
-fun CharSequence?.asItalicSpannable(): Spannable {
- val spannable = SpannableString(this)
- spannable.setSpan(StyleSpan(Typeface.ITALIC), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
- return spannable
-}
-fun CharSequence?.asBoldSpannable(): Spannable {
- val spannable = SpannableString(this)
- spannable.setSpan(StyleSpan(Typeface.BOLD), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
- return spannable
-}
-fun CharSequence.asSpannable(vararg spans: Any, substring: String? = null, ignoreCase: Boolean = false, ignoreDiacritics: Boolean = false): Spannable {
- val spannable = SpannableString(this)
- if (substring == null) {
- spans.forEach {
- spannable.setSpan(it, 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
- }
- }
- else if (substring.isNotEmpty()) {
- val string =
- if (ignoreDiacritics)
- this.cleanDiacritics()
- else this
-
- var index = string.indexOf(substring, ignoreCase = ignoreCase)
- .takeIf { it != -1 } ?: indexOf(substring, ignoreCase = ignoreCase)
- while (index >= 0) {
- spans.forEach {
- spannable.setSpan(it, index, index + substring.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
- }
- index = string.indexOf(substring, startIndex = index + 1, ignoreCase = ignoreCase)
- .takeIf { it != -1 } ?: indexOf(substring, startIndex = index + 1, ignoreCase = ignoreCase)
- }
- }
- return spannable
-}
-
-fun CharSequence.cleanDiacritics(): String {
- val nameClean = StringBuilder()
- forEach {
- val ch = when (it) {
- 'ż' -> 'z'
- 'ó' -> 'o'
- 'ł' -> 'l'
- 'ć' -> 'c'
- 'ę' -> 'e'
- 'ś' -> 's'
- 'ą' -> 'a'
- 'ź' -> 'z'
- 'ń' -> 'n'
- else -> it
- }
- nameClean.append(ch)
- }
- return nameClean.toString()
-}
-
-/**
- * Returns a new read-only list only of those given elements, that are not empty.
- * Applies for CharSequence and descendants.
- */
-fun listOfNotEmpty(vararg elements: T): List = elements.filterNot { it.isEmpty() }
-
-fun List.concat(delimiter: CharSequence? = null): CharSequence {
- if (this.isEmpty()) {
- return ""
- }
-
- if (this.size == 1) {
- return this[0] ?: ""
- }
-
- var spanned = delimiter is Spanned
- if (!spanned) {
- for (piece in this) {
- if (piece is Spanned) {
- spanned = true
- break
- }
- }
- }
-
- var first = true
- if (spanned) {
- val ssb = SpannableStringBuilder()
- for (piece in this) {
- if (piece == null)
- continue
- if (!first && delimiter != null)
- ssb.append(delimiter)
- first = false
- ssb.append(piece)
- }
- return SpannedString(ssb)
- } else {
- val sb = StringBuilder()
- for (piece in this) {
- if (piece == null)
- continue
- if (!first && delimiter != null)
- sb.append(delimiter)
- first = false
- sb.append(piece)
- }
- return sb.toString()
- }
-}
-
-fun TextView.setText(@StringRes resid: Int, vararg formatArgs: Any) {
- text = context.getString(resid, *formatArgs)
-}
-
-fun MaterialAlertDialogBuilder.setTitle(@StringRes resid: Int, vararg formatArgs: Any): MaterialAlertDialogBuilder {
- setTitle(context.getString(resid, *formatArgs))
- return this
-}
-
-fun MaterialAlertDialogBuilder.setMessage(@StringRes resid: Int, vararg formatArgs: Any): MaterialAlertDialogBuilder {
- setMessage(context.getString(resid, *formatArgs))
- return this
-}
-
-fun JsonObject(vararg properties: Pair): JsonObject {
- return JsonObject().apply {
- for (property in properties) {
- when (property.second) {
- is JsonElement -> add(property.first, property.second as JsonElement?)
- is String -> addProperty(property.first, property.second as String?)
- is Char -> addProperty(property.first, property.second as Char?)
- is Number -> addProperty(property.first, property.second as Number?)
- is Boolean -> addProperty(property.first, property.second as Boolean?)
- }
- }
- }
-}
-
-fun JsonObject.toBundle(): Bundle {
- return Bundle().also {
- for ((key, value) in this.entrySet()) {
- when (value) {
- is JsonObject -> it.putBundle(key, value.toBundle())
- is JsonPrimitive -> when {
- value.isString -> it.putString(key, value.asString)
- value.isBoolean -> it.putBoolean(key, value.asBoolean)
- value.isNumber -> it.putInt(key, value.asInt)
- }
- }
- }
- }
-}
-
-fun JsonArray(vararg properties: Any?): JsonArray {
- return JsonArray().apply {
- for (property in properties) {
- when (property) {
- is JsonElement -> add(property as JsonElement?)
- is String -> add(property as String?)
- is Char -> add(property as Char?)
- is Number -> add(property as Number?)
- is Boolean -> add(property as Boolean?)
- }
- }
- }
-}
-
-fun Bundle(vararg properties: Pair): Bundle {
- return Bundle().apply {
- for (property in properties) {
- when (property.second) {
- is String -> putString(property.first, property.second as String?)
- is Char -> putChar(property.first, property.second as Char)
- is Int -> putInt(property.first, property.second as Int)
- is Long -> putLong(property.first, property.second as Long)
- is Float -> putFloat(property.first, property.second as Float)
- is Short -> putShort(property.first, property.second as Short)
- is Double -> putDouble(property.first, property.second as Double)
- is Boolean -> putBoolean(property.first, property.second as Boolean)
- }
- }
- }
-}
-fun Intent(action: String? = null, vararg properties: Pair): Intent {
- return Intent(action).putExtras(Bundle(*properties))
-}
-fun Intent(packageContext: Context, cls: Class<*>, vararg properties: Pair): Intent {
- return Intent(packageContext, cls).putExtras(Bundle(*properties))
-}
-
-fun Bundle.toJsonObject(): JsonObject {
- val json = JsonObject()
- keySet()?.forEach { key ->
- get(key)?.let {
- when (it) {
- is String -> json.addProperty(key, it)
- is Char -> json.addProperty(key, it)
- is Int -> json.addProperty(key, it)
- is Long -> json.addProperty(key, it)
- is Float -> json.addProperty(key, it)
- is Short -> json.addProperty(key, it)
- is Double -> json.addProperty(key, it)
- is Boolean -> json.addProperty(key, it)
- is Bundle -> json.add(key, it.toJsonObject())
- else -> json.addProperty(key, it.toString())
- }
- }
- }
- return json
-}
-fun Intent.toJsonObject() = extras?.toJsonObject()
-
-fun JsonArray?.isNullOrEmpty(): Boolean = (this?.size() ?: 0) == 0
-fun JsonArray.isEmpty(): Boolean = this.size() == 0
-operator fun JsonArray.plusAssign(o: JsonElement) = this.add(o)
-operator fun JsonArray.plusAssign(o: String) = this.add(o)
-operator fun JsonArray.plusAssign(o: Char) = this.add(o)
-operator fun JsonArray.plusAssign(o: Number) = this.add(o)
-operator fun JsonArray.plusAssign(o: Boolean) = this.add(o)
-
-@Suppress("UNCHECKED_CAST")
-inline fun T.onClick(crossinline onClickListener: (v: T) -> Unit) {
- setOnClickListener { v: View ->
- onClickListener(v as T)
- }
-}
-
-@Suppress("UNCHECKED_CAST")
-inline fun T.onLongClick(crossinline onLongClickListener: (v: T) -> Boolean) {
- setOnLongClickListener { v: View ->
- onLongClickListener(v as T)
- }
-}
-
-@Suppress("UNCHECKED_CAST")
-inline fun T.onChange(crossinline onChangeListener: (v: T, isChecked: Boolean) -> Unit) {
- setOnCheckedChangeListener { buttonView, isChecked ->
- onChangeListener(buttonView as T, isChecked)
- }
-}
-
-@Suppress("UNCHECKED_CAST")
-inline fun T.onChange(crossinline onChangeListener: (v: T, isChecked: Boolean) -> Unit) {
- clearOnCheckedChangeListeners()
- addOnCheckedChangeListener { buttonView, isChecked ->
- onChangeListener(buttonView as T, isChecked)
- }
-}
-
-fun View.attachToastHint(stringRes: Int) = onLongClick {
- Toast.makeText(it.context, stringRes, Toast.LENGTH_SHORT).show()
- true
-}
-
-fun LiveData.observeOnce(lifecycleOwner: LifecycleOwner, observer: Observer) {
- observe(lifecycleOwner, object : Observer {
- override fun onChanged(t: T?) {
- observer.onChanged(t)
- removeObserver(this)
- }
- })
-}
-
-/**
- * Convert a value in dp to pixels.
- */
-val Int.dp: Int
- get() = (this * Resources.getSystem().displayMetrics.density).toInt()
-/**
- * Convert a value in pixels to dp.
- */
-val Int.px: Int
- get() = (this / Resources.getSystem().displayMetrics.density).toInt()
-
-@ColorInt
-fun @receiver:AttrRes Int.resolveAttr(context: Context?): Int {
- val typedValue = TypedValue()
- context?.theme?.resolveAttribute(this, typedValue, true)
- return typedValue.data
-}
-@ColorInt
-fun @receiver:ColorRes Int.resolveColor(context: Context): Int {
- return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- context.resources.getColor(this, context.theme)
- }
- else {
- context.resources.getColor(this)
- }
-}
-fun @receiver:DrawableRes Int.resolveDrawable(context: Context): Drawable {
- return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- context.resources.getDrawable(this, context.theme)
- }
- else {
- context.resources.getDrawable(this)
- }
-}
-
-fun View.findParentById(targetId: Int): View? {
- if (id == targetId) {
- return this
- }
- val viewParent = this.parent ?: return null
- if (viewParent is View) {
- return viewParent.findParentById(targetId)
- }
- return null
-}
-
-fun CoroutineScope.startCoroutineTimer(delayMillis: Long = 0, repeatMillis: Long = 0, action: suspend CoroutineScope.() -> Unit) = launch {
- delay(delayMillis)
- if (repeatMillis > 0) {
- while (true) {
- action()
- delay(repeatMillis)
- }
- } else {
- action()
- }
-}
-
-operator fun Time?.compareTo(other: Time?): Int {
- if (this == null && other == null)
- return 0
- if (this == null)
- return -1
- if (other == null)
- return 1
- return this.compareTo(other)
-}
-
-operator fun StringBuilder.plusAssign(str: String?) {
- this.append(str)
-}
-
-fun Context.timeTill(time: Int, delimiter: String = " ", countInSeconds: Boolean = false): String {
- val parts = mutableListOf>()
-
- val hours = time / 3600
- val minutes = (time - hours*3600) / 60
- val seconds = time - minutes*60 - hours*3600
-
- if (!countInSeconds) {
- var prefixAdded = false
- if (hours > 0) {
- if (!prefixAdded) parts += R.plurals.time_till_text to hours
- prefixAdded = true
- parts += R.plurals.time_till_hours to hours
- }
- if (minutes > 0) {
- if (!prefixAdded) parts += R.plurals.time_till_text to minutes
- prefixAdded = true
- parts += R.plurals.time_till_minutes to minutes
- }
- if (hours == 0 && minutes < 10) {
- if (!prefixAdded) parts += R.plurals.time_till_text to seconds
- prefixAdded = true
- parts += R.plurals.time_till_seconds to seconds
- }
- } else {
- parts += R.plurals.time_till_text to time
- parts += R.plurals.time_till_seconds to time
- }
-
- return parts.joinToString(delimiter) { resources.getQuantityString(it.first, it.second, it.second) }
-}
-
-fun Context.timeLeft(time: Int, delimiter: String = " ", countInSeconds: Boolean = false): String {
- val parts = mutableListOf>()
-
- val hours = time / 3600
- val minutes = (time - hours*3600) / 60
- val seconds = time - minutes*60 - hours*3600
-
- if (!countInSeconds) {
- var prefixAdded = false
- if (hours > 0) {
- if (!prefixAdded) parts += R.plurals.time_left_text to hours
- prefixAdded = true
- parts += R.plurals.time_left_hours to hours
- }
- if (minutes > 0) {
- if (!prefixAdded) parts += R.plurals.time_left_text to minutes
- prefixAdded = true
- parts += R.plurals.time_left_minutes to minutes
- }
- if (hours == 0 && minutes < 10) {
- if (!prefixAdded) parts += R.plurals.time_left_text to seconds
- prefixAdded = true
- parts += R.plurals.time_left_seconds to seconds
- }
- } else {
- parts += R.plurals.time_left_text to time
- parts += R.plurals.time_left_seconds to time
- }
-
- return parts.joinToString(delimiter) { resources.getQuantityString(it.first, it.second, it.second) }
-}
-
-inline fun Any?.instanceOfOrNull(): T? {
- return when (this) {
- is T -> this
- else -> null
- }
-}
-
-fun Drawable.setTintColor(color: Int): Drawable {
- colorFilter = PorterDuffColorFilter(
- color,
- PorterDuff.Mode.SRC_ATOP
- )
- return this
-}
-
-inline fun List.ifNotEmpty(block: (List) -> Unit) {
- if (!isEmpty())
- block(this)
-}
-
-val String.firstLettersName: String
- get() {
- var nameShort = ""
- this.split(" ").forEach {
- if (it.isBlank())
- return@forEach
- nameShort += it[0].toLowerCase()
- }
- return nameShort
- }
-
-val Throwable.stackTraceString: String
- get() {
- val sw = StringWriter()
- printStackTrace(PrintWriter(sw))
- return sw.toString()
- }
-
-inline fun LongSparseArray.filter(predicate: (T) -> Boolean): List {
- val destination = ArrayList()
- this.forEach { _, element -> if (predicate(element)) destination.add(element) }
- return destination
-}
-
-fun CharSequence.replace(oldValue: String, newValue: CharSequence, ignoreCase: Boolean = false): CharSequence =
- splitToSequence(oldValue, ignoreCase = ignoreCase).toList().concat(newValue)
-
-fun Int.toColorStateList(): ColorStateList {
- val states = arrayOf(
- intArrayOf( android.R.attr.state_enabled ),
- intArrayOf(-android.R.attr.state_enabled ),
- intArrayOf(-android.R.attr.state_checked ),
- intArrayOf( android.R.attr.state_pressed )
- )
-
- val colors = intArrayOf(
- this,
- this,
- this,
- this
- )
-
- return ColorStateList(states, colors)
-}
-
-fun SpannableStringBuilder.appendText(text: CharSequence): SpannableStringBuilder {
- append(text)
- return this
-}
-fun SpannableStringBuilder.appendSpan(text: CharSequence, what: Any, flags: Int): SpannableStringBuilder {
- val start: Int = length
- append(text)
- setSpan(what, start, length, flags)
- return this
-}
-
-fun joinNotNullStrings(delimiter: String = "", vararg parts: String?): String {
- var first = true
- val sb = StringBuilder()
- for (part in parts) {
- if (part == null)
- continue
- if (!first)
- sb += delimiter
- first = false
- sb += part
- }
- return sb.toString()
-}
-
-fun String.notEmptyOrNull(): String? {
- return if (isEmpty())
- null
- else
- this
-}
-
-fun String.base64Encode(): String {
- return encodeToString(toByteArray(), NO_WRAP)
-}
-fun ByteArray.base64Encode(): String {
- return encodeToString(this, NO_WRAP)
-}
-fun String.base64Decode(): ByteArray {
- return Base64.decode(this, Base64.DEFAULT)
-}
-fun String.base64DecodeToString(): String {
- return Base64.decode(this, Base64.DEFAULT).toString(Charset.defaultCharset())
-}
-
-fun CheckBox.trigger() { isChecked = !isChecked }
-
-fun Context.plural(@PluralsRes resId: Int, value: Int): String = resources.getQuantityString(resId, value, value)
-
-fun Context.getNotificationTitle(type: Int): String {
- return getString(when (type) {
- Notification.TYPE_UPDATE -> R.string.notification_type_update
- Notification.TYPE_ERROR -> R.string.notification_type_error
- Notification.TYPE_TIMETABLE_CHANGED -> R.string.notification_type_timetable_change
- Notification.TYPE_TIMETABLE_LESSON_CHANGE -> R.string.notification_type_timetable_lesson_change
- Notification.TYPE_NEW_GRADE -> R.string.notification_type_new_grade
- Notification.TYPE_NEW_EVENT -> R.string.notification_type_new_event
- Notification.TYPE_NEW_HOMEWORK -> R.string.notification_type_new_homework
- Notification.TYPE_NEW_SHARED_EVENT -> R.string.notification_type_new_shared_event
- Notification.TYPE_NEW_SHARED_HOMEWORK -> R.string.notification_type_new_shared_homework
- Notification.TYPE_REMOVED_SHARED_EVENT -> R.string.notification_type_removed_shared_event
- Notification.TYPE_NEW_MESSAGE -> R.string.notification_type_new_message
- Notification.TYPE_NEW_NOTICE -> R.string.notification_type_notice
- Notification.TYPE_NEW_ATTENDANCE -> R.string.notification_type_attendance
- Notification.TYPE_SERVER_MESSAGE -> R.string.notification_type_server_message
- Notification.TYPE_LUCKY_NUMBER -> R.string.notification_type_lucky_number
- Notification.TYPE_FEEDBACK_MESSAGE -> R.string.notification_type_feedback_message
- Notification.TYPE_NEW_ANNOUNCEMENT -> R.string.notification_type_new_announcement
- Notification.TYPE_AUTO_ARCHIVING -> R.string.notification_type_auto_archiving
- Notification.TYPE_TEACHER_ABSENCE -> R.string.notification_type_new_teacher_absence
- Notification.TYPE_GENERAL -> R.string.notification_type_general
- else -> R.string.notification_type_general
- })
-}
-
-fun Cursor?.getString(columnName: String) = this?.getStringOrNull(getColumnIndex(columnName))
-fun Cursor?.getInt(columnName: String) = this?.getIntOrNull(getColumnIndex(columnName))
-fun Cursor?.getLong(columnName: String) = this?.getLongOrNull(getColumnIndex(columnName))
-
-fun CharSequence.containsAll(list: List, ignoreCase: Boolean = false): Boolean {
- for (i in list) {
- if (!contains(i, ignoreCase))
- return false
- }
- return true
-}
-
-inline fun RadioButton.setOnSelectedListener(crossinline listener: (buttonView: CompoundButton) -> Unit)
- = setOnCheckedChangeListener { buttonView, isChecked -> if (isChecked) listener(buttonView) }
-
-fun Response.toErrorCode() = when (this.code()) {
- 400 -> ERROR_REQUEST_HTTP_400
- 401 -> ERROR_REQUEST_HTTP_401
- 403 -> ERROR_REQUEST_HTTP_403
- 404 -> ERROR_REQUEST_HTTP_404
- 405 -> ERROR_REQUEST_HTTP_405
- 410 -> ERROR_REQUEST_HTTP_410
- 424 -> ERROR_REQUEST_HTTP_424
- 500 -> ERROR_REQUEST_HTTP_500
- 503 -> ERROR_REQUEST_HTTP_503
- else -> null
-}
-fun Throwable.toErrorCode() = when (this) {
- is UnknownHostException -> ERROR_REQUEST_FAILURE_HOSTNAME_NOT_FOUND
- is SSLException -> ERROR_REQUEST_FAILURE_SSL_ERROR
- is SocketTimeoutException -> ERROR_REQUEST_FAILURE_TIMEOUT
- is InterruptedIOException, is ConnectException -> ERROR_REQUEST_FAILURE_NO_INTERNET
- is SzkolnyApiException -> this.error?.toErrorCode()
- else -> null
-}
-fun ApiResponse.Error.toErrorCode() = when (this.code) {
- "PdoError" -> ERROR_API_PDO_ERROR
- "InvalidClient" -> ERROR_API_INVALID_CLIENT
- "InvalidArgument" -> ERROR_API_INVALID_ARGUMENT
- "InvalidSignature" -> ERROR_API_INVALID_SIGNATURE
- "MissingScopes" -> ERROR_API_MISSING_SCOPES
- "ResourceNotFound" -> ERROR_API_RESOURCE_NOT_FOUND
- "InternalServerError" -> ERROR_API_INTERNAL_SERVER_ERROR
- "PhpError" -> ERROR_API_PHP_E_ERROR
- "PhpWarning" -> ERROR_API_PHP_E_WARNING
- "PhpParse" -> ERROR_API_PHP_E_PARSE
- "PhpNotice" -> ERROR_API_PHP_E_NOTICE
- "PhpOther" -> ERROR_API_PHP_E_OTHER
- "ApiMaintenance" -> ERROR_API_MAINTENANCE
- "MissingArgument" -> ERROR_API_MISSING_ARGUMENT
- "MissingPayload" -> ERROR_API_PAYLOAD_EMPTY
- "InvalidAction" -> ERROR_API_INVALID_ACTION
- "VersionNotFound" -> ERROR_API_UPDATE_NOT_FOUND
- "InvalidDeviceIdUserCode" -> ERROR_API_INVALID_DEVICEID_USERCODE
- "InvalidPairToken" -> ERROR_API_INVALID_PAIRTOKEN
- "InvalidBrowserId" -> ERROR_API_INVALID_BROWSERID
- "InvalidDeviceId" -> ERROR_API_INVALID_DEVICEID
- "InvalidDeviceIdBrowserId" -> ERROR_API_INVALID_DEVICEID_BROWSERID
- "HelpCategoryNotFound" -> ERROR_API_HELP_CATEGORY_NOT_FOUND
- else -> ERROR_API_EXCEPTION
-}
-fun Throwable.toApiError(tag: String) = ApiError.fromThrowable(tag, this)
-
-inline fun ifNotNull(a: A?, b: B?, code: (A, B) -> R): R? {
- if (a != null && b != null) {
- return code(a, b)
- }
- return null
-}
-
-@kotlin.jvm.JvmName("averageOrNullOfInt")
-fun Iterable.averageOrNull() = this.average().let { if (it.isNaN()) null else it }
-@kotlin.jvm.JvmName("averageOrNullOfFloat")
-fun Iterable.averageOrNull() = this.average().let { if (it.isNaN()) null else it }
-
-fun String.copyToClipboard(context: Context) {
- val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
- val clipData = ClipData.newPlainText("Tekst", this)
- clipboard.setPrimaryClip(clipData)
-}
-
-fun TextView.getTextPosition(range: IntRange): Rect {
- val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
-
- // Initialize global value
- var parentTextViewRect = Rect()
-
- // Initialize values for the computing of clickedText position
- //val completeText = parentTextView.text as SpannableString
- val textViewLayout = this.layout
-
- val startOffsetOfClickedText = range.first//completeText.getSpanStart(clickedText)
- val endOffsetOfClickedText = range.last//completeText.getSpanEnd(clickedText)
- var startXCoordinatesOfClickedText = textViewLayout.getPrimaryHorizontal(startOffsetOfClickedText)
- var endXCoordinatesOfClickedText = textViewLayout.getPrimaryHorizontal(endOffsetOfClickedText)
-
- // Get the rectangle of the clicked text
- val currentLineStartOffset = textViewLayout.getLineForOffset(startOffsetOfClickedText)
- val currentLineEndOffset = textViewLayout.getLineForOffset(endOffsetOfClickedText)
- val keywordIsInMultiLine = currentLineStartOffset != currentLineEndOffset
- textViewLayout.getLineBounds(currentLineStartOffset, parentTextViewRect)
-
- // Update the rectangle position to his real position on screen
- val parentTextViewLocation = intArrayOf(0, 0)
- this.getLocationOnScreen(parentTextViewLocation)
-
- val parentTextViewTopAndBottomOffset = (parentTextViewLocation[1] - this.scrollY + this.compoundPaddingTop)
- parentTextViewRect.top += parentTextViewTopAndBottomOffset
- parentTextViewRect.bottom += parentTextViewTopAndBottomOffset
-
- // In the case of multi line text, we have to choose what rectangle take
- if (keywordIsInMultiLine) {
- val screenHeight = windowManager.defaultDisplay.height
- val dyTop = parentTextViewRect.top
- val dyBottom = screenHeight - parentTextViewRect.bottom
- val onTop = dyTop > dyBottom
-
- if (onTop) {
- endXCoordinatesOfClickedText = textViewLayout.getLineRight(currentLineStartOffset);
- } else {
- parentTextViewRect = Rect()
- textViewLayout.getLineBounds(currentLineEndOffset, parentTextViewRect);
- parentTextViewRect.top += parentTextViewTopAndBottomOffset;
- parentTextViewRect.bottom += parentTextViewTopAndBottomOffset;
- startXCoordinatesOfClickedText = textViewLayout.getLineLeft(currentLineEndOffset);
- }
- }
-
- parentTextViewRect.left += (
- parentTextViewLocation[0] +
- startXCoordinatesOfClickedText +
- this.compoundPaddingLeft -
- this.scrollX
- ).toInt()
- parentTextViewRect.right = (
- parentTextViewRect.left +
- endXCoordinatesOfClickedText -
- startXCoordinatesOfClickedText
- ).toInt()
-
- return parentTextViewRect
-}
-
-inline fun ViewPager.addOnPageSelectedListener(crossinline block: (position: Int) -> Unit) = addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
- override fun onPageScrollStateChanged(state: Int) {}
- override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
- override fun onPageSelected(position: Int) { block(position) }
-})
-
-val SwipeRefreshLayout.onScrollListener: RecyclerView.OnScrollListener
- get() = object : RecyclerView.OnScrollListener() {
- override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
- if (recyclerView.canScrollVertically(-1))
- this@onScrollListener.isEnabled = false
- if (!recyclerView.canScrollVertically(-1) && newState == RecyclerView.SCROLL_STATE_IDLE)
- this@onScrollListener.isEnabled = true
- }
- }
-
-operator fun Iterable>.get(key: K): V? {
- return firstOrNull { it.first == key }?.second
-}
-
-fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }
-
-fun MutableList.after(what: E, insert: E) {
- val index = indexOf(what)
- if (index != -1)
- add(index + 1, insert)
-}
-
-fun MutableList.before(what: E, insert: E) {
- val index = indexOf(what)
- if (index != -1)
- add(index, insert)
-}
-
-fun MutableList.after(what: E, insert: Collection) {
- val index = indexOf(what)
- if (index != -1)
- addAll(index + 1, insert)
-}
-
-fun MutableList.before(what: E, insert: Collection) {
- val index = indexOf(what)
- if (index != -1)
- addAll(index, insert)
-}
-
-fun Context.getSyncInterval(interval: Int): String {
- val hours = interval / 60 / 60
- val minutes = interval / 60 % 60
- val hoursText = if (hours > 0)
- plural(R.plurals.time_till_hours, hours)
- else
- null
- val minutesText = if (minutes > 0)
- plural(R.plurals.time_till_minutes, minutes)
- else
- ""
- return hoursText?.plus(" $minutesText") ?: minutesText
-}
-
-fun Profile.getSchoolYearConstrains(): CalendarConstraints {
- return CalendarConstraints.Builder()
- .setStart(dateSemester1Start.inMillisUtc)
- .setEnd(dateYearEnd.inMillisUtc)
- .build()
-}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt
index 8dd83bf2..7965d17a 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt
@@ -17,78 +17,59 @@ import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.graphics.ColorUtils
import androidx.core.view.isVisible
-import androidx.lifecycle.Observer
import androidx.navigation.NavOptions
import com.danimahardhika.cafebar.CafeBar
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.jetradarmobile.snowfall.SnowfallView
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
-import com.mikepenz.materialdrawer.model.DividerDrawerItem
-import com.mikepenz.materialdrawer.model.ProfileDrawerItem
-import com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem
+import com.mikepenz.materialdrawer.model.*
import com.mikepenz.materialdrawer.model.interfaces.*
-import com.mikepenz.materialdrawer.model.utils.withIsHiddenInMiniDrawer
-import eu.szkolny.font.SzkolnyFont
+import com.mikepenz.materialdrawer.model.utils.hiddenInMiniDrawer
import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import pl.droidsonroids.gif.GifDrawable
-import pl.szczodrzynski.edziennik.data.api.ERROR_API_INVALID_SIGNATURE
import pl.szczodrzynski.edziennik.data.api.ERROR_VULCAN_API_DEPRECATED
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.api.events.*
import pl.szczodrzynski.edziennik.data.api.models.ApiError
-import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
-import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
-import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
+import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.Metadata.*
import pl.szczodrzynski.edziennik.data.db.entity.Profile
+import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
+import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
import pl.szczodrzynski.edziennik.sync.SyncWorker
+import pl.szczodrzynski.edziennik.sync.UpdateStateEvent
import pl.szczodrzynski.edziennik.sync.UpdateWorker
-import pl.szczodrzynski.edziennik.ui.dialogs.RegisterUnavailableDialog
-import pl.szczodrzynski.edziennik.ui.dialogs.ServerMessageDialog
-import pl.szczodrzynski.edziennik.ui.dialogs.UpdateAvailableDialog
-import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
-import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
-import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileConfigDialog
+import pl.szczodrzynski.edziennik.ui.base.MainSnackbar
+import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
+import pl.szczodrzynski.edziennik.ui.base.enums.NavTargetLocation
+import pl.szczodrzynski.edziennik.ui.dialogs.ChangelogDialog
+import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileConfigDialog
+import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegisterUnavailableDialog
+import pl.szczodrzynski.edziennik.ui.dialogs.sync.ServerMessageDialog
import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncViewListDialog
-import pl.szczodrzynski.edziennik.ui.modules.agenda.AgendaFragment
-import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment
-import pl.szczodrzynski.edziennik.ui.modules.attendance.AttendanceFragment
-import pl.szczodrzynski.edziennik.ui.modules.base.MainSnackbar
-import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment
-import pl.szczodrzynski.edziennik.ui.modules.debug.DebugFragment
-import pl.szczodrzynski.edziennik.ui.modules.debug.LabFragment
-import pl.szczodrzynski.edziennik.ui.modules.error.ErrorDetailsDialog
-import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar
-import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment
-import pl.szczodrzynski.edziennik.ui.modules.grades.GradesListFragment
-import pl.szczodrzynski.edziennik.ui.modules.grades.editor.GradesEditorFragment
-import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment
-import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment
-import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
-import pl.szczodrzynski.edziennik.ui.modules.messages.MessageFragment
-import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
-import pl.szczodrzynski.edziennik.ui.modules.messages.compose.MessagesComposeFragment
-import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsListFragment
-import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment
-import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsFragment
-import pl.szczodrzynski.edziennik.ui.modules.timetable.TimetableFragment
-import pl.szczodrzynski.edziennik.ui.modules.webpush.WebPushFragment
-import pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoTouch
-import pl.szczodrzynski.edziennik.utils.Themes
-import pl.szczodrzynski.edziennik.utils.Utils
+import pl.szczodrzynski.edziennik.ui.dialogs.sync.UpdateAvailableDialog
+import pl.szczodrzynski.edziennik.ui.dialogs.sync.UpdateProgressDialog
+import pl.szczodrzynski.edziennik.ui.error.ErrorDetailsDialog
+import pl.szczodrzynski.edziennik.ui.error.ErrorSnackbar
+import pl.szczodrzynski.edziennik.ui.event.EventManualDialog
+import pl.szczodrzynski.edziennik.ui.login.LoginActivity
+import pl.szczodrzynski.edziennik.ui.messages.list.MessagesFragment
+import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment
+import pl.szczodrzynski.edziennik.utils.*
import pl.szczodrzynski.edziennik.utils.Utils.d
import pl.szczodrzynski.edziennik.utils.Utils.dpToPx
-import pl.szczodrzynski.edziennik.utils.appManagerIntentList
+import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type
+import pl.szczodrzynski.edziennik.utils.managers.UserActionManager
import pl.szczodrzynski.edziennik.utils.models.Date
-import pl.szczodrzynski.edziennik.utils.models.NavTarget
import pl.szczodrzynski.navlib.*
import pl.szczodrzynski.navlib.SystemBarsUtil.Companion.COLOR_HALF_TRANSPARENT
import pl.szczodrzynski.navlib.bottomsheet.NavBottomSheet
@@ -103,142 +84,7 @@ import kotlin.math.roundToInt
class MainActivity : AppCompatActivity(), CoroutineScope {
companion object {
-
- var useOldMessages = false
-
- const val TAG = "MainActivity"
-
- const val DRAWER_PROFILE_ADD_NEW = 200
- const val DRAWER_PROFILE_SYNC_ALL = 201
- const val DRAWER_PROFILE_EXPORT_DATA = 202
- const val DRAWER_PROFILE_MANAGE = 203
- const val DRAWER_PROFILE_MARK_ALL_AS_READ = 204
- const val DRAWER_ITEM_HOME = 1
- const val DRAWER_ITEM_TIMETABLE = 11
- const val DRAWER_ITEM_AGENDA = 12
- const val DRAWER_ITEM_GRADES = 13
- const val DRAWER_ITEM_MESSAGES = 17
- const val DRAWER_ITEM_HOMEWORK = 14
- const val DRAWER_ITEM_BEHAVIOUR = 15
- const val DRAWER_ITEM_ATTENDANCE = 16
- const val DRAWER_ITEM_ANNOUNCEMENTS = 18
- const val DRAWER_ITEM_NOTIFICATIONS = 20
- const val DRAWER_ITEM_SETTINGS = 101
- const val DRAWER_ITEM_DEBUG = 102
-
- const val TARGET_GRADES_EDITOR = 501
- const val TARGET_FEEDBACK = 120
- const val TARGET_MESSAGES_DETAILS = 503
- const val TARGET_MESSAGES_COMPOSE = 504
- const val TARGET_WEB_PUSH = 140
- const val TARGET_LAB = 1000
-
- const val HOME_ID = DRAWER_ITEM_HOME
-
- val navTargetList: List by lazy {
- val list: MutableList = mutableListOf()
-
- // home item
- list += NavTarget(DRAWER_ITEM_HOME, R.string.menu_home_page, HomeFragment::class)
- .withTitle(R.string.app_name)
- .withIcon(CommunityMaterial.Icon2.cmd_home_outline)
- .isInDrawer(true)
- .isStatic(true)
- .withPopToHome(false)
-
- list += NavTarget(DRAWER_ITEM_TIMETABLE, R.string.menu_timetable, TimetableFragment::class)
- .withIcon(CommunityMaterial.Icon3.cmd_timetable)
- .withBadgeTypeId(TYPE_LESSON_CHANGE)
- .isInDrawer(true)
-
- list += NavTarget(DRAWER_ITEM_AGENDA, R.string.menu_agenda, AgendaFragment::class)
- .withIcon(CommunityMaterial.Icon.cmd_calendar_outline)
- .withBadgeTypeId(TYPE_EVENT)
- .isInDrawer(true)
-
- list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesListFragment::class)
- .withIcon(CommunityMaterial.Icon3.cmd_numeric_5_box_outline)
- .withBadgeTypeId(TYPE_GRADE)
- .isInDrawer(true)
-
- list += NavTarget(DRAWER_ITEM_MESSAGES, R.string.menu_messages, MessagesFragment::class)
- .withIcon(CommunityMaterial.Icon.cmd_email_outline)
- .withBadgeTypeId(TYPE_MESSAGE)
- .isInDrawer(true)
-
- list += NavTarget(DRAWER_ITEM_HOMEWORK, R.string.menu_homework, HomeworkFragment::class)
- .withIcon(SzkolnyFont.Icon.szf_notebook_outline)
- .withBadgeTypeId(TYPE_HOMEWORK)
- .isInDrawer(true)
-
- list += NavTarget(DRAWER_ITEM_BEHAVIOUR, R.string.menu_notices, BehaviourFragment::class)
- .withIcon(CommunityMaterial.Icon.cmd_emoticon_outline)
- .withBadgeTypeId(TYPE_NOTICE)
- .isInDrawer(true)
-
- list += NavTarget(DRAWER_ITEM_ATTENDANCE, R.string.menu_attendance, AttendanceFragment::class)
- .withIcon(CommunityMaterial.Icon.cmd_calendar_remove_outline)
- .withBadgeTypeId(TYPE_ATTENDANCE)
- .isInDrawer(true)
-
- list += NavTarget(DRAWER_ITEM_ANNOUNCEMENTS, R.string.menu_announcements, AnnouncementsFragment::class)
- .withIcon(CommunityMaterial.Icon.cmd_bullhorn_outline)
- .withBadgeTypeId(TYPE_ANNOUNCEMENT)
- .isInDrawer(true)
-
-
- // static drawer items
- list += NavTarget(DRAWER_ITEM_NOTIFICATIONS, R.string.menu_notifications, NotificationsListFragment::class)
- .withIcon(CommunityMaterial.Icon.cmd_bell_ring_outline)
- .isInDrawer(true)
- .isStatic(true)
- .isBelowSeparator(true)
-
- list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsFragment::class)
- .withIcon(CommunityMaterial.Icon.cmd_cog_outline)
- .isInDrawer(true)
- .isStatic(true)
- .isBelowSeparator(true)
-
-
- // profile settings items
- list += NavTarget(DRAWER_PROFILE_ADD_NEW, R.string.menu_add_new_profile, null)
- .withIcon(CommunityMaterial.Icon3.cmd_plus)
- .withDescription(R.string.drawer_add_new_profile_desc)
- .isInProfileList(true)
-
- list += NavTarget(DRAWER_PROFILE_MANAGE, R.string.menu_manage_profiles, ProfileManagerFragment::class)
- .withTitle(R.string.title_profile_manager)
- .withIcon(CommunityMaterial.Icon.cmd_account_group)
- .withDescription(R.string.drawer_manage_profiles_desc)
- .isInProfileList(false)
-
- list += NavTarget(DRAWER_PROFILE_MARK_ALL_AS_READ, R.string.menu_mark_everything_as_read, null)
- .withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
- .isInProfileList(true)
-
- list += NavTarget(DRAWER_PROFILE_SYNC_ALL, R.string.menu_sync_all, null)
- .withIcon(CommunityMaterial.Icon.cmd_download_outline)
- .isInProfileList(true)
-
-
- // other target items, not directly navigated
- list += NavTarget(TARGET_GRADES_EDITOR, R.string.menu_grades_editor, GradesEditorFragment::class)
- list += NavTarget(TARGET_FEEDBACK, R.string.menu_feedback, FeedbackFragment::class)
- list += NavTarget(TARGET_MESSAGES_DETAILS, R.string.menu_message, MessageFragment::class).withPopTo(DRAWER_ITEM_MESSAGES)
- list += NavTarget(TARGET_MESSAGES_COMPOSE, R.string.menu_message_compose, MessagesComposeFragment::class)
- list += NavTarget(TARGET_WEB_PUSH, R.string.menu_web_push, WebPushFragment::class)
- if (App.devMode) {
- list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class)
- list += NavTarget(TARGET_LAB, R.string.menu_lab, LabFragment::class)
- .withIcon(CommunityMaterial.Icon2.cmd_flask_outline)
- .isInDrawer(true)
- .isBelowSeparator(true)
- .isStatic(true)
- }
-
- list
- }
+ private const val TAG = "MainActivity"
}
private var job = Job()
@@ -255,15 +101,17 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
val swipeRefreshLayout: SwipeRefreshLayoutNoTouch by lazy { b.swipeRefreshLayout }
+ var onBeforeNavigate: (() -> Boolean)? = null
+ private var pausedNavigationData: PausedNavigationData? = null
+
val app: App by lazy {
applicationContext as App
}
private val fragmentManager by lazy { supportFragmentManager }
- private lateinit var navTarget: NavTarget
+ lateinit var navTarget: NavTarget
+ private set
private var navArguments: Bundle? = null
- val navTargetId
- get() = navTarget.id
private val navBackStack = mutableListOf>()
private var navLoading = true
@@ -326,8 +174,12 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.statusBarColor = statusBarColor
}
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ColorUtils.calculateLuminance(statusBarColor) > 0.6) {
- window.decorView.systemUiVisibility = window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+ && ColorUtils.calculateLuminance(statusBarColor) > 0.6
+ ) {
+ @Suppress("deprecation")
+ window.decorView.systemUiVisibility =
+ window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}
// TODO fix navlib navbar detection, orientation change issues, status bar color setting if not fullscreen
@@ -347,8 +199,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
fabGravity = Gravity.CENTER
if (Themes.isDark) {
setBackgroundColor(blendColors(
- getColorFromAttr(context, R.attr.colorSurface),
- getColorFromRes(R.color.colorSurface_4dp)
+ getColorFromAttr(context, R.attr.colorSurface),
+ getColorFromRes(R.color.colorSurface_4dp)
))
elevation = dpToPx(4).toFloat()
}
@@ -370,13 +222,15 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
drawerProfileListEmptyListener = {
onProfileListEmptyEvent(ProfileListEmptyEvent())
}
- drawerItemSelectedListener = { id, position, drawerItem ->
- loadTarget(id)
- true
+ drawerItemSelectedListener = { id, _, item ->
+ if (item is ExpandableDrawerItem)
+ false
+ else
+ navigate(navTarget = id.asNavTargetOrNull())
}
- drawerProfileSelectedListener = { id, profile, _, _ ->
- loadProfile(id)
- false
+ drawerProfileSelectedListener = { id, _, _, _ ->
+ // why is this negated -_-
+ !navigate(profileId = id)
}
drawerProfileLongClickListener = { _, profile, _, view ->
if (view != null && profile is ProfileDrawerItem) {
@@ -385,11 +239,10 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
App.db.profileDao().getByIdNow(profile.identifier.toInt())
} ?: return@launch
drawer.close()
- ProfileConfigDialog(this@MainActivity, appProfile)
+ ProfileConfigDialog(this@MainActivity, appProfile).show()
}
true
- }
- else {
+ } else {
false
}
}
@@ -401,48 +254,47 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
}
- navTarget = navTargetList[0]
+ navTarget = NavTarget.HOME
if (savedInstanceState != null) {
intent?.putExtras(savedInstanceState)
savedInstanceState.clear()
}
- app.db.profileDao().all.observe(this, Observer { profiles ->
+ app.db.profileDao().all.observe(this) { profiles ->
val allArchived = profiles.all { it.archived }
- drawer.setProfileList(profiles.filter { it.id >= 0 && (!it.archived || allArchived) }.toMutableList())
+ drawer.setProfileList(profiles.filter {
+ it.id >= 0 && (!it.archived || allArchived)
+ }.toMutableList())
//prepend the archived profile if loaded
if (app.profile.archived && !allArchived) {
drawer.prependProfile(Profile(
- id = app.profile.id,
- loginStoreId = app.profile.loginStoreId,
- loginStoreType = app.profile.loginStoreType,
- name = app.profile.name,
- subname = "Archiwum - ${app.profile.subname}"
+ id = app.profile.id,
+ loginStoreId = app.profile.loginStoreId,
+ loginStoreType = app.profile.loginStoreType,
+ name = app.profile.name,
+ subname = "Archiwum - ${app.profile.subname}"
).also {
it.archived = true
})
}
drawer.currentProfile = App.profileId
- })
+ }
setDrawerItems()
handleIntent(intent?.extras)
- app.db.metadataDao().unreadCounts.observe(this, Observer { unreadCounters ->
- unreadCounters.map {
- it.type = it.thingType
- }
+ app.db.metadataDao().unreadCounts.observe(this) { unreadCounters ->
drawer.setUnreadCounterList(unreadCounters)
- })
+ }
b.swipeRefreshLayout.isEnabled = true
b.swipeRefreshLayout.setOnRefreshListener { launch { syncCurrentFeature() } }
b.swipeRefreshLayout.setColorSchemeResources(
- R.color.md_blue_500,
- R.color.md_amber_500,
- R.color.md_green_500
+ R.color.md_blue_500,
+ R.color.md_amber_500,
+ R.color.md_green_500
)
SyncWorker.scheduleNext(app)
@@ -456,11 +308,11 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
app.db.profileDao().getNotArchivedOf(app.profile.archiveId!!)
}
if (profile != null)
- loadProfile(profile)
+ navigate(profile = profile)
else
- loadProfile(0)
+ navigate(profileId = 0)
} else {
- loadProfile(0)
+ navigate(profileId = 0)
}
}
}
@@ -470,15 +322,30 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
// IT'S WINTER MY DUDES
val today = Date.getToday()
- if ((today.month == 12 || today.month == 1) && app.config.ui.snowfall) {
+ if ((today.month / 3 % 4 == 0) && app.config.ui.snowfall) {
b.rootFrame.addView(layoutInflater.inflate(R.layout.snowfall, b.rootFrame, false))
+ } else if (app.config.ui.eggfall && BigNightUtil().isDataWielkanocyNearDzisiaj()) {
+ val eggfall = layoutInflater.inflate(
+ R.layout.eggfall,
+ b.rootFrame,
+ false
+ ) as SnowfallView
+ eggfall.setSnowflakeBitmaps(listOf(
+ BitmapFactory.decodeResource(resources, R.drawable.egg1),
+ BitmapFactory.decodeResource(resources, R.drawable.egg2),
+ BitmapFactory.decodeResource(resources, R.drawable.egg3),
+ BitmapFactory.decodeResource(resources, R.drawable.egg4),
+ BitmapFactory.decodeResource(resources, R.drawable.egg5),
+ BitmapFactory.decodeResource(resources, R.drawable.egg6)
+ ))
+ b.rootFrame.addView(eggfall)
}
// WHAT'S NEW DIALOG
if (app.config.appVersion < BuildConfig.VERSION_CODE) {
// force an AppSync after update
app.config.sync.lastAppSync = 0L
- ChangelogDialog(this)
+ ChangelogDialog(this).show()
if (app.config.appVersion < 170) {
//Intent intent = new Intent(this, ChangelogIntroActivity.class);
//startActivity(intent);
@@ -491,89 +358,90 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
if (app.config.appRateSnackbarTime != 0L && app.config.appRateSnackbarTime <= System.currentTimeMillis()) {
navView.coordinator.postDelayed({
CafeBar.builder(this)
- .content(R.string.rate_snackbar_text)
- .icon(IconicsDrawable(this).apply {
- icon = CommunityMaterial.Icon3.cmd_star_outline
- sizeDp = 24
- colorInt = Themes.getPrimaryTextColor(this@MainActivity)
- })
- .positiveText(R.string.rate_snackbar_positive)
- .positiveColor(-0xb350b0)
- .negativeText(R.string.rate_snackbar_negative)
- .negativeColor(0xff666666.toInt())
- .neutralText(R.string.rate_snackbar_neutral)
- .neutralColor(0xff666666.toInt())
- .onPositive { cafeBar ->
- Utils.openGooglePlay(this)
- cafeBar.dismiss()
- app.config.appRateSnackbarTime = 0
- }
- .onNegative { cafeBar ->
- Toast.makeText(this, R.string.rate_snackbar_negative_message, Toast.LENGTH_LONG).show()
- cafeBar.dismiss()
- app.config.appRateSnackbarTime = 0
- }
- .onNeutral { cafeBar ->
- Toast.makeText(this, R.string.ok, Toast.LENGTH_LONG).show()
- cafeBar.dismiss()
- app.config.appRateSnackbarTime = System.currentTimeMillis() + 7 * 24 * 60 * 60 * 1000
- }
- .autoDismiss(false)
- .swipeToDismiss(true)
- .floating(true)
- .show()
+ .content(R.string.rate_snackbar_text)
+ .icon(IconicsDrawable(this).apply {
+ icon = CommunityMaterial.Icon3.cmd_star_outline
+ sizeDp = 24
+ colorInt = Themes.getPrimaryTextColor(this@MainActivity)
+ })
+ .positiveText(R.string.rate_snackbar_positive)
+ .positiveColor(-0xb350b0)
+ .negativeText(R.string.rate_snackbar_negative)
+ .negativeColor(0xff666666.toInt())
+ .neutralText(R.string.rate_snackbar_neutral)
+ .neutralColor(0xff666666.toInt())
+ .onPositive { cafeBar ->
+ Utils.openGooglePlay(this)
+ cafeBar.dismiss()
+ app.config.appRateSnackbarTime = 0
+ }
+ .onNegative { cafeBar ->
+ Toast.makeText(this,
+ R.string.rate_snackbar_negative_message,
+ Toast.LENGTH_LONG).show()
+ cafeBar.dismiss()
+ app.config.appRateSnackbarTime = 0
+ }
+ .onNeutral { cafeBar ->
+ Toast.makeText(this, R.string.ok, Toast.LENGTH_LONG).show()
+ cafeBar.dismiss()
+ app.config.appRateSnackbarTime =
+ System.currentTimeMillis() + 7 * 24 * 60 * 60 * 1000
+ }
+ .autoDismiss(false)
+ .swipeToDismiss(true)
+ .floating(true)
+ .show()
}, 10000)
}
// CONTEXT MENU ITEMS
bottomSheet.removeAllItems()
bottomSheet.appendItems(
- BottomSheetPrimaryItem(false)
- .withTitle(R.string.menu_sync)
- .withIcon(CommunityMaterial.Icon.cmd_download_outline)
- .withOnClickListener(View.OnClickListener {
- bottomSheet.close()
- SyncViewListDialog(this, navTargetId)
- }),
- BottomSheetSeparatorItem(false),
- BottomSheetPrimaryItem(false)
- .withTitle(R.string.menu_settings)
- .withIcon(CommunityMaterial.Icon.cmd_cog_outline)
- .withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_SETTINGS) }),
- BottomSheetPrimaryItem(false)
- .withTitle(R.string.menu_feedback)
- .withIcon(CommunityMaterial.Icon2.cmd_help_circle_outline)
- .withOnClickListener(View.OnClickListener { loadTarget(TARGET_FEEDBACK) })
+ BottomSheetPrimaryItem(false)
+ .withTitle(R.string.menu_sync)
+ .withIcon(CommunityMaterial.Icon.cmd_download_outline)
+ .withOnClickListener {
+ bottomSheet.close()
+ SyncViewListDialog(this, navTarget).show()
+ },
+ BottomSheetSeparatorItem(false),
)
- if (App.devMode) {
- bottomSheet += BottomSheetPrimaryItem(false)
- .withTitle(R.string.menu_debug)
- .withIcon(CommunityMaterial.Icon.cmd_android_debug_bridge)
- .withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_DEBUG) })
+ for (target in NavTarget.values()) {
+ if (target.location != NavTargetLocation.BOTTOM_SHEET)
+ continue
+ if (target.devModeOnly && !App.devMode)
+ continue
+ bottomSheet += target.toBottomSheetItem(this)
}
}
- private var profileSettingClickListener = { id: Int, view: View? ->
- when (id) {
- DRAWER_PROFILE_ADD_NEW -> {
+ private var profileSettingClickListener = { itemId: Int, _: View? ->
+ when (val item = itemId.asNavTarget()) {
+ NavTarget.PROFILE_ADD -> {
requestHandler.requestLogin()
}
- DRAWER_PROFILE_SYNC_ALL -> {
+ NavTarget.PROFILE_SYNC_ALL -> {
EdziennikTask.sync().enqueue(this)
}
- DRAWER_PROFILE_MARK_ALL_AS_READ -> { launch {
- withContext(Dispatchers.Default) {
- app.db.profileDao().allNow.forEach { profile ->
- if (profile.loginStoreType != LoginStore.LOGIN_TYPE_LIBRUS)
- app.db.metadataDao().setAllSeenExceptMessagesAndAnnouncements(profile.id, true)
- else
- app.db.metadataDao().setAllSeenExceptMessages(profile.id, true)
+ NavTarget.PROFILE_MARK_AS_READ -> {
+ launch {
+ withContext(Dispatchers.Default) {
+ app.db.profileDao().allNow.forEach { profile ->
+ if (!profile.getAppData().uiConfig.enableMarkAsReadAnnouncements)
+ app.db.metadataDao()
+ .setAllSeenExceptMessagesAndAnnouncements(profile.id, true)
+ else
+ app.db.metadataDao().setAllSeenExceptMessages(profile.id, true)
+ }
}
+ Toast.makeText(this@MainActivity,
+ R.string.main_menu_mark_as_read_success,
+ Toast.LENGTH_SHORT).show()
}
- Toast.makeText(this@MainActivity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show()
- }}
+ }
else -> {
- loadTarget(id)
+ navigate(navTarget = item)
}
}
false
@@ -587,114 +455,106 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|_____/ \__, |_| |_|\___|
__/ |
|__*/
- suspend fun syncCurrentFeature() {
+ private suspend fun syncCurrentFeature() {
if (app.profile.archived) {
MaterialAlertDialogBuilder(this)
- .setTitle(R.string.profile_archived_title)
- .setMessage(
- R.string.profile_archived_text,
- app.profile.studentSchoolYearStart,
- app.profile.studentSchoolYearStart + 1
- )
- .setPositiveButton(R.string.ok, null)
- .show()
+ .setTitle(R.string.profile_archived_title)
+ .setMessage(
+ R.string.profile_archived_text,
+ app.profile.studentSchoolYearStart,
+ app.profile.studentSchoolYearStart + 1
+ )
+ .setPositiveButton(R.string.ok, null)
+ .show()
swipeRefreshLayout.isRefreshing = false
return
}
if (app.profile.shouldArchive()) {
MaterialAlertDialogBuilder(this)
- .setTitle(R.string.profile_archiving_title)
- .setMessage(
- R.string.profile_archiving_format,
- app.profile.dateYearEnd.formattedString
- )
- .setPositiveButton(R.string.ok, null)
- .show()
+ .setTitle(R.string.profile_archiving_title)
+ .setMessage(
+ R.string.profile_archiving_format,
+ app.profile.dateYearEnd.formattedString
+ )
+ .setPositiveButton(R.string.ok, null)
+ .show()
}
if (app.profile.isBeforeYear()) {
MaterialAlertDialogBuilder(this)
- .setTitle(R.string.profile_year_not_started_title)
- .setMessage(
- R.string.profile_year_not_started_format,
- app.profile.dateSemester1Start.formattedString
- )
- .setPositiveButton(R.string.ok, null)
- .show()
+ .setTitle(R.string.profile_year_not_started_title)
+ .setMessage(
+ R.string.profile_year_not_started_format,
+ app.profile.dateSemester1Start.formattedString
+ )
+ .setPositiveButton(R.string.ok, null)
+ .show()
swipeRefreshLayout.isRefreshing = false
return
}
- app.profile.registerName?.let { registerName ->
- var status = app.config.sync.registerAvailability[registerName]
- if (status == null || status.nextCheckAt < currentTimeUnix()) {
- val api = SzkolnyApi(app)
- val result = withContext(Dispatchers.IO) {
- return@withContext api.runCatching({
- val availability = getRegisterAvailability()
- app.config.sync.registerAvailability = availability
- availability[registerName]
- }, onError = {
- if (it.toErrorCode() == ERROR_API_INVALID_SIGNATURE) {
- return@withContext false
- }
- return@withContext it
- })
- }
-
- when (result) {
- false -> {
- Toast.makeText(this@MainActivity, R.string.error_no_api_access, Toast.LENGTH_SHORT).show()
- return@let
- }
- is Throwable -> {
- errorSnackbar.addError(result.toApiError(TAG)).show()
- return
- }
- is RegisterAvailabilityStatus -> {
- status = result
- }
- }
- }
-
- if (status?.available != true || status.minVersionCode > BuildConfig.VERSION_CODE) {
+ val error = withContext(Dispatchers.IO) {
+ app.availabilityManager.check(app.profile)
+ }
+ when (error?.type) {
+ Type.NOT_AVAILABLE -> {
swipeRefreshLayout.isRefreshing = false
- loadTarget(DRAWER_ITEM_HOME)
- if (status != null)
- RegisterUnavailableDialog(this, status)
+ navigate(navTarget = NavTarget.HOME)
+ RegisterUnavailableDialog(this, error.status!!).show()
return
}
+ Type.API_ERROR -> {
+ errorSnackbar.addError(error.apiError!!).show()
+ return
+ }
+ Type.NO_API_ACCESS -> {
+ Toast.makeText(this, R.string.error_no_api_access, Toast.LENGTH_SHORT).show()
+ }
+ else -> {}
}
swipeRefreshLayout.isRefreshing = true
- Toast.makeText(this, fragmentToSyncName(navTargetId), Toast.LENGTH_SHORT).show()
- val fragmentParam = when (navTargetId) {
- DRAWER_ITEM_MESSAGES -> MessagesFragment.pageSelection
- else -> 0
+ Toast.makeText(this, fragmentToSyncName(navTarget), Toast.LENGTH_SHORT).show()
+ val featureType = when (navTarget) {
+ NavTarget.MESSAGES -> when (MessagesFragment.pageSelection) {
+ Message.TYPE_SENT -> FeatureType.MESSAGES_SENT
+ else -> FeatureType.MESSAGES_INBOX
+ }
+ else -> navTarget.featureType
}
- val arguments = when (navTargetId) {
- DRAWER_ITEM_TIMETABLE -> JsonObject("weekStart" to TimetableFragment.pageSelection?.weekStart?.stringY_m_d)
+ val arguments = when (navTarget) {
+ NavTarget.TIMETABLE -> JsonObject("weekStart" to TimetableFragment.pageSelection?.weekStart?.stringY_m_d)
else -> null
}
EdziennikTask.syncProfile(
- App.profileId,
- listOf(navTargetId to fragmentParam),
- arguments = arguments
+ App.profileId,
+ featureType?.let { setOf(it) },
+ arguments = arguments
).enqueue(this)
}
+
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onUpdateEvent(event: Update) {
EventBus.getDefault().removeStickyEvent(event)
- UpdateAvailableDialog(this, event)
+ UpdateAvailableDialog(this, event).show()
}
+
+ @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
+ fun onUpdateStateEvent(event: UpdateStateEvent) {
+ if (!event.running)
+ return
+ EventBus.getDefault().removeStickyEvent(event)
+ UpdateProgressDialog(this, event.update ?: return, event.downloadId).show()
+ }
+
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onRegisterAvailabilityEvent(event: RegisterAvailabilityEvent) {
EventBus.getDefault().removeStickyEvent(event)
- app.profile.registerName?.let { registerName ->
- event.data[registerName]?.let {
- RegisterUnavailableDialog(this, it)
- }
+ val error = app.availabilityManager.check(app.profile, cacheOnly = true)
+ if (error != null) {
+ RegisterUnavailableDialog(this, error.status!!).show()
}
}
+
@Subscribe(threadMode = ThreadMode.MAIN)
fun onApiTaskStartedEvent(event: ApiTaskStartedEvent) {
swipeRefreshLayout.isRefreshing = true
@@ -706,6 +566,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
}
}
+
@Subscribe(threadMode = ThreadMode.MAIN)
fun onProfileListEmptyEvent(event: ProfileListEmptyEvent) {
d(TAG, "Profile list is empty. Launch LoginActivity.")
@@ -713,6 +574,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
startActivity(Intent(this, LoginActivity::class.java))
finish()
}
+
@Subscribe(threadMode = ThreadMode.MAIN)
fun onApiTaskProgressEvent(event: ApiTaskProgressEvent) {
if (event.profileId == App.profileId) {
@@ -722,11 +584,16 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
subtitle = if (event.progress < 0f)
event.progressText ?: ""
else
- getString(R.string.toolbar_subtitle_syncing_format, event.progress.roundToInt(), event.progressText ?: "")
+ getString(
+ R.string.toolbar_subtitle_syncing_format,
+ event.progress.roundToInt(),
+ event.progressText ?: "",
+ )
}
}
}
+
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onApiTaskFinishedEvent(event: ApiTaskFinishedEvent) {
EventBus.getDefault().removeStickyEvent(event)
@@ -738,18 +605,20 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
}
}
+
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onApiTaskAllFinishedEvent(event: ApiTaskAllFinishedEvent) {
EventBus.getDefault().removeStickyEvent(event)
swipeRefreshLayout.isRefreshing = false
}
+
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onApiTaskErrorEvent(event: ApiTaskErrorEvent) {
EventBus.getDefault().removeStickyEvent(event)
if (event.error.errorCode == ERROR_VULCAN_API_DEPRECATED) {
if (event.error.profileId != App.profileId)
return
- ErrorDetailsDialog(this, listOf(event.error))
+ ErrorDetailsDialog(this, listOf(event.error)).show()
}
navView.toolbar.apply {
subtitleFormat = R.string.toolbar_subtitle
@@ -759,54 +628,59 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
mainSnackbar.dismiss()
errorSnackbar.addError(event.error).show()
}
+
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onAppManagerDetectedEvent(event: AppManagerDetectedEvent) {
EventBus.getDefault().removeStickyEvent(event)
if (app.config.sync.dontShowAppManagerDialog)
return
MaterialAlertDialogBuilder(this)
- .setTitle(R.string.app_manager_dialog_title)
- .setMessage(R.string.app_manager_dialog_text)
- .setPositiveButton(R.string.ok) { dialog, which ->
- try {
- for (intent in appManagerIntentList) {
- if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
- startActivity(intent)
- }
- }
- } catch (e: Exception) {
- try {
- startActivity(Intent(Settings.ACTION_SETTINGS))
- } catch (e: Exception) {
- e.printStackTrace()
- Toast.makeText(this, R.string.app_manager_open_failed, Toast.LENGTH_SHORT).show()
+ .setTitle(R.string.app_manager_dialog_title)
+ .setMessage(R.string.app_manager_dialog_text)
+ .setPositiveButton(R.string.ok) { _, _ ->
+ try {
+ for (intent in appManagerIntentList) {
+ if (packageManager.resolveActivity(intent,
+ PackageManager.MATCH_DEFAULT_ONLY) != null
+ ) {
+ startActivity(intent)
}
}
+ } catch (e: Exception) {
+ try {
+ startActivity(Intent(Settings.ACTION_SETTINGS))
+ } catch (e: Exception) {
+ e.printStackTrace()
+ Toast.makeText(this, R.string.app_manager_open_failed, Toast.LENGTH_SHORT)
+ .show()
+ }
}
- .setNeutralButton(R.string.dont_ask_again) { dialog, which ->
- app.config.sync.dontShowAppManagerDialog = true
- }
- .setCancelable(false)
- .show()
- }
- @Subscribe(threadMode = ThreadMode.MAIN)
- fun onUserActionRequiredEvent(event: UserActionRequiredEvent) {
- app.userActionManager.execute(this, event.profileId, event.type)
+ }
+ .setNeutralButton(R.string.dont_ask_again) { _, _ ->
+ app.config.sync.dontShowAppManagerDialog = true
+ }
+ .setCancelable(false)
+ .show()
}
- private fun fragmentToSyncName(currentFragment: Int): Int {
- return when (currentFragment) {
- DRAWER_ITEM_TIMETABLE -> R.string.sync_feature_timetable
- DRAWER_ITEM_AGENDA -> R.string.sync_feature_agenda
- DRAWER_ITEM_GRADES -> R.string.sync_feature_grades
- DRAWER_ITEM_HOMEWORK -> R.string.sync_feature_homework
- DRAWER_ITEM_BEHAVIOUR -> R.string.sync_feature_notices
- DRAWER_ITEM_ATTENDANCE -> R.string.sync_feature_attendance
- DRAWER_ITEM_MESSAGES -> when (MessagesFragment.pageSelection) {
- 1 -> R.string.sync_feature_messages_outbox
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ fun onUserActionRequiredEvent(event: UserActionRequiredEvent) {
+ app.userActionManager.execute(this, event, UserActionManager.UserActionCallback())
+ }
+
+ private fun fragmentToSyncName(navTarget: NavTarget): Int {
+ return when (navTarget) {
+ NavTarget.TIMETABLE -> R.string.sync_feature_timetable
+ NavTarget.AGENDA -> R.string.sync_feature_agenda
+ NavTarget.GRADES -> R.string.sync_feature_grades
+ NavTarget.HOMEWORK -> R.string.sync_feature_homework
+ NavTarget.BEHAVIOUR -> R.string.sync_feature_notices
+ NavTarget.ATTENDANCE -> R.string.sync_feature_attendance
+ NavTarget.MESSAGES -> when (MessagesFragment.pageSelection) {
+ Message.TYPE_SENT -> R.string.sync_feature_messages_outbox
else -> R.string.sync_feature_messages_inbox
}
- DRAWER_ITEM_ANNOUNCEMENTS -> R.string.sync_feature_announcements
+ NavTarget.ANNOUNCEMENTS -> R.string.sync_feature_announcements
else -> R.string.sync_feature_syncing_all
}
}
@@ -822,46 +696,56 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
handleIntent(intent?.extras)
}
}
- fun handleIntent(extras: Bundle?) {
+ fun handleIntent(extras: Bundle?) {
d(TAG, "handleIntent() {")
extras?.keySet()?.forEach { key ->
- d(TAG, " \"$key\": "+extras.get(key))
+ d(TAG, " \"$key\": " + extras.get(key))
}
d(TAG, "}")
- var intentProfileId = -1
- var intentTargetId = -1
+ val intentProfileId = extras.getIntOrNull("profileId").takePositive()
+ var intentNavTarget = extras.getIntOrNull("fragmentId").asNavTargetOrNull()
if (extras?.containsKey("action") == true) {
val handled = when (extras.getString("action")) {
+ "updateRequest" -> {
+ UpdateAvailableDialog(this, app.config.update).show()
+ true
+ }
"serverMessage" -> {
ServerMessageDialog(
- this,
- extras.getString("serverMessageTitle") ?: getString(R.string.app_name),
- extras.getString("serverMessageText") ?: ""
- )
+ this,
+ extras.getString("serverMessageTitle") ?: getString(R.string.app_name),
+ extras.getString("serverMessageText") ?: ""
+ ).show()
true
}
"feedbackMessage" -> {
- intentTargetId = TARGET_FEEDBACK
+ intentNavTarget = NavTarget.FEEDBACK
false
}
"userActionRequired" -> {
- app.userActionManager.execute(
- this,
- extras.getInt("profileId"),
- extras.getInt("type")
+ val event = UserActionRequiredEvent(
+ profileId = extras.getInt("profileId"),
+ type = extras.getEnum("type") ?: return,
+ params = extras.getBundle("params") ?: return,
+ errorText = 0,
)
+ app.userActionManager.execute(this,
+ event,
+ UserActionManager.UserActionCallback())
true
}
"createManualEvent" -> {
- val date = extras.getString("eventDate")?.let { Date.fromY_m_d(it) } ?: Date.getToday()
+ val date = extras.getString("eventDate")
+ ?.let { Date.fromY_m_d(it) }
+ ?: Date.getToday()
EventManualDialog(
- this,
- App.profileId,
- defaultDate = date
- )
+ this,
+ App.profileId,
+ defaultDate = date
+ ).show()
true
}
else -> false
@@ -872,70 +756,59 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
if (extras?.containsKey("reloadProfileId") == true) {
- val reloadProfileId = extras.getInt("reloadProfileId", -1)
- extras.remove("reloadProfileId")
- if (reloadProfileId == -1 || app.profile.id == reloadProfileId) {
+ val reloadProfileId = extras.getIntOrNull("reloadProfileId").takePositive()
+ if (reloadProfileId == null || app.profile.id == reloadProfileId) {
reloadTarget()
return
}
}
- if (extras?.getInt("profileId", -1) != -1) {
- intentProfileId = extras.getInt("profileId", -1)
- extras?.remove("profileId")
- }
-
- if (extras?.getInt("fragmentId", -1) != -1) {
- intentTargetId = extras.getInt("fragmentId", -1)
- extras?.remove("fragmentId")
- }
+ extras?.remove("profileId")
+ extras?.remove("fragmentId")
+ extras?.remove("reloadProfileId")
/*if (intentTargetId == -1 && navController.currentDestination?.id == R.id.loadingFragment) {
intentTargetId = navTarget.id
}*/
- if (navLoading) {
+ if (navLoading)
b.fragment.removeAllViews()
- if (intentTargetId == -1)
- intentTargetId = HOME_ID
- }
when {
- app.profile.id == 0 -> {
- if (intentProfileId == -1)
- intentProfileId = app.config.lastProfileId
- loadProfile(intentProfileId, intentTargetId, extras)
- }
- intentProfileId != -1 -> {
- if (app.profile.id != intentProfileId)
- loadProfile(intentProfileId, intentTargetId, extras)
- else
- loadTarget(intentTargetId, extras)
- }
- intentTargetId != -1 -> {
- drawer.currentProfile = app.profile.id
- if (navTargetId != intentTargetId || navLoading)
- loadTarget(intentTargetId, extras)
- }
- else -> {
- drawer.currentProfile = app.profile.id
- }
+ app.profile.id == 0 -> navigate(
+ profileId = intentProfileId ?: app.config.lastProfileId,
+ navTarget = intentNavTarget,
+ args = extras,
+ )
+ intentProfileId != null -> navigate(
+ profileId = intentProfileId,
+ navTarget = intentNavTarget,
+ args = extras,
+ )
+ intentNavTarget != null -> navigate(
+ navTarget = intentNavTarget,
+ args = extras,
+ )
+ navLoading -> navigate()
+ else -> drawer.currentProfile = app.profile.id
}
navLoading = false
}
override fun recreate() {
- recreate(navTargetId)
+ recreate(navTarget)
}
- fun recreate(targetId: Int) {
- recreate(targetId, null)
+
+ fun recreate(navTarget: NavTarget) {
+ recreate(navTarget, null)
}
- fun recreate(targetId: Int? = null, arguments: Bundle? = null) {
+
+ fun recreate(navTarget: NavTarget? = null, arguments: Bundle? = null) {
val intent = Intent(this, MainActivity::class.java)
if (arguments != null)
intent.putExtras(arguments)
- if (targetId != null) {
- intent.putExtra("fragmentId", targetId)
+ if (navTarget != null) {
+ intent.putExtra("fragmentId", navTarget.id)
}
finish()
overridePendingTransition(R.anim.fade_in, R.anim.fade_out)
@@ -946,10 +819,12 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
d(TAG, "Activity started")
super.onStart()
}
+
override fun onStop() {
d(TAG, "Activity stopped")
super.onStop()
}
+
override fun onResume() {
d(TAG, "Activity resumed")
val filter = IntentFilter()
@@ -958,12 +833,14 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
EventBus.getDefault().register(this)
super.onResume()
}
+
override fun onPause() {
d(TAG, "Activity paused")
unregisterReceiver(intentReceiver)
EventBus.getDefault().unregister(this)
super.onPause()
}
+
override fun onDestroy() {
d(TAG, "Activity destroyed")
super.onDestroy()
@@ -971,13 +848,15 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- outState.putInt("fragmentId", navTargetId)
+ outState.putExtras("fragmentId" to navTarget)
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
handleIntent(intent?.extras)
}
+
+ @Suppress("deprecation")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
requestHandler.handleResult(requestCode, resultCode, data)
@@ -990,110 +869,139 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
| |___| (_) | (_| | (_| | | | | | | | __/ |_| | | | (_) | (_| \__ \
|______\___/ \__,_|\__,_| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|__*/
val navOptions = NavOptions.Builder()
- .setEnterAnim(R.anim.task_open_enter) // new fragment enter
- .setExitAnim(R.anim.task_open_exit) // old fragment exit
- .setPopEnterAnim(R.anim.task_close_enter) // old fragment enter back
- .setPopExitAnim(R.anim.task_close_exit) // new fragment exit
- .build()
+ .setEnterAnim(R.anim.task_open_enter) // new fragment enter
+ .setExitAnim(R.anim.task_open_exit) // old fragment exit
+ .setPopEnterAnim(R.anim.task_close_enter) // old fragment enter back
+ .setPopExitAnim(R.anim.task_close_exit) // new fragment exit
+ .build()
- fun loadProfile(id: Int) = loadProfile(id, navTargetId)
- fun loadProfile(id: Int, arguments: Bundle?) = loadProfile(id, navTargetId, arguments)
- fun loadProfile(profile: Profile) = loadProfile(
- profile,
- navTargetId,
- null,
- if (app.profile.archived) app.profile.id else null
- )
- private fun loadProfile(id: Int, drawerSelection: Int, arguments: Bundle? = null) {
- if (App.profileId == id) {
- drawer.currentProfile = app.profile.id
- loadTarget(drawerSelection, arguments)
+ private fun canNavigate(): Boolean = onBeforeNavigate?.invoke() != false
+
+ fun resumePausedNavigation(): Boolean {
+ val data = pausedNavigationData ?: return false
+ navigate(
+ profileId = data.profileId,
+ navTarget = data.navTarget,
+ args = data.args,
+ skipBeforeNavigate = true,
+ )
+ pausedNavigationData = null
+ return true
+ }
+
+ fun navigate(
+ profileId: Int? = null,
+ profile: Profile? = null,
+ navTarget: NavTarget? = null,
+ args: Bundle? = null,
+ skipBeforeNavigate: Boolean = false,
+ ): Boolean {
+ d(TAG, "navigate(profileId = ${profile?.id ?: profileId}, target = ${navTarget?.name}, args = $args)")
+ if (!(skipBeforeNavigate || navTarget == this.navTarget) && !canNavigate()) {
+ bottomSheet.close()
+ drawer.close()
+ // restore the previous profile if changing it with the drawer
+ // well, it still does not change the toolbar profile image,
+ // but that's now NavView's problem, not mine.
+ drawer.currentProfile = App.profile.id
+ pausedNavigationData = PausedNavigationData(profileId, navTarget, args)
+ return false
+ }
+
+ val loadNavTarget = navTarget ?: this.navTarget
+ if (profile != null && profile.id != App.profileId) {
+ navigateImpl(profile, loadNavTarget, args, profileChanged = true)
+ return true
+ }
+ if (profileId != null && profileId != App.profileId) {
+ app.profileLoad(profileId) {
+ navigateImpl(it, loadNavTarget, args, profileChanged = true)
+ }
+ return true
+ }
+ navigateImpl(App.profile, loadNavTarget, args, profileChanged = false)
+ return true
+ }
+
+ private fun navigateImpl(
+ profile: Profile,
+ navTarget: NavTarget,
+ args: Bundle?,
+ profileChanged: Boolean,
+ ) {
+ d(TAG, "navigateImpl(profileId = ${profile.id}, target = ${navTarget.name}, args = $args)")
+
+ if (navTarget.featureType != null && !profile.hasUIFeature(navTarget.featureType)) {
+ navigateImpl(profile, NavTarget.HOME, args, profileChanged)
return
}
- val previousArchivedId = if (app.profile.archived) app.profile.id else null
- app.profileLoad(id) {
- loadProfile(it, drawerSelection, arguments, previousArchivedId)
- }
- }
- private fun loadProfile(profile: Profile, drawerSelection: Int, arguments: Bundle?, previousArchivedId: Int?) {
- App.profile = profile
- MessagesFragment.pageSelection = -1
- setDrawerItems()
+ if (profileChanged) {
+ if (App.profileId != profile.id)
+ app.profileLoad(profile)
+ MessagesFragment.pageSelection = -1
+ // set new drawer items for this profile
+ setDrawerItems()
- if (previousArchivedId != null) {
- // prevents accidentally removing the first item if the archived profile is not shown
- drawer.removeProfileById(previousArchivedId)
- }
- if (profile.archived) {
- drawer.prependProfile(Profile(
+ val previousArchivedId = if (app.profile.archived) app.profile.id else null
+ if (previousArchivedId != null) {
+ // prevents accidentally removing the first item if the archived profile is not shown
+ drawer.removeProfileById(previousArchivedId)
+ }
+ if (profile.archived) {
+ // add the same profile but with a different name
+ // (other fields are not needed by the drawer)
+ drawer.prependProfile(Profile(
id = profile.id,
loginStoreId = profile.loginStoreId,
loginStoreType = profile.loginStoreType,
name = profile.name,
subname = "Archiwum - ${profile.subname}"
- ).also {
- it.archived = true
- })
+ ).also {
+ it.archived = true
+ })
+ }
+
+ // the drawer profile is updated automatically when the drawer item is clicked
+ // update it manually when switching profiles from other source
+ //if (drawer.currentProfile != app.profile.id)
+ drawer.currentProfile = App.profileId
}
- // the drawer profile is updated automatically when the drawer item is clicked
- // update it manually when switching profiles from other source
- //if (drawer.currentProfile != app.profile.id)
- drawer.currentProfile = app.profileId
- loadTarget(drawerSelection, arguments)
- }
- fun loadTarget(id: Int, arguments: Bundle? = null) {
- var loadId = id
- if (loadId == -1) {
- loadId = DRAWER_ITEM_HOME
- }
- val target = navTargetList
- .firstOrNull { it.id == loadId }
- if (target == null) {
- Toast.makeText(this, getString(R.string.error_invalid_fragment, id), Toast.LENGTH_LONG).show()
- loadTarget(navTargetList.first(), arguments)
- }
- else {
- loadTarget(target, arguments)
- }
- }
- private fun loadTarget(target: NavTarget, args: Bundle? = null) {
- d("NavDebug", "loadTarget(target = $target, args = $args)")
-
- val arguments = args ?: navBackStack.firstOrNull { it.first.id == target.id }?.second ?: Bundle()
+ val arguments = args
+ ?: navBackStack.firstOrNull { it.first == navTarget }?.second
+ ?: Bundle()
bottomSheet.close()
bottomSheet.removeAllContextual()
bottomSheet.toggleGroupEnabled = false
drawer.close()
- if (drawer.getSelection() != target.id)
- drawer.setSelection(target.id, fireOnClick = false)
- navView.toolbar.setTitle(target.title ?: target.name)
+ if (drawer.getSelection() != navTarget.id)
+ drawer.setSelection(navTarget.id, fireOnClick = false)
+ navView.toolbar.setTitle(navTarget.titleRes ?: navTarget.nameRes)
navView.bottomBar.fabEnable = false
navView.bottomBar.fabExtended = false
navView.bottomBar.setFabOnClickListener(null)
- d("NavDebug", "Navigating from ${navTarget.fragmentClass?.java?.simpleName} to ${target.fragmentClass?.java?.simpleName}")
+ d("NavDebug", "Navigating from ${this.navTarget.name} to ${navTarget.name}")
- val fragment = target.fragmentClass?.java?.newInstance() ?: return
+ val fragment = navTarget.fragmentClass?.newInstance() ?: return
fragment.arguments = arguments
val transaction = fragmentManager.beginTransaction()
- if (navTarget == target) {
+ if (navTarget == this.navTarget) {
// just reload the current target
transaction.setCustomAnimations(
- R.anim.fade_in,
- R.anim.fade_out
+ R.anim.fade_in,
+ R.anim.fade_out
)
- }
- else {
- navBackStack.keys().lastIndexOf(target).let {
+ } else {
+ navBackStack.keys().lastIndexOf(navTarget).let {
if (it == -1)
- return@let target
+ return@let navTarget
// pop the back stack up until that target
transaction.setCustomAnimations(
- R.anim.task_close_enter,
- R.anim.task_close_exit
+ R.anim.task_close_enter,
+ R.anim.task_close_exit
)
// navigating grades_add -> grades
@@ -1108,24 +1016,24 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
for (i in 0 until popCount) {
navBackStack.removeAt(navBackStack.lastIndex)
}
- navTarget = target
- navArguments = arguments
+ this.navTarget = navTarget
+ this.navArguments = arguments
return@let null
}?.let {
// target is neither current nor in the back stack
// so navigate to it
transaction.setCustomAnimations(
- R.anim.task_open_enter,
- R.anim.task_open_exit
+ R.anim.task_open_enter,
+ R.anim.task_open_exit
)
- navBackStack.add(navTarget to navArguments)
- navTarget = target
- navArguments = arguments
+ navBackStack.add(this.navTarget to this.navArguments)
+ this.navTarget = navTarget
+ this.navArguments = arguments
}
}
- if (navTarget.popToHome) {
+ if (navTarget.popTo == NavTarget.HOME) {
// if the current has popToHome, let only home be in the back stack
// probably `if (navTarget.popToHome)` in popBackStack() is not needed now
val popCount = navBackStack.size - 1
@@ -1134,9 +1042,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
}
- d("NavDebug", "Current fragment ${navTarget.fragmentClass?.java?.simpleName}, pop to home ${navTarget.popToHome}, back stack:")
- navBackStack.forEachIndexed { index, target2 ->
- d("NavDebug", " - $index: ${target2.first.fragmentClass?.java?.simpleName}")
+ d("NavDebug", "Current fragment ${navTarget.name}, back stack:")
+ navBackStack.forEachIndexed { index, item ->
+ d("NavDebug", " - $index: ${item.first.name}")
}
transaction.replace(R.id.fragment, fragment)
@@ -1145,39 +1053,47 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
// TASK DESCRIPTION
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val bm = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
+
+ @Suppress("deprecation")
val taskDesc = ActivityManager.TaskDescription(
- if (target.id == HOME_ID) getString(R.string.app_name) else getString(R.string.app_task_format, getString(target.name)),
- bm,
- getColorFromAttr(this, R.attr.colorSurface)
+ if (navTarget == NavTarget.HOME)
+ getString(R.string.app_name)
+ else
+ getString(R.string.app_task_format, getString(navTarget.nameRes)),
+ bm,
+ getColorFromAttr(this, R.attr.colorSurface)
)
setTaskDescription(taskDesc)
}
-
+ return
}
- fun reloadTarget() = loadTarget(navTarget)
- private fun popBackStack(): Boolean {
+ fun reloadTarget() = navigate()
+
+ private fun popBackStack(skipBeforeNavigate: Boolean = false): Boolean {
if (navBackStack.size == 0) {
return false
}
// TODO back stack argument support
- when {
- navTarget.popToHome -> {
- loadTarget(HOME_ID)
- }
- navTarget.popTo != null -> {
- loadTarget(navTarget.popTo ?: HOME_ID)
- }
- else -> {
- navBackStack.last().let {
- loadTarget(it.first, it.second)
- }
+ if (navTarget.popTo != null) {
+ navigate(
+ navTarget = navTarget.popTo,
+ skipBeforeNavigate = skipBeforeNavigate,
+ )
+ } else {
+ navBackStack.last().let {
+ navigate(
+ navTarget = it.first,
+ args = it.second,
+ skipBeforeNavigate = skipBeforeNavigate,
+ )
}
}
return true
}
- fun navigateUp() {
- if (!popBackStack()) {
+
+ fun navigateUp(skipBeforeNavigate: Boolean = false) {
+ if (!popBackStack(skipBeforeNavigate)) {
super.onBackPressed()
}
}
@@ -1226,25 +1142,31 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
| |__| | | | (_| |\ V V / __/ | | | || __/ | | | | \__ \
|_____/|_| \__,_| \_/\_/ \___|_| |_|\__\___|_| |_| |_|__*/
private fun createDrawerItem(target: NavTarget, level: Int = 1): IDrawerItem<*> {
- val item = DrawerPrimaryItem()
- .withIdentifier(target.id.toLong())
- .withName(target.name)
- .withIsHiddenInMiniDrawer(!app.config.ui.miniMenuButtons.contains(target.id))
- .also { if (target.description != null) it.withDescription(target.description!!) }
- .also { if (target.icon != null) it.withIcon(target.icon!!) }
- .also { if (target.title != null) it.withAppTitle(getString(target.title!!)) }
- .also { if (target.badgeTypeId != null) it.withBadgeStyle(drawer.badgeStyle)}
- .withSelectedBackgroundAnimated(false)
+ val item = when {
+ // target.subItems != null -> ExpandableDrawerItem()
+ level > 1 -> SecondaryDrawerItem()
+ else -> DrawerPrimaryItem()
+ }
- if (target.badgeTypeId != null)
- drawer.addUnreadCounterType(target.badgeTypeId!!, target.id)
- // TODO sub items
- /*
- if (target.subItems != null) {
- for (subItem in target.subItems!!) {
- item.subItems += createDrawerItem(subItem, level+1)
- }
- }*/
+ item.also {
+ it.identifier = target.id.toLong()
+ it.nameRes = target.nameRes
+ it.descriptionRes = target.descriptionRes ?: -1
+ it.icon = target.icon?.toImageHolder()
+ it.hiddenInMiniDrawer = !app.config.ui.miniMenuButtons.contains(target)
+ if (it is DrawerPrimaryItem)
+ it.appTitle = target.titleRes?.resolveString(this)
+ if (/* it is ColorfulBadgeable && */ target.badgeType != null)
+ it.badgeStyle = drawer.badgeStyle
+ it.isSelectedBackgroundAnimated = false
+ it.level = level
+ }
+ if (target.badgeType != null)
+ drawer.addUnreadCounterType(target.badgeType.id, target.id)
+
+ /* item.subItems = target.subItems?.map {
+ createDrawerItem(it, level + 1)
+ }?.toMutableList() ?: mutableListOf() */
return item
}
@@ -1252,62 +1174,75 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
fun setDrawerItems() {
d("NavDebug", "setDrawerItems() app.profile = ${app.profile}")
val drawerItems = arrayListOf>()
+ val drawerItemsMore = arrayListOf>()
+ val drawerItemsBottom = arrayListOf>()
val drawerProfiles = arrayListOf()
- val supportedFragments = app.profile.supportedFragments
+ for (target in NavTarget.values()) {
+ if (target.devModeOnly && !App.devMode)
+ continue
+ if (target.featureType != null && !app.profile.hasUIFeature(target.featureType))
+ continue
- targetPopToHomeList.clear()
-
- var separatorAdded = false
-
- for (target in navTargetList) {
- if (target.isInDrawer && target.isBelowSeparator && !separatorAdded) {
- separatorAdded = true
- drawerItems += DividerDrawerItem()
- }
-
- if (target.popToHome)
- targetPopToHomeList += target.id
-
- if (target.isInDrawer && (target.isStatic || supportedFragments.isEmpty() || supportedFragments.contains(target.id))) {
- drawerItems += createDrawerItem(target)
- if (target.id == 1) {
- targetHomeId = target.id
+ when (target.location) {
+ NavTargetLocation.DRAWER -> {
+ drawerItems += createDrawerItem(target, level = 1)
}
- }
-
- if (target.isInProfileList) {
- drawerProfiles += ProfileSettingDrawerItem()
- .withIdentifier(target.id.toLong())
- .withName(target.name)
- .also { if (target.description != null) it.withDescription(target.description!!) }
- .also { if (target.icon != null) it.withIcon(target.icon!!) }
+ NavTargetLocation.DRAWER_MORE -> {
+ drawerItemsMore += createDrawerItem(target, level = 2)
+ }
+ NavTargetLocation.DRAWER_BOTTOM -> {
+ drawerItemsBottom += createDrawerItem(target, level = 1)
+ }
+ NavTargetLocation.PROFILE_LIST -> {
+ drawerProfiles += ProfileSettingDrawerItem().also {
+ it.identifier = target.id.toLong()
+ it.nameRes = target.nameRes
+ it.descriptionRes = target.descriptionRes ?: -1
+ it.icon = target.icon?.toImageHolder()
+ }
+ }
+ else -> continue
}
}
+ drawerItems += ExpandableDrawerItem().also {
+ it.identifier = -1L
+ it.nameRes = R.string.menu_more
+ it.icon = CommunityMaterial.Icon.cmd_dots_horizontal.toImageHolder()
+ it.subItems = drawerItemsMore.toMutableList()
+ it.isSelectedBackgroundAnimated = false
+ it.isSelectable = false
+ }
+ drawerItems += DividerDrawerItem()
+ drawerItems += drawerItemsBottom
+
// seems that this cannot be open, because the itemAdapter has Profile items
// instead of normal Drawer items...
drawer.profileSelectionClose()
-
drawer.setItems(*drawerItems.toTypedArray())
drawer.removeAllProfileSettings()
drawer.addProfileSettings(*drawerProfiles.toTypedArray())
}
- private val targetPopToHomeList = arrayListOf()
- private var targetHomeId: Int = -1
override fun onBackPressed() {
- if (!b.navView.onBackPressed()) {
- if (App.config.ui.openDrawerOnBackPressed && ((navTarget.popTo == null && navTarget.popToHome)
- || navTarget.id == DRAWER_ITEM_HOME)) {
- b.navView.drawer.toggle()
- } else {
+ if (App.config.ui.openDrawerOnBackPressed) {
+ if (drawer.isOpen)
+ navigateUp()
+ else if (!navView.onBackPressed())
+ drawer.open()
+ } else {
+ if (!navView.onBackPressed())
navigateUp()
- }
}
}
fun error(error: ApiError) = errorSnackbar.addError(error).show()
- fun snackbar(text: String, actionText: String? = null, onClick: (() -> Unit)? = null) = mainSnackbar.snackbar(text, actionText, onClick)
+ fun snackbar(
+ text: String,
+ actionText: String? = null,
+ onClick: (() -> Unit)? = null,
+ ) = mainSnackbar.snackbar(text, actionText, onClick)
+
fun snackbarDismiss() = mainSnackbar.dismiss()
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt
index a39a5872..ff165a46 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivityRequestHandler.kt
@@ -11,7 +11,7 @@ import android.provider.OpenableColumns
import com.canhub.cropper.CropImage
import com.canhub.cropper.CropImageView
import pl.szczodrzynski.edziennik.data.db.entity.Profile
-import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
+import pl.szczodrzynski.edziennik.ui.login.LoginActivity
import java.io.File
import java.io.FileOutputStream
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/AbstractConfig.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/AbstractConfig.kt
deleted file mode 100644
index d597a119..00000000
--- a/app/src/main/java/pl/szczodrzynski/edziennik/config/AbstractConfig.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright (c) Kuba Szczodrzyński 2019-11-27.
- */
-
-package pl.szczodrzynski.edziennik.config
-
-interface AbstractConfig {
- fun set(key: String, value: String?)
-}
\ No newline at end of file
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/AppData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/AppData.kt
new file mode 100644
index 00000000..a0fa7c27
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/AppData.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2022-10-21.
+ */
+
+package pl.szczodrzynski.edziennik.config
+
+import com.google.gson.Gson
+import com.google.gson.JsonObject
+import com.google.gson.JsonParser
+import com.google.gson.stream.JsonReader
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.R
+import pl.szczodrzynski.edziennik.data.db.enums.LoginType
+import pl.szczodrzynski.edziennik.ext.getJsonObject
+import pl.szczodrzynski.edziennik.ext.mergeWith
+import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager.HtmlMode
+
+data class AppData(
+ val configOverrides: Map,
+ val messagesConfig: MessagesConfig,
+ val uiConfig: UIConfig,
+ val eventTypes: List,
+) {
+ companion object {
+ private var data: JsonObject? = null
+ private val appData = mutableMapOf()
+
+ fun read(app: App) {
+ val res = app.resources.openRawResource(R.raw.app_data)
+ data = JsonParser.parseReader(JsonReader(res.reader())).asJsonObject
+ }
+
+ fun get(loginType: LoginType): AppData {
+ if (loginType in appData)
+ return appData.getValue(loginType)
+ val json = data?.getJsonObject("base")?.deepCopy()
+ ?: throw NoSuchElementException("Base data not found")
+ val overrides = setOf(loginType, loginType.schoolType)
+ for (overrideType in overrides) {
+ val override = data?.getJsonObject(overrideType.name.lowercase()) ?: continue
+ json.mergeWith(override)
+ }
+ val value = Gson().fromJson(json, AppData::class.java)
+ appData[loginType] = value
+ return value
+ }
+ }
+
+ data class MessagesConfig(
+ val subjectLength: Int?,
+ val bodyLength: Int?,
+ val textStyling: Boolean,
+ val syncRecipientList: Boolean,
+ val htmlMode: HtmlMode,
+ val needsReadStatus: Boolean,
+ )
+
+ data class UIConfig(
+ val lessonHeight: Int,
+ val enableMarkAsReadAnnouncements: Boolean,
+ val enableNoticePoints: Boolean,
+ val eventManualShowSubjectDropdown: Boolean,
+ )
+
+ data class EventType(
+ val id: Long,
+ val color: String,
+ val name: String,
+ )
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/BaseConfig.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/BaseConfig.kt
new file mode 100644
index 00000000..76d95b0b
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/BaseConfig.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2019-11-27.
+ */
+
+package pl.szczodrzynski.edziennik.config
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import pl.szczodrzynski.edziennik.config.db.ConfigEntry
+import pl.szczodrzynski.edziennik.data.db.AppDb
+import pl.szczodrzynski.edziennik.ext.takePositive
+import kotlin.coroutines.CoroutineContext
+
+abstract class BaseConfig(
+ @Transient
+ val db: AppDb,
+ val profileId: Int? = null,
+ protected var entries: List? = null,
+) : CoroutineScope {
+
+ private val job = Job()
+ override val coroutineContext: CoroutineContext
+ get() = job + Dispatchers.Default
+
+ val values = hashMapOf()
+
+ init {
+ if (entries == null)
+ entries = db.configDao().getAllNow()
+ values.clear()
+ for ((profileId, key, value) in entries!!) {
+ if (profileId.takePositive() != this.profileId)
+ continue
+ values[key] = value
+ }
+ }
+
+ fun set(key: String, value: String?) {
+ values[key] = value
+ launch(Dispatchers.IO) {
+ db.configDao().add(ConfigEntry(profileId ?: -1, key, value))
+ }
+ }
+
+ fun has(key: String) = values.containsKey(key)
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/Config.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/Config.kt
index 160deb23..2042e8b2 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/config/Config.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/Config.kt
@@ -5,144 +5,59 @@
package pl.szczodrzynski.edziennik.config
import com.google.gson.JsonObject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.launch
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.BuildConfig
-import pl.szczodrzynski.edziennik.config.db.ConfigEntry
-import pl.szczodrzynski.edziennik.config.utils.ConfigMigration
-import pl.szczodrzynski.edziennik.config.utils.get
-import pl.szczodrzynski.edziennik.config.utils.set
-import pl.szczodrzynski.edziennik.config.utils.toHashMap
+import pl.szczodrzynski.edziennik.config.utils.*
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
import pl.szczodrzynski.edziennik.data.db.AppDb
-import kotlin.coroutines.CoroutineContext
-class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
+@Suppress("RemoveExplicitTypeArguments")
+class Config(db: AppDb) : BaseConfig(db) {
companion object {
const val DATA_VERSION = 12
}
- private val job = Job()
- override val coroutineContext: CoroutineContext
- get() = job + Dispatchers.Default
-
- val values: HashMap = hashMapOf()
+ private val profileConfigs: HashMap = hashMapOf()
val ui by lazy { ConfigUI(this) }
val sync by lazy { ConfigSync(this) }
val timetable by lazy { ConfigTimetable(this) }
val grades by lazy { ConfigGrades(this) }
- private var mDataVersion: Int? = null
- var dataVersion: Int
- get() { mDataVersion = mDataVersion ?: values.get("dataVersion", 0); return mDataVersion ?: 0 }
- set(value) { set("dataVersion", value); mDataVersion = value }
+ var dataVersion by config(DATA_VERSION)
+ var hash by config("")
- private var mHash: String? = null
- var hash: String
- get() { mHash = mHash ?: values.get("hash", ""); return mHash ?: "" }
- set(value) { set("hash", value); mHash = value }
+ var lastProfileId by config(0)
+ var loginFinished by config(false)
+ var privacyPolicyAccepted by config(false)
+ var update by config(null)
+ var updatesChannel by config("release")
- private var mLastProfileId: Int? = null
- var lastProfileId: Int
- get() { mLastProfileId = mLastProfileId ?: values.get("lastProfileId", 0); return mLastProfileId ?: 0 }
- set(value) { set("lastProfileId", value); mLastProfileId = value }
+ var devMode by config("debugMode", null)
+ var devModePassword by config(null)
+ var enableChucker by config(null)
- private var mUpdatesChannel: String? = null
- var updatesChannel: String
- get() { mUpdatesChannel = mUpdatesChannel ?: values.get("updatesChannel", "release"); return mUpdatesChannel ?: "release" }
- set(value) { set("updatesChannel", value); mUpdatesChannel = value }
- private var mUpdate: Update? = null
- var update: Update?
- get() { mUpdate = mUpdate ?: values.get("update", null as Update?); return mUpdate ?: null as Update? }
- set(value) { set("update", value); mUpdate = value }
+ var apiAvailabilityCheck by config(true)
+ var apiInvalidCert by config(null)
+ var apiKeyCustom by config(null)
+ var appInstalledTime by config(0L)
+ var appRateSnackbarTime by config(0L)
+ var appVersion by config(BuildConfig.VERSION_CODE)
+ var validation by config(null, "buildValidation")
- private var mAppVersion: Int? = null
- var appVersion: Int
- get() { mAppVersion = mAppVersion ?: values.get("appVersion", BuildConfig.VERSION_CODE); return mAppVersion ?: BuildConfig.VERSION_CODE }
- set(value) { set("appVersion", value); mAppVersion = value }
+ var archiverEnabled by config(true)
+ var runSync by config(false)
+ var widgetConfigs by config { JsonObject() }
- private var mLoginFinished: Boolean? = null
- var loginFinished: Boolean
- get() { mLoginFinished = mLoginFinished ?: values.get("loginFinished", false); return mLoginFinished ?: false }
- set(value) { set("loginFinished", value); mLoginFinished = value }
-
- private var mPrivacyPolicyAccepted: Boolean? = null
- var privacyPolicyAccepted: Boolean
- get() { mPrivacyPolicyAccepted = mPrivacyPolicyAccepted ?: values.get("privacyPolicyAccepted", false); return mPrivacyPolicyAccepted ?: false }
- set(value) { set("privacyPolicyAccepted", value); mPrivacyPolicyAccepted = value }
-
- private var mDebugMode: Boolean? = null
- var debugMode: Boolean
- get() { mDebugMode = mDebugMode ?: values.get("debugMode", false); return mDebugMode ?: false }
- set(value) { set("debugMode", value); mDebugMode = value }
-
- private var mDevModePassword: String? = null
- var devModePassword: String?
- get() { mDevModePassword = mDevModePassword ?: values.get("devModePassword", null as String?); return mDevModePassword }
- set(value) { set("devModePassword", value); mDevModePassword = value }
-
- private var mAppInstalledTime: Long? = null
- var appInstalledTime: Long
- get() { mAppInstalledTime = mAppInstalledTime ?: values.get("appInstalledTime", 0L); return mAppInstalledTime ?: 0L }
- set(value) { set("appInstalledTime", value); mAppInstalledTime = value }
-
- private var mAppRateSnackbarTime: Long? = null
- var appRateSnackbarTime: Long
- get() { mAppRateSnackbarTime = mAppRateSnackbarTime ?: values.get("appRateSnackbarTime", 0L); return mAppRateSnackbarTime ?: 0L }
- set(value) { set("appRateSnackbarTime", value); mAppRateSnackbarTime = value }
-
- private var mRunSync: Boolean? = null
- var runSync: Boolean
- get() { mRunSync = mRunSync ?: values.get("runSync", false); return mRunSync ?: false }
- set(value) { set("runSync", value); mRunSync = value }
-
- private var mWidgetConfigs: JsonObject? = null
- var widgetConfigs: JsonObject
- get() { mWidgetConfigs = mWidgetConfigs ?: values.get("widgetConfigs", JsonObject()); return mWidgetConfigs ?: JsonObject() }
- set(value) { set("widgetConfigs", value); mWidgetConfigs = value }
-
- private var mArchiverEnabled: Boolean? = null
- var archiverEnabled: Boolean
- get() { mArchiverEnabled = mArchiverEnabled ?: values.get("archiverEnabled", true); return mArchiverEnabled ?: true }
- set(value) { set("archiverEnabled", value); mArchiverEnabled = value }
-
- private var mValidation: String? = null
- var validation: String?
- get() { mValidation = mValidation ?: values["buildValidation"]; return mValidation }
- set(value) { set("buildValidation", value); mValidation = value }
-
- private var mApiInvalidCert: String? = null
- var apiInvalidCert: String?
- get() { mApiInvalidCert = mApiInvalidCert ?: values["apiInvalidCert"]; return mApiInvalidCert }
- set(value) { set("apiInvalidCert", value); mApiInvalidCert = value }
-
- private var rawEntries: List = db.configDao().getAllNow()
- private val profileConfigs: HashMap = hashMapOf()
- init {
- rawEntries.toHashMap(-1, values)
- }
fun migrate(app: App) {
- if (dataVersion < DATA_VERSION)
+ if (dataVersion < DATA_VERSION || hash == "")
+ // migrate old data version OR freshly installed app (or updated from 3.x)
ConfigMigration(app, this)
}
- fun getFor(profileId: Int): ProfileConfig {
- return profileConfigs[profileId] ?: ProfileConfig(db, profileId, db.configDao().getAllNow(profileId)).also {
+
+ operator fun get(profileId: Int): ProfileConfig {
+ return profileConfigs[profileId] ?: ProfileConfig(db, profileId, entries).also {
profileConfigs[profileId] = it
}
}
- fun forProfile() = getFor(App.profileId)
-
- fun setProfile(profileId: Int) {
- }
-
- override fun set(key: String, value: String?) {
- values[key] = value
- launch {
- db.configDao().add(ConfigEntry(-1, key, value))
- }
- }
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigGrades.kt
index 267ec322..a28dcc3d 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigGrades.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigGrades.kt
@@ -4,13 +4,10 @@
package pl.szczodrzynski.edziennik.config
-import pl.szczodrzynski.edziennik.config.utils.get
-import pl.szczodrzynski.edziennik.config.utils.set
-import pl.szczodrzynski.edziennik.utils.managers.GradesManager
+import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.ORDER_BY_DATE_DESC
-class ConfigGrades(private val config: Config) {
- private var mOrderBy: Int? = null
- var orderBy: Int
- get() { mOrderBy = mOrderBy ?: config.values.get("gradesOrderBy", 0); return mOrderBy ?: GradesManager.ORDER_BY_DATE_DESC }
- set(value) { config.set("gradesOrderBy", value); mOrderBy = value }
+@Suppress("RemoveExplicitTypeArguments")
+class ConfigGrades(base: Config) {
+
+ var orderBy by base.config("gradesOrderBy", ORDER_BY_DATE_DESC)
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigSync.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigSync.kt
index 068400a1..6688838b 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigSync.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigSync.kt
@@ -4,125 +4,53 @@
package pl.szczodrzynski.edziennik.config
-import com.google.gson.Gson
-import com.google.gson.reflect.TypeToken
-import pl.szczodrzynski.edziennik.config.utils.get
-import pl.szczodrzynski.edziennik.config.utils.getIntList
-import pl.szczodrzynski.edziennik.config.utils.set
-import pl.szczodrzynski.edziennik.config.utils.setMap
+import pl.szczodrzynski.edziennik.BuildConfig
import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus
+import pl.szczodrzynski.edziennik.ext.HOUR
import pl.szczodrzynski.edziennik.utils.models.Time
-class ConfigSync(private val config: Config) {
- private val gson = Gson()
+@Suppress("RemoveExplicitTypeArguments")
+class ConfigSync(base: Config) {
- private var mDontShowAppManagerDialog: Boolean? = null
- var dontShowAppManagerDialog: Boolean
- get() { mDontShowAppManagerDialog = mDontShowAppManagerDialog ?: config.values.get("dontShowAppManagerDialog", false); return mDontShowAppManagerDialog ?: false }
- set(value) { config.set("dontShowAppManagerDialog", value); mDontShowAppManagerDialog = value }
+ var enabled by base.config("syncEnabled", true)
+ var interval by base.config("syncInterval", 1 * HOUR.toInt())
+ var onlyWifi by base.config("syncOnlyWifi", false)
- private var mSyncEnabled: Boolean? = null
- var enabled: Boolean
- get() { mSyncEnabled = mSyncEnabled ?: config.values.get("syncEnabled", true); return mSyncEnabled ?: true }
- set(value) { config.set("syncEnabled", value); mSyncEnabled = value }
+ var dontShowAppManagerDialog by base.config(false)
+ var lastAppSync by base.config(0L)
+ var notifyAboutUpdates by base.config(true)
+ var webPushEnabled by base.config(true)
- private var mWebPushEnabled: Boolean? = null
- var webPushEnabled: Boolean
- get() { mWebPushEnabled = mWebPushEnabled ?: config.values.get("webPushEnabled", true); return mWebPushEnabled ?: true }
- set(value) { config.set("webPushEnabled", value); mWebPushEnabled = value }
+ // Quiet Hours
+ var quietHoursEnabled by base.config(false)
+ var quietHoursStart by base.config