forked from github/szkolny
Compare commits
No commits in common. "develop" and "feature/elearning-events" have entirely different histories.
develop
...
feature/el
4
.github/utils/extract_changelogs.py
vendored
4
.github/utils/extract_changelogs.py
vendored
@ -23,11 +23,11 @@ if __name__ == "__main__":
|
||||
(title, changelog) = get_changelog(project_dir, format="plain")
|
||||
|
||||
# plain text changelog - Firebase App Distribution
|
||||
with open(dir + "whatsnew_titled.txt", "w", encoding="utf-8") as f:
|
||||
with open(dir + "whatsnew-titled.txt", "w", encoding="utf-8") as f:
|
||||
f.write(title)
|
||||
f.write("\n")
|
||||
f.write(changelog)
|
||||
print("::set-output name=changelogPlainTitledFile::" + dir + "whatsnew_titled.txt")
|
||||
print("::set-output name=changelogPlainTitledFile::" + dir + "whatsnew-titled.txt")
|
||||
|
||||
print("::set-output name=changelogTitle::" + title)
|
||||
|
||||
|
11
.github/workflows/build-nightly-apk.yml
vendored
11
.github/workflows/build-nightly-apk.yml
vendored
@ -51,11 +51,10 @@ jobs:
|
||||
androidHome: ${{ env.ANDROID_HOME }}
|
||||
androidSdkRoot: ${{ env.ANDROID_SDK_ROOT }}
|
||||
steps:
|
||||
- name: Setup JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
- name: Setup JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '11'
|
||||
java-version: 1.8
|
||||
- name: Setup Android SDK
|
||||
uses: android-actions/setup-android@v2
|
||||
- name: Clean build artifacts
|
||||
@ -64,9 +63,7 @@ jobs:
|
||||
rm -rf app/build/outputs/apk/*
|
||||
rm -rf app/build/outputs/bundle/*
|
||||
- name: Assemble official release with Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
arguments: assembleOfficialRelease
|
||||
run: ./gradlew assembleOfficialRelease
|
||||
sign:
|
||||
name: Sign APK
|
||||
runs-on: self-hosted
|
||||
|
14
.github/workflows/build-release-aab-play.yml
vendored
14
.github/workflows/build-release-aab-play.yml
vendored
@ -43,11 +43,10 @@ jobs:
|
||||
androidHome: ${{ env.ANDROID_HOME }}
|
||||
androidSdkRoot: ${{ env.ANDROID_SDK_ROOT }}
|
||||
steps:
|
||||
- name: Setup JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
- name: Setup JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '11'
|
||||
java-version: 1.8
|
||||
- name: Setup Android SDK
|
||||
uses: android-actions/setup-android@v2
|
||||
- name: Clean build artifacts
|
||||
@ -56,9 +55,7 @@ jobs:
|
||||
rm -rf app/build/outputs/apk/*
|
||||
rm -rf app/build/outputs/bundle/*
|
||||
- name: Bundle play release with Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
arguments: bundlePlayRelease
|
||||
run: ./gradlew bundlePlayRelease
|
||||
sign:
|
||||
name: Sign App Bundle
|
||||
runs-on: self-hosted
|
||||
@ -113,11 +110,10 @@ jobs:
|
||||
with:
|
||||
serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }}
|
||||
packageName: pl.szczodrzynski.edziennik
|
||||
releaseFiles: ${{ needs.sign.outputs.signedReleaseFile }}
|
||||
releaseFile: ${{ needs.sign.outputs.signedReleaseFile }}
|
||||
releaseName: ${{ steps.changelog.outputs.appVersionName }}
|
||||
track: ${{ secrets.PLAY_RELEASE_TRACK }}
|
||||
whatsNewDirectory: ${{ steps.changelog.outputs.changelogDir }}
|
||||
status: completed
|
||||
|
||||
- name: Upload workflow artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
|
11
.github/workflows/build-release-apk.yml
vendored
11
.github/workflows/build-release-apk.yml
vendored
@ -43,11 +43,10 @@ jobs:
|
||||
androidHome: ${{ env.ANDROID_HOME }}
|
||||
androidSdkRoot: ${{ env.ANDROID_SDK_ROOT }}
|
||||
steps:
|
||||
- name: Setup JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
- name: Setup JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '11'
|
||||
java-version: 1.8
|
||||
- name: Setup Android SDK
|
||||
uses: android-actions/setup-android@v2
|
||||
- name: Clean build artifacts
|
||||
@ -56,9 +55,7 @@ jobs:
|
||||
rm -rf app/build/outputs/apk/*
|
||||
rm -rf app/build/outputs/bundle/*
|
||||
- name: Assemble official release with Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
arguments: assembleOfficialRelease
|
||||
run: ./gradlew assembleOfficialRelease
|
||||
sign:
|
||||
name: Sign APK
|
||||
runs-on: self-hosted
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -265,4 +265,3 @@ fabric.properties
|
||||
# End of https://www.toptal.com/developers/gitignore/api/android,androidstudio,gradle,java,kotlin
|
||||
|
||||
signatures/
|
||||
.idea/*.xml
|
||||
|
9
.idea/codeStyles/Project.xml
generated
9
.idea/codeStyles/Project.xml
generated
@ -1,17 +1,8 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<JetCodeStyleSettings>
|
||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
|
||||
<option name="ALLOW_TRAILING_COMMA" value="true" />
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="JSON">
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="4" />
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
<option name="SMART_TABS" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<option name="FORCE_REARRANGE_MODE" value="1" />
|
||||
<indentOptions>
|
||||
|
6
.idea/copyright/Antoni.xml
generated
6
.idea/copyright/Antoni.xml
generated
@ -1,6 +0,0 @@
|
||||
<component name="CopyrightManager">
|
||||
<copyright>
|
||||
<option name="notice" value="Copyright (c) Antoni Czaplicki &#36;{today.year}-&#36;{today.month}-&#36;{today.day}. " />
|
||||
<option name="myName" value="Antoni" />
|
||||
</copyright>
|
||||
</component>
|
2
.idea/dictionaries/Kuba.xml
generated
2
.idea/dictionaries/Kuba.xml
generated
@ -5,7 +5,6 @@
|
||||
<w>ciasteczko</w>
|
||||
<w>csrf</w>
|
||||
<w>edziennik</w>
|
||||
<w>eggfall</w>
|
||||
<w>elearning</w>
|
||||
<w>gson</w>
|
||||
<w>hebe</w>
|
||||
@ -14,7 +13,6 @@
|
||||
<w>synergia</w>
|
||||
<w>szczodrzyński</w>
|
||||
<w>szkolny</w>
|
||||
<w>usos</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
9
.idea/discord.xml
generated
Normal file
9
.idea/discord.xml
generated
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DiscordProjectSettings">
|
||||
<option name="show" value="PROJECT_FILES" />
|
||||
</component>
|
||||
<component name="ProjectNotificationSettings">
|
||||
<option name="askShowProject" value="false" />
|
||||
</component>
|
||||
</project>
|
6
.idea/kotlinc.xml
generated
Normal file
6
.idea/kotlinc.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Kotlin2JvmCompilerArguments">
|
||||
<option name="jvmTarget" value="1.8" />
|
||||
</component>
|
||||
</project>
|
13
.idea/runConfigurations.xml
generated
Normal file
13
.idea/runConfigurations.xml
generated
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
111
app/build.gradle
111
app/build.gradle
@ -1,7 +1,6 @@
|
||||
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'
|
||||
|
||||
@ -31,21 +30,11 @@ 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
|
||||
@ -56,34 +45,23 @@ android {
|
||||
}
|
||||
flavorDimensions "platform"
|
||||
productFlavors {
|
||||
unofficial {
|
||||
getIsDefault().set(true)
|
||||
versionName "${release.versionName}-${gitInfo.versionSuffix}"
|
||||
main {
|
||||
versionName gitInfo.versionHuman
|
||||
}
|
||||
official {}
|
||||
play {}
|
||||
}
|
||||
variantFilter { variant ->
|
||||
def flavors = variant.flavors*.name
|
||||
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"]
|
||||
}
|
||||
setIgnore(variant.buildType.name == "debug" && !flavors.contains("main"))
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
}
|
||||
lintOptions {
|
||||
checkReleaseBuilds = false
|
||||
}
|
||||
buildFeatures {
|
||||
dataBinding = true
|
||||
viewBinding = true
|
||||
@ -97,9 +75,7 @@ android {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
packagingOptions {
|
||||
resources {
|
||||
excludes += ['META-INF/library-core_release.kotlin_module']
|
||||
}
|
||||
exclude 'META-INF/library-core_release.kotlin_module'
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
@ -107,9 +83,6 @@ android {
|
||||
version "3.10.2"
|
||||
}
|
||||
}
|
||||
lint {
|
||||
checkReleaseBuilds false
|
||||
}
|
||||
}
|
||||
|
||||
tasks.whenTaskAdded { task ->
|
||||
@ -144,30 +117,28 @@ 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.5.1"
|
||||
implementation "androidx.appcompat:appcompat:1.2.0"
|
||||
implementation "androidx.cardview:cardview:1.0.0"
|
||||
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"
|
||||
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"
|
||||
|
||||
// Google design libs
|
||||
implementation "com.google.android.material:material:1.6.1"
|
||||
implementation "com.google.android.flexbox:flexbox:3.0.0"
|
||||
implementation "com.google.android.material:material:1.3.0"
|
||||
implementation "com.google.android:flexbox:2.0.1"
|
||||
|
||||
// Play Services/Firebase
|
||||
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.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.firebase:firebase-messaging") { version { strictly "20.1.3" } }
|
||||
|
||||
// OkHttp, Retrofit, Gson, Jsoup
|
||||
@ -175,22 +146,21 @@ 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.8'
|
||||
implementation 'org.jsoup:jsoup:1.14.3'
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
implementation "org.jsoup:jsoup:1.13.1"
|
||||
implementation "pl.droidsonroids:jspoon:1.3.2"
|
||||
implementation "pl.droidsonroids.retrofit2:converter-jspoon:1.3.2"
|
||||
|
||||
// Szkolny.eu libraries/forks
|
||||
implementation "eu.szkolny:android-snowfall:1ca9ea2da3"
|
||||
implementation "eu.szkolny:agendacalendarview:1.0.4"
|
||||
implementation "eu.szkolny:agendacalendarview:5431f03098"
|
||||
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"
|
||||
officialImplementation "eu.szkolny:ssl-provider:1.0.0"
|
||||
unofficialImplementation "eu.szkolny:ssl-provider:1.0.0"
|
||||
implementation "eu.szkolny:ssl-provider:1.0.0"
|
||||
implementation "pl.szczodrzynski:navlib:0.8.0"
|
||||
implementation "pl.szczodrzynski:numberslidingpicker:2921225f76"
|
||||
implementation "pl.szczodrzynski:recyclertablayout:700f980584"
|
||||
@ -198,34 +168,33 @@ dependencies {
|
||||
kapt "eu.szkolny.selective-dao:codegen:27f8f3f194"
|
||||
|
||||
// Iconics & related
|
||||
implementation "com.mikepenz:iconics-core:5.3.2"
|
||||
implementation "com.mikepenz:iconics-views:5.3.2"
|
||||
implementation "com.mikepenz:iconics-core:5.3.0-b01"
|
||||
implementation "com.mikepenz:iconics-views:5.3.0-b01"
|
||||
implementation "com.mikepenz:community-material-typeface:5.8.55.0-kotlin@aar"
|
||||
implementation "eu.szkolny:szkolny-font:77e33acc2a"
|
||||
implementation "eu.szkolny:szkolny-font:1.3"
|
||||
|
||||
// Other dependencies
|
||||
implementation "cat.ereza:customactivityoncrash:2.3.0"
|
||||
implementation "com.android.volley:volley:1.2.1"
|
||||
implementation "com.applandeo:material-calendar-view:1.5.0"
|
||||
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
|
||||
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.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.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.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.github.amitshekhariitbhu.Android-Debug-Database:debug-db:v1.0.6"
|
||||
debugImplementation "com.amitshekhar.android:debug-db:1.0.5"
|
||||
}
|
||||
|
@ -97,17 +97,18 @@ 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" : ""),
|
||||
versionSuffix : """${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" : ""),
|
||||
versionHuman: """$versionName-${repo.branch.replace("/", "_")}""" + (dirty ? ".dirty" : "")
|
||||
]
|
||||
return result
|
||||
}
|
||||
|
9
app/proguard-rules.pro
vendored
9
app/proguard-rules.pro
vendored
@ -22,19 +22,14 @@
|
||||
-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.data.db.entity.Note { *; }
|
||||
-keep class pl.szczodrzynski.edziennik.ui.home.HomeCardModel { *; }
|
||||
-keep class pl.szczodrzynski.edziennik.ui.modules.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); }
|
||||
-keepnames class androidx.appcompat.view.menu.MenuPopupHelper { showPopup(int, int, boolean, boolean); }
|
||||
@ -72,7 +67,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.login.LoginInfo$Platform { *; }
|
||||
-keepclassmembernames class pl.szczodrzynski.edziennik.ui.modules.login.LoginInfo$Platform { *; }
|
||||
|
||||
-keepclassmembernames class pl.szczodrzynski.fslogin.realm.RealmData { *; }
|
||||
-keepclassmembernames class pl.szczodrzynski.fslogin.realm.RealmData$Type { *; }
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="pl.szczodrzynski.edziennik">
|
||||
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
@ -12,7 +13,7 @@
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
|
||||
<!-- PowerPermission uses minSdk 21, it's safe to override as it is used only in >= 23 -->
|
||||
<uses-sdk tools:overrideLibrary="com.qifan.powerpermission.coroutines, com.qifan.powerpermission.core" />
|
||||
|
||||
@ -42,7 +43,6 @@
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop"
|
||||
android:exported="true"
|
||||
android:theme="@style/SplashTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
@ -66,7 +66,6 @@
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:excludeFromRecents="true"
|
||||
android:noHistory="true"
|
||||
android:exported="true"
|
||||
android:theme="@style/AppTheme.Dark.NoDisplay">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||
@ -74,8 +73,7 @@
|
||||
</activity>
|
||||
<!-- TIMETABLE -->
|
||||
<receiver android:name=".ui.widgets.timetable.WidgetTimetableProvider"
|
||||
android:label="@string/widget_timetable_title"
|
||||
android:exported="true">
|
||||
android:label="@string/widget_timetable_title">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
@ -90,12 +88,10 @@
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:excludeFromRecents="true"
|
||||
android:noHistory="true"
|
||||
android:exported="true"
|
||||
android:theme="@style/AppTheme.Dark.NoDisplay" />
|
||||
<!-- NOTIFICATIONS -->
|
||||
<receiver android:name=".ui.widgets.notifications.WidgetNotificationsProvider"
|
||||
android:label="@string/widget_notifications_title"
|
||||
android:exported="true">
|
||||
android:label="@string/widget_notifications_title">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
@ -108,8 +104,7 @@
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||
<!-- LUCKY NUMBER -->
|
||||
<receiver android:name=".ui.widgets.luckynumber.WidgetLuckyNumberProvider"
|
||||
android:label="@string/widget_lucky_number_title"
|
||||
android:exported="true">
|
||||
android:label="@string/widget_lucky_number_title">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
@ -126,47 +121,31 @@
|
||||
/ ____ \ (__| |_| |\ V /| | |_| | __/\__ \
|
||||
/_/ \_\___|\__|_| \_/ |_|\__|_|\___||___/
|
||||
-->
|
||||
<activity android:name=".ui.base.CrashActivity"
|
||||
<activity android:name=".ui.modules.base.CrashActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||
android:process=":error_activity"
|
||||
android:exported="false"
|
||||
android:theme="@style/DeadTheme" />
|
||||
<activity android:name=".ui.intro.ChangelogIntroActivity"
|
||||
<activity android:name=".ui.modules.intro.ChangelogIntroActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:label="@string/app_name"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.Intro" />
|
||||
<activity android:name=".ui.login.LoginActivity"
|
||||
<activity android:name=".ui.modules.login.LoginActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:launchMode="singleTop"
|
||||
android:exported="false"
|
||||
android:theme="@style/AppTheme.Light" />
|
||||
<activity android:name=".ui.home.CounterActivity"
|
||||
android:exported="false"
|
||||
<activity android:name=".ui.modules.home.CounterActivity"
|
||||
android:theme="@style/AppTheme.Black" />
|
||||
<activity android:name=".ui.feedback.FeedbackActivity"
|
||||
<activity android:name=".ui.modules.feedback.FeedbackActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||
android:label="@string/app_name"
|
||||
android:exported="false"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity android:name=".ui.settings.SettingsLicenseActivity"
|
||||
<activity android:name=".ui.modules.settings.SettingsLicenseActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:exported="false"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity android:name="com.canhub.cropper.CropImageActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:exported="false"
|
||||
android:theme="@style/Base.Theme.AppCompat" />
|
||||
<activity android:name=".ui.login.oauth.OAuthLoginActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.MaterialComponents.Light.DarkActionBar" />
|
||||
<activity android:name=".ui.login.recaptcha.RecaptchaActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.MaterialComponents.Light.DarkActionBar" />
|
||||
<activity android:name=".ui.base.BuildInvalidActivity" android:exported="false" />
|
||||
<activity android:name=".ui.settings.contributors.ContributorsActivity" android:exported="false" />
|
||||
<activity android:name=".ui.modules.base.BuildInvalidActivity" />
|
||||
|
||||
<!-- _____ _
|
||||
| __ \ (_)
|
||||
@ -176,14 +155,12 @@
|
||||
|_| \_\___|\___\___|_| \_/ \___|_| |___/
|
||||
-->
|
||||
<receiver android:name=".receivers.UserPresentReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
android:enabled="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.USER_PRESENT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:name=".sync.UpdateDownloaderService$DownloadProgressReceiver"
|
||||
android:exported="true">
|
||||
<receiver android:name=".sync.UpdateDownloaderService$DownloadProgressReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
||||
</intent-filter>
|
||||
|
@ -1,10 +1,9 @@
|
||||
<h3>Wersja 4.13.6, 2023-03-24</h3>
|
||||
<h3>Wersja 4.7.1, 2021-04-12</h3>
|
||||
<ul>
|
||||
<li>Naprawiono pobieranie załączników na Androidzie 13 i nowszym.</li>
|
||||
<li>Dodano opcję odświeżenia planu lekcji na wybrany tydzień.</li>
|
||||
<li>Usunięto błędy logowania. @BxOxSxS</li>
|
||||
<li>Poprawiono sprawdzanie dostępności e-dziennika.</li>
|
||||
<li>Zmieniono datę w informacjach o aplikacji. @Luncenok</li>
|
||||
</ul>
|
||||
<br>
|
||||
<br>
|
||||
Dzięki za korzystanie ze Szkolnego!<br>
|
||||
<i>© [Kuba Szczodrzyński](@kuba2k2) 2023</i>
|
||||
<i>© [Kuba Szczodrzyński](@kuba2k2), [Kacper Ziubryniewicz](@kapi2289) 2021</i>
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
/*secret password - removed for source code publication*/
|
||||
static toys AES_IV[16] = {
|
||||
0x6d, 0xa5, 0x32, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
0xcc, 0x64, 0xdb, 0x3a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);
|
||||
|
||||
|
@ -12,7 +12,6 @@ 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
|
||||
@ -27,88 +26,50 @@ 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.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.*
|
||||
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.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.ui.modules.base.CrashActivity
|
||||
import pl.szczodrzynski.edziennik.utils.*
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
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 pl.szczodrzynski.edziennik.utils.managers.*
|
||||
import timber.log.Timber
|
||||
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 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 gradesManager by lazy { GradesManager(this) }
|
||||
val timetableManager by lazy { TimetableManager(this) }
|
||||
val eventManager by lazy { EventManager(this) }
|
||||
val permissionManager by lazy { PermissionManager(this) }
|
||||
val attendanceManager by lazy { AttendanceManager(this) }
|
||||
val buildManager by lazy { BuildManager(this) }
|
||||
|
||||
val db
|
||||
get() = App.db
|
||||
@ -118,8 +79,6 @@ 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
|
||||
@ -150,15 +109,15 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
||||
.connectTimeout(15, TimeUnit.SECONDS)
|
||||
.writeTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
|
||||
SSLProviderInstaller.enableSupportedTls(builder, enableCleartext = true)
|
||||
.enableSupportedTls(enableCleartext = true)
|
||||
|
||||
if (devMode) {
|
||||
if (enableChucker) {
|
||||
val chuckerCollector = ChuckerCollector(this, true, RetentionManager.Period.ONE_HOUR)
|
||||
val chuckerInterceptor = ChuckerInterceptor(this, chuckerCollector)
|
||||
builder.addInterceptor(chuckerInterceptor)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
http = builder.build()
|
||||
@ -208,23 +167,14 @@ 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.devMode ?: debugMode
|
||||
enableChucker = config.enableChucker ?: devMode
|
||||
|
||||
if (devMode) {
|
||||
HyperLog.initialize(this)
|
||||
HyperLog.setLogLevel(Log.VERBOSE)
|
||||
HyperLog.setLogFormat(DebugLogFormat(this))
|
||||
}
|
||||
devMode = config.debugMode || debugMode
|
||||
|
||||
if (!profileLoadById(config.lastProfileId)) {
|
||||
val success = db.profileDao().firstId?.let { profileLoadById(it) }
|
||||
if (success != true)
|
||||
profileLoad(Profile(0, 0, LoginType.TEMPLATE, ""))
|
||||
db.profileDao().firstId?.let { profileLoadById(it) }
|
||||
}
|
||||
|
||||
buildHttp()
|
||||
@ -235,13 +185,23 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
||||
}
|
||||
|
||||
Signing.getCert(this)
|
||||
Utils.initializeStorageDir(this)
|
||||
|
||||
launch {
|
||||
withContext(Dispatchers.Default) {
|
||||
config.migrate(this@App)
|
||||
|
||||
SSLProviderInstaller.install(applicationContext, this@App::buildHttp)
|
||||
SSLProvider.install(
|
||||
applicationContext,
|
||||
downloadIfNeeded = true,
|
||||
supportTls13 = false,
|
||||
onFinish = {
|
||||
buildHttp()
|
||||
},
|
||||
onError = {
|
||||
Timber.e("Failed to install SSLProvider: $it")
|
||||
it.printStackTrace()
|
||||
}
|
||||
)
|
||||
|
||||
if (config.devModePassword != null)
|
||||
checkDevModePassword()
|
||||
@ -263,35 +223,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)
|
||||
.putExtras("fragmentId" to NavTarget.TIMETABLE))
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_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)
|
||||
.putExtras("fragmentId" to NavTarget.AGENDA))
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_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)
|
||||
.putExtras("fragmentId" to NavTarget.GRADES))
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_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)
|
||||
.putExtras("fragmentId" to NavTarget.HOMEWORK))
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_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)
|
||||
.putExtras("fragmentId" to NavTarget.MESSAGES))
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_MESSAGES))
|
||||
.build()
|
||||
|
||||
shortcutManager.dynamicShortcuts = listOf(
|
||||
@ -417,28 +377,10 @@ 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 {
|
||||
profileLoad(it)
|
||||
App.profile = it
|
||||
App.config.lastProfileId = it.id
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@ -469,8 +411,6 @@ 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)
|
||||
}
|
||||
|
@ -4,11 +4,8 @@
|
||||
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
|
||||
@ -20,64 +17,4 @@ 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,
|
||||
)
|
||||
}
|
||||
|
1308
app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt
Normal file
1308
app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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.login.LoginActivity
|
||||
import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
interface AbstractConfig {
|
||||
fun set(key: String, value: String?)
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* 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<String, String>,
|
||||
val messagesConfig: MessagesConfig,
|
||||
val uiConfig: UIConfig,
|
||||
val eventTypes: List<EventType>,
|
||||
) {
|
||||
companion object {
|
||||
private var data: JsonObject? = null
|
||||
private val appData = mutableMapOf<LoginType, AppData>()
|
||||
|
||||
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,
|
||||
)
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* 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<ConfigEntry>? = null,
|
||||
) : CoroutineScope {
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Default
|
||||
|
||||
val values = hashMapOf<String, String?>()
|
||||
|
||||
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)
|
||||
}
|
@ -5,59 +5,144 @@
|
||||
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.utils.*
|
||||
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.data.api.szkolny.response.Update
|
||||
import pl.szczodrzynski.edziennik.data.db.AppDb
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class Config(db: AppDb) : BaseConfig(db) {
|
||||
class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
|
||||
companion object {
|
||||
const val DATA_VERSION = 12
|
||||
}
|
||||
|
||||
private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf()
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Default
|
||||
|
||||
val values: HashMap<String, String?> = 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) }
|
||||
|
||||
var dataVersion by config<Int>(DATA_VERSION)
|
||||
var hash by config<String>("")
|
||||
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 lastProfileId by config<Int>(0)
|
||||
var loginFinished by config<Boolean>(false)
|
||||
var privacyPolicyAccepted by config<Boolean>(false)
|
||||
var update by config<Update?>(null)
|
||||
var updatesChannel by config<String>("release")
|
||||
private var mHash: String? = null
|
||||
var hash: String
|
||||
get() { mHash = mHash ?: values.get("hash", ""); return mHash ?: "" }
|
||||
set(value) { set("hash", value); mHash = value }
|
||||
|
||||
var devMode by config<Boolean?>("debugMode", null)
|
||||
var devModePassword by config<String?>(null)
|
||||
var enableChucker by config<Boolean?>(null)
|
||||
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 apiAvailabilityCheck by config<Boolean>(true)
|
||||
var apiInvalidCert by config<String?>(null)
|
||||
var apiKeyCustom by config<String?>(null)
|
||||
var appInstalledTime by config<Long>(0L)
|
||||
var appRateSnackbarTime by config<Long>(0L)
|
||||
var appVersion by config<Int>(BuildConfig.VERSION_CODE)
|
||||
var validation by config<String?>(null, "buildValidation")
|
||||
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 archiverEnabled by config<Boolean>(true)
|
||||
var runSync by config<Boolean>(false)
|
||||
var widgetConfigs by config<JsonObject> { JsonObject() }
|
||||
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 }
|
||||
|
||||
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<ConfigEntry> = db.configDao().getAllNow()
|
||||
private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf()
|
||||
init {
|
||||
rawEntries.toHashMap(-1, values)
|
||||
}
|
||||
fun migrate(app: App) {
|
||||
if (dataVersion < DATA_VERSION || hash == "")
|
||||
// migrate old data version OR freshly installed app (or updated from 3.x)
|
||||
if (dataVersion < DATA_VERSION)
|
||||
ConfigMigration(app, this)
|
||||
}
|
||||
|
||||
operator fun get(profileId: Int): ProfileConfig {
|
||||
return profileConfigs[profileId] ?: ProfileConfig(db, profileId, entries).also {
|
||||
fun getFor(profileId: Int): ProfileConfig {
|
||||
return profileConfigs[profileId] ?: ProfileConfig(db, profileId, db.configDao().getAllNow(profileId)).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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,13 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.ORDER_BY_DATE_DESC
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager
|
||||
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ConfigGrades(base: Config) {
|
||||
|
||||
var orderBy by base.config<Int>("gradesOrderBy", 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 }
|
||||
}
|
||||
|
@ -4,53 +4,139 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import pl.szczodrzynski.edziennik.BuildConfig
|
||||
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.data.api.szkolny.response.RegisterAvailabilityStatus
|
||||
import pl.szczodrzynski.edziennik.ext.HOUR
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ConfigSync(base: Config) {
|
||||
class ConfigSync(private val config: Config) {
|
||||
private val gson = Gson()
|
||||
|
||||
var enabled by base.config<Boolean>("syncEnabled", true)
|
||||
var interval by base.config<Int>("syncInterval", 1 * HOUR.toInt())
|
||||
var onlyWifi by base.config<Boolean>("syncOnlyWifi", false)
|
||||
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 dontShowAppManagerDialog by base.config<Boolean>(false)
|
||||
var lastAppSync by base.config<Long>(0L)
|
||||
var notifyAboutUpdates by base.config<Boolean>(true)
|
||||
var webPushEnabled by base.config<Boolean>(true)
|
||||
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 }
|
||||
|
||||
// Quiet Hours
|
||||
var quietHoursEnabled by base.config<Boolean>(false)
|
||||
var quietHoursStart by base.config<Time?>(null)
|
||||
var quietHoursEnd by base.config<Time?>(null)
|
||||
var quietDuringLessons by base.config<Boolean>(false)
|
||||
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 }
|
||||
|
||||
// FCM Tokens
|
||||
var tokenApp by base.config<String?>(null)
|
||||
var tokenMobidziennik by base.config<String?>(null)
|
||||
var tokenLibrus by base.config<String?>(null)
|
||||
var tokenVulcan by base.config<String?>(null)
|
||||
var tokenVulcanHebe by base.config<String?>(null)
|
||||
private var mSyncOnlyWifi: Boolean? = null
|
||||
var onlyWifi: Boolean
|
||||
get() { mSyncOnlyWifi = mSyncOnlyWifi ?: config.values.get("syncOnlyWifi", false); return mSyncOnlyWifi ?: notifyAboutUpdates }
|
||||
set(value) { config.set("syncOnlyWifi", value); mSyncOnlyWifi = value }
|
||||
|
||||
var tokenMobidziennikList by base.config<List<Int>> { listOf() }
|
||||
var tokenLibrusList by base.config<List<Int>> { listOf() }
|
||||
var tokenVulcanList by base.config<List<Int>> { listOf() }
|
||||
var tokenVulcanHebeList by base.config<List<Int>> { listOf() }
|
||||
private var mSyncInterval: Int? = null
|
||||
var interval: Int
|
||||
get() { mSyncInterval = mSyncInterval ?: config.values.get("syncInterval", 60*60); return mSyncInterval ?: 60*60 }
|
||||
set(value) { config.set("syncInterval", value); mSyncInterval = value }
|
||||
|
||||
// Register Availability
|
||||
private var registerAvailabilityMap by base.config<Map<String, RegisterAvailabilityStatus>>("registerAvailability") { mapOf() }
|
||||
private var registerAvailabilityFlavor by base.config<String?>(null)
|
||||
private var mNotifyAboutUpdates: Boolean? = null
|
||||
var notifyAboutUpdates: Boolean
|
||||
get() { mNotifyAboutUpdates = mNotifyAboutUpdates ?: config.values.get("notifyAboutUpdates", true); return mNotifyAboutUpdates ?: true }
|
||||
set(value) { config.set("notifyAboutUpdates", value); mNotifyAboutUpdates = value }
|
||||
|
||||
private var mLastAppSync: Long? = null
|
||||
var lastAppSync: Long
|
||||
get() { mLastAppSync = mLastAppSync ?: config.values.get("lastAppSync", 0L); return mLastAppSync ?: 0L }
|
||||
set(value) { config.set("lastAppSync", value); mLastAppSync = value }
|
||||
|
||||
/* ____ _ _ _
|
||||
/ __ \ (_) | | | |
|
||||
| | | |_ _ _ ___| |_ | |__ ___ _ _ _ __ ___
|
||||
| | | | | | | |/ _ \ __| | '_ \ / _ \| | | | '__/ __|
|
||||
| |__| | |_| | | __/ |_ | | | | (_) | |_| | | \__ \
|
||||
\___\_\\__,_|_|\___|\__| |_| |_|\___/ \__,_|_| |__*/
|
||||
private var mQuietHoursEnabled: Boolean? = null
|
||||
var quietHoursEnabled: Boolean
|
||||
get() { mQuietHoursEnabled = mQuietHoursEnabled ?: config.values.get("quietHoursEnabled", false); return mQuietHoursEnabled ?: false }
|
||||
set(value) { config.set("quietHoursEnabled", value); mQuietHoursEnabled = value }
|
||||
|
||||
private var mQuietHoursStart: Time? = null
|
||||
var quietHoursStart: Time?
|
||||
get() { mQuietHoursStart = mQuietHoursStart ?: config.values.get("quietHoursStart", null as Time?); return mQuietHoursStart }
|
||||
set(value) { config.set("quietHoursStart", value); mQuietHoursStart = value }
|
||||
|
||||
private var mQuietHoursEnd: Time? = null
|
||||
var quietHoursEnd: Time?
|
||||
get() { mQuietHoursEnd = mQuietHoursEnd ?: config.values.get("quietHoursEnd", null as Time?); return mQuietHoursEnd }
|
||||
set(value) { config.set("quietHoursEnd", value); mQuietHoursEnd = value }
|
||||
|
||||
private var mQuietDuringLessons: Boolean? = null
|
||||
var quietDuringLessons: Boolean
|
||||
get() { mQuietDuringLessons = mQuietDuringLessons ?: config.values.get("quietDuringLessons", false); return mQuietDuringLessons ?: false }
|
||||
set(value) { config.set("quietDuringLessons", value); mQuietDuringLessons = value }
|
||||
|
||||
/* ______ _____ __ __ _______ _
|
||||
| ____/ ____| \/ | |__ __| | |
|
||||
| |__ | | | \ / | | | ___ | | _____ _ __ ___
|
||||
| __|| | | |\/| | | |/ _ \| |/ / _ \ '_ \/ __|
|
||||
| | | |____| | | | | | (_) | < __/ | | \__ \
|
||||
|_| \_____|_| |_| |_|\___/|_|\_\___|_| |_|__*/
|
||||
private var mTokenApp: String? = null
|
||||
var tokenApp: String?
|
||||
get() { mTokenApp = mTokenApp ?: config.values.get("tokenApp", null as String?); return mTokenApp }
|
||||
set(value) { config.set("tokenApp", value); mTokenApp = value }
|
||||
private var mTokenMobidziennik: String? = null
|
||||
var tokenMobidziennik: String?
|
||||
get() { mTokenMobidziennik = mTokenMobidziennik ?: config.values.get("tokenMobidziennik", null as String?); return mTokenMobidziennik }
|
||||
set(value) { config.set("tokenMobidziennik", value); mTokenMobidziennik = value }
|
||||
private var mTokenLibrus: String? = null
|
||||
var tokenLibrus: String?
|
||||
get() { mTokenLibrus = mTokenLibrus ?: config.values.get("tokenLibrus", null as String?); return mTokenLibrus }
|
||||
set(value) { config.set("tokenLibrus", value); mTokenLibrus = value }
|
||||
private var mTokenVulcan: String? = null
|
||||
var tokenVulcan: String?
|
||||
get() { mTokenVulcan = mTokenVulcan ?: config.values.get("tokenVulcan", null as String?); return mTokenVulcan }
|
||||
set(value) { config.set("tokenVulcan", value); mTokenVulcan = value }
|
||||
private var mTokenVulcanHebe: String? = null
|
||||
var tokenVulcanHebe: String?
|
||||
get() { mTokenVulcanHebe = mTokenVulcanHebe ?: config.values.get("tokenVulcanHebe", null as String?); return mTokenVulcanHebe }
|
||||
set(value) { config.set("tokenVulcanHebe", value); mTokenVulcanHebe = value }
|
||||
|
||||
private var mTokenMobidziennikList: List<Int>? = null
|
||||
var tokenMobidziennikList: List<Int>
|
||||
get() { mTokenMobidziennikList = mTokenMobidziennikList ?: config.values.getIntList("tokenMobidziennikList", listOf()); return mTokenMobidziennikList ?: listOf() }
|
||||
set(value) { config.set("tokenMobidziennikList", value); mTokenMobidziennikList = value }
|
||||
private var mTokenLibrusList: List<Int>? = null
|
||||
var tokenLibrusList: List<Int>
|
||||
get() { mTokenLibrusList = mTokenLibrusList ?: config.values.getIntList("tokenLibrusList", listOf()); return mTokenLibrusList ?: listOf() }
|
||||
set(value) { config.set("tokenLibrusList", value); mTokenLibrusList = value }
|
||||
private var mTokenVulcanList: List<Int>? = null
|
||||
var tokenVulcanList: List<Int>
|
||||
get() { mTokenVulcanList = mTokenVulcanList ?: config.values.getIntList("tokenVulcanList", listOf()); return mTokenVulcanList ?: listOf() }
|
||||
set(value) { config.set("tokenVulcanList", value); mTokenVulcanList = value }
|
||||
private var mTokenVulcanHebeList: List<Int>? = null
|
||||
var tokenVulcanHebeList: List<Int>
|
||||
get() { mTokenVulcanHebeList = mTokenVulcanHebeList ?: config.values.getIntList("tokenVulcanHebeList", listOf()); return mTokenVulcanHebeList ?: listOf() }
|
||||
set(value) { config.set("tokenVulcanHebeList", value); mTokenVulcanHebeList = value }
|
||||
|
||||
private var mRegisterAvailability: Map<String, RegisterAvailabilityStatus>? = null
|
||||
var registerAvailability: Map<String, RegisterAvailabilityStatus>
|
||||
get() {
|
||||
if (BuildConfig.FLAVOR != registerAvailabilityFlavor)
|
||||
val flavor = config.values.get("registerAvailabilityFlavor", null as String?)
|
||||
if (BuildConfig.FLAVOR != flavor)
|
||||
return mapOf()
|
||||
return registerAvailabilityMap
|
||||
|
||||
mRegisterAvailability = mRegisterAvailability ?: config.values.get("registerAvailability", null as String?)?.let { it ->
|
||||
gson.fromJson(it, object: TypeToken<Map<String, RegisterAvailabilityStatus>>(){}.type)
|
||||
}
|
||||
return mRegisterAvailability ?: mapOf()
|
||||
}
|
||||
set(value) {
|
||||
registerAvailabilityMap = value
|
||||
registerAvailabilityFlavor = BuildConfig.FLAVOR
|
||||
config.setMap("registerAvailability", value)
|
||||
config.set("registerAvailabilityFlavor", BuildConfig.FLAVOR)
|
||||
mRegisterAvailability = value
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,23 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ConfigTimetable(base: Config) {
|
||||
class ConfigTimetable(private val config: Config) {
|
||||
private var mBellSyncMultiplier: Int? = null
|
||||
var bellSyncMultiplier: Int
|
||||
get() { mBellSyncMultiplier = mBellSyncMultiplier ?: config.values.get("bellSyncMultiplier", 0); return mBellSyncMultiplier ?: 0 }
|
||||
set(value) { config.set("bellSyncMultiplier", value); mBellSyncMultiplier = value }
|
||||
|
||||
var bellSyncMultiplier by base.config<Int>(0)
|
||||
var bellSyncDiff by base.config<Time?>(null)
|
||||
var countInSeconds by base.config<Boolean>(false)
|
||||
}
|
||||
private var mBellSyncDiff: Time? = null
|
||||
var bellSyncDiff: Time?
|
||||
get() { mBellSyncDiff = mBellSyncDiff ?: config.values.get("bellSyncDiff", null as Time?); return mBellSyncDiff }
|
||||
set(value) { config.set("bellSyncDiff", value); mBellSyncDiff = value }
|
||||
|
||||
private var mCountInSeconds: Boolean? = null
|
||||
var countInSeconds: Boolean
|
||||
get() { mCountInSeconds = mCountInSeconds ?: config.values.get("countInSeconds", false); return mCountInSeconds ?: false }
|
||||
set(value) { config.set("countInSeconds", value); mCountInSeconds = value }
|
||||
}
|
@ -4,32 +4,58 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.getIntList
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ConfigUI(base: Config) {
|
||||
class ConfigUI(private val config: Config) {
|
||||
private var mTheme: Int? = null
|
||||
var theme: Int
|
||||
get() { mTheme = mTheme ?: config.values.get("theme", 1); return mTheme ?: 1 }
|
||||
set(value) { config.set("theme", value); mTheme = value }
|
||||
|
||||
var theme by base.config<Int>(1)
|
||||
var language by base.config<String?>(null)
|
||||
private var mLanguage: String? = null
|
||||
var language: String?
|
||||
get() { mLanguage = mLanguage ?: config.values.get("language", null as String?); return mLanguage }
|
||||
set(value) { config.set("language", value); mLanguage = value }
|
||||
|
||||
var appBackground by base.config<String?>("appBg", null)
|
||||
var headerBackground by base.config<String?>("headerBg", null)
|
||||
private var mHeaderBackground: String? = null
|
||||
var headerBackground: String?
|
||||
get() { mHeaderBackground = mHeaderBackground ?: config.values.get("headerBg", null as String?); return mHeaderBackground }
|
||||
set(value) { config.set("headerBg", value); mHeaderBackground = value }
|
||||
|
||||
var miniMenuVisible by base.config<Boolean>(false)
|
||||
var miniMenuButtons by base.config<Set<NavTarget>> {
|
||||
setOf(
|
||||
NavTarget.HOME,
|
||||
NavTarget.TIMETABLE,
|
||||
NavTarget.AGENDA,
|
||||
NavTarget.GRADES,
|
||||
NavTarget.MESSAGES,
|
||||
NavTarget.HOMEWORK,
|
||||
NavTarget.SETTINGS
|
||||
)
|
||||
}
|
||||
var openDrawerOnBackPressed by base.config<Boolean>(false)
|
||||
private var mAppBackground: String? = null
|
||||
var appBackground: String?
|
||||
get() { mAppBackground = mAppBackground ?: config.values.get("appBg", null as String?); return mAppBackground }
|
||||
set(value) { config.set("appBg", value); mAppBackground = value }
|
||||
|
||||
var bottomSheetOpened by base.config<Boolean>(false)
|
||||
var snowfall by base.config<Boolean>(false)
|
||||
var eggfall by base.config<Boolean>(false)
|
||||
private var mMiniMenuVisible: Boolean? = null
|
||||
var miniMenuVisible: Boolean
|
||||
get() { mMiniMenuVisible = mMiniMenuVisible ?: config.values.get("miniMenuVisible", false); return mMiniMenuVisible ?: false }
|
||||
set(value) { config.set("miniMenuVisible", value); mMiniMenuVisible = value }
|
||||
|
||||
private var mMiniMenuButtons: List<Int>? = null
|
||||
var miniMenuButtons: List<Int>
|
||||
get() { mMiniMenuButtons = mMiniMenuButtons ?: config.values.getIntList("miniMenuButtons", listOf()); return mMiniMenuButtons ?: listOf() }
|
||||
set(value) { config.set("miniMenuButtons", value); mMiniMenuButtons = value }
|
||||
|
||||
private var mOpenDrawerOnBackPressed: Boolean? = null
|
||||
var openDrawerOnBackPressed: Boolean
|
||||
get() { mOpenDrawerOnBackPressed = mOpenDrawerOnBackPressed ?: config.values.get("openDrawerOnBackPressed", false); return mOpenDrawerOnBackPressed ?: false }
|
||||
set(value) { config.set("openDrawerOnBackPressed", value); mOpenDrawerOnBackPressed = value }
|
||||
|
||||
private var mSnowfall: Boolean? = null
|
||||
var snowfall: Boolean
|
||||
get() { mSnowfall = mSnowfall ?: config.values.get("snowfall", false); return mSnowfall ?: false }
|
||||
set(value) { config.set("snowfall", value); mSnowfall = value }
|
||||
|
||||
private var mEggfall: Boolean? = null
|
||||
var eggfall: Boolean
|
||||
get() { mEggfall = mEggfall ?: config.values.get("eggfall", false); return mEggfall ?: false }
|
||||
set(value) { config.set("eggfall", value); mEggfall = value }
|
||||
|
||||
private var mBottomSheetOpened: Boolean? = null
|
||||
var bottomSheetOpened: Boolean
|
||||
get() { mBottomSheetOpened = mBottomSheetOpened ?: config.values.get("bottomSheetOpened", false); return mBottomSheetOpened ?: false }
|
||||
set(value) { config.set("bottomSheetOpened", value); mBottomSheetOpened = value }
|
||||
}
|
||||
|
@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2022-10-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.WildcardType
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
private val gson = Gson()
|
||||
|
||||
inline fun <reified T> BaseConfig.config(name: String? = null, noinline default: () -> T) = ConfigDelegate(
|
||||
config = this,
|
||||
type = T::class.java,
|
||||
nullable = null is T,
|
||||
typeToken = object : TypeToken<T>() {},
|
||||
defaultFunc = default,
|
||||
defaultValue = null,
|
||||
fieldName = name,
|
||||
)
|
||||
|
||||
inline fun <reified T> BaseConfig.config(default: T) = ConfigDelegate(
|
||||
config = this,
|
||||
type = T::class.java,
|
||||
nullable = null is T,
|
||||
typeToken = object : TypeToken<T>() {},
|
||||
defaultFunc = null,
|
||||
defaultValue = default,
|
||||
fieldName = null,
|
||||
)
|
||||
|
||||
inline fun <reified T> BaseConfig.config(name: String? = null, default: T) = ConfigDelegate(
|
||||
config = this,
|
||||
type = T::class.java,
|
||||
nullable = null is T,
|
||||
typeToken = object : TypeToken<T>() {},
|
||||
defaultFunc = null,
|
||||
defaultValue = default,
|
||||
fieldName = name,
|
||||
)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class ConfigDelegate<T>(
|
||||
private val config: BaseConfig,
|
||||
private val type: Class<T>,
|
||||
private val nullable: Boolean,
|
||||
private val typeToken: TypeToken<T>,
|
||||
private val defaultFunc: (() -> T)?,
|
||||
private val defaultValue: T?,
|
||||
private val fieldName: String?,
|
||||
) {
|
||||
private var value: T? = null
|
||||
private var isInitialized = false
|
||||
|
||||
private fun getDefault(): T = when {
|
||||
defaultFunc != null -> defaultFunc.invoke()
|
||||
else -> defaultValue as T
|
||||
}
|
||||
|
||||
private fun getGenericType(index: Int = 0): Class<*> {
|
||||
val parameterizedType = typeToken.type as ParameterizedType
|
||||
val typeArgument = parameterizedType.actualTypeArguments[index] as WildcardType
|
||||
return typeArgument.upperBounds[0] as Class<*>
|
||||
}
|
||||
|
||||
operator fun setValue(_thisRef: Any, property: KProperty<*>, newValue: T) {
|
||||
value = newValue
|
||||
isInitialized = true
|
||||
config.set(fieldName ?: property.name, serialize(newValue)?.toString())
|
||||
}
|
||||
|
||||
operator fun getValue(_thisRef: Any, property: KProperty<*>): T {
|
||||
if (isInitialized)
|
||||
return value as T
|
||||
val key = fieldName ?: property.name
|
||||
|
||||
if (key !in config.values) {
|
||||
value = getDefault()
|
||||
isInitialized = true
|
||||
return value as T
|
||||
}
|
||||
val str = config.values[key]
|
||||
|
||||
value = if (str == null && nullable)
|
||||
null as T
|
||||
else if (str == null)
|
||||
getDefault()
|
||||
else
|
||||
deserialize(str)
|
||||
|
||||
isInitialized = true
|
||||
return value as T
|
||||
}
|
||||
|
||||
private fun <I> serialize(value: I?, serializeObjects: Boolean = true): Any? {
|
||||
if (value == null)
|
||||
return null
|
||||
|
||||
return when (value) {
|
||||
is String -> value
|
||||
is Date -> value.stringY_m_d
|
||||
is Time -> value.stringValue
|
||||
is JsonObject -> value
|
||||
is JsonArray -> value
|
||||
// primitives
|
||||
is Number -> value
|
||||
is Boolean -> value
|
||||
// enums, maps & collections
|
||||
is Enum<*> -> value.toInt()
|
||||
is Collection<*> -> value.map {
|
||||
if (it is Number || it is Boolean) it else serialize(it, serializeObjects = false)
|
||||
}.toJsonElement()
|
||||
is Map<*, *> -> gson.toJson(value.mapValues { (_, it) ->
|
||||
if (it is Number || it is Boolean) it else serialize(it, serializeObjects = false)
|
||||
})
|
||||
// objects or else
|
||||
else -> if (serializeObjects) gson.toJson(value) else value
|
||||
}
|
||||
}
|
||||
|
||||
private fun <I> deserialize(value: String?, type: Class<*> = this.type): I? {
|
||||
if (value == null)
|
||||
return null
|
||||
|
||||
@Suppress("TYPE_MISMATCH_WARNING")
|
||||
return when (type) {
|
||||
String::class.java -> value
|
||||
Date::class.java -> Date.fromY_m_d(value)
|
||||
Time::class.java -> Time.fromHms(value)
|
||||
JsonObject::class.java -> value.toJsonObject()
|
||||
JsonArray::class.java -> value.toJsonArray()
|
||||
// primitives
|
||||
java.lang.Integer::class.java -> value.toIntOrNull()
|
||||
java.lang.Boolean::class.java -> value.toBooleanStrictOrNull()
|
||||
java.lang.Long::class.java -> value.toLongOrNull()
|
||||
java.lang.Float::class.java -> value.toFloatOrNull()
|
||||
// enums, maps & collections
|
||||
else -> when {
|
||||
Enum::class.java.isAssignableFrom(type) -> value.toIntOrNull()?.toEnum(type) as Enum<*>
|
||||
Collection::class.java.isAssignableFrom(type) -> {
|
||||
val array = value.toJsonArray()
|
||||
val genericType = getGenericType()
|
||||
val list = array?.map {
|
||||
val str = if (it.isJsonPrimitive) it.asString else it.toString()
|
||||
deserialize<Any>(str, genericType)
|
||||
}
|
||||
when {
|
||||
List::class.java.isAssignableFrom(type) -> list
|
||||
Set::class.java.isAssignableFrom(type) -> list?.toSet()
|
||||
else -> list?.toTypedArray()
|
||||
}
|
||||
}
|
||||
Map::class.java.isAssignableFrom(type) -> {
|
||||
val obj = value.toJsonObject()
|
||||
val genericType = getGenericType(index = 1)
|
||||
val map = obj?.entrySet()?.associate { (key, it) ->
|
||||
val str = if (it.isJsonPrimitive) it.asString else it.toString()
|
||||
key to deserialize<Any>(str, genericType)
|
||||
}
|
||||
map
|
||||
}
|
||||
// objects or else
|
||||
else -> gson.fromJson(value, type)
|
||||
}
|
||||
} as? I
|
||||
}
|
||||
}
|
@ -4,20 +4,29 @@
|
||||
|
||||
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.config.utils.ProfileConfigMigration
|
||||
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.data.db.AppDb
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ProfileConfig(
|
||||
db: AppDb,
|
||||
profileId: Int,
|
||||
entries: List<ConfigEntry>?,
|
||||
) : BaseConfig(db, profileId, entries) {
|
||||
class ProfileConfig(val db: AppDb, val profileId: Int, rawEntries: List<ConfigEntry>) : CoroutineScope, AbstractConfig {
|
||||
companion object {
|
||||
const val DATA_VERSION = 5
|
||||
const val DATA_VERSION = 2
|
||||
}
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Default
|
||||
|
||||
val values: HashMap<String, String?> = hashMapOf()
|
||||
|
||||
val grades by lazy { ProfileConfigGrades(this) }
|
||||
val ui by lazy { ProfileConfigUI(this) }
|
||||
val sync by lazy { ProfileConfigSync(this) }
|
||||
@ -26,13 +35,26 @@ class ProfileConfig(
|
||||
val timetable by lazy { ConfigTimetable(this) }
|
||||
val grades by lazy { ConfigGrades(this) }*/
|
||||
|
||||
var dataVersion by config<Int>(DATA_VERSION)
|
||||
var hash by config<String>("")
|
||||
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 shareByDefault by config<Boolean>(false)
|
||||
private var mHash: String? = null
|
||||
var hash: String
|
||||
get() { mHash = mHash ?: values.get("hash", ""); return mHash ?: "" }
|
||||
set(value) { set("hash", value); mHash = value }
|
||||
|
||||
init {
|
||||
rawEntries.toHashMap(profileId, values)
|
||||
if (dataVersion < DATA_VERSION)
|
||||
ProfileConfigMigration(this)
|
||||
}
|
||||
|
||||
override fun set(key: String, value: String?) {
|
||||
values[key] = value
|
||||
launch {
|
||||
db.configDao().add(ConfigEntry(profileId, key, value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,27 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ProfileConfigAttendance(base: ProfileConfig) {
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
|
||||
var attendancePageSelection by base.config<Int>(1)
|
||||
var groupConsecutiveDays by base.config<Boolean>(true)
|
||||
var showPresenceInMonth by base.config<Boolean>(false)
|
||||
var useSymbols by base.config<Boolean>(false)
|
||||
class ProfileConfigAttendance(private val config: ProfileConfig) {
|
||||
private var mAttendancePageSelection: Int? = null
|
||||
var attendancePageSelection: Int
|
||||
get() { mAttendancePageSelection = mAttendancePageSelection ?: config.values.get("attendancePageSelection", 1); return mAttendancePageSelection ?: 1 }
|
||||
set(value) { config.set("attendancePageSelection", value); mAttendancePageSelection = value }
|
||||
|
||||
private var mUseSymbols: Boolean? = null
|
||||
var useSymbols: Boolean
|
||||
get() { mUseSymbols = mUseSymbols ?: config.values.get("useSymbols", false); return mUseSymbols ?: false }
|
||||
set(value) { config.set("useSymbols", value); mUseSymbols = value }
|
||||
|
||||
private var mGroupConsecutiveDays: Boolean? = null
|
||||
var groupConsecutiveDays: Boolean
|
||||
get() { mGroupConsecutiveDays = mGroupConsecutiveDays ?: config.values.get("groupConsecutiveDays", true); return mGroupConsecutiveDays ?: true }
|
||||
set(value) { config.set("groupConsecutiveDays", value); mGroupConsecutiveDays = value }
|
||||
|
||||
private var mShowPresenceInMonth: Boolean? = null
|
||||
var showPresenceInMonth: Boolean
|
||||
get() { mShowPresenceInMonth = mShowPresenceInMonth ?: config.values.get("showPresenceInMonth", false); return mShowPresenceInMonth ?: false }
|
||||
set(value) { config.set("showPresenceInMonth", value); mShowPresenceInMonth = value }
|
||||
}
|
||||
|
@ -4,19 +4,54 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.getFloat
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.COLOR_MODE_WEIGHTED
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_ALL_GRADES
|
||||
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ProfileConfigGrades(base: ProfileConfig) {
|
||||
class ProfileConfigGrades(private val config: ProfileConfig) {
|
||||
private var mColorMode: Int? = null
|
||||
var colorMode: Int
|
||||
get() { mColorMode = mColorMode ?: config.values.get("gradesColorMode", COLOR_MODE_WEIGHTED); return mColorMode ?: COLOR_MODE_WEIGHTED }
|
||||
set(value) { config.set("gradesColorMode", value); mColorMode = value }
|
||||
|
||||
var averageWithoutWeight by base.config<Boolean>(true)
|
||||
var colorMode by base.config<Int>(COLOR_MODE_WEIGHTED)
|
||||
var dontCountEnabled by base.config<Boolean>(false)
|
||||
var dontCountGrades by base.config<List<String>> { listOf() }
|
||||
var hideImproved by base.config<Boolean>(false)
|
||||
var hideSticksFromOld by base.config<Boolean>(false)
|
||||
var minusValue by base.config<Float?>(null)
|
||||
var plusValue by base.config<Float?>(null)
|
||||
var yearAverageMode by base.config<Int>(YEAR_ALL_GRADES)
|
||||
private var mYearAverageMode: Int? = null
|
||||
var yearAverageMode: Int
|
||||
get() { mYearAverageMode = mYearAverageMode ?: config.values.get("yearAverageMode", YEAR_ALL_GRADES); return mYearAverageMode ?: YEAR_ALL_GRADES }
|
||||
set(value) { config.set("yearAverageMode", value); mYearAverageMode = value }
|
||||
|
||||
private var mHideImproved: Boolean? = null
|
||||
var hideImproved: Boolean
|
||||
get() { mHideImproved = mHideImproved ?: config.values.get("hideImproved", false); return mHideImproved ?: false }
|
||||
set(value) { config.set("hideImproved", value); mHideImproved = value }
|
||||
|
||||
private var mAverageWithoutWeight: Boolean? = null
|
||||
var averageWithoutWeight: Boolean
|
||||
get() { mAverageWithoutWeight = mAverageWithoutWeight ?: config.values.get("averageWithoutWeight", true); return mAverageWithoutWeight ?: true }
|
||||
set(value) { config.set("averageWithoutWeight", value); mAverageWithoutWeight = value }
|
||||
|
||||
private var mPlusValue: Float? = null
|
||||
var plusValue: Float?
|
||||
get() { mPlusValue = mPlusValue ?: config.values.getFloat("plusValue"); return mPlusValue }
|
||||
set(value) { config.set("plusValue", value); mPlusValue = value }
|
||||
private var mMinusValue: Float? = null
|
||||
var minusValue: Float?
|
||||
get() { mMinusValue = mMinusValue ?: config.values.getFloat("minusValue"); return mMinusValue }
|
||||
set(value) { config.set("minusValue", value); mMinusValue = value }
|
||||
|
||||
private var mDontCountEnabled: Boolean? = null
|
||||
var dontCountEnabled: Boolean
|
||||
get() { mDontCountEnabled = mDontCountEnabled ?: config.values.get("dontCountEnabled", false); return mDontCountEnabled ?: false }
|
||||
set(value) { config.set("dontCountEnabled", value); mDontCountEnabled = value }
|
||||
|
||||
private var mDontCountGrades: List<String>? = null
|
||||
var dontCountGrades: List<String>
|
||||
get() { mDontCountGrades = mDontCountGrades ?: config.values.get("dontCountGrades", listOf()); return mDontCountGrades ?: listOf() }
|
||||
set(value) { config.set("dontCountGrades", value); mDontCountGrades = value }
|
||||
|
||||
private var mHideSticksFromOld: Boolean? = null
|
||||
var hideSticksFromOld: Boolean
|
||||
get() { mHideSticksFromOld = mHideSticksFromOld ?: config.values.get("hideSticksFromOld", false); return mHideSticksFromOld ?: false }
|
||||
set(value) { config.set("hideSticksFromOld", value); mHideSticksFromOld = value }
|
||||
}
|
||||
|
@ -4,14 +4,12 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.NotificationType
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ProfileConfigSync(base: ProfileConfig) {
|
||||
|
||||
var notificationFilter by base.config<Set<NotificationType>> {
|
||||
NotificationType.values()
|
||||
.filter { it.enabledByDefault == false }
|
||||
.toSet()
|
||||
}
|
||||
class ProfileConfigSync(private val config: ProfileConfig) {
|
||||
private var mNotificationFilter: List<Int>? = null
|
||||
var notificationFilter: List<Int>
|
||||
get() { mNotificationFilter = mNotificationFilter ?: config.values.get("notificationFilter", listOf()); return mNotificationFilter ?: listOf() }
|
||||
set(value) { config.set("notificationFilter", value); mNotificationFilter = value }
|
||||
}
|
||||
|
@ -4,30 +4,69 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.AGENDA_DEFAULT
|
||||
import pl.szczodrzynski.edziennik.ui.home.HomeCardModel
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeCardModel
|
||||
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ProfileConfigUI(base: ProfileConfig) {
|
||||
class ProfileConfigUI(private val config: ProfileConfig) {
|
||||
private var mAgendaViewType: Int? = null
|
||||
var agendaViewType: Int
|
||||
get() { mAgendaViewType = mAgendaViewType ?: config.values.get("agendaViewType", 0); return mAgendaViewType ?: AGENDA_DEFAULT }
|
||||
set(value) { config.set("agendaViewType", value); mAgendaViewType = value }
|
||||
|
||||
var agendaViewType by base.config<Int>(AGENDA_DEFAULT)
|
||||
var agendaCompactMode by base.config<Boolean>(false)
|
||||
var agendaGroupByType by base.config<Boolean>(false)
|
||||
var agendaLessonChanges by base.config<Boolean>(true)
|
||||
var agendaTeacherAbsence by base.config<Boolean>(true)
|
||||
var agendaSubjectImportant by base.config<Boolean>(false)
|
||||
var agendaElearningMark by base.config<Boolean>(false)
|
||||
var agendaElearningGroup by base.config<Boolean>(true)
|
||||
private var mAgendaCompactMode: Boolean? = null
|
||||
var agendaCompactMode: Boolean
|
||||
get() { mAgendaCompactMode = mAgendaCompactMode ?: config.values.get("agendaCompactMode", false); return mAgendaCompactMode ?: false }
|
||||
set(value) { config.set("agendaCompactMode", value); mAgendaCompactMode = value }
|
||||
|
||||
var homeCards by base.config<List<HomeCardModel>> { listOf() }
|
||||
private var mAgendaGroupByType: Boolean? = null
|
||||
var agendaGroupByType: Boolean
|
||||
get() { mAgendaGroupByType = mAgendaGroupByType ?: config.values.get("agendaGroupByType", false); return mAgendaGroupByType ?: false }
|
||||
set(value) { config.set("agendaGroupByType", value); mAgendaGroupByType = value }
|
||||
|
||||
var messagesGreetingOnCompose by base.config<Boolean>(true)
|
||||
var messagesGreetingOnReply by base.config<Boolean>(true)
|
||||
var messagesGreetingOnForward by base.config<Boolean>(false)
|
||||
var messagesGreetingText by base.config<String?>(null)
|
||||
private var mAgendaLessonChanges: Boolean? = null
|
||||
var agendaLessonChanges: Boolean
|
||||
get() { mAgendaLessonChanges = mAgendaLessonChanges ?: config.values.get("agendaLessonChanges", true); return mAgendaLessonChanges ?: true }
|
||||
set(value) { config.set("agendaLessonChanges", value); mAgendaLessonChanges = value }
|
||||
|
||||
var timetableShowAttendance by base.config<Boolean>(true)
|
||||
var timetableShowEvents by base.config<Boolean>(true)
|
||||
var timetableTrimHourRange by base.config<Boolean>(false)
|
||||
var timetableColorSubjectName by base.config<Boolean>(false)
|
||||
private var mAgendaTeacherAbsence: Boolean? = null
|
||||
var agendaTeacherAbsence: Boolean
|
||||
get() { mAgendaTeacherAbsence = mAgendaTeacherAbsence ?: config.values.get("agendaTeacherAbsence", true); return mAgendaTeacherAbsence ?: true }
|
||||
set(value) { config.set("agendaTeacherAbsence", value); mAgendaTeacherAbsence = value }
|
||||
|
||||
private var mAgendaElearningMark: Boolean? = null
|
||||
var agendaElearningMark: Boolean
|
||||
get() { mAgendaElearningMark = mAgendaElearningMark ?: config.values.get("agendaElearningMark", false); return mAgendaElearningMark ?: false }
|
||||
set(value) { config.set("agendaElearningMark", value); mAgendaElearningMark = value }
|
||||
|
||||
private var mAgendaElearningGroup: Boolean? = null
|
||||
var agendaElearningGroup: Boolean
|
||||
get() { mAgendaElearningGroup = mAgendaElearningGroup ?: config.values.get("agendaElearningGroup", true); return mAgendaElearningGroup ?: true }
|
||||
set(value) { config.set("agendaElearningGroup", value); mAgendaElearningGroup = value }
|
||||
|
||||
private var mHomeCards: List<HomeCardModel>? = null
|
||||
var homeCards: List<HomeCardModel>
|
||||
get() { mHomeCards = mHomeCards ?: config.values.get("homeCards", listOf(), HomeCardModel::class.java); return mHomeCards ?: listOf() }
|
||||
set(value) { config.set("homeCards", value); mHomeCards = value }
|
||||
|
||||
private var mMessagesGreetingOnCompose: Boolean? = null
|
||||
var messagesGreetingOnCompose: Boolean
|
||||
get() { mMessagesGreetingOnCompose = mMessagesGreetingOnCompose ?: config.values.get("messagesGreetingOnCompose", true); return mMessagesGreetingOnCompose ?: true }
|
||||
set(value) { config.set("messagesGreetingOnCompose", value); mMessagesGreetingOnCompose = value }
|
||||
|
||||
private var mMessagesGreetingOnReply: Boolean? = null
|
||||
var messagesGreetingOnReply: Boolean
|
||||
get() { mMessagesGreetingOnReply = mMessagesGreetingOnReply ?: config.values.get("messagesGreetingOnReply", true); return mMessagesGreetingOnReply ?: true }
|
||||
set(value) { config.set("messagesGreetingOnReply", value); mMessagesGreetingOnReply = value }
|
||||
|
||||
private var mMessagesGreetingOnForward: Boolean? = null
|
||||
var messagesGreetingOnForward: Boolean
|
||||
get() { mMessagesGreetingOnForward = mMessagesGreetingOnForward ?: config.values.get("messagesGreetingOnForward", false); return mMessagesGreetingOnForward ?: false }
|
||||
set(value) { config.set("messagesGreetingOnForward", value); mMessagesGreetingOnForward = value }
|
||||
|
||||
private var mMessagesGreetingText: String? = null
|
||||
var messagesGreetingText: String?
|
||||
get() { mMessagesGreetingText = mMessagesGreetingText ?: config.values["messagesGreetingText"]; return mMessagesGreetingText }
|
||||
set(value) { config.set("messagesGreetingText", value); mMessagesGreetingText = value }
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ interface ConfigDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun addAll(list: List<ConfigEntry>)
|
||||
|
||||
@Query("SELECT * FROM config")
|
||||
@Query("SELECT * FROM config WHERE profileId = -1")
|
||||
fun getAllNow(): List<ConfigEntry>
|
||||
|
||||
@Query("SELECT * FROM config WHERE profileId = :profileId")
|
||||
@ -25,4 +25,4 @@ interface ConfigDao {
|
||||
|
||||
@Query("DELETE FROM config WHERE profileId = :profileId")
|
||||
fun clear(profileId: Int)
|
||||
}
|
||||
}
|
@ -8,35 +8,38 @@ import android.content.SharedPreferences
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import pl.szczodrzynski.edziennik.BuildConfig
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.config.Config
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
|
||||
import pl.szczodrzynski.edziennik.ext.asNavTargetOrNull
|
||||
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_LIBRUS
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_MOBIDZIENNIK
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_VULCAN
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import kotlin.math.abs
|
||||
|
||||
class AppConfigMigrationV3(p: SharedPreferences, config: Config) {
|
||||
init {
|
||||
init { config.apply {
|
||||
val s = "app.appConfig"
|
||||
config.apply {
|
||||
if (dataVersion < 1) {
|
||||
ui.theme = p.getString("$s.appTheme", null)?.toIntOrNull() ?: 1
|
||||
sync.enabled = p.getString("$s.registerSyncEnabled", null)?.toBoolean() ?: true
|
||||
sync.interval = p.getString("$s.registerSyncInterval", null)?.toIntOrNull() ?: 3600
|
||||
val oldButtons = p.getString("$s.miniDrawerButtonIds", null)?.let { str ->
|
||||
str.replace("[\\[\\]]*".toRegex(), "")
|
||||
.split(",\\s?".toRegex())
|
||||
.mapNotNull { it.toIntOrNull().asNavTargetOrNull() }
|
||||
.toSet()
|
||||
.mapNotNull { it.toIntOrNull() }
|
||||
}
|
||||
ui.miniMenuButtons = oldButtons ?: setOf(
|
||||
NavTarget.HOME,
|
||||
NavTarget.TIMETABLE,
|
||||
NavTarget.AGENDA,
|
||||
NavTarget.GRADES,
|
||||
NavTarget.MESSAGES,
|
||||
NavTarget.HOMEWORK,
|
||||
NavTarget.SETTINGS
|
||||
ui.miniMenuButtons = oldButtons ?: listOf(
|
||||
MainActivity.DRAWER_ITEM_HOME,
|
||||
MainActivity.DRAWER_ITEM_TIMETABLE,
|
||||
MainActivity.DRAWER_ITEM_AGENDA,
|
||||
MainActivity.DRAWER_ITEM_GRADES,
|
||||
MainActivity.DRAWER_ITEM_MESSAGES,
|
||||
MainActivity.DRAWER_ITEM_HOMEWORK,
|
||||
MainActivity.DRAWER_ITEM_SETTINGS
|
||||
)
|
||||
dataVersion = 1
|
||||
}
|
||||
if (dataVersion < 2) {
|
||||
devModePassword = p.getString("$s.devModePassword", null).fix()
|
||||
sync.tokenApp = p.getString("$s.fcmToken", null).fix()
|
||||
timetable.bellSyncMultiplier = p.getString("$s.bellSyncMultiplier", null)?.toIntOrNull() ?: 0
|
||||
@ -78,13 +81,14 @@ class AppConfigMigrationV3(p: SharedPreferences, config: Config) {
|
||||
tokens?.forEach {
|
||||
val token = it.value.first
|
||||
when (it.key) {
|
||||
LoginType.MOBIDZIENNIK.id -> sync.tokenMobidziennik = token
|
||||
LoginType.VULCAN.id -> sync.tokenVulcan = token
|
||||
LoginType.LIBRUS.id -> sync.tokenLibrus = token
|
||||
LOGIN_TYPE_MOBIDZIENNIK -> sync.tokenMobidziennik = token
|
||||
LOGIN_TYPE_VULCAN -> sync.tokenVulcan = token
|
||||
LOGIN_TYPE_LIBRUS -> sync.tokenLibrus = token
|
||||
}
|
||||
}
|
||||
dataVersion = 2
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
private fun String?.fix(): String? {
|
||||
return this?.replace("\"", "")?.let { if (it == "null") null else it }
|
||||
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
import com.google.gson.*
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import pl.szczodrzynski.edziennik.config.AbstractConfig
|
||||
import pl.szczodrzynski.edziennik.config.db.ConfigEntry
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
private val gson = Gson()
|
||||
|
||||
fun AbstractConfig.set(key: String, value: Int) {
|
||||
set(key, value.toString())
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Boolean) {
|
||||
set(key, value.toString())
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Long) {
|
||||
set(key, value.toString())
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Float) {
|
||||
set(key, value.toString())
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Date?) {
|
||||
set(key, value?.stringY_m_d)
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Time?) {
|
||||
set(key, value?.stringValue)
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: JsonElement?) {
|
||||
set(key, value?.toString())
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: List<Any>?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Any?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
fun AbstractConfig.setStringList(key: String, value: List<String>?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
fun AbstractConfig.setIntList(key: String, value: List<Int>?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
fun AbstractConfig.setLongList(key: String, value: List<Long>?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
fun <K, V> AbstractConfig.setMap(key: String, value: Map<K, V>?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
|
||||
fun HashMap<String, String?>.get(key: String, default: String?): String? {
|
||||
return this[key] ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Boolean): Boolean {
|
||||
return this[key]?.toBoolean() ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Int): Int {
|
||||
return this[key]?.toIntOrNull() ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Long): Long {
|
||||
return this[key]?.toLongOrNull() ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Float): Float {
|
||||
return this[key]?.toFloatOrNull() ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Date?): Date? {
|
||||
return this[key]?.let { Date.fromY_m_d(it) } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Time?): Time? {
|
||||
return this[key]?.let { Time.fromHms(it) } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: JsonObject?): JsonObject? {
|
||||
return this[key]?.let { JsonParser().parse(it)?.asJsonObject } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: JsonArray?): JsonArray? {
|
||||
return this[key]?.let { JsonParser().parse(it)?.asJsonArray } ?: default
|
||||
}
|
||||
inline fun <reified T> HashMap<String, String?>.get(key: String, default: T?): T? {
|
||||
return this[key]?.let { Gson().fromJson(it, T::class.java) } ?: default
|
||||
}
|
||||
/* !!! cannot use mutable list here - modifying it will not update the DB */
|
||||
fun <T> HashMap<String, String?>.get(key: String, default: List<T>?, classOfT: Class<T>): List<T>? {
|
||||
return this[key]?.let { ConfigGsonUtils().deserializeList<T>(gson, it, classOfT) } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.getStringList(key: String, default: List<String>?): List<String>? {
|
||||
return this[key]?.let { gson.fromJson<List<String>>(it, object: TypeToken<List<String>>(){}.type) } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.getIntList(key: String, default: List<Int>?): List<Int>? {
|
||||
return this[key]?.let { gson.fromJson<List<Int>>(it, object: TypeToken<List<Int>>(){}.type) } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.getLongList(key: String, default: List<Long>?): List<Long>? {
|
||||
return this[key]?.let { gson.fromJson<List<Long>>(it, object: TypeToken<List<Long>>(){}.type) } ?: default
|
||||
}
|
||||
|
||||
fun HashMap<String, String?>.getFloat(key: String): Float? {
|
||||
return this[key]?.toFloatOrNull()
|
||||
}
|
||||
|
||||
fun List<ConfigEntry>.toHashMap(profileId: Int, map: HashMap<String, String?>) {
|
||||
map.clear()
|
||||
forEach {
|
||||
if (it.profileId == profileId)
|
||||
map[it.key] = it.value
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-12-2.
|
||||
*/
|
||||
package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonParser
|
||||
import pl.szczodrzynski.edziennik.getInt
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeCardModel
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class ConfigGsonUtils {
|
||||
fun <T> deserializeList(gson: Gson, str: String?, classOfT: Class<T>): List<T> {
|
||||
val json = JsonParser().parse(str)
|
||||
val list: MutableList<T> = mutableListOf()
|
||||
if (!json.isJsonArray)
|
||||
return list
|
||||
|
||||
json.asJsonArray.forEach { e ->
|
||||
when (classOfT) {
|
||||
String::class.java -> {
|
||||
list += e.asString as T
|
||||
}
|
||||
HomeCardModel::class.java -> {
|
||||
val o = e.asJsonObject
|
||||
list += HomeCardModel(
|
||||
o.getInt("profileId", 0),
|
||||
o.getInt("cardId", 0)
|
||||
) as T
|
||||
}
|
||||
Time::class.java -> {
|
||||
val o = e.asJsonObject
|
||||
list += Time(
|
||||
o.getInt("hour", 0),
|
||||
o.getInt("minute", 0),
|
||||
o.getInt("second", 0)
|
||||
) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
}
|
@ -5,9 +5,12 @@
|
||||
package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.content.edit
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.BuildConfig
|
||||
import pl.szczodrzynski.edziennik.HOUR
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.config.Config
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.ORDER_BY_DATE_DESC
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import kotlin.math.abs
|
||||
|
||||
@ -19,14 +22,74 @@ class ConfigMigration(app: App, config: Config) {
|
||||
// migrate appConfig from app version 3.x and lower.
|
||||
// Updates dataVersion to level 2.
|
||||
AppConfigMigrationV3(p, config)
|
||||
p.edit {
|
||||
remove("app.appConfig.appTheme")
|
||||
}
|
||||
}
|
||||
|
||||
if (dataVersion < 2) {
|
||||
appVersion = BuildConfig.VERSION_CODE
|
||||
loginFinished = false
|
||||
ui.language = null
|
||||
ui.theme = 1
|
||||
ui.appBackground = null
|
||||
ui.headerBackground = null
|
||||
ui.miniMenuVisible = false
|
||||
ui.miniMenuButtons = listOf(
|
||||
MainActivity.DRAWER_ITEM_HOME,
|
||||
MainActivity.DRAWER_ITEM_TIMETABLE,
|
||||
MainActivity.DRAWER_ITEM_AGENDA,
|
||||
MainActivity.DRAWER_ITEM_GRADES,
|
||||
MainActivity.DRAWER_ITEM_MESSAGES,
|
||||
MainActivity.DRAWER_ITEM_HOMEWORK,
|
||||
MainActivity.DRAWER_ITEM_SETTINGS
|
||||
)
|
||||
sync.enabled = true
|
||||
sync.interval = 1*HOUR.toInt()
|
||||
sync.notifyAboutUpdates = true
|
||||
sync.onlyWifi = false
|
||||
sync.quietHoursEnabled = false
|
||||
sync.quietHoursStart = null
|
||||
sync.quietHoursEnd = null
|
||||
sync.quietDuringLessons = false
|
||||
sync.tokenApp = null
|
||||
sync.tokenMobidziennik = null
|
||||
sync.tokenMobidziennikList = listOf()
|
||||
sync.tokenLibrus = null
|
||||
sync.tokenLibrusList = listOf()
|
||||
sync.tokenVulcan = null
|
||||
sync.tokenVulcanList = listOf()
|
||||
timetable.bellSyncMultiplier = 0
|
||||
timetable.bellSyncDiff = null
|
||||
timetable.countInSeconds = false
|
||||
grades.orderBy = ORDER_BY_DATE_DESC
|
||||
|
||||
dataVersion = 2
|
||||
}
|
||||
|
||||
if (dataVersion < 3) {
|
||||
update = null
|
||||
privacyPolicyAccepted = false
|
||||
debugMode = false
|
||||
devModePassword = null
|
||||
appInstalledTime = 0L
|
||||
appRateSnackbarTime = 0L
|
||||
|
||||
dataVersion = 3
|
||||
}
|
||||
|
||||
if (dataVersion < 10) {
|
||||
ui.openDrawerOnBackPressed = false
|
||||
ui.snowfall = false
|
||||
ui.bottomSheetOpened = false
|
||||
sync.dontShowAppManagerDialog = false
|
||||
sync.webPushEnabled = true
|
||||
sync.lastAppSync = 0L
|
||||
|
||||
|
||||
dataVersion = 10
|
||||
}
|
||||
|
||||
if (dataVersion < 11) {
|
||||
val startMillis = config.values["quietHoursStart"]?.toLongOrNull() ?: 0L
|
||||
val endMillis = config.values["quietHoursEnd"]?.toLongOrNull() ?: 0L
|
||||
val startMillis = config.values.get("quietHoursStart", 0L)
|
||||
val endMillis = config.values.get("quietHoursEnd", 0L)
|
||||
if (startMillis > 0) {
|
||||
try {
|
||||
sync.quietHoursStart = Time.fromMillis(abs(startMillis))
|
||||
@ -43,7 +106,5 @@ class ConfigMigration(app: App, config: Config) {
|
||||
|
||||
dataVersion = 11
|
||||
}
|
||||
|
||||
hash = "invalid"
|
||||
}}
|
||||
}
|
||||
|
@ -5,57 +5,33 @@
|
||||
package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.ProfileConfig
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.AGENDA_DEFAULT
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.NotificationType
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.SchoolType
|
||||
import pl.szczodrzynski.edziennik.ui.home.HomeCard
|
||||
import pl.szczodrzynski.edziennik.ui.home.HomeCardModel
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.COLOR_MODE_WEIGHTED
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_ALL_GRADES
|
||||
|
||||
class ProfileConfigMigration(config: ProfileConfig) {
|
||||
init { config.apply {
|
||||
|
||||
val profile = db.profileDao().getByIdNow(profileId ?: -1)
|
||||
if (dataVersion < 1) {
|
||||
grades.colorMode = COLOR_MODE_WEIGHTED
|
||||
grades.yearAverageMode = YEAR_ALL_GRADES
|
||||
grades.hideImproved = false
|
||||
grades.averageWithoutWeight = true
|
||||
grades.plusValue = null
|
||||
grades.minusValue = null
|
||||
grades.dontCountEnabled = false
|
||||
grades.dontCountGrades = listOf()
|
||||
ui.agendaViewType = AGENDA_DEFAULT
|
||||
// no migration for ui.homeCards
|
||||
|
||||
dataVersion = 1
|
||||
}
|
||||
|
||||
if (dataVersion < 2) {
|
||||
sync.notificationFilter = sync.notificationFilter + NotificationType.TEACHER_ABSENCE
|
||||
sync.notificationFilter = sync.notificationFilter + Notification.TYPE_TEACHER_ABSENCE
|
||||
|
||||
dataVersion = 2
|
||||
}
|
||||
|
||||
if (dataVersion < 3) {
|
||||
if (ui.homeCards.isNotEmpty()) {
|
||||
ui.homeCards = ui.homeCards + HomeCardModel(
|
||||
profileId = config.profileId ?: -1,
|
||||
cardId = HomeCard.CARD_NOTES,
|
||||
)
|
||||
}
|
||||
|
||||
dataVersion = 3
|
||||
}
|
||||
|
||||
if (dataVersion < 4) {
|
||||
// switch to new event types (USOS)
|
||||
dataVersion = 4
|
||||
|
||||
if (profile?.loginStoreType?.schoolType == SchoolType.UNIVERSITY) {
|
||||
db.eventTypeDao().clear(profileId ?: -1)
|
||||
db.eventTypeDao().addDefaultTypes(profile)
|
||||
}
|
||||
}
|
||||
|
||||
if (dataVersion < 5) {
|
||||
// update USOS event types and the appropriate events (2022-12-25)
|
||||
dataVersion = 5
|
||||
|
||||
if (profile?.loginStoreType?.schoolType == SchoolType.UNIVERSITY) {
|
||||
db.eventTypeDao().getAllWithDefaults(profile)
|
||||
// wejściówka (4) -> kartkówka (3)
|
||||
db.eventDao().getRawNow("UPDATE events SET eventType = 3 WHERE profileId = $profileId AND eventType = 4;")
|
||||
// zadanie (6) -> zadanie domowe (-1)
|
||||
db.eventDao().getRawNow("UPDATE events SET eventType = -1 WHERE profileId = $profileId AND eventType = 6;")
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import pl.szczodrzynski.edziennik.data.api.task.ErrorReportTask
|
||||
import pl.szczodrzynski.edziennik.data.api.task.IApiTask
|
||||
import pl.szczodrzynski.edziennik.data.api.task.SzkolnyTask
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.ext.toApiError
|
||||
import pl.szczodrzynski.edziennik.toApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
@ -84,21 +84,19 @@ class ApiService : Service() {
|
||||
runTask()
|
||||
}
|
||||
|
||||
override fun onRequiresUserAction(event: UserActionRequiredEvent) {
|
||||
app.userActionManager.sendToUser(event)
|
||||
taskRunning?.cancel()
|
||||
clearTask()
|
||||
runTask()
|
||||
}
|
||||
|
||||
override fun onError(apiError: ApiError) {
|
||||
lastEventTime = System.currentTimeMillis()
|
||||
d(TAG, "Task $taskRunningId threw an error - $apiError")
|
||||
apiError.profileId = taskProfileId
|
||||
|
||||
EventBus.getDefault().postSticky(ApiTaskErrorEvent(apiError))
|
||||
errorList.add(apiError)
|
||||
apiError.throwable?.printStackTrace()
|
||||
if (app.userActionManager.requiresUserAction(apiError)) {
|
||||
app.userActionManager.sendToUser(apiError)
|
||||
}
|
||||
else {
|
||||
EventBus.getDefault().postSticky(ApiTaskErrorEvent(apiError))
|
||||
errorList.add(apiError)
|
||||
apiError.throwable?.printStackTrace()
|
||||
}
|
||||
|
||||
if (apiError.isCritical) {
|
||||
taskRunning?.cancel()
|
||||
|
@ -24,12 +24,11 @@ const val FAKE_LIBRUS_ACCOUNTS = "/synergia_accounts.php"
|
||||
|
||||
val LIBRUS_USER_AGENT = "${SYSTEM_USER_AGENT}LibrusMobileApp"
|
||||
const val SYNERGIA_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Gecko/20100101 Firefox/62.0"
|
||||
const val LIBRUS_CLIENT_ID = "VaItV6oRutdo8fnjJwysnTjVlvaswf52ZqmXsJGP"
|
||||
const val LIBRUS_CLIENT_ID = "0RbsDOkV9tyKEQYzlLv5hs3DM1ukrynFI4p6C1Yc"
|
||||
const val LIBRUS_REDIRECT_URL = "app://librus"
|
||||
const val LIBRUS_AUTHORIZE_URL = "https://portal.librus.pl/konto-librus/redirect/dru"
|
||||
const val LIBRUS_LOGIN_URL = "https://portal.librus.pl/konto-librus/login/action"
|
||||
const val LIBRUS_AUTHORIZE_URL = "https://portal.librus.pl/oauth2/authorize?client_id=$LIBRUS_CLIENT_ID&redirect_uri=$LIBRUS_REDIRECT_URL&response_type=code"
|
||||
const val LIBRUS_LOGIN_URL = "https://portal.librus.pl/rodzina/login/action"
|
||||
const val LIBRUS_TOKEN_URL = "https://portal.librus.pl/oauth2/access_token"
|
||||
const val LIBRUS_HEADER = "pl.librus.synergiaDru2"
|
||||
|
||||
const val LIBRUS_ACCOUNT_URL = "/v3/SynergiaAccounts/fresh/" // + login
|
||||
const val LIBRUS_ACCOUNTS_URL = "/v3/SynergiaAccounts"
|
||||
@ -44,7 +43,7 @@ const val LIBRUS_API_TOKEN_URL = "https://api.librus.pl/OAuth/Token"
|
||||
const val LIBRUS_API_TOKEN_JST_URL = "https://api.librus.pl/OAuth/TokenJST"
|
||||
const val LIBRUS_API_AUTHORIZATION = "Mjg6ODRmZGQzYTg3YjAzZDNlYTZmZmU3NzdiNThiMzMyYjE="
|
||||
const val LIBRUS_API_SECRET_JST = "18b7c1ee08216f636a1b1a2440e68398"
|
||||
const val LIBRUS_API_CLIENT_ID_JST = "59"
|
||||
const val LIBRUS_API_CLIENT_ID_JST = "49"
|
||||
//const val LIBRUS_API_CLIENT_ID_JST_REFRESH = "42"
|
||||
|
||||
const val LIBRUS_JST_DEMO_CODE = "68656A21"
|
||||
@ -60,12 +59,40 @@ const val LIBRUS_SANDBOX_URL = "https://sandbox.librus.pl/index.php?action="
|
||||
const val LIBRUS_SYNERGIA_HOMEWORK_ATTACHMENT_URL = "https://synergia.librus.pl/homework/downloadFile"
|
||||
const val LIBRUS_SYNERGIA_MESSAGES_ATTACHMENT_URL = "https://synergia.librus.pl/wiadomosci/pobierz_zalacznik"
|
||||
|
||||
const val IDZIENNIK_USER_AGENT = SYNERGIA_USER_AGENT
|
||||
const val IDZIENNIK_WEB_URL = "https://iuczniowie.progman.pl/idziennik"
|
||||
const val IDZIENNIK_WEB_LOGIN = "login.aspx"
|
||||
const val IDZIENNIK_WEB_SETTINGS = "mod_panelRodzica/Ustawienia.aspx"
|
||||
const val IDZIENNIK_WEB_HOME = "mod_panelRodzica/StronaGlowna.aspx"
|
||||
const val IDZIENNIK_WEB_TIMETABLE = "mod_panelRodzica/plan/WS_Plan.asmx/pobierzPlanZajec"
|
||||
const val IDZIENNIK_WEB_GRADES = "mod_panelRodzica/oceny/WS_ocenyUcznia.asmx/pobierzOcenyUcznia"
|
||||
const val IDZIENNIK_WEB_MISSING_GRADES = "mod_panelRodzica/brak_ocen/WS_BrakOcenUcznia.asmx/pobierzBrakujaceOcenyUcznia"
|
||||
const val IDZIENNIK_WEB_EXAMS = "mod_panelRodzica/sprawdziany/mod_sprawdzianyPanel.asmx/pobierzListe"
|
||||
const val IDZIENNIK_WEB_HOMEWORK = "mod_panelRodzica/pracaDomowa/WS_pracaDomowa.asmx/pobierzPraceDomowe"
|
||||
const val IDZIENNIK_WEB_NOTICES = "mod_panelRodzica/uwagi/WS_uwagiUcznia.asmx/pobierzUwagiUcznia"
|
||||
const val IDZIENNIK_WEB_ATTENDANCE = "mod_panelRodzica/obecnosci/WS_obecnosciUcznia.asmx/pobierzObecnosciUcznia"
|
||||
const val IDZIENNIK_WEB_ANNOUNCEMENTS = "mod_panelRodzica/tabOgl/WS_tablicaOgloszen.asmx/GetOgloszenia"
|
||||
const val IDZIENNIK_WEB_MESSAGES_LIST = "mod_komunikator/WS_wiadomosci.asmx/PobierzListeWiadomosci"
|
||||
const val IDZIENNIK_WEB_GET_MESSAGE = "mod_komunikator/WS_wiadomosci.asmx/PobierzWiadomosc"
|
||||
const val IDZIENNIK_WEB_GET_RECIPIENT_LIST = "mod_komunikator/WS_wiadomosci.asmx/pobierzListeOdbiorcowPanelRodzic"
|
||||
const val IDZIENNIK_WEB_SEND_MESSAGE = "mod_komunikator/WS_wiadomosci.asmx/WyslijWiadomosc"
|
||||
const val IDZIENNIK_WEB_GET_ATTACHMENT = "mod_komunikator/Download.ashx"
|
||||
const val IDZIENNIK_WEB_GET_HOMEWORK = "mod_panelRodzica/pracaDomowa/WS_pracaDomowa.asmx/pobierzJednaPraceDomowa"
|
||||
const val IDZIENNIK_WEB_GET_HOMEWORK_ATTACHMENT = "mod_panelRodzica/pracaDomowa.aspx"
|
||||
|
||||
val IDZIENNIK_API_USER_AGENT = SYSTEM_USER_AGENT
|
||||
const val IDZIENNIK_API_URL = "https://iuczniowie.progman.pl/idziennik/api"
|
||||
const val IDZIENNIK_API_CURRENT_REGISTER = "Uczniowie/\$STUDENT_ID/AktualnyDziennik"
|
||||
const val IDZIENNIK_API_GRADES = "Uczniowie/\$STUDENT_ID/Oceny/" /* + semester */
|
||||
const val IDZIENNIK_API_MESSAGES_INBOX = "Wiadomosci/Odebrane"
|
||||
const val IDZIENNIK_API_MESSAGES_SENT = "Wiadomosci/Wyslane"
|
||||
|
||||
|
||||
val MOBIDZIENNIK_USER_AGENT = SYSTEM_USER_AGENT
|
||||
|
||||
const val VULCAN_HEBE_USER_AGENT = "Dart/2.10 (dart:io)"
|
||||
const val VULCAN_HEBE_APP_NAME = "DzienniczekPlus 2.0"
|
||||
const val VULCAN_HEBE_APP_VERSION = "22.09.02 (G)"
|
||||
const val VULCAN_HEBE_APP_VERSION = "21.02.09 (G)"
|
||||
private const val VULCAN_API_DEVICE_NAME_PREFIX = "Szkolny.eu "
|
||||
private const val VULCAN_API_DEVICE_NAME_SUFFIX = " - nie usuwać"
|
||||
val VULCAN_API_DEVICE_NAME by lazy {
|
||||
@ -82,30 +109,20 @@ const val VULCAN_HEBE_ENDPOINT_PUSH_ALL = "api/mobile/push/all"
|
||||
const val VULCAN_HEBE_ENDPOINT_TIMETABLE = "api/mobile/schedule"
|
||||
const val VULCAN_HEBE_ENDPOINT_TIMETABLE_CHANGES = "api/mobile/schedule/changes"
|
||||
const val VULCAN_HEBE_ENDPOINT_ADDRESSBOOK = "api/mobile/addressbook"
|
||||
const val VULCAN_HEBE_ENDPOINT_TEACHERS = "api/mobile/teacher"
|
||||
const val VULCAN_HEBE_ENDPOINT_EXAMS = "api/mobile/exam"
|
||||
const val VULCAN_HEBE_ENDPOINT_GRADES = "api/mobile/grade"
|
||||
const val VULCAN_HEBE_ENDPOINT_GRADE_SUMMARY = "api/mobile/grade/summary"
|
||||
const val VULCAN_HEBE_ENDPOINT_HOMEWORK = "api/mobile/homework"
|
||||
const val VULCAN_HEBE_ENDPOINT_NOTICES = "api/mobile/note"
|
||||
const val VULCAN_HEBE_ENDPOINT_ATTENDANCE = "api/mobile/lesson"
|
||||
const val VULCAN_HEBE_ENDPOINT_MESSAGEBOX = "api/mobile/messagebox"
|
||||
const val VULCAN_HEBE_ENDPOINT_MESSAGEBOX_ADDRESSBOOK = "api/mobile/messagebox/addressbook"
|
||||
const val VULCAN_HEBE_ENDPOINT_MESSAGEBOX_MESSAGES = "api/mobile/messagebox/message"
|
||||
const val VULCAN_HEBE_ENDPOINT_MESSAGEBOX_STATUS = "api/mobile/messagebox/message/status"
|
||||
const val VULCAN_HEBE_ENDPOINT_MESSAGEBOX_SEND = "api/mobile/messagebox/message"
|
||||
const val VULCAN_HEBE_ENDPOINT_MESSAGES = "api/mobile/message"
|
||||
const val VULCAN_HEBE_ENDPOINT_MESSAGES_STATUS = "api/mobile/message/status"
|
||||
const val VULCAN_HEBE_ENDPOINT_MESSAGES_SEND = "api/mobile/message"
|
||||
const val VULCAN_HEBE_ENDPOINT_LUCKY_NUMBER = "api/mobile/school/lucky"
|
||||
|
||||
const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}"
|
||||
|
||||
const val PODLASIE_API_VERSION = "1.0.62"
|
||||
const val PODLASIE_API_URL = "https://cpdklaser.zeto.bialystok.pl/api"
|
||||
const val PODLASIE_API_USER_ENDPOINT = "/pobierzDaneUcznia"
|
||||
const val PODLASIE_API_LOGOUT_DEVICES_ENDPOINT = "/wyczyscUrzadzenia"
|
||||
|
||||
const val USOS_API_OAUTH_REDIRECT_URL = "szkolny://redirect/usos"
|
||||
|
||||
val USOS_API_SCOPES by lazy { listOf(
|
||||
"offline_access",
|
||||
"studies",
|
||||
"grades",
|
||||
"events",
|
||||
) }
|
||||
|
@ -11,9 +11,8 @@ import android.content.Context
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationCompat.PRIORITY_MIN
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.Bundle
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.ext.Bundle
|
||||
import pl.szczodrzynski.edziennik.ext.pendingIntentFlag
|
||||
import pl.szczodrzynski.edziennik.receivers.SzkolnyReceiver
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@ -41,14 +40,14 @@ class EdziennikNotification(val app: App) {
|
||||
"task" to "TaskCancelRequest",
|
||||
"taskId" to taskId
|
||||
))
|
||||
return PendingIntent.getBroadcast(app, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or pendingIntentFlag()) as PendingIntent
|
||||
return PendingIntent.getBroadcast(app, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) as PendingIntent
|
||||
}
|
||||
private val closePendingIntent: PendingIntent
|
||||
get() {
|
||||
val intent = SzkolnyReceiver.getIntent(app, Bundle(
|
||||
"task" to "ServiceCloseRequest"
|
||||
))
|
||||
return PendingIntent.getBroadcast(app, 0, intent, pendingIntentFlag()) as PendingIntent
|
||||
return PendingIntent.getBroadcast(app, 0, intent, 0) as PendingIntent
|
||||
}
|
||||
|
||||
private fun errorCountText(): String? {
|
||||
|
@ -2,116 +2,115 @@ package pl.szczodrzynski.edziennik.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.api.models.Data
|
||||
import pl.szczodrzynski.edziennik.data.api.models.Feature
|
||||
import pl.szczodrzynski.edziennik.data.api.models.LoginMethod
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.EndpointTimer
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_NEVER
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod
|
||||
import pl.szczodrzynski.edziennik.ext.getFeatureTypesNecessary
|
||||
import pl.szczodrzynski.edziennik.ext.getFeatureTypesUnnecessary
|
||||
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
|
||||
|
||||
fun Data.prepare(
|
||||
features: List<Feature>,
|
||||
featureTypes: Set<FeatureType>?,
|
||||
onlyEndpoints: Set<Int>?,
|
||||
) {
|
||||
val loginType = this.loginStore.type
|
||||
val possibleLoginMethods = this.loginMethods.toMutableList()
|
||||
possibleLoginMethods += LoginMethod.values().filter {
|
||||
it.loginType == loginType && it.isPossible?.invoke(profile, loginStore) != false
|
||||
fun Data.prepare(loginMethods: List<LoginMethod>, features: List<Feature>, featureIds: List<Int>, viewId: Int?, onlyEndpoints: List<Int>?) {
|
||||
val data = this
|
||||
|
||||
val possibleLoginMethods = data.loginMethods.toMutableList()
|
||||
|
||||
for (loginMethod in loginMethods) {
|
||||
if (loginMethod.isPossible(profile, loginStore))
|
||||
possibleLoginMethods += loginMethod.loginMethodId
|
||||
}
|
||||
|
||||
//var highestLoginMethod = 0
|
||||
var possibleFeatures = mutableListOf<Feature>()
|
||||
val requiredLoginMethods = mutableListOf<LoginMethod>()
|
||||
var endpointList = mutableListOf<Feature>()
|
||||
val requiredLoginMethods = mutableListOf<Int>()
|
||||
|
||||
val syncFeatureTypes = when {
|
||||
featureTypes.isNotNullNorEmpty() -> featureTypes!!
|
||||
else -> getFeatureTypesUnnecessary()
|
||||
} + getFeatureTypesNecessary()
|
||||
val forceFeatureType = featureTypes?.singleOrNull()
|
||||
|
||||
this.targetEndpoints.clear()
|
||||
this.targetLoginMethods.clear()
|
||||
data.targetEndpointIds.clear()
|
||||
data.targetLoginMethodIds.clear()
|
||||
|
||||
// get all endpoints for every feature, only if possible to login and possible/necessary to sync
|
||||
for (featureId in syncFeatureTypes) {
|
||||
possibleFeatures += features.filter {
|
||||
it.featureType == featureId // feature ID matches
|
||||
for (featureId in featureIds) {
|
||||
features.filter {
|
||||
it.featureId == featureId // feature ID matches
|
||||
&& possibleLoginMethods.containsAll(it.requiredLoginMethods) // is possible to login
|
||||
&& it.shouldSync?.invoke(this) ?: true // is necessary/possible to sync
|
||||
&& it.shouldSync?.invoke(data) ?: true // is necessary/possible to sync
|
||||
}.let {
|
||||
endpointList.addAll(it)
|
||||
}
|
||||
}
|
||||
|
||||
val timestamp = System.currentTimeMillis()
|
||||
|
||||
possibleFeatures = possibleFeatures
|
||||
// sort the endpoint list by feature ID and priority
|
||||
.sortedWith(compareBy(Feature::featureType, Feature::priority))
|
||||
// select only the most important endpoint for each feature
|
||||
.distinctBy { it.featureType }
|
||||
.toMutableList()
|
||||
endpointList = endpointList
|
||||
// sort the endpoint list by feature ID and priority
|
||||
.sortedWith(compareBy(Feature::featureId, Feature::priority))
|
||||
// select only the most important endpoint for each feature
|
||||
.distinctBy { it.featureId }
|
||||
.toMutableList()
|
||||
// add all endpoint IDs and required login methods, filtering using timers
|
||||
.onEach { feature ->
|
||||
feature.endpointIds.forEach { endpoint ->
|
||||
if (onlyEndpoints?.contains(endpoint.first) == false)
|
||||
return@forEach
|
||||
(data.endpointTimers
|
||||
.singleOrNull { it.endpointId == endpoint.first } ?: EndpointTimer(data.profile?.id
|
||||
?: -1, endpoint.first))
|
||||
.let { timer ->
|
||||
if (
|
||||
onlyEndpoints?.contains(endpoint.first) == true ||
|
||||
timer.nextSync == SYNC_ALWAYS ||
|
||||
viewId != null && timer.viewId == viewId ||
|
||||
timer.nextSync != SYNC_NEVER && timer.nextSync < timestamp
|
||||
) {
|
||||
data.targetEndpointIds[endpoint.first] = timer.lastSync
|
||||
requiredLoginMethods.add(endpoint.second)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (feature in possibleFeatures) {
|
||||
// add all endpoint IDs and required login methods, filtering using timers
|
||||
feature.endpoints.forEach { endpoint ->
|
||||
if (onlyEndpoints?.contains(endpoint.first) == false)
|
||||
return@forEach
|
||||
val timer = this.endpointTimers
|
||||
.singleOrNull { it.endpointId == endpoint.first }
|
||||
?: EndpointTimer(this.profileId, endpoint.first)
|
||||
if (
|
||||
onlyEndpoints?.contains(endpoint.first) == true ||
|
||||
timer.nextSync == SYNC_ALWAYS ||
|
||||
forceFeatureType != null && timer.featureType == forceFeatureType ||
|
||||
timer.nextSync != SYNC_NEVER && timer.nextSync < timestamp
|
||||
) {
|
||||
this.targetEndpoints[endpoint.first] = timer.lastSync
|
||||
requiredLoginMethods += endpoint.second
|
||||
// check every login method for any dependencies
|
||||
for (loginMethodId in requiredLoginMethods) {
|
||||
var requiredLoginMethod: Int? = loginMethodId
|
||||
while (requiredLoginMethod != LOGIN_METHOD_NOT_NEEDED) {
|
||||
loginMethods.singleOrNull { it.loginMethodId == requiredLoginMethod }?.let { loginMethod ->
|
||||
if (requiredLoginMethod != null)
|
||||
data.targetLoginMethodIds.add(requiredLoginMethod!!)
|
||||
requiredLoginMethod = loginMethod.requiredLoginMethod(data.profile, data.loginStore)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check every login method for any dependencies
|
||||
for (loginMethod in requiredLoginMethods) {
|
||||
var requiredLoginMethod: LoginMethod? = loginMethod
|
||||
while (requiredLoginMethod != null) {
|
||||
this.targetLoginMethods += requiredLoginMethod
|
||||
requiredLoginMethod = requiredLoginMethod.requiredLoginMethod?.invoke(this.profile, this.loginStore)
|
||||
}
|
||||
}
|
||||
|
||||
// sort and distinct every login method and endpoint
|
||||
this.targetLoginMethods = this.targetLoginMethods.toHashSet().toMutableList()
|
||||
this.targetLoginMethods.sort()
|
||||
data.targetLoginMethodIds = data.targetLoginMethodIds.toHashSet().toMutableList()
|
||||
data.targetLoginMethodIds.sort()
|
||||
|
||||
//data.targetEndpointIds = data.targetEndpointIds.toHashSet().toMutableList()
|
||||
//data.targetEndpointIds.sort()
|
||||
|
||||
progressCount = targetLoginMethods.size + targetEndpoints.size
|
||||
progressCount = targetLoginMethodIds.size + targetEndpointIds.size
|
||||
progressStep = if (progressCount <= 0) 0f else 100f / progressCount.toFloat()
|
||||
}
|
||||
|
||||
fun Data.prepareFor(loginMethod: LoginMethod) {
|
||||
val loginType = loginStore.type
|
||||
fun Data.prepareFor(loginMethods: List<LoginMethod>, loginMethodId: Int) {
|
||||
val possibleLoginMethods = this.loginMethods.toMutableList()
|
||||
possibleLoginMethods += LoginMethod.values().filter {
|
||||
it.loginType == loginType && it.isPossible?.invoke(profile, loginStore) != false
|
||||
|
||||
loginMethods.forEach {
|
||||
if (it.isPossible(profile, loginStore))
|
||||
possibleLoginMethods += it.loginMethodId
|
||||
}
|
||||
|
||||
this.targetLoginMethods.clear()
|
||||
targetLoginMethodIds.clear()
|
||||
|
||||
// check the login method for any dependencies
|
||||
var requiredLoginMethod: LoginMethod? = loginMethod
|
||||
while (requiredLoginMethod != null) {
|
||||
this.targetLoginMethods += requiredLoginMethod
|
||||
requiredLoginMethod = requiredLoginMethod.requiredLoginMethod?.invoke(this.profile, this.loginStore)
|
||||
var requiredLoginMethod: Int? = loginMethodId
|
||||
while (requiredLoginMethod != LOGIN_METHOD_NOT_NEEDED) {
|
||||
loginMethods.singleOrNull { it.loginMethodId == requiredLoginMethod }?.let {
|
||||
if (requiredLoginMethod != null)
|
||||
targetLoginMethodIds.add(requiredLoginMethod!!)
|
||||
requiredLoginMethod = it.requiredLoginMethod(profile, loginStore)
|
||||
}
|
||||
}
|
||||
|
||||
// sort and distinct every login method
|
||||
this.targetLoginMethods = this.targetLoginMethods.toHashSet().toMutableList()
|
||||
this.targetLoginMethods.sort()
|
||||
targetLoginMethodIds = targetLoginMethodIds.toHashSet().toMutableList()
|
||||
targetLoginMethodIds.sort()
|
||||
|
||||
progressCount = 0
|
||||
progressStep = 0f
|
||||
|
@ -58,7 +58,11 @@ const val ERROR_INVALID_LOGIN_MODE = 110
|
||||
const val ERROR_LOGIN_METHOD_NOT_SATISFIED = 111
|
||||
const val ERROR_NOT_IMPLEMENTED = 112
|
||||
const val ERROR_FILE_DOWNLOAD = 113
|
||||
const val ERROR_REQUIRES_USER_ACTION = 114
|
||||
|
||||
const val ERROR_NO_STUDENTS_IN_ACCOUNT = 115
|
||||
|
||||
const val ERROR_CAPTCHA_NEEDED = 3000
|
||||
const val ERROR_CAPTCHA_LIBRUS_PORTAL = 3001
|
||||
|
||||
const val ERROR_API_PDO_ERROR = 5000
|
||||
const val ERROR_API_INVALID_CLIENT = 5001
|
||||
@ -191,21 +195,21 @@ const val ERROR_VULCAN_HEBE_FIREBASE_ERROR = 362
|
||||
const val ERROR_VULCAN_HEBE_CERTIFICATE_GONE = 363
|
||||
const val ERROR_VULCAN_HEBE_SERVER_ERROR = 364
|
||||
const val ERROR_VULCAN_HEBE_ENTITY_NOT_FOUND = 365
|
||||
const val ERROR_VULCAN_HEBE_MISSING_SENDER_ENTRY = 366
|
||||
const val ERROR_VULCAN_API_DEPRECATED = 390
|
||||
|
||||
const val ERROR_LOGIN_EDUDZIENNIK_WEB_INVALID_LOGIN = 501
|
||||
const val ERROR_LOGIN_EDUDZIENNIK_WEB_OTHER = 510
|
||||
const val ERROR_LOGIN_EDUDZIENNIK_WEB_NO_SESSION_ID = 511
|
||||
const val ERROR_EDUDZIENNIK_WEB_LIMITED_ACCESS = 521
|
||||
const val ERROR_EDUDZIENNIK_WEB_SESSION_EXPIRED = 522
|
||||
const val ERROR_EDUDZIENNIK_WEB_TEAM_MISSING = 530
|
||||
|
||||
const val ERROR_LOGIN_PODLASIE_API_INVALID_TOKEN = 601
|
||||
const val ERROR_LOGIN_PODLASIE_API_DEVICE_LIMIT = 602
|
||||
const val ERROR_PODLASIE_API_NO_TOKEN = 630
|
||||
const val ERROR_PODLASIE_API_OTHER = 631
|
||||
const val ERROR_PODLASIE_API_DATA_MISSING = 632
|
||||
|
||||
const val ERROR_USOS_OAUTH_GOT_DIFFERENT_TOKEN = 702
|
||||
const val ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE = 703
|
||||
const val ERROR_USOS_NO_STUDENT_PROGRAMMES = 704
|
||||
const val ERROR_USOS_API_INCOMPLETE_RESPONSE = 705
|
||||
const val ERROR_USOS_API_MISSING_RESPONSE = 706
|
||||
|
||||
const val ERROR_TEMPLATE_WEB_OTHER = 801
|
||||
|
||||
const val EXCEPTION_API_TASK = 900
|
||||
@ -219,6 +223,8 @@ const val EXCEPTION_MOBIDZIENNIK_WEB_FILE_REQUEST = 908
|
||||
const val EXCEPTION_LIBRUS_MESSAGES_FILE_REQUEST = 909
|
||||
const val EXCEPTION_NOTIFY = 910
|
||||
const val EXCEPTION_LIBRUS_MESSAGES_REQUEST = 911
|
||||
const val EXCEPTION_EDUDZIENNIK_WEB_REQUEST = 920
|
||||
const val EXCEPTION_EDUDZIENNIK_FILE_REQUEST = 921
|
||||
const val ERROR_ONEDRIVE_DOWNLOAD = 930
|
||||
const val EXCEPTION_VULCAN_WEB_LOGIN = 931
|
||||
const val EXCEPTION_VULCAN_WEB_REQUEST = 932
|
||||
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-29.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
|
||||
|
||||
internal const val FEATURE_TIMETABLE = 1
|
||||
internal const val FEATURE_AGENDA = 2
|
||||
internal const val FEATURE_GRADES = 3
|
||||
internal const val FEATURE_HOMEWORK = 4
|
||||
internal const val FEATURE_BEHAVIOUR = 5
|
||||
internal const val FEATURE_ATTENDANCE = 6
|
||||
internal const val FEATURE_MESSAGES_INBOX = 7
|
||||
internal const val FEATURE_MESSAGES_SENT = 8
|
||||
internal const val FEATURE_ANNOUNCEMENTS = 9
|
||||
|
||||
internal const val FEATURE_ALWAYS_NEEDED = 100
|
||||
internal const val FEATURE_STUDENT_INFO = 101
|
||||
internal const val FEATURE_STUDENT_NUMBER = 109
|
||||
internal const val FEATURE_SCHOOL_INFO = 102
|
||||
internal const val FEATURE_CLASS_INFO = 103
|
||||
internal const val FEATURE_TEAM_INFO = 104
|
||||
internal const val FEATURE_LUCKY_NUMBER = 105
|
||||
internal const val FEATURE_TEACHERS = 106
|
||||
internal const val FEATURE_SUBJECTS = 107
|
||||
internal const val FEATURE_CLASSROOMS = 108
|
||||
internal const val FEATURE_PUSH_CONFIG = 120
|
||||
|
||||
object Features {
|
||||
private fun getAllNecessary(): List<Int> = listOf(
|
||||
FEATURE_ALWAYS_NEEDED,
|
||||
FEATURE_PUSH_CONFIG,
|
||||
FEATURE_STUDENT_INFO,
|
||||
FEATURE_STUDENT_NUMBER,
|
||||
FEATURE_SCHOOL_INFO,
|
||||
FEATURE_CLASS_INFO,
|
||||
FEATURE_TEAM_INFO,
|
||||
FEATURE_LUCKY_NUMBER,
|
||||
FEATURE_TEACHERS,
|
||||
FEATURE_SUBJECTS,
|
||||
FEATURE_CLASSROOMS)
|
||||
|
||||
private fun getAllFeatures(): List<Int> = listOf(
|
||||
FEATURE_TIMETABLE,
|
||||
FEATURE_AGENDA,
|
||||
FEATURE_GRADES,
|
||||
FEATURE_HOMEWORK,
|
||||
FEATURE_BEHAVIOUR,
|
||||
FEATURE_ATTENDANCE,
|
||||
FEATURE_MESSAGES_INBOX,
|
||||
FEATURE_MESSAGES_SENT,
|
||||
FEATURE_ANNOUNCEMENTS)
|
||||
|
||||
fun getAllIds(): List<Int> = getAllFeatures() + getAllNecessary()
|
||||
|
||||
fun getIdsByView(targetId: Int, targetType: Int): List<Int> {
|
||||
return (when (targetId) {
|
||||
DRAWER_ITEM_HOME -> getAllFeatures()
|
||||
DRAWER_ITEM_TIMETABLE -> listOf(FEATURE_TIMETABLE)
|
||||
DRAWER_ITEM_AGENDA -> listOf(FEATURE_AGENDA)
|
||||
DRAWER_ITEM_GRADES -> listOf(FEATURE_GRADES)
|
||||
DRAWER_ITEM_MESSAGES -> when (targetType) {
|
||||
TYPE_RECEIVED -> listOf(FEATURE_MESSAGES_INBOX)
|
||||
TYPE_SENT -> listOf(FEATURE_MESSAGES_SENT)
|
||||
else -> listOf(FEATURE_MESSAGES_INBOX, FEATURE_MESSAGES_SENT)
|
||||
}
|
||||
DRAWER_ITEM_HOMEWORK -> listOf(FEATURE_HOMEWORK)
|
||||
DRAWER_ITEM_BEHAVIOUR -> listOf(FEATURE_BEHAVIOUR)
|
||||
DRAWER_ITEM_ATTENDANCE -> listOf(FEATURE_ATTENDANCE)
|
||||
DRAWER_ITEM_ANNOUNCEMENTS -> listOf(FEATURE_ANNOUNCEMENTS)
|
||||
else -> getAllFeatures()
|
||||
} + getAllNecessary()).sorted()
|
||||
}
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-20.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login.EdudziennikLoginWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginApi
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginMessages
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginPortal
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginSynergia
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLoginApi2
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLoginWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login.PodlasieLoginApi
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginApi
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginHebe
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginWebMain
|
||||
import pl.szczodrzynski.edziennik.data.api.models.LoginMethod
|
||||
|
||||
// librus
|
||||
// mobidziennik
|
||||
// idziennik [*]
|
||||
// vulcan
|
||||
// mobireg
|
||||
|
||||
const val SYNERGIA_API_ENABLED = false
|
||||
|
||||
|
||||
const val LOGIN_TYPE_IDZIENNIK = 3
|
||||
|
||||
const val LOGIN_TYPE_TEMPLATE = 21
|
||||
|
||||
// LOGIN MODES
|
||||
const val LOGIN_MODE_TEMPLATE_WEB = 0
|
||||
|
||||
// LOGIN METHODS
|
||||
const val LOGIN_METHOD_NOT_NEEDED = -1
|
||||
const val LOGIN_METHOD_TEMPLATE_WEB = 100
|
||||
const val LOGIN_METHOD_TEMPLATE_API = 200
|
||||
|
||||
const val LOGIN_TYPE_LIBRUS = 2
|
||||
const val LOGIN_MODE_LIBRUS_EMAIL = 0
|
||||
const val LOGIN_MODE_LIBRUS_SYNERGIA = 1
|
||||
const val LOGIN_MODE_LIBRUS_JST = 2
|
||||
const val LOGIN_METHOD_LIBRUS_PORTAL = 100
|
||||
const val LOGIN_METHOD_LIBRUS_API = 200
|
||||
const val LOGIN_METHOD_LIBRUS_SYNERGIA = 300
|
||||
const val LOGIN_METHOD_LIBRUS_MESSAGES = 400
|
||||
val librusLoginMethods = listOf(
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_PORTAL, LibrusLoginPortal::class.java)
|
||||
.withIsPossible { _, loginStore ->
|
||||
loginStore.mode == LOGIN_MODE_LIBRUS_EMAIL
|
||||
}
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED },
|
||||
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_API, LibrusLoginApi::class.java)
|
||||
.withIsPossible { _, loginStore ->
|
||||
loginStore.mode != LOGIN_MODE_LIBRUS_SYNERGIA || SYNERGIA_API_ENABLED
|
||||
}
|
||||
.withRequiredLoginMethod { _, loginStore ->
|
||||
if (loginStore.mode == LOGIN_MODE_LIBRUS_EMAIL) LOGIN_METHOD_LIBRUS_PORTAL else LOGIN_METHOD_NOT_NEEDED
|
||||
},
|
||||
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_SYNERGIA, LibrusLoginSynergia::class.java)
|
||||
.withIsPossible { _, loginStore -> !loginStore.hasLoginData("fakeLogin") }
|
||||
.withRequiredLoginMethod { profile, _ ->
|
||||
if (profile?.hasStudentData("accountPassword") == false || true) LOGIN_METHOD_LIBRUS_API else LOGIN_METHOD_NOT_NEEDED
|
||||
},
|
||||
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_MESSAGES, LibrusLoginMessages::class.java)
|
||||
.withIsPossible { _, loginStore -> !loginStore.hasLoginData("fakeLogin") }
|
||||
.withRequiredLoginMethod { profile, _ ->
|
||||
if (profile?.hasStudentData("accountPassword") == false || true) LOGIN_METHOD_LIBRUS_SYNERGIA else LOGIN_METHOD_NOT_NEEDED
|
||||
}
|
||||
)
|
||||
|
||||
const val LOGIN_TYPE_MOBIDZIENNIK = 1
|
||||
const val LOGIN_MODE_MOBIDZIENNIK_WEB = 0
|
||||
const val LOGIN_METHOD_MOBIDZIENNIK_WEB = 100
|
||||
const val LOGIN_METHOD_MOBIDZIENNIK_API2 = 300
|
||||
val mobidziennikLoginMethods = listOf(
|
||||
LoginMethod(LOGIN_TYPE_MOBIDZIENNIK, LOGIN_METHOD_MOBIDZIENNIK_WEB, MobidziennikLoginWeb::class.java)
|
||||
.withIsPossible { _, _ -> true }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED },
|
||||
|
||||
LoginMethod(LOGIN_TYPE_MOBIDZIENNIK, LOGIN_METHOD_MOBIDZIENNIK_API2, MobidziennikLoginApi2::class.java)
|
||||
.withIsPossible { profile, _ -> profile?.getStudentData("email", null) != null }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
|
||||
)
|
||||
|
||||
const val LOGIN_TYPE_VULCAN = 4
|
||||
const val LOGIN_MODE_VULCAN_API = 0
|
||||
const val LOGIN_MODE_VULCAN_WEB = 1
|
||||
const val LOGIN_MODE_VULCAN_HEBE = 2
|
||||
const val LOGIN_METHOD_VULCAN_WEB_MAIN = 100
|
||||
const val LOGIN_METHOD_VULCAN_WEB_NEW = 200
|
||||
const val LOGIN_METHOD_VULCAN_WEB_OLD = 300
|
||||
const val LOGIN_METHOD_VULCAN_WEB_MESSAGES = 400
|
||||
const val LOGIN_METHOD_VULCAN_HEBE = 600
|
||||
val vulcanLoginMethods = listOf(
|
||||
LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_MAIN, VulcanLoginWebMain::class.java)
|
||||
.withIsPossible { _, loginStore -> loginStore.hasLoginData("webHost") }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED },
|
||||
|
||||
/*LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_NEW, VulcanLoginWebNew::class.java)
|
||||
.withIsPossible { _, _ -> false }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_VULCAN_WEB_MAIN },
|
||||
|
||||
LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_OLD, VulcanLoginWebOld::class.java)
|
||||
.withIsPossible { _, _ -> false }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_VULCAN_WEB_MAIN },*/
|
||||
|
||||
LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_HEBE, VulcanLoginHebe::class.java)
|
||||
.withIsPossible { _, loginStore ->
|
||||
loginStore.mode != LOGIN_MODE_VULCAN_API
|
||||
}
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
|
||||
)
|
||||
|
||||
const val LOGIN_TYPE_EDUDZIENNIK = 5
|
||||
const val LOGIN_MODE_EDUDZIENNIK_WEB = 0
|
||||
const val LOGIN_METHOD_EDUDZIENNIK_WEB = 100
|
||||
val edudziennikLoginMethods = listOf(
|
||||
LoginMethod(LOGIN_TYPE_EDUDZIENNIK, LOGIN_METHOD_EDUDZIENNIK_WEB, EdudziennikLoginWeb::class.java)
|
||||
.withIsPossible { _, _ -> true }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
|
||||
)
|
||||
|
||||
const val LOGIN_TYPE_PODLASIE = 6
|
||||
const val LOGIN_MODE_PODLASIE_API = 0
|
||||
const val LOGIN_METHOD_PODLASIE_API = 100
|
||||
val podlasieLoginMethods = listOf(
|
||||
LoginMethod(LOGIN_TYPE_PODLASIE, LOGIN_METHOD_PODLASIE_API, PodlasieLoginApi::class.java)
|
||||
.withIsPossible { _, _ -> true }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
|
||||
)
|
||||
|
||||
val templateLoginMethods = listOf(
|
||||
LoginMethod(LOGIN_TYPE_TEMPLATE, LOGIN_METHOD_TEMPLATE_WEB, TemplateLoginWeb::class.java)
|
||||
.withIsPossible { _, _ -> true }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED },
|
||||
|
||||
LoginMethod(LOGIN_TYPE_TEMPLATE, LOGIN_METHOD_TEMPLATE_API, TemplateLoginApi::class.java)
|
||||
.withIsPossible { _, _ -> true }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_TEMPLATE_WEB }
|
||||
)
|
@ -16,33 +16,6 @@ object Regexes {
|
||||
"""[^0-9]""".toRegex()
|
||||
}
|
||||
|
||||
val HTML_BR by lazy {
|
||||
"""<br\s?/?>""".toRegex()
|
||||
}
|
||||
|
||||
val MESSAGE_META by lazy {
|
||||
"""^\[META:([A-z0-9-&=]+)]""".toRegex()
|
||||
}
|
||||
|
||||
val HTML_INPUT_HIDDEN by lazy {
|
||||
"""<input .*?type="hidden".+?>""".toRegex()
|
||||
}
|
||||
val HTML_INPUT_NAME by lazy {
|
||||
"""name="(.+?)"""".toRegex()
|
||||
}
|
||||
val HTML_INPUT_VALUE by lazy {
|
||||
"""value="(.+?)"""".toRegex()
|
||||
}
|
||||
val HTML_CSRF_TOKEN by lazy {
|
||||
"""name="csrf-token" content="([A-z0-9=+/\-_]+?)"""".toRegex()
|
||||
}
|
||||
val HTML_FORM_ACTION by lazy {
|
||||
"""<form .*?action="(.+?)"""".toRegex()
|
||||
}
|
||||
val HTML_RECAPTCHA_KEY by lazy {
|
||||
"""data-sitekey="(.+?)"""".toRegex()
|
||||
}
|
||||
|
||||
|
||||
|
||||
val MOBIDZIENNIK_GRADES_SUBJECT_NAME by lazy {
|
||||
@ -77,16 +50,15 @@ object Regexes {
|
||||
"""events: (.+),$""".toRegex(RegexOption.MULTILINE)
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_WEB_ATTACHMENT by lazy {
|
||||
"""href="https://.+?\.mobidziennik.pl/.+?&(?:amp;)?zalacznik(_rozwiazania)?=([0-9]+)".+?>(.+?)(?: <small.+?\(([0-9.]+)\s(M|K|G|)B\)</small>)?</a>""".toRegex()
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_MESSAGE_READ_DATE by lazy {
|
||||
"""czas przeczytania:.+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_MESSAGE_SENT_READ_DATE by lazy {
|
||||
""".+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_MESSAGE_ATTACHMENT by lazy {
|
||||
"""href="https://.+?\.mobidziennik.pl/.+?&(?:amp;)?zalacznik=([0-9]+)"(?:.+?<small.+?\(([0-9.]+)\s(M|K|G|)B\))*""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_MESSAGE_SENT_READ_BY by lazy {
|
||||
"""([0-9]+)/([0-9]+)""".toRegex()
|
||||
}
|
||||
@ -128,43 +100,61 @@ object Regexes {
|
||||
"""<strong>(.+?)</strong>\s*<small>\s*\((.+?),\s*(.+?)\)""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_MOBILE_HOMEWORK_ROW by lazy {
|
||||
val MOBIDZIENNIK_HOMEWORK_ROW by lazy {
|
||||
"""class="rowRolling">(.+?</div>\s*</td>)""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_MOBILE_HOMEWORK_ITEM by lazy {
|
||||
val MOBIDZIENNIK_HOMEWORK_ITEM by lazy {
|
||||
"""<p><b>(.+?):</b>\s*(.+?)\s*</p>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_MOBILE_HOMEWORK_BODY by lazy {
|
||||
val MOBIDZIENNIK_HOMEWORK_BODY by lazy {
|
||||
"""Treść:</b>(.+?)<p><b>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_MOBILE_HOMEWORK_ID by lazy {
|
||||
"""name="id_zadania" value="([0-9]+)"""".toRegex(DOT_MATCHES_ALL)
|
||||
val MOBIDZIENNIK_HOMEWORK_ID by lazy {
|
||||
"""zadanieFormularz\(([0-9]+),""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_MOBILE_HOMEWORK_ATTACHMENT by lazy {
|
||||
val MOBIDZIENNIK_HOMEWORK_ATTACHMENT by lazy {
|
||||
"""zalacznik(_zadania)?=([0-9]+)'.+?word-break">(.+?)</td>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_WEB_HOMEWORK_ADDED_DATE by lazy {
|
||||
"""Wpisał\(a\):</td>\s+<th>\s+(.+?), (.+?), ([0-9]{1,2}) (.+?) ([0-9]{4}), godzina ([0-9:]+)""".toRegex()
|
||||
|
||||
|
||||
val IDZIENNIK_LOGIN_HIDDEN_FIELDS by lazy {
|
||||
"""<input type="hidden".+?name="([A-z0-9_]+)?".+?value="([A-z0-9_+-/=]+)?".+?>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_LOGIN_ERROR by lazy {
|
||||
"""id="spanErrorMessage">(.*?)</""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_LOGIN_FIRST_ACCOUNT_NAME by lazy {
|
||||
"""Imię i nazwisko:.+?">(.+?)</div>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_LOGIN_FIRST_IS_PARENT by lazy {
|
||||
"""id="ctl00_CzyRodzic" value="([01])" />""".toRegex()
|
||||
}
|
||||
val IDZIENNIK_LOGIN_FIRST_SCHOOL_YEAR by lazy {
|
||||
"""name="ctl00\${"$"}dxComboRokSzkolny".+?selected="selected".*?value="([0-9]+)">([0-9]+)/([0-9]+)<""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_LOGIN_FIRST_STUDENT_SELECT by lazy {
|
||||
"""<select.*?name="ctl00\${"$"}dxComboUczniowie".*?</select>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_LOGIN_FIRST_STUDENT by lazy {
|
||||
"""<option.*?value="([0-9]+)"\sdata-id-ucznia="([A-z0-9]+?)".*?>(.+?)\s(.+?)\s*\((.+?),\s*(.+?)\)</option>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_MESSAGES_RECIPIENT_PARENT by lazy {
|
||||
"""(.+?)\s\((.+)\)""".toRegex()
|
||||
}
|
||||
/*<span id="ctl00_spanSzczesliwyLos">Szczęśliwy los na dzisiaj to <b>19</b>. Los na jutro to <b>22</b></span>*/
|
||||
val IDZIENNIK_WEB_LUCKY_NUMBER by lazy {
|
||||
"""dzisiaj to <b>([0-9]+)</b>""".toRegex()
|
||||
}
|
||||
val IDZIENNIK_WEB_SELECTED_REGISTER by lazy {
|
||||
"""selected="selected" value="([0-9]+)" data-id-ucznia""".toRegex()
|
||||
}
|
||||
|
||||
|
||||
val MOBIDZIENNIK_TIMETABLE_TOP by lazy {
|
||||
"""<div class="plansc_top">.+?</div></div>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_TIMETABLE_CELL by lazy {
|
||||
"""<div class="plansc_cnt_w" style="(.+?)">.+?style="(.+?)".+?title="(.+?)".+?>\s+(.+?)\s+</div>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_TIMETABLE_LEFT by lazy {
|
||||
"""<div class="plansc_godz">.+?</div></div>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
|
||||
val MOBIDZIENNIK_EVENT_CONTENT by lazy {
|
||||
"""<h1>(.+?) <small>\(wpisał\(a\) (.+?) w dniu ([0-9-]{10})\).+?<strong>(.+?)</strong><br""".toRegex(DOT_MATCHES_ALL)
|
||||
val VULCAN_SHIFT_ANNOTATION by lazy {
|
||||
"""\(przeniesiona (z|na) lekcj[ię] ([0-9]+), (.+)\)""".toRegex()
|
||||
}
|
||||
|
||||
|
||||
val VULCAN_WEB_PERMISSIONS by lazy {
|
||||
"""permissions: '([A-z0-9/=+\-_|]+?)'""".toRegex()
|
||||
}
|
||||
@ -182,6 +172,82 @@ object Regexes {
|
||||
}
|
||||
|
||||
|
||||
|
||||
val EDUDZIENNIK_STUDENTS_START by lazy {
|
||||
"""<li><a href="/Students/([\w-_]+?)/start/">(.*?)</a>""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_ACCOUNT_NAME_START by lazy {
|
||||
"""<span id='user_dn'>(.*?)</span>""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_SUBJECTS_START by lazy {
|
||||
"""<a class="menu-course" href="/Students/[\w-_]+?/Courses/([\w-_]+)/">(.+?)</a>""".toRegex()
|
||||
}
|
||||
|
||||
val EDUDZIENNIK_ATTENDANCE_ENTRIES by lazy {
|
||||
"""<td id="([\d-]+?):(\d+?)".*?>(.+?)</td>""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_ATTENDANCE_TYPES by lazy {
|
||||
"""<div class="info">.*?<p>(.*?)</p>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val EDUDZIENNIK_ATTENDANCE_TYPE by lazy {
|
||||
"""\((.+?)\) (.+)""".toRegex()
|
||||
}
|
||||
|
||||
val EDUDZIENNIK_ANNOUNCEMENT_DESCRIPTION by lazy {
|
||||
"""<div class="desc">.*?<p>(.*?)</p>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val EDUDZIENNIK_HOMEWORK_DESCRIPTION by lazy {
|
||||
"""<div class="desc">(.*?)</div>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
val EDUDZIENNIK_SUBJECT_ID by lazy {
|
||||
"""/Courses/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_GRADE_ID by lazy {
|
||||
"""/Grades/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_EXAM_ID by lazy {
|
||||
"""/Evaluations/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_EVENT_TYPE_ID by lazy {
|
||||
"""/GradeLabels/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_ANNOUNCEMENT_ID by lazy {
|
||||
"""/Announcement/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_HOMEWORK_ID by lazy {
|
||||
"""/Homework/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_TEACHER_ID by lazy {
|
||||
"""/Teachers/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_EVENT_ID by lazy {
|
||||
"""/KlassEvent/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_NOTE_ID by lazy {
|
||||
"""/RegistryNotes/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
|
||||
val EDUDZIENNIK_SCHOOL_DETAIL_ID by lazy {
|
||||
"""<a id="School_detail".*?/School/([\w-_]+?)/""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val EDUDZIENNIK_SCHOOL_DETAIL_NAME by lazy {
|
||||
"""</li>.*?<p>(.*?)</p>.*?<li>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val EDUDZIENNIK_CLASS_DETAIL_ID by lazy {
|
||||
"""<a id="Klass_detail".*?/Klass/([\w-_]+?)/""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val EDUDZIENNIK_CLASS_DETAIL_NAME by lazy {
|
||||
"""<a id="Klass_detail".*?>(.*?)</a>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
val EDUDZIENNIK_TEACHERS by lazy {
|
||||
"""<div class="teacher">.*?<p>(.+?) (.+?)</p>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
val LINKIFY_DATE_YMD by lazy {
|
||||
"""(1\d{3}|20\d{2})[\-./](1[0-2]|0?\d)[\-./]([1-2]\d|3[0-1]|0?\d)""".toRegex()
|
||||
}
|
||||
|
@ -6,32 +6,27 @@ package pl.szczodrzynski.edziennik.data.api.edziennik
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_PROFILE_ARCHIVED
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.Edudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.Librus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.Mobidziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.Podlasie
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.template.Template
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.Usos
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.Vulcan
|
||||
import pl.szczodrzynski.edziennik.data.api.events.RegisterAvailabilityEvent
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
||||
import pl.szczodrzynski.edziennik.data.api.task.IApiTask
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.ext.isBeforeYear
|
||||
import pl.szczodrzynski.edziennik.ext.shouldArchive
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type
|
||||
|
||||
open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTask(profileId) {
|
||||
companion object {
|
||||
@ -42,10 +37,10 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
||||
|
||||
fun firstLogin(loginStore: LoginStore) = EdziennikTask(-1, FirstLoginRequest(loginStore))
|
||||
fun sync() = EdziennikTask(-1, SyncRequest())
|
||||
fun syncProfile(profileId: Int, featureTypes: Set<FeatureType>? = null, onlyEndpoints: Set<Int>? = null, arguments: JsonObject? = null) = EdziennikTask(profileId, SyncProfileRequest(featureTypes, onlyEndpoints, arguments))
|
||||
fun syncProfileList(profileList: Set<Int>) = EdziennikTask(-1, SyncProfileListRequest(profileList))
|
||||
fun syncProfile(profileId: Int, viewIds: List<Pair<Int, Int>>? = null, onlyEndpoints: List<Int>? = null, arguments: JsonObject? = null) = EdziennikTask(profileId, SyncProfileRequest(viewIds, onlyEndpoints, arguments))
|
||||
fun syncProfileList(profileList: List<Int>) = EdziennikTask(-1, SyncProfileListRequest(profileList))
|
||||
fun messageGet(profileId: Int, message: MessageFull) = EdziennikTask(profileId, MessageGetRequest(message))
|
||||
fun messageSend(profileId: Int, recipients: Set<Teacher>, subject: String, text: String) = EdziennikTask(profileId, MessageSendRequest(recipients, subject, text))
|
||||
fun messageSend(profileId: Int, recipients: List<Teacher>, subject: String, text: String) = EdziennikTask(profileId, MessageSendRequest(recipients, subject, text))
|
||||
fun announcementsRead(profileId: Int) = EdziennikTask(profileId, AnnouncementsReadRequest())
|
||||
fun announcementGet(profileId: Int, announcement: AnnouncementFull) = EdziennikTask(profileId, AnnouncementGetRequest(announcement))
|
||||
fun attachmentGet(profileId: Int, owner: Any, attachmentId: Long, attachmentName: String) = EdziennikTask(profileId, AttachmentGetRequest(owner, attachmentId, attachmentName))
|
||||
@ -95,31 +90,45 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
||||
return
|
||||
}
|
||||
|
||||
val error = app.availabilityManager.check(profile)
|
||||
when (error?.type) {
|
||||
Type.NOT_AVAILABLE -> {
|
||||
profile.registerName?.also { registerName ->
|
||||
var status = app.config.sync.registerAvailability[registerName]
|
||||
if (status == null || status.nextCheckAt < currentTimeUnix()) {
|
||||
val api = SzkolnyApi(app)
|
||||
api.runCatching({
|
||||
val availability = getRegisterAvailability()
|
||||
app.config.sync.registerAvailability = availability
|
||||
status = availability[registerName]
|
||||
}, onError = {
|
||||
val apiError = it.toApiError(TAG)
|
||||
if (apiError.errorCode == ERROR_API_INVALID_SIGNATURE) {
|
||||
return@also
|
||||
}
|
||||
taskCallback.onError(apiError)
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
if (status?.available != true
|
||||
|| status?.minVersionCode ?: BuildConfig.VERSION_CODE > BuildConfig.VERSION_CODE) {
|
||||
if (EventBus.getDefault().hasSubscriberForEvent(RegisterAvailabilityEvent::class.java)) {
|
||||
EventBus.getDefault().postSticky(RegisterAvailabilityEvent())
|
||||
EventBus.getDefault().postSticky(
|
||||
RegisterAvailabilityEvent(app.config.sync.registerAvailability)
|
||||
)
|
||||
}
|
||||
cancel()
|
||||
taskCallback.onCompleted()
|
||||
return
|
||||
}
|
||||
Type.API_ERROR -> {
|
||||
taskCallback.onError(error.apiError!!)
|
||||
return
|
||||
}
|
||||
else -> return@let
|
||||
}
|
||||
}
|
||||
|
||||
edziennikInterface = when (loginStore.type) {
|
||||
LoginType.LIBRUS -> Librus(app, profile, loginStore, taskCallback)
|
||||
LoginType.MOBIDZIENNIK -> Mobidziennik(app, profile, loginStore, taskCallback)
|
||||
LoginType.VULCAN -> Vulcan(app, profile, loginStore, taskCallback)
|
||||
LoginType.PODLASIE -> Podlasie(app, profile, loginStore, taskCallback)
|
||||
LoginType.TEMPLATE -> Template(app, profile, loginStore, taskCallback)
|
||||
LoginType.USOS -> Usos(app, profile, loginStore, taskCallback)
|
||||
LOGIN_TYPE_LIBRUS -> Librus(app, profile, loginStore, taskCallback)
|
||||
LOGIN_TYPE_MOBIDZIENNIK -> Mobidziennik(app, profile, loginStore, taskCallback)
|
||||
LOGIN_TYPE_VULCAN -> Vulcan(app, profile, loginStore, taskCallback)
|
||||
LOGIN_TYPE_EDUDZIENNIK -> Edudziennik(app, profile, loginStore, taskCallback)
|
||||
LOGIN_TYPE_PODLASIE -> Podlasie(app, profile, loginStore, taskCallback)
|
||||
LOGIN_TYPE_TEMPLATE -> Template(app, profile, loginStore, taskCallback)
|
||||
else -> null
|
||||
}
|
||||
if (edziennikInterface == null) {
|
||||
@ -128,7 +137,9 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
||||
|
||||
when (request) {
|
||||
is SyncProfileRequest -> edziennikInterface?.sync(
|
||||
featureTypes = request.featureTypes,
|
||||
featureIds = request.viewIds?.flatMap { Features.getIdsByView(it.first, it.second) }
|
||||
?: Features.getAllIds(),
|
||||
viewId = request.viewIds?.get(0)?.first,
|
||||
onlyEndpoints = request.onlyEndpoints,
|
||||
arguments = request.arguments)
|
||||
is MessageGetRequest -> edziennikInterface?.getMessage(request.message)
|
||||
@ -153,10 +164,10 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
||||
|
||||
data class FirstLoginRequest(val loginStore: LoginStore)
|
||||
class SyncRequest
|
||||
data class SyncProfileRequest(val featureTypes: Set<FeatureType>? = null, val onlyEndpoints: Set<Int>? = null, val arguments: JsonObject? = null)
|
||||
data class SyncProfileListRequest(val profileList: Set<Int>)
|
||||
data class SyncProfileRequest(val viewIds: List<Pair<Int, Int>>? = null, val onlyEndpoints: List<Int>? = null, val arguments: JsonObject? = null)
|
||||
data class SyncProfileListRequest(val profileList: List<Int>)
|
||||
data class MessageGetRequest(val message: MessageFull)
|
||||
data class MessageSendRequest(val recipients: Set<Teacher>, val subject: String, val text: String)
|
||||
data class MessageSendRequest(val recipients: List<Teacher>, val subject: String, val text: String)
|
||||
class AnnouncementsReadRequest
|
||||
data class AnnouncementGetRequest(val announcement: AnnouncementFull)
|
||||
data class AttachmentGetRequest(val owner: Any, val attachmentId: Long, val attachmentName: String)
|
||||
|
@ -6,9 +6,9 @@ package pl.szczodrzynski.edziennik.data.api.edziennik
|
||||
|
||||
import android.content.Intent
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.Intent
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
|
||||
import pl.szczodrzynski.edziennik.ext.Intent
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
@ -51,32 +51,35 @@ class ProfileArchiver(val app: App, val profile: Profile) {
|
||||
d(TAG, "New profile ID for ${profile.name}: ${profile.id}")
|
||||
|
||||
when (profile.loginStoreType) {
|
||||
LoginType.LIBRUS -> {
|
||||
profile.studentData.remove("isPremium")
|
||||
profile.studentData.remove("pushDeviceId")
|
||||
profile.studentData.remove("startPointsSemester1")
|
||||
profile.studentData.remove("startPointsSemester2")
|
||||
profile.studentData.remove("enablePointGrades")
|
||||
profile.studentData.remove("enableDescriptiveGrades")
|
||||
LOGIN_TYPE_LIBRUS -> {
|
||||
profile.removeStudentData("isPremium")
|
||||
profile.removeStudentData("pushDeviceId")
|
||||
profile.removeStudentData("startPointsSemester1")
|
||||
profile.removeStudentData("startPointsSemester2")
|
||||
profile.removeStudentData("enablePointGrades")
|
||||
profile.removeStudentData("enableDescriptiveGrades")
|
||||
}
|
||||
LoginType.MOBIDZIENNIK -> {}
|
||||
LoginType.VULCAN -> {
|
||||
LOGIN_TYPE_MOBIDZIENNIK -> {
|
||||
|
||||
}
|
||||
LOGIN_TYPE_VULCAN -> {
|
||||
// DataVulcan.isApiLoginValid() returns false so it will update the semester
|
||||
profile.studentData.remove("currentSemesterEndDate")
|
||||
profile.studentData.remove("studentSemesterId")
|
||||
profile.studentData.remove("studentSemesterNumber")
|
||||
profile.studentData.remove("semester1Id")
|
||||
profile.studentData.remove("semester2Id")
|
||||
profile.studentData.remove("studentClassId")
|
||||
profile.removeStudentData("currentSemesterEndDate")
|
||||
profile.removeStudentData("studentSemesterId")
|
||||
profile.removeStudentData("studentSemesterNumber")
|
||||
profile.removeStudentData("semester1Id")
|
||||
profile.removeStudentData("semester2Id")
|
||||
profile.removeStudentData("studentClassId")
|
||||
}
|
||||
LoginType.IDZIENNIK -> {
|
||||
profile.studentData.remove("schoolYearId")
|
||||
LOGIN_TYPE_IDZIENNIK -> {
|
||||
profile.removeStudentData("schoolYearId")
|
||||
}
|
||||
LOGIN_TYPE_EDUDZIENNIK -> {
|
||||
|
||||
}
|
||||
LOGIN_TYPE_PODLASIE -> {
|
||||
|
||||
}
|
||||
LoginType.EDUDZIENNIK -> {}
|
||||
LoginType.PODLASIE -> {}
|
||||
LoginType.USOS -> {}
|
||||
LoginType.DEMO -> {}
|
||||
LoginType.TEMPLATE -> {}
|
||||
}
|
||||
|
||||
d(TAG, "Processed student data: ${profile.studentData}")
|
||||
|
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
import pl.szczodrzynski.edziennik.data.api.models.Data
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.*
|
||||
|
||||
/**
|
||||
* Use http://patorjk.com/software/taag/#p=display&f=Big for the ascii art
|
||||
*
|
||||
* Use https://codepen.io/kubasz/pen/RwwwbGN to easily generate the student data getters/setters
|
||||
*/
|
||||
class DataEdudziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
||||
|
||||
fun isWebLoginValid() = webSessionIdExpiryTime-30 > currentTimeUnix() && webSessionId.isNotNullNorEmpty()
|
||||
|
||||
override fun satisfyLoginMethods() {
|
||||
loginMethods.clear()
|
||||
if (isWebLoginValid()) {
|
||||
loginMethods += LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateUserCode() = "$schoolName:$loginEmail:${studentId?.crc32()}"
|
||||
|
||||
private var mLoginEmail: String? = null
|
||||
var loginEmail: String?
|
||||
get() { mLoginEmail = mLoginEmail ?: loginStore.getLoginData("email", null); return mLoginEmail }
|
||||
set(value) { loginStore.putLoginData("email", value); mLoginEmail = value }
|
||||
|
||||
private var mLoginPassword: String? = null
|
||||
var loginPassword: String?
|
||||
get() { mLoginPassword = mLoginPassword ?: loginStore.getLoginData("password", null); return mLoginPassword }
|
||||
set(value) { loginStore.putLoginData("password", value); mLoginPassword = value }
|
||||
|
||||
private var mStudentId: String? = null
|
||||
var studentId: String?
|
||||
get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", null); return mStudentId }
|
||||
set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value }
|
||||
|
||||
private var mSchoolId: String? = null
|
||||
var schoolId: String?
|
||||
get() { mSchoolId = mSchoolId ?: profile?.getStudentData("schoolId", null); return mSchoolId }
|
||||
set(value) { profile?.putStudentData("schoolId", value) ?: return; mSchoolId = value }
|
||||
|
||||
private var mClassId: String? = null
|
||||
var classId: String?
|
||||
get() { mClassId = mClassId ?: profile?.getStudentData("classId", null); return mClassId }
|
||||
set(value) { profile?.putStudentData("classId", value) ?: return; mClassId = value }
|
||||
|
||||
/* __ __ _
|
||||
\ \ / / | |
|
||||
\ \ /\ / /__| |__
|
||||
\ \/ \/ / _ \ '_ \
|
||||
\ /\ / __/ |_) |
|
||||
\/ \/ \___|_._*/
|
||||
private var mWebSessionId: String? = null
|
||||
var webSessionId: String?
|
||||
get() { mWebSessionId = mWebSessionId ?: loginStore.getLoginData("webSessionId", null); return mWebSessionId }
|
||||
set(value) { loginStore.putLoginData("webSessionId", value); mWebSessionId = value }
|
||||
|
||||
private var mWebSessionIdExpiryTime: Long? = null
|
||||
var webSessionIdExpiryTime: Long
|
||||
get() { mWebSessionIdExpiryTime = mWebSessionIdExpiryTime ?: loginStore.getLoginData("webSessionIdExpiryTime", 0L); return mWebSessionIdExpiryTime ?: 0L }
|
||||
set(value) { loginStore.putLoginData("webSessionIdExpiryTime", value); mWebSessionIdExpiryTime = value }
|
||||
|
||||
/* ____ _ _
|
||||
/ __ \| | | |
|
||||
| | | | |_| |__ ___ _ __
|
||||
| | | | __| '_ \ / _ \ '__|
|
||||
| |__| | |_| | | | __/ |
|
||||
\____/ \__|_| |_|\___|*/
|
||||
private var mCurrentSemester: Int? = null
|
||||
var currentSemester: Int
|
||||
get() { mCurrentSemester = mCurrentSemester ?: profile?.getStudentData("currentSemester", 1); return mCurrentSemester ?: 1 }
|
||||
set(value) { profile?.putStudentData("currentSemester", value) ?: return; mCurrentSemester = value }
|
||||
|
||||
private var mSchoolName: String? = null
|
||||
var schoolName: String?
|
||||
get() { mSchoolName = mSchoolName ?: profile?.getStudentData("schoolName", null); return mSchoolName }
|
||||
set(value) { profile?.putStudentData("schoolName", value) ?: return; mSchoolName = value }
|
||||
|
||||
val studentEndpoint: String
|
||||
get() = "Students/$studentId/"
|
||||
|
||||
val schoolEndpoint: String
|
||||
get() = "Schools/$schoolId/"
|
||||
|
||||
val classStudentEndpoint: String
|
||||
get() = "Class/$studentId/"
|
||||
|
||||
val schoolClassEndpoint: String
|
||||
get() = "Schools/$classId/"
|
||||
|
||||
val studentAndClassEndpoint: String
|
||||
get() = "Students/$studentId/Klass/$classId/"
|
||||
|
||||
val studentAndClassesEndpoint: String
|
||||
get() = "Students/$studentId/Classes/$classId/"
|
||||
|
||||
val timetableEndpoint: String
|
||||
get() = "Plan/$studentId/"
|
||||
|
||||
val studentAndTeacherClassEndpoint: String
|
||||
get() = "Students/$studentId/Teachers/$classId/"
|
||||
|
||||
val courseStudentEndpoint: String
|
||||
get() = "Course/$studentId/"
|
||||
|
||||
fun getSubject(longId: String, name: String): Subject {
|
||||
val id = longId.crc32()
|
||||
return subjectList.singleOrNull { it.id == id } ?: run {
|
||||
val subject = Subject(profileId, id, name, name)
|
||||
subjectList.put(id, subject)
|
||||
subject
|
||||
}
|
||||
}
|
||||
|
||||
fun getTeacher(firstName: String, lastName: String, longId: String? = null): Teacher {
|
||||
val name = "$firstName $lastName".fixName()
|
||||
val id = name.crc32()
|
||||
return teacherList.singleOrNull { it.id == id }?.also {
|
||||
if (longId != null && it.loginId == null) it.loginId = longId
|
||||
} ?: run {
|
||||
val teacher = Teacher(profileId, id, firstName, lastName, longId)
|
||||
teacherList.put(id, teacher)
|
||||
teacher
|
||||
}
|
||||
}
|
||||
|
||||
fun getTeacherByFirstLast(nameFirstLast: String, longId: String? = null): Teacher {
|
||||
val nameParts = nameFirstLast.split(" ")
|
||||
return getTeacher(nameParts[0], nameParts[1], longId)
|
||||
}
|
||||
|
||||
fun getTeacherByLastFirst(nameLastFirst: String, longId: String? = null): Teacher {
|
||||
val nameParts = nameLastFirst.split(" ")
|
||||
return getTeacher(nameParts[1], nameParts[0], longId)
|
||||
}
|
||||
|
||||
fun getEventType(longId: String, name: String): EventType {
|
||||
val id = longId.crc16().toLong()
|
||||
return eventTypes.singleOrNull { it.id == id } ?: run {
|
||||
val eventType = EventType(profileId, id, name, colorFromName(name))
|
||||
eventTypes.put(id, eventType)
|
||||
eventType
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikData
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web.EdudziennikWebGetAnnouncement
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web.EdudziennikWebGetHomework
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.firstlogin.EdudziennikFirstLogin
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login.EdudziennikLogin
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login.EdudziennikLoginWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class Edudziennik(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
companion object {
|
||||
private const val TAG = "Edudziennik"
|
||||
}
|
||||
|
||||
val internalErrorList = mutableListOf<Int>()
|
||||
val data: DataEdudziennik
|
||||
private var afterLogin: (() -> Unit)? = null
|
||||
|
||||
init {
|
||||
data = DataEdudziennik(app, profile, loginStore).apply {
|
||||
callback = wrapCallback(this@Edudziennik.callback)
|
||||
satisfyLoginMethods()
|
||||
}
|
||||
}
|
||||
|
||||
private fun completed() {
|
||||
data.saveData()
|
||||
callback.onCompleted()
|
||||
}
|
||||
|
||||
/* _______ _ _ _ _ _
|
||||
|__ __| | /\ | | (_) | | |
|
||||
| | | |__ ___ / \ | | __ _ ___ _ __ _| |_| |__ _ __ ___
|
||||
| | | '_ \ / _ \ / /\ \ | |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \
|
||||
| | | | | | __/ / ____ \| | (_| | (_) | | | | |_| | | | | | | | |
|
||||
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
||||
__/ |
|
||||
|__*/
|
||||
override fun sync(featureIds: List<Int>, viewId: Int?, onlyEndpoints: List<Int>?, arguments: JsonObject?) {
|
||||
data.arguments = arguments
|
||||
data.prepare(edudziennikLoginMethods, EdudziennikFeatures, featureIds, viewId, onlyEndpoints)
|
||||
login()
|
||||
}
|
||||
|
||||
private fun login(loginMethodId: Int? = null, afterLogin: (() -> Unit)? = null) {
|
||||
d(TAG, "Trying to login with ${data.targetLoginMethodIds}")
|
||||
if (internalErrorList.isNotEmpty()) {
|
||||
d(TAG, " - Internal errors:")
|
||||
internalErrorList.forEach { d(TAG, " - code $it") }
|
||||
}
|
||||
loginMethodId?.let { data.prepareFor(edudziennikLoginMethods, it) }
|
||||
afterLogin?.let { this.afterLogin = it }
|
||||
EdudziennikLogin(data) {
|
||||
data()
|
||||
}
|
||||
}
|
||||
|
||||
private fun data() {
|
||||
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
||||
if (internalErrorList.isNotEmpty()) {
|
||||
d(TAG, " - Internal errors:")
|
||||
internalErrorList.forEach { d(TAG, " - code $it") }
|
||||
}
|
||||
afterLogin?.invoke() ?: EdudziennikData(data) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMessage(message: MessageFull) {}
|
||||
override fun sendMessage(recipients: List<Teacher>, subject: String, text: String) {}
|
||||
override fun markAllAnnouncementsAsRead() {}
|
||||
|
||||
override fun getAnnouncement(announcement: AnnouncementFull) {
|
||||
EdudziennikLoginWeb(data) {
|
||||
EdudziennikWebGetAnnouncement(data, announcement) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {}
|
||||
override fun getRecipientList() {}
|
||||
|
||||
override fun getEvent(eventFull: EventFull) {
|
||||
EdudziennikLoginWeb(data) {
|
||||
EdudziennikWebGetHomework(data, eventFull) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun firstLogin() { EdudziennikFirstLogin(data) { completed() } }
|
||||
override fun cancel() {
|
||||
d(TAG, "Cancelled")
|
||||
data.cancel()
|
||||
}
|
||||
|
||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||
return object : EdziennikCallback {
|
||||
override fun onCompleted() { callback.onCompleted() }
|
||||
override fun onProgress(step: Float) { callback.onProgress(step) }
|
||||
override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) }
|
||||
override fun onError(apiError: ApiError) {
|
||||
if (apiError.errorCode in internalErrorList) {
|
||||
// finish immediately if the same error occurs twice during the same sync
|
||||
callback.onError(apiError)
|
||||
return
|
||||
}
|
||||
internalErrorList.add(apiError.errorCode)
|
||||
when (apiError.errorCode) {
|
||||
ERROR_EDUDZIENNIK_WEB_SESSION_EXPIRED -> {
|
||||
login()
|
||||
}
|
||||
ERROR_LOGIN_EDUDZIENNIK_WEB_NO_SESSION_ID -> {
|
||||
login()
|
||||
}
|
||||
ERROR_EDUDZIENNIK_WEB_LIMITED_ACCESS -> {
|
||||
data()
|
||||
}
|
||||
else -> callback.onError(apiError)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-23
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.models.Feature
|
||||
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_START = 1000
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_TEACHERS = 1001
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_GRADES = 1011
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE = 1012
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_EXAMS = 1013
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE = 1014
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS = 1015
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK = 1016
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_EVENTS = 1017
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_NOTES = 1018
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER = 1030
|
||||
|
||||
val EdudziennikFeatures = listOf(
|
||||
/* School and team info and subjects */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_STUDENT_INFO, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_START to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Teachers */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_TEACHERS, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_TEACHERS to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Timetable */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_TIMETABLE, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Grades */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_GRADES, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_GRADES to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Agenda */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_AGENDA, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_EXAMS to LOGIN_METHOD_EDUDZIENNIK_WEB,
|
||||
ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK to LOGIN_METHOD_EDUDZIENNIK_WEB,
|
||||
ENDPOINT_EDUDZIENNIK_WEB_EVENTS to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Homework */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_HOMEWORK, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Behaviour */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_BEHAVIOUR, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_NOTES to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Attendance */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_ATTENDANCE, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Announcements */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_ANNOUNCEMENTS, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Lucky number */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_LUCKY_NUMBER, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB))
|
||||
)
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data
|
||||
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web.*
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
|
||||
class EdudziennikData(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikData"
|
||||
}
|
||||
|
||||
init {
|
||||
nextEndpoint(onSuccess)
|
||||
}
|
||||
|
||||
private fun nextEndpoint(onSuccess: () -> Unit) {
|
||||
if (data.targetEndpointIds.isEmpty()) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
if (data.cancelled) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
val id = data.targetEndpointIds.firstKey()
|
||||
val lastSync = data.targetEndpointIds.remove(id)
|
||||
useEndpoint(id, lastSync) { endpointId ->
|
||||
data.progress(data.progressStep)
|
||||
nextEndpoint(onSuccess)
|
||||
}
|
||||
}
|
||||
|
||||
private fun useEndpoint(endpointId: Int, lastSync: Long?, onSuccess: (endpointId: Int) -> Unit) {
|
||||
Utils.d(TAG, "Using endpoint $endpointId. Last sync time = $lastSync")
|
||||
when (endpointId) {
|
||||
ENDPOINT_EDUDZIENNIK_WEB_START -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_data)
|
||||
EdudziennikWebStart(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_TEACHERS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_teachers)
|
||||
EdudziennikWebTeachers(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
||||
EdudziennikWebGrades(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
||||
EdudziennikWebTimetable(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_EXAMS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_exams)
|
||||
EdudziennikWebExams(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
||||
EdudziennikWebAttendance(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_announcements)
|
||||
EdudziennikWebAnnouncements(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
||||
EdudziennikWebHomework(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_EVENTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_events)
|
||||
EdudziennikWebEvents(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_NOTES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
||||
EdudziennikWebNotes(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
|
||||
EdudziennikWebLuckyNumber(data, lastSync, onSuccess)
|
||||
}
|
||||
else -> onSuccess(endpointId)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data
|
||||
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
open class EdudziennikWeb(open val data: DataEdudziennik, open val lastSync: Long?) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWeb"
|
||||
}
|
||||
|
||||
val profileId
|
||||
get() = data.profile?.id ?: -1
|
||||
|
||||
val profile
|
||||
get() = data.profile
|
||||
|
||||
fun webGet(tag: String, endpoint: String, xhr: Boolean = false, semester: Int? = null, onSuccess: (text: String) -> Unit) {
|
||||
val url = "https://dziennikel.appspot.com/" + when (endpoint.endsWith('/') || endpoint.contains('?') || endpoint.isEmpty()) {
|
||||
true -> endpoint
|
||||
else -> "$endpoint/"
|
||||
} + (semester?.let { "?semester=" + if(it == -1) "all" else it } ?: "")
|
||||
|
||||
d(tag, "Request: Edudziennik/Web - $url")
|
||||
|
||||
val callback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String?, response: Response?) {
|
||||
if (text == null || response == null) {
|
||||
data.error(ApiError(tag, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
if (semester == null && url.contains("start")) {
|
||||
profile?.also { profile ->
|
||||
val cookies = data.app.cookieJar.getAll("dziennikel.appspot.com")
|
||||
val semesterCookie = cookies["semester"]?.toIntOrNull()
|
||||
|
||||
semesterCookie?.let { data.currentSemester = it }
|
||||
|
||||
if (semesterCookie == 2 && profile.dateSemester2Start > Date.getToday())
|
||||
profile.dateSemester2Start = Date.getToday().stepForward(0, 0, -1)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
onSuccess(text)
|
||||
} catch (e: Exception) {
|
||||
data.error(ApiError(tag, EXCEPTION_EDUDZIENNIK_WEB_REQUEST)
|
||||
.withThrowable(e)
|
||||
.withResponse(response)
|
||||
.withApiResponse(text))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
val error = when (response?.code()) {
|
||||
402 -> ERROR_EDUDZIENNIK_WEB_LIMITED_ACCESS
|
||||
403 -> ERROR_EDUDZIENNIK_WEB_SESSION_EXPIRED
|
||||
else -> ERROR_REQUEST_FAILURE
|
||||
}
|
||||
data.error(ApiError(tag, error)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
data.app.cookieJar.set("dziennikel.appspot.com", "sessionid", data.webSessionId)
|
||||
|
||||
Request.builder()
|
||||
.url(url)
|
||||
.userAgent(EDUDZIENNIK_USER_AGENT)
|
||||
.apply {
|
||||
if (xhr) header("X-Requested-With", "XMLHttpRequest")
|
||||
}
|
||||
.get()
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-26
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ANNOUNCEMENT_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Announcement
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebAnnouncements(override val data: DataEdudziennik,
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebAnnouncements"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
webGet(TAG, data.schoolClassEndpoint + "Announcements") { text ->
|
||||
val doc = Jsoup.parse(text)
|
||||
|
||||
if (doc.getElementsByClass("message").text().trim() != "Brak ogłoszeń.") {
|
||||
doc.select("table.list tbody tr").forEach { announcementElement ->
|
||||
val titleElement = announcementElement.child(0).child(0)
|
||||
|
||||
val longId = EDUDZIENNIK_ANNOUNCEMENT_ID.find(titleElement.attr("href"))?.get(1)
|
||||
?: return@forEach
|
||||
val id = longId.crc32()
|
||||
val subject = titleElement.text()
|
||||
|
||||
val teacherName = announcementElement.child(1).text()
|
||||
val teacher = data.getTeacherByFirstLast(teacherName)
|
||||
|
||||
val dateString = announcementElement.getElementsByClass("datetime").first().text()
|
||||
val startDate = Date.fromY_m_d(dateString)
|
||||
val addedDate = Date.fromIsoHm(dateString)
|
||||
|
||||
val announcementObject = Announcement(
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
subject = subject,
|
||||
text = null,
|
||||
startDate = startDate,
|
||||
endDate = null,
|
||||
teacherId = teacher.id,
|
||||
addedDate = addedDate
|
||||
).also {
|
||||
it.idString = longId
|
||||
}
|
||||
|
||||
data.announcementList.add(announcementObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_ANNOUNCEMENT,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS, SYNC_ALWAYS)
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS)
|
||||
}
|
||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS) }
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-24
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ATTENDANCE_ENTRIES
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ATTENDANCE_TYPE
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ATTENDANCE_TYPES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import java.util.*
|
||||
|
||||
class EdudziennikWebAttendance(override val data: DataEdudziennik,
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebAttendance"
|
||||
}
|
||||
|
||||
private var requestSemester: Int? = null
|
||||
|
||||
init {
|
||||
if (profile?.empty == true && data.currentSemester == 2) requestSemester = 1
|
||||
getAttendances()
|
||||
}
|
||||
|
||||
private fun getAttendances() { data.profile?.also { profile ->
|
||||
webGet(TAG, data.studentEndpoint + "Presence", semester = requestSemester) { text ->
|
||||
|
||||
val attendanceTypes = EDUDZIENNIK_ATTENDANCE_TYPES.find(text)?.get(1)?.split(',')?.map {
|
||||
val type = EDUDZIENNIK_ATTENDANCE_TYPE.find(it.trim())
|
||||
val symbol = type?.get(1)?.trim() ?: "?"
|
||||
val name = type?.get(2)?.trim() ?: "nieznany rodzaj"
|
||||
return@map Triple(
|
||||
symbol,
|
||||
name,
|
||||
when (name.toLowerCase(Locale.ROOT)) {
|
||||
"obecność" -> Attendance.TYPE_PRESENT
|
||||
"nieobecność" -> Attendance.TYPE_ABSENT
|
||||
"spóźnienie" -> Attendance.TYPE_BELATED
|
||||
"nieobecność usprawiedliwiona" -> Attendance.TYPE_ABSENT_EXCUSED
|
||||
"dzień wolny" -> Attendance.TYPE_DAY_FREE
|
||||
"brak zajęć" -> Attendance.TYPE_DAY_FREE
|
||||
"oddelegowany" -> Attendance.TYPE_RELEASED
|
||||
else -> Attendance.TYPE_UNKNOWN
|
||||
}
|
||||
)
|
||||
} ?: emptyList()
|
||||
|
||||
EDUDZIENNIK_ATTENDANCE_ENTRIES.findAll(text).forEach { attendanceElement ->
|
||||
val date = Date.fromY_m_d(attendanceElement[1])
|
||||
val lessonNumber = attendanceElement[2].toInt()
|
||||
val attendanceSymbol = attendanceElement[3]
|
||||
|
||||
val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
|
||||
val lesson = lessons.firstOrNull { it.lessonNumber == lessonNumber }
|
||||
|
||||
val id = "${date.stringY_m_d}:$lessonNumber:$attendanceSymbol".crc32()
|
||||
|
||||
val (typeSymbol, typeName, baseType) = attendanceTypes.firstOrNull { (symbol, _, _) -> symbol == attendanceSymbol }
|
||||
?: return@forEach
|
||||
|
||||
val startTime = data.lessonRanges.singleOrNull { it.lessonNumber == lessonNumber }?.startTime
|
||||
?: return@forEach
|
||||
|
||||
val attendanceObject = Attendance(
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
baseType = baseType,
|
||||
typeName = typeName,
|
||||
typeShort = data.app.attendanceManager.getTypeShort(baseType),
|
||||
typeSymbol = typeSymbol,
|
||||
typeColor = null,
|
||||
date = date,
|
||||
startTime = lesson?.displayStartTime ?: startTime,
|
||||
semester = profile.currentSemester,
|
||||
teacherId = lesson?.displayTeacherId ?: -1,
|
||||
subjectId = lesson?.displaySubjectId ?: -1
|
||||
).also {
|
||||
it.lessonNumber = lessonNumber
|
||||
}
|
||||
|
||||
data.attendanceList.add(attendanceObject)
|
||||
if (baseType != Attendance.TYPE_PRESENT) {
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_ATTENDANCE,
|
||||
id,
|
||||
profile.empty || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN,
|
||||
profile.empty || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
if (profile.empty && requestSemester == 1 && data.currentSemester == 2) {
|
||||
requestSemester = null
|
||||
getAttendances()
|
||||
} else {
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE, SYNC_ALWAYS)
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE)
|
||||
}
|
||||
}
|
||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE) }
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2020-1-1
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_EVENT_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_EVENTS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebEvents(override val data: DataEdudziennik,
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebEvents"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
webGet(TAG, data.studentAndClassesEndpoint + "KlassEvent", xhr = true) { text ->
|
||||
val doc = Jsoup.parseBodyFragment("<table>" + text.trim() + "</table>")
|
||||
|
||||
doc.getElementsByTag("tr").forEach { eventElement ->
|
||||
val date = Date.fromY_m_d(eventElement.child(1).text())
|
||||
|
||||
val titleElement = eventElement.child(2).child(0)
|
||||
val title = titleElement.text().trim()
|
||||
|
||||
val id = EDUDZIENNIK_EVENT_ID.find(titleElement.attr("href"))?.get(1)?.crc32()
|
||||
?: return@forEach
|
||||
|
||||
val eventObject = Event(
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
date = date,
|
||||
time = null,
|
||||
topic = title,
|
||||
color = null,
|
||||
type = Event.TYPE_CLASS_EVENT,
|
||||
teacherId = -1,
|
||||
subjectId = -1,
|
||||
teamId = data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_EVENT,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty
|
||||
))
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_CLASS_EVENT))
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_EVENTS, SYNC_ALWAYS)
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_EVENTS)
|
||||
}
|
||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_EVENTS) }
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-24
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_EVENT_TYPE_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_EXAM_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECT_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_EXAMS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebExams(override val data: DataEdudziennik,
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebExams"
|
||||
}
|
||||
|
||||
init { profile?.also { profile ->
|
||||
webGet(TAG, data.studentAndClassEndpoint + "Evaluations", xhr = true) { text ->
|
||||
val doc = Jsoup.parseBodyFragment("<table>" + text.trim() + "</table>")
|
||||
|
||||
doc.select("tr").forEach { examElement ->
|
||||
val id = EDUDZIENNIK_EXAM_ID.find(examElement.child(0).child(0).attr("href"))
|
||||
?.get(1)?.crc32() ?: return@forEach
|
||||
val topic = examElement.child(0).text().trim()
|
||||
|
||||
val subjectElement = examElement.child(1).child(0)
|
||||
val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
|
||||
?: return@forEach
|
||||
val subjectName = subjectElement.text().trim()
|
||||
val subject = data.getSubject(subjectId, subjectName)
|
||||
|
||||
val dateString = examElement.child(2).text().trim()
|
||||
if (dateString.isBlank()) return@forEach
|
||||
val date = Date.fromY_m_d(dateString)
|
||||
|
||||
val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
|
||||
val startTime = lessons.firstOrNull { it.displaySubjectId == subject.id }?.displayStartTime
|
||||
|
||||
val eventTypeElement = examElement.child(3).child(0)
|
||||
val eventTypeId = EDUDZIENNIK_EVENT_TYPE_ID.find(eventTypeElement.attr("href"))?.get(1)
|
||||
?: return@forEach
|
||||
val eventTypeName = eventTypeElement.text()
|
||||
val eventType = data.getEventType(eventTypeId, eventTypeName)
|
||||
|
||||
val eventObject = Event(
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
date = date,
|
||||
time = startTime,
|
||||
topic = topic,
|
||||
color = null,
|
||||
type = eventType.id,
|
||||
teacherId = -1,
|
||||
subjectId = subject.id,
|
||||
teamId = data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_EVENT,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty
|
||||
))
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Events.futureExceptTypes(listOf(
|
||||
Event.TYPE_HOMEWORK,
|
||||
Event.TYPE_CLASS_EVENT
|
||||
)))
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_EXAMS, SYNC_ALWAYS)
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_EXAMS)
|
||||
}
|
||||
}}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-26
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.events.AnnouncementGetEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
|
||||
class EdudziennikWebGetAnnouncement(override val data: DataEdudziennik,
|
||||
private val announcement: AnnouncementFull,
|
||||
val onSuccess: () -> Unit
|
||||
) : EdudziennikWeb(data, null) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebGetAnnouncement"
|
||||
}
|
||||
|
||||
init {
|
||||
webGet(TAG, "Announcement/${announcement.idString}") { text ->
|
||||
val description = Regexes.EDUDZIENNIK_ANNOUNCEMENT_DESCRIPTION.find(text)?.get(1)?.trim() ?: ""
|
||||
|
||||
announcement.text = description
|
||||
|
||||
EventBus.getDefault().postSticky(AnnouncementGetEvent(announcement))
|
||||
|
||||
data.announcementList.add(announcement)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import android.text.Html
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||
|
||||
class EdudziennikWebGetHomework(
|
||||
override val data: DataEdudziennik,
|
||||
val event: EventFull,
|
||||
val onSuccess: () -> Unit
|
||||
) : EdudziennikWeb(data, null) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebGetHomework"
|
||||
}
|
||||
|
||||
init {
|
||||
if (event.attachmentNames.isNotNullNorEmpty()) {
|
||||
val id = event.attachmentNames!![0]
|
||||
|
||||
webGet(TAG, "Homework/$id") { text ->
|
||||
val description = Regexes.EDUDZIENNIK_HOMEWORK_DESCRIPTION.find(text)?.get(1)?.trim()
|
||||
|
||||
if (description != null) event.topic = Html.fromHtml(description).toString()
|
||||
|
||||
event.homeworkBody = ""
|
||||
event.attachmentNames = null
|
||||
|
||||
data.eventList += event
|
||||
data.eventListReplace = true
|
||||
|
||||
EventBus.getDefault().postSticky(EventGetEvent(event))
|
||||
onSuccess()
|
||||
}
|
||||
} else {
|
||||
EventBus.getDefault().postSticky(EventGetEvent(event))
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-25
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import android.graphics.Color
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.colorFromCssName
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_GRADES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_NORMAL
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_POINT_SUM
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_FINAL
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_PROPOSED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_FINAL
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_PROPOSED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebGrades(override val data: DataEdudziennik,
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebGrades"
|
||||
}
|
||||
|
||||
private var requestSemester: Int? = null
|
||||
|
||||
init {
|
||||
if (profile?.empty == true && data.currentSemester == 2) requestSemester = 1
|
||||
getGrades()
|
||||
}
|
||||
|
||||
private fun getGrades() { data.profile?.also { profile ->
|
||||
webGet(TAG, data.studentEndpoint + "start", semester = requestSemester) { text ->
|
||||
val semester = requestSemester ?: data.currentSemester
|
||||
|
||||
val doc = Jsoup.parse(text)
|
||||
val subjects = doc.select("#student_grades tbody").firstOrNull()?.children()
|
||||
|
||||
subjects?.forEach { subjectElement ->
|
||||
if (subjectElement.id().isBlank()) return@forEach
|
||||
|
||||
val subjectId = subjectElement.id().trim()
|
||||
val subjectName = subjectElement.child(0).text().trim()
|
||||
val subject = data.getSubject(subjectId, subjectName)
|
||||
|
||||
val gradeType = when {
|
||||
subjectElement.select("#sum").text().isNotBlank() -> TYPE_POINT_SUM
|
||||
else -> TYPE_NORMAL
|
||||
}
|
||||
|
||||
val gradeCountToAverage = subjectElement.select("#avg").text().isNotBlank()
|
||||
|
||||
val grades = subjectElement.select(".grade[data-edited]")
|
||||
val gradesInfo = subjectElement.select(".grade-tip")
|
||||
|
||||
val gradeValues = if (grades.isNotEmpty()) {
|
||||
subjects.select(".avg-$subjectId .grade-tip > p").first()
|
||||
.text().split('+').map {
|
||||
val split = it.split('*')
|
||||
val value = split[1].trim().toFloatOrNull()
|
||||
val weight = value?.let { split[0].trim().toFloatOrNull() } ?: 0f
|
||||
|
||||
Pair(value ?: 0f, weight)
|
||||
}
|
||||
} else emptyList()
|
||||
|
||||
grades.forEachIndexed { index, gradeElement ->
|
||||
val id = Regexes.EDUDZIENNIK_GRADE_ID.find(gradeElement.attr("href"))?.get(1)?.crc32()
|
||||
?: return@forEachIndexed
|
||||
val (value, weight) = gradeValues[index]
|
||||
val name = gradeElement.text().trim().let {
|
||||
if (it.contains(',') || it.contains('.')) {
|
||||
val replaced = it.replace(',', '.')
|
||||
val float = replaced.toFloatOrNull()
|
||||
|
||||
if (float != null && float % 1 == 0f) float.toInt().toString()
|
||||
else it
|
||||
} else it
|
||||
}
|
||||
|
||||
val info = gradesInfo[index]
|
||||
val fullName = info.child(0).text().trim()
|
||||
val columnName = info.child(4).text().trim()
|
||||
val comment = info.ownText()
|
||||
|
||||
val description = columnName + if (comment.isNotBlank()) " - $comment" else null
|
||||
|
||||
val teacherName = info.child(1).text()
|
||||
val teacher = data.getTeacherByLastFirst(teacherName)
|
||||
|
||||
val addedDate = info.child(2).text().split(' ').let {
|
||||
val day = it[0].toInt()
|
||||
val month = Utils.monthFromName(it[1])
|
||||
val year = it[2].toInt()
|
||||
|
||||
Date(year, month, day).inMillis
|
||||
}
|
||||
|
||||
val color = Regexes.STYLE_CSS_COLOR.find(gradeElement.attr("style"))?.get(1)?.let {
|
||||
if (it.startsWith('#')) Color.parseColor(it)
|
||||
else colorFromCssName(it)
|
||||
} ?: -1
|
||||
|
||||
val gradeObject = Grade(
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
name = name,
|
||||
type = gradeType,
|
||||
value = value,
|
||||
weight = if (gradeCountToAverage) weight else 0f,
|
||||
color = color,
|
||||
category = fullName,
|
||||
description = description,
|
||||
comment = null,
|
||||
semester = semester,
|
||||
teacherId = teacher.id,
|
||||
subjectId = subject.id,
|
||||
addedDate = addedDate
|
||||
)
|
||||
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty
|
||||
))
|
||||
}
|
||||
|
||||
val proposed = subjectElement.select(".proposal").firstOrNull()?.text()?.trim()
|
||||
|
||||
if (proposed != null && proposed.isNotBlank()) {
|
||||
val proposedGradeObject = Grade(
|
||||
profileId = profileId,
|
||||
id = (-1 * subject.id) - 1,
|
||||
name = proposed,
|
||||
type = when (semester) {
|
||||
1 -> TYPE_SEMESTER1_PROPOSED
|
||||
else -> TYPE_SEMESTER2_PROPOSED
|
||||
},
|
||||
value = proposed.toFloatOrNull() ?: 0f,
|
||||
weight = 0f,
|
||||
color = -1,
|
||||
category = null,
|
||||
description = null,
|
||||
comment = null,
|
||||
semester = semester,
|
||||
teacherId = -1,
|
||||
subjectId = subject.id
|
||||
)
|
||||
|
||||
data.gradeList.add(proposedGradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
proposedGradeObject.id,
|
||||
profile.empty,
|
||||
profile.empty
|
||||
))
|
||||
}
|
||||
|
||||
val final = subjectElement.select(".final").firstOrNull()?.text()?.trim()
|
||||
|
||||
if (final != null && final.isNotBlank()) {
|
||||
val finalGradeObject = Grade(
|
||||
profileId = profileId,
|
||||
id = (-1 * subject.id) - 2,
|
||||
name = final,
|
||||
type = when (semester) {
|
||||
1 -> TYPE_SEMESTER1_FINAL
|
||||
else -> TYPE_SEMESTER2_FINAL
|
||||
},
|
||||
value = final.toFloatOrNull() ?: 0f,
|
||||
weight = 0f,
|
||||
color = -1,
|
||||
category = null,
|
||||
description = null,
|
||||
comment = null,
|
||||
semester = semester,
|
||||
teacherId = -1,
|
||||
subjectId = subject.id
|
||||
)
|
||||
|
||||
data.gradeList.add(finalGradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
data.profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
finalGradeObject.id,
|
||||
profile.empty,
|
||||
profile.empty
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
if (!subjects.isNullOrEmpty()) {
|
||||
data.toRemove.addAll(listOf(
|
||||
TYPE_NORMAL,
|
||||
TYPE_POINT_SUM,
|
||||
TYPE_SEMESTER1_PROPOSED,
|
||||
TYPE_SEMESTER2_PROPOSED,
|
||||
TYPE_SEMESTER1_FINAL,
|
||||
TYPE_SEMESTER2_FINAL
|
||||
).map {
|
||||
DataRemoveModel.Grades.semesterWithType(semester, it)
|
||||
})
|
||||
}
|
||||
|
||||
if (profile.empty && requestSemester == 1 && data.currentSemester == 2) {
|
||||
requestSemester = null
|
||||
getGrades()
|
||||
} else {
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_GRADES, SYNC_ALWAYS)
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_GRADES)
|
||||
}
|
||||
}
|
||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_GRADES) }
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-29
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_HOMEWORK_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECT_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebHomework(override val data: DataEdudziennik,
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebHomework"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
webGet(TAG, data.courseStudentEndpoint + "Homework", xhr = true) { text ->
|
||||
val doc = Jsoup.parseBodyFragment("<table>" + text.trim() + "</table>")
|
||||
|
||||
if (doc.getElementsByClass("message").text().trim() != "Brak prac domowych") {
|
||||
doc.getElementsByTag("tr").forEach { homeworkElement ->
|
||||
val dateElement = homeworkElement.getElementsByClass("date").first().child(0)
|
||||
val idStr = EDUDZIENNIK_HOMEWORK_ID.find(dateElement.attr("href"))?.get(1) ?: return@forEach
|
||||
val id = idStr.crc32()
|
||||
val date = Date.fromY_m_d(dateElement.text())
|
||||
|
||||
val subjectElement = homeworkElement.child(1).child(0)
|
||||
val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
|
||||
?: return@forEach
|
||||
val subjectName = subjectElement.text()
|
||||
val subject = data.getSubject(subjectId, subjectName)
|
||||
|
||||
val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
|
||||
val startTime = lessons.firstOrNull { it.subjectId == subject.id }?.displayStartTime
|
||||
|
||||
val teacherName = homeworkElement.child(2).text()
|
||||
val teacher = data.getTeacherByFirstLast(teacherName)
|
||||
|
||||
val topic = homeworkElement.child(4).text()?.trim()
|
||||
|
||||
val eventObject = Event(
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
date = date,
|
||||
time = startTime,
|
||||
topic = topic ?: "",
|
||||
color = null,
|
||||
type = Event.TYPE_HOMEWORK,
|
||||
teacherId = teacher.id,
|
||||
subjectId = subject.id,
|
||||
teamId = data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
eventObject.attachmentNames = mutableListOf(idStr)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_HOMEWORK,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK, SYNC_ALWAYS)
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK)
|
||||
}
|
||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK) }
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-23
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebLuckyNumber(override val data: DataEdudziennik,
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebLuckyNumber"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
webGet(TAG, data.schoolEndpoint + "Lucky", xhr = true) { text ->
|
||||
text.toIntOrNull()?.also { luckyNumber ->
|
||||
val luckyNumberObject = LuckyNumber(
|
||||
profileId = profileId,
|
||||
date = Date.getToday(),
|
||||
number = luckyNumber
|
||||
)
|
||||
|
||||
data.luckyNumberList.add(luckyNumberObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_LUCKY_NUMBER,
|
||||
luckyNumberObject.date.value.toLong(),
|
||||
true,
|
||||
profile.empty
|
||||
))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER, SYNC_ALWAYS)
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER)
|
||||
}
|
||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER) }
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2020-1-1
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_NOTE_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_NOTES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notice
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebNotes(override val data: DataEdudziennik,
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebNotes"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
webGet(TAG, data.classStudentEndpoint + "RegistryNotesStudent", xhr = true) { text ->
|
||||
val doc = Jsoup.parseBodyFragment("<table>" + text.trim() + "</table>")
|
||||
|
||||
doc.getElementsByTag("tr").forEach { noteElement ->
|
||||
val dateElement = noteElement.getElementsByClass("date").first().child(0)
|
||||
val addedDate = Date.fromY_m_d(dateElement.text()).inMillis
|
||||
|
||||
val id = EDUDZIENNIK_NOTE_ID.find(dateElement.attr("href"))?.get(0)?.crc32()
|
||||
?: return@forEach
|
||||
|
||||
val teacherName = noteElement.child(1).text()
|
||||
val teacher = data.getTeacherByFirstLast(teacherName)
|
||||
|
||||
val description = noteElement.child(3).text()
|
||||
|
||||
val noticeObject = Notice(
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
type = Notice.TYPE_NEUTRAL,
|
||||
semester = profile.currentSemester,
|
||||
text = description,
|
||||
category = null,
|
||||
points = null,
|
||||
teacherId = teacher.id,
|
||||
addedDate = addedDate
|
||||
)
|
||||
|
||||
data.noticeList.add(noticeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_NOTICE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty
|
||||
))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_NOTES, SYNC_ALWAYS)
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_NOTES)
|
||||
}
|
||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_NOTES) }
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-23
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import pl.szczodrzynski.edziennik.MONTH
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_EDUDZIENNIK_WEB_TEAM_MISSING
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECTS_START
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_START
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Team
|
||||
import pl.szczodrzynski.edziennik.firstLettersName
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
|
||||
class EdudziennikWebStart(override val data: DataEdudziennik,
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebStart"
|
||||
}
|
||||
|
||||
init {
|
||||
webGet(TAG, data.studentEndpoint + "start") { text ->
|
||||
getSchoolAndTeam(text)
|
||||
getSubjects(text)
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_START, MONTH)
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_START)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSchoolAndTeam(text: String) {
|
||||
val schoolId = Regexes.EDUDZIENNIK_SCHOOL_DETAIL_ID.find(text)?.get(1)?.trim()
|
||||
val schoolLongName = Regexes.EDUDZIENNIK_SCHOOL_DETAIL_NAME.find(text)?.get(1)?.trim()
|
||||
data.schoolId = schoolId
|
||||
|
||||
val classId = Regexes.EDUDZIENNIK_CLASS_DETAIL_ID.find(text)?.get(1)?.trim()
|
||||
val className = Regexes.EDUDZIENNIK_CLASS_DETAIL_NAME.find(text)?.get(1)?.trim()
|
||||
data.classId = classId
|
||||
|
||||
if (classId == null || className == null || schoolId == null || schoolLongName == null) {
|
||||
data.error(ApiError(TAG, ERROR_EDUDZIENNIK_WEB_TEAM_MISSING)
|
||||
.withApiResponse(text))
|
||||
return
|
||||
}
|
||||
|
||||
val schoolName = schoolId.crc32().toString() + schoolLongName.firstLettersName + "_edu"
|
||||
data.schoolName = schoolName
|
||||
|
||||
val teamId = classId.crc32()
|
||||
val teamCode = "$schoolName:$className"
|
||||
|
||||
val teamObject = Team(
|
||||
data.profileId,
|
||||
teamId,
|
||||
className,
|
||||
Team.TYPE_CLASS,
|
||||
teamCode,
|
||||
-1
|
||||
)
|
||||
|
||||
data.teamClass = teamObject
|
||||
data.teamList.put(teamObject.id, teamObject)
|
||||
}
|
||||
|
||||
private fun getSubjects(text: String) {
|
||||
EDUDZIENNIK_SUBJECTS_START.findAll(text).forEach {
|
||||
val id = it[1].trim()
|
||||
val name = it[2].trim()
|
||||
data.getSubject(id, name)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-25
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import pl.szczodrzynski.edziennik.MONTH
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_TEACHERS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_TEACHERS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
|
||||
class EdudziennikWebTeachers(override val data: DataEdudziennik,
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebTeachers"
|
||||
}
|
||||
|
||||
init {
|
||||
webGet(TAG, data.studentAndTeacherClassEndpoint + "grid") { text ->
|
||||
EDUDZIENNIK_TEACHERS.findAll(text).forEach {
|
||||
val lastName = it[1].trim()
|
||||
val firstName = it[2].trim()
|
||||
data.getTeacher(firstName, lastName)
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_TEACHERS, MONTH)
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_TEACHERS)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-23
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECT_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_TEACHER_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LessonRange
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||
|
||||
class EdudziennikWebTimetable(override val data: DataEdudziennik,
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebTimetable"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
|
||||
val currentWeekStart = Week.getWeekStart()
|
||||
|
||||
if (Date.getToday().weekDay > 4) {
|
||||
currentWeekStart.stepForward(0, 0, 7)
|
||||
}
|
||||
|
||||
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
||||
|
||||
val weekStart = Date.fromY_m_d(getDate)
|
||||
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||
|
||||
webGet(TAG, data.timetableEndpoint + "print?date=$getDate") { text ->
|
||||
val doc = Jsoup.parse(text)
|
||||
|
||||
val dataDays = mutableListOf<Int>()
|
||||
val dataStart = weekStart.clone()
|
||||
while (dataStart <= weekEnd) {
|
||||
dataDays += dataStart.value
|
||||
dataStart.stepForward(0, 0, 1)
|
||||
}
|
||||
|
||||
val table = doc.select("#Schedule tbody").first()
|
||||
|
||||
if (!table.text().contains("Brak planu lekcji.")) {
|
||||
table.children().forEach { row ->
|
||||
val rowElements = row.children()
|
||||
|
||||
val lessonNumber = rowElements[0].text().toInt()
|
||||
|
||||
val times = rowElements[1].text().split('-')
|
||||
val startTime = Time.fromH_m(times[0].trim())
|
||||
val endTime = Time.fromH_m(times[1].trim())
|
||||
|
||||
data.lessonRanges.singleOrNull {
|
||||
it.lessonNumber == lessonNumber && it.startTime == startTime && it.endTime == endTime
|
||||
} ?: run {
|
||||
data.lessonRanges.put(lessonNumber, LessonRange(profileId, lessonNumber, startTime, endTime))
|
||||
}
|
||||
|
||||
rowElements.subList(2, rowElements.size).forEachIndexed { index, lesson ->
|
||||
val course = lesson.select(".course").firstOrNull() ?: return@forEachIndexed
|
||||
val info = course.select("span > span")
|
||||
|
||||
if (info.isEmpty()) return@forEachIndexed
|
||||
|
||||
val type = when (course.hasClass("substitute")) {
|
||||
true -> Lesson.TYPE_CHANGE
|
||||
else -> Lesson.TYPE_NORMAL
|
||||
}
|
||||
|
||||
/* Getting subject */
|
||||
|
||||
val subjectElement = info[0].child(0)
|
||||
val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
|
||||
?: return@forEachIndexed
|
||||
val subjectName = subjectElement.text().trim()
|
||||
val subject = data.getSubject(subjectId, subjectName)
|
||||
|
||||
/* Getting teacher */
|
||||
|
||||
val teacherId = if (info.size >= 2) {
|
||||
val teacherElement = info[1].child(0)
|
||||
val teacherLongId = EDUDZIENNIK_TEACHER_ID.find(teacherElement.attr("href"))?.get(1)
|
||||
val teacherName = teacherElement.text().trim()
|
||||
data.getTeacherByLastFirst(teacherName, teacherLongId).id
|
||||
} else null
|
||||
|
||||
val lessonObject = Lesson(profileId, -1).also {
|
||||
it.type = type
|
||||
it.date = weekStart.clone().stepForward(0, 0, index)
|
||||
it.lessonNumber = lessonNumber
|
||||
it.startTime = startTime
|
||||
it.endTime = endTime
|
||||
it.subjectId = subject.id
|
||||
it.teacherId = teacherId
|
||||
it.teamId = data.teamClass?.id
|
||||
|
||||
it.id = it.buildId()
|
||||
}
|
||||
|
||||
data.lessonList.add(lessonObject)
|
||||
dataDays.remove(lessonObject.date!!.value)
|
||||
|
||||
if (type != Lesson.TYPE_NORMAL) {
|
||||
val seen = profile.empty || lessonObject.date!! < Date.getToday()
|
||||
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_LESSON_CHANGE,
|
||||
lessonObject.id,
|
||||
seen,
|
||||
seen
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (day in dataDays) {
|
||||
val lessonDate = Date.fromValue(day)
|
||||
data.lessonList += Lesson(profileId, lessonDate.value.toLong()).apply {
|
||||
type = Lesson.TYPE_NO_LESSONS
|
||||
date = lessonDate
|
||||
}
|
||||
}
|
||||
|
||||
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE)
|
||||
}
|
||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE) }
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.firstlogin
|
||||
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_EDUDZIENNIK
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ACCOUNT_NAME_START
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_STUDENTS_START
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login.EdudziennikLoginWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.fixName
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.getShortName
|
||||
import pl.szczodrzynski.edziennik.set
|
||||
|
||||
class EdudziennikFirstLogin(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikFirstLogin"
|
||||
}
|
||||
|
||||
private val web = EdudziennikWeb(data, null)
|
||||
private val profileList = mutableListOf<Profile>()
|
||||
|
||||
init {
|
||||
val loginStoreId = data.loginStore.id
|
||||
val loginStoreType = LOGIN_TYPE_EDUDZIENNIK
|
||||
var firstProfileId = loginStoreId
|
||||
|
||||
EdudziennikLoginWeb(data) {
|
||||
web.webGet(TAG, "") { text ->
|
||||
val accountNameLong = EDUDZIENNIK_ACCOUNT_NAME_START.find(text)?.get(1)?.fixName()
|
||||
|
||||
EDUDZIENNIK_STUDENTS_START.findAll(text).forEach {
|
||||
val studentId = it[1]
|
||||
val studentNameLong = it[2].fixName()
|
||||
|
||||
if (studentId.isBlank() || studentNameLong.isBlank()) return@forEach
|
||||
|
||||
val studentNameShort = studentNameLong.getShortName()
|
||||
val accountName = if (accountNameLong == studentNameLong) null else accountNameLong
|
||||
|
||||
val profile = Profile(
|
||||
firstProfileId++,
|
||||
loginStoreId,
|
||||
loginStoreType,
|
||||
studentNameLong,
|
||||
data.loginEmail,
|
||||
studentNameLong,
|
||||
studentNameShort,
|
||||
accountName
|
||||
).apply {
|
||||
studentData["studentId"] = studentId
|
||||
}
|
||||
profileList.add(profile)
|
||||
}
|
||||
|
||||
EventBus.getDefault().postSticky(FirstLoginFinishedEvent(profileList, data.loginStore))
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login
|
||||
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
|
||||
class EdudziennikLogin(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikLogin"
|
||||
}
|
||||
|
||||
private var cancelled = false
|
||||
|
||||
init {
|
||||
nextLoginMethod(onSuccess)
|
||||
}
|
||||
|
||||
private fun nextLoginMethod(onSuccess: () -> Unit) {
|
||||
if (data.targetLoginMethodIds.isEmpty()) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
if (cancelled) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
useLoginMethod(data.targetLoginMethodIds.removeAt(0)) { usedMethodId ->
|
||||
data.progress(data.progressStep)
|
||||
if (usedMethodId != -1)
|
||||
data.loginMethods.add(usedMethodId)
|
||||
nextLoginMethod(onSuccess)
|
||||
}
|
||||
}
|
||||
|
||||
private fun useLoginMethod(loginMethodId: Int, onSuccess: (usedMethodId: Int) -> Unit) {
|
||||
// this should never be true
|
||||
if (data.loginMethods.contains(loginMethodId)) {
|
||||
onSuccess(-1)
|
||||
return
|
||||
}
|
||||
Utils.d(TAG, "Using login method $loginMethodId")
|
||||
when (loginMethodId) {
|
||||
LOGIN_METHOD_EDUDZIENNIK_WEB -> {
|
||||
data.startProgress(R.string.edziennik_progress_login_edudziennik_web)
|
||||
EdudziennikLoginWeb(data) { onSuccess(loginMethodId) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login
|
||||
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.getUnixDate
|
||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class EdudziennikLoginWeb(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikLoginWeb"
|
||||
}
|
||||
|
||||
init { run {
|
||||
if (data.isWebLoginValid()) {
|
||||
onSuccess()
|
||||
}
|
||||
else {
|
||||
data.app.cookieJar.clear("dziennikel.appspot.com")
|
||||
if (data.loginEmail.isNotNullNorEmpty() && data.loginPassword.isNotNullNorEmpty()) {
|
||||
loginWithCredentials()
|
||||
}
|
||||
else {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
private fun loginWithCredentials() {
|
||||
d(TAG, "Request: Edudziennik/Login/Web - https://dziennikel.appspot.com/login/?next=/")
|
||||
|
||||
val callback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String?, response: Response?) {
|
||||
if (text == null || response == null) {
|
||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
val url = response.raw().request().url().toString()
|
||||
|
||||
if (!url.contains("Student")) {
|
||||
when {
|
||||
text.contains("Wprowadzono nieprawidłową nazwę użytkownika lub hasło.") -> ERROR_LOGIN_EDUDZIENNIK_WEB_INVALID_LOGIN
|
||||
else -> ERROR_LOGIN_EDUDZIENNIK_WEB_OTHER
|
||||
}.let { errorCode ->
|
||||
data.error(ApiError(TAG, errorCode)
|
||||
.withApiResponse(text)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val cookies = data.app.cookieJar.getAll("dziennikel.appspot.com")
|
||||
val sessionId = cookies["sessionid"]
|
||||
|
||||
if (sessionId == null) {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_EDUDZIENNIK_WEB_NO_SESSION_ID)
|
||||
.withResponse(response)
|
||||
.withApiResponse(text))
|
||||
return
|
||||
}
|
||||
|
||||
data.webSessionId = sessionId
|
||||
data.webSessionIdExpiryTime = response.getUnixDate() + 45 * 60 /* 45 min */
|
||||
onSuccess()
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url("https://dziennikel.appspot.com/login/?next=/")
|
||||
.userAgent(EDUDZIENNIK_USER_AGENT)
|
||||
.contentType("application/x-www-form-urlencoded")
|
||||
.addParameter("email", data.loginEmail)
|
||||
.addParameter("password", data.loginPassword)
|
||||
.addParameter("auth_method", "password")
|
||||
.addParameter("next", "/")
|
||||
.post()
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -5,14 +5,15 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.currentTimeUnix
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_API
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_MESSAGES
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_PORTAL
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
import pl.szczodrzynski.edziennik.data.api.models.Data
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod
|
||||
import pl.szczodrzynski.edziennik.ext.currentTimeUnix
|
||||
import pl.szczodrzynski.edziennik.ext.getStudentData
|
||||
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
|
||||
import pl.szczodrzynski.edziennik.ext.set
|
||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||
|
||||
class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
||||
|
||||
@ -24,15 +25,15 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
override fun satisfyLoginMethods() {
|
||||
loginMethods.clear()
|
||||
if (isPortalLoginValid())
|
||||
loginMethods += LoginMethod.LIBRUS_PORTAL
|
||||
loginMethods += LOGIN_METHOD_LIBRUS_PORTAL
|
||||
if (isApiLoginValid())
|
||||
loginMethods += LoginMethod.LIBRUS_API
|
||||
loginMethods += LOGIN_METHOD_LIBRUS_API
|
||||
if (isSynergiaLoginValid()) {
|
||||
loginMethods += LoginMethod.LIBRUS_SYNERGIA
|
||||
loginMethods += LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
app.cookieJar.set("synergia.librus.pl", "DZIENNIKSID", synergiaSessionId)
|
||||
}
|
||||
if (isMessagesLoginValid()) {
|
||||
loginMethods += LoginMethod.LIBRUS_MESSAGES
|
||||
loginMethods += LOGIN_METHOD_LIBRUS_MESSAGES
|
||||
app.cookieJar.set("wiadomosci.librus.pl", "DZIENNIKSID", messagesSessionId)
|
||||
}
|
||||
}
|
||||
@ -119,7 +120,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
private var mApiLogin: String? = null
|
||||
var apiLogin: String?
|
||||
get() { mApiLogin = mApiLogin ?: profile?.getStudentData("accountLogin", null); return mApiLogin }
|
||||
set(value) { profile["accountLogin"] = value; mApiLogin = value }
|
||||
set(value) { profile?.putStudentData("accountLogin", value); mApiLogin = value }
|
||||
/**
|
||||
* A Synergia password.
|
||||
* Used: for login (API Login Method) in Synergia mode.
|
||||
@ -128,7 +129,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
private var mApiPassword: String? = null
|
||||
var apiPassword: String?
|
||||
get() { mApiPassword = mApiPassword ?: profile?.getStudentData("accountPassword", null); return mApiPassword }
|
||||
set(value) { profile["accountPassword"] = value; mApiPassword = value }
|
||||
set(value) { profile?.putStudentData("accountPassword", value); mApiPassword = value }
|
||||
|
||||
/**
|
||||
* A JST login Code.
|
||||
@ -137,7 +138,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
private var mApiCode: String? = null
|
||||
var apiCode: String?
|
||||
get() { mApiCode = mApiCode ?: loginStore.getLoginData("accountCode", null); return mApiCode }
|
||||
set(value) { profile["accountCode"] = value; mApiCode = value }
|
||||
set(value) { profile?.putStudentData("accountCode", value); mApiCode = value }
|
||||
/**
|
||||
* A JST login PIN.
|
||||
* Used only during first login in JST mode.
|
||||
@ -145,7 +146,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
private var mApiPin: String? = null
|
||||
var apiPin: String?
|
||||
get() { mApiPin = mApiPin ?: loginStore.getLoginData("accountPin", null); return mApiPin }
|
||||
set(value) { profile["accountPin"] = value; mApiPin = value }
|
||||
set(value) { profile?.putStudentData("accountPin", value); mApiPin = value }
|
||||
|
||||
/**
|
||||
* A Synergia API access token.
|
||||
@ -156,7 +157,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
private var mApiAccessToken: String? = null
|
||||
var apiAccessToken: String?
|
||||
get() { mApiAccessToken = mApiAccessToken ?: profile?.getStudentData("accountToken", null); return mApiAccessToken }
|
||||
set(value) { mApiAccessToken = value; profile["accountToken"] = value ?: return; }
|
||||
set(value) { mApiAccessToken = value; profile?.putStudentData("accountToken", value) ?: return; }
|
||||
/**
|
||||
* A Synergia API refresh token.
|
||||
* Used when refreshing the [apiAccessToken] in JST, Synergia modes.
|
||||
@ -164,7 +165,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
private var mApiRefreshToken: String? = null
|
||||
var apiRefreshToken: String?
|
||||
get() { mApiRefreshToken = mApiRefreshToken ?: profile?.getStudentData("accountRefreshToken", null); return mApiRefreshToken }
|
||||
set(value) { mApiRefreshToken = value; profile["accountRefreshToken"] = value ?: return; }
|
||||
set(value) { mApiRefreshToken = value; profile?.putStudentData("accountRefreshToken", value) ?: return; }
|
||||
/**
|
||||
* The expiry time for [apiAccessToken], as a UNIX timestamp.
|
||||
* Used when refreshing the [apiAccessToken] in JST, Synergia modes.
|
||||
@ -173,7 +174,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
private var mApiTokenExpiryTime: Long? = null
|
||||
var apiTokenExpiryTime: Long
|
||||
get() { mApiTokenExpiryTime = mApiTokenExpiryTime ?: profile?.getStudentData("accountTokenTime", 0L); return mApiTokenExpiryTime ?: 0L }
|
||||
set(value) { mApiTokenExpiryTime = value; profile["accountTokenTime"] = value; }
|
||||
set(value) { mApiTokenExpiryTime = value; profile?.putStudentData("accountTokenTime", value) ?: return; }
|
||||
|
||||
/**
|
||||
* A push device ID, generated by Librus when registering
|
||||
@ -183,7 +184,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
private var mPushDeviceId: Int? = null
|
||||
var pushDeviceId: Int
|
||||
get() { mPushDeviceId = mPushDeviceId ?: profile?.getStudentData("pushDeviceId", 0); return mPushDeviceId ?: 0 }
|
||||
set(value) { mPushDeviceId = value; profile["pushDeviceId"] = value; }
|
||||
set(value) { mPushDeviceId = value; profile?.putStudentData("pushDeviceId", value) ?: return; }
|
||||
|
||||
/* _____ _
|
||||
/ ____| (_)
|
||||
@ -200,7 +201,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
private var mSynergiaSessionId: String? = null
|
||||
var synergiaSessionId: String?
|
||||
get() { mSynergiaSessionId = mSynergiaSessionId ?: profile?.getStudentData("accountSID", null); return mSynergiaSessionId }
|
||||
set(value) { profile["accountSID"] = value; mSynergiaSessionId = value }
|
||||
set(value) { profile?.putStudentData("accountSID", value) ?: return; mSynergiaSessionId = value }
|
||||
/**
|
||||
* The expiry time for [synergiaSessionId], as a UNIX timestamp.
|
||||
* Used in endpoints with Synergia login method.
|
||||
@ -209,7 +210,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
private var mSynergiaSessionIdExpiryTime: Long? = null
|
||||
var synergiaSessionIdExpiryTime: Long
|
||||
get() { mSynergiaSessionIdExpiryTime = mSynergiaSessionIdExpiryTime ?: profile?.getStudentData("accountSIDTime", 0L); return mSynergiaSessionIdExpiryTime ?: 0L }
|
||||
set(value) { profile["accountSIDTime"] = value; mSynergiaSessionIdExpiryTime = value }
|
||||
set(value) { profile?.putStudentData("accountSIDTime", value) ?: return; mSynergiaSessionIdExpiryTime = value }
|
||||
|
||||
|
||||
/**
|
||||
@ -219,7 +220,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
private var mMessagesSessionId: String? = null
|
||||
var messagesSessionId: String?
|
||||
get() { mMessagesSessionId = mMessagesSessionId ?: profile?.getStudentData("messagesSID", null); return mMessagesSessionId }
|
||||
set(value) { profile["messagesSID"] = value; mMessagesSessionId = value }
|
||||
set(value) { profile?.putStudentData("messagesSID", value) ?: return; mMessagesSessionId = value }
|
||||
/**
|
||||
* The expiry time for [messagesSessionId], as a UNIX timestamp.
|
||||
* Used in endpoints with Messages login method.
|
||||
@ -228,7 +229,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
private var mMessagesSessionIdExpiryTime: Long? = null
|
||||
var messagesSessionIdExpiryTime: Long
|
||||
get() { mMessagesSessionIdExpiryTime = mMessagesSessionIdExpiryTime ?: profile?.getStudentData("messagesSIDTime", 0L); return mMessagesSessionIdExpiryTime ?: 0L }
|
||||
set(value) { profile["messagesSIDTime"] = value; mMessagesSessionIdExpiryTime = value }
|
||||
set(value) { profile?.putStudentData("messagesSIDTime", value) ?: return; mMessagesSessionIdExpiryTime = value }
|
||||
|
||||
/* ____ _ _
|
||||
/ __ \| | | |
|
||||
@ -238,42 +239,42 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
\____/ \__|_| |_|\___|*/
|
||||
var isPremium
|
||||
get() = profile?.getStudentData("isPremium", false) ?: false
|
||||
set(value) { profile["isPremium"] = value }
|
||||
set(value) { profile?.putStudentData("isPremium", value) }
|
||||
|
||||
private var mSchoolName: String? = null
|
||||
var schoolName: String?
|
||||
get() { mSchoolName = mSchoolName ?: profile?.getStudentData("schoolName", null); return mSchoolName }
|
||||
set(value) { profile["schoolName"] = value; mSchoolName = value }
|
||||
set(value) { profile?.putStudentData("schoolName", value) ?: return; mSchoolName = value }
|
||||
|
||||
private var mUnitId: Long? = null
|
||||
var unitId: Long
|
||||
get() { mUnitId = mUnitId ?: profile?.getStudentData("unitId", 0L); return mUnitId ?: 0L }
|
||||
set(value) { profile["unitId"] = value; mUnitId = value }
|
||||
set(value) { profile?.putStudentData("unitId", value) ?: return; mUnitId = value }
|
||||
|
||||
private var mStartPointsSemester1: Int? = null
|
||||
var startPointsSemester1: Int
|
||||
get() { mStartPointsSemester1 = mStartPointsSemester1 ?: profile?.getStudentData("startPointsSemester1", 0); return mStartPointsSemester1 ?: 0 }
|
||||
set(value) { profile["startPointsSemester1"] = value; mStartPointsSemester1 = value }
|
||||
set(value) { profile?.putStudentData("startPointsSemester1", value) ?: return; mStartPointsSemester1 = value }
|
||||
|
||||
private var mStartPointsSemester2: Int? = null
|
||||
var startPointsSemester2: Int
|
||||
get() { mStartPointsSemester2 = mStartPointsSemester2 ?: profile?.getStudentData("startPointsSemester2", 0); return mStartPointsSemester2 ?: 0 }
|
||||
set(value) { profile["startPointsSemester2"] = value; mStartPointsSemester2 = value }
|
||||
set(value) { profile?.putStudentData("startPointsSemester2", value) ?: return; mStartPointsSemester2 = value }
|
||||
|
||||
private var mEnablePointGrades: Boolean? = null
|
||||
var enablePointGrades: Boolean
|
||||
get() { mEnablePointGrades = mEnablePointGrades ?: profile?.getStudentData("enablePointGrades", true); return mEnablePointGrades ?: true }
|
||||
set(value) { profile["enablePointGrades"] = value; mEnablePointGrades = value }
|
||||
set(value) { profile?.putStudentData("enablePointGrades", value) ?: return; mEnablePointGrades = value }
|
||||
|
||||
private var mEnableDescriptiveGrades: Boolean? = null
|
||||
var enableDescriptiveGrades: Boolean
|
||||
get() { mEnableDescriptiveGrades = mEnableDescriptiveGrades ?: profile?.getStudentData("enableDescriptiveGrades", true); return mEnableDescriptiveGrades ?: true }
|
||||
set(value) { profile["enableDescriptiveGrades"] = value; mEnableDescriptiveGrades = value }
|
||||
set(value) { profile?.putStudentData("enableDescriptiveGrades", value) ?: return; mEnableDescriptiveGrades = value }
|
||||
|
||||
private var mTimetableNotPublic: Boolean? = null
|
||||
var timetableNotPublic: Boolean
|
||||
get() { mTimetableNotPublic = mTimetableNotPublic ?: profile?.getStudentData("timetableNotPublic", false); return mTimetableNotPublic ?: false }
|
||||
set(value) { profile["timetableNotPublic"] = value; mTimetableNotPublic = value }
|
||||
set(value) { profile?.putStudentData("timetableNotPublic", value) ?: return; mTimetableNotPublic = value }
|
||||
|
||||
/**
|
||||
* Set to false when Recaptcha helper doesn't provide a working token.
|
||||
|
@ -16,7 +16,6 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.Librus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.firstlogin.LibrusFirstLogin
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLogin
|
||||
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
@ -24,8 +23,6 @@ import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
@ -60,19 +57,19 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
||||
__/ |
|
||||
|__*/
|
||||
override fun sync(featureTypes: Set<FeatureType>?, onlyEndpoints: Set<Int>?, arguments: JsonObject?) {
|
||||
override fun sync(featureIds: List<Int>, viewId: Int?, onlyEndpoints: List<Int>?, arguments: JsonObject?) {
|
||||
data.arguments = arguments
|
||||
data.prepare(LibrusFeatures, featureTypes, onlyEndpoints)
|
||||
data.prepare(librusLoginMethods, LibrusFeatures, featureIds, viewId, onlyEndpoints)
|
||||
login()
|
||||
}
|
||||
|
||||
private fun login(loginMethod: LoginMethod? = null, afterLogin: (() -> Unit)? = null) {
|
||||
d(TAG, "Trying to login with ${data.targetLoginMethods}")
|
||||
private fun login(loginMethodId: Int? = null, afterLogin: (() -> Unit)? = null) {
|
||||
d(TAG, "Trying to login with ${data.targetLoginMethodIds}")
|
||||
if (internalErrorList.isNotEmpty()) {
|
||||
d(TAG, " - Internal errors:")
|
||||
internalErrorList.forEach { d(TAG, " - code $it") }
|
||||
}
|
||||
loginMethod?.let { data.prepareFor(it) }
|
||||
loginMethodId?.let { data.prepareFor(librusLoginMethods, it) }
|
||||
afterLogin?.let { this.afterLogin = it }
|
||||
LibrusLogin(data) {
|
||||
data()
|
||||
@ -80,7 +77,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
}
|
||||
|
||||
private fun data() {
|
||||
d(TAG, "Endpoint IDs: ${data.targetEndpoints}")
|
||||
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
||||
if (internalErrorList.isNotEmpty()) {
|
||||
d(TAG, " - Internal errors:")
|
||||
internalErrorList.forEach { d(TAG, " - code $it") }
|
||||
@ -91,14 +88,14 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
}
|
||||
|
||||
override fun getMessage(message: MessageFull) {
|
||||
login(LoginMethod.LIBRUS_MESSAGES) {
|
||||
login(LOGIN_METHOD_LIBRUS_MESSAGES) {
|
||||
if (data.messagesLoginSuccessful) LibrusMessagesGetMessage(data, message) { completed() }
|
||||
else LibrusSynergiaGetMessage(data, message) { completed() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun sendMessage(recipients: Set<Teacher>, subject: String, text: String) {
|
||||
login(LoginMethod.LIBRUS_MESSAGES) {
|
||||
override fun sendMessage(recipients: List<Teacher>, subject: String, text: String) {
|
||||
login(LOGIN_METHOD_LIBRUS_MESSAGES) {
|
||||
LibrusMessagesSendMessage(data, recipients, subject, text) {
|
||||
completed()
|
||||
}
|
||||
@ -106,7 +103,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
}
|
||||
|
||||
override fun markAllAnnouncementsAsRead() {
|
||||
login(LoginMethod.LIBRUS_SYNERGIA) {
|
||||
login(LOGIN_METHOD_LIBRUS_SYNERGIA) {
|
||||
LibrusSynergiaMarkAllAnnouncementsAsRead(data) {
|
||||
completed()
|
||||
}
|
||||
@ -114,7 +111,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
}
|
||||
|
||||
override fun getAnnouncement(announcement: AnnouncementFull) {
|
||||
login(LoginMethod.LIBRUS_API) {
|
||||
login(LOGIN_METHOD_LIBRUS_API) {
|
||||
LibrusApiAnnouncementMarkAsRead(data, announcement) {
|
||||
completed()
|
||||
}
|
||||
@ -124,13 +121,13 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {
|
||||
when (owner) {
|
||||
is Message -> {
|
||||
login(LoginMethod.LIBRUS_SYNERGIA) {
|
||||
login(LOGIN_METHOD_LIBRUS_SYNERGIA) {
|
||||
if (data.messagesLoginSuccessful) LibrusMessagesGetAttachment(data, owner, attachmentId, attachmentName) { completed() }
|
||||
LibrusSynergiaGetAttachment(data, owner, attachmentId, attachmentName) { completed() }
|
||||
}
|
||||
}
|
||||
is EventFull -> {
|
||||
login(LoginMethod.LIBRUS_SYNERGIA) {
|
||||
login(LOGIN_METHOD_LIBRUS_SYNERGIA) {
|
||||
LibrusSynergiaHomeworkGetAttachment(data, owner, attachmentId, attachmentName) {
|
||||
completed()
|
||||
}
|
||||
@ -141,7 +138,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
}
|
||||
|
||||
override fun getRecipientList() {
|
||||
login(LoginMethod.LIBRUS_MESSAGES) {
|
||||
login(LOGIN_METHOD_LIBRUS_MESSAGES) {
|
||||
LibrusMessagesGetRecipientList(data) {
|
||||
completed()
|
||||
}
|
||||
@ -149,7 +146,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
}
|
||||
|
||||
override fun getEvent(eventFull: EventFull) {
|
||||
login(LoginMethod.LIBRUS_SYNERGIA) {
|
||||
login(LOGIN_METHOD_LIBRUS_SYNERGIA) {
|
||||
LibrusSynergiaGetHomework(data, eventFull) {
|
||||
completed()
|
||||
}
|
||||
@ -165,7 +162,6 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||
return object : EdziennikCallback {
|
||||
override fun onCompleted() { callback.onCompleted() }
|
||||
override fun onRequiresUserAction(event: UserActionRequiredEvent) { callback.onRequiresUserAction(event) }
|
||||
override fun onProgress(step: Float) { callback.onProgress(step) }
|
||||
override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) }
|
||||
override fun onError(apiError: ApiError) {
|
||||
@ -177,27 +173,27 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
internalErrorList.add(apiError.errorCode)
|
||||
when (apiError.errorCode) {
|
||||
ERROR_LIBRUS_PORTAL_ACCESS_DENIED -> {
|
||||
data.loginMethods.remove(LoginMethod.LIBRUS_PORTAL)
|
||||
data.prepareFor(LoginMethod.LIBRUS_PORTAL)
|
||||
data.loginMethods.remove(LOGIN_METHOD_LIBRUS_PORTAL)
|
||||
data.prepareFor(librusLoginMethods, LOGIN_METHOD_LIBRUS_PORTAL)
|
||||
data.portalTokenExpiryTime = 0
|
||||
login()
|
||||
}
|
||||
ERROR_LIBRUS_API_ACCESS_DENIED,
|
||||
ERROR_LIBRUS_API_TOKEN_EXPIRED -> {
|
||||
data.loginMethods.remove(LoginMethod.LIBRUS_API)
|
||||
data.prepareFor(LoginMethod.LIBRUS_API)
|
||||
data.loginMethods.remove(LOGIN_METHOD_LIBRUS_API)
|
||||
data.prepareFor(librusLoginMethods, LOGIN_METHOD_LIBRUS_API)
|
||||
data.apiTokenExpiryTime = 0
|
||||
login()
|
||||
}
|
||||
ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED -> {
|
||||
data.loginMethods.remove(LoginMethod.LIBRUS_SYNERGIA)
|
||||
data.prepareFor(LoginMethod.LIBRUS_SYNERGIA)
|
||||
data.loginMethods.remove(LOGIN_METHOD_LIBRUS_SYNERGIA)
|
||||
data.prepareFor(librusLoginMethods, LOGIN_METHOD_LIBRUS_SYNERGIA)
|
||||
data.synergiaSessionIdExpiryTime = 0
|
||||
login()
|
||||
}
|
||||
ERROR_LIBRUS_MESSAGES_ACCESS_DENIED -> {
|
||||
data.loginMethods.remove(LoginMethod.LIBRUS_MESSAGES)
|
||||
data.prepareFor(LoginMethod.LIBRUS_MESSAGES)
|
||||
data.loginMethods.remove(LOGIN_METHOD_LIBRUS_MESSAGES)
|
||||
data.prepareFor(librusLoginMethods, LOGIN_METHOD_LIBRUS_MESSAGES)
|
||||
data.messagesSessionIdExpiryTime = 0
|
||||
login()
|
||||
}
|
||||
|
@ -4,10 +4,8 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.models.Feature
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
|
||||
|
||||
const val ENDPOINT_LIBRUS_API_ME = 1001
|
||||
const val ENDPOINT_LIBRUS_API_SCHOOLS = 1002
|
||||
@ -60,14 +58,14 @@ const val ENDPOINT_LIBRUS_MESSAGES_TRASH = 3030
|
||||
|
||||
val LibrusFeatures = listOf(
|
||||
|
||||
Feature(LoginType.LIBRUS, FeatureType.ALWAYS_NEEDED, listOf(
|
||||
ENDPOINT_LIBRUS_API_LESSONS to LoginMethod.LIBRUS_API
|
||||
)),
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_ALWAYS_NEEDED, listOf(
|
||||
ENDPOINT_LIBRUS_API_LESSONS to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
|
||||
// push config
|
||||
Feature(LoginType.LIBRUS, FeatureType.PUSH_CONFIG, listOf(
|
||||
ENDPOINT_LIBRUS_API_PUSH_CONFIG to LoginMethod.LIBRUS_API
|
||||
)).withShouldSync { data ->
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_PUSH_CONFIG, listOf(
|
||||
ENDPOINT_LIBRUS_API_PUSH_CONFIG to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)).withShouldSync { data ->
|
||||
(data as DataLibrus).isPremium && !data.app.config.sync.tokenLibrusList.contains(data.profileId)
|
||||
},
|
||||
|
||||
@ -78,72 +76,72 @@ val LibrusFeatures = listOf(
|
||||
/**
|
||||
* Timetable - using API.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.TIMETABLE, listOf(
|
||||
ENDPOINT_LIBRUS_API_TIMETABLES to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_SUBSTITUTIONS to LoginMethod.LIBRUS_API
|
||||
)),
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_TIMETABLE, listOf(
|
||||
ENDPOINT_LIBRUS_API_TIMETABLES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_SUBSTITUTIONS to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* Agenda - using API.
|
||||
* Events, Parent-teacher meetings, free days (teacher/school/class).
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.AGENDA, listOf(
|
||||
ENDPOINT_LIBRUS_API_EVENTS to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_EVENT_TYPES to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_PT_MEETINGS to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_SCHOOL_FREE_DAYS to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS to LoginMethod.LIBRUS_API
|
||||
)),
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_AGENDA, listOf(
|
||||
ENDPOINT_LIBRUS_API_EVENTS to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_EVENT_TYPES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_PT_MEETINGS to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_SCHOOL_FREE_DAYS to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* Grades - using API.
|
||||
* All grades + categories.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.GRADES, listOf(
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADE_CATEGORIES to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_POINT_GRADE_CATEGORIES to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADE_CATEGORIES to LoginMethod.LIBRUS_API,
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf(
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_POINT_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API,
|
||||
// Commented out, because TextGrades/Categories is the same as Grades/Categories
|
||||
/* ENDPOINT_LIBRUS_API_TEXT_GRADE_CATEGORIES to LoginMethod.LIBRUS_API, */
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADE_CATEGORIES to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_COMMENTS to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADES to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_POINT_GRADES to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_TEXT_GRADES to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADES to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES to LoginMethod.LIBRUS_API
|
||||
)),
|
||||
/* ENDPOINT_LIBRUS_API_TEXT_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API, */
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_COMMENTS to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_POINT_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_TEXT_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* Homework - using API.
|
||||
* Sync only if account has premium access.
|
||||
*/
|
||||
/*Feature(LoginType.LIBRUS, FeatureType.HOMEWORK, listOf(
|
||||
ENDPOINT_LIBRUS_API_HOMEWORK to LoginMethod.LIBRUS_API
|
||||
)).withShouldSync { data ->
|
||||
/*Feature(LOGIN_TYPE_LIBRUS, FEATURE_HOMEWORK, listOf(
|
||||
ENDPOINT_LIBRUS_API_HOMEWORK to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)).withShouldSync { data ->
|
||||
(data as DataLibrus).isPremium
|
||||
},*/
|
||||
/**
|
||||
* Behaviour - using API.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.BEHAVIOUR, listOf(
|
||||
ENDPOINT_LIBRUS_API_NOTICES to LoginMethod.LIBRUS_API
|
||||
)),
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_BEHAVIOUR, listOf(
|
||||
ENDPOINT_LIBRUS_API_NOTICES to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* Attendance - using API.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.ATTENDANCE, listOf(
|
||||
ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_ATTENDANCES to LoginMethod.LIBRUS_API
|
||||
)),
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_ATTENDANCE, listOf(
|
||||
ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_ATTENDANCES to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* Announcements - using API.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.ANNOUNCEMENTS, listOf(
|
||||
ENDPOINT_LIBRUS_API_ANNOUNCEMENTS to LoginMethod.LIBRUS_API
|
||||
)),
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_ANNOUNCEMENTS, listOf(
|
||||
ENDPOINT_LIBRUS_API_ANNOUNCEMENTS to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
|
||||
|
||||
|
||||
@ -152,99 +150,99 @@ val LibrusFeatures = listOf(
|
||||
/**
|
||||
* Student info - using API.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.STUDENT_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_API_ME to LoginMethod.LIBRUS_API
|
||||
)),
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_API_ME to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* School info - using API.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.SCHOOL_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_API_SCHOOLS to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_UNITS to LoginMethod.LIBRUS_API
|
||||
)),
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_SCHOOL_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_API_SCHOOLS to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_UNITS to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* Class info - using API.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.CLASS_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_API_CLASSES to LoginMethod.LIBRUS_API
|
||||
)),
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_CLASS_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_API_CLASSES to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* Team info - using API.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.TEAM_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES to LoginMethod.LIBRUS_API
|
||||
)),
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_TEAM_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* Lucky number - using API.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.LUCKY_NUMBER, listOf(
|
||||
ENDPOINT_LIBRUS_API_LUCKY_NUMBER to LoginMethod.LIBRUS_API
|
||||
)).withShouldSync { data -> data.shouldSyncLuckyNumber() },
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_LUCKY_NUMBER, listOf(
|
||||
ENDPOINT_LIBRUS_API_LUCKY_NUMBER to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)).withShouldSync { data -> data.shouldSyncLuckyNumber() },
|
||||
/**
|
||||
* Teacher list - using API.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.TEACHERS, listOf(
|
||||
ENDPOINT_LIBRUS_API_USERS to LoginMethod.LIBRUS_API
|
||||
)),
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_TEACHERS, listOf(
|
||||
ENDPOINT_LIBRUS_API_USERS to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* Subject list - using API.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.SUBJECTS, listOf(
|
||||
ENDPOINT_LIBRUS_API_SUBJECTS to LoginMethod.LIBRUS_API
|
||||
)),
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_SUBJECTS, listOf(
|
||||
ENDPOINT_LIBRUS_API_SUBJECTS to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* Classroom list - using API.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.CLASSROOMS, listOf(
|
||||
ENDPOINT_LIBRUS_API_CLASSROOMS to LoginMethod.LIBRUS_API
|
||||
)),
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_CLASSROOMS, listOf(
|
||||
ENDPOINT_LIBRUS_API_CLASSROOMS to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
|
||||
/**
|
||||
* Student info - using synergia scrapper.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.STUDENT_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_SYNERGIA_INFO to LoginMethod.LIBRUS_SYNERGIA
|
||||
)),
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_SYNERGIA_INFO to LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)),
|
||||
/**
|
||||
* Student number - using synergia scrapper.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.STUDENT_NUMBER, listOf(
|
||||
ENDPOINT_LIBRUS_SYNERGIA_INFO to LoginMethod.LIBRUS_SYNERGIA
|
||||
)),
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_NUMBER, listOf(
|
||||
ENDPOINT_LIBRUS_SYNERGIA_INFO to LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)),
|
||||
|
||||
|
||||
/**
|
||||
* Grades - using API + synergia scrapper.
|
||||
*/
|
||||
/*Feature(LoginType.LIBRUS, FeatureType.GRADES, listOf(
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GC to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADES to LoginMethod.LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_SYNERGIA_GRADES to LoginMethod.LIBRUS_SYNERGIA
|
||||
)),*/
|
||||
/*Endpoint(LoginType.LIBRUS, FeatureType.GRADES, listOf(
|
||||
ENDPOINT_LIBRUS_SYNERGIA_GRADES to LoginMethod.LIBRUS_SYNERGIA
|
||||
)),*/
|
||||
/*Feature(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf(
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GC to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_SYNERGIA_GRADES to LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API, LOGIN_METHOD_LIBRUS_SYNERGIA)),*/
|
||||
/*Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf(
|
||||
ENDPOINT_LIBRUS_SYNERGIA_GRADES to LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)),*/
|
||||
|
||||
/**
|
||||
* Homework - using scrapper.
|
||||
* Sync only if account has not premium access.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.HOMEWORK, listOf(
|
||||
ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK to LoginMethod.LIBRUS_SYNERGIA
|
||||
))/*.withShouldSync { data ->
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_HOMEWORK, listOf(
|
||||
ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK to LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA))/*.withShouldSync { data ->
|
||||
!(data as DataLibrus).isPremium
|
||||
}*/,
|
||||
|
||||
/**
|
||||
* Messages inbox - using messages website.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.MESSAGES_INBOX, listOf(
|
||||
ENDPOINT_LIBRUS_MESSAGES_RECEIVED to LoginMethod.LIBRUS_MESSAGES
|
||||
)),
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_MESSAGES_INBOX, listOf(
|
||||
ENDPOINT_LIBRUS_MESSAGES_RECEIVED to LOGIN_METHOD_LIBRUS_MESSAGES
|
||||
), listOf(LOGIN_METHOD_LIBRUS_MESSAGES)),
|
||||
/**
|
||||
* Messages sent - using messages website.
|
||||
*/
|
||||
Feature(LoginType.LIBRUS, FeatureType.MESSAGES_SENT, listOf(
|
||||
ENDPOINT_LIBRUS_MESSAGES_SENT to LoginMethod.LIBRUS_MESSAGES
|
||||
))
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_MESSAGES_SENT, listOf(
|
||||
ENDPOINT_LIBRUS_MESSAGES_SENT to LOGIN_METHOD_LIBRUS_MESSAGES
|
||||
), listOf(LOGIN_METHOD_LIBRUS_MESSAGES))
|
||||
)
|
||||
|
@ -10,7 +10,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import pl.szczodrzynski.edziennik.ext.startCoroutineTimer
|
||||
import pl.szczodrzynski.edziennik.startCoroutineTimer
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class LibrusRecaptchaHelper(
|
||||
|
@ -11,7 +11,7 @@ import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.ext.getString
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.net.HttpURLConnection.*
|
||||
|
||||
|
@ -24,7 +24,7 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
}
|
||||
|
||||
private fun nextEndpoint(onSuccess: () -> Unit) {
|
||||
if (data.targetEndpoints.isEmpty()) {
|
||||
if (data.targetEndpointIds.isEmpty()) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
@ -32,8 +32,8 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
val id = data.targetEndpoints.firstKey()
|
||||
val lastSync = data.targetEndpoints.remove(id)
|
||||
val id = data.targetEndpointIds.firstKey()
|
||||
val lastSync = data.targetEndpointIds.remove(id)
|
||||
useEndpoint(id, lastSync) { endpointId ->
|
||||
data.progress(data.progressStep)
|
||||
nextEndpoint(onSuccess)
|
||||
@ -182,6 +182,10 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_pt_meetings)
|
||||
LibrusApiPtMeetings(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_teacher_free_day_types)
|
||||
LibrusApiTeacherFreeDayTypes(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_teacher_free_days)
|
||||
LibrusApiTeacherFreeDays(data, lastSync, onSuccess)
|
||||
|
@ -7,7 +7,7 @@ import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.ext.getString
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.net.HttpURLConnection
|
||||
|
||||
|
@ -12,7 +12,6 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.api.events.AnnouncementGetEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
|
||||
class LibrusApiAnnouncementMarkAsRead(override val data: DataLibrus,
|
||||
@ -35,7 +34,7 @@ class LibrusApiAnnouncementMarkAsRead(override val data: DataLibrus,
|
||||
|
||||
data.setSeenMetadataList.add(Metadata(
|
||||
profileId,
|
||||
MetadataType.ANNOUNCEMENT,
|
||||
Metadata.TYPE_ANNOUNCEMENT,
|
||||
announcement.id,
|
||||
announcement.seen,
|
||||
announcement.notified
|
||||
|
@ -11,8 +11,6 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Announcement
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiAnnouncements(override val data: DataLibrus,
|
||||
@ -55,7 +53,7 @@ class LibrusApiAnnouncements(override val data: DataLibrus,
|
||||
data.announcementList.add(announcementObject)
|
||||
data.setSeenMetadataList.add(Metadata(
|
||||
profileId,
|
||||
MetadataType.ANNOUNCEMENT,
|
||||
Metadata.TYPE_ANNOUNCEMENT,
|
||||
id,
|
||||
read,
|
||||
profile.empty || read
|
||||
|
@ -11,7 +11,6 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.AttendanceType
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiAttendanceTypes(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
@ -59,7 +58,7 @@ class LibrusApiAttendanceTypes(override val data: DataLibrus,
|
||||
))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES, 2* DAY)
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES, 2*DAY)
|
||||
onSuccess(ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES)
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,6 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiAttendances(override val data: DataLibrus,
|
||||
@ -77,7 +75,7 @@ class LibrusApiAttendances(override val data: DataLibrus,
|
||||
if(type?.baseType != Attendance.TYPE_PRESENT) {
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
MetadataType.ATTENDANCE,
|
||||
Metadata.TYPE_ATTENDANCE,
|
||||
id,
|
||||
profile?.empty ?: false || type?.baseType == Attendance.TYPE_PRESENT_CUSTOM || type?.baseType == Attendance.TYPE_UNKNOWN,
|
||||
profile?.empty ?: false || type?.baseType == Attendance.TYPE_PRESENT_CUSTOM || type?.baseType == Attendance.TYPE_UNKNOWN
|
||||
|
@ -10,7 +10,6 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiBehaviourGradeCategories(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -10,7 +10,6 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiBehaviourGradeComments(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -14,8 +14,6 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_POINT_SUM
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import java.text.DecimalFormat
|
||||
|
||||
@ -64,7 +62,7 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
|
||||
data.gradeList.add(semester1StartGradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
MetadataType.GRADE,
|
||||
Metadata.TYPE_GRADE,
|
||||
semester1StartGradeObject.id,
|
||||
true,
|
||||
true
|
||||
@ -92,7 +90,7 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
|
||||
data.gradeList.add(semester2StartGradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
MetadataType.GRADE,
|
||||
Metadata.TYPE_GRADE,
|
||||
semester2StartGradeObject.id,
|
||||
true,
|
||||
true
|
||||
@ -166,7 +164,7 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
MetadataType.GRADE,
|
||||
Metadata.TYPE_GRADE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty
|
||||
|
@ -4,14 +4,14 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.DAY
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_CLASSES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Team
|
||||
import pl.szczodrzynski.edziennik.ext.DAY
|
||||
import pl.szczodrzynski.edziennik.ext.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.ext.getLong
|
||||
import pl.szczodrzynski.edziennik.ext.getString
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.getLong
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiClasses(override val data: DataLibrus,
|
||||
|
@ -9,7 +9,6 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_CLASSROOMS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Classroom
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import java.util.*
|
||||
|
||||
class LibrusApiClassrooms(override val data: DataLibrus,
|
||||
@ -26,8 +25,8 @@ class LibrusApiClassrooms(override val data: DataLibrus,
|
||||
|
||||
classrooms?.forEach { classroom ->
|
||||
val id = classroom.getLong("Id") ?: return@forEach
|
||||
val name = classroom.getString("Name")?.lowercase() ?: ""
|
||||
val symbol = classroom.getString("Symbol")?.lowercase() ?: ""
|
||||
val name = classroom.getString("Name")?.toLowerCase(Locale.getDefault()) ?: ""
|
||||
val symbol = classroom.getString("Symbol")?.toLowerCase(Locale.getDefault()) ?: ""
|
||||
val nameShort = name.fixWhiteSpaces().split(" ").onEach { it[0] }.joinToString()
|
||||
val symbolParts = symbol.fixWhiteSpaces().split(" ")
|
||||
|
||||
@ -41,7 +40,7 @@ class LibrusApiClassrooms(override val data: DataLibrus,
|
||||
data.classrooms.put(id, Classroom(profileId, id, friendlyName))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_CLASSROOMS, 4* DAY)
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_CLASSROOMS, 4*DAY)
|
||||
onSuccess(ENDPOINT_LIBRUS_API_CLASSROOMS)
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADE_CATEGORIES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiDescriptiveGradeCategories(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -15,8 +15,6 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_TEXT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiDescriptiveGrades(override val data: DataLibrus,
|
||||
@ -74,7 +72,7 @@ class LibrusApiDescriptiveGrades(override val data: DataLibrus,
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
MetadataType.GRADE,
|
||||
Metadata.TYPE_GRADE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty
|
||||
|
@ -9,7 +9,6 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_EVENT_TYPES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.EventType
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiEventTypes(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
@ -31,7 +30,7 @@ class LibrusApiEventTypes(override val data: DataLibrus,
|
||||
data.eventTypes.put(id, EventType(profileId, id, name, color))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_EVENT_TYPES, 4* DAY)
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_EVENT_TYPES, 4*DAY)
|
||||
onSuccess(ENDPOINT_LIBRUS_API_EVENT_TYPES)
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,6 @@ import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
@ -72,7 +70,7 @@ class LibrusApiEvents(override val data: DataLibrus,
|
||||
data.metadataList.add(
|
||||
Metadata(
|
||||
profileId,
|
||||
MetadataType.EVENT,
|
||||
Metadata.TYPE_EVENT,
|
||||
id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false
|
||||
|
@ -11,7 +11,6 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiGradeCategories(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -4,12 +4,12 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiGradeComments(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -16,8 +16,6 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_PROPO
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
@ -98,7 +96,7 @@ class LibrusApiGrades(override val data: DataLibrus,
|
||||
data.metadataList.add(
|
||||
Metadata(
|
||||
profileId,
|
||||
MetadataType.GRADE,
|
||||
Metadata.TYPE_GRADE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user