mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-06-12 13:40:47 +02:00
Compare commits
263 Commits
v4.0-beta.
...
api-v2
Author | SHA1 | Date | |
---|---|---|---|
dc9e6081c5 | |||
26f8c03570 | |||
97e0f36f09 | |||
9b13552b73 | |||
d8559637a5 | |||
00a90a14dc | |||
d56afb034b | |||
0327ba37f1 | |||
12a54e58b5 | |||
238250e8c9 | |||
041bfc6cc0 | |||
8a4866cb62 | |||
0e4d609bbf | |||
f07b12bd87 | |||
0413dbffa2 | |||
c214b48409 | |||
91a6366548 | |||
03c9932b8c | |||
ea4919a25d | |||
f98b174857 | |||
c0aeb0d2f3 | |||
fcb627aac6 | |||
7f0aea29cd | |||
f6dcbb6594 | |||
b790421693 | |||
f5a7799924 | |||
b052b5bd66 | |||
12d8de1def | |||
9303483470 | |||
f8adc86a0e | |||
db57c258c5 | |||
ddb2760c16 | |||
14d267a95a | |||
a6c4053896 | |||
949a68ec1d | |||
93333a8c48 | |||
da48c059ec | |||
ee5566d1ef | |||
b794b30346 | |||
0db6393bb0 | |||
fcc3c55110 | |||
328c07eaf4 | |||
b004ec048e | |||
b9f83875a0 | |||
8c869d082b | |||
043f8210ba | |||
41a79caf83 | |||
0427fa6087 | |||
2f3c912dbe | |||
219a7443c0 | |||
6deb408d80 | |||
c6e1ff2164 | |||
bc0918a115 | |||
55ff9173be | |||
d4d548846f | |||
ef4527f140 | |||
0b1e7242bb | |||
30b6ac2a06 | |||
a7fa7cb5e4 | |||
f3e87f9016 | |||
a983af6c28 | |||
114c841f0c | |||
e271048577 | |||
b8c5925e82 | |||
9bda6c8869 | |||
d1608d308c | |||
b8e1e1d33a | |||
8099a037e7 | |||
af23c932a6 | |||
4edabbb186 | |||
37a5bea79b | |||
40cdc7d713 | |||
49825aca48 | |||
1d57c4e705 | |||
87ae5787ee | |||
20f16c25a3 | |||
6f1ec79d9b | |||
18c7eea89c | |||
f73060aeb6 | |||
2f653b83b6 | |||
445dec907d | |||
927316d24b | |||
3957453ed6 | |||
0296c704cb | |||
1e7fe972de | |||
c95bc656ea | |||
a082d95b04 | |||
6866dd4801 | |||
2186da416e | |||
22d859fcde | |||
39514b69b3 | |||
c384736840 | |||
507657f273 | |||
60641742ed | |||
0fc6f07986 | |||
1b2bdc0580 | |||
9bac239f77 | |||
371acb2d2a | |||
454f82e139 | |||
e8da249353 | |||
c7950c53da | |||
b5502478e4 | |||
4480a7e486 | |||
7c7dff743b | |||
c568cd3f2e | |||
6ec2bc6f21 | |||
af3b6f3a97 | |||
d855118610 | |||
c9992d9fe8 | |||
85fe2636cc | |||
35f4a31a76 | |||
1e494ebb70 | |||
ed93627505 | |||
b9b4b0036f | |||
4aa31424d6 | |||
8a825227cb | |||
cc1b581d7e | |||
9936d90ae2 | |||
df1a241b2b | |||
ae89b33fb7 | |||
e05b483f5c | |||
715f536b23 | |||
930813fb8a | |||
acd5e9b998 | |||
06011bf4ae | |||
30e15b813c | |||
fcd7a7f349 | |||
42ef40439e | |||
098beb14fe | |||
0b186a754a | |||
d00963b53d | |||
e282af0e80 | |||
630361849c | |||
88a1de50ca | |||
d8263d0b6a | |||
611ab0f100 | |||
70c307b796 | |||
054a233ad6 | |||
55268f1c43 | |||
1bec6d281c | |||
f17a02be54 | |||
4e8fdd2225 | |||
59819b4a96 | |||
673378d8d9 | |||
30044d6b21 | |||
ee43d40680 | |||
1354faf8c7 | |||
1bfb3781ab | |||
d7d0c6f822 | |||
2bea18dc3c | |||
f998f2d956 | |||
faa77ee5fb | |||
88ec463284 | |||
b7df71d7d9 | |||
6a28dbd2c4 | |||
010f7fa1fe | |||
209f98594f | |||
54121c99a3 | |||
f6f1370edf | |||
d5863485f9 | |||
afc88d316b | |||
b141279811 | |||
1997ea25d5 | |||
f4b49eecd4 | |||
a4493ec964 | |||
af8bda9e92 | |||
06d252e4ca | |||
67be456bb0 | |||
aa5e225148 | |||
367f46fac8 | |||
d2f14093ec | |||
43ed621879 | |||
15c8134d13 | |||
c2b8f71467 | |||
a6b91c3a14 | |||
164cfbfd0d | |||
0bb340e96e | |||
f0447dc455 | |||
626bbfa7a4 | |||
169a900f01 | |||
d0992eaf54 | |||
fc21d757c3 | |||
54363ee919 | |||
fdad3b9997 | |||
4ad826ebe8 | |||
f5e1e9fdd9 | |||
82b232d0e5 | |||
c8c1fe5367 | |||
71128e0244 | |||
453bcaa1f6 | |||
48898ab1d4 | |||
a095520d0d | |||
2e0c6fa6a5 | |||
bfbc0861df | |||
3a500f3f28 | |||
df8094c39c | |||
448fd0e884 | |||
4717b4549e | |||
57a8d72f1c | |||
7e57617e04 | |||
37ddd643ac | |||
bcf3fef303 | |||
7ac4d24106 | |||
93e5bce778 | |||
d48beba307 | |||
760338496c | |||
b52e7a3078 | |||
78c5b6b2a5 | |||
60a3c38951 | |||
4763033f24 | |||
3b0570d21c | |||
16bf478d1a | |||
5bf181b6d1 | |||
21b2e5d194 | |||
759afcf3ca | |||
d48c7844a4 | |||
7d8caa8df7 | |||
62f53930da | |||
9a45cbb679 | |||
8e5a10f6d8 | |||
10c57d2272 | |||
67d4d0f898 | |||
97e0d04842 | |||
3ba30ede92 | |||
1035e411ab | |||
d5ae4b7ec9 | |||
111d040cf9 | |||
8cc594d170 | |||
d8a8bed68d | |||
eedbd954bd | |||
0eb8366027 | |||
894135104b | |||
7b2e408efc | |||
e4115c122e | |||
537b16949e | |||
ca60ceb2a7 | |||
0fad12fea5 | |||
6cd2c23aac | |||
512baaa43f | |||
d097fcc973 | |||
621dbd459c | |||
840ab4b0c4 | |||
904be34a87 | |||
b7fc6fcc38 | |||
55c6e40d6d | |||
4dfb015057 | |||
e40a0ba2bb | |||
fd48f10df9 | |||
6a54e7fef7 | |||
5c4d6ed140 | |||
9ed1be3594 | |||
c5ce582678 | |||
2050083bce | |||
92e6bdb562 | |||
93e70c38b7 | |||
45b96179a5 | |||
a29a534a40 | |||
8e2297359c | |||
92ba7248ef | |||
f657d37cbd | |||
9e312f60bf | |||
85f72b78f7 | |||
40acb67ceb |
3
.gitignore
vendored
3
.gitignore
vendored
@ -86,4 +86,5 @@ app/schemas/
|
||||
|
||||
signatures/
|
||||
|
||||
app/.cxx
|
||||
app/.cxx
|
||||
/i18n/
|
||||
|
10
.idea/jarRepositories.xml
generated
10
.idea/jarRepositories.xml
generated
@ -41,5 +41,15 @@
|
||||
<option name="name" value="MavenRepo" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven4" />
|
||||
<option name="name" value="maven4" />
|
||||
<option name="url" value="https://dl.bintray.com/undervoid/Powerpermission" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven4" />
|
||||
<option name="name" value="maven4" />
|
||||
<option name="url" value="https://dl.bintray.com/undervoid/PowerPermission" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
@ -2,7 +2,7 @@ apply plugin: 'com.android.library'
|
||||
//apply plugin: 'me.tatarka.retrolambda'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
compileSdkVersion setup.compileSdk
|
||||
|
||||
android {
|
||||
lintOptions {
|
||||
@ -12,7 +12,7 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
targetSdkVersion setup.targetSdk
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
@ -43,9 +43,9 @@ android {
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
// Google libraries
|
||||
implementation "androidx.appcompat:appcompat:${androidXAppCompat}"
|
||||
implementation "androidx.recyclerview:recyclerview:${androidXRecyclerView}"
|
||||
implementation "com.google.android.material:material:${googleMaterial}"
|
||||
implementation "androidx.appcompat:appcompat:${versions.appcompat}"
|
||||
implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}"
|
||||
implementation "com.google.android.material:material:${versions.material}"
|
||||
|
||||
// other libraries
|
||||
//implementation 'se.emilsjolander:stickylistheaders:2.7.0'
|
||||
|
1
annotation/.gitignore
vendored
Normal file
1
annotation/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
29
annotation/build.gradle
Normal file
29
annotation/build.gradle
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-28.
|
||||
*/
|
||||
|
||||
apply plugin: 'java-library'
|
||||
apply plugin: 'kotlin'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
}
|
||||
|
||||
sourceCompatibility = "7"
|
||||
targetCompatibility = "7"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
compileKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
compileTestKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.annotation
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
@MustBeDocumented
|
||||
annotation class SelectiveDao(
|
||||
val db: KClass<*>
|
||||
)
|
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.annotation
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
@MustBeDocumented
|
||||
annotation class UpdateSelective(
|
||||
val primaryKeys: Array<String>,
|
||||
val skippedColumns: Array<String> = []
|
||||
)
|
@ -1,13 +1,14 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'io.fabric'
|
||||
|
||||
android {
|
||||
signingConfigs {
|
||||
}
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
compileSdkVersion setup.compileSdk
|
||||
defaultConfig {
|
||||
applicationId 'pl.szczodrzynski.edziennik'
|
||||
minSdkVersion setup.minSdk
|
||||
@ -103,7 +104,7 @@ tasks.whenTaskAdded { task ->
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
|
||||
annotationProcessor "androidx.room:room-compiler:${versions.room}"
|
||||
kapt "androidx.room:room-compiler:${versions.room}"
|
||||
debugImplementation "com.amitshekhar.android:debug-db:1.0.5"
|
||||
|
||||
implementation "android.arch.navigation:navigation-fragment-ktx:${versions.navigationFragment}"
|
||||
@ -127,6 +128,7 @@ dependencies {
|
||||
implementation "com.mikepenz:iconics-core:${versions.iconics}"
|
||||
implementation "com.mikepenz:iconics-views:${versions.iconics}"
|
||||
implementation "com.mikepenz:community-material-typeface:${versions.font_cmd}@aar"
|
||||
implementation "com.mikepenz:materialize:1.2.1"
|
||||
|
||||
implementation "com.github.kuba2k2:NavLib:${versions.navlib}"
|
||||
|
||||
@ -165,8 +167,8 @@ dependencies {
|
||||
//implementation project(":Navigation")
|
||||
implementation project(":szkolny-font")
|
||||
|
||||
debugImplementation "com.github.ChuckerTeam.Chucker:library:3.0.1"
|
||||
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:3.0.1"
|
||||
implementation "com.github.ChuckerTeam.Chucker:library:3.0.1"
|
||||
//releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:3.0.1"
|
||||
|
||||
//implementation 'com.github.wulkanowy:uonet-request-signer:master-SNAPSHOT'
|
||||
//implementation 'com.github.kuba2k2.uonet-request-signer:android:master-63f094b14a-1'
|
||||
@ -187,6 +189,18 @@ dependencies {
|
||||
implementation "com.squareup.retrofit2:converter-gson:${versions.retrofit}"
|
||||
|
||||
implementation 'com.github.jetradarmobile:android-snowfall:1.2.0'
|
||||
|
||||
implementation "io.coil-kt:coil:0.9.2"
|
||||
|
||||
implementation 'com.github.kuba2k2:NumberSlidingPicker:2921225f76'
|
||||
|
||||
implementation project(":annotation")
|
||||
kapt project(":codegen")
|
||||
|
||||
implementation 'com.google.android:flexbox:2.0.1'
|
||||
|
||||
implementation 'com.qifan.powerpermission:powerpermission:1.0.0'
|
||||
implementation 'com.qifan.powerpermission:powerpermission-coroutines:1.0.0'
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
@ -24,11 +24,18 @@
|
||||
-keep class pl.szczodrzynski.edziennik.utils.models.** { *; }
|
||||
-keep class pl.szczodrzynski.edziennik.data.db.entity.Event { *; }
|
||||
-keep class pl.szczodrzynski.edziennik.data.db.full.EventFull { *; }
|
||||
-keep class pl.szczodrzynski.edziennik.data.db.entity.FeedbackMessage { *; }
|
||||
-keep class pl.szczodrzynski.edziennik.ui.modules.home.HomeCardModel { *; }
|
||||
-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.widgets.luckynumber.WidgetLuckyNumber
|
||||
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.luckynumber.WidgetLuckyNumberProvider
|
||||
|
||||
-keepnames class androidx.appcompat.view.menu.MenuBuilder { setHeaderTitleInt(java.lang.CharSequence); }
|
||||
-keepclassmembernames class androidx.appcompat.view.menu.StandardMenuPopup { private *; }
|
||||
-keepnames class androidx.appcompat.view.menu.MenuPopupHelper { showPopup(int, int, boolean, boolean); }
|
||||
|
||||
-keepclassmembernames class com.mikepenz.materialdrawer.widget.MiniDrawerSliderView { private *; }
|
||||
|
||||
-keep class .R
|
||||
-keep class **.R$* {
|
||||
|
@ -14,6 +14,9 @@
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<!-- 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" />
|
||||
|
||||
<application
|
||||
android:name=".App"
|
||||
android:allowBackup="true"
|
||||
@ -62,7 +65,7 @@
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:excludeFromRecents="true"
|
||||
android:noHistory="true"
|
||||
android:theme="@style/AppTheme.NoDisplay">
|
||||
android:theme="@style/AppTheme.Dark.NoDisplay">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||
</intent-filter>
|
||||
@ -80,10 +83,11 @@
|
||||
<service android:name=".ui.widgets.timetable.WidgetTimetableService"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||
<activity android:name=".ui.widgets.LessonDialogActivity"
|
||||
android:label=""
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:excludeFromRecents="true"
|
||||
android:noHistory="true"
|
||||
android:theme="@style/AppTheme.NoDisplay" />
|
||||
android:theme="@style/AppTheme.Dark.NoDisplay" />
|
||||
<!-- NOTIFICATIONS -->
|
||||
<receiver android:name=".ui.widgets.notifications.WidgetNotificationsProvider"
|
||||
android:label="@string/widget_notifications_title">
|
||||
@ -141,12 +145,8 @@
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity android:name=".ui.modules.settings.SettingsLicenseActivity"
|
||||
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity android:name=".ui.modules.webpush.WebPushConfigActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:theme="@style/AppTheme.Dark" />
|
||||
<activity android:name=".ui.modules.webpush.QrScannerActivity" />
|
||||
<activity android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
@ -165,18 +165,9 @@
|
||||
<action android:name="android.intent.action.USER_PRESENT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:name=".receivers.BootReceiver">
|
||||
<receiver android:name=".sync.UpdateDownloaderService$DownloadProgressReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
||||
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:name=".sync.FirebaseBroadcastReceiver"
|
||||
android:exported="true"
|
||||
android:permission="com.google.android.c2dm.permission.SEND">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:name=".receivers.SzkolnyReceiver"
|
||||
@ -193,16 +184,22 @@
|
||||
____) | __/ | \ V /| | (_| __/\__ \
|
||||
|_____/ \___|_| \_/ |_|\___\___||___/
|
||||
-->
|
||||
<service android:name=".sync.MyFirebaseMessagingService"
|
||||
<!--<service android:name=".sync.MyFirebaseMessagingService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service android:name=".receivers.BootReceiver$NotificationActionService" />
|
||||
<service android:name=".Notifier$GetDataRetryService" />
|
||||
</service>-->
|
||||
<service android:name=".data.api.ApiService" />
|
||||
<service android:name=".data.firebase.MyFirebaseService"
|
||||
android:exported="false">
|
||||
<intent-filter android:priority="10000000">
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service android:name=".sync.UpdateDownloaderService" />
|
||||
|
||||
<!--
|
||||
_____ _ _
|
||||
|
@ -1,37 +1,32 @@
|
||||
<h3>Wersja 4.0-beta.3, 2020-01-10</h3>
|
||||
<h3>Wersja 4.0, 2020-04-19</h3>
|
||||
<ul>
|
||||
<li><b>Przebudowaliśmy cały moduł synchronizacji</b>, co oznacza większą stabilność aplikacji, szybkosć oraz poprawność pobieranych danych.</li>
|
||||
<li><b><u>Wysyłanie wiadomości</u></b> - funkcja, na którą czekał każdy. Od teraz w Szkolnym można wysyłać oraz odpowiadać na wiadomości do nauczycieli 👏</li>
|
||||
<li><b>Przebudowaliśmy cały moduł synchronizacji</b>, co oznacza większą stabilność aplikacji, szybkość oraz poprawność pobieranych danych</li>
|
||||
<li>Udoskonalony wygląd Szkolnego - sprawi, że korzystanie z aplikacji będzie jeszcze przyjemniejsze</li>
|
||||
<li>Wyszukiwarka wiadomości, pozwalająca na łatwe znalezienie potrzebnej konwersacji.</li>
|
||||
<li>Możliwość pobierania załączników do zadań domowych oraz wiadomości w każdym dzienniku.</li>
|
||||
<li>Nowa <b>Strona główna</b> - ładniejszy wygląd oraz możliwość przestawiania kart na każdym profilu</li>
|
||||
<li>Nowy <b>Plan lekcji</b> - z doskonałą obsługą lekcji przesuniętych oraz dwóch lekcji o tej samej godzinie</li>
|
||||
<li>Nowe <b>Oceny</b> - z możliwością zmiany wartości plusów oraz minusów oraz wyłączenia niektórych ocen ze średniej</li>
|
||||
<li>Opcja wyłączenia wybranych powiadomień z aplikacji</li>
|
||||
<li>Znaczki nieprzeczytanych informacji na obrazkach profili.</li>
|
||||
<br>
|
||||
<br>
|
||||
<li>Udoskonalone tłumaczenie na j.angielski (dzięki @Predator)</li>
|
||||
<li>Nowe okienka informacji o wydarzeniach oraz lekcjach</li>
|
||||
<li>Łatwiejsze dodawanie własnych wydarzeń</li>
|
||||
<li>Nowe, przyjemniejsze powiadomienia</li>
|
||||
<li>Dużo poprawek w widoku <b>Wiadomości</b> oraz <b>Ogłoszeń</b></li>
|
||||
<li>Częściowa <b>Obsługa dziennika EduDziennik</b></li>
|
||||
<li>Librus: opcja logowania w dziennikach <b>Jednostek Samorządu Terytorialnego</b> oraz <b>Oświata w Radomiu</b></li>
|
||||
<li>Librus: <b>poprawione obliczanie frekwencji</b></li>
|
||||
<li>Librus: obsługa Zadań domowych bez posiadania Mobilnych dodatków (przez system Synergia)</li>
|
||||
<li>Lepsze <b>przekazywanie powiadomień na komputer</b> oraz łatwiejsze parowanie</li>
|
||||
<li>Łatwiejsze dodawanie własnych wydarzeń</li>
|
||||
<li>Poprawiliśmy synchronizację w tle na niektórych telefonach</li>
|
||||
<li>Usunąłem denerwujący brak zaznaczenia w lewym menu</li>
|
||||
<li>Znaczna ilość błędów z poprzednich wersji już nie występuje</li>
|
||||
</ul>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<b>Uwaga.</b> Ponieważ to wersja <i>beta</i>, niektóre funkcje mogą nie działać prawidłowo.<br>
|
||||
Staramy się usuwać takie przypadki, jednak na chwilę obecną mogą występować błędy w:
|
||||
<ul>
|
||||
<li>Wysyłanie wiadomości może czasami nie działać - proszę o zgłaszanie wszystkich błędów na naszym serwerze Discord</li>
|
||||
<li>Terminarz - brak informacji o odwołanych lekcjach w dialogu</li>
|
||||
</ul>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<i>Okazja ograniczona czasowo:</i> Poczuj prawdziwą zimę, włączając w Ustawieniach widok padającego śniegu!
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
Dzięki za korzystanie ze Szkolnego!<br>
|
||||
<i>© Kuba Szczodrzyński, Kacper Ziubryniewicz 2020</i>
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
/*secret password - removed for source code publication*/
|
||||
static toys AES_IV[16] = {
|
||||
0x1e, 0xef, 0x4e, 0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
0x38, 0xd4, 0x73, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);
|
||||
|
||||
|
@ -1,714 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.content.pm.ShortcutManager;
|
||||
import android.content.pm.Signature;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.work.Configuration;
|
||||
|
||||
import com.chuckerteam.chucker.api.ChuckerCollector;
|
||||
import com.chuckerteam.chucker.api.ChuckerInterceptor;
|
||||
import com.chuckerteam.chucker.api.RetentionManager;
|
||||
import com.google.android.gms.security.ProviderInstaller;
|
||||
import com.google.firebase.FirebaseApp;
|
||||
import com.google.firebase.FirebaseOptions;
|
||||
import com.google.firebase.iid.FirebaseInstanceId;
|
||||
import com.google.firebase.messaging.FirebaseMessaging;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.hypertrack.hyperlog.HyperLog;
|
||||
import com.mikepenz.iconics.Iconics;
|
||||
import com.mikepenz.iconics.IconicsColor;
|
||||
import com.mikepenz.iconics.IconicsDrawable;
|
||||
import com.mikepenz.iconics.IconicsSize;
|
||||
import com.mikepenz.iconics.typeface.IIcon;
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.security.KeyStore;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import cat.ereza.customactivityoncrash.config.CaocConfig;
|
||||
import im.wangchao.mhttp.MHttp;
|
||||
import im.wangchao.mhttp.internal.cookie.PersistentCookieJar;
|
||||
import im.wangchao.mhttp.internal.cookie.cache.SetCookieCache;
|
||||
import im.wangchao.mhttp.internal.cookie.persistence.SharedPrefsCookiePersistor;
|
||||
import me.leolin.shortcutbadger.ShortcutBadger;
|
||||
import okhttp3.ConnectionSpec;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.TlsVersion;
|
||||
import pl.szczodrzynski.edziennik.config.Config;
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing;
|
||||
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask;
|
||||
import pl.szczodrzynski.edziennik.data.db.AppDb;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.DebugLog;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile;
|
||||
import pl.szczodrzynski.edziennik.network.NetworkUtils;
|
||||
import pl.szczodrzynski.edziennik.network.TLSSocketFactory;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity;
|
||||
import pl.szczodrzynski.edziennik.utils.DebugLogFormat;
|
||||
import pl.szczodrzynski.edziennik.utils.PermissionChecker;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
import pl.szczodrzynski.edziennik.utils.models.AppConfig;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.data.db.entity.LoginStore.LOGIN_TYPE_MOBIDZIENNIK;
|
||||
|
||||
public class App extends androidx.multidex.MultiDexApplication implements Configuration.Provider {
|
||||
private static final String TAG = "App";
|
||||
public static int profileId = -1;
|
||||
private Context mContext;
|
||||
|
||||
@Override
|
||||
public Configuration getWorkManagerConfiguration() {
|
||||
return new Configuration.Builder()
|
||||
.setMinimumLoggingLevel(Log.VERBOSE)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
public static final int REQUEST_TIMEOUT = 10 * 1000;
|
||||
|
||||
// notifications
|
||||
//public NotificationManager mNotificationManager;
|
||||
//public final String NOTIFICATION_CHANNEL_ID_UPDATES = "4566";
|
||||
//public String NOTIFICATION_CHANNEL_NAME_UPDATES;
|
||||
public Notifier notifier;
|
||||
|
||||
public static final String APP_URL = "://edziennik.szczodrzynski.pl/app/";
|
||||
|
||||
public ShortcutManager shortcutManager;
|
||||
|
||||
public PermissionChecker permissionChecker;
|
||||
|
||||
public String signature = "";
|
||||
public String deviceId = "";
|
||||
|
||||
public AppDb db;
|
||||
public void debugLog(String text) {
|
||||
if (!devMode)
|
||||
return;
|
||||
db.debugLogDao().add(new DebugLog(Utils.getCurrentTimeUsingCalendar()+": "+text));
|
||||
}
|
||||
public void debugLogAsync(String text) {
|
||||
if (!devMode)
|
||||
return;
|
||||
AsyncTask.execute(() -> {
|
||||
db.debugLogDao().add(new DebugLog(Utils.getCurrentTimeUsingCalendar()+": "+text));
|
||||
});
|
||||
}
|
||||
|
||||
// network & APIs
|
||||
public NetworkUtils networkUtils;
|
||||
public PersistentCookieJar cookieJar;
|
||||
public OkHttpClient http;
|
||||
public OkHttpClient httpLazy;
|
||||
|
||||
public SharedPreferences appSharedPrefs; // sharedPreferences for APPCONFIG + JOBS STORE
|
||||
public AppConfig appConfig; // APPCONFIG: common for all profiles
|
||||
//public AppProfile profile; // current profile
|
||||
public SharedPreferences registerStore; // sharedPreferences for REGISTER
|
||||
//public Register register; // REGISTER for current profile, read from registerStore
|
||||
|
||||
public Profile profile;
|
||||
public Config config;
|
||||
private static Config mConfig;
|
||||
public static Config getConfig() {
|
||||
return mConfig;
|
||||
}
|
||||
|
||||
// other stuff
|
||||
public Gson gson;
|
||||
public String requestScheme = "https";
|
||||
public boolean unreadBadgesAvailable = true;
|
||||
|
||||
public static boolean devMode = false;
|
||||
|
||||
public static final boolean UPDATES_ON_PLAY_STORE = true;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
public Icon getDesktopIconFromIconics(IIcon icon) {
|
||||
final IconicsDrawable drawable = new IconicsDrawable(mContext, icon)
|
||||
.color(IconicsColor.colorInt(Color.WHITE))
|
||||
.size(IconicsSize.dp(48))
|
||||
.padding(IconicsSize.dp(8))
|
||||
.backgroundColor(IconicsColor.colorRes(R.color.colorPrimaryDark))
|
||||
.roundedCorners(IconicsSize.dp(10));
|
||||
//drawable.setStyle(Paint.Style.FILL);
|
||||
final Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
final Canvas canvas = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||
drawable.draw(canvas);
|
||||
|
||||
return Icon.createWithBitmap(bitmap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
|
||||
CaocConfig.Builder.create()
|
||||
.backgroundMode(CaocConfig.BACKGROUND_MODE_SHOW_CUSTOM) //default: CaocConfig.BACKGROUND_MODE_SHOW_CUSTOM
|
||||
.enabled(true) //default: true
|
||||
.showErrorDetails(true) //default: true
|
||||
.showRestartButton(true) //default: true
|
||||
.logErrorOnRestart(true) //default: true
|
||||
.trackActivities(true) //default: false
|
||||
.minTimeBetweenCrashesMs(2000) //default: 3000
|
||||
.errorDrawable(R.drawable.ic_rip) //default: bug image
|
||||
.restartActivity(MainActivity.class) //default: null (your app's launch activity)
|
||||
.errorActivity(CrashActivity.class) //default: null (default error activity)
|
||||
//.eventListener(new YourCustomEventListener()) //default: null
|
||||
.apply();
|
||||
mContext = this;
|
||||
db = AppDb.getDatabase(this);
|
||||
gson = new Gson();
|
||||
networkUtils = new NetworkUtils(this);
|
||||
|
||||
config = new Config(db);
|
||||
config.migrate(this);
|
||||
mConfig = config;
|
||||
|
||||
Iconics.init(getApplicationContext());
|
||||
Iconics.registerFont(SzkolnyFont.INSTANCE);
|
||||
|
||||
notifier = new Notifier(this);
|
||||
permissionChecker = new PermissionChecker(mContext);
|
||||
|
||||
deviceId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
|
||||
|
||||
cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(this));
|
||||
|
||||
appSharedPrefs = getSharedPreferences(getString(R.string.preference_file_global), Context.MODE_PRIVATE);
|
||||
|
||||
loadConfig();
|
||||
|
||||
Signing.INSTANCE.getCert(this);
|
||||
|
||||
Themes.INSTANCE.setThemeInt(config.getUi().getTheme());
|
||||
|
||||
try {
|
||||
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
|
||||
for (Signature signature: packageInfo.signatures) {
|
||||
byte[] signatureBytes = signature.toByteArray();
|
||||
MessageDigest md = MessageDigest.getInstance("SHA");
|
||||
md.update(signatureBytes);
|
||||
this.signature = Base64.encodeToString(md.digest(), Base64.NO_WRAP);
|
||||
//Log.d(TAG, "Signature is "+this.signature);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if ("f054761fbdb6a238".equals(deviceId) || BuildConfig.DEBUG) {
|
||||
devMode = true;
|
||||
}
|
||||
else if (config.getDevModePassword() != null) {
|
||||
checkDevModePassword();
|
||||
}
|
||||
|
||||
OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder()
|
||||
.cache(null)
|
||||
.followRedirects(true)
|
||||
.followSslRedirects(true)
|
||||
.retryOnConnectionFailure(true)
|
||||
.cookieJar(cookieJar)
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.writeTimeout(20, TimeUnit.SECONDS)
|
||||
.readTimeout(40, TimeUnit.SECONDS);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
try {
|
||||
try {
|
||||
ProviderInstaller.installIfNeeded(this);
|
||||
} catch (Exception e) {
|
||||
Log.e("OkHttpTLSCompat", "Play Services not found or outdated");
|
||||
X509TrustManager x509TrustManager = null;
|
||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
trustManagerFactory.init((KeyStore) null);
|
||||
for (TrustManager trustManager: trustManagerFactory.getTrustManagers()) {
|
||||
if (trustManager instanceof X509TrustManager)
|
||||
x509TrustManager = (X509TrustManager) trustManager;
|
||||
}
|
||||
|
||||
SSLContext sc = SSLContext.getInstance("TLSv1.2");
|
||||
sc.init(null, null, null);
|
||||
httpBuilder.sslSocketFactory(new TLSSocketFactory(sc.getSocketFactory()), x509TrustManager);
|
||||
|
||||
ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
||||
.tlsVersions(TlsVersion.TLS_1_0)
|
||||
.tlsVersions(TlsVersion.TLS_1_1)
|
||||
.tlsVersions(TlsVersion.TLS_1_2)
|
||||
.build();
|
||||
|
||||
List<ConnectionSpec> specs = new ArrayList<>();
|
||||
specs.add(cs);
|
||||
specs.add(ConnectionSpec.COMPATIBLE_TLS);
|
||||
specs.add(ConnectionSpec.CLEARTEXT);
|
||||
|
||||
httpBuilder.connectionSpecs(specs);
|
||||
}
|
||||
|
||||
|
||||
} catch (Exception exc) {
|
||||
Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc);
|
||||
}
|
||||
}
|
||||
|
||||
if (App.devMode || BuildConfig.DEBUG) {
|
||||
HyperLog.initialize(this);
|
||||
HyperLog.setLogLevel(Log.VERBOSE);
|
||||
HyperLog.setLogFormat(new DebugLogFormat(this));
|
||||
|
||||
ChuckerCollector chuckerCollector = new ChuckerCollector(this, true, RetentionManager.Period.ONE_HOUR);
|
||||
ChuckerInterceptor chuckerInterceptor = new ChuckerInterceptor(this, chuckerCollector);
|
||||
httpBuilder.addInterceptor(chuckerInterceptor);
|
||||
}
|
||||
|
||||
http = httpBuilder.build();
|
||||
httpLazy = http.newBuilder().followRedirects(false).followSslRedirects(false).build();
|
||||
|
||||
MHttp.instance()
|
||||
.customOkHttpClient(http);
|
||||
|
||||
//register = new Register(mContext);
|
||||
|
||||
//profileLoadById(appSharedPrefs.getInt("current_profile_id", 1));
|
||||
|
||||
if (config.getSync().getEnabled()) {
|
||||
SyncWorker.Companion.scheduleNext(this, false);
|
||||
}
|
||||
else {
|
||||
SyncWorker.Companion.cancelNext(this);
|
||||
}
|
||||
|
||||
db.metadataDao().countUnseen().observeForever(count -> {
|
||||
Log.d("MainActivity", "Overall unseen count changed");
|
||||
assert count != null;
|
||||
if (unreadBadgesAvailable) {
|
||||
unreadBadgesAvailable = ShortcutBadger.applyCount(this, count);
|
||||
}
|
||||
});
|
||||
|
||||
//new IonCookieManager(mContext);
|
||||
|
||||
new Handler().post(() -> {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||
shortcutManager = getSystemService(ShortcutManager.class);
|
||||
|
||||
ShortcutInfo shortcutTimetable = new ShortcutInfo.Builder(mContext, "item_timetable")
|
||||
.setShortLabel(getString(R.string.shortcut_timetable)).setLongLabel(getString(R.string.shortcut_timetable))
|
||||
.setIcon(Icon.createWithResource(this, R.mipmap.ic_shortcut_timetable))
|
||||
//.setIcon(getDesktopIconFromIconics(CommunityMaterial.Icon2.cmd_timetable))
|
||||
.setIntent(new Intent(Intent.ACTION_MAIN, null, this, MainActivity.class)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE))
|
||||
.build();
|
||||
|
||||
ShortcutInfo shortcutAgenda = new ShortcutInfo.Builder(mContext, "item_agenda")
|
||||
.setShortLabel(getString(R.string.shortcut_agenda)).setLongLabel(getString(R.string.shortcut_agenda))
|
||||
.setIcon(Icon.createWithResource(this, R.mipmap.ic_shortcut_agenda))
|
||||
//.setIcon(getDesktopIconFromIconics(CommunityMaterial.Icon.cmd_calendar))
|
||||
.setIntent(new Intent(Intent.ACTION_MAIN, null, this, MainActivity.class)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_AGENDA))
|
||||
.build();
|
||||
|
||||
ShortcutInfo shortcutGrades = new ShortcutInfo.Builder(mContext, "item_grades")
|
||||
.setShortLabel(getString(R.string.shortcut_grades)).setLongLabel(getString(R.string.shortcut_grades))
|
||||
.setIcon(Icon.createWithResource(this, R.mipmap.ic_shortcut_grades))
|
||||
//.setIcon(getDesktopIconFromIconics(CommunityMaterial.Icon2.cmd_numeric_5_box))
|
||||
.setIntent(new Intent(Intent.ACTION_MAIN, null, this, MainActivity.class)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_GRADES))
|
||||
.build();
|
||||
|
||||
ShortcutInfo shortcutHomework = new ShortcutInfo.Builder(mContext, "item_homeworks")
|
||||
.setShortLabel(getString(R.string.shortcut_homework)).setLongLabel(getString(R.string.shortcut_homework))
|
||||
.setIcon(Icon.createWithResource(this, R.mipmap.ic_shortcut_homework))
|
||||
//.setIcon(getDesktopIconFromIconics(SzkolnyFont.Icon.szf_file_document_edit))
|
||||
.setIntent(new Intent(Intent.ACTION_MAIN, null, this, MainActivity.class)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_HOMEWORK))
|
||||
.build();
|
||||
|
||||
ShortcutInfo shortcutMessages = new ShortcutInfo.Builder(mContext, "item_messages")
|
||||
.setShortLabel(getString(R.string.shortcut_messages)).setLongLabel(getString(R.string.shortcut_messages))
|
||||
.setIcon(Icon.createWithResource(this, R.mipmap.ic_shortcut_messages))
|
||||
//.setIcon(getDesktopIconFromIconics(CommunityMaterial.Icon.cmd_email))
|
||||
.setIntent(new Intent(Intent.ACTION_MAIN, null, this, MainActivity.class)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_MESSAGES ))
|
||||
.build();
|
||||
|
||||
shortcutManager.setDynamicShortcuts(Arrays.asList(shortcutTimetable, shortcutAgenda, shortcutGrades, shortcutHomework, shortcutMessages));
|
||||
}
|
||||
|
||||
if (config.getAppInstalledTime() == 0) {
|
||||
try {
|
||||
config.setAppInstalledTime(getPackageManager().getPackageInfo(getPackageName(), 0).firstInstallTime);
|
||||
config.setAppRateSnackbarTime(config.getAppInstalledTime() + 7 * 24 * 60 * 60 * 1000);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/*Task<CapabilityInfo> capabilityInfoTask =
|
||||
Wearable.getCapabilityClient(this)
|
||||
.getCapability("edziennik_wear_app", CapabilityClient.FILTER_REACHABLE);
|
||||
capabilityInfoTask.addOnCompleteListener((task) -> {
|
||||
if (task.isSuccessful()) {
|
||||
CapabilityInfo capabilityInfo = task.getResult();
|
||||
assert capabilityInfo != null;
|
||||
Set<Node> nodes;
|
||||
nodes = capabilityInfo.getNodes();
|
||||
Log.d(TAG, "Nodes "+nodes);
|
||||
|
||||
if (nodes.size() > 0) {
|
||||
Wearable.getMessageClient(this).sendMessage(
|
||||
nodes.toArray(new Node[]{})[0].getId(), "/ping", "Hello world".getBytes());
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Capability request failed to return any results.");
|
||||
}
|
||||
});
|
||||
|
||||
Wearable.getDataClient(this).addListener(dataEventBuffer -> {
|
||||
Log.d(TAG, "onDataChanged(): " + dataEventBuffer);
|
||||
|
||||
for (DataEvent event : dataEventBuffer) {
|
||||
if (event.getType() == DataEvent.TYPE_CHANGED) {
|
||||
String path = event.getDataItem().getUri().getPath();
|
||||
Log.d(TAG, "Data "+path+ " :: "+Arrays.toString(event.getDataItem().getData()));
|
||||
}
|
||||
}
|
||||
});*/
|
||||
|
||||
FirebaseApp pushMobidziennikApp = FirebaseApp.initializeApp(
|
||||
this,
|
||||
new FirebaseOptions.Builder()
|
||||
.setApiKey("AIzaSyCi5LmsZ5BBCQnGtrdvWnp1bWLCNP8OWQE")
|
||||
.setApplicationId("1:747285019373:android:f6341bf7b158621d")
|
||||
.build(),
|
||||
"Mobidziennik2"
|
||||
);
|
||||
|
||||
FirebaseApp pushLibrusApp = FirebaseApp.initializeApp(
|
||||
this,
|
||||
new FirebaseOptions.Builder()
|
||||
.setApiKey("AIzaSyDfTuEoYPKdv4aceEws1CO3n0-HvTndz-o")
|
||||
.setApplicationId("1:513056078587:android:1e29083b760af544")
|
||||
.build(),
|
||||
"Librus"
|
||||
);
|
||||
|
||||
FirebaseApp pushVulcanApp = FirebaseApp.initializeApp(
|
||||
this,
|
||||
new FirebaseOptions.Builder()
|
||||
.setApiKey("AIzaSyDW8MUtanHy64_I0oCpY6cOxB3jrvJd_iA")
|
||||
.setApplicationId("1:987828170337:android:ac97431a0a4578c3")
|
||||
.build(),
|
||||
"Vulcan"
|
||||
);
|
||||
|
||||
if (config.getRunSync()) {
|
||||
config.setRunSync(false);
|
||||
EdziennikTask.Companion.sync().enqueue(this);
|
||||
}
|
||||
|
||||
try {
|
||||
final long startTime = System.currentTimeMillis();
|
||||
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(instanceIdResult -> {
|
||||
Log.d(TAG, "Token for App is " + instanceIdResult.getToken() + ", ID is " + instanceIdResult.getId()+". Time is "+(System.currentTimeMillis() - startTime));
|
||||
config.getSync().setTokenApp(instanceIdResult.getToken());
|
||||
});
|
||||
/*FirebaseInstanceId.getInstance(pushMobidziennikApp).getInstanceId().addOnSuccessListener(instanceIdResult -> {
|
||||
Log.d(TAG, "Token for Mobidziennik is " + instanceIdResult.getToken() + ", ID is " + instanceIdResult.getId());
|
||||
appConfig.fcmTokens.put(LOGIN_TYPE_MOBIDZIENNIK, new Pair<>(instanceIdResult.getToken(), new ArrayList<>()));
|
||||
});
|
||||
FirebaseInstanceId.getInstance(pushLibrusApp).getInstanceId().addOnSuccessListener(instanceIdResult -> {
|
||||
Log.d(TAG, "Token for Librus is " + instanceIdResult.getToken() + ", ID is " + instanceIdResult.getId());
|
||||
appConfig.fcmTokens.put(LOGIN_TYPE_LIBRUS, new Pair<>(instanceIdResult.getToken(), new ArrayList<>()));
|
||||
});
|
||||
FirebaseInstanceId.getInstance(pushVulcanApp).getInstanceId().addOnSuccessListener(instanceIdResult -> {
|
||||
Log.d(TAG, "Token for Vulcan is " + instanceIdResult.getToken() + ", ID is " + instanceIdResult.getId());
|
||||
Pair<String, List<Integer>> pair = appConfig.fcmTokens.get(LOGIN_TYPE_VULCAN);
|
||||
if (pair == null || pair.first == null || !pair.first.equals(instanceIdResult.getToken())) {
|
||||
appConfig.fcmTokens.put(LOGIN_TYPE_VULCAN, new Pair<>(instanceIdResult.getToken(), new ArrayList<>()));
|
||||
}
|
||||
});*/
|
||||
|
||||
|
||||
FirebaseMessaging.getInstance().subscribeToTopic(getPackageName());
|
||||
}
|
||||
catch (IllegalStateException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void loadConfig()
|
||||
{
|
||||
appConfig = new AppConfig(this);
|
||||
|
||||
|
||||
if (appSharedPrefs.contains("config")) {
|
||||
// remove old-format config, save the new one and empty the incorrectly-nulled config
|
||||
appConfig = gson.fromJson(appSharedPrefs.getString("config", ""), AppConfig.class);
|
||||
appSharedPrefs.edit().remove("config").apply();
|
||||
saveConfig();
|
||||
appConfig = new AppConfig(this);
|
||||
}
|
||||
|
||||
if (appSharedPrefs.contains("profiles")) {
|
||||
SharedPreferences.Editor appSharedPrefsEditor = appSharedPrefs.edit();
|
||||
/*List<Integer> appProfileIds = gson.fromJson(appSharedPrefs.getString("profiles", ""), new TypeToken<List<Integer>>(){}.getType());
|
||||
for (int id: appProfileIds) {
|
||||
AppProfile appProfile = gson.fromJson(appSharedPrefs.getString("profile"+id, ""), AppProfile.class);
|
||||
if (appProfile != null) {
|
||||
appConfig.profiles.add(appProfile);
|
||||
}
|
||||
appSharedPrefsEditor.remove("profile"+id);
|
||||
}*/
|
||||
appSharedPrefsEditor.remove("profiles");
|
||||
appSharedPrefsEditor.apply();
|
||||
//profilesSave();
|
||||
}
|
||||
|
||||
|
||||
Map<String,?> keys = appSharedPrefs.getAll();
|
||||
for (Map.Entry<String,?> entry : keys.entrySet()) {
|
||||
if (entry.getKey().startsWith("app.appConfig.")) {
|
||||
String fieldName = entry.getKey().replace("app.appConfig.", "");
|
||||
|
||||
try {
|
||||
Field field = AppConfig.class.getField(fieldName);
|
||||
Object object;
|
||||
try {
|
||||
object = gson.fromJson(entry.getValue().toString(), field.getGenericType());
|
||||
} catch (JsonSyntaxException e) {
|
||||
Log.d(TAG, "For field "+fieldName);
|
||||
e.printStackTrace();
|
||||
object = entry.getValue().toString();
|
||||
}
|
||||
if (object != null)
|
||||
field.set(appConfig, object);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
Log.w(TAG, "Should remove app.appConfig."+fieldName);
|
||||
//appSharedPrefs.edit().remove("app.appConfig."+fieldName).apply(); TODO migration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*if (appConfig.lastAppVersion > BuildConfig.VERSION_CODE) {
|
||||
BootReceiver br = new BootReceiver();
|
||||
Intent i = new Intent();
|
||||
//i.putExtra("UserChecked", true);
|
||||
br.onReceive(getContext(), i);
|
||||
Toast.makeText(mContext, R.string.warning_older_version_running, Toast.LENGTH_LONG).show();
|
||||
//Toast.makeText(mContext, "Zaktualizuj aplikację.", Toast.LENGTH_LONG).show();
|
||||
//System.exit(0);
|
||||
}*/
|
||||
|
||||
if (appConfig == null) {
|
||||
appConfig = new AppConfig(this);
|
||||
}
|
||||
}
|
||||
public void saveConfig()
|
||||
{
|
||||
try {
|
||||
appConfig.savePending = false;
|
||||
|
||||
SharedPreferences.Editor appSharedPrefsEditor = appSharedPrefs.edit();
|
||||
|
||||
JsonObject appConfigJson = gson.toJsonTree(appConfig).getAsJsonObject();
|
||||
for (Map.Entry<String, JsonElement> entry : appConfigJson.entrySet()) {
|
||||
String jsonObj;
|
||||
jsonObj = entry.getValue().toString();
|
||||
/*if (entry.getValue().isJsonObject()) {
|
||||
jsonObj = entry.getValue().getAsJsonObject().toString();
|
||||
}
|
||||
else if (entry.getValue().isJsonArray()) {
|
||||
jsonObj = entry.getValue().getAsJsonArray().toString();
|
||||
}
|
||||
else {
|
||||
jsonObj = entry.getValue().toString();
|
||||
}*/
|
||||
appSharedPrefsEditor.putString("app.appConfig." + entry.getKey(), jsonObj);
|
||||
}
|
||||
|
||||
appSharedPrefsEditor.apply();
|
||||
}
|
||||
catch (ConcurrentModificationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//appSharedPrefs.edit().putString("config", gson.toJson(appConfig)).apply();
|
||||
}
|
||||
public void saveConfig(String ... fieldNames)
|
||||
{
|
||||
appConfig.savePending = false;
|
||||
|
||||
SharedPreferences.Editor appSharedPrefsEditor = appSharedPrefs.edit();
|
||||
|
||||
for (String fieldName: fieldNames) {
|
||||
try {
|
||||
Object object = AppConfig.class.getField(fieldName).get(appConfig);
|
||||
appSharedPrefsEditor.putString("app.appConfig."+fieldName, gson.toJson(object));
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ConcurrentModificationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
appSharedPrefsEditor.apply();
|
||||
//appSharedPrefs.edit().putString("config", gson.toJson(appConfig)).apply();
|
||||
}
|
||||
|
||||
public void profileSave() {
|
||||
AsyncTask.execute(() -> {
|
||||
db.profileDao().add(profile);
|
||||
});
|
||||
}
|
||||
|
||||
public void profileSaveAsync() {
|
||||
AsyncTask.execute(() -> {
|
||||
db.profileDao().add(profile);
|
||||
});
|
||||
}
|
||||
public void profileSaveAsync(Profile profile) {
|
||||
AsyncTask.execute(() -> {
|
||||
db.profileDao().add(profile);
|
||||
});
|
||||
}
|
||||
|
||||
public void profileLoadById(int id) {
|
||||
profileLoadById(id, false);
|
||||
}
|
||||
public void profileLoadById(int id, boolean loadedLast) {
|
||||
//Log.d(TAG, "Loading ID "+id);
|
||||
/*if (profile == null) {
|
||||
profile = profileNew();
|
||||
AppDb.profileId = profile.id;
|
||||
appSharedPrefs.edit().putInt("current_profile_id", profile.id).apply();
|
||||
return;
|
||||
}*/
|
||||
if (profile == null || profile.getId() != id) {
|
||||
profile = db.profileDao().getByIdNow(id);
|
||||
/*if (profile == null) {
|
||||
profileLoadById(id);
|
||||
return;
|
||||
}*/
|
||||
if (profile != null) {
|
||||
MainActivity.Companion.setUseOldMessages(profile.getLoginStoreType() == LOGIN_TYPE_MOBIDZIENNIK && appConfig.mobidziennikOldMessages == 1);
|
||||
profileId = profile.getId();
|
||||
appSharedPrefs.edit().putInt("current_profile_id", profile.getId()).apply();
|
||||
config.setProfile(profileId);
|
||||
}
|
||||
else if (!loadedLast) {
|
||||
profileLoadById(profileLastId(), true);
|
||||
}
|
||||
else {
|
||||
profileId = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*public void profileRemove(int id)
|
||||
{
|
||||
Profile profile = db.profileDao().getFullByIdNow(id);
|
||||
|
||||
if (profile.id == profile.loginStoreId) {
|
||||
// this profile is the owner of the login store
|
||||
// we need to check if any other profile is using it
|
||||
List<Integer> transferProfileIds = db.profileDao().getIdsByLoginStoreIdNow(profile.loginStoreId);
|
||||
if (transferProfileIds.size() == 1) {
|
||||
// this login store is free of users, remove it along with the profile
|
||||
db.loginStoreDao().remove(profile.loginStoreId);
|
||||
// the current store is removed, we are ready to remove the profile
|
||||
}
|
||||
else if (transferProfileIds.size() > 1) {
|
||||
transferProfileIds.remove(transferProfileIds.indexOf(profile.id));
|
||||
// someone is using the store
|
||||
// we need to transfer it to the firstProfileId
|
||||
db.loginStoreDao().changeId(profile.loginStoreId, transferProfileIds.get(0));
|
||||
db.profileDao().changeStoreId(profile.loginStoreId, transferProfileIds.get(0));
|
||||
// the current store is removed, we are ready to remove the profile
|
||||
}
|
||||
}
|
||||
// else, the profile uses a store that it doesn't own
|
||||
// leave the store and go on with removing
|
||||
|
||||
Log.d(TAG, "Before removal: "+db.profileDao().getAllNow().toString());
|
||||
db.profileDao().remove(profile.id);
|
||||
Log.d(TAG, "After removal: "+db.profileDao().getAllNow().toString());
|
||||
|
||||
*//*int newId = 1;
|
||||
if (appConfig.profiles.size() > 0) {
|
||||
newId = appConfig.profiles.get(appConfig.profiles.size() - 1).id;
|
||||
}
|
||||
Log.d(TAG, "New ID: "+newId);
|
||||
//Toast.makeText(mContext, "selected new id "+newId, Toast.LENGTH_SHORT).show();
|
||||
profileLoadById(newId);*//*
|
||||
}*/
|
||||
|
||||
public int profileFirstId() {
|
||||
Integer id = db.profileDao().getFirstId();
|
||||
return id == null ? 1 : id;
|
||||
}
|
||||
|
||||
public int profileLastId() {
|
||||
Integer id = db.profileDao().getLastId();
|
||||
return id == null ? 1 : id;
|
||||
}
|
||||
|
||||
|
||||
public Context getContext()
|
||||
{
|
||||
return mContext;
|
||||
}
|
||||
|
||||
public void checkDevModePassword() {
|
||||
try {
|
||||
devMode = Utils.AESCrypt.decrypt("nWFVxY65Pa8/aRrT7EylNAencmOD+IxUY2Gg/beiIWY=", config.getDevModePassword()).equals("ok here you go it's enabled now")
|
||||
|| BuildConfig.DEBUG;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
devMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -4,20 +4,77 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.ShortcutInfo
|
||||
import android.content.pm.ShortcutManager
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.multidex.MultiDexApplication
|
||||
import androidx.work.Configuration
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import cat.ereza.customactivityoncrash.config.CaocConfig
|
||||
import com.chuckerteam.chucker.api.ChuckerCollector
|
||||
import com.chuckerteam.chucker.api.ChuckerInterceptor
|
||||
import com.chuckerteam.chucker.api.RetentionManager
|
||||
import com.google.firebase.FirebaseApp
|
||||
import com.google.firebase.FirebaseOptions
|
||||
import com.google.firebase.iid.FirebaseInstanceId
|
||||
import com.google.firebase.messaging.FirebaseMessaging
|
||||
import com.google.gson.Gson
|
||||
import com.hypertrack.hyperlog.HyperLog
|
||||
import com.mikepenz.iconics.Iconics
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
|
||||
import im.wangchao.mhttp.MHttp
|
||||
import kotlinx.coroutines.*
|
||||
import me.leolin.shortcutbadger.ShortcutBadger
|
||||
import okhttp3.OkHttpClient
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.config.Config
|
||||
import pl.szczodrzynski.edziennik.data.api.events.ProfileListEmptyEvent
|
||||
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.network.NetworkUtils
|
||||
import pl.szczodrzynski.edziennik.network.cookie.DumbCookieJar
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
||||
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity
|
||||
import pl.szczodrzynski.edziennik.utils.*
|
||||
import pl.szczodrzynski.edziennik.utils.managers.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class Szkolny : /*MultiDexApplication(),*/ Configuration.Provider, CoroutineScope {
|
||||
class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
||||
companion object {
|
||||
@Volatile
|
||||
lateinit var db: AppDb
|
||||
val config: Config by lazy { Config(db) }
|
||||
var profile: Profile by mutableLazy { Profile(0, 0, 0, "") }
|
||||
val profileId
|
||||
get() = profile.id
|
||||
|
||||
var devMode = false
|
||||
var debugMode = false
|
||||
}
|
||||
|
||||
//lateinit var db: AppDb
|
||||
//val config by lazy { Config(db); // TODO migrate }
|
||||
val notificationChannelsManager by lazy { NotificationChannelsManager(this) }
|
||||
val userActionManager by lazy { UserActionManager(this) }
|
||||
val gradesManager by lazy { GradesManager(this) }
|
||||
val timetableManager by lazy { TimetableManager(this) }
|
||||
val eventManager by lazy { EventManager(this) }
|
||||
val permissionManager by lazy { PermissionManager(this) }
|
||||
|
||||
val db
|
||||
get() = App.db
|
||||
val config
|
||||
get() = App.config
|
||||
val profile
|
||||
get() = App.profile
|
||||
val profileId
|
||||
get() = App.profileId
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
@ -26,11 +83,9 @@ class Szkolny : /*MultiDexApplication(),*/ Configuration.Provider, CoroutineScop
|
||||
.setMinimumLoggingLevel(Log.VERBOSE)
|
||||
.build()
|
||||
|
||||
/*val preferences by lazy { getSharedPreferences(getString(R.string.preference_file), Context.MODE_PRIVATE) }
|
||||
val notifier by lazy { Notifier(this) }
|
||||
val permissionChecker by lazy { PermissionChecker(this) }
|
||||
|
||||
lateinit var profile: ProfileFull
|
||||
val networkUtils by lazy { NetworkUtils(this) }
|
||||
val gson by lazy { Gson() }
|
||||
|
||||
/* _ _ _______ _______ _____
|
||||
| | | |__ __|__ __| __ \
|
||||
@ -48,13 +103,13 @@ class Szkolny : /*MultiDexApplication(),*/ Configuration.Provider, CoroutineScop
|
||||
.connectTimeout(20, TimeUnit.SECONDS)
|
||||
.writeTimeout(5, TimeUnit.SECONDS)
|
||||
.readTimeout(10, TimeUnit.SECONDS)
|
||||
builder.installHttpsSupport()
|
||||
builder.installHttpsSupport(this)
|
||||
|
||||
if (devMode || BuildConfig.DEBUG) {
|
||||
if (debugMode || BuildConfig.DEBUG) {
|
||||
HyperLog.initialize(this)
|
||||
HyperLog.setLogLevel(Log.VERBOSE)
|
||||
HyperLog.setLogFormat(DebugLogFormat(this))
|
||||
val chuckerCollector = ChuckerCollector(this, true, Period.ONE_HOUR)
|
||||
val chuckerCollector = ChuckerCollector(this, true, RetentionManager.Period.ONE_HOUR)
|
||||
val chuckerInterceptor = ChuckerInterceptor(this, chuckerCollector)
|
||||
builder.addInterceptor(chuckerInterceptor)
|
||||
}
|
||||
@ -67,7 +122,7 @@ class Szkolny : /*MultiDexApplication(),*/ Configuration.Provider, CoroutineScop
|
||||
.followSslRedirects(false)
|
||||
.build()
|
||||
}
|
||||
val cookieJar by lazy { PersistentCookieJar(SetCookieCache(), SharedPrefsCookiePersistor(this)) }
|
||||
val cookieJar by lazy { DumbCookieJar(this) }
|
||||
|
||||
/* _____ _ _
|
||||
/ ____(_) | |
|
||||
@ -77,22 +132,7 @@ class Szkolny : /*MultiDexApplication(),*/ Configuration.Provider, CoroutineScop
|
||||
|_____/|_|\__, |_| |_|\__,_|\__|\__,_|_| \___|
|
||||
__/ |
|
||||
|__*/
|
||||
private val deviceId: String by lazy { Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID) ?: "" }
|
||||
private val signature: String by lazy {
|
||||
var str = ""
|
||||
try {
|
||||
val packageInfo: PackageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES)
|
||||
for (signature in packageInfo.signatures) {
|
||||
val signatureBytes = signature.toByteArray()
|
||||
val md = MessageDigest.getInstance("SHA")
|
||||
md.update(signatureBytes)
|
||||
str = Base64.encodeToString(md.digest(), Base64.DEFAULT)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
str
|
||||
}
|
||||
val deviceId: String by lazy { Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID) ?: "" }
|
||||
private var unreadBadgesAvailable = true
|
||||
|
||||
/* _____ _
|
||||
@ -118,193 +158,198 @@ class Szkolny : /*MultiDexApplication(),*/ Configuration.Provider, CoroutineScop
|
||||
.apply()
|
||||
Iconics.init(applicationContext)
|
||||
Iconics.registerFont(SzkolnyFont)
|
||||
db = AppDb.getDatabase(this)
|
||||
App.db = AppDb(this)
|
||||
Themes.themeInt = config.ui.theme
|
||||
debugMode = config.debugMode
|
||||
MHttp.instance().customOkHttpClient(http)
|
||||
|
||||
devMode = "f054761fbdb6a238" == deviceId || BuildConfig.DEBUG
|
||||
if (config.devModePassword != null)
|
||||
checkDevModePassword()
|
||||
if (!profileLoadById(config.lastProfileId)) {
|
||||
db.profileDao().firstId?.let { profileLoadById(it) }
|
||||
}
|
||||
|
||||
config.ui.language?.let {
|
||||
setLanguage(it)
|
||||
}
|
||||
|
||||
devMode = BuildConfig.DEBUG
|
||||
|
||||
Signing.getCert(this)
|
||||
|
||||
launch { async(Dispatchers.Default) {
|
||||
if (config.sync.enabled) {
|
||||
scheduleNext(this@App, false)
|
||||
} else {
|
||||
cancelNext(this@App)
|
||||
launch {
|
||||
withContext(Dispatchers.Default) {
|
||||
config.migrate(this@App)
|
||||
|
||||
if (config.devModePassword != null)
|
||||
checkDevModePassword()
|
||||
debugMode = devMode || config.debugMode
|
||||
|
||||
if (config.sync.enabled)
|
||||
SyncWorker.scheduleNext(this@App, false)
|
||||
else
|
||||
SyncWorker.cancelNext(this@App)
|
||||
|
||||
if (config.sync.notifyAboutUpdates)
|
||||
UpdateWorker.scheduleNext(this@App, false)
|
||||
else
|
||||
UpdateWorker.cancelNext(this@App)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||
val shortcutManager = getSystemService(ShortcutManager::class.java)
|
||||
|
||||
val shortcutTimetable = ShortcutInfo.Builder(this@App, "item_timetable")
|
||||
.setShortLabel(getString(R.string.shortcut_timetable)).setLongLabel(getString(R.string.shortcut_timetable))
|
||||
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_timetable))
|
||||
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE))
|
||||
.build()
|
||||
|
||||
val shortcutAgenda = ShortcutInfo.Builder(this@App, "item_agenda")
|
||||
.setShortLabel(getString(R.string.shortcut_agenda)).setLongLabel(getString(R.string.shortcut_agenda))
|
||||
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_agenda))
|
||||
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_AGENDA))
|
||||
.build()
|
||||
|
||||
val shortcutGrades = ShortcutInfo.Builder(this@App, "item_grades")
|
||||
.setShortLabel(getString(R.string.shortcut_grades)).setLongLabel(getString(R.string.shortcut_grades))
|
||||
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_grades))
|
||||
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_GRADES))
|
||||
.build()
|
||||
|
||||
val shortcutHomework = ShortcutInfo.Builder(this@App, "item_homeworks")
|
||||
.setShortLabel(getString(R.string.shortcut_homework)).setLongLabel(getString(R.string.shortcut_homework))
|
||||
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_homework))
|
||||
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_HOMEWORK))
|
||||
.build()
|
||||
|
||||
val shortcutMessages = ShortcutInfo.Builder(this@App, "item_messages")
|
||||
.setShortLabel(getString(R.string.shortcut_messages)).setLongLabel(getString(R.string.shortcut_messages))
|
||||
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_messages))
|
||||
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_MESSAGES))
|
||||
.build()
|
||||
|
||||
shortcutManager.dynamicShortcuts = listOf(
|
||||
shortcutTimetable,
|
||||
shortcutAgenda,
|
||||
shortcutGrades,
|
||||
shortcutHomework,
|
||||
shortcutMessages
|
||||
)
|
||||
} // shortcuts - end
|
||||
|
||||
notificationChannelsManager.registerAllChannels()
|
||||
|
||||
|
||||
if (config.appInstalledTime == 0L)
|
||||
try {
|
||||
config.appInstalledTime = packageManager.getPackageInfo(packageName, 0).firstInstallTime
|
||||
config.appRateSnackbarTime = config.appInstalledTime + 7 * DAY * MS
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
val pushMobidziennikApp = FirebaseApp.initializeApp(
|
||||
this@App,
|
||||
FirebaseOptions.Builder()
|
||||
.setApiKey("AIzaSyCi5LmsZ5BBCQnGtrdvWnp1bWLCNP8OWQE")
|
||||
.setApplicationId("1:747285019373:android:f6341bf7b158621d")
|
||||
.build(),
|
||||
"Mobidziennik2"
|
||||
)
|
||||
|
||||
val pushLibrusApp = FirebaseApp.initializeApp(
|
||||
this@App,
|
||||
FirebaseOptions.Builder()
|
||||
.setApiKey("AIzaSyDfTuEoYPKdv4aceEws1CO3n0-HvTndz-o")
|
||||
.setApplicationId("1:513056078587:android:1e29083b760af544")
|
||||
.build(),
|
||||
"Librus"
|
||||
)
|
||||
|
||||
val pushVulcanApp = FirebaseApp.initializeApp(
|
||||
this@App,
|
||||
FirebaseOptions.Builder()
|
||||
.setApiKey("AIzaSyDW8MUtanHy64_I0oCpY6cOxB3jrvJd_iA")
|
||||
.setApplicationId("1:987828170337:android:ac97431a0a4578c3")
|
||||
.build(),
|
||||
"Vulcan"
|
||||
)
|
||||
|
||||
try {
|
||||
FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener { instanceIdResult ->
|
||||
val token = instanceIdResult.token
|
||||
config.sync.tokenApp = token
|
||||
}
|
||||
FirebaseInstanceId.getInstance(pushMobidziennikApp).instanceId.addOnSuccessListener { instanceIdResult ->
|
||||
val token = instanceIdResult.token
|
||||
if (token != config.sync.tokenMobidziennik) {
|
||||
config.sync.tokenMobidziennik = token
|
||||
config.sync.tokenMobidziennikList = listOf()
|
||||
}
|
||||
}
|
||||
FirebaseInstanceId.getInstance(pushLibrusApp).instanceId.addOnSuccessListener { instanceIdResult ->
|
||||
val token = instanceIdResult.token
|
||||
if (token != config.sync.tokenLibrus) {
|
||||
config.sync.tokenLibrus = token
|
||||
config.sync.tokenLibrusList = listOf()
|
||||
}
|
||||
}
|
||||
FirebaseInstanceId.getInstance(pushVulcanApp).instanceId.addOnSuccessListener { instanceIdResult ->
|
||||
val token = instanceIdResult.token
|
||||
if (token != config.sync.tokenVulcan) {
|
||||
config.sync.tokenVulcan = token
|
||||
config.sync.tokenVulcanList = listOf()
|
||||
}
|
||||
}
|
||||
FirebaseMessaging.getInstance().subscribeToTopic(packageName)
|
||||
} catch (e: IllegalStateException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
db.metadataDao().countUnseen().observeForever { count: Int ->
|
||||
if (unreadBadgesAvailable)
|
||||
unreadBadgesAvailable = ShortcutBadger.applyCount(this@App, count)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||
val shortcutManager = getSystemService(ShortcutManager::class.java)
|
||||
|
||||
val shortcutTimetable = ShortcutInfo.Builder(this@App, "item_timetable")
|
||||
.setShortLabel(getString(R.string.shortcut_timetable)).setLongLabel(getString(R.string.shortcut_timetable))
|
||||
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_timetable))
|
||||
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE))
|
||||
.build()
|
||||
|
||||
val shortcutAgenda = ShortcutInfo.Builder(this@App, "item_agenda")
|
||||
.setShortLabel(getString(R.string.shortcut_agenda)).setLongLabel(getString(R.string.shortcut_agenda))
|
||||
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_agenda))
|
||||
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_AGENDA))
|
||||
.build()
|
||||
|
||||
val shortcutGrades = ShortcutInfo.Builder(this@App, "item_grades")
|
||||
.setShortLabel(getString(R.string.shortcut_grades)).setLongLabel(getString(R.string.shortcut_grades))
|
||||
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_grades))
|
||||
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_GRADES))
|
||||
.build()
|
||||
|
||||
val shortcutHomework = ShortcutInfo.Builder(this@App, "item_homeworks")
|
||||
.setShortLabel(getString(R.string.shortcut_homework)).setLongLabel(getString(R.string.shortcut_homework))
|
||||
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_homework))
|
||||
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_HOMEWORK))
|
||||
.build()
|
||||
|
||||
val shortcutMessages = ShortcutInfo.Builder(this@App, "item_messages")
|
||||
.setShortLabel(getString(R.string.shortcut_messages)).setLongLabel(getString(R.string.shortcut_messages))
|
||||
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_messages))
|
||||
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_MESSAGES))
|
||||
.build()
|
||||
|
||||
shortcutManager.dynamicShortcuts = listOf(
|
||||
shortcutTimetable,
|
||||
shortcutAgenda,
|
||||
shortcutGrades,
|
||||
shortcutHomework,
|
||||
shortcutMessages
|
||||
)
|
||||
} // shortcuts - end
|
||||
|
||||
if (config.appInstalledTime == 0L)
|
||||
try {
|
||||
config.appInstalledTime = packageManager.getPackageInfo(packageName, 0).firstInstallTime
|
||||
config.appRateSnackbarTime = config.appInstalledTime + 7*DAY*MS
|
||||
} catch (e: NameNotFoundException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
val pushMobidziennikApp = FirebaseApp.initializeApp(
|
||||
this@App,
|
||||
FirebaseOptions.Builder()
|
||||
.setApiKey("AIzaSyCi5LmsZ5BBCQnGtrdvWnp1bWLCNP8OWQE")
|
||||
.setApplicationId("1:747285019373:android:f6341bf7b158621d")
|
||||
.build(),
|
||||
"Mobidziennik2"
|
||||
)
|
||||
|
||||
val pushLibrusApp = FirebaseApp.initializeApp(
|
||||
this@App,
|
||||
FirebaseOptions.Builder()
|
||||
.setApiKey("AIzaSyDfTuEoYPKdv4aceEws1CO3n0-HvTndz-o")
|
||||
.setApplicationId("1:513056078587:android:1e29083b760af544")
|
||||
.build(),
|
||||
"Librus"
|
||||
)
|
||||
|
||||
val pushVulcanApp = FirebaseApp.initializeApp(
|
||||
this@App,
|
||||
FirebaseOptions.Builder()
|
||||
.setApiKey("AIzaSyDW8MUtanHy64_I0oCpY6cOxB3jrvJd_iA")
|
||||
.setApplicationId("1:987828170337:android:ac97431a0a4578c3")
|
||||
.build(),
|
||||
"Vulcan"
|
||||
)
|
||||
|
||||
try {
|
||||
FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener { instanceIdResult ->
|
||||
val token = instanceIdResult.token
|
||||
config.sync.tokenApp = token
|
||||
}
|
||||
FirebaseInstanceId.getInstance(pushMobidziennikApp).instanceId.addOnSuccessListener { instanceIdResult ->
|
||||
val token = instanceIdResult.token
|
||||
if (token != config.sync.tokenMobidziennik) {
|
||||
config.sync.tokenMobidziennik = token
|
||||
config.sync.tokenMobidziennikList = listOf()
|
||||
}
|
||||
}
|
||||
FirebaseInstanceId.getInstance(pushLibrusApp).instanceId.addOnSuccessListener { instanceIdResult ->
|
||||
val token = instanceIdResult.token
|
||||
if (token != config.sync.tokenLibrus) {
|
||||
config.sync.tokenLibrus = token
|
||||
config.sync.tokenLibrusList = listOf()
|
||||
}
|
||||
}
|
||||
FirebaseInstanceId.getInstance(pushVulcanApp).instanceId.addOnSuccessListener { instanceIdResult ->
|
||||
val token = instanceIdResult.token
|
||||
if (token != config.sync.tokenVulcan) {
|
||||
config.sync.tokenVulcan = token
|
||||
config.sync.tokenVulcanList = listOf()
|
||||
}
|
||||
}
|
||||
FirebaseMessaging.getInstance().subscribeToTopic(packageName)
|
||||
} catch (e: IllegalStateException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
private fun profileLoad(profileId: Int) {
|
||||
db.profileDao().getFullByIdNow(profileId)?.also {
|
||||
profile = it
|
||||
} ?: run {
|
||||
if (!::profile.isInitialized) {
|
||||
profile = ProfileFull(-1, "", "", -1)
|
||||
}
|
||||
}
|
||||
}
|
||||
fun profileLoad(profileId: Int, onSuccess: (profile: ProfileFull) -> Unit) {
|
||||
|
||||
private fun profileLoadById(profileId: Int): Boolean {
|
||||
db.profileDao().getByIdNow(profileId)?.also {
|
||||
App.profile = it
|
||||
App.config.lastProfileId = it.id
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
fun profileLoad(profileId: Int, onSuccess: (profile: Profile) -> Unit) {
|
||||
launch {
|
||||
val deferred = async(Dispatchers.Default) {
|
||||
profileLoad(profileId)
|
||||
val success = withContext(Dispatchers.Default) {
|
||||
profileLoadById(profileId)
|
||||
}
|
||||
deferred.await()
|
||||
onSuccess(profile)
|
||||
if (success)
|
||||
onSuccess(profile)
|
||||
else
|
||||
profileLoadLast(onSuccess)
|
||||
}
|
||||
}
|
||||
|
||||
private fun OkHttpClient.Builder.installHttpsSupport() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
try {
|
||||
try {
|
||||
ProviderInstaller.installIfNeeded(this@App)
|
||||
} catch (e: Exception) {
|
||||
Log.e("OkHttpTLSCompat", "Play Services not found or outdated")
|
||||
|
||||
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
|
||||
trustManagerFactory.init(null as KeyStore?)
|
||||
|
||||
val x509TrustManager = trustManagerFactory.trustManagers.singleOrNull { it is X509TrustManager } as X509TrustManager?
|
||||
?: return
|
||||
|
||||
val sc = SSLContext.getInstance("TLSv1.2")
|
||||
sc.init(null, null, null)
|
||||
sslSocketFactory(TLSSocketFactory(sc.socketFactory), x509TrustManager)
|
||||
val cs: ConnectionSpec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
||||
.tlsVersions(TlsVersion.TLS_1_0)
|
||||
.tlsVersions(TlsVersion.TLS_1_1)
|
||||
.tlsVersions(TlsVersion.TLS_1_2)
|
||||
.build()
|
||||
val specs: MutableList<ConnectionSpec> = ArrayList()
|
||||
specs.add(cs)
|
||||
specs.add(ConnectionSpec.COMPATIBLE_TLS)
|
||||
specs.add(ConnectionSpec.CLEARTEXT)
|
||||
connectionSpecs(specs)
|
||||
}
|
||||
} catch (exc: Exception) {
|
||||
Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc)
|
||||
fun profileLoadLast(onSuccess: (profile: Profile) -> Unit) {
|
||||
launch {
|
||||
val success = withContext(Dispatchers.Default) {
|
||||
profileLoadById(db.profileDao().lastId ?: return@withContext false)
|
||||
}
|
||||
if (!success) {
|
||||
EventBus.getDefault().post(ProfileListEmptyEvent())
|
||||
}
|
||||
}
|
||||
}
|
||||
fun profileSave() = profileSave(profile)
|
||||
fun profileSave(profile: Profile) {
|
||||
launch(Dispatchers.Default) {
|
||||
App.db.profileDao().add(profile)
|
||||
}
|
||||
}
|
||||
|
||||
@ -315,5 +360,5 @@ class Szkolny : /*MultiDexApplication(),*/ Configuration.Provider, CoroutineScop
|
||||
e.printStackTrace()
|
||||
false
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-11.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik;
|
||||
|
||||
import android.graphics.Paint;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.databinding.BindingAdapter;
|
||||
|
||||
public class Binding {
|
||||
@BindingAdapter("strikeThrough")
|
||||
public static void strikeThrough(TextView textView, Boolean strikeThrough) {
|
||||
if (strikeThrough) {
|
||||
textView.setPaintFlags(textView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
|
||||
} else {
|
||||
textView.setPaintFlags(textView.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
|
||||
}
|
||||
}
|
||||
}
|
20
app/src/main/java/pl/szczodrzynski/edziennik/Binding.kt
Normal file
20
app/src/main/java/pl/szczodrzynski/edziennik/Binding.kt
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-11.
|
||||
*/
|
||||
package pl.szczodrzynski.edziennik
|
||||
|
||||
import android.graphics.Paint
|
||||
import android.widget.TextView
|
||||
import androidx.databinding.BindingAdapter
|
||||
|
||||
object Binding {
|
||||
@JvmStatic
|
||||
@BindingAdapter("strikeThrough")
|
||||
fun strikeThrough(textView: TextView, strikeThrough: Boolean) {
|
||||
if (strikeThrough) {
|
||||
textView.paintFlags = textView.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
|
||||
} else {
|
||||
textView.paintFlags = textView.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
|
||||
}
|
||||
}
|
||||
}
|
@ -2,13 +2,17 @@ package pl.szczodrzynski.edziennik
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.ColorStateList
|
||||
import android.content.res.Resources
|
||||
import android.database.Cursor
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.graphics.Rect
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
@ -22,9 +26,8 @@ import android.util.Base64
|
||||
import android.util.Base64.NO_WRAP
|
||||
import android.util.Base64.encodeToString
|
||||
import android.view.View
|
||||
import android.widget.CheckBox
|
||||
import android.widget.CompoundButton
|
||||
import android.widget.TextView
|
||||
import android.view.WindowManager
|
||||
import android.widget.*
|
||||
import androidx.annotation.*
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.database.getIntOrNull
|
||||
@ -34,30 +37,53 @@ import androidx.core.util.forEach
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import com.google.android.gms.security.ProviderInstaller
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import im.wangchao.mhttp.Response
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.ConnectionSpec
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.TlsVersion
|
||||
import okio.Buffer
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApiException
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.ApiResponse
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Team
|
||||
import pl.szczodrzynski.edziennik.network.TLSSocketFactory
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import java.io.InterruptedIOException
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import java.math.BigInteger
|
||||
import java.net.ConnectException
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
import java.nio.charset.Charset
|
||||
import java.security.KeyStore
|
||||
import java.security.MessageDigest
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.zip.CRC32
|
||||
import javax.crypto.Mac
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.SSLException
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
import javax.net.ssl.X509TrustManager
|
||||
import kotlin.Pair
|
||||
|
||||
|
||||
@ -75,8 +101,8 @@ fun JsonObject?.getInt(key: String): Int? = get(key)?.let { if (it.isJsonNull) n
|
||||
fun JsonObject?.getLong(key: String): Long? = get(key)?.let { if (it.isJsonNull) null else it.asLong }
|
||||
fun JsonObject?.getFloat(key: String): Float? = get(key)?.let { if(it.isJsonNull) null else it.asFloat }
|
||||
fun JsonObject?.getChar(key: String): Char? = get(key)?.let { if(it.isJsonNull) null else it.asCharacter }
|
||||
fun JsonObject?.getJsonObject(key: String): JsonObject? = get(key)?.let { if (it.isJsonNull) null else it.asJsonObject }
|
||||
fun JsonObject?.getJsonArray(key: String): JsonArray? = get(key)?.let { if (it.isJsonNull) null else it.asJsonArray }
|
||||
fun JsonObject?.getJsonObject(key: String): JsonObject? = get(key)?.let { if (it.isJsonObject) it.asJsonObject else null }
|
||||
fun JsonObject?.getJsonArray(key: String): JsonArray? = get(key)?.let { if (it.isJsonArray) it.asJsonArray else null }
|
||||
|
||||
fun JsonObject?.getBoolean(key: String, defaultValue: Boolean): Boolean = get(key)?.let { if (it.isJsonNull) defaultValue else it.asBoolean } ?: defaultValue
|
||||
fun JsonObject?.getString(key: String, defaultValue: String): String = get(key)?.let { if (it.isJsonNull) defaultValue else it.asString } ?: defaultValue
|
||||
@ -84,8 +110,19 @@ fun JsonObject?.getInt(key: String, defaultValue: Int): Int = get(key)?.let { if
|
||||
fun JsonObject?.getLong(key: String, defaultValue: Long): Long = get(key)?.let { if (it.isJsonNull) defaultValue else it.asLong } ?: defaultValue
|
||||
fun JsonObject?.getFloat(key: String, defaultValue: Float): Float = get(key)?.let { if(it.isJsonNull) defaultValue else it.asFloat } ?: defaultValue
|
||||
fun JsonObject?.getChar(key: String, defaultValue: Char): Char = get(key)?.let { if(it.isJsonNull) defaultValue else it.asCharacter } ?: defaultValue
|
||||
fun JsonObject?.getJsonObject(key: String, defaultValue: JsonObject): JsonObject = get(key)?.let { if (it.isJsonNull) defaultValue else it.asJsonObject } ?: defaultValue
|
||||
fun JsonObject?.getJsonArray(key: String, defaultValue: JsonArray): JsonArray = get(key)?.let { if (it.isJsonNull) defaultValue else it.asJsonArray } ?: defaultValue
|
||||
fun JsonObject?.getJsonObject(key: String, defaultValue: JsonObject): JsonObject = get(key)?.let { if (it.isJsonObject) it.asJsonObject else defaultValue } ?: defaultValue
|
||||
fun JsonObject?.getJsonArray(key: String, defaultValue: JsonArray): JsonArray = get(key)?.let { if (it.isJsonArray) it.asJsonArray else defaultValue } ?: defaultValue
|
||||
|
||||
fun JsonArray.getBoolean(key: Int): Boolean? = if (key >= size()) null else get(key)?.let { if (it.isJsonNull) null else it.asBoolean }
|
||||
fun JsonArray.getString(key: Int): String? = if (key >= size()) null else get(key)?.let { if (it.isJsonNull) null else it.asString }
|
||||
fun JsonArray.getInt(key: Int): Int? = if (key >= size()) null else get(key)?.let { if (it.isJsonNull) null else it.asInt }
|
||||
fun JsonArray.getLong(key: Int): Long? = if (key >= size()) null else get(key)?.let { if (it.isJsonNull) null else it.asLong }
|
||||
fun JsonArray.getFloat(key: Int): Float? = if (key >= size()) null else get(key)?.let { if(it.isJsonNull) null else it.asFloat }
|
||||
fun JsonArray.getChar(key: Int): Char? = if (key >= size()) null else get(key)?.let { if(it.isJsonNull) null else it.asCharacter }
|
||||
fun JsonArray.getJsonObject(key: Int): JsonObject? = if (key >= size()) null else get(key)?.let { if (it.isJsonObject) it.asJsonObject else null }
|
||||
fun JsonArray.getJsonArray(key: Int): JsonArray? = if (key >= size()) null else get(key)?.let { if (it.isJsonArray) it.asJsonArray else null }
|
||||
|
||||
fun String.toJsonObject(): JsonObject? = try { JsonParser().parse(this).asJsonObject } catch (ignore: Exception) { null }
|
||||
|
||||
operator fun JsonObject.set(key: String, value: JsonElement) = this.add(key, value)
|
||||
operator fun JsonObject.set(key: String, value: Boolean) = this.addProperty(key, value)
|
||||
@ -105,6 +142,10 @@ fun CharSequence?.isNotNullNorEmpty(): Boolean {
|
||||
return this != null && this.isNotEmpty()
|
||||
}
|
||||
|
||||
fun <T> Collection<T>?.isNotNullNorEmpty(): Boolean {
|
||||
return this != null && this.isNotEmpty()
|
||||
}
|
||||
|
||||
fun CharSequence?.isNotNullNorBlank(): Boolean {
|
||||
return this != null && this.isNotBlank()
|
||||
}
|
||||
@ -124,6 +165,13 @@ fun Bundle?.getString(key: String, defaultValue: String): String {
|
||||
return this?.getString(key, defaultValue) ?: defaultValue
|
||||
}
|
||||
|
||||
fun Bundle?.getIntOrNull(key: String): Int? {
|
||||
return this?.get(key) as? Int
|
||||
}
|
||||
fun <T : Any> Bundle?.get(key: String): T? {
|
||||
return this?.get(key) as? T?
|
||||
}
|
||||
|
||||
/**
|
||||
* ` The quick BROWN_fox Jumps OveR THE LAZy-DOG. `
|
||||
*
|
||||
@ -406,7 +454,7 @@ operator fun MatchResult.get(group: Int): String {
|
||||
return groupValues[group]
|
||||
}
|
||||
|
||||
fun Activity.setLanguage(language: String) {
|
||||
fun Context.setLanguage(language: String) {
|
||||
val locale = Locale(language.toLowerCase(Locale.ROOT))
|
||||
val configuration = resources.configuration
|
||||
Locale.setDefault(locale)
|
||||
@ -415,7 +463,6 @@ fun Activity.setLanguage(language: String) {
|
||||
}
|
||||
configuration.locale = locale
|
||||
resources.updateConfiguration(configuration, resources.displayMetrics)
|
||||
baseContext.resources.updateConfiguration(configuration, baseContext.resources.displayMetrics)
|
||||
}
|
||||
|
||||
/*
|
||||
@ -524,7 +571,7 @@ fun CharSequence?.asBoldSpannable(): Spannable {
|
||||
spannable.setSpan(StyleSpan(Typeface.BOLD), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
return spannable
|
||||
}
|
||||
fun CharSequence.asSpannable(vararg spans: Any, substring: String? = null, ignoreCase: Boolean = false): Spannable {
|
||||
fun CharSequence.asSpannable(vararg spans: Any, substring: String? = null, ignoreCase: Boolean = false, ignoreDiacritics: Boolean = false): Spannable {
|
||||
val spannable = SpannableString(this)
|
||||
if (substring == null) {
|
||||
spans.forEach {
|
||||
@ -532,17 +579,44 @@ fun CharSequence.asSpannable(vararg spans: Any, substring: String? = null, ignor
|
||||
}
|
||||
}
|
||||
else if (substring.isNotEmpty()) {
|
||||
var index = indexOf(substring, ignoreCase = ignoreCase)
|
||||
val string =
|
||||
if (ignoreDiacritics)
|
||||
this.cleanDiacritics()
|
||||
else this
|
||||
|
||||
var index = string.indexOf(substring, ignoreCase = ignoreCase)
|
||||
.takeIf { it != -1 } ?: indexOf(substring, ignoreCase = ignoreCase)
|
||||
while (index >= 0) {
|
||||
spans.forEach {
|
||||
spannable.setSpan(it, index, index + substring.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
index = indexOf(substring, startIndex = index + 1, ignoreCase = ignoreCase)
|
||||
index = string.indexOf(substring, startIndex = index + 1, ignoreCase = ignoreCase)
|
||||
.takeIf { it != -1 } ?: indexOf(substring, startIndex = index + 1, ignoreCase = ignoreCase)
|
||||
}
|
||||
}
|
||||
return spannable
|
||||
}
|
||||
|
||||
fun CharSequence.cleanDiacritics(): String {
|
||||
val nameClean = StringBuilder()
|
||||
forEach {
|
||||
val ch = when (it) {
|
||||
'ż' -> 'z'
|
||||
'ó' -> 'o'
|
||||
'ł' -> 'l'
|
||||
'ć' -> 'c'
|
||||
'ę' -> 'e'
|
||||
'ś' -> 's'
|
||||
'ą' -> 'a'
|
||||
'ź' -> 'z'
|
||||
'ń' -> 'n'
|
||||
else -> it
|
||||
}
|
||||
nameClean.append(ch)
|
||||
}
|
||||
return nameClean.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new read-only list only of those given elements, that are not empty.
|
||||
* Applies for CharSequence and descendants.
|
||||
@ -642,6 +716,34 @@ fun Bundle(vararg properties: Pair<String, Any?>): Bundle {
|
||||
}
|
||||
}
|
||||
}
|
||||
fun Intent(action: String? = null, vararg properties: Pair<String, Any?>): Intent {
|
||||
return Intent(action).putExtras(Bundle(*properties))
|
||||
}
|
||||
fun Intent(packageContext: Context, cls: Class<*>, vararg properties: Pair<String, Any?>): Intent {
|
||||
return Intent(packageContext, cls).putExtras(Bundle(*properties))
|
||||
}
|
||||
|
||||
fun Bundle.toJsonObject(): JsonObject {
|
||||
val json = JsonObject()
|
||||
keySet()?.forEach { key ->
|
||||
get(key)?.let {
|
||||
when (it) {
|
||||
is String -> json.addProperty(key, it)
|
||||
is Char -> json.addProperty(key, it)
|
||||
is Int -> json.addProperty(key, it)
|
||||
is Long -> json.addProperty(key, it)
|
||||
is Float -> json.addProperty(key, it)
|
||||
is Short -> json.addProperty(key, it)
|
||||
is Double -> json.addProperty(key, it)
|
||||
is Boolean -> json.addProperty(key, it)
|
||||
is Bundle -> json.add(key, it.toJsonObject())
|
||||
else -> json.addProperty(key, it.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
return json
|
||||
}
|
||||
fun Intent.toJsonObject() = extras?.toJsonObject()
|
||||
|
||||
fun JsonArray?.isNullOrEmpty(): Boolean = (this?.size() ?: 0) == 0
|
||||
fun JsonArray.isEmpty(): Boolean = this.size() == 0
|
||||
@ -658,6 +760,13 @@ inline fun <T : View> T.onClick(crossinline onClickListener: (v: T) -> Unit) {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <T : View> T.onLongClick(crossinline onLongClickListener: (v: T) -> Boolean) {
|
||||
setOnLongClickListener { v: View ->
|
||||
onLongClickListener(v as T)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <T : CompoundButton> T.onChange(crossinline onChangeListener: (v: T, isChecked: Boolean) -> Unit) {
|
||||
setOnCheckedChangeListener { buttonView, isChecked ->
|
||||
@ -665,6 +774,19 @@ inline fun <T : CompoundButton> T.onChange(crossinline onChangeListener: (v: T,
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <T : MaterialButton> T.onChange(crossinline onChangeListener: (v: T, isChecked: Boolean) -> Unit) {
|
||||
clearOnCheckedChangeListeners()
|
||||
addOnCheckedChangeListener { buttonView, isChecked ->
|
||||
onChangeListener(buttonView as T, isChecked)
|
||||
}
|
||||
}
|
||||
|
||||
fun View.attachToastHint(stringRes: Int) = onLongClick {
|
||||
Toast.makeText(it.context, stringRes, Toast.LENGTH_SHORT).show()
|
||||
true
|
||||
}
|
||||
|
||||
fun <T> LiveData<T>.observeOnce(lifecycleOwner: LifecycleOwner, observer: Observer<T>) {
|
||||
observe(lifecycleOwner, object : Observer<T> {
|
||||
override fun onChanged(t: T?) {
|
||||
@ -720,7 +842,7 @@ fun View.findParentById(targetId: Int): View? {
|
||||
return null
|
||||
}
|
||||
|
||||
fun CoroutineScope.startCoroutineTimer(delayMillis: Long = 0, repeatMillis: Long = 0, action: () -> Unit) = launch {
|
||||
fun CoroutineScope.startCoroutineTimer(delayMillis: Long = 0, repeatMillis: Long = 0, action: suspend CoroutineScope.() -> Unit) = launch {
|
||||
delay(delayMillis)
|
||||
if (repeatMillis > 0) {
|
||||
while (true) {
|
||||
@ -934,6 +1056,8 @@ fun Context.getNotificationTitle(type: Int): String {
|
||||
Notification.TYPE_NEW_EVENT -> R.string.notification_type_new_event
|
||||
Notification.TYPE_NEW_HOMEWORK -> R.string.notification_type_new_homework
|
||||
Notification.TYPE_NEW_SHARED_EVENT -> R.string.notification_type_new_shared_event
|
||||
Notification.TYPE_NEW_SHARED_HOMEWORK -> R.string.notification_type_new_shared_homework
|
||||
Notification.TYPE_REMOVED_SHARED_EVENT -> R.string.notification_type_removed_shared_event
|
||||
Notification.TYPE_NEW_MESSAGE -> R.string.notification_type_new_message
|
||||
Notification.TYPE_NEW_NOTICE -> R.string.notification_type_notice
|
||||
Notification.TYPE_NEW_ATTENDANCE -> R.string.notification_type_attendance
|
||||
@ -942,6 +1066,7 @@ fun Context.getNotificationTitle(type: Int): String {
|
||||
Notification.TYPE_FEEDBACK_MESSAGE -> R.string.notification_type_feedback_message
|
||||
Notification.TYPE_NEW_ANNOUNCEMENT -> R.string.notification_type_new_announcement
|
||||
Notification.TYPE_AUTO_ARCHIVING -> R.string.notification_type_auto_archiving
|
||||
Notification.TYPE_TEACHER_ABSENCE -> R.string.notification_type_new_teacher_absence
|
||||
Notification.TYPE_GENERAL -> R.string.notification_type_general
|
||||
else -> R.string.notification_type_general
|
||||
})
|
||||
@ -950,3 +1075,173 @@ fun Context.getNotificationTitle(type: Int): String {
|
||||
fun Cursor?.getString(columnName: String) = this?.getStringOrNull(getColumnIndex(columnName))
|
||||
fun Cursor?.getInt(columnName: String) = this?.getIntOrNull(getColumnIndex(columnName))
|
||||
fun Cursor?.getLong(columnName: String) = this?.getLongOrNull(getColumnIndex(columnName))
|
||||
|
||||
fun OkHttpClient.Builder.installHttpsSupport(context: Context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
try {
|
||||
try {
|
||||
ProviderInstaller.installIfNeeded(context)
|
||||
} catch (e: Exception) {
|
||||
Log.e("OkHttpTLSCompat", "Play Services not found or outdated")
|
||||
|
||||
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
|
||||
trustManagerFactory.init(null as KeyStore?)
|
||||
|
||||
val x509TrustManager = trustManagerFactory.trustManagers.singleOrNull { it is X509TrustManager } as X509TrustManager?
|
||||
?: return
|
||||
|
||||
val sc = SSLContext.getInstance("TLSv1.2")
|
||||
sc.init(null, null, null)
|
||||
sslSocketFactory(TLSSocketFactory(sc.socketFactory), x509TrustManager)
|
||||
val cs: ConnectionSpec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
||||
.tlsVersions(TlsVersion.TLS_1_0)
|
||||
.tlsVersions(TlsVersion.TLS_1_1)
|
||||
.tlsVersions(TlsVersion.TLS_1_2)
|
||||
.build()
|
||||
val specs: MutableList<ConnectionSpec> = ArrayList()
|
||||
specs.add(cs)
|
||||
specs.add(ConnectionSpec.COMPATIBLE_TLS)
|
||||
specs.add(ConnectionSpec.CLEARTEXT)
|
||||
connectionSpecs(specs)
|
||||
}
|
||||
} catch (exc: Exception) {
|
||||
Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun CharSequence.containsAll(list: List<CharSequence>, ignoreCase: Boolean = false): Boolean {
|
||||
for (i in list) {
|
||||
if (!contains(i, ignoreCase))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
inline fun RadioButton.setOnSelectedListener(crossinline listener: (buttonView: CompoundButton) -> Unit)
|
||||
= setOnCheckedChangeListener { buttonView, isChecked -> if (isChecked) listener(buttonView) }
|
||||
|
||||
fun Response.toErrorCode() = when (this.code()) {
|
||||
400 -> ERROR_REQUEST_HTTP_400
|
||||
401 -> ERROR_REQUEST_HTTP_401
|
||||
403 -> ERROR_REQUEST_HTTP_403
|
||||
404 -> ERROR_REQUEST_HTTP_404
|
||||
405 -> ERROR_REQUEST_HTTP_405
|
||||
410 -> ERROR_REQUEST_HTTP_410
|
||||
424 -> ERROR_REQUEST_HTTP_424
|
||||
500 -> ERROR_REQUEST_HTTP_500
|
||||
503 -> ERROR_REQUEST_HTTP_503
|
||||
else -> null
|
||||
}
|
||||
fun Throwable.toErrorCode() = when (this) {
|
||||
is UnknownHostException -> ERROR_REQUEST_FAILURE_HOSTNAME_NOT_FOUND
|
||||
is SSLException -> ERROR_REQUEST_FAILURE_SSL_ERROR
|
||||
is SocketTimeoutException -> ERROR_REQUEST_FAILURE_TIMEOUT
|
||||
is InterruptedIOException, is ConnectException -> ERROR_REQUEST_FAILURE_NO_INTERNET
|
||||
is SzkolnyApiException -> this.error?.toErrorCode()
|
||||
else -> null
|
||||
}
|
||||
private fun ApiResponse.Error.toErrorCode() = when (this.code) {
|
||||
else -> ERROR_API_EXCEPTION
|
||||
}
|
||||
fun Throwable.toApiError(tag: String) = ApiError.fromThrowable(tag, this)
|
||||
|
||||
inline fun <A, B, R> ifNotNull(a: A?, b: B?, code: (A, B) -> R): R? {
|
||||
if (a != null && b != null) {
|
||||
return code(a, b)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@kotlin.jvm.JvmName("averageOrNullOfInt")
|
||||
fun Iterable<Int>.averageOrNull() = this.average().let { if (it.isNaN()) null else it }
|
||||
@kotlin.jvm.JvmName("averageOrNullOfFloat")
|
||||
fun Iterable<Float>.averageOrNull() = this.average().let { if (it.isNaN()) null else it }
|
||||
|
||||
fun String.copyToClipboard(context: Context) {
|
||||
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clipData = ClipData.newPlainText("Tekst", this)
|
||||
clipboard.primaryClip = clipData
|
||||
}
|
||||
|
||||
fun TextView.getTextPosition(range: IntRange): Rect {
|
||||
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
||||
|
||||
// Initialize global value
|
||||
var parentTextViewRect = Rect()
|
||||
|
||||
// Initialize values for the computing of clickedText position
|
||||
//val completeText = parentTextView.text as SpannableString
|
||||
val textViewLayout = this.layout
|
||||
|
||||
val startOffsetOfClickedText = range.first//completeText.getSpanStart(clickedText)
|
||||
val endOffsetOfClickedText = range.last//completeText.getSpanEnd(clickedText)
|
||||
var startXCoordinatesOfClickedText = textViewLayout.getPrimaryHorizontal(startOffsetOfClickedText)
|
||||
var endXCoordinatesOfClickedText = textViewLayout.getPrimaryHorizontal(endOffsetOfClickedText)
|
||||
|
||||
// Get the rectangle of the clicked text
|
||||
val currentLineStartOffset = textViewLayout.getLineForOffset(startOffsetOfClickedText)
|
||||
val currentLineEndOffset = textViewLayout.getLineForOffset(endOffsetOfClickedText)
|
||||
val keywordIsInMultiLine = currentLineStartOffset != currentLineEndOffset
|
||||
textViewLayout.getLineBounds(currentLineStartOffset, parentTextViewRect)
|
||||
|
||||
// Update the rectangle position to his real position on screen
|
||||
val parentTextViewLocation = intArrayOf(0, 0)
|
||||
this.getLocationOnScreen(parentTextViewLocation)
|
||||
|
||||
val parentTextViewTopAndBottomOffset = (parentTextViewLocation[1] - this.scrollY + this.compoundPaddingTop)
|
||||
parentTextViewRect.top += parentTextViewTopAndBottomOffset
|
||||
parentTextViewRect.bottom += parentTextViewTopAndBottomOffset
|
||||
|
||||
// In the case of multi line text, we have to choose what rectangle take
|
||||
if (keywordIsInMultiLine) {
|
||||
val screenHeight = windowManager.defaultDisplay.height
|
||||
val dyTop = parentTextViewRect.top
|
||||
val dyBottom = screenHeight - parentTextViewRect.bottom
|
||||
val onTop = dyTop > dyBottom
|
||||
|
||||
if (onTop) {
|
||||
endXCoordinatesOfClickedText = textViewLayout.getLineRight(currentLineStartOffset);
|
||||
} else {
|
||||
parentTextViewRect = Rect()
|
||||
textViewLayout.getLineBounds(currentLineEndOffset, parentTextViewRect);
|
||||
parentTextViewRect.top += parentTextViewTopAndBottomOffset;
|
||||
parentTextViewRect.bottom += parentTextViewTopAndBottomOffset;
|
||||
startXCoordinatesOfClickedText = textViewLayout.getLineLeft(currentLineEndOffset);
|
||||
}
|
||||
}
|
||||
|
||||
parentTextViewRect.left += (
|
||||
parentTextViewLocation[0] +
|
||||
startXCoordinatesOfClickedText +
|
||||
this.compoundPaddingLeft -
|
||||
this.scrollX
|
||||
).toInt()
|
||||
parentTextViewRect.right = (
|
||||
parentTextViewRect.left +
|
||||
endXCoordinatesOfClickedText -
|
||||
startXCoordinatesOfClickedText
|
||||
).toInt()
|
||||
|
||||
return parentTextViewRect
|
||||
}
|
||||
|
||||
inline fun ViewPager.addOnPageSelectedListener(crossinline block: (position: Int) -> Unit) = addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
|
||||
override fun onPageScrollStateChanged(state: Int) {}
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
|
||||
override fun onPageSelected(position: Int) { block(position) }
|
||||
})
|
||||
|
||||
val SwipeRefreshLayout.onScrollListener: RecyclerView.OnScrollListener
|
||||
get() = object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
if (recyclerView.canScrollVertically(-1))
|
||||
this@onScrollListener.isEnabled = false
|
||||
if (!recyclerView.canScrollVertically(-1) && newState == RecyclerView.SCROLL_STATE_IDLE)
|
||||
this@onScrollListener.isEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
operator fun <K, V> Iterable<Pair<K, V>>.get(key: K): V? {
|
||||
return firstOrNull { it.first == key }?.second
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package pl.szczodrzynski.edziennik
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.ActivityManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
@ -9,12 +8,10 @@ import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.AsyncTask
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
@ -23,7 +20,6 @@ import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.navigation.NavOptions
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.danimahardhika.cafebar.CafeBar
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.mikepenz.iconics.IconicsColor
|
||||
@ -34,42 +30,46 @@ import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
|
||||
import com.mikepenz.materialdrawer.model.DividerDrawerItem
|
||||
import com.mikepenz.materialdrawer.model.ProfileDrawerItem
|
||||
import com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem
|
||||
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem
|
||||
import com.mikepenz.materialdrawer.model.interfaces.IProfile
|
||||
import com.mikepenz.materialdrawer.model.interfaces.*
|
||||
import com.mikepenz.materialdrawer.model.utils.withIsHiddenInMiniDrawer
|
||||
import kotlinx.coroutines.*
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import pl.droidsonroids.gif.GifDrawable
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.events.*
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing
|
||||
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata.*
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
|
||||
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
||||
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.ServerMessageDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncViewListDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.agenda.AgendaFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.attendance.AttendanceFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.DebugFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.MainSnackbar
|
||||
import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.debug.DebugFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.debug.LabFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar
|
||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesListFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.editor.GradesEditorFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessageFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesComposeFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesListFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.compose.MessagesComposeFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsListFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsNewFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.timetable.TimetableFragment
|
||||
@ -89,13 +89,13 @@ import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
|
||||
import pl.szczodrzynski.navlib.drawer.NavDrawer
|
||||
import pl.szczodrzynski.navlib.drawer.items.DrawerPrimaryItem
|
||||
import pl.szczodrzynski.navlib.drawer.items.withAppTitle
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
companion object {
|
||||
|
||||
var useOldMessages = false
|
||||
@ -108,6 +108,7 @@ class MainActivity : AppCompatActivity() {
|
||||
const val DRAWER_PROFILE_SYNC_ALL = 201
|
||||
const val DRAWER_PROFILE_EXPORT_DATA = 202
|
||||
const val DRAWER_PROFILE_MANAGE = 203
|
||||
const val DRAWER_PROFILE_MARK_ALL_AS_READ = 204
|
||||
const val DRAWER_ITEM_HOME = 1
|
||||
const val DRAWER_ITEM_TIMETABLE = 11
|
||||
const val DRAWER_ITEM_AGENDA = 12
|
||||
@ -127,6 +128,7 @@ class MainActivity : AppCompatActivity() {
|
||||
const val TARGET_MESSAGES_DETAILS = 503
|
||||
const val TARGET_MESSAGES_COMPOSE = 504
|
||||
const val TARGET_WEB_PUSH = 140
|
||||
const val TARGET_LAB = 1000
|
||||
|
||||
const val HOME_ID = DRAWER_ITEM_HOME
|
||||
|
||||
@ -151,7 +153,7 @@ class MainActivity : AppCompatActivity() {
|
||||
.withBadgeTypeId(TYPE_EVENT)
|
||||
.isInDrawer(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesFragment::class)
|
||||
list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesListFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_numeric_5_box_outline)
|
||||
.withBadgeTypeId(TYPE_GRADE)
|
||||
.isInDrawer(true)
|
||||
@ -183,7 +185,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
|
||||
// static drawer items
|
||||
list += NavTarget(DRAWER_ITEM_NOTIFICATIONS, R.string.menu_notifications, NotificationsFragment::class)
|
||||
list += NavTarget(DRAWER_ITEM_NOTIFICATIONS, R.string.menu_notifications, NotificationsListFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_bell_ring_outline)
|
||||
.isInDrawer(true)
|
||||
.isStatic(true)
|
||||
@ -208,6 +210,10 @@ class MainActivity : AppCompatActivity() {
|
||||
.withDescription(R.string.drawer_manage_profiles_desc)
|
||||
.isInProfileList(false)
|
||||
|
||||
list += NavTarget(DRAWER_PROFILE_MARK_ALL_AS_READ, R.string.menu_mark_everything_as_read, null)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.isInProfileList(true)
|
||||
|
||||
list += NavTarget(DRAWER_PROFILE_SYNC_ALL, R.string.menu_sync_all, null)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_download_outline)
|
||||
.isInProfileList(true)
|
||||
@ -220,12 +226,23 @@ class MainActivity : AppCompatActivity() {
|
||||
list += NavTarget(TARGET_MESSAGES_DETAILS, R.string.menu_message, MessageFragment::class).withPopTo(DRAWER_ITEM_MESSAGES)
|
||||
list += NavTarget(TARGET_MESSAGES_COMPOSE, R.string.menu_message_compose, MessagesComposeFragment::class)
|
||||
list += NavTarget(TARGET_WEB_PUSH, R.string.menu_web_push, WebPushFragment::class)
|
||||
list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class)
|
||||
if (App.debugMode) {
|
||||
list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class)
|
||||
list += NavTarget(TARGET_LAB, R.string.menu_lab, LabFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_flask_outline)
|
||||
.isInDrawer(true)
|
||||
.isBelowSeparator(true)
|
||||
.isStatic(true)
|
||||
}
|
||||
|
||||
list
|
||||
}
|
||||
}
|
||||
|
||||
private var job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
val b: ActivitySzkolnyBinding by lazy { ActivitySzkolnyBinding.inflate(layoutInflater) }
|
||||
val navView: NavView by lazy { b.navView }
|
||||
val drawer: NavDrawer by lazy { navView.drawer }
|
||||
@ -257,15 +274,22 @@ class MainActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
d(TAG, "Activity created")
|
||||
|
||||
setTheme(Themes.appTheme)
|
||||
|
||||
app.config.ui.language?.let {
|
||||
setLanguage(it)
|
||||
}
|
||||
|
||||
setContentView(b.root)
|
||||
if (App.profileId == 0) {
|
||||
onProfileListEmptyEvent(ProfileListEmptyEvent())
|
||||
return
|
||||
}
|
||||
|
||||
Log.d(TAG, Signing.appPassword)
|
||||
d(TAG, "Profile is valid, inflating views")
|
||||
|
||||
setContentView(b.root)
|
||||
|
||||
mainSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
|
||||
errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
|
||||
@ -332,8 +356,7 @@ class MainActivity : AppCompatActivity() {
|
||||
setAccountHeaderBackground(app.config.ui.headerBackground)
|
||||
|
||||
drawerProfileListEmptyListener = {
|
||||
app.config.loginFinished = false
|
||||
profileListEmptyListener()
|
||||
onProfileListEmptyEvent(ProfileListEmptyEvent())
|
||||
}
|
||||
drawerItemSelectedListener = { id, position, drawerItem ->
|
||||
loadTarget(id)
|
||||
@ -344,7 +367,7 @@ class MainActivity : AppCompatActivity() {
|
||||
false
|
||||
}
|
||||
drawerProfileLongClickListener = { _, profile, _, view ->
|
||||
if (profile is ProfileDrawerItem) {
|
||||
if (view != null && profile is ProfileDrawerItem) {
|
||||
showProfileContextMenu(profile, view)
|
||||
true
|
||||
}
|
||||
@ -362,30 +385,19 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
navTarget = navTargetList[0]
|
||||
|
||||
var profileListEmpty = drawer.profileListEmpty
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
intent?.putExtras(savedInstanceState)
|
||||
savedInstanceState.clear()
|
||||
}
|
||||
|
||||
if (!profileListEmpty) {
|
||||
handleIntent(intent?.extras)
|
||||
}
|
||||
app.db.profileDao().all.observe(this, Observer { profiles ->
|
||||
drawer.setProfileList(profiles.filter { it.id >= 0 }.toMutableList())
|
||||
if (profileListEmpty) {
|
||||
profileListEmpty = false
|
||||
handleIntent(intent?.extras)
|
||||
}
|
||||
else if (app.profile != null) {
|
||||
drawer.currentProfile = app.profile.id
|
||||
}
|
||||
drawer.currentProfile = App.profileId
|
||||
})
|
||||
|
||||
// if null, getAllFull will load a profile and update drawerItems
|
||||
if (app.profile != null)
|
||||
setDrawerItems()
|
||||
setDrawerItems()
|
||||
|
||||
handleIntent(intent?.extras)
|
||||
|
||||
app.db.metadataDao().unreadCounts.observe(this, Observer { unreadCounters ->
|
||||
unreadCounters.map {
|
||||
@ -402,9 +414,8 @@ class MainActivity : AppCompatActivity() {
|
||||
R.color.md_green_500
|
||||
)
|
||||
|
||||
isStoragePermissionGranted()
|
||||
|
||||
SyncWorker.scheduleNext(app)
|
||||
UpdateWorker.scheduleNext(app)
|
||||
|
||||
// APP BACKGROUND
|
||||
if (app.config.ui.appBackground != null) {
|
||||
@ -438,6 +449,8 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
// WHAT'S NEW DIALOG
|
||||
if (app.config.appVersion < BuildConfig.VERSION_CODE) {
|
||||
// force an AppSync after update
|
||||
app.config.sync.lastAppSync = 0L
|
||||
ChangelogDialog(this)
|
||||
if (app.config.appVersion < 170) {
|
||||
//Intent intent = new Intent(this, ChangelogIntroActivity.class);
|
||||
@ -501,7 +514,7 @@ class MainActivity : AppCompatActivity() {
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_help_circle_outline)
|
||||
.withOnClickListener(View.OnClickListener { loadTarget(TARGET_FEEDBACK) })
|
||||
)
|
||||
if (App.devMode) {
|
||||
if (App.debugMode) {
|
||||
bottomSheet += BottomSheetPrimaryItem(false)
|
||||
.withTitle(R.string.menu_debug)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_android_studio)
|
||||
@ -509,17 +522,25 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
var profileListEmptyListener = {
|
||||
startActivityForResult(Intent(this, LoginActivity::class.java), REQUEST_LOGIN_ACTIVITY)
|
||||
}
|
||||
private var profileSettingClickListener = { id: Int, view: View? ->
|
||||
when (id) {
|
||||
DRAWER_PROFILE_ADD_NEW -> {
|
||||
profileListEmptyListener()
|
||||
startActivityForResult(Intent(this, LoginActivity::class.java), REQUEST_LOGIN_ACTIVITY)
|
||||
}
|
||||
DRAWER_PROFILE_SYNC_ALL -> {
|
||||
EdziennikTask.sync().enqueue(this)
|
||||
}
|
||||
DRAWER_PROFILE_MARK_ALL_AS_READ -> { launch {
|
||||
withContext(Dispatchers.Default) {
|
||||
app.db.profileDao().allNow.forEach { profile ->
|
||||
if (profile.loginStoreType != LoginStore.LOGIN_TYPE_LIBRUS)
|
||||
app.db.metadataDao().setAllSeenExceptMessagesAndAnnouncements(profile.id, true)
|
||||
else
|
||||
app.db.metadataDao().setAllSeenExceptMessages(profile.id, true)
|
||||
}
|
||||
}
|
||||
Toast.makeText(this@MainActivity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show()
|
||||
}}
|
||||
else -> {
|
||||
loadTarget(id)
|
||||
}
|
||||
@ -549,7 +570,7 @@ class MainActivity : AppCompatActivity() {
|
||||
EdziennikTask.syncProfile(
|
||||
App.profileId,
|
||||
listOf(navTargetId to fragmentParam),
|
||||
arguments
|
||||
arguments = arguments
|
||||
).enqueue(this)
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
@ -564,6 +585,13 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onProfileListEmptyEvent(event: ProfileListEmptyEvent) {
|
||||
d(TAG, "Profile list is empty. Launch LoginActivity.")
|
||||
app.config.loginFinished = false
|
||||
startActivity(Intent(this, LoginActivity::class.java))
|
||||
finish()
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onApiTaskProgressEvent(event: ApiTaskProgressEvent) {
|
||||
if (event.profileId == App.profileId) {
|
||||
navView.toolbar.apply {
|
||||
@ -579,6 +607,7 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||
fun onApiTaskFinishedEvent(event: ApiTaskFinishedEvent) {
|
||||
EventBus.getDefault().removeStickyEvent(event)
|
||||
if (event.profileId == App.profileId) {
|
||||
navView.toolbar.apply {
|
||||
subtitleFormat = R.string.toolbar_subtitle
|
||||
@ -589,6 +618,7 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||
fun onApiTaskAllFinishedEvent(event: ApiTaskAllFinishedEvent) {
|
||||
EventBus.getDefault().removeStickyEvent(event)
|
||||
swipeRefreshLayout.isRefreshing = false
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||
@ -604,7 +634,8 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||
fun onAppManagerDetectedEvent(event: AppManagerDetectedEvent) {
|
||||
if (app.appConfig.dontShowAppManagerDialog)
|
||||
EventBus.getDefault().removeStickyEvent(event)
|
||||
if (app.config.sync.dontShowAppManagerDialog)
|
||||
return
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.app_manager_dialog_title)
|
||||
@ -626,12 +657,15 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
.setNeutralButton(R.string.dont_ask_again) { dialog, which ->
|
||||
app.appConfig.dontShowAppManagerDialog = true
|
||||
app.saveConfig("dontShowAppManagerDialog")
|
||||
app.config.sync.dontShowAppManagerDialog = true
|
||||
}
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onUserActionRequiredEvent(event: UserActionRequiredEvent) {
|
||||
app.userActionManager.execute(this, event.profileId, event.type)
|
||||
}
|
||||
|
||||
private fun fragmentToSyncName(currentFragment: Int): Int {
|
||||
return when (currentFragment) {
|
||||
@ -669,26 +703,64 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
d(TAG, "}")
|
||||
|
||||
var intentProfileId = -1
|
||||
var intentTargetId = -1
|
||||
|
||||
if (extras?.containsKey("action") == true) {
|
||||
val handled = when (extras.getString("action")) {
|
||||
"serverMessage" -> {
|
||||
ServerMessageDialog(
|
||||
this,
|
||||
extras.getString("serverMessageTitle") ?: getString(R.string.app_name),
|
||||
extras.getString("serverMessageText") ?: ""
|
||||
)
|
||||
true
|
||||
}
|
||||
"feedbackMessage" -> {
|
||||
intentTargetId = TARGET_FEEDBACK
|
||||
false
|
||||
}
|
||||
"userActionRequired" -> {
|
||||
app.userActionManager.execute(
|
||||
this,
|
||||
extras.getInt("profileId"),
|
||||
extras.getInt("type")
|
||||
)
|
||||
true
|
||||
}
|
||||
"createManualEvent" -> {
|
||||
val date = extras.getString("eventDate")?.let { Date.fromY_m_d(it) } ?: Date.getToday()
|
||||
EventManualDialog(
|
||||
this,
|
||||
App.profileId,
|
||||
defaultDate = date
|
||||
)
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
if (handled && !navLoading) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (extras?.containsKey("reloadProfileId") == true) {
|
||||
val reloadProfileId = extras.getInt("reloadProfileId", -1)
|
||||
extras.remove("reloadProfileId")
|
||||
if (reloadProfileId == -1 || (app.profile != null && app.profile.id == reloadProfileId)) {
|
||||
if (reloadProfileId == -1 || app.profile.id == reloadProfileId) {
|
||||
reloadTarget()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var intentProfileId = -1
|
||||
var intentTargetId = -1
|
||||
|
||||
if (extras?.containsKey("profileId") == true) {
|
||||
if (extras?.getInt("profileId", -1) != -1) {
|
||||
intentProfileId = extras.getInt("profileId", -1)
|
||||
extras.remove("profileId")
|
||||
extras?.remove("profileId")
|
||||
}
|
||||
|
||||
if (extras?.containsKey("fragmentId") == true) {
|
||||
if (extras?.getInt("fragmentId", -1) != -1) {
|
||||
intentTargetId = extras.getInt("fragmentId", -1)
|
||||
extras.remove("fragmentId")
|
||||
extras?.remove("fragmentId")
|
||||
}
|
||||
|
||||
/*if (intentTargetId == -1 && navController.currentDestination?.id == R.id.loadingFragment) {
|
||||
@ -702,9 +774,9 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
when {
|
||||
app.profile == null || app.profile.id == -1 -> {
|
||||
app.profile.id == 0 -> {
|
||||
if (intentProfileId == -1)
|
||||
intentProfileId = app.appSharedPrefs.getInt("current_profile_id", 1)
|
||||
intentProfileId = app.config.lastProfileId
|
||||
loadProfile(intentProfileId, intentTargetId, extras)
|
||||
}
|
||||
intentProfileId != -1 -> {
|
||||
@ -743,7 +815,16 @@ class MainActivity : AppCompatActivity() {
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
d(TAG, "Activity started")
|
||||
super.onStart()
|
||||
}
|
||||
override fun onStop() {
|
||||
d(TAG, "Activity stopped")
|
||||
super.onStop()
|
||||
}
|
||||
override fun onResume() {
|
||||
d(TAG, "Activity resumed")
|
||||
val filter = IntentFilter()
|
||||
filter.addAction(Intent.ACTION_MAIN)
|
||||
registerReceiver(intentReceiver, filter)
|
||||
@ -751,10 +832,15 @@ class MainActivity : AppCompatActivity() {
|
||||
super.onResume()
|
||||
}
|
||||
override fun onPause() {
|
||||
d(TAG, "Activity paused")
|
||||
unregisterReceiver(intentReceiver)
|
||||
EventBus.getDefault().unregister(this)
|
||||
super.onPause()
|
||||
}
|
||||
override fun onDestroy() {
|
||||
d(TAG, "Activity destroyed")
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
@ -768,15 +854,10 @@ class MainActivity : AppCompatActivity() {
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == REQUEST_LOGIN_ACTIVITY) {
|
||||
if (resultCode == Activity.RESULT_CANCELED && false) {
|
||||
if (!app.config.loginFinished)
|
||||
finish()
|
||||
}
|
||||
else {
|
||||
if (!app.config.loginFinished)
|
||||
finish()
|
||||
else {
|
||||
handleIntent(data?.extras)
|
||||
}
|
||||
handleIntent(data?.extras)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -797,34 +878,20 @@ class MainActivity : AppCompatActivity() {
|
||||
fun loadProfile(id: Int) = loadProfile(id, navTargetId)
|
||||
fun loadProfile(id: Int, arguments: Bundle?) = loadProfile(id, navTargetId, arguments)
|
||||
fun loadProfile(id: Int, drawerSelection: Int, arguments: Bundle? = null) {
|
||||
//d("NavDebug", "loadProfile(id = $id, drawerSelection = $drawerSelection)")
|
||||
if (app.profile != null && App.profileId == id) {
|
||||
if (App.profileId == id) {
|
||||
drawer.currentProfile = app.profile.id
|
||||
loadTarget(drawerSelection, arguments)
|
||||
return
|
||||
}
|
||||
AsyncTask.execute {
|
||||
app.profileLoadById(id)
|
||||
app.profileLoad(id) {
|
||||
MessagesFragment.pageSelection = -1
|
||||
MessagesListFragment.tapPositions = intArrayOf(RecyclerView.NO_POSITION, RecyclerView.NO_POSITION)
|
||||
MessagesListFragment.topPositions = intArrayOf(RecyclerView.NO_POSITION, RecyclerView.NO_POSITION)
|
||||
MessagesListFragment.bottomPositions = intArrayOf(RecyclerView.NO_POSITION, RecyclerView.NO_POSITION)
|
||||
|
||||
this.runOnUiThread {
|
||||
if (app.profile == null) {
|
||||
if (app.config.loginFinished) {
|
||||
// this shouldn't run
|
||||
profileListEmptyListener()
|
||||
}
|
||||
} else {
|
||||
setDrawerItems()
|
||||
// the drawer profile is updated automatically when the drawer item is clicked
|
||||
// update it manually when switching profiles from other source
|
||||
//if (drawer.currentProfile != app.profile.id)
|
||||
drawer.currentProfile = app.profile.id
|
||||
loadTarget(drawerSelection, arguments)
|
||||
}
|
||||
}
|
||||
setDrawerItems()
|
||||
// the drawer profile is updated automatically when the drawer item is clicked
|
||||
// update it manually when switching profiles from other source
|
||||
//if (drawer.currentProfile != app.profile.id)
|
||||
drawer.currentProfile = app.profileId
|
||||
loadTarget(drawerSelection, arguments)
|
||||
}
|
||||
}
|
||||
fun loadTarget(id: Int, arguments: Bundle? = null) {
|
||||
@ -842,15 +909,16 @@ class MainActivity : AppCompatActivity() {
|
||||
loadTarget(target, arguments)
|
||||
}
|
||||
}
|
||||
private fun loadTarget(target: NavTarget, arguments: Bundle? = null) {
|
||||
d("NavDebug", "loadTarget(target = $target, arguments = $arguments)")
|
||||
private fun loadTarget(target: NavTarget, args: Bundle? = null) {
|
||||
d("NavDebug", "loadTarget(target = $target, args = $args)")
|
||||
|
||||
val arguments = args ?: navBackStack.firstOrNull { it.first.id == target.id }?.second ?: Bundle()
|
||||
bottomSheet.close()
|
||||
bottomSheet.removeAllContextual()
|
||||
bottomSheet.toggleGroupEnabled = false
|
||||
bottomSheet.onCloseListener = null
|
||||
drawer.close()
|
||||
drawer.setSelection(target.id, fireOnClick = false)
|
||||
if (drawer.getSelection() != target.id)
|
||||
drawer.setSelection(target.id, fireOnClick = false)
|
||||
navView.toolbar.setTitle(target.title ?: target.name)
|
||||
navView.bottomBar.fabEnable = false
|
||||
navView.bottomBar.fabExtended = false
|
||||
@ -892,6 +960,7 @@ class MainActivity : AppCompatActivity() {
|
||||
navBackStack.removeAt(navBackStack.lastIndex)
|
||||
}
|
||||
navTarget = target
|
||||
navArguments = arguments
|
||||
|
||||
return@let null
|
||||
}?.let {
|
||||
@ -901,7 +970,7 @@ class MainActivity : AppCompatActivity() {
|
||||
R.anim.task_open_enter,
|
||||
R.anim.task_open_exit
|
||||
)
|
||||
navBackStack.add(navTarget to arguments)
|
||||
navBackStack.add(navTarget to navArguments)
|
||||
navTarget = target
|
||||
navArguments = arguments
|
||||
}
|
||||
@ -969,7 +1038,7 @@ class MainActivity : AppCompatActivity() {
|
||||
* that something has changed in the bottom sheet.
|
||||
*/
|
||||
fun gainAttention() {
|
||||
if (app.config.ui.bottomSheetOpened || true)
|
||||
if (app.config.ui.bottomSheetOpened)
|
||||
return
|
||||
b.navView.postDelayed({
|
||||
navView.gainAttentionOnBottomBar()
|
||||
@ -998,11 +1067,12 @@ class MainActivity : AppCompatActivity() {
|
||||
val item = DrawerPrimaryItem()
|
||||
.withIdentifier(target.id.toLong())
|
||||
.withName(target.name)
|
||||
.withHiddenInMiniDrawer(!app.config.ui.miniMenuButtons.contains(target.id))
|
||||
.withIsHiddenInMiniDrawer(!app.config.ui.miniMenuButtons.contains(target.id))
|
||||
.also { if (target.description != null) it.withDescription(target.description!!) }
|
||||
.also { if (target.icon != null) it.withIcon(target.icon!!) }
|
||||
.also { if (target.title != null) it.withAppTitle(getString(target.title!!)) }
|
||||
.also { if (target.badgeTypeId != null) it.withBadgeStyle(drawer.badgeStyle)}
|
||||
.withSelectedBackgroundAnimated(false)
|
||||
|
||||
if (target.badgeTypeId != null)
|
||||
drawer.addUnreadCounterType(target.badgeTypeId!!, target.id)
|
||||
@ -1018,12 +1088,11 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
fun setDrawerItems() {
|
||||
d("NavDebug", "setDrawerItems() app.profile = ${app.profile ?: "null"}")
|
||||
d("NavDebug", "setDrawerItems() app.profile = ${app.profile}")
|
||||
val drawerItems = arrayListOf<IDrawerItem<*>>()
|
||||
val drawerProfiles = arrayListOf<ProfileSettingDrawerItem>()
|
||||
|
||||
val supportedFragments = if (app.profile == null) arrayListOf<Int>()
|
||||
else app.profile.supportedFragments
|
||||
val supportedFragments = app.profile.supportedFragments
|
||||
|
||||
targetPopToHomeList.clear()
|
||||
|
||||
@ -1063,7 +1132,7 @@ class MainActivity : AppCompatActivity() {
|
||||
drawer.addProfileSettings(*drawerProfiles.toTypedArray())
|
||||
}
|
||||
|
||||
private fun showProfileContextMenu(profile: IProfile<*>, view: View) {
|
||||
private fun showProfileContextMenu(profile: IProfile, view: View) {
|
||||
val profileId = profile.identifier.toInt()
|
||||
val popupMenu = PopupMenu(this, view)
|
||||
popupMenu.menu.add(0, 1, 1, R.string.profile_menu_open_settings)
|
||||
@ -1076,7 +1145,7 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
loadTarget(DRAWER_ITEM_SETTINGS, null)
|
||||
} else if (item.itemId == 2) {
|
||||
ProfileRemoveDialog(this, profileId, profile.name?.getText(this)?.toString() ?: "?")
|
||||
ProfileRemoveDialog(this, profileId, profile.name?.getText(this) ?: "?")
|
||||
}
|
||||
true
|
||||
}
|
||||
@ -1087,7 +1156,8 @@ class MainActivity : AppCompatActivity() {
|
||||
private var targetHomeId: Int = -1
|
||||
override fun onBackPressed() {
|
||||
if (!b.navView.onBackPressed()) {
|
||||
if (App.getConfig().ui.openDrawerOnBackPressed) {
|
||||
if (App.config.ui.openDrawerOnBackPressed && ((navTarget.popTo == null && navTarget.popToHome)
|
||||
|| navTarget.id == DRAWER_ITEM_HOME)) {
|
||||
b.navView.drawer.toggle()
|
||||
} else {
|
||||
navigateUp()
|
||||
|
@ -1,350 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik;
|
||||
|
||||
import android.app.IntentService;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.receivers.BootReceiver;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
|
||||
import static androidx.core.app.NotificationCompat.PRIORITY_DEFAULT;
|
||||
import static androidx.core.app.NotificationCompat.PRIORITY_MAX;
|
||||
|
||||
public class Notifier {
|
||||
|
||||
private static final String TAG = "Notifier";
|
||||
public static final int ID_GET_DATA = 1337000;
|
||||
public static final int ID_GET_DATA_ERROR = 1337001;
|
||||
private static String CHANNEL_GET_DATA_NAME;
|
||||
private static String CHANNEL_GET_DATA_DESC;
|
||||
private static final String GROUP_KEY_GET_DATA = "pl.szczodrzynski.edziennik.GET_DATA";
|
||||
|
||||
public static final int ID_NOTIFICATIONS = 1337002;
|
||||
public static String CHANNEL_NOTIFICATIONS_NAME;
|
||||
public static String CHANNEL_NOTIFICATIONS_DESC;
|
||||
public static final String GROUP_KEY_NOTIFICATIONS = "pl.szczodrzynski.edziennik.NOTIFICATIONS";
|
||||
|
||||
public static final int ID_NOTIFICATIONS_QUIET = 1337002;
|
||||
public static String CHANNEL_NOTIFICATIONS_QUIET_NAME;
|
||||
public static String CHANNEL_NOTIFICATIONS_QUIET_DESC;
|
||||
public static final String GROUP_KEY_NOTIFICATIONS_QUIET = "pl.szczodrzynski.edziennik.NOTIFICATIONS_QUIET";
|
||||
|
||||
private static final int ID_UPDATES = 1337003;
|
||||
private static String CHANNEL_UPDATES_NAME;
|
||||
private static String CHANNEL_UPDATES_DESC;
|
||||
private static final String GROUP_KEY_UPDATES = "pl.szczodrzynski.edziennik.UPDATES";
|
||||
|
||||
private App app;
|
||||
public NotificationManager notificationManager;
|
||||
private NotificationCompat.Builder getDataNotificationBuilder;
|
||||
public int notificationColor;
|
||||
|
||||
Notifier(App _app) {
|
||||
this.app = _app;
|
||||
|
||||
CHANNEL_GET_DATA_NAME = app.getString(R.string.notification_channel_get_data_name);
|
||||
CHANNEL_GET_DATA_DESC = app.getString(R.string.notification_channel_get_data_desc);
|
||||
CHANNEL_NOTIFICATIONS_NAME = app.getString(R.string.notification_channel_notifications_name);
|
||||
CHANNEL_NOTIFICATIONS_DESC = app.getString(R.string.notification_channel_notifications_desc);
|
||||
CHANNEL_NOTIFICATIONS_QUIET_NAME = app.getString(R.string.notification_channel_notifications_quiet_name);
|
||||
CHANNEL_NOTIFICATIONS_QUIET_DESC = app.getString(R.string.notification_channel_notifications_quiet_desc);
|
||||
CHANNEL_UPDATES_NAME = app.getString(R.string.notification_channel_updates_name);
|
||||
CHANNEL_UPDATES_DESC = app.getString(R.string.notification_channel_updates_desc);
|
||||
|
||||
notificationColor = ContextCompat.getColor(app.getContext(), R.color.colorPrimary);
|
||||
notificationManager = (NotificationManager) app.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channelGetData = new NotificationChannel(GROUP_KEY_GET_DATA, CHANNEL_GET_DATA_NAME, NotificationManager.IMPORTANCE_MIN);
|
||||
channelGetData.setDescription(CHANNEL_GET_DATA_DESC);
|
||||
notificationManager.createNotificationChannel(channelGetData);
|
||||
|
||||
NotificationChannel channelNotifications = new NotificationChannel(GROUP_KEY_NOTIFICATIONS, CHANNEL_NOTIFICATIONS_NAME, NotificationManager.IMPORTANCE_HIGH);
|
||||
channelNotifications.setDescription(CHANNEL_NOTIFICATIONS_DESC);
|
||||
channelNotifications.enableLights(true);
|
||||
channelNotifications.setLightColor(notificationColor);
|
||||
notificationManager.createNotificationChannel(channelNotifications);
|
||||
|
||||
NotificationChannel channelNotificationsQuiet = new NotificationChannel(GROUP_KEY_NOTIFICATIONS_QUIET, CHANNEL_NOTIFICATIONS_QUIET_NAME, NotificationManager.IMPORTANCE_DEFAULT);
|
||||
channelNotificationsQuiet.setDescription(CHANNEL_NOTIFICATIONS_QUIET_DESC);
|
||||
channelNotificationsQuiet.setSound(null, null);
|
||||
channelNotificationsQuiet.enableVibration(false);
|
||||
notificationManager.createNotificationChannel(channelNotificationsQuiet);
|
||||
|
||||
NotificationChannel channelUpdates = new NotificationChannel(GROUP_KEY_UPDATES, CHANNEL_UPDATES_NAME, NotificationManager.IMPORTANCE_HIGH);
|
||||
channelUpdates.setDescription(CHANNEL_UPDATES_DESC);
|
||||
notificationManager.createNotificationChannel(channelUpdates);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldBeQuiet() {
|
||||
long now = Time.getNow().getInMillis();
|
||||
long start = app.config.getSync().getQuietHoursStart();
|
||||
long end = app.config.getSync().getQuietHoursEnd();
|
||||
if (start > end) {
|
||||
end += 1000 * 60 * 60 * 24;
|
||||
//Log.d(TAG, "Night passing");
|
||||
}
|
||||
if (start > now) {
|
||||
now += 1000 * 60 * 60 * 24;
|
||||
//Log.d(TAG, "Now is smaller");
|
||||
}
|
||||
//Log.d(TAG, "Start is "+start+", now is "+now+", end is "+end);
|
||||
return start > 0 && now >= start && now <= end;
|
||||
}
|
||||
|
||||
public int getNotificationDefaults() {
|
||||
return (shouldBeQuiet() ? 0 : Notification.DEFAULT_ALL);
|
||||
}
|
||||
public String getNotificationGroup() {
|
||||
return shouldBeQuiet() ? GROUP_KEY_NOTIFICATIONS_QUIET : GROUP_KEY_NOTIFICATIONS;
|
||||
}
|
||||
public int getNotificationPriority() {
|
||||
return shouldBeQuiet() ? PRIORITY_DEFAULT : PRIORITY_MAX;
|
||||
}
|
||||
|
||||
/* _____ _ _____ _
|
||||
| __ \ | | / ____| | |
|
||||
| | | | __ _| |_ __ _ | | __ ___| |_
|
||||
| | | |/ _` | __/ _` | | | |_ |/ _ \ __|
|
||||
| |__| | (_| | || (_| | | |__| | __/ |_
|
||||
|_____/ \__,_|\__\__,_| \_____|\___|\_*/
|
||||
public Notification notificationGetDataShow(int maxProgress) {
|
||||
/*Intent notificationIntent = new Intent(app.getContext(), SyncService.class);
|
||||
notificationIntent.setAction(ACTION_CANCEL);
|
||||
PendingIntent pendingIntent = PendingIntent.getService(app.getContext(), 0,
|
||||
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);*/
|
||||
|
||||
getDataNotificationBuilder = new NotificationCompat.Builder(app, GROUP_KEY_GET_DATA)
|
||||
.setSmallIcon(android.R.drawable.stat_sys_download)
|
||||
.setColor(notificationColor)
|
||||
.setContentTitle(app.getString(R.string.notification_get_data_title))
|
||||
.setContentText(app.getString(R.string.notification_get_data_text))
|
||||
//.addAction(R.drawable.ic_notification, app.getString(R.string.notification_get_data_cancel), pendingIntent)
|
||||
//.setGroup(GROUP_KEY_GET_DATA)
|
||||
.setOngoing(true)
|
||||
.setProgress(maxProgress, 0, false)
|
||||
.setTicker(app.getString(R.string.notification_get_data_summary))
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW);
|
||||
return getDataNotificationBuilder.build();
|
||||
}
|
||||
|
||||
public Notification notificationGetDataProgress(int progress, int maxProgress) {
|
||||
getDataNotificationBuilder.setProgress(maxProgress, progress, false);
|
||||
return getDataNotificationBuilder.build();
|
||||
}
|
||||
|
||||
public Notification notificationGetDataAction(int stringResId) {
|
||||
getDataNotificationBuilder.setContentTitle(app.getString(R.string.sync_action_format, app.getString(stringResId)));
|
||||
return getDataNotificationBuilder.build();
|
||||
}
|
||||
|
||||
public Notification notificationGetDataProfile(String profileName) {
|
||||
getDataNotificationBuilder.setContentText(profileName);
|
||||
return getDataNotificationBuilder.build();
|
||||
}
|
||||
|
||||
public Notification notificationGetDataError(String profileName, String error, int failedProfileId) {
|
||||
Intent notificationIntent = new Intent(app.getContext(), Notifier.GetDataRetryService.class);
|
||||
notificationIntent.putExtra("failedProfileId", failedProfileId);
|
||||
PendingIntent pendingIntent = PendingIntent.getService(app.getContext(), 0,
|
||||
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
|
||||
getDataNotificationBuilder.mActions.clear();
|
||||
/*try {
|
||||
//Use reflection clean up old actions
|
||||
Field f = getDataNotificationBuilder.getClass().getDeclaredField("mActions");
|
||||
f.setAccessible(true);
|
||||
f.set(getDataNotificationBuilder, new ArrayList<NotificationCompat.Action>());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}*/
|
||||
|
||||
getDataNotificationBuilder.setProgress(0, 0, false)
|
||||
.setTicker(app.getString(R.string.notification_get_data_error_summary))
|
||||
.setSmallIcon(android.R.drawable.stat_sys_warning)
|
||||
.addAction(R.drawable.ic_notification, app.getString(R.string.notification_get_data_once_again), pendingIntent)
|
||||
.setContentTitle(app.getString(R.string.notification_get_data_error_title, profileName))
|
||||
.setContentText(error)
|
||||
.setStyle(new NotificationCompat.BigTextStyle().bigText(error))
|
||||
.setOngoing(false);
|
||||
return getDataNotificationBuilder.build();
|
||||
}
|
||||
|
||||
public void notificationPost(int id, Notification notification) {
|
||||
notificationManager.notify(id, notification);
|
||||
}
|
||||
|
||||
public void notificationCancel(int id) {
|
||||
notificationManager.cancel(id);
|
||||
}
|
||||
|
||||
//public void notificationGetDataHide() {
|
||||
// notificationManager.cancel(ID_GET_DATA);
|
||||
// }
|
||||
|
||||
public static class GetDataRetryService extends IntentService {
|
||||
private static final String TAG = "Notifier/GetDataRetry";
|
||||
|
||||
public GetDataRetryService() {
|
||||
super(Notifier.GetDataRetryService.class.getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* _ _ _ _ __ _ _ _
|
||||
| \ | | | | (_)/ _(_) | | (_)
|
||||
| \| | ___ | |_ _| |_ _ ___ __ _| |_ _ ___ _ __
|
||||
| . ` |/ _ \| __| | _| |/ __/ _` | __| |/ _ \| '_ \
|
||||
| |\ | (_) | |_| | | | | (_| (_| | |_| | (_) | | | |
|
||||
|_| \_|\___/ \__|_|_| |_|\___\__,_|\__|_|\___/|_| |*/
|
||||
public void add(pl.szczodrzynski.edziennik.utils.models.Notification notification) {
|
||||
app.appConfig.notifications.add(notification);
|
||||
}
|
||||
|
||||
public void postAll() {
|
||||
Collections.sort(app.appConfig.notifications, (o1, o2) -> (o2.addedDate - o1.addedDate > 0) ? 1 : (o2.addedDate - o1.addedDate < 0) ? -1 : 0);
|
||||
|
||||
if (app.appConfig.notifications.size() > 40) {
|
||||
app.appConfig.notifications.subList(40, app.appConfig.notifications.size() - 1).clear();
|
||||
}
|
||||
|
||||
int unreadCount = 0;
|
||||
List<pl.szczodrzynski.edziennik.utils.models.Notification> notificationList = new ArrayList<>();
|
||||
for (pl.szczodrzynski.edziennik.utils.models.Notification notification: app.appConfig.notifications) {
|
||||
if (!notification.notified) {
|
||||
notification.seen = false;
|
||||
notification.notified = true;
|
||||
unreadCount++;
|
||||
if (notificationList.size() < 10) {
|
||||
notificationList.add(notification);
|
||||
}
|
||||
}
|
||||
else {
|
||||
notification.seen = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (pl.szczodrzynski.edziennik.utils.models.Notification notification: notificationList) {
|
||||
Intent intent = new Intent(app, MainActivity.class);
|
||||
notification.fillIntent(intent);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(app, notification.id, intent, 0);
|
||||
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(app, getNotificationGroup())
|
||||
// title, text, type, date
|
||||
.setContentTitle(notification.title)
|
||||
.setContentText(notification.text)
|
||||
.setSubText(pl.szczodrzynski.edziennik.utils.models.Notification.stringType(app, notification.type))
|
||||
.setWhen(notification.addedDate)
|
||||
.setTicker(app.getString(R.string.notification_ticker_format, pl.szczodrzynski.edziennik.utils.models.Notification.stringType(app, notification.type)))
|
||||
// icon, color, lights, priority
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setColor(notificationColor)
|
||||
.setLights(0xFF00FFFF, 2000, 2000)
|
||||
.setPriority(getNotificationPriority())
|
||||
// channel, group, style
|
||||
.setChannelId(getNotificationGroup())
|
||||
.setGroup(getNotificationGroup())
|
||||
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY)
|
||||
.setStyle(new NotificationCompat.BigTextStyle().bigText(notification.text))
|
||||
// intent, auto cancel
|
||||
.setContentIntent(pendingIntent)
|
||||
.setAutoCancel(true);
|
||||
if (!shouldBeQuiet()) {
|
||||
notificationBuilder.setDefaults(getNotificationDefaults());
|
||||
}
|
||||
notificationManager.notify(notification.id, notificationBuilder.build());
|
||||
}
|
||||
|
||||
if (notificationList.size() > 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
Intent intent = new Intent(app, MainActivity.class);
|
||||
intent.setAction("android.intent.action.MAIN");
|
||||
intent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_NOTIFICATIONS);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(app, ID_NOTIFICATIONS,
|
||||
intent, 0);
|
||||
|
||||
NotificationCompat.Builder groupBuilder =
|
||||
new NotificationCompat.Builder(app, getNotificationGroup())
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setColor(notificationColor)
|
||||
.setContentTitle(app.getString(R.string.notification_new_notification_title_format, unreadCount))
|
||||
.setGroupSummary(true)
|
||||
.setAutoCancel(true)
|
||||
.setChannelId(getNotificationGroup())
|
||||
.setGroup(getNotificationGroup())
|
||||
.setLights(0xFF00FFFF, 2000, 2000)
|
||||
.setPriority(getNotificationPriority())
|
||||
.setContentIntent(pendingIntent)
|
||||
.setStyle(new NotificationCompat.BigTextStyle());
|
||||
if (!shouldBeQuiet()) {
|
||||
groupBuilder.setDefaults(getNotificationDefaults());
|
||||
}
|
||||
notificationManager.notify(ID_NOTIFICATIONS, groupBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
/* _ _ _ _
|
||||
| | | | | | | |
|
||||
| | | |_ __ __| | __ _| |_ ___ ___
|
||||
| | | | '_ \ / _` |/ _` | __/ _ \/ __|
|
||||
| |__| | |_) | (_| | (_| | || __/\__ \
|
||||
\____/| .__/ \__,_|\__,_|\__\___||___/
|
||||
| |
|
||||
|*/
|
||||
public void notificationUpdatesShow(String updateVersion, String updateUrl, String updateFilename, boolean updateDirect) {
|
||||
if (!app.config.getSync().getNotifyAboutUpdates())
|
||||
return;
|
||||
Intent notificationIntent = new Intent(app.getContext(), BootReceiver.NotificationActionService.class)
|
||||
.putExtra("update_version", updateVersion)
|
||||
.putExtra("update_url", updateUrl)
|
||||
.putExtra("update_filename", updateFilename)
|
||||
.putExtra("update_direct", updateDirect);
|
||||
|
||||
PendingIntent pendingIntent = PendingIntent.getService(app.getContext(), 0,
|
||||
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
|
||||
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(app, GROUP_KEY_UPDATES)
|
||||
.setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
.setColor(notificationColor)
|
||||
.setContentTitle(app.getString(R.string.notification_updates_title))
|
||||
.setContentText(app.getString(R.string.notification_updates_text, updateVersion))
|
||||
.setLights(0xFF00FFFF, 2000, 2000)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setTicker(app.getString(R.string.notification_updates_summary))
|
||||
.setPriority(PRIORITY_MAX)
|
||||
.setAutoCancel(true);
|
||||
if (!shouldBeQuiet()) {
|
||||
notificationBuilder.setDefaults(getNotificationDefaults());
|
||||
}
|
||||
notificationManager.notify(ID_UPDATES, notificationBuilder.build());
|
||||
}
|
||||
|
||||
public void notificationUpdatesHide() {
|
||||
if (!app.config.getSync().getNotifyAboutUpdates())
|
||||
return;
|
||||
notificationManager.cancel(ID_UPDATES);
|
||||
}
|
||||
|
||||
public void dump() {
|
||||
for (pl.szczodrzynski.edziennik.utils.models.Notification notification: app.appConfig.notifications) {
|
||||
Log.d(TAG, "Profile"+notification.profileId+" Notification from "+ Date.fromMillis(notification.addedDate).getFormattedString()+" "+ Time.fromMillis(notification.addedDate).getStringHMS()+" - "+notification.text);
|
||||
}
|
||||
}
|
||||
}
|
@ -16,12 +16,13 @@ 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
|
||||
|
||||
class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
|
||||
companion object {
|
||||
const val DATA_VERSION = 2
|
||||
const val DATA_VERSION = 12
|
||||
}
|
||||
|
||||
private val job = Job()
|
||||
@ -45,6 +46,20 @@ class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
|
||||
get() { mHash = mHash ?: values.get("hash", ""); return mHash ?: "" }
|
||||
set(value) { set("hash", value); mHash = value }
|
||||
|
||||
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 }
|
||||
|
||||
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 }
|
||||
|
||||
private var mAppVersion: Int? = null
|
||||
var appVersion: Int
|
||||
get() { mAppVersion = mAppVersion ?: values.get("appVersion", BuildConfig.VERSION_CODE); return mAppVersion ?: BuildConfig.VERSION_CODE }
|
||||
@ -60,6 +75,11 @@ class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
|
||||
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 }
|
||||
@ -110,4 +130,4 @@ class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
|
||||
db.configDao().add(ConfigEntry(-1, key, value))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,17 +6,11 @@ package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager
|
||||
|
||||
class ConfigGrades(private val config: Config) {
|
||||
companion object {
|
||||
const val ORDER_BY_DATE_DESC = 0
|
||||
const val ORDER_BY_SUBJECT_ASC = 1
|
||||
const val ORDER_BY_DATE_ASC = 2
|
||||
const val ORDER_BY_SUBJECT_DESC = 3
|
||||
}
|
||||
|
||||
private var mOrderBy: Int? = null
|
||||
var orderBy: Int
|
||||
get() { mOrderBy = mOrderBy ?: config.values.get("gradesOrderBy", 0); return mOrderBy ?: 0 }
|
||||
get() { mOrderBy = mOrderBy ?: config.values.get("gradesOrderBy", 0); return mOrderBy ?: GradesManager.ORDER_BY_DATE_DESC }
|
||||
set(value) { config.set("gradesOrderBy", value); mOrderBy = value }
|
||||
}
|
||||
}
|
||||
|
@ -7,13 +7,24 @@ package pl.szczodrzynski.edziennik.config
|
||||
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.utils.models.Time
|
||||
|
||||
class ConfigSync(private val config: Config) {
|
||||
private var mDontShowAppManagerDialog: Boolean? = null
|
||||
var dontShowAppManagerDialog: Boolean
|
||||
get() { mDontShowAppManagerDialog = mDontShowAppManagerDialog ?: config.values.get("dontShowAppManagerDialog", false); return mDontShowAppManagerDialog ?: false }
|
||||
set(value) { config.set("dontShowAppManagerDialog", value); mDontShowAppManagerDialog = value }
|
||||
|
||||
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 }
|
||||
|
||||
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 }
|
||||
|
||||
private var mSyncOnlyWifi: Boolean? = null
|
||||
var onlyWifi: Boolean
|
||||
get() { mSyncOnlyWifi = mSyncOnlyWifi ?: config.values.get("syncOnlyWifi", false); return mSyncOnlyWifi ?: notifyAboutUpdates }
|
||||
@ -29,20 +40,30 @@ class ConfigSync(private val config: Config) {
|
||||
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 mQuietHoursStart: Long? = null
|
||||
var quietHoursStart: Long
|
||||
get() { mQuietHoursStart = mQuietHoursStart ?: config.values.get("quietHoursStart", 0L); return mQuietHoursStart ?: 0L }
|
||||
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: Long? = null
|
||||
var quietHoursEnd: Long
|
||||
get() { mQuietHoursEnd = mQuietHoursEnd ?: config.values.get("quietHoursEnd", 0L); return mQuietHoursEnd ?: 0L }
|
||||
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
|
||||
@ -85,4 +106,4 @@ class ConfigSync(private val config: Config) {
|
||||
var tokenVulcanList: List<Int>
|
||||
get() { mTokenVulcanList = mTokenVulcanList ?: config.values.getIntList("tokenVulcanList", listOf()); return mTokenVulcanList ?: listOf() }
|
||||
set(value) { config.set("tokenVulcanList", value); mTokenVulcanList = value }
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ package pl.szczodrzynski.edziennik.config
|
||||
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.ui.modules.home.HomeCardModel
|
||||
|
||||
class ConfigUI(private val config: Config) {
|
||||
private var mTheme: Int? = null
|
||||
@ -45,16 +44,6 @@ class ConfigUI(private val config: Config) {
|
||||
get() { mOpenDrawerOnBackPressed = mOpenDrawerOnBackPressed ?: config.values.get("openDrawerOnBackPressed", false); return mOpenDrawerOnBackPressed ?: false }
|
||||
set(value) { config.set("openDrawerOnBackPressed", value); mOpenDrawerOnBackPressed = value }
|
||||
|
||||
private var mAgendaViewType: Int? = null
|
||||
var agendaViewType: Int
|
||||
get() { mAgendaViewType = mAgendaViewType ?: config.values.get("agendaViewType", 0); return mAgendaViewType ?: 0 }
|
||||
set(value) { config.set("agendaViewType", value); mAgendaViewType = 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 mSnowfall: Boolean? = null
|
||||
var snowfall: Boolean
|
||||
get() { mSnowfall = mSnowfall ?: config.values.get("snowfall", false); return mSnowfall ?: false }
|
||||
|
@ -9,6 +9,7 @@ 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
|
||||
@ -17,7 +18,7 @@ import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class ProfileConfig(val db: AppDb, val profileId: Int, rawEntries: List<ConfigEntry>) : CoroutineScope, AbstractConfig {
|
||||
companion object {
|
||||
const val DATA_VERSION = 1
|
||||
const val DATA_VERSION = 2
|
||||
}
|
||||
|
||||
private val job = Job()
|
||||
@ -27,8 +28,9 @@ class ProfileConfig(val db: AppDb, val profileId: Int, rawEntries: List<ConfigEn
|
||||
val values: HashMap<String, String?> = hashMapOf()
|
||||
|
||||
val grades by lazy { ProfileConfigGrades(this) }
|
||||
val ui by lazy { ProfileConfigUI(this) }
|
||||
val sync by lazy { ProfileConfigSync(this) }
|
||||
/*
|
||||
val sync by lazy { ConfigSync(this) }
|
||||
val timetable by lazy { ConfigTimetable(this) }
|
||||
val grades by lazy { ConfigGrades(this) }*/
|
||||
|
||||
@ -44,8 +46,8 @@ class ProfileConfig(val db: AppDb, val profileId: Int, rawEntries: List<ConfigEn
|
||||
|
||||
init {
|
||||
rawEntries.toHashMap(profileId, values)
|
||||
/*if (dataVersion < DATA_VERSION)
|
||||
ProfileConfigMigration(this)*/
|
||||
if (dataVersion < DATA_VERSION)
|
||||
ProfileConfigMigration(this)
|
||||
}
|
||||
|
||||
override fun set(key: String, value: String?) {
|
||||
@ -54,4 +56,4 @@ class ProfileConfig(val db: AppDb, val profileId: Int, rawEntries: List<ConfigEn
|
||||
db.configDao().add(ConfigEntry(profileId, key, value))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,10 @@
|
||||
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.data.db.entity.Profile.Companion.COLOR_MODE_WEIGHTED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.YEAR_ALL_GRADES
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.COLOR_MODE_WEIGHTED
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_ALL_GRADES
|
||||
|
||||
class ProfileConfigGrades(private val config: ProfileConfig) {
|
||||
private var mColorMode: Int? = null
|
||||
@ -20,8 +21,32 @@ class ProfileConfigGrades(private val config: ProfileConfig) {
|
||||
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 mCountZeroToAvg: Boolean? = null
|
||||
var countZeroToAvg: Boolean
|
||||
get() { mCountZeroToAvg = mCountZeroToAvg ?: config.values.get("countZeroToAvg", true); return mCountZeroToAvg ?: true }
|
||||
set(value) { config.set("countZeroToAvg", value); mCountZeroToAvg = 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 }
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-2-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
|
||||
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 }
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-19.
|
||||
*/
|
||||
|
||||
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.modules.home.HomeCardModel
|
||||
|
||||
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 }
|
||||
|
||||
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 }
|
||||
}
|
@ -22,4 +22,7 @@ interface ConfigDao {
|
||||
|
||||
@Query("SELECT * FROM config WHERE profileId = :profileId")
|
||||
fun getAllNow(profileId: Int): List<ConfigEntry>
|
||||
|
||||
@Query("DELETE FROM config WHERE profileId = :profileId")
|
||||
fun clear(profileId: Int)
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-19.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
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.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 { config.apply {
|
||||
val s = "app.appConfig"
|
||||
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() }
|
||||
}
|
||||
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
|
||||
appRateSnackbarTime = p.getString("$s.appRateSnackbarTime", null)?.toLongOrNull() ?: 0
|
||||
timetable.countInSeconds = p.getString("$s.countInSeconds", null)?.toBoolean() ?: false
|
||||
ui.headerBackground = p.getString("$s.headerBackground", null).fix()
|
||||
ui.appBackground = p.getString("$s.appBackground", null).fix()
|
||||
ui.language = p.getString("$s.language", null).fix()
|
||||
appVersion = p.getString("$s.lastAppVersion", null)?.toIntOrNull() ?: BuildConfig.VERSION_CODE
|
||||
appInstalledTime = p.getString("$s.appInstalledTime", null)?.toLongOrNull() ?: 0
|
||||
grades.orderBy = p.getString("$s.gradesOrderBy", null)?.toIntOrNull() ?: 0
|
||||
sync.quietDuringLessons = p.getString("$s.quietDuringLessons", null)?.toBoolean() ?: false
|
||||
ui.miniMenuVisible = p.getString("$s.miniDrawerVisible", null)?.toBoolean() ?: false
|
||||
loginFinished = p.getString("$s.loginFinished", null)?.toBoolean() ?: false
|
||||
sync.onlyWifi = p.getString("$s.registerSyncOnlyWifi", null)?.toBoolean() ?: false
|
||||
sync.notifyAboutUpdates = p.getString("$s.notifyAboutUpdates", null)?.toBoolean() ?: true
|
||||
timetable.bellSyncDiff = p.getString("$s.bellSyncDiff", null)?.let { Gson().fromJson(it, Time::class.java) }
|
||||
|
||||
val startMillis = p.getString("$s.quietHoursStart", null)?.toLongOrNull() ?: 0
|
||||
val endMillis = p.getString("$s.quietHoursEnd", null)?.toLongOrNull() ?: 0
|
||||
if (startMillis > 0) {
|
||||
try {
|
||||
sync.quietHoursStart = Time.fromMillis(abs(startMillis))
|
||||
sync.quietHoursEnd = Time.fromMillis(abs(endMillis))
|
||||
sync.quietHoursEnabled = true
|
||||
}
|
||||
catch (_: Exception) {}
|
||||
}
|
||||
else {
|
||||
sync.quietHoursEnabled = false
|
||||
sync.quietHoursStart = null
|
||||
sync.quietHoursEnd = null
|
||||
}
|
||||
|
||||
sync.tokenMobidziennikList = listOf()
|
||||
sync.tokenVulcanList = listOf()
|
||||
sync.tokenLibrusList = listOf()
|
||||
val tokens = p.getString("$s.fcmTokens", null)?.let { Gson().fromJson<Map<Int, Pair<String, List<Int>>>>(it, object: TypeToken<Map<Int, Pair<String, List<Int>>>>(){}.type) }
|
||||
tokens?.forEach {
|
||||
val token = it.value.first
|
||||
when (it.key) {
|
||||
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 }
|
||||
}
|
||||
}
|
@ -37,6 +37,9 @@ fun AbstractConfig.set(key: String, value: JsonElement?) {
|
||||
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) })
|
||||
}
|
||||
@ -74,6 +77,9 @@ fun HashMap<String, String?>.get(key: String, default: JsonObject?): JsonObject?
|
||||
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
|
||||
@ -88,10 +94,14 @@ fun HashMap<String, String?>.getLongList(key: String, default: List<Long>?): Lis
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,32 +5,34 @@
|
||||
package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
import android.content.Context
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.BuildConfig
|
||||
import pl.szczodrzynski.edziennik.HOUR
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
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.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
|
||||
|
||||
class ConfigMigration(app: App, config: Config) {
|
||||
init { config.apply {
|
||||
val p = app.getSharedPreferences("pl.szczodrzynski.edziennik_profiles", Context.MODE_PRIVATE)
|
||||
val s = "app.appConfig"
|
||||
|
||||
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.registerSyncEnabled", null)?.toIntOrNull() ?: 3600
|
||||
val oldButtons = p.getString("$s.miniDrawerButtonIds", null)?.let { str ->
|
||||
str.replace("[\\[\\]]*".toRegex(), "")
|
||||
.split(",\\s?".toRegex())
|
||||
.mapNotNull { it.toIntOrNull() }
|
||||
}
|
||||
ui.miniMenuButtons = oldButtons ?: listOf(
|
||||
val p = app.getSharedPreferences("pl.szczodrzynski.edziennik_profiles", Context.MODE_PRIVATE)
|
||||
if (p.contains("app.appConfig.appTheme")) {
|
||||
// migrate appConfig from app version 3.x and lower.
|
||||
// Updates dataVersion to level 2.
|
||||
AppConfigMigrationV3(p, config)
|
||||
}
|
||||
|
||||
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,
|
||||
@ -39,46 +41,70 @@ class ConfigMigration(app: App, config: Config) {
|
||||
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
|
||||
sync.quietHoursStart = p.getString("$s.quietHoursStart", null)?.toLongOrNull() ?: 0
|
||||
appRateSnackbarTime = p.getString("$s.appRateSnackbarTime", null)?.toLongOrNull() ?: 0
|
||||
sync.quietHoursEnd = p.getString("$s.quietHoursEnd", null)?.toLongOrNull() ?: 0
|
||||
timetable.countInSeconds = p.getString("$s.countInSeconds", null)?.toBoolean() ?: false
|
||||
ui.headerBackground = p.getString("$s.headerBackground", null).fix()
|
||||
ui.appBackground = p.getString("$s.appBackground", null).fix()
|
||||
ui.language = p.getString("$s.language", null).fix()
|
||||
appVersion = p.getString("$s.lastAppVersion", null)?.toIntOrNull() ?: BuildConfig.VERSION_CODE
|
||||
appInstalledTime = p.getString("$s.appInstalledTime", null)?.toLongOrNull() ?: 0
|
||||
grades.orderBy = p.getString("$s.gradesOrderBy", null)?.toIntOrNull() ?: 0
|
||||
sync.quietDuringLessons = p.getString("$s.quietDuringLessons", null)?.toBoolean() ?: false
|
||||
ui.miniMenuVisible = p.getString("$s.miniDrawerVisible", null)?.toBoolean() ?: false
|
||||
loginFinished = p.getString("$s.loginFinished", null)?.toBoolean() ?: false
|
||||
sync.onlyWifi = p.getString("$s.registerSyncOnlyWifi", null)?.toBoolean() ?: false
|
||||
sync.notifyAboutUpdates = p.getString("$s.notifyAboutUpdates", null)?.toBoolean() ?: true
|
||||
timetable.bellSyncDiff = p.getString("$s.bellSyncDiff", null)?.let { Gson().fromJson(it, Time::class.java) }
|
||||
|
||||
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.tokenVulcanList = listOf()
|
||||
sync.tokenLibrus = null
|
||||
sync.tokenLibrusList = listOf()
|
||||
val tokens = p.getString("$s.fcmTokens", null)?.let { Gson().fromJson<Map<Int, Pair<String, List<Int>>>>(it, object: TypeToken<Map<Int, Pair<String, List<Int>>>>(){}.type) }
|
||||
tokens?.forEach {
|
||||
val token = it.value.first
|
||||
when (it.key) {
|
||||
LOGIN_TYPE_MOBIDZIENNIK -> sync.tokenMobidziennik = token
|
||||
LOGIN_TYPE_VULCAN -> sync.tokenVulcan = token
|
||||
LOGIN_TYPE_LIBRUS -> sync.tokenLibrus = token
|
||||
}
|
||||
}
|
||||
sync.tokenVulcan = null
|
||||
sync.tokenVulcanList = listOf()
|
||||
timetable.bellSyncMultiplier = 0
|
||||
timetable.bellSyncDiff = null
|
||||
timetable.countInSeconds = false
|
||||
grades.orderBy = ORDER_BY_DATE_DESC
|
||||
|
||||
dataVersion = 2
|
||||
}
|
||||
}}
|
||||
|
||||
private fun String?.fix(): String? {
|
||||
return this?.replace("\"", "")?.let { if (it == "null") null else it }
|
||||
}
|
||||
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.get("quietHoursStart", 0L)
|
||||
val endMillis = config.values.get("quietHoursEnd", 0L)
|
||||
if (startMillis > 0) {
|
||||
try {
|
||||
sync.quietHoursStart = Time.fromMillis(abs(startMillis))
|
||||
sync.quietHoursEnd = Time.fromMillis(abs(endMillis))
|
||||
sync.quietHoursEnabled = true
|
||||
}
|
||||
catch (_: Exception) {}
|
||||
}
|
||||
else {
|
||||
sync.quietHoursEnabled = false
|
||||
sync.quietHoursStart = null
|
||||
sync.quietHoursEnd = null
|
||||
}
|
||||
|
||||
dataVersion = 11
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
@ -4,23 +4,34 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
import android.content.Context
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.config.Config
|
||||
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.utils.managers.GradesManager.Companion.COLOR_MODE_WEIGHTED
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_ALL_GRADES
|
||||
|
||||
class ProfileConfigMigration(app: App, config: Config) {
|
||||
class ProfileConfigMigration(config: ProfileConfig) {
|
||||
init { config.apply {
|
||||
val p = app.getSharedPreferences("pl.szczodrzynski.edziennik_profiles", Context.MODE_PRIVATE)
|
||||
val s = "app.appConfig"
|
||||
|
||||
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
|
||||
dataVersion = 1
|
||||
}
|
||||
|
||||
if (dataVersion < 2) {
|
||||
//gradesColorMode do profilu !
|
||||
//agendaViewType do profilu !
|
||||
// app.appConfig.dontCountZeroToAverage do profilu !
|
||||
sync.notificationFilter = sync.notificationFilter + Notification.TYPE_TEACHER_ABSENCE
|
||||
|
||||
dataVersion = 2
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
@ -12,13 +12,17 @@ import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.events.*
|
||||
import pl.szczodrzynski.edziennik.data.api.events.requests.ServiceCloseRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.events.requests.TaskCancelRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.task.*
|
||||
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.toApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
@ -26,7 +30,7 @@ import kotlin.math.roundToInt
|
||||
class ApiService : Service() {
|
||||
companion object {
|
||||
const val TAG = "ApiService"
|
||||
const val NOTIFICATION_API_CHANNEL_ID = "pl.szczodrzynski.edziennik.GET_DATA"
|
||||
const val NOTIFICATION_API_CHANNEL_ID = "pl.szczodrzynski.edziennik.SYNC"
|
||||
fun start(context: Context) {
|
||||
context.startService(Intent(context, ApiService::class.java))
|
||||
}
|
||||
@ -34,35 +38,34 @@ class ApiService : Service() {
|
||||
context.startService(Intent(context, ApiService::class.java))
|
||||
EventBus.getDefault().postSticky(request)
|
||||
}
|
||||
|
||||
var lastEventTime = System.currentTimeMillis()
|
||||
var taskCancelTries = 0
|
||||
}
|
||||
|
||||
private val app by lazy { applicationContext as App }
|
||||
|
||||
private val syncingProfiles = mutableListOf<Profile>()
|
||||
|
||||
private val finishingTaskQueue = mutableListOf(
|
||||
SzkolnyTask.sync(syncingProfiles),
|
||||
NotifyTask()
|
||||
)
|
||||
private val allTaskList = mutableListOf<IApiTask>()
|
||||
private var szkolnyTaskFinished = false
|
||||
private val allTaskRequestList = mutableListOf<Any>()
|
||||
private val taskQueue = mutableListOf<IApiTask>()
|
||||
private val errorList = mutableListOf<ApiError>()
|
||||
|
||||
private var serviceClosed = false
|
||||
set(value) { field = value; notification.serviceClosed = value }
|
||||
private var taskCancelled = false
|
||||
private var taskIsRunning = false
|
||||
private var taskRunning: IApiTask? = null // for debug purposes
|
||||
private var taskRunningId = -1
|
||||
private var taskStartTime = 0L
|
||||
private var taskMaximumId = 0
|
||||
|
||||
private var taskProfileId = -1
|
||||
private var taskProgress = -1f
|
||||
private var taskProgressText: String? = null
|
||||
|
||||
private val notification by lazy { EdziennikNotification(this) }
|
||||
|
||||
private var lastEventTime = System.currentTimeMillis()
|
||||
private var taskCancelTries = 0
|
||||
private val notification by lazy { EdziennikNotification(app) }
|
||||
|
||||
/* ______ _ _ _ _ _____ _ _ _ _
|
||||
| ____| | | (_) (_) | / ____| | | | | | |
|
||||
@ -73,7 +76,7 @@ class ApiService : Service() {
|
||||
private val taskCallback = object : EdziennikCallback {
|
||||
override fun onCompleted() {
|
||||
lastEventTime = System.currentTimeMillis()
|
||||
d(TAG, "Task $taskRunningId (profile $taskProfileId) - $taskProgressText - finished")
|
||||
d(TAG, "Task $taskRunningId (profile $taskProfileId) finished in ${System.currentTimeMillis()-taskStartTime}")
|
||||
EventBus.getDefault().postSticky(ApiTaskFinishedEvent(taskProfileId))
|
||||
clearTask()
|
||||
|
||||
@ -85,9 +88,16 @@ class ApiService : Service() {
|
||||
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()
|
||||
notification.setCriticalError().post()
|
||||
@ -131,15 +141,20 @@ class ApiService : Service() {
|
||||
checkIfTaskFrozen()
|
||||
if (taskIsRunning)
|
||||
return
|
||||
if (taskCancelled || serviceClosed || (taskQueue.isEmpty() && finishingTaskQueue.isEmpty())) {
|
||||
serviceClosed = false
|
||||
if (taskCancelled || serviceClosed || (taskQueue.isEmpty() && szkolnyTaskFinished)) {
|
||||
allCompleted()
|
||||
return
|
||||
}
|
||||
|
||||
lastEventTime = System.currentTimeMillis()
|
||||
|
||||
val task = if (taskQueue.isEmpty()) finishingTaskQueue.removeAt(0) else taskQueue.removeAt(0)
|
||||
val task = if (taskQueue.isNotEmpty()) {
|
||||
taskQueue.removeAt(0)
|
||||
} else {
|
||||
szkolnyTaskFinished = true
|
||||
SzkolnyTask(app, syncingProfiles)
|
||||
}
|
||||
|
||||
task.taskId = ++taskMaximumId
|
||||
task.prepare(app)
|
||||
taskIsRunning = true
|
||||
@ -149,7 +164,7 @@ class ApiService : Service() {
|
||||
taskProgress = -1f
|
||||
taskProgressText = task.taskName
|
||||
|
||||
d(TAG, "Executing task $taskRunningId ($taskProgressText) - $task")
|
||||
d(TAG, "Executing task $taskRunningId - ${task::class.java.name}")
|
||||
|
||||
// update the notification
|
||||
notification.setCurrentTask(taskRunningId, taskProgressText).post()
|
||||
@ -159,15 +174,15 @@ class ApiService : Service() {
|
||||
|
||||
task.profile?.let { syncingProfiles.add(it) }
|
||||
|
||||
taskStartTime = System.currentTimeMillis()
|
||||
try {
|
||||
when (task) {
|
||||
is EdziennikTask -> task.run(app, taskCallback)
|
||||
is NotifyTask -> task.run(app, taskCallback)
|
||||
is ErrorReportTask -> task.run(app, taskCallback, notification, errorList)
|
||||
is SzkolnyTask -> task.run(app, taskCallback)
|
||||
is SzkolnyTask -> task.run(taskCallback)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
taskCallback.onError(ApiError(TAG, EXCEPTION_API_TASK).withThrowable(e))
|
||||
taskCallback.onError(e.toApiError(TAG))
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,6 +229,7 @@ class ApiService : Service() {
|
||||
}
|
||||
|
||||
private fun allCompleted() {
|
||||
serviceClosed = true
|
||||
EventBus.getDefault().postSticky(ApiTaskAllFinishedEvent())
|
||||
stopSelf()
|
||||
}
|
||||
@ -229,10 +245,12 @@ class ApiService : Service() {
|
||||
EventBus.getDefault().removeStickyEvent(task)
|
||||
d(TAG, task.toString())
|
||||
|
||||
// fix for duplicated tasks, thank you EventBus
|
||||
if (task in allTaskList)
|
||||
return
|
||||
allTaskList += task
|
||||
if (task is EdziennikTask) {
|
||||
// fix for duplicated tasks, thank you EventBus
|
||||
if (task.request in allTaskRequestList)
|
||||
return
|
||||
allTaskRequestList += task.request
|
||||
}
|
||||
|
||||
if (task is EdziennikTask) {
|
||||
when (task.request) {
|
||||
@ -293,11 +311,13 @@ class ApiService : Service() {
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
d(TAG, "Foreground service onStartCommand")
|
||||
startForeground(EdziennikNotification.NOTIFICATION_ID, notification.notification)
|
||||
startForeground(app.notificationChannelsManager.sync.id, notification.notification)
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
d(TAG, "Service destroyed")
|
||||
serviceClosed = true
|
||||
EventBus.getDefault().unregister(this)
|
||||
}
|
||||
|
||||
|
@ -22,9 +22,9 @@ const val FAKE_LIBRUS_TOKEN = "https://librus.szkolny.eu/access_token.php"
|
||||
const val FAKE_LIBRUS_ACCOUNT = "/synergia_accounts_fresh.php?login="
|
||||
const val FAKE_LIBRUS_ACCOUNTS = "/synergia_accounts.php"
|
||||
|
||||
val LIBRUS_USER_AGENT = "$SYSTEM_USER_AGENT LibrusMobileApp"
|
||||
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 = "wmSyUMo8llDAs4y9tJVYY92oyZ6h4lAt7KCuy0Gv"
|
||||
const val LIBRUS_CLIENT_ID = "6XPsKf10LPz1nxgHQLcvZ1KM48DYzlBAhxipaXY8"
|
||||
const val LIBRUS_REDIRECT_URL = "http://localhost/bar"
|
||||
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"
|
||||
@ -56,10 +56,13 @@ const val LIBRUS_SYNERGIA_TOKEN_LOGIN_URL = "https://synergia.librus.pl/loguj/to
|
||||
const val LIBRUS_MESSAGES_URL = "https://wiadomosci.librus.pl/module"
|
||||
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 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"
|
||||
@ -73,6 +76,8 @@ const val IDZIENNIK_WEB_GET_MESSAGE = "mod_komunikator/WS_wiadomosci.asmx/Pobier
|
||||
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"
|
||||
@ -106,5 +111,7 @@ const val VULCAN_API_ENDPOINT_MESSAGES_SENT = "mobile-api/Uczen.v3.Uczen/Wiadomo
|
||||
const val VULCAN_API_ENDPOINT_MESSAGES_CHANGE_STATUS = "mobile-api/Uczen.v3.Uczen/ZmienStatusWiadomosci"
|
||||
const val VULCAN_API_ENDPOINT_MESSAGES_ADD = "mobile-api/Uczen.v3.Uczen/DodajWiadomosc"
|
||||
const val VULCAN_API_ENDPOINT_PUSH = "mobile-api/Uczen.v3.Uczen/UstawPushToken"
|
||||
const val VULCAN_API_ENDPOINT_MESSAGES_ATTACHMENTS = "mobile-api/Uczen.v3.Uczen/WiadomosciZalacznik"
|
||||
const val VULCAN_API_ENDPOINT_HOMEWORK_ATTACHMENTS = "mobile-api/Uczen.v3.Uczen/ZadaniaDomoweZalacznik"
|
||||
|
||||
const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}"
|
||||
|
@ -1,209 +0,0 @@
|
||||
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.R
|
||||
import pl.szczodrzynski.edziennik.data.api.models.Data
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notice
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_LUCKY_NUMBER
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_ANNOUNCEMENT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_ATTENDANCE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_EVENT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_GRADE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_MESSAGE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_NOTICE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_TIMETABLE_LESSON_CHANGE
|
||||
import pl.szczodrzynski.edziennik.getNotificationTitle
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class DataNotifications(val data: Data) {
|
||||
companion object {
|
||||
private const val TAG = "DataNotifications"
|
||||
}
|
||||
|
||||
val app = data.app
|
||||
val profileId = data.profile?.id ?: -1
|
||||
val profileName = data.profile?.name ?: ""
|
||||
val profile = data.profile
|
||||
val loginStore = data.loginStore
|
||||
|
||||
init { run {
|
||||
if (profile == null) {
|
||||
return@run
|
||||
}
|
||||
|
||||
val today = Date.getToday()
|
||||
val todayValue = today.value
|
||||
|
||||
for (lesson in app.db.timetableDao().getNotNotifiedNow(profileId)) {
|
||||
val text = app.getString(R.string.notification_lesson_change_format, lesson.getDisplayChangeType(app), if (lesson.displayDate == null) "" else lesson.displayDate!!.formattedString, lesson.changeSubjectName)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_TIMETABLE_LESSON_CHANGE),
|
||||
text = text,
|
||||
type = TYPE_TIMETABLE_LESSON_CHANGE,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_TIMETABLE,
|
||||
addedDate = lesson.addedDate
|
||||
).addExtra("timetableDate", lesson.displayDate?.stringY_m_d ?: "")
|
||||
}
|
||||
|
||||
for (event in app.db.eventDao().getNotNotifiedNow(profileId)) {
|
||||
val text = if (event.type == Event.TYPE_HOMEWORK)
|
||||
app.getString(
|
||||
if (event.subjectLongName.isNullOrEmpty())
|
||||
R.string.notification_homework_no_subject_format
|
||||
else
|
||||
R.string.notification_homework_format,
|
||||
event.subjectLongName,
|
||||
event.eventDate.formattedString
|
||||
)
|
||||
else
|
||||
app.getString(
|
||||
if (event.subjectLongName.isNullOrEmpty())
|
||||
R.string.notification_event_no_subject_format
|
||||
else
|
||||
R.string.notification_event_format,
|
||||
event.typeName,
|
||||
event.eventDate.formattedString,
|
||||
event.subjectLongName
|
||||
)
|
||||
val type = if (event.type == Event.TYPE_HOMEWORK) TYPE_NEW_HOMEWORK else TYPE_NEW_EVENT
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(type),
|
||||
text = text,
|
||||
type = type,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = if (event.type == Event.TYPE_HOMEWORK) DRAWER_ITEM_HOMEWORK else DRAWER_ITEM_AGENDA,
|
||||
addedDate = event.addedDate
|
||||
).addExtra("eventId", event.id).addExtra("eventDate", event.eventDate.value.toLong())
|
||||
}
|
||||
|
||||
for (grade in app.db.gradeDao().getNotNotifiedNow(profileId)) {
|
||||
val gradeName = when (grade.type) {
|
||||
TYPE_SEMESTER1_PROPOSED, TYPE_SEMESTER2_PROPOSED -> app.getString(R.string.grade_semester_proposed_format_2, grade.name)
|
||||
TYPE_SEMESTER1_FINAL, TYPE_SEMESTER2_FINAL -> app.getString(R.string.grade_semester_final_format_2, grade.name)
|
||||
TYPE_YEAR_PROPOSED -> app.getString(R.string.grade_year_proposed_format_2, grade.name)
|
||||
TYPE_YEAR_FINAL -> app.getString(R.string.grade_year_final_format_2, grade.name)
|
||||
else -> grade.name
|
||||
}
|
||||
val text = app.getString(R.string.notification_grade_format, gradeName, grade.subjectLongName)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_NEW_GRADE),
|
||||
text = text,
|
||||
type = TYPE_NEW_GRADE,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_GRADES,
|
||||
addedDate = grade.addedDate
|
||||
).addExtra("gradeId", grade.id).addExtra("gradesSubjectId", grade.subjectId)
|
||||
}
|
||||
|
||||
for (notice in app.db.noticeDao().getNotNotifiedNow(profileId)) {
|
||||
val noticeTypeStr = if (notice.type == Notice.TYPE_POSITIVE) app.getString(R.string.notification_notice_praise) else if (notice.type == Notice.TYPE_NEGATIVE) app.getString(R.string.notification_notice_warning) else app.getString(R.string.notification_notice_new)
|
||||
val text = app.getString(R.string.notification_notice_format, noticeTypeStr, notice.teacherFullName, Date.fromMillis(notice.addedDate).formattedString)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_NEW_NOTICE),
|
||||
text = text,
|
||||
type = TYPE_NEW_NOTICE,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_BEHAVIOUR,
|
||||
addedDate = notice.addedDate
|
||||
).addExtra("noticeId", notice.id)
|
||||
}
|
||||
|
||||
for (attendance in app.db.attendanceDao().getNotNotifiedNow(profileId)) {
|
||||
var attendanceTypeStr = app.getString(R.string.notification_type_attendance)
|
||||
when (attendance.type) {
|
||||
Attendance.TYPE_ABSENT -> attendanceTypeStr = app.getString(R.string.notification_absence)
|
||||
Attendance.TYPE_ABSENT_EXCUSED -> attendanceTypeStr = app.getString(R.string.notification_absence_excused)
|
||||
Attendance.TYPE_BELATED -> attendanceTypeStr = app.getString(R.string.notification_belated)
|
||||
Attendance.TYPE_BELATED_EXCUSED -> attendanceTypeStr = app.getString(R.string.notification_belated_excused)
|
||||
Attendance.TYPE_RELEASED -> attendanceTypeStr = app.getString(R.string.notification_release)
|
||||
}
|
||||
val text = app.getString(
|
||||
if (attendance.subjectLongName.isNullOrEmpty())
|
||||
R.string.notification_attendance_no_lesson_format
|
||||
else
|
||||
R.string.notification_attendance_format,
|
||||
attendanceTypeStr,
|
||||
attendance.subjectLongName,
|
||||
attendance.lessonDate.formattedString
|
||||
)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_NEW_ATTENDANCE),
|
||||
text = text,
|
||||
type = TYPE_NEW_ATTENDANCE,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_ATTENDANCE,
|
||||
addedDate = attendance.addedDate
|
||||
).addExtra("attendanceId", attendance.id).addExtra("attendanceSubjectId", attendance.subjectId)
|
||||
}
|
||||
|
||||
for (announcement in app.db.announcementDao().getNotNotifiedNow(profileId)) {
|
||||
val text = app.context.getString(R.string.notification_announcement_format, announcement.subject)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_NEW_ANNOUNCEMENT),
|
||||
text = text,
|
||||
type = TYPE_NEW_ANNOUNCEMENT,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_ANNOUNCEMENTS,
|
||||
addedDate = announcement.addedDate
|
||||
).addExtra("announcementId", announcement.id)
|
||||
}
|
||||
|
||||
for (message in app.db.messageDao().getReceivedNotNotifiedNow(profileId)) {
|
||||
val text = app.context.getString(R.string.notification_message_format, message.senderFullName, message.subject)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_NEW_MESSAGE),
|
||||
text = text,
|
||||
type = TYPE_NEW_MESSAGE,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_MESSAGES,
|
||||
addedDate = message.addedDate
|
||||
).addExtra("messageType", Message.TYPE_RECEIVED.toLong()).addExtra("messageId", message.id)
|
||||
}
|
||||
|
||||
val luckyNumbers = app.db.luckyNumberDao().getNotNotifiedNow(profileId)
|
||||
luckyNumbers?.removeAll { it.date < today }
|
||||
luckyNumbers?.forEach { luckyNumber ->
|
||||
val text = when (luckyNumber.date.value) {
|
||||
todayValue -> // LN for today
|
||||
app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_format else R.string.notification_lucky_number_format, luckyNumber.number)
|
||||
todayValue + 1 -> // LN for tomorrow
|
||||
app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_tomorrow_format else R.string.notification_lucky_number_tomorrow_format, luckyNumber.number)
|
||||
else -> // LN for later
|
||||
app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_later_format else R.string.notification_lucky_number_later_format, luckyNumber.date.formattedString, luckyNumber.number)
|
||||
}
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_LUCKY_NUMBER),
|
||||
text = text,
|
||||
type = TYPE_LUCKY_NUMBER,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_HOME,
|
||||
addedDate = luckyNumber.addedDate
|
||||
)
|
||||
}
|
||||
|
||||
data.db.metadataDao().setAllNotified(profileId, true)
|
||||
}}
|
||||
}
|
@ -8,22 +8,20 @@ import android.app.Notification
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
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.receivers.SzkolnyReceiver
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
||||
class EdziennikNotification(val context: Context) {
|
||||
companion object {
|
||||
const val NOTIFICATION_ID = 20191001
|
||||
}
|
||||
|
||||
private val notificationManager by lazy { context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager }
|
||||
class EdziennikNotification(val app: App) {
|
||||
private val notificationManager by lazy { app.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager }
|
||||
|
||||
private val notificationBuilder: NotificationCompat.Builder by lazy {
|
||||
NotificationCompat.Builder(context, ApiService.NOTIFICATION_API_CHANNEL_ID)
|
||||
NotificationCompat.Builder(app, ApiService.NOTIFICATION_API_CHANNEL_ID)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setPriority(PRIORITY_MIN)
|
||||
.setOngoing(true)
|
||||
@ -35,39 +33,42 @@ class EdziennikNotification(val context: Context) {
|
||||
|
||||
private var errorCount = 0
|
||||
private var criticalErrorCount = 0
|
||||
var serviceClosed = false
|
||||
|
||||
private fun cancelPendingIntent(taskId: Int): PendingIntent {
|
||||
val intent = Intent("pl.szczodrzynski.edziennik.SZKOLNY_MAIN")
|
||||
intent.putExtra("task", "TaskCancelRequest")
|
||||
intent.putExtra("taskId", taskId)
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT) as PendingIntent
|
||||
val intent = SzkolnyReceiver.getIntent(app, Bundle(
|
||||
"task" to "TaskCancelRequest",
|
||||
"taskId" to taskId
|
||||
))
|
||||
return PendingIntent.getBroadcast(app, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) as PendingIntent
|
||||
}
|
||||
private val closePendingIntent: PendingIntent
|
||||
get() {
|
||||
val intent = Intent("pl.szczodrzynski.edziennik.SZKOLNY_MAIN")
|
||||
intent.putExtra("task", "ServiceCloseRequest")
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT) as PendingIntent
|
||||
val intent = SzkolnyReceiver.getIntent(app, Bundle(
|
||||
"task" to "ServiceCloseRequest"
|
||||
))
|
||||
return PendingIntent.getBroadcast(app, 0, intent, 0) as PendingIntent
|
||||
}
|
||||
|
||||
private fun errorCountText(): String? {
|
||||
var result = ""
|
||||
if (criticalErrorCount > 0) {
|
||||
result += context.resources.getQuantityString(R.plurals.critical_errors_format, criticalErrorCount, criticalErrorCount)
|
||||
result += app.resources.getQuantityString(R.plurals.critical_errors_format, criticalErrorCount, criticalErrorCount)
|
||||
}
|
||||
if (criticalErrorCount > 0 && errorCount > 0) {
|
||||
result += ", "
|
||||
}
|
||||
if (errorCount > 0) {
|
||||
result += context.resources.getQuantityString(R.plurals.normal_errors_format, errorCount, errorCount)
|
||||
result += app.resources.getQuantityString(R.plurals.normal_errors_format, errorCount, errorCount)
|
||||
}
|
||||
return if (result.isEmpty()) null else result
|
||||
}
|
||||
|
||||
fun setIdle(): EdziennikNotification {
|
||||
notificationBuilder.setContentTitle(context.getString(R.string.edziennik_notification_api_title))
|
||||
notificationBuilder.setContentTitle(app.getString(R.string.edziennik_notification_api_title))
|
||||
notificationBuilder.setProgress(0, 0, false)
|
||||
notificationBuilder.apply {
|
||||
val str = context.getString(R.string.edziennik_notification_api_text)
|
||||
val str = app.getString(R.string.edziennik_notification_api_text)
|
||||
setStyle(NotificationCompat.BigTextStyle().bigText(str))
|
||||
setContentText(str)
|
||||
}
|
||||
@ -81,7 +82,7 @@ class EdziennikNotification(val context: Context) {
|
||||
}
|
||||
fun setCriticalError(): EdziennikNotification {
|
||||
criticalErrorCount++
|
||||
notificationBuilder.setContentTitle(context.getString(R.string.edziennik_notification_api_error_title))
|
||||
notificationBuilder.setContentTitle(app.getString(R.string.edziennik_notification_api_error_title))
|
||||
notificationBuilder.setProgress(0, 0, false)
|
||||
notificationBuilder.apply {
|
||||
val str = errorCountText()
|
||||
@ -118,7 +119,7 @@ class EdziennikNotification(val context: Context) {
|
||||
notificationBuilder.addAction(
|
||||
NotificationCompat.Action(
|
||||
R.drawable.ic_notification,
|
||||
context.getString(R.string.edziennik_notification_api_close),
|
||||
app.getString(R.string.edziennik_notification_api_close),
|
||||
closePendingIntent
|
||||
))
|
||||
return this
|
||||
@ -128,13 +129,15 @@ class EdziennikNotification(val context: Context) {
|
||||
notificationBuilder.addAction(
|
||||
NotificationCompat.Action(
|
||||
R.drawable.ic_notification,
|
||||
context.getString(R.string.edziennik_notification_api_cancel),
|
||||
app.getString(R.string.edziennik_notification_api_cancel),
|
||||
cancelPendingIntent(taskId)
|
||||
))
|
||||
}
|
||||
|
||||
fun post() {
|
||||
notificationManager.notify(NOTIFICATION_ID, notification)
|
||||
if (serviceClosed)
|
||||
return
|
||||
notificationManager.notify(app.notificationChannelsManager.sync.id, notification)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ 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
|
||||
|
||||
fun Data.prepare(loginMethods: List<LoginMethod>, features: List<Feature>, featureIds: List<Int>, viewId: Int?) {
|
||||
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()
|
||||
@ -46,14 +46,19 @@ fun Data.prepare(loginMethods: List<LoginMethod>, features: List<Feature>, featu
|
||||
// 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 (timer.nextSync == SYNC_ALWAYS ||
|
||||
(viewId != null && timer.viewId == viewId) ||
|
||||
(timer.nextSync != SYNC_NEVER && timer.nextSync < timestamp)) {
|
||||
data.targetEndpointIds.add(endpoint.first)
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -76,8 +81,8 @@ fun Data.prepare(loginMethods: List<LoginMethod>, features: List<Feature>, featu
|
||||
data.targetLoginMethodIds = data.targetLoginMethodIds.toHashSet().toMutableList()
|
||||
data.targetLoginMethodIds.sort()
|
||||
|
||||
data.targetEndpointIds = data.targetEndpointIds.toHashSet().toMutableList()
|
||||
data.targetEndpointIds.sort()
|
||||
//data.targetEndpointIds = data.targetEndpointIds.toHashSet().toMutableList()
|
||||
//data.targetEndpointIds.sort()
|
||||
|
||||
progressCount = targetLoginMethodIds.size + targetEndpointIds.size
|
||||
progressStep = if (progressCount <= 0) 0f else 100f / progressCount.toFloat()
|
||||
@ -91,7 +96,6 @@ fun Data.prepareFor(loginMethods: List<LoginMethod>, loginMethodId: Int) {
|
||||
possibleLoginMethods += it.loginMethodId
|
||||
}
|
||||
|
||||
targetEndpointIds.clear()
|
||||
targetLoginMethodIds.clear()
|
||||
|
||||
// check the login method for any dependencies
|
||||
|
@ -32,6 +32,8 @@ const val CODE_LIBRUS_DISCONNECTED = 31
|
||||
const val CODE_PROFILE_ARCHIVED = 30*/
|
||||
|
||||
const val ERROR_APP_CRASH = 1
|
||||
const val ERROR_EXCEPTION = 2
|
||||
const val ERROR_API_EXCEPTION = 3
|
||||
const val ERROR_MESSAGE_NOT_SENT = 10
|
||||
|
||||
const val ERROR_REQUEST_FAILURE = 50
|
||||
@ -51,6 +53,7 @@ const val ERROR_REQUEST_FAILURE_SSL_ERROR = 63
|
||||
const val ERROR_RESPONSE_EMPTY = 100
|
||||
const val ERROR_LOGIN_DATA_MISSING = 101
|
||||
const val ERROR_PROFILE_MISSING = 105
|
||||
const val ERROR_PROFILE_ARCHIVED = 106
|
||||
const val ERROR_INVALID_LOGIN_MODE = 110
|
||||
const val ERROR_LOGIN_METHOD_NOT_SATISFIED = 111
|
||||
const val ERROR_NOT_IMPLEMENTED = 112
|
||||
@ -58,6 +61,9 @@ const val ERROR_FILE_DOWNLOAD = 113
|
||||
|
||||
const val ERROR_NO_STUDENTS_IN_ACCOUNT = 115
|
||||
|
||||
const val ERROR_CAPTCHA_NEEDED = 3000
|
||||
const val ERROR_CAPTCHA_LIBRUS_PORTAL = 3001
|
||||
|
||||
const val CODE_INTERNAL_LIBRUS_ACCOUNT_410 = 120
|
||||
const val CODE_INTERNAL_LIBRUS_SYNERGIA_EXPIRED = 121
|
||||
const val ERROR_LOGIN_LIBRUS_API_CAPTCHA_NEEDED = 124
|
||||
@ -115,6 +121,12 @@ const val ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN = 179
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN = 180
|
||||
const val ERROR_LIBRUS_API_MAINTENANCE = 181
|
||||
const val ERROR_LIBRUS_PORTAL_MAINTENANCE = 182
|
||||
const val ERROR_LIBRUS_API_NOTICEBOARD_PROBLEM = 183
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_CSRF_EXPIRED = 184
|
||||
const val ERROR_LIBRUS_API_DEVICE_REGISTERED = 185
|
||||
const val ERROR_LIBRUS_MESSAGES_NOT_FOUND = 186
|
||||
const val ERROR_LOGIN_LIBRUS_API_INVALID_REQUEST = 187
|
||||
const val ERROR_LIBRUS_MESSAGES_ATTACHMENT_NOT_FOUND = 188
|
||||
|
||||
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_LOGIN = 201
|
||||
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_OLD_PASSWORD = 202
|
||||
@ -129,6 +141,9 @@ const val ERROR_MOBIDZIENNIK_WEB_NO_SESSION_VALUE = 216
|
||||
const val ERROR_MOBIDZIENNIK_WEB_NO_SERVER_ID = 213
|
||||
const val ERROR_MOBIDZIENNIK_WEB_INVALID_RESPONSE = 214
|
||||
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_NO_SESSION_ID = 215
|
||||
const val ERROR_LOGIN_MOBIDZIENNIK_API2_INVALID_LOGIN = 216
|
||||
const val ERROR_LOGIN_MOBIDZIENNIK_API2_OTHER = 217
|
||||
const val ERROR_MOBIDZIENNIK_WEB_SERVER_PROBLEM = 218
|
||||
|
||||
const val ERROR_LOGIN_VULCAN_INVALID_SYMBOL = 301
|
||||
const val ERROR_LOGIN_VULCAN_INVALID_TOKEN = 302
|
||||
@ -143,6 +158,7 @@ const val ERROR_LOGIN_VULCAN_NO_PUPILS = 331
|
||||
const val ERROR_VULCAN_API_MAINTENANCE = 340
|
||||
const val ERROR_VULCAN_API_BAD_REQUEST = 341
|
||||
const val ERROR_VULCAN_API_OTHER = 342
|
||||
const val ERROR_VULCAN_ATTACHMENT_DOWNLOAD = 343
|
||||
|
||||
const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN = 401
|
||||
const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME = 402
|
||||
@ -192,5 +208,6 @@ const val EXCEPTION_IDZIENNIK_WEB_API_REQUEST = 913
|
||||
const val EXCEPTION_IDZIENNIK_API_REQUEST = 914
|
||||
const val EXCEPTION_EDUDZIENNIK_WEB_REQUEST = 920
|
||||
const val EXCEPTION_EDUDZIENNIK_FILE_REQUEST = 921
|
||||
const val ERROR_ONEDRIVE_DOWNLOAD = 930
|
||||
|
||||
const val LOGIN_NO_ARGUMENTS = 1201
|
||||
|
@ -13,8 +13,8 @@ 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.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_SENT
|
||||
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
|
||||
@ -41,6 +41,7 @@ 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,
|
||||
|
@ -11,6 +11,7 @@ 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.template.login.TemplateLoginApi
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginWeb
|
||||
@ -69,13 +70,13 @@ val librusLoginMethods = listOf(
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_SYNERGIA, LibrusLoginSynergia::class.java)
|
||||
.withIsPossible { _, loginStore -> !loginStore.hasLoginData("fakeLogin") }
|
||||
.withRequiredLoginMethod { profile, _ ->
|
||||
if (profile?.hasStudentData("accountPassword") == false) LOGIN_METHOD_LIBRUS_API else LOGIN_METHOD_NOT_NEEDED
|
||||
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) LOGIN_METHOD_LIBRUS_SYNERGIA else LOGIN_METHOD_NOT_NEEDED
|
||||
if (profile?.hasStudentData("accountPassword") == false || true) LOGIN_METHOD_LIBRUS_SYNERGIA else LOGIN_METHOD_NOT_NEEDED
|
||||
}
|
||||
)
|
||||
|
||||
@ -86,11 +87,11 @@ 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 }/*,
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED },
|
||||
|
||||
LoginMethod(LOGIN_TYPE_MOBIDZIENNIK, LOGIN_METHOD_MOBIDZIENNIK_API2, MobidziennikLoginApi2::class.java)
|
||||
.withIsPossible { _, loginStore -> loginStore.hasLoginData("email") }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }*/
|
||||
.withIsPossible { profile, _ -> profile?.getStudentData("email", null) != null }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
|
||||
)
|
||||
|
||||
const val LOGIN_TYPE_VULCAN = 4
|
||||
|
@ -5,6 +5,7 @@
|
||||
package pl.szczodrzynski.edziennik.data.api
|
||||
|
||||
import kotlin.text.RegexOption.DOT_MATCHES_ALL
|
||||
import kotlin.text.RegexOption.IGNORE_CASE
|
||||
|
||||
object Regexes {
|
||||
val STYLE_CSS_COLOR by lazy {
|
||||
@ -54,9 +55,49 @@ object Regexes {
|
||||
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()
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_MESSAGE_RECIPIENTS_JSON by lazy {
|
||||
"""odbiorcy: (\[.+?\]),${'$'}""".toRegex(RegexOption.MULTILINE)
|
||||
"""odbiorcy: (\[.+?]),${'$'}""".toRegex(RegexOption.MULTILINE)
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_ACCOUNT_EMAIL by lazy {
|
||||
"""name="email" value="(.+?@.+?\..+?)"""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
|
||||
val MOBIDZIENNIK_ATTENDANCE_TABLE by lazy {
|
||||
"""<table .+?id="obecnosci_tabela">(.+?)</table>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_ATTENDANCE_LESSON_COUNT by lazy {
|
||||
"""rel="([0-9-]{10})" colspan="([0-9]+)"""".toRegex()
|
||||
}
|
||||
val MOBIDZIENNIK_ATTENDANCE_ENTRIES by lazy {
|
||||
"""font-size:.+?class=".*?">(.*?)</td>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_ATTENDANCE_RANGE by lazy {
|
||||
"""<span>([0-9:]+) - .+? (.+?)</span></a>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_ATTENDANCE_LESSON by lazy {
|
||||
"""<strong>(.+?) - (.*?)</strong>.+?<small>.+?\((.+?), .+?(.+?)\)""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_HOMEWORK_ROW by lazy {
|
||||
"""class="rowRolling">(.+?</div>\s*</td>)""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_HOMEWORK_ITEM by lazy {
|
||||
"""<p><b>(.+?):</b>\s*(.+?)\s*</p>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_HOMEWORK_BODY by lazy {
|
||||
"""Treść:</b>(.+?)<p><b>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_HOMEWORK_ID by lazy {
|
||||
"""zadanieFormularz\(([0-9]+),""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_HOMEWORK_ATTACHMENT by lazy {
|
||||
"""zalacznik(_zadania)?=([0-9]+)'.+?word-break">(.+?)</td>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
|
||||
@ -74,7 +115,7 @@ object Regexes {
|
||||
"""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)
|
||||
"""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)
|
||||
@ -85,6 +126,13 @@ object Regexes {
|
||||
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()
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -95,7 +143,7 @@ object Regexes {
|
||||
|
||||
|
||||
val LIBRUS_ATTACHMENT_KEY by lazy {
|
||||
"""singleUseKey=([0-9A-f_]+)""".toRegex()
|
||||
"""singleUseKey=([0-9A-z_]+)""".toRegex()
|
||||
}
|
||||
|
||||
|
||||
@ -123,6 +171,9 @@ object Regexes {
|
||||
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()
|
||||
@ -168,4 +219,20 @@ object Regexes {
|
||||
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()
|
||||
}
|
||||
val LINKIFY_DATE_DMY by lazy {
|
||||
"""(?<![\d\-./])([1-2]\d|3[0-1]|0?\d)[\-./](1[0-2]|0?\d)(?:[\-./](1\d{3}|2?0?\d{2}))?(?![\d\-/])""".toRegex()
|
||||
}
|
||||
val LINKIFY_DATE_ABSOLUTE by lazy {
|
||||
"""([1-3][0-9]|[1-9])\s(sty|lut|mar|kwi|maj|cze|lip|sie|wrz|paź|lis|gru).*?\s(1[0-9]{3}|20[0-9]{2})?""".toRegex(IGNORE_CASE)
|
||||
}
|
||||
val LINKIFY_DATE_RELATIVE by lazy {
|
||||
"""za\s([0-9]+)?\s?(dni|dzień|tydzień|tygodnie)""".toRegex(IGNORE_CASE)
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,8 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.task
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-16.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
@ -12,11 +16,13 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.template.Template
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.Vulcan
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.task.IApiTask
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
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
|
||||
|
||||
open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTask(profileId) {
|
||||
companion object {
|
||||
@ -24,14 +30,15 @@ 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, viewIds: List<Pair<Int, Int>>? = null, arguments: JsonObject? = null) = EdziennikTask(profileId, SyncProfileRequest(viewIds, arguments))
|
||||
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: 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, message: Message, attachmentId: Long, attachmentName: String) = EdziennikTask(profileId, AttachmentGetRequest(message, attachmentId, attachmentName))
|
||||
fun attachmentGet(profileId: Int, owner: Any, attachmentId: Long, attachmentName: String) = EdziennikTask(profileId, AttachmentGetRequest(owner, attachmentId, attachmentName))
|
||||
fun recipientListGet(profileId: Int) = EdziennikTask(profileId, RecipientListGetRequest())
|
||||
fun eventGet(profileId: Int, event: EventFull) = EdziennikTask(profileId, EventGetRequest(event))
|
||||
}
|
||||
|
||||
private lateinit var loginStore: LoginStore
|
||||
@ -57,6 +64,10 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
||||
private var edziennikInterface: EdziennikInterface? = null
|
||||
|
||||
internal fun run(app: App, taskCallback: EdziennikCallback) {
|
||||
if (profile?.archived == true) {
|
||||
taskCallback.onError(ApiError(TAG, ERROR_PROFILE_ARCHIVED))
|
||||
return
|
||||
}
|
||||
edziennikInterface = when (loginStore.type) {
|
||||
LOGIN_TYPE_LIBRUS -> Librus(app, profile, loginStore, taskCallback)
|
||||
LOGIN_TYPE_MOBIDZIENNIK -> Mobidziennik(app, profile, loginStore, taskCallback)
|
||||
@ -75,14 +86,16 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
||||
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)
|
||||
is MessageSendRequest -> edziennikInterface?.sendMessage(request.recipients, request.subject, request.text)
|
||||
is FirstLoginRequest -> edziennikInterface?.firstLogin()
|
||||
is AnnouncementsReadRequest -> edziennikInterface?.markAllAnnouncementsAsRead()
|
||||
is AnnouncementGetRequest -> edziennikInterface?.getAnnouncement(request.announcement)
|
||||
is AttachmentGetRequest -> edziennikInterface?.getAttachment(request.message, request.attachmentId, request.attachmentName)
|
||||
is AttachmentGetRequest -> edziennikInterface?.getAttachment(request.owner, request.attachmentId, request.attachmentName)
|
||||
is RecipientListGetRequest -> edziennikInterface?.getRecipientList()
|
||||
is EventGetRequest -> edziennikInterface?.getEvent(request.event)
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,12 +109,13 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
||||
|
||||
data class FirstLoginRequest(val loginStore: LoginStore)
|
||||
class SyncRequest
|
||||
data class SyncProfileRequest(val viewIds: List<Pair<Int, Int>>? = null, val arguments: JsonObject? = null)
|
||||
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: List<Teacher>, val subject: String, val text: String)
|
||||
class AnnouncementsReadRequest
|
||||
data class AnnouncementGetRequest(val announcement: AnnouncementFull)
|
||||
data class AttachmentGetRequest(val message: Message, val attachmentId: Long, val attachmentName: String)
|
||||
data class AttachmentGetRequest(val owner: Any, val attachmentId: Long, val attachmentName: String)
|
||||
class RecipientListGetRequest
|
||||
data class EventGetRequest(val event: EventFull)
|
||||
}
|
@ -7,11 +7,7 @@ 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.EventType
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Subject
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.*
|
||||
|
||||
/**
|
||||
* Use http://patorjk.com/software/taag/#p=display&f=Big for the ascii art
|
||||
|
@ -9,18 +9,19 @@ 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.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
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 {
|
||||
@ -41,9 +42,7 @@ class Edudziennik(val app: App, val profile: Profile?, val loginStore: LoginStor
|
||||
|
||||
private fun completed() {
|
||||
data.saveData()
|
||||
data.notify {
|
||||
callback.onCompleted()
|
||||
}
|
||||
callback.onCompleted()
|
||||
}
|
||||
|
||||
/* _______ _ _ _ _ _
|
||||
@ -54,9 +53,9 @@ class Edudziennik(val app: App, val profile: Profile?, val loginStore: LoginStor
|
||||
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
||||
__/ |
|
||||
|__*/
|
||||
override fun sync(featureIds: List<Int>, viewId: Int?, arguments: JsonObject?) {
|
||||
override fun sync(featureIds: List<Int>, viewId: Int?, onlyEndpoints: List<Int>?, arguments: JsonObject?) {
|
||||
data.arguments = arguments
|
||||
data.prepare(edudziennikLoginMethods, EdudziennikFeatures, featureIds, viewId)
|
||||
data.prepare(edudziennikLoginMethods, EdudziennikFeatures, featureIds, viewId, onlyEndpoints)
|
||||
login()
|
||||
}
|
||||
|
||||
@ -96,13 +95,22 @@ class Edudziennik(val app: App, val profile: Profile?, val loginStore: LoginStor
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {}
|
||||
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()
|
||||
callback.onCompleted()
|
||||
}
|
||||
|
||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||
|
@ -27,60 +27,62 @@ class EdudziennikData(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
useEndpoint(data.targetEndpointIds.removeAt(0)) {
|
||||
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, onSuccess: () -> Unit) {
|
||||
Utils.d(TAG, "Using endpoint $endpointId")
|
||||
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, onSuccess)
|
||||
EdudziennikWebStart(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_TEACHERS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_teachers)
|
||||
EdudziennikWebTeachers(data, onSuccess)
|
||||
EdudziennikWebTeachers(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
||||
EdudziennikWebGrades(data, onSuccess)
|
||||
EdudziennikWebGrades(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
||||
EdudziennikWebTimetable(data, onSuccess)
|
||||
EdudziennikWebTimetable(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_EXAMS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_exams)
|
||||
EdudziennikWebExams(data, onSuccess)
|
||||
EdudziennikWebExams(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
||||
EdudziennikWebAttendance(data, onSuccess)
|
||||
EdudziennikWebAttendance(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_announcements)
|
||||
EdudziennikWebAnnouncements(data, onSuccess)
|
||||
EdudziennikWebAnnouncements(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
||||
EdudziennikWebHomework(data, onSuccess)
|
||||
EdudziennikWebHomework(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_EVENTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_events)
|
||||
EdudziennikWebEvents(data, onSuccess)
|
||||
EdudziennikWebEvents(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_NOTES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
||||
EdudziennikWebNotes(data, onSuccess)
|
||||
EdudziennikWebNotes(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
|
||||
EdudziennikWebLuckyNumber(data, onSuccess)
|
||||
EdudziennikWebLuckyNumber(data, lastSync, onSuccess)
|
||||
}
|
||||
else -> onSuccess()
|
||||
else -> onSuccess(endpointId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,13 +7,13 @@ 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 okhttp3.Cookie
|
||||
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 class EdudziennikWeb(open val data: DataEdudziennik, open val lastSync: Long?) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWeb"
|
||||
}
|
||||
@ -24,11 +24,11 @@ open class EdudziennikWeb(open val data: DataEdudziennik) {
|
||||
val profile
|
||||
get() = data.profile
|
||||
|
||||
fun webGet(tag: String, endpoint: String, xhr: Boolean = false, onSuccess: (text: String) -> Unit) {
|
||||
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")
|
||||
|
||||
@ -40,6 +40,18 @@ open class EdudziennikWeb(open val data: DataEdudziennik) {
|
||||
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) {
|
||||
@ -62,18 +74,7 @@ open class EdudziennikWeb(open val data: DataEdudziennik) {
|
||||
}
|
||||
}
|
||||
|
||||
data.app.cookieJar.saveFromResponse(null, listOf(
|
||||
Cookie.Builder()
|
||||
.name("sessionid")
|
||||
.value(data.webSessionId!!)
|
||||
.domain("dziennikel.appspot.com")
|
||||
.secure().httpOnly().build(),
|
||||
Cookie.Builder()
|
||||
.name("semester")
|
||||
.value((data.currentSemester).toString())
|
||||
.domain("dziennikel.appspot.com")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
data.app.cookieJar.set("dziennikel.appspot.com", "sessionid", data.webSessionId)
|
||||
|
||||
Request.builder()
|
||||
.url(url)
|
||||
|
@ -11,13 +11,15 @@ 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.SYNC_ALWAYS
|
||||
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,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebAnnouncements"
|
||||
}
|
||||
@ -66,7 +68,7 @@ class EdudziennikWebAnnouncements(override val data: DataEdudziennik,
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS)
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS) }
|
||||
}
|
||||
|
@ -11,22 +11,31 @@ 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.SYNC_ALWAYS
|
||||
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,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebAttendance"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
webGet(TAG, data.studentEndpoint + "Presence") { text ->
|
||||
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())
|
||||
@ -69,7 +78,7 @@ class EdudziennikWebAttendance(override val data: DataEdudziennik,
|
||||
id,
|
||||
lesson?.displayTeacherId ?: -1,
|
||||
lesson?.displaySubjectId ?: -1,
|
||||
data.currentSemester,
|
||||
profile.currentSemester,
|
||||
name,
|
||||
date,
|
||||
lesson?.displayStartTime ?: startTime,
|
||||
@ -77,18 +86,25 @@ class EdudziennikWebAttendance(override val data: DataEdudziennik,
|
||||
)
|
||||
|
||||
data.attendanceList.add(attendanceObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_ATTENDANCE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
if(type != Attendance.TYPE_PRESENT) {
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_ATTENDANCE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
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() }
|
||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE) }
|
||||
}
|
||||
|
@ -11,14 +11,16 @@ 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.SYNC_ALWAYS
|
||||
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,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebEvents"
|
||||
}
|
||||
@ -37,17 +39,16 @@ class EdudziennikWebEvents(override val data: DataEdudziennik,
|
||||
?: return@forEach
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
date,
|
||||
null,
|
||||
title,
|
||||
-1,
|
||||
Event.TYPE_CLASS_EVENT,
|
||||
false,
|
||||
-1,
|
||||
-1,
|
||||
data.teamClass?.id ?: -1
|
||||
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)
|
||||
@ -64,7 +65,7 @@ class EdudziennikWebEvents(override val data: DataEdudziennik,
|
||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_CLASS_EVENT))
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_EVENTS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_EVENTS)
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_EVENTS) }
|
||||
}
|
||||
|
@ -13,14 +13,16 @@ 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.SYNC_ALWAYS
|
||||
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,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebExams"
|
||||
}
|
||||
@ -54,17 +56,16 @@ class EdudziennikWebExams(override val data: DataEdudziennik,
|
||||
val eventType = data.getEventType(eventTypeId, eventTypeName)
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
date,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
eventType.id.toInt(),
|
||||
false,
|
||||
-1,
|
||||
subject.id,
|
||||
data.teamClass?.id ?: -1
|
||||
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)
|
||||
@ -84,7 +85,7 @@ class EdudziennikWebExams(override val data: DataEdudziennik,
|
||||
)))
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_EXAMS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_EXAMS)
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
@ -12,11 +12,10 @@ 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) {
|
||||
class EdudziennikWebGetAnnouncement(override val data: DataEdudziennik,
|
||||
private val announcement: AnnouncementFull,
|
||||
val onSuccess: () -> Unit
|
||||
) : EdudziennikWeb(data, null) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebGetAnnouncement"
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -13,24 +13,39 @@ 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.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade
|
||||
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,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebGrades"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
webGet(TAG, data.studentEndpoint + "start") { text ->
|
||||
val doc = Jsoup.parse(text)
|
||||
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 ->
|
||||
@ -80,7 +95,7 @@ class EdudziennikWebGrades(override val data: DataEdudziennik,
|
||||
val columnName = info.child(4).text().trim()
|
||||
val comment = info.ownText()
|
||||
|
||||
val description = columnName + if (comment.isNotBlank()) " - $comment" else ""
|
||||
val description = columnName + if (comment.isNotBlank()) " - $comment" else null
|
||||
|
||||
val teacherName = info.child(1).text()
|
||||
val teacher = data.getTeacherByLastFirst(teacherName)
|
||||
@ -99,20 +114,20 @@ class EdudziennikWebGrades(override val data: DataEdudziennik,
|
||||
} ?: -1
|
||||
|
||||
val gradeObject = Grade(
|
||||
profileId,
|
||||
id,
|
||||
fullName,
|
||||
color,
|
||||
description,
|
||||
name,
|
||||
value,
|
||||
if (gradeCountToAverage) weight else 0f,
|
||||
data.currentSemester,
|
||||
teacher.id,
|
||||
subject.id
|
||||
).apply {
|
||||
type = gradeType
|
||||
}
|
||||
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
|
||||
)
|
||||
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
@ -129,23 +144,23 @@ class EdudziennikWebGrades(override val data: DataEdudziennik,
|
||||
|
||||
if (proposed != null && proposed.isNotBlank()) {
|
||||
val proposedGradeObject = Grade(
|
||||
profileId,
|
||||
(-1 * subject.id) - 1,
|
||||
"",
|
||||
-1,
|
||||
"",
|
||||
proposed,
|
||||
proposed.toFloatOrNull() ?: 0f,
|
||||
0f,
|
||||
data.currentSemester,
|
||||
-1,
|
||||
subject.id
|
||||
).apply {
|
||||
type = when (semester) {
|
||||
1 -> TYPE_SEMESTER1_PROPOSED
|
||||
else -> TYPE_SEMESTER2_PROPOSED
|
||||
}
|
||||
}
|
||||
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(
|
||||
@ -162,23 +177,23 @@ class EdudziennikWebGrades(override val data: DataEdudziennik,
|
||||
|
||||
if (final != null && final.isNotBlank()) {
|
||||
val finalGradeObject = Grade(
|
||||
profileId,
|
||||
(-1 * subject.id) - 2,
|
||||
"",
|
||||
-1,
|
||||
"",
|
||||
final,
|
||||
final.toFloatOrNull() ?: 0f,
|
||||
0f,
|
||||
data.currentSemester,
|
||||
-1,
|
||||
subject.id
|
||||
).apply {
|
||||
type = when (semester) {
|
||||
1 -> TYPE_SEMESTER1_FINAL
|
||||
else -> TYPE_SEMESTER2_FINAL
|
||||
}
|
||||
}
|
||||
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(
|
||||
@ -201,12 +216,17 @@ class EdudziennikWebGrades(override val data: DataEdudziennik,
|
||||
TYPE_SEMESTER1_FINAL,
|
||||
TYPE_SEMESTER2_FINAL
|
||||
).map {
|
||||
DataRemoveModel.Grades.semesterWithType(data.currentSemester, it)
|
||||
DataRemoveModel.Grades.semesterWithType(semester, it)
|
||||
})
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_GRADES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
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) }
|
||||
}
|
||||
|
@ -12,14 +12,16 @@ 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.SYNC_ALWAYS
|
||||
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,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebHomework"
|
||||
}
|
||||
@ -31,8 +33,8 @@ class EdudziennikWebHomework(override val data: DataEdudziennik,
|
||||
if (doc.getElementsByClass("message").text().trim() != "Brak prac domowych") {
|
||||
doc.getElementsByTag("tr").forEach { homeworkElement ->
|
||||
val dateElement = homeworkElement.getElementsByClass("date").first().child(0)
|
||||
val id = EDUDZIENNIK_HOMEWORK_ID.find(dateElement.attr("href"))?.get(1)?.crc32()
|
||||
?: return@forEach
|
||||
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)
|
||||
@ -47,22 +49,23 @@ class EdudziennikWebHomework(override val data: DataEdudziennik,
|
||||
val teacherName = homeworkElement.child(2).text()
|
||||
val teacher = data.getTeacherByFirstLast(teacherName)
|
||||
|
||||
val topic = homeworkElement.child(4).text()
|
||||
val topic = homeworkElement.child(4).text()?.trim()
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
date,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
Event.TYPE_HOMEWORK,
|
||||
false,
|
||||
teacher.id,
|
||||
subject.id,
|
||||
data.teamClass?.id ?: -1
|
||||
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,
|
||||
@ -78,7 +81,7 @@ class EdudziennikWebHomework(override val data: DataEdudziennik,
|
||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK)
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK) }
|
||||
}
|
||||
|
@ -7,13 +7,15 @@ 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.SYNC_ALWAYS
|
||||
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,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebLuckyNumber"
|
||||
}
|
||||
@ -39,7 +41,7 @@ class EdudziennikWebLuckyNumber(override val data: DataEdudziennik,
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER)
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER) }
|
||||
}
|
||||
|
@ -10,14 +10,16 @@ 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.SYNC_ALWAYS
|
||||
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,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebNotes"
|
||||
}
|
||||
@ -42,7 +44,7 @@ class EdudziennikWebNotes(override val data: DataEdudziennik,
|
||||
profileId,
|
||||
id,
|
||||
description,
|
||||
data.currentSemester,
|
||||
profile.currentSemester,
|
||||
Notice.TYPE_NEUTRAL,
|
||||
teacher.id
|
||||
)
|
||||
@ -59,7 +61,7 @@ class EdudziennikWebNotes(override val data: DataEdudziennik,
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_NOTES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_NOTES)
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_NOTES) }
|
||||
}
|
||||
|
@ -18,7 +18,9 @@ import pl.szczodrzynski.edziennik.firstLettersName
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
|
||||
class EdudziennikWebStart(override val data: DataEdudziennik,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebStart"
|
||||
}
|
||||
@ -29,7 +31,7 @@ class EdudziennikWebStart(override val data: DataEdudziennik,
|
||||
getSubjects(text)
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_START, MONTH)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_START)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,9 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.Edudzienni
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
|
||||
class EdudziennikWebTeachers(override val data: DataEdudziennik,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebTeachers"
|
||||
}
|
||||
@ -26,7 +28,7 @@ class EdudziennikWebTeachers(override val data: DataEdudziennik,
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_TEACHERS, MONTH)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_TEACHERS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,10 +11,10 @@ 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.SYNC_ALWAYS
|
||||
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.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.singleOrNull
|
||||
@ -24,7 +24,9 @@ import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||
|
||||
class EdudziennikWebTimetable(override val data: DataEdudziennik,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : EdudziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebTimetable"
|
||||
}
|
||||
@ -142,7 +144,7 @@ class EdudziennikWebTimetable(override val data: DataEdudziennik,
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE)
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE) }
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ class EdudziennikFirstLogin(val data: DataEdudziennik, val onSuccess: () -> Unit
|
||||
private const val TAG = "EdudziennikFirstLogin"
|
||||
}
|
||||
|
||||
private val web = EdudziennikWeb(data)
|
||||
private val web = EdudziennikWeb(data, null)
|
||||
private val profileList = mutableListOf<Profile>()
|
||||
|
||||
init {
|
||||
|
@ -13,7 +13,6 @@ 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
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikLoginWeb(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
@ -25,7 +24,7 @@ class EdudziennikLoginWeb(val data: DataEdudziennik, val onSuccess: () -> Unit)
|
||||
onSuccess()
|
||||
}
|
||||
else {
|
||||
data.app.cookieJar.clearForDomain("dziennikel.appspot.com")
|
||||
data.app.cookieJar.clear("dziennikel.appspot.com")
|
||||
if (data.loginEmail.isNotNullNorEmpty() && data.loginPassword.isNotNullNorEmpty()) {
|
||||
loginWithCredentials()
|
||||
}
|
||||
@ -60,9 +59,8 @@ class EdudziennikLoginWeb(val data: DataEdudziennik, val onSuccess: () -> Unit)
|
||||
}
|
||||
}
|
||||
|
||||
val cookies = data.app.cookieJar.getForDomain("dziennikel.appspot.com")
|
||||
val sessionId = cookies.firstOrNull { it.name() == "sessionid" }?.value()
|
||||
val semester = cookies.firstOrNull { it.name() == "semester" }?.value()?.toIntOrNull()
|
||||
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)
|
||||
@ -72,14 +70,6 @@ class EdudziennikLoginWeb(val data: DataEdudziennik, val onSuccess: () -> Unit)
|
||||
}
|
||||
|
||||
data.webSessionId = sessionId
|
||||
|
||||
if (data.profile != null && semester != null) {
|
||||
data.currentSemester = semester
|
||||
|
||||
if (semester == 2 && data.profile.dateSemester2Start > Date.getToday())
|
||||
data.profile.dateSemester2Start = Date.getToday().stepForward(0, 0, -1)
|
||||
}
|
||||
|
||||
data.webSessionIdExpiryTime = response.getUnixDate() + 45 * 60 /* 45 min */
|
||||
onSuccess()
|
||||
}
|
||||
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-4-7.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.helper
|
||||
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.callback.FileCallbackHandler
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_ONEDRIVE_DOWNLOAD
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_REQUEST_FAILURE
|
||||
import pl.szczodrzynski.edziennik.data.api.SYSTEM_USER_AGENT
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import java.io.File
|
||||
|
||||
class OneDriveDownloadAttachment(
|
||||
app: App,
|
||||
fileUrl: String,
|
||||
val onSuccess: (file: File) -> Unit,
|
||||
val onProgress: (written: Long, total: Long) -> Unit,
|
||||
val onError: (apiError: ApiError) -> Unit
|
||||
) {
|
||||
companion object {
|
||||
private const val TAG = "OneDriveDownloadAttachment"
|
||||
}
|
||||
|
||||
init {
|
||||
Request.builder()
|
||||
.url(fileUrl)
|
||||
.userAgent(SYSTEM_USER_AGENT)
|
||||
.withClient(app.httpLazy)
|
||||
.callback(object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String, response: Response) {
|
||||
val location = response.headers().get("Location")
|
||||
// https://onedrive.live.com/redir?resid=D75496A2EB87531C!706&authkey=!ABjZeh3pHMqj11Q
|
||||
if (location?.contains("onedrive.live.com/redir?resid=") != true) {
|
||||
onError(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD)
|
||||
.withApiResponse(text)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
val url = location
|
||||
.replace("onedrive.live.com/redir?resid=", "storage.live.com/items/")
|
||||
.replace("?", "&")
|
||||
.replaceFirst("&", "?")
|
||||
downloadFile(url)
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response, throwable: Throwable) {
|
||||
onError(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
})
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
private fun downloadFile(url: String) {
|
||||
val targetFile = Utils.getStorageDir()
|
||||
|
||||
val callback = object : FileCallbackHandler(targetFile) {
|
||||
override fun onSuccess(file: File?, response: Response?) {
|
||||
if (file == null) {
|
||||
onError(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
onSuccess(file)
|
||||
} catch (e: Exception) {
|
||||
onError(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD)
|
||||
.withResponse(response)
|
||||
.withThrowable(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onProgress(bytesWritten: Long, bytesTotal: Long) {
|
||||
try {
|
||||
this@OneDriveDownloadAttachment.onProgress(bytesWritten, bytesTotal)
|
||||
} catch (e: Exception) {
|
||||
onError(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD)
|
||||
.withThrowable(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
onError(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url(url)
|
||||
.userAgent(SYSTEM_USER_AGENT)
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik
|
||||
|
||||
import androidx.core.util.set
|
||||
import okhttp3.Cookie
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_IDZIENNIK_API
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_IDZIENNIK_WEB
|
||||
@ -24,18 +23,8 @@ class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(
|
||||
loginMethods.clear()
|
||||
if (isWebLoginValid()) {
|
||||
loginMethods += LOGIN_METHOD_IDZIENNIK_WEB
|
||||
app.cookieJar.saveFromResponse(null, listOf(
|
||||
Cookie.Builder()
|
||||
.name("ASP.NET_SessionId_iDziennik")
|
||||
.value(webSessionId!!)
|
||||
.domain("iuczniowie.progman.pl")
|
||||
.secure().httpOnly().build(),
|
||||
Cookie.Builder()
|
||||
.name(".ASPXAUTH")
|
||||
.value(webAuth!!)
|
||||
.domain("iuczniowie.progman.pl")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
app.cookieJar.set("iuczniowie.progman.pl", "ASP.NET_SessionId_iDziennik", webSessionId)
|
||||
app.cookieJar.set("iuczniowie.progman.pl", ".ASPXAUTH", webAuth)
|
||||
}
|
||||
if (isApiLoginValid())
|
||||
loginMethods += LOGIN_METHOD_IDZIENNIK_API
|
||||
@ -81,6 +70,11 @@ class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(
|
||||
get() { mWebAuth = mWebAuth ?: loginStore.getLoginData("webAuth", null); return mWebAuth }
|
||||
set(value) { loginStore.putLoginData("webAuth", value); mWebAuth = value }
|
||||
|
||||
private var mWebSelectedRegister: Int? = null
|
||||
var webSelectedRegister: Int
|
||||
get() { mWebSelectedRegister = mWebSelectedRegister ?: loginStore.getLoginData("webSelectedRegister", 0); return mWebSelectedRegister ?: 0 }
|
||||
set(value) { loginStore.putLoginData("webSelectedRegister", value); mWebSelectedRegister = value }
|
||||
|
||||
/* _
|
||||
/\ (_)
|
||||
/ \ _ __ _
|
||||
|
@ -8,21 +8,16 @@ import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikData
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web.IdziennikWebGetAttachment
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web.IdziennikWebGetMessage
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web.IdziennikWebGetRecipientList
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web.IdziennikWebSendMessage
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.firstlogin.IdziennikFirstLogin
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.login.IdziennikLogin
|
||||
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.*
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
@ -43,9 +38,7 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
||||
|
||||
private fun completed() {
|
||||
data.saveData()
|
||||
data.notify {
|
||||
callback.onCompleted()
|
||||
}
|
||||
callback.onCompleted()
|
||||
}
|
||||
|
||||
/* _______ _ _ _ _ _
|
||||
@ -56,9 +49,9 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
||||
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
||||
__/ |
|
||||
|__*/
|
||||
override fun sync(featureIds: List<Int>, viewId: Int?, arguments: JsonObject?) {
|
||||
override fun sync(featureIds: List<Int>, viewId: Int?, onlyEndpoints: List<Int>?, arguments: JsonObject?) {
|
||||
data.arguments = arguments
|
||||
data.prepare(idziennikLoginMethods, IdziennikFeatures, featureIds, viewId)
|
||||
data.prepare(idziennikLoginMethods, IdziennikFeatures, featureIds, viewId, onlyEndpoints)
|
||||
login()
|
||||
}
|
||||
|
||||
@ -105,10 +98,17 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
||||
override fun markAllAnnouncementsAsRead() {}
|
||||
override fun getAnnouncement(announcement: AnnouncementFull) {}
|
||||
|
||||
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
|
||||
override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {
|
||||
login(LOGIN_METHOD_IDZIENNIK_WEB) {
|
||||
IdziennikWebGetAttachment(data, message, attachmentId, attachmentName) {
|
||||
completed()
|
||||
if (owner is Message) {
|
||||
IdziennikWebGetAttachment(data, owner, attachmentId, attachmentName) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
else if (owner is Event) {
|
||||
IdziennikWebGetHomeworkAttachment(data, owner, attachmentId, attachmentName) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -121,10 +121,19 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
||||
}
|
||||
}
|
||||
|
||||
override fun getEvent(eventFull: EventFull) {
|
||||
login(LOGIN_METHOD_IDZIENNIK_WEB) {
|
||||
IdziennikWebGetHomework(data, eventFull) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun firstLogin() { IdziennikFirstLogin(data) { completed() } }
|
||||
override fun cancel() {
|
||||
d(TAG, "Cancelled")
|
||||
data.cancel()
|
||||
callback.onCompleted()
|
||||
}
|
||||
|
||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||
|
@ -18,7 +18,7 @@ import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import java.net.HttpURLConnection
|
||||
|
||||
open class IdziennikApi(open val data: DataIdziennik) {
|
||||
open class IdziennikApi(open val data: DataIdziennik, open val lastSync: Long?) {
|
||||
companion object {
|
||||
const val TAG = "IdziennikApi"
|
||||
}
|
||||
|
@ -30,60 +30,62 @@ class IdziennikData(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
useEndpoint(data.targetEndpointIds.removeAt(0)) {
|
||||
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, onSuccess: () -> Unit) {
|
||||
Utils.d(TAG, "Using endpoint $endpointId")
|
||||
private fun useEndpoint(endpointId: Int, lastSync: Long?, onSuccess: (endpointId: Int) -> Unit) {
|
||||
Utils.d(TAG, "Using endpoint $endpointId. Last sync time = $lastSync")
|
||||
when (endpointId) {
|
||||
ENDPOINT_IDZIENNIK_WEB_TIMETABLE -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
||||
IdziennikWebTimetable(data, onSuccess)
|
||||
IdziennikWebTimetable(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_WEB_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
||||
IdziennikWebGrades(data, onSuccess)
|
||||
IdziennikWebGrades(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_proposed_grades)
|
||||
IdziennikWebProposedGrades(data, onSuccess)
|
||||
IdziennikWebProposedGrades(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_WEB_EXAMS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_exams)
|
||||
IdziennikWebExams(data, onSuccess)
|
||||
IdziennikWebExams(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_WEB_HOMEWORK -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
||||
IdziennikWebHomework(data, onSuccess)
|
||||
IdziennikWebHomework(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_WEB_NOTICES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
||||
IdziennikWebNotices(data, onSuccess)
|
||||
IdziennikWebNotices(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_announcements)
|
||||
IdziennikWebAnnouncements(data, onSuccess)
|
||||
IdziennikWebAnnouncements(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_WEB_ATTENDANCE -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
||||
IdziennikWebAttendance(data, onSuccess)
|
||||
IdziennikWebAttendance(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
|
||||
IdziennikApiCurrentRegister(data, onSuccess)
|
||||
IdziennikApiCurrentRegister(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
||||
IdziennikApiMessagesInbox(data, onSuccess)
|
||||
IdziennikApiMessagesInbox(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_API_MESSAGES_SENT -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
|
||||
IdziennikApiMessagesSent(data, onSuccess)
|
||||
IdziennikApiMessagesSent(data, lastSync, onSuccess)
|
||||
}
|
||||
else -> onSuccess()
|
||||
else -> onSuccess(endpointId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,13 +13,14 @@ import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web.IdziennikWebSwitchRegister
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.io.File
|
||||
import java.net.HttpURLConnection.HTTP_INTERNAL_ERROR
|
||||
import java.net.HttpURLConnection.HTTP_UNAUTHORIZED
|
||||
|
||||
open class IdziennikWeb(open val data: DataIdziennik) {
|
||||
open class IdziennikWeb(open val data: DataIdziennik, open val lastSync: Long?) {
|
||||
companion object {
|
||||
const val TAG = "IdziennikWeb"
|
||||
}
|
||||
@ -48,6 +49,17 @@ open class IdziennikWeb(open val data: DataIdziennik) {
|
||||
return
|
||||
}
|
||||
|
||||
if (response?.code() == HTTP_INTERNAL_ERROR && endpoint == IDZIENNIK_WEB_GRADES) {
|
||||
// special override for accounts where displaying grades
|
||||
// for another student requires switching it manually
|
||||
if (data.registerId != data.webSelectedRegister) {
|
||||
IdziennikWebSwitchRegister(data, data.registerId) {
|
||||
webApiGet(tag, endpoint, parameters, onSuccess)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
when {
|
||||
response?.code() == HTTP_UNAUTHORIZED -> ERROR_IDZIENNIK_WEB_ACCESS_DENIED
|
||||
response?.code() == HTTP_INTERNAL_ERROR -> ERROR_IDZIENNIK_WEB_SERVER_ERROR
|
||||
@ -115,7 +127,7 @@ open class IdziennikWeb(open val data: DataIdziennik) {
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
fun webGet(tag: String, endpoint: String, onSuccess: (text: String) -> Unit) {
|
||||
fun webGet(tag: String, endpoint: String, parameters: Map<String, Any> = emptyMap(), onSuccess: (text: String) -> Unit) {
|
||||
d(tag, "Request: Idziennik/Web - $IDZIENNIK_WEB_URL/$endpoint")
|
||||
|
||||
val callback = object : TextCallbackHandler() {
|
||||
@ -160,7 +172,14 @@ open class IdziennikWeb(open val data: DataIdziennik) {
|
||||
Request.builder()
|
||||
.url("$IDZIENNIK_WEB_URL/$endpoint")
|
||||
.userAgent(IDZIENNIK_USER_AGENT)
|
||||
.get()
|
||||
.apply {
|
||||
if (parameters.isEmpty()) get()
|
||||
else post()
|
||||
|
||||
parameters.map { (name, value) ->
|
||||
addParameter(name, value)
|
||||
}
|
||||
}
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
@ -210,6 +229,7 @@ open class IdziennikWeb(open val data: DataIdziennik) {
|
||||
.apply {
|
||||
parameters.forEach { (k, v) -> addParameter(k, v) }
|
||||
}
|
||||
.contentType("application/x-www-form-urlencoded")
|
||||
.post()
|
||||
.callback(callback)
|
||||
.build()
|
||||
|
@ -19,7 +19,9 @@ import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class IdziennikApiCurrentRegister(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikApi(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : IdziennikApi(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikApiCurrentRegister"
|
||||
}
|
||||
@ -27,7 +29,7 @@ class IdziennikApiCurrentRegister(override val data: DataIdziennik,
|
||||
init {
|
||||
apiGet(TAG, IDZIENNIK_API_CURRENT_REGISTER) { json ->
|
||||
if (json !is JsonObject) {
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER)
|
||||
return@apiGet
|
||||
}
|
||||
|
||||
@ -67,7 +69,7 @@ class IdziennikApiCurrentRegister(override val data: DataIdziennik,
|
||||
|
||||
val luckyNumberObject = LuckyNumber(
|
||||
data.profileId,
|
||||
Date.getToday(),
|
||||
luckyNumberDate,
|
||||
luckyNumber
|
||||
)
|
||||
|
||||
@ -85,7 +87,7 @@ class IdziennikApiCurrentRegister(override val data: DataIdziennik,
|
||||
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER, syncAt = nextSync)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,20 +10,18 @@ import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_API_MESSAGES_INBOX
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_DELETED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_DELETED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.getBoolean
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.crc32
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class IdziennikApiMessagesInbox(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikApi(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : IdziennikApi(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikApiMessagesInbox"
|
||||
}
|
||||
@ -31,15 +29,15 @@ class IdziennikApiMessagesInbox(override val data: DataIdziennik,
|
||||
init {
|
||||
apiGet(TAG, IDZIENNIK_API_MESSAGES_INBOX) { json ->
|
||||
if (json !is JsonArray) {
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX)
|
||||
return@apiGet
|
||||
}
|
||||
|
||||
json.asJsonObjectList()?.forEach { jMessage ->
|
||||
val subject = jMessage.getString("tytul")
|
||||
if (subject?.contains("(") == true && subject.startsWith("iDziennik - "))
|
||||
json.asJsonObjectList().forEach { jMessage ->
|
||||
val subject = jMessage.getString("tytul") ?: ""
|
||||
if (subject.contains("(") && subject.startsWith("iDziennik - "))
|
||||
return@forEach
|
||||
if (subject?.startsWith("Uwaga dla ucznia (klasa:") == true)
|
||||
if (subject.startsWith("Uwaga dla ucznia (klasa:"))
|
||||
return@forEach
|
||||
|
||||
val messageIdStr = jMessage.getString("id")
|
||||
@ -66,13 +64,12 @@ class IdziennikApiMessagesInbox(override val data: DataIdziennik,
|
||||
rTeacher.setTeacherType(Teacher.TYPE_OTHER)
|
||||
|
||||
val message = Message(
|
||||
profileId,
|
||||
messageId,
|
||||
subject,
|
||||
body,
|
||||
if (jMessage.getBoolean("rekordUsuniety") == true) TYPE_DELETED else TYPE_RECEIVED,
|
||||
rTeacher.id,
|
||||
-1
|
||||
profileId = profileId,
|
||||
id = messageId,
|
||||
type = if (jMessage.getBoolean("rekordUsuniety") == true) TYPE_DELETED else TYPE_RECEIVED,
|
||||
subject = subject,
|
||||
body = body,
|
||||
senderId = rTeacher.id
|
||||
)
|
||||
|
||||
val messageRecipient = MessageRecipient(
|
||||
@ -83,7 +80,7 @@ class IdziennikApiMessagesInbox(override val data: DataIdziennik,
|
||||
/*messageId*/ messageId
|
||||
)
|
||||
|
||||
data.messageIgnoreList.add(message)
|
||||
data.messageList.add(message)
|
||||
data.messageRecipientList.add(messageRecipient)
|
||||
data.setSeenMetadataList.add(Metadata(
|
||||
profileId,
|
||||
@ -96,7 +93,7 @@ class IdziennikApiMessagesInbox(override val data: DataIdziennik,
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,14 +13,16 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_SENT
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_SENT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.crc32
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class IdziennikApiMessagesSent(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikApi(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : IdziennikApi(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikApiMessagesSent"
|
||||
}
|
||||
@ -28,7 +30,7 @@ class IdziennikApiMessagesSent(override val data: DataIdziennik,
|
||||
init {
|
||||
apiGet(TAG, IDZIENNIK_API_MESSAGES_SENT) { json ->
|
||||
if (json !is JsonArray) {
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_IDZIENNIK_API_MESSAGES_SENT)
|
||||
return@apiGet
|
||||
}
|
||||
|
||||
@ -44,13 +46,12 @@ class IdziennikApiMessagesSent(override val data: DataIdziennik,
|
||||
val sentDate = Date.fromIso(jMessage.get("dataWyslania").asString)
|
||||
|
||||
val message = Message(
|
||||
profileId,
|
||||
messageId,
|
||||
subject,
|
||||
body,
|
||||
TYPE_SENT,
|
||||
-1,
|
||||
-1
|
||||
profileId = profileId,
|
||||
id = messageId,
|
||||
type = TYPE_SENT,
|
||||
subject = subject,
|
||||
body = body,
|
||||
senderId = null
|
||||
)
|
||||
|
||||
for (recipientEl in jMessage.getAsJsonArray("odbiorcy")) {
|
||||
@ -74,12 +75,12 @@ class IdziennikApiMessagesSent(override val data: DataIdziennik,
|
||||
data.messageRecipientIgnoreList.add(messageRecipient)
|
||||
}
|
||||
|
||||
data.messageIgnoreList.add(message)
|
||||
data.messageList.add(message)
|
||||
data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true, sentDate))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_API_MESSAGES_SENT, DAY, DRAWER_ITEM_MESSAGES)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_IDZIENNIK_API_MESSAGES_SENT)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,13 +13,17 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNI
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Announcement
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.getLong
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class IdziennikWebAnnouncements(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : IdziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebAnnouncements"
|
||||
}
|
||||
@ -41,11 +45,11 @@ class IdziennikWebAnnouncements(override val data: DataIdziennik,
|
||||
for (jAnnouncementEl in json.getAsJsonArray("ListK")) {
|
||||
val jAnnouncement = jAnnouncementEl.asJsonObject
|
||||
// jAnnouncement
|
||||
val announcementId = jAnnouncement.get("Id").asLong
|
||||
val announcementId = jAnnouncement.getLong("Id") ?: -1
|
||||
|
||||
val rTeacher = data.getTeacherByFirstLast(jAnnouncement.get("Autor").asString)
|
||||
val addedDate = java.lang.Long.parseLong(jAnnouncement.get("DataDodania").asString.replace("[^\\d]".toRegex(), ""))
|
||||
val startDate = Date.fromMillis(java.lang.Long.parseLong(jAnnouncement.get("DataWydarzenia").asString.replace("[^\\d]".toRegex(), "")))
|
||||
val rTeacher = data.getTeacherByFirstLast(jAnnouncement.getString("Autor") ?: "")
|
||||
val addedDate = jAnnouncement.getString("DataDodania")?.replace("[^\\d]".toRegex(), "")?.toLongOrNull() ?: System.currentTimeMillis()
|
||||
val startDate = jAnnouncement.getString("DataWydarzenia")?.replace("[^\\d]".toRegex(), "")?.toLongOrNull()?.let { Date.fromMillis(it) }
|
||||
|
||||
val announcementObject = Announcement(
|
||||
profileId,
|
||||
@ -69,7 +73,7 @@ class IdziennikWebAnnouncements(override val data: DataIdziennik,
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,25 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
||||
|
||||
import pl.szczodrzynski.edziennik.crc16
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_ATTENDANCE
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_ATTENDANCE
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.crc16
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance
|
||||
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.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class IdziennikWebAttendance(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : IdziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebAttendance"
|
||||
}
|
||||
@ -137,7 +139,7 @@ class IdziennikWebAttendance(override val data: DataIdziennik,
|
||||
getAttendance()
|
||||
} else {
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_ATTENDANCE, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_IDZIENNIK_WEB_ATTENDANCE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,13 +13,16 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNI
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
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.utils.models.Date
|
||||
import java.util.*
|
||||
|
||||
class IdziennikWebExams(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : IdziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebExams"
|
||||
}
|
||||
@ -63,28 +66,30 @@ class IdziennikWebExams(override val data: DataIdziennik,
|
||||
val subjectId = data.getSubject(subjectName, null, subjectName).id
|
||||
val teacherName = exam.getString("wpisal") ?: return@forEach
|
||||
val teacherId = data.getTeacherByLastFirst(teacherName).id
|
||||
val topic = exam.getString("zakres") ?: ""
|
||||
val topic = exam.getString("zakres")?.trim() ?: ""
|
||||
|
||||
val lessonList = data.db.timetableDao().getForDateNow(profileId, examDate)
|
||||
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime
|
||||
|
||||
val eventType = when (exam.getString("rodzaj")) {
|
||||
"sprawdzian/praca klasowa" -> Event.TYPE_EXAM
|
||||
else -> Event.TYPE_SHORT_QUIZ
|
||||
val eventType = when (exam.getString("rodzaj")?.toLowerCase(Locale.getDefault())) {
|
||||
"sprawdzian/praca klasowa",
|
||||
"sprawdzian",
|
||||
"praca klasowa" -> Event.TYPE_EXAM
|
||||
"kartkówka" -> Event.TYPE_SHORT_QUIZ
|
||||
else -> Event.TYPE_EXAM
|
||||
}
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
examDate,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
eventType,
|
||||
false,
|
||||
teacherId,
|
||||
subjectId,
|
||||
data.teamClass?.id ?: -1
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
date = examDate,
|
||||
time = startTime,
|
||||
topic = topic,
|
||||
color = null,
|
||||
type = eventType,
|
||||
teacherId = teacherId,
|
||||
subjectId = subjectId,
|
||||
teamId = data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
@ -116,7 +121,7 @@ class IdziennikWebExams(override val data: DataIdziennik,
|
||||
data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_EXAMS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_IDZIENNIK_WEB_EXAMS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,15 +14,19 @@ import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import java.io.File
|
||||
|
||||
class IdziennikWebGetAttachment(
|
||||
override val data: DataIdziennik, val message: Message, val attachmentId: Long,
|
||||
val attachmentName: String, val onSuccess: () -> Unit
|
||||
) : IdziennikWeb(data) {
|
||||
class IdziennikWebGetAttachment(override val data: DataIdziennik,
|
||||
val owner: Any,
|
||||
val attachmentId: Long,
|
||||
val attachmentName: String,
|
||||
val onSuccess: () -> Unit
|
||||
) : IdziennikWeb(data, null) {
|
||||
companion object {
|
||||
const val TAG = "IdziennikWebGetAttachment"
|
||||
}
|
||||
|
||||
init {
|
||||
val message = owner as Message
|
||||
|
||||
val messageId = "\\[META:([A-z0-9]+);([0-9-]+)]".toRegex().find(message.body ?: "")?.get(2) ?: -1
|
||||
val targetFile = File(Utils.getStorageDir(), attachmentName)
|
||||
|
||||
@ -32,29 +36,29 @@ class IdziennikWebGetAttachment(
|
||||
), { file ->
|
||||
val event = AttachmentGetEvent(
|
||||
profileId,
|
||||
message.id,
|
||||
owner,
|
||||
attachmentId,
|
||||
AttachmentGetEvent.TYPE_FINISHED,
|
||||
file.absolutePath
|
||||
)
|
||||
|
||||
val attachmentDataFile = File(Utils.getStorageDir(), ".${profileId}_${event.messageId}_${event.attachmentId}")
|
||||
val attachmentDataFile = File(Utils.getStorageDir(), ".${profileId}_${event.ownerId}_${event.attachmentId}")
|
||||
Utils.writeStringToFile(attachmentDataFile, event.fileName)
|
||||
|
||||
EventBus.getDefault().post(event)
|
||||
EventBus.getDefault().postSticky(event)
|
||||
|
||||
onSuccess()
|
||||
|
||||
}) { written, _ ->
|
||||
val event = AttachmentGetEvent(
|
||||
profileId,
|
||||
message.id,
|
||||
owner,
|
||||
attachmentId,
|
||||
AttachmentGetEvent.TYPE_PROGRESS,
|
||||
bytesWritten = written
|
||||
)
|
||||
|
||||
EventBus.getDefault().post(event)
|
||||
EventBus.getDefault().postSticky(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-4-1.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
||||
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_GET_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||
import pl.szczodrzynski.edziennik.getBoolean
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
|
||||
class IdziennikWebGetHomework(override val data: DataIdziennik,
|
||||
val event: EventFull,
|
||||
val onSuccess: () -> Unit
|
||||
) : IdziennikWeb(data, null) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebGetHomework"
|
||||
}
|
||||
|
||||
init {
|
||||
webApiGet(TAG, IDZIENNIK_WEB_GET_HOMEWORK, mapOf(
|
||||
"idP" to data.registerId,
|
||||
"idPD" to event.id
|
||||
)) { result ->
|
||||
val json = result.getJsonObject("d") ?: run {
|
||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
||||
.withApiResponse(result))
|
||||
return@webApiGet
|
||||
}
|
||||
|
||||
val homework = json.getJsonObject("praca") ?: return@webApiGet
|
||||
|
||||
if (homework.getBoolean("zalacznik", false)) {
|
||||
event.attachmentIds = mutableListOf(event.id)
|
||||
event.attachmentNames = mutableListOf("Załącznik do zadania")
|
||||
}
|
||||
else {
|
||||
event.attachmentIds = mutableListOf()
|
||||
event.attachmentNames = mutableListOf()
|
||||
}
|
||||
event.homeworkBody = homework.getString("tresc")
|
||||
|
||||
data.eventList.add(event)
|
||||
data.eventListReplace = true
|
||||
|
||||
EventBus.getDefault().postSticky(EventGetEvent(event))
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-4-1.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_GET_HOMEWORK_ATTACHMENT
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.set
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import java.io.File
|
||||
|
||||
class IdziennikWebGetHomeworkAttachment(override val data: DataIdziennik,
|
||||
val owner: Any,
|
||||
val attachmentId: Long,
|
||||
val attachmentName: String,
|
||||
val onSuccess: () -> Unit
|
||||
) : IdziennikWeb(data, null) {
|
||||
companion object {
|
||||
const val TAG = "IdziennikWebGetHomeworkAttachment"
|
||||
}
|
||||
|
||||
init {
|
||||
val homework = owner as Event
|
||||
|
||||
/*val request = Request.Builder()
|
||||
.url("")
|
||||
.build()
|
||||
data.app.http.newCall(request).enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||
.withThrowable(e))
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
val filename = response.header("content-disposition")?.substringAfter("\"")?.substringBeforeLast("\"")
|
||||
|
||||
val file: File = File(Utils.getStorageDir(), filename)
|
||||
val sink = file.sink().buffer()
|
||||
response.body()?.source()?.let {
|
||||
sink.writeAll(it)
|
||||
}
|
||||
sink.close()
|
||||
}
|
||||
})*/
|
||||
|
||||
webGet(TAG, IDZIENNIK_WEB_GET_HOMEWORK_ATTACHMENT) { text ->
|
||||
val hiddenFields = JsonObject()
|
||||
Regexes.IDZIENNIK_LOGIN_HIDDEN_FIELDS.findAll(text).forEach {
|
||||
hiddenFields[it[1]] = it[2]
|
||||
}
|
||||
|
||||
webGetFile(TAG, IDZIENNIK_WEB_GET_HOMEWORK_ATTACHMENT, Utils.getStorageDir(), mapOf(
|
||||
"__VIEWSTATE" to hiddenFields.getString("__VIEWSTATE", ""),
|
||||
"__VIEWSTATEGENERATOR" to hiddenFields.getString("__VIEWSTATEGENERATOR", ""),
|
||||
"__EVENTVALIDATION" to hiddenFields.getString("__EVENTVALIDATION", ""),
|
||||
"__EVENTTARGET" to "ctl00\$cphContent\$bt_pobraniePliku",
|
||||
"ctl00\$dxComboUczniowie" to data.registerId,
|
||||
"ctl00\$cphContent\$idPracyDomowej" to attachmentId
|
||||
), { file ->
|
||||
val event = AttachmentGetEvent(
|
||||
profileId,
|
||||
owner,
|
||||
attachmentId,
|
||||
AttachmentGetEvent.TYPE_FINISHED,
|
||||
file.absolutePath
|
||||
)
|
||||
|
||||
val attachmentDataFile = File(Utils.getStorageDir(), ".${profileId}_${event.ownerId}_${event.attachmentId}")
|
||||
Utils.writeStringToFile(attachmentDataFile, event.fileName)
|
||||
|
||||
homework.attachmentNames = mutableListOf(file.name)
|
||||
data.eventList.add(homework)
|
||||
data.eventListReplace = true
|
||||
|
||||
EventBus.getDefault().postSticky(event)
|
||||
onSuccess()
|
||||
|
||||
}) { written, _ ->
|
||||
val event = AttachmentGetEvent(
|
||||
profileId,
|
||||
owner,
|
||||
attachmentId,
|
||||
AttachmentGetEvent.TYPE_PROGRESS,
|
||||
bytesWritten = written
|
||||
)
|
||||
|
||||
EventBus.getDefault().postSticky(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,18 +10,17 @@ import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_GET_MESSAGE
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_SENT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageRecipientFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class IdziennikWebGetMessage(
|
||||
override val data: DataIdziennik,
|
||||
private val message: MessageFull,
|
||||
val onSuccess: () -> Unit
|
||||
) : IdziennikWeb(data) {
|
||||
class IdziennikWebGetMessage(override val data: DataIdziennik,
|
||||
private val message: MessageFull,
|
||||
val onSuccess: () -> Unit
|
||||
) : IdziennikWeb(data, null) {
|
||||
companion object {
|
||||
const val TAG = "IdziennikWebGetMessage"
|
||||
}
|
||||
@ -51,7 +50,11 @@ class IdziennikWebGetMessage(
|
||||
message.recipients?.clear()
|
||||
when (message.type) {
|
||||
TYPE_RECEIVED -> {
|
||||
val recipientObject = MessageRecipientFull(profileId, -1, message.id)
|
||||
val recipientObject = MessageRecipientFull(
|
||||
profileId = profileId,
|
||||
id = -1,
|
||||
messageId = message.id
|
||||
)
|
||||
|
||||
val readDateString = it.getString("DataOdczytania")
|
||||
recipientObject.readDate = if (readDateString.isNullOrBlank()) System.currentTimeMillis()
|
||||
@ -68,7 +71,11 @@ class IdziennikWebGetMessage(
|
||||
val recipientName = recipient.getString("NazwaOdbiorcy") ?: return@forEach
|
||||
val teacher = data.getTeacherByLastFirst(recipientName)
|
||||
|
||||
val recipientObject = MessageRecipientFull(profileId, teacher.id, message.id)
|
||||
val recipientObject = MessageRecipientFull(
|
||||
profileId = profileId,
|
||||
id = teacher.id,
|
||||
messageId = message.id
|
||||
)
|
||||
|
||||
recipientObject.readDate = recipient.getLong("Status") ?: return@forEach
|
||||
recipientObject.fullName = teacher.fullName
|
||||
@ -92,9 +99,10 @@ class IdziennikWebGetMessage(
|
||||
))
|
||||
}
|
||||
|
||||
EventBus.getDefault().postSticky(MessageGetEvent(message))
|
||||
|
||||
data.messageList.add(message)
|
||||
data.messageListReplace = true
|
||||
|
||||
EventBus.getDefault().postSticky(MessageGetEvent(message))
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,9 @@ import pl.szczodrzynski.edziennik.data.api.events.RecipientListGetEvent
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
|
||||
class IdziennikWebGetRecipientList(
|
||||
override val data: DataIdziennik, val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
class IdziennikWebGetRecipientList(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit
|
||||
) : IdziennikWeb(data, null) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebGetRecipientList"
|
||||
}
|
||||
|
@ -14,12 +14,15 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
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.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class IdziennikWebGrades(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : IdziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebGrades"
|
||||
}
|
||||
@ -61,17 +64,19 @@ class IdziennikWebGrades(override val data: DataIdziennik,
|
||||
}
|
||||
|
||||
val gradeObject = Grade(
|
||||
profileId,
|
||||
id,
|
||||
category,
|
||||
colorInt,
|
||||
"",
|
||||
name,
|
||||
value,
|
||||
weight,
|
||||
semester,
|
||||
teacher.id,
|
||||
subject.id)
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
name = name,
|
||||
type = TYPE_NORMAL,
|
||||
value = value,
|
||||
weight = weight,
|
||||
color = colorInt,
|
||||
category = category,
|
||||
description = null,
|
||||
comment = null,
|
||||
semester = semester,
|
||||
teacherId = teacher.id,
|
||||
subjectId = subject.id)
|
||||
|
||||
when (grade.getInt("Typ")) {
|
||||
0 -> {
|
||||
@ -96,17 +101,19 @@ class IdziennikWebGrades(override val data: DataIdziennik,
|
||||
}
|
||||
|
||||
val historyObject = Grade(
|
||||
profileId,
|
||||
gradeObject.id * -1,
|
||||
historyItem.get("Kategoria").asString,
|
||||
colorInt,
|
||||
historyItem.get("Uzasadnienie").asString,
|
||||
historyItem.get("Ocena").asString,
|
||||
value,
|
||||
if (value > 0f && countToTheAverage) weight * -1f else 0f,
|
||||
historyItem.get("Semestr").asInt,
|
||||
teacher.id,
|
||||
subject.id)
|
||||
profileId = profileId,
|
||||
id = gradeObject.id * -1,
|
||||
name = historyItem.getString("Ocena") ?: "",
|
||||
type = TYPE_NORMAL,
|
||||
value = value,
|
||||
weight = if (value > 0f && countToTheAverage) weight * -1f else 0f,
|
||||
color = colorInt,
|
||||
category = historyItem.getString("Kategoria"),
|
||||
description = historyItem.getString("Uzasadnienie"),
|
||||
comment = null,
|
||||
semester = historyItem.getInt("Semestr") ?: 1,
|
||||
teacherId = teacher.id,
|
||||
subjectId = subject.id)
|
||||
historyObject.parentId = gradeObject.id
|
||||
|
||||
val addedDate = historyItem.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis()
|
||||
@ -163,7 +170,7 @@ class IdziennikWebGrades(override val data: DataIdziennik,
|
||||
DataRemoveModel.Grades.semesterWithType(profile.currentSemester, it)
|
||||
})
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_GRADES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_IDZIENNIK_WEB_GRADES)
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
} ?: onSuccess(ENDPOINT_IDZIENNIK_WEB_GRADES) }
|
||||
}
|
||||
|
@ -13,13 +13,15 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNI
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
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.utils.models.Date
|
||||
|
||||
class IdziennikWebHomework(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : IdziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebHomework"
|
||||
}
|
||||
@ -50,13 +52,14 @@ class IdziennikWebHomework(override val data: DataIdziennik,
|
||||
json.getJsonArray("ListK")?.asJsonObjectList()?.forEach { homework ->
|
||||
val id = homework.getLong("_recordId") ?: return@forEach
|
||||
val eventDate = Date.fromY_m_d(homework.getString("dataO") ?: return@forEach)
|
||||
val addedDate = Date.fromY_m_d(homework.getString("dataZ") ?: return@forEach)
|
||||
val subjectName = homework.getString("przed") ?: return@forEach
|
||||
val subjectId = data.getSubject(subjectName, null, subjectName).id
|
||||
val teacherName = homework.getString("usr") ?: return@forEach
|
||||
val teacherId = data.getTeacherByLastFirst(teacherName).id
|
||||
val lessonList = data.db.timetableDao().getForDateNow(profileId, eventDate)
|
||||
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.displayStartTime
|
||||
val topic = homework.getString("tytul") ?: ""
|
||||
val topic = homework.getString("tytul")?.trim() ?: ""
|
||||
|
||||
val seen = when (profile?.empty) {
|
||||
true -> true
|
||||
@ -65,17 +68,16 @@ class IdziennikWebHomework(override val data: DataIdziennik,
|
||||
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
eventDate,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
Event.TYPE_HOMEWORK,
|
||||
false,
|
||||
teacherId,
|
||||
subjectId,
|
||||
data.teamClass?.id ?: -1
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
date = eventDate,
|
||||
time = startTime,
|
||||
topic = topic,
|
||||
color = null,
|
||||
type = Event.TYPE_HOMEWORK,
|
||||
teacherId = teacherId,
|
||||
subjectId = subjectId,
|
||||
teamId = data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
@ -85,14 +87,14 @@ class IdziennikWebHomework(override val data: DataIdziennik,
|
||||
eventObject.id,
|
||||
seen,
|
||||
seen,
|
||||
System.currentTimeMillis()
|
||||
addedDate.inMillis
|
||||
))
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_HOMEWORK, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_IDZIENNIK_WEB_HOMEWORK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,22 +4,24 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
||||
|
||||
import pl.szczodrzynski.edziennik.crc16
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_NOTICES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_NOTICES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.crc16
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notice
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notice.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class IdziennikWebNotices(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : IdziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebNotices"
|
||||
}
|
||||
@ -69,7 +71,7 @@ class IdziennikWebNotices(override val data: DataIdziennik,
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_NOTICES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_IDZIENNIK_WEB_NOTICES)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,18 +12,20 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNI
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.TYPE_SEMESTER1_PROPOSED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.TYPE_YEAR_PROPOSED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_DESCRIPTIVE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_PROPOSED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_PROPOSED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.getJsonArray
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.getWordGradeValue
|
||||
|
||||
class IdziennikWebProposedGrades(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : IdziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebProposedGrades"
|
||||
}
|
||||
@ -37,35 +39,63 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
|
||||
.withApiResponse(result))
|
||||
return@webApiGet
|
||||
}
|
||||
val manager = data.app.gradesManager
|
||||
|
||||
json.getJsonArray("Przedmioty")?.asJsonObjectList()?.forEach { subject ->
|
||||
val subjectName = subject.getString("Przedmiot") ?: return@forEach
|
||||
val subjectObject = data.getSubject(subjectName, null, subjectName)
|
||||
|
||||
val semester1Proposed = subject.getString("OcenaSem1") ?: ""
|
||||
val semester1Value = getWordGradeValue(semester1Proposed)
|
||||
val semester1Value = manager.getGradeValue(semester1Proposed)
|
||||
val semester1Id = subjectObject.id * (-100) - 1
|
||||
val semester1Type =
|
||||
if (semester1Value == 0f) TYPE_DESCRIPTIVE
|
||||
else TYPE_SEMESTER1_PROPOSED
|
||||
val semester1Name = when {
|
||||
semester1Value == 0f -> " "
|
||||
semester1Value % 1.0f == 0f -> semester1Value.toInt().toString()
|
||||
else -> semester1Value.toString()
|
||||
}
|
||||
val semester1Color =
|
||||
if (semester1Value == 0f) 0xff536dfe.toInt()
|
||||
else -1
|
||||
|
||||
val semester2Proposed = subject.getString("OcenaSem2") ?: ""
|
||||
val semester2Value = getWordGradeValue(semester2Proposed)
|
||||
val semester2Value = manager.getGradeValue(semester2Proposed)
|
||||
val semester2Id = subjectObject.id * (-100) - 2
|
||||
val semester2Type =
|
||||
if (semester2Value == 0f) TYPE_DESCRIPTIVE
|
||||
else TYPE_YEAR_PROPOSED
|
||||
val semester2Name = when {
|
||||
semester2Value == 0f -> " "
|
||||
semester2Value % 1.0f == 0f -> semester2Value.toInt().toString()
|
||||
else -> semester2Value.toString()
|
||||
}
|
||||
val semester2Color =
|
||||
if (semester2Value == 0f) 0xffff4081.toInt()
|
||||
else -1
|
||||
|
||||
if (semester1Proposed != "") {
|
||||
val gradeObject = Grade(
|
||||
profileId,
|
||||
semester1Id,
|
||||
"",
|
||||
-1,
|
||||
"",
|
||||
semester1Value.toString(),
|
||||
semester1Value.toFloat(),
|
||||
0f,
|
||||
1,
|
||||
-1,
|
||||
subjectObject.id
|
||||
).apply {
|
||||
type = TYPE_SEMESTER1_PROPOSED
|
||||
}
|
||||
profileId = profileId,
|
||||
id = semester1Id,
|
||||
name = semester1Name,
|
||||
type = semester1Type,
|
||||
value = semester1Value,
|
||||
weight = 0f,
|
||||
color = semester1Color,
|
||||
category = if (semester1Value == 0f) "Ocena opisowa semestralna" else null,
|
||||
description = if (semester1Value == 0f) semester1Proposed else null,
|
||||
comment = null,
|
||||
semester = 1,
|
||||
teacherId = -1,
|
||||
subjectId = subjectObject.id
|
||||
)
|
||||
|
||||
val addedDate = if (data.profile.empty)
|
||||
data.profile.dateSemester1Start.inMillis
|
||||
else
|
||||
System.currentTimeMillis()
|
||||
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
@ -74,26 +104,31 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
|
||||
gradeObject.id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
|
||||
if (semester2Proposed != "") {
|
||||
val gradeObject = Grade(
|
||||
profileId,
|
||||
semester2Id,
|
||||
"",
|
||||
-1,
|
||||
"",
|
||||
semester2Value.toString(),
|
||||
semester2Value.toFloat(),
|
||||
0f,
|
||||
2,
|
||||
-1,
|
||||
subjectObject.id
|
||||
).apply {
|
||||
type = TYPE_YEAR_PROPOSED
|
||||
}
|
||||
profileId = profileId,
|
||||
id = semester2Id,
|
||||
name = semester2Name,
|
||||
type = semester2Type,
|
||||
value = semester2Value,
|
||||
weight = 0f,
|
||||
color = semester2Color,
|
||||
category = if (semester2Value == 0f) "Ocena opisowa końcoworoczna" else null,
|
||||
description = if (semester2Value == 0f) semester2Proposed else null,
|
||||
comment = null,
|
||||
semester = 2,
|
||||
teacherId = -1,
|
||||
subjectId = subjectObject.id
|
||||
)
|
||||
|
||||
val addedDate = if (data.profile.empty)
|
||||
data.profile.dateSemester2Start.inMillis
|
||||
else
|
||||
System.currentTimeMillis()
|
||||
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
@ -102,7 +137,7 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
|
||||
gradeObject.id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
}
|
||||
@ -111,7 +146,7 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
|
||||
DataRemoveModel.Grades.semesterWithType(profile.currentSemester, it)
|
||||
})
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES)
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
} ?: onSuccess(ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES) }
|
||||
}
|
||||
|
@ -18,13 +18,12 @@ import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import java.util.*
|
||||
|
||||
class IdziennikWebSendMessage(
|
||||
override val data: DataIdziennik,
|
||||
val recipients: List<Teacher>,
|
||||
val subject: String,
|
||||
val text: String,
|
||||
val onSuccess: () -> Unit
|
||||
) : IdziennikWeb(data) {
|
||||
class IdziennikWebSendMessage(override val data: DataIdziennik,
|
||||
val recipients: List<Teacher>,
|
||||
val subject: String,
|
||||
val text: String,
|
||||
val onSuccess: () -> Unit
|
||||
) : IdziennikWeb(data, null) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebSendMessage"
|
||||
}
|
||||
@ -57,8 +56,8 @@ class IdziennikWebSendMessage(
|
||||
return@webApiGet
|
||||
}
|
||||
|
||||
IdziennikApiMessagesSent(data) {
|
||||
val message = data.messageIgnoreList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject }
|
||||
IdziennikApiMessagesSent(data, null) {
|
||||
val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject }
|
||||
val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id }
|
||||
val event = MessageSentEvent(data.profileId, message, metadata?.addedDate)
|
||||
|
||||
|
@ -0,0 +1,36 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_HOME
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
|
||||
class IdziennikWebSwitchRegister(override val data: DataIdziennik,
|
||||
val registerId: Int,
|
||||
val onSuccess: () -> Unit
|
||||
) : IdziennikWeb(data, null) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebSwitchRegister"
|
||||
}
|
||||
|
||||
init {
|
||||
val hiddenFields = data.loginStore.getLoginData("hiddenFields", JsonObject())
|
||||
// TODO error checking
|
||||
|
||||
webGet(TAG, IDZIENNIK_WEB_HOME, mapOf(
|
||||
"__VIEWSTATE" to hiddenFields.getString("__VIEWSTATE", ""),
|
||||
"__VIEWSTATEGENERATOR" to hiddenFields.getString("__VIEWSTATEGENERATOR", ""),
|
||||
"__EVENTVALIDATION" to hiddenFields.getString("__EVENTVALIDATION", ""),
|
||||
"ctl00\$dxComboUczniowie" to registerId
|
||||
)) { text ->
|
||||
Regexes.IDZIENNIK_WEB_SELECTED_REGISTER.find(text)?.let {
|
||||
val registerId = it[1].toIntOrNull() ?: return@let
|
||||
data.webSelectedRegister = registerId
|
||||
}
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -13,17 +13,19 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNI
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
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.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
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 IdziennikWebTimetable(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : IdziennikWeb(data, lastSync) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebTimetable"
|
||||
}
|
||||
@ -187,7 +189,7 @@ class IdziennikWebTimetable(override val data: DataIdziennik,
|
||||
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_IDZIENNIK_WEB_TIMETABLE)
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ class IdziennikFirstLogin(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
||||
private const val TAG = "IdziennikFirstLogin"
|
||||
}
|
||||
|
||||
private val web = IdziennikWeb(data)
|
||||
private val web = IdziennikWeb(data, null)
|
||||
private val profileList = mutableListOf<Profile>()
|
||||
|
||||
init {
|
||||
|
@ -7,15 +7,14 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.login
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import okhttp3.Cookie
|
||||
import pl.szczodrzynski.edziennik.HOUR
|
||||
import pl.szczodrzynski.edziennik.MINUTE
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.getUnixDate
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class IdziennikLoginWeb(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
@ -24,22 +23,12 @@ class IdziennikLoginWeb(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
||||
|
||||
init { run {
|
||||
if (data.isWebLoginValid()) {
|
||||
data.app.cookieJar.saveFromResponse(null, listOf(
|
||||
Cookie.Builder()
|
||||
.name("ASP.NET_SessionId_iDziennik")
|
||||
.value(data.webSessionId!!)
|
||||
.domain("iuczniowie.progman.pl")
|
||||
.secure().httpOnly().build(),
|
||||
Cookie.Builder()
|
||||
.name(".ASPXAUTH")
|
||||
.value(data.webAuth!!)
|
||||
.domain("iuczniowie.progman.pl")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
data.app.cookieJar.set("iuczniowie.progman.pl", "ASP.NET_SessionId_iDziennik", data.webSessionId)
|
||||
data.app.cookieJar.set("iuczniowie.progman.pl", ".ASPXAUTH", data.webAuth)
|
||||
onSuccess()
|
||||
}
|
||||
else {
|
||||
data.app.cookieJar.clearForDomain("iuczniowie.progman.pl")
|
||||
data.app.cookieJar.clear("iuczniowie.progman.pl")
|
||||
if (data.webSchoolName != null && data.webUsername != null && data.webPassword != null) {
|
||||
loginWithCredentials()
|
||||
}
|
||||
@ -62,13 +51,47 @@ class IdziennikLoginWeb(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
||||
|
||||
// login succeeded: there is a start page
|
||||
if (text.contains("czyWyswietlicDostepMobilny")) {
|
||||
val cookies = data.app.cookieJar.getForDomain("iuczniowie.progman.pl")
|
||||
val cookies = data.app.cookieJar.getAll("iuczniowie.progman.pl")
|
||||
run {
|
||||
data.webSessionId = cookies.singleOrNull { it.name() == "ASP.NET_SessionId_iDziennik" }?.value() ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_SESSION
|
||||
data.webAuth = cookies.singleOrNull { it.name() == ".ASPXAUTH" }?.value() ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_AUTH
|
||||
data.apiBearer = cookies.singleOrNull { it.name() == "Bearer" }?.value() ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_BEARER
|
||||
data.webSessionId = cookies["ASP.NET_SessionId_iDziennik"] ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_SESSION
|
||||
data.webAuth = cookies[".ASPXAUTH"] ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_AUTH
|
||||
data.apiBearer = cookies["Bearer"]?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_BEARER
|
||||
data.loginExpiryTime = response.getUnixDate() + 30 * MINUTE /* after about 40 minutes the login didn't work already */
|
||||
data.apiExpiryTime = response.getUnixDate() + 12 * HOUR /* actually it expires after 24 hours but I'm not sure when does the token refresh. */
|
||||
|
||||
val hiddenFields = JsonObject()
|
||||
Regexes.IDZIENNIK_LOGIN_HIDDEN_FIELDS.findAll(text).forEach {
|
||||
hiddenFields[it[1]] = it[2]
|
||||
}
|
||||
data.loginStore.putLoginData("hiddenFields", hiddenFields)
|
||||
|
||||
Regexes.IDZIENNIK_WEB_SELECTED_REGISTER.find(text)?.let {
|
||||
val registerId = it[1].toIntOrNull() ?: return@let
|
||||
data.webSelectedRegister = registerId
|
||||
}
|
||||
|
||||
data.profile?.let { profile ->
|
||||
Regexes.IDZIENNIK_WEB_LUCKY_NUMBER.find(text)?.also {
|
||||
val number = it[1].toIntOrNull() ?: return@also
|
||||
val luckyNumberObject = LuckyNumber(
|
||||
data.profileId,
|
||||
Date.getToday(),
|
||||
number
|
||||
)
|
||||
|
||||
data.luckyNumberList.add(luckyNumberObject)
|
||||
data.metadataList.add(
|
||||
Metadata(
|
||||
profile.id,
|
||||
Metadata.TYPE_LUCKY_NUMBER,
|
||||
luckyNumberObject.date.value.toLong(),
|
||||
true,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
return@run null
|
||||
}?.let { errorCode ->
|
||||
data.error(ApiError(TAG, errorCode)
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus
|
||||
|
||||
import okhttp3.Cookie
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.currentTimeUnix
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_API
|
||||
@ -31,23 +30,11 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
loginMethods += LOGIN_METHOD_LIBRUS_API
|
||||
if (isSynergiaLoginValid()) {
|
||||
loginMethods += LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
app.cookieJar.saveFromResponse(null, listOf(
|
||||
Cookie.Builder()
|
||||
.name("DZIENNIKSID")
|
||||
.value(synergiaSessionId!!)
|
||||
.domain("synergia.librus.pl")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
app.cookieJar.set("synergia.librus.pl", "DZIENNIKSID", synergiaSessionId)
|
||||
}
|
||||
if (isMessagesLoginValid()) {
|
||||
loginMethods += LOGIN_METHOD_LIBRUS_MESSAGES
|
||||
app.cookieJar.saveFromResponse(null, listOf(
|
||||
Cookie.Builder()
|
||||
.name("DZIENNIKSID")
|
||||
.value(messagesSessionId!!)
|
||||
.domain("wiadomosci.librus.pl")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
app.cookieJar.set("wiadomosci.librus.pl", "DZIENNIKSID", messagesSessionId)
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,6 +178,16 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
get() { mApiTokenExpiryTime = mApiTokenExpiryTime ?: profile?.getStudentData("accountTokenTime", 0L); return mApiTokenExpiryTime ?: 0L }
|
||||
set(value) { mApiTokenExpiryTime = value; profile?.putStudentData("accountTokenTime", value) ?: return; }
|
||||
|
||||
/**
|
||||
* A push device ID, generated by Librus when registering
|
||||
* a FCM token. I don't really know if this has any use,
|
||||
* but it may be worthy to save that ID.
|
||||
*/
|
||||
private var mPushDeviceId: Int? = null
|
||||
var pushDeviceId: Int
|
||||
get() { mPushDeviceId = mPushDeviceId ?: profile?.getStudentData("pushDeviceId", 0); return mPushDeviceId ?: 0 }
|
||||
set(value) { mPushDeviceId = value; profile?.putStudentData("pushDeviceId", value) ?: return; }
|
||||
|
||||
/* _____ _
|
||||
/ ____| (_)
|
||||
| (___ _ _ _ __ ___ _ __ __ _ _ __ _
|
||||
|
@ -13,18 +13,21 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.Librus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetMessage
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetRecipientList
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesSendMessage
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaGetHomework
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaHomeworkGetAttachment
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaMarkAllAnnouncementsAsRead
|
||||
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.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
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 Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
@ -45,9 +48,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
|
||||
private fun completed() {
|
||||
data.saveData()
|
||||
data.notify {
|
||||
callback.onCompleted()
|
||||
}
|
||||
callback.onCompleted()
|
||||
}
|
||||
|
||||
/* _______ _ _ _ _ _
|
||||
@ -58,9 +59,9 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
||||
__/ |
|
||||
|__*/
|
||||
override fun sync(featureIds: List<Int>, viewId: Int?, arguments: JsonObject?) {
|
||||
override fun sync(featureIds: List<Int>, viewId: Int?, onlyEndpoints: List<Int>?, arguments: JsonObject?) {
|
||||
data.arguments = arguments
|
||||
data.prepare(librusLoginMethods, LibrusFeatures, featureIds, viewId)
|
||||
data.prepare(librusLoginMethods, LibrusFeatures, featureIds, viewId, onlyEndpoints)
|
||||
login()
|
||||
}
|
||||
|
||||
@ -120,11 +121,23 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
|
||||
login(LOGIN_METHOD_LIBRUS_MESSAGES) {
|
||||
LibrusMessagesGetAttachment(data, message, attachmentId, attachmentName) {
|
||||
completed()
|
||||
override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {
|
||||
when (owner) {
|
||||
is Message -> {
|
||||
login(LOGIN_METHOD_LIBRUS_MESSAGES) {
|
||||
LibrusMessagesGetAttachment(data, owner, attachmentId, attachmentName) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
is EventFull -> {
|
||||
login(LOGIN_METHOD_LIBRUS_SYNERGIA) {
|
||||
LibrusSynergiaHomeworkGetAttachment(data, owner, attachmentId, attachmentName) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> completed()
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,10 +149,19 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
}
|
||||
}
|
||||
|
||||
override fun getEvent(eventFull: EventFull) {
|
||||
login(LOGIN_METHOD_LIBRUS_SYNERGIA) {
|
||||
LibrusSynergiaGetHomework(data, eventFull) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun firstLogin() { LibrusFirstLogin(data) { completed() } }
|
||||
override fun cancel() {
|
||||
d(TAG, "Cancelled")
|
||||
data.cancel()
|
||||
callback.onCompleted()
|
||||
}
|
||||
|
||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||
@ -182,6 +204,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
}
|
||||
ERROR_LOGIN_LIBRUS_PORTAL_NO_CODE,
|
||||
ERROR_LOGIN_LIBRUS_PORTAL_CSRF_MISSING,
|
||||
ERROR_LOGIN_LIBRUS_PORTAL_CSRF_EXPIRED,
|
||||
ERROR_LOGIN_LIBRUS_PORTAL_CODE_REVOKED,
|
||||
ERROR_LOGIN_LIBRUS_PORTAL_CODE_EXPIRED -> {
|
||||
login()
|
||||
@ -200,7 +223,6 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
ERROR_LOGIN_LIBRUS_MESSAGES_NO_SESSION_ID -> {
|
||||
login()
|
||||
}
|
||||
// TODO PORTAL CAPTCHA
|
||||
ERROR_LIBRUS_API_TIMETABLE_NOT_PUBLIC -> {
|
||||
data.timetableNotPublic = true
|
||||
data()
|
||||
@ -209,6 +231,11 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
ERROR_LIBRUS_API_NOTES_NOT_ACTIVE -> {
|
||||
data()
|
||||
}
|
||||
ERROR_LIBRUS_API_DEVICE_REGISTERED -> {
|
||||
data.app.config.sync.tokenLibrusList =
|
||||
data.app.config.sync.tokenLibrusList + data.profileId
|
||||
data()
|
||||
}
|
||||
else -> callback.onError(apiError)
|
||||
}
|
||||
}
|
||||
|
@ -53,8 +53,6 @@ const val ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK = 2030
|
||||
const val ENDPOINT_LIBRUS_MESSAGES_RECEIVED = 3010
|
||||
const val ENDPOINT_LIBRUS_MESSAGES_SENT = 3020
|
||||
const val ENDPOINT_LIBRUS_MESSAGES_TRASH = 3030
|
||||
const val ENDPOINT_LIBRUS_MESSAGES_RECEIVERS = 3040
|
||||
const val ENDPOINT_LIBRUS_MESSAGES_GET = 3040
|
||||
|
||||
val LibrusFeatures = listOf(
|
||||
|
||||
@ -66,7 +64,7 @@ val LibrusFeatures = listOf(
|
||||
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.app.config.sync.tokenLibrusList.contains(data.profileId)
|
||||
(data as DataLibrus).isPremium && !data.app.config.sync.tokenLibrusList.contains(data.profileId)
|
||||
},
|
||||
|
||||
|
||||
@ -118,11 +116,11 @@ val LibrusFeatures = listOf(
|
||||
* Homework - using API.
|
||||
* Sync only if account has premium access.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_HOMEWORK, listOf(
|
||||
/*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.
|
||||
*/
|
||||
@ -229,9 +227,9 @@ val LibrusFeatures = listOf(
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_HOMEWORK, listOf(
|
||||
ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK to LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)).withShouldSync { data ->
|
||||
), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA))/*.withShouldSync { data ->
|
||||
!(data as DataLibrus).isPremium
|
||||
},
|
||||
}*/,
|
||||
|
||||
/**
|
||||
* Messages inbox - using messages website.
|
||||
|
@ -15,7 +15,7 @@ import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.net.HttpURLConnection.*
|
||||
|
||||
open class LibrusApi(open val data: DataLibrus) {
|
||||
open class LibrusApi(open val data: DataLibrus, open val lastSync: Long?) {
|
||||
companion object {
|
||||
private const val TAG = "LibrusApi"
|
||||
}
|
||||
@ -44,9 +44,12 @@ open class LibrusApi(open val data: DataLibrus) {
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
/*
|
||||
{"Status":"Error","Code":"DeviceRegistered","Message":"This device is alerdy registered.","Resources":{"..":{"Url":"https:\/\/api.librus.pl\/2.0\/Root"}},"Url":"https:\/\/api.librus.pl\/2.0\/ChangeRegister"}*/
|
||||
val error = if (response?.code() == 200) null else
|
||||
json.getString("Code") ?:
|
||||
json.getString("Message") ?:
|
||||
json.getString("Status") ?:
|
||||
response?.parserErrorBody
|
||||
error?.let { code ->
|
||||
when (code) {
|
||||
@ -63,6 +66,9 @@ open class LibrusApi(open val data: DataLibrus) {
|
||||
"NotesIsNotActive" -> ERROR_LIBRUS_API_NOTES_NOT_ACTIVE
|
||||
"InvalidRequest" -> ERROR_LIBRUS_API_INVALID_REQUEST_PARAMS
|
||||
"Nieprawidłowy węzeł." -> ERROR_LIBRUS_API_INCORRECT_ENDPOINT
|
||||
"NoticeboardProblem" -> ERROR_LIBRUS_API_NOTICEBOARD_PROBLEM
|
||||
"DeviceRegistered" -> ERROR_LIBRUS_API_DEVICE_REGISTERED
|
||||
"Maintenance" -> ERROR_LIBRUS_API_MAINTENANCE
|
||||
else -> ERROR_LIBRUS_API_OTHER
|
||||
}.let { errorCode ->
|
||||
if (errorCode !in ignoreErrors) {
|
||||
@ -114,6 +120,8 @@ open class LibrusApi(open val data: DataLibrus) {
|
||||
.allowErrorCode(HTTP_FORBIDDEN)
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.allowErrorCode(HTTP_UNAVAILABLE)
|
||||
.allowErrorCode(HTTP_NOT_FOUND)
|
||||
.allowErrorCode(503)
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
|
@ -31,158 +31,163 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
useEndpoint(data.targetEndpointIds.removeAt(0)) {
|
||||
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, onSuccess: () -> Unit) {
|
||||
Utils.d(TAG, "Using endpoint $endpointId")
|
||||
private fun useEndpoint(endpointId: Int, lastSync: Long?, onSuccess: (endpointId: Int) -> Unit) {
|
||||
Utils.d(TAG, "Using endpoint $endpointId. Last sync time = $lastSync")
|
||||
when (endpointId) {
|
||||
/**
|
||||
* API
|
||||
*/
|
||||
ENDPOINT_LIBRUS_API_ME -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_student_info)
|
||||
LibrusApiMe(data, onSuccess)
|
||||
LibrusApiMe(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_SCHOOLS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_school_info)
|
||||
LibrusApiSchools(data, onSuccess)
|
||||
LibrusApiSchools(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_CLASSES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_classes)
|
||||
LibrusApiClasses(data, onSuccess)
|
||||
LibrusApiClasses(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_teams)
|
||||
LibrusApiVirtualClasses(data, onSuccess)
|
||||
LibrusApiVirtualClasses(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_UNITS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_units)
|
||||
LibrusApiUnits(data, onSuccess)
|
||||
LibrusApiUnits(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_USERS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_teachers)
|
||||
LibrusApiUsers(data, onSuccess)
|
||||
LibrusApiUsers(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_SUBJECTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_subjects)
|
||||
LibrusApiSubjects(data, onSuccess)
|
||||
LibrusApiSubjects(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_CLASSROOMS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_classrooms)
|
||||
LibrusApiClassrooms(data, onSuccess)
|
||||
LibrusApiClassrooms(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_LESSONS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_lessons)
|
||||
LibrusApiLessons(data, onSuccess)
|
||||
LibrusApiLessons(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_PUSH_CONFIG -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_push_config)
|
||||
LibrusApiPushConfig(data, lastSync, onSuccess)
|
||||
}
|
||||
// TODO push config
|
||||
ENDPOINT_LIBRUS_API_TIMETABLES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
||||
LibrusApiTimetables(data, onSuccess)
|
||||
LibrusApiTimetables(data, lastSync, onSuccess)
|
||||
}
|
||||
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADE_CATEGORIES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grade_categories)
|
||||
LibrusApiGradeCategories(data, onSuccess)
|
||||
LibrusApiGradeCategories(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grade_categories)
|
||||
LibrusApiBehaviourGradeCategories(data, onSuccess)
|
||||
LibrusApiBehaviourGradeCategories(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADE_CATEGORIES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grade_categories)
|
||||
LibrusApiDescriptiveGradeCategories(data, onSuccess)
|
||||
LibrusApiDescriptiveGradeCategories(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_TEXT_GRADE_CATEGORIES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grade_categories)
|
||||
LibrusApiTextGradeCategories(data, onSuccess)
|
||||
LibrusApiTextGradeCategories(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_POINT_GRADE_CATEGORIES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grade_categories)
|
||||
LibrusApiPointGradeCategories(data, onSuccess)
|
||||
LibrusApiPointGradeCategories(data, lastSync, onSuccess)
|
||||
}
|
||||
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grade_comments)
|
||||
LibrusApiGradeComments(data, onSuccess)
|
||||
LibrusApiGradeComments(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_COMMENTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grade_comments)
|
||||
LibrusApiBehaviourGradeComments(data, onSuccess)
|
||||
LibrusApiBehaviourGradeComments(data, lastSync, onSuccess)
|
||||
}
|
||||
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
||||
LibrusApiGrades(data, onSuccess)
|
||||
LibrusApiGrades(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_behaviour_grades)
|
||||
LibrusApiBehaviourGrades(data, onSuccess)
|
||||
LibrusApiBehaviourGrades(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_descriptive_grades)
|
||||
LibrusApiDescriptiveGrades(data, onSuccess)
|
||||
LibrusApiDescriptiveGrades(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_TEXT_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_descriptive_grades)
|
||||
LibrusApiTextGrades(data, onSuccess)
|
||||
LibrusApiTextGrades(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_POINT_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_point_grades)
|
||||
LibrusApiPointGrades(data, onSuccess)
|
||||
LibrusApiPointGrades(data, lastSync, onSuccess)
|
||||
}
|
||||
|
||||
ENDPOINT_LIBRUS_API_EVENT_TYPES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_event_types)
|
||||
LibrusApiEventTypes(data, onSuccess)
|
||||
LibrusApiEventTypes(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_EVENTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_events)
|
||||
LibrusApiEvents(data, onSuccess)
|
||||
LibrusApiEvents(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_HOMEWORK -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
||||
LibrusApiHomework(data, onSuccess)
|
||||
LibrusApiHomework(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_LUCKY_NUMBER -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
|
||||
LibrusApiLuckyNumber(data, onSuccess)
|
||||
LibrusApiLuckyNumber(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_NOTICE_TYPES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_notice_types)
|
||||
LibrusApiNoticeTypes(data, onSuccess)
|
||||
LibrusApiNoticeTypes(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_NOTICES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
||||
LibrusApiNotices(data, onSuccess)
|
||||
LibrusApiNotices(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance_types)
|
||||
LibrusApiAttendanceTypes(data, onSuccess)
|
||||
LibrusApiAttendanceTypes(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_ATTENDANCES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
||||
LibrusApiAttendances(data, onSuccess)
|
||||
LibrusApiAttendances(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_ANNOUNCEMENTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_announcements)
|
||||
LibrusApiAnnouncements(data, onSuccess)
|
||||
LibrusApiAnnouncements(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_PT_MEETINGS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_pt_meetings)
|
||||
LibrusApiPtMeetings(data, onSuccess)
|
||||
LibrusApiPtMeetings(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_teacher_free_day_types)
|
||||
LibrusApiTeacherFreeDayTypes(data, onSuccess)
|
||||
LibrusApiTeacherFreeDayTypes(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_teacher_free_days)
|
||||
LibrusApiTeacherFreeDays(data, onSuccess)
|
||||
LibrusApiTeacherFreeDays(data, lastSync, onSuccess)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -190,11 +195,11 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
*/
|
||||
ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
||||
LibrusSynergiaHomework(data, onSuccess)
|
||||
LibrusSynergiaHomework(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_SYNERGIA_INFO -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_student_info)
|
||||
LibrusSynergiaInfo(data, onSuccess)
|
||||
LibrusSynergiaInfo(data, lastSync, onSuccess)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -202,14 +207,14 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
*/
|
||||
ENDPOINT_LIBRUS_MESSAGES_RECEIVED -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
||||
LibrusMessagesGetList(data, type = Message.TYPE_RECEIVED, onSuccess = onSuccess)
|
||||
LibrusMessagesGetList(data, type = Message.TYPE_RECEIVED, lastSync = lastSync, onSuccess = onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_MESSAGES_SENT -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
|
||||
LibrusMessagesGetList(data, type = Message.TYPE_SENT, onSuccess = onSuccess)
|
||||
LibrusMessagesGetList(data, type = Message.TYPE_SENT, lastSync = lastSync, onSuccess = onSuccess)
|
||||
}
|
||||
|
||||
else -> onSuccess()
|
||||
else -> onSuccess(endpointId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ import im.wangchao.mhttp.body.MediaTypeUtils
|
||||
import im.wangchao.mhttp.callback.FileCallbackHandler
|
||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import okhttp3.Cookie
|
||||
import org.json.JSONObject
|
||||
import org.json.XML
|
||||
import org.jsoup.Jsoup
|
||||
@ -30,7 +29,7 @@ import javax.xml.transform.TransformerFactory
|
||||
import javax.xml.transform.dom.DOMSource
|
||||
import javax.xml.transform.stream.StreamResult
|
||||
|
||||
open class LibrusMessages(open val data: DataLibrus) {
|
||||
open class LibrusMessages(open val data: DataLibrus, open val lastSync: Long?) {
|
||||
companion object {
|
||||
private const val TAG = "LibrusMessages"
|
||||
}
|
||||
@ -55,13 +54,20 @@ open class LibrusMessages(open val data: DataLibrus) {
|
||||
}
|
||||
|
||||
when {
|
||||
text.contains("<message>Niepoprawny login i/lub hasło.</message>") -> data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN, response, text)
|
||||
text.contains("stop.png") -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
|
||||
text.contains("eAccessDeny") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||
text.contains("OffLine") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_MAINTENANCE, response, text)
|
||||
text.contains("<status>error</status>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ERROR, response, text)
|
||||
text.contains("<type>eVarWhitThisNameNotExists</type>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||
text.contains("<error>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
|
||||
text.contains("<message>Niepoprawny login i/lub hasło.</message>") -> ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN
|
||||
text.contains("<message>Nie odnaleziono wiadomości.</message>") -> ERROR_LIBRUS_MESSAGES_NOT_FOUND
|
||||
text.contains("stop.png") -> ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED
|
||||
text.contains("eAccessDeny") -> ERROR_LIBRUS_MESSAGES_ACCESS_DENIED
|
||||
text.contains("OffLine") -> ERROR_LIBRUS_MESSAGES_MAINTENANCE
|
||||
text.contains("<status>error</status>") -> ERROR_LIBRUS_MESSAGES_ERROR
|
||||
text.contains("<type>eVarWhitThisNameNotExists</type>") -> ERROR_LIBRUS_MESSAGES_ACCESS_DENIED
|
||||
text.contains("<error>") -> ERROR_LIBRUS_MESSAGES_OTHER
|
||||
else -> null
|
||||
}?.let { errorCode ->
|
||||
data.error(ApiError(tag, errorCode)
|
||||
.withApiResponse(text)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
@ -82,14 +88,7 @@ open class LibrusMessages(open val data: DataLibrus) {
|
||||
}
|
||||
}
|
||||
|
||||
data.app.cookieJar.saveFromResponse(null, listOf(
|
||||
Cookie.Builder()
|
||||
.name("DZIENNIKSID")
|
||||
.value(data.messagesSessionId!!)
|
||||
.domain("wiadomosci.librus.pl")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
|
||||
data.app.cookieJar.set("wiadomosci.librus.pl", "DZIENNIKSID", data.messagesSessionId)
|
||||
|
||||
val docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||
val doc = docBuilder.newDocument()
|
||||
@ -139,13 +138,20 @@ open class LibrusMessages(open val data: DataLibrus) {
|
||||
}
|
||||
|
||||
when {
|
||||
text.contains("<message>Niepoprawny login i/lub hasło.</message>") -> data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN, response, text)
|
||||
text.contains("stop.png") -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
|
||||
text.contains("eAccessDeny") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||
text.contains("OffLine") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_MAINTENANCE, response, text)
|
||||
text.contains("<status>error</status>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ERROR, response, text)
|
||||
text.contains("<type>eVarWhitThisNameNotExists</type>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||
text.contains("<error>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
|
||||
text.contains("<message>Niepoprawny login i/lub hasło.</message>") -> ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN
|
||||
text.contains("<message>Nie odnaleziono wiadomości.</message>") -> ERROR_LIBRUS_MESSAGES_NOT_FOUND
|
||||
text.contains("stop.png") -> ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED
|
||||
text.contains("eAccessDeny") -> ERROR_LIBRUS_MESSAGES_ACCESS_DENIED
|
||||
text.contains("OffLine") -> ERROR_LIBRUS_MESSAGES_MAINTENANCE
|
||||
text.contains("<status>error</status>") -> ERROR_LIBRUS_MESSAGES_ERROR
|
||||
text.contains("<type>eVarWhitThisNameNotExists</type>") -> ERROR_LIBRUS_MESSAGES_ACCESS_DENIED
|
||||
text.contains("<error>") -> ERROR_LIBRUS_MESSAGES_OTHER
|
||||
else -> null
|
||||
}?.let { errorCode ->
|
||||
data.error(ApiError(tag, errorCode)
|
||||
.withApiResponse(text)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
@ -166,14 +172,7 @@ open class LibrusMessages(open val data: DataLibrus) {
|
||||
}
|
||||
}
|
||||
|
||||
data.app.cookieJar.saveFromResponse(null, listOf(
|
||||
Cookie.Builder()
|
||||
.name("DZIENNIKSID")
|
||||
.value(data.messagesSessionId!!)
|
||||
.domain("wiadomosci.librus.pl")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
|
||||
data.app.cookieJar.set("wiadomosci.librus.pl", "DZIENNIKSID", data.messagesSessionId)
|
||||
|
||||
val docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||
val doc = docBuilder.newDocument()
|
||||
@ -253,10 +252,11 @@ open class LibrusMessages(open val data: DataLibrus) {
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
fun sandboxGetFile(tag: String, action: String, targetFile: File, onSuccess: (file: File) -> Unit,
|
||||
fun sandboxGetFile(tag: String, url: String, targetFile: File, onSuccess: (file: File) -> Unit,
|
||||
method: Int = GET,
|
||||
onProgress: (written: Long, total: Long) -> Unit) {
|
||||
|
||||
d(tag, "Request: Librus/Messages - $LIBRUS_SANDBOX_URL$action")
|
||||
d(tag, "Request: Librus/Messages - $url")
|
||||
|
||||
val callback = object : FileCallbackHandler(targetFile) {
|
||||
override fun onSuccess(file: File?, response: Response?) {
|
||||
@ -292,9 +292,14 @@ open class LibrusMessages(open val data: DataLibrus) {
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url("$LIBRUS_SANDBOX_URL$action")
|
||||
.url(url)
|
||||
.userAgent(SYNERGIA_USER_AGENT)
|
||||
.post()
|
||||
.also {
|
||||
when (method) {
|
||||
POST -> it.post()
|
||||
else -> it.get()
|
||||
}
|
||||
}
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
|
@ -44,6 +44,7 @@ open class LibrusPortal(open val data: DataLibrus) {
|
||||
"Access token is invalid" -> ERROR_LIBRUS_PORTAL_ACCESS_DENIED
|
||||
"ApiDisabled" -> ERROR_LIBRUS_PORTAL_API_DISABLED
|
||||
"Account not found" -> ERROR_LIBRUS_PORTAL_SYNERGIA_NOT_FOUND
|
||||
"Unable to refresh the account" -> ERROR_LIBRUS_PORTAL_MAINTENANCE
|
||||
else -> when (json.getString("hint")) {
|
||||
"Error while decoding to JSON" -> ERROR_LIBRUS_PORTAL_ACCESS_DENIED
|
||||
else -> ERROR_LIBRUS_PORTAL_OTHER
|
||||
@ -97,6 +98,7 @@ open class LibrusPortal(open val data: DataLibrus) {
|
||||
.allowErrorCode(HttpURLConnection.HTTP_UNAUTHORIZED)
|
||||
.allowErrorCode(HttpURLConnection.HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HttpURLConnection.HTTP_GONE)
|
||||
.allowErrorCode(424)
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
|
@ -12,7 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
open class LibrusSynergia(open val data: DataLibrus) {
|
||||
open class LibrusSynergia(open val data: DataLibrus, open val lastSync: Long?) {
|
||||
companion object {
|
||||
private const val TAG = "LibrusSynergia"
|
||||
}
|
||||
@ -35,7 +35,7 @@ open class LibrusSynergia(open val data: DataLibrus) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!text.contains("jesteś zalogowany")) {
|
||||
if (!text.contains("jesteś zalogowany") && !text.contains("Podgląd zadania")) {
|
||||
when {
|
||||
text.contains("stop.png") -> ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED
|
||||
text.contains("Przerwa techniczna") -> ERROR_LIBRUS_SYNERGIA_MAINTENANCE
|
||||
@ -48,7 +48,6 @@ open class LibrusSynergia(open val data: DataLibrus) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
onSuccess(text)
|
||||
} catch (e: Exception) {
|
||||
@ -90,4 +89,42 @@ open class LibrusSynergia(open val data: DataLibrus) {
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
fun redirectUrlGet(tag: String, url: String, onSuccess: (url: String) -> Unit) {
|
||||
val callback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String?, response: Response) {
|
||||
val redirectUrl = response.headers().get("Location")
|
||||
|
||||
if (redirectUrl != null) {
|
||||
try {
|
||||
onSuccess(redirectUrl)
|
||||
} catch (e: Exception) {
|
||||
data.error(ApiError(tag, EXCEPTION_LIBRUS_SYNERGIA_REQUEST)
|
||||
.withResponse(response)
|
||||
.withThrowable(e)
|
||||
.withApiResponse(text))
|
||||
}
|
||||
} else {
|
||||
data.error(ApiError(tag, ERROR_LIBRUS_SYNERGIA_OTHER)
|
||||
.withResponse(response)
|
||||
.withApiResponse(text))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url(url)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.withClient(data.app.httpLazy)
|
||||
.get()
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
||||
|
@ -6,25 +6,28 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api
|
||||
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_LIBRUS_API_INVALID_REQUEST_PARAMS
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_LIBRUS_API_NOTICEBOARD_PROBLEM
|
||||
import pl.szczodrzynski.edziennik.data.api.POST
|
||||
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.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
|
||||
class LibrusApiAnnouncementMarkAsRead(
|
||||
override val data: DataLibrus,
|
||||
private val announcement: AnnouncementFull,
|
||||
val onSuccess: () -> Unit
|
||||
) : LibrusApi(data) {
|
||||
class LibrusApiAnnouncementMarkAsRead(override val data: DataLibrus,
|
||||
private val announcement: AnnouncementFull,
|
||||
val onSuccess: () -> Unit
|
||||
) : LibrusApi(data, null) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiAnnouncementMarkAsRead"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "SchoolNotices/MarkAsRead/${announcement.idString}", method = POST,
|
||||
ignoreErrors = listOf(ERROR_LIBRUS_API_INVALID_REQUEST_PARAMS)) {
|
||||
ignoreErrors = listOf(
|
||||
ERROR_LIBRUS_API_INVALID_REQUEST_PARAMS,
|
||||
ERROR_LIBRUS_API_NOTICEBOARD_PROBLEM
|
||||
)) {
|
||||
announcement.seen = true
|
||||
|
||||
EventBus.getDefault().postSticky(AnnouncementGetEvent(announcement))
|
||||
|
@ -9,12 +9,14 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_ANNOUNCEMENTS
|
||||
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.SYNC_ALWAYS
|
||||
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 LibrusApiAnnouncements(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : LibrusApi(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiAnnouncements"
|
||||
}
|
||||
@ -58,7 +60,7 @@ class LibrusApiAnnouncements(override val data: DataLibrus,
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_ANNOUNCEMENTS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_LIBRUS_API_ANNOUNCEMENTS)
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
@ -13,7 +13,9 @@ import pl.szczodrzynski.edziennik.data.db.entity.Attendance
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.AttendanceType
|
||||
|
||||
class LibrusApiAttendanceTypes(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : LibrusApi(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiAttendanceTypes"
|
||||
}
|
||||
@ -43,7 +45,7 @@ class LibrusApiAttendanceTypes(override val data: DataLibrus,
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES, 4*DAY)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,14 +9,16 @@ import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_ATTENDANCES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class LibrusApiAttendances(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : LibrusApi(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiAttendances"
|
||||
}
|
||||
@ -33,17 +35,18 @@ class LibrusApiAttendances(override val data: DataLibrus,
|
||||
val attendances = json.getJsonArray("Attendances")?.asJsonObjectList()
|
||||
|
||||
attendances?.forEach { attendance ->
|
||||
val id = Utils.strToInt((attendance.getString("Id") ?: return@forEach)
|
||||
val id = ((attendance.getString("Id") ?: return@forEach)
|
||||
.replace("[^\\d.]".toRegex(), "")).toLong()
|
||||
val lessonId = attendance.getJsonObject("Lesson")?.getLong("Id") ?: -1
|
||||
val lessonNo = attendance.getInt("LessonNo") ?: return@forEach
|
||||
val lessonDate = Date.fromY_m_d(attendance.getString("Date"))
|
||||
val teacherId = attendance.getJsonObject("AddedBy")?.getLong("Id")
|
||||
val semester = attendance.getInt("Semester") ?: return@forEach
|
||||
val type = attendance.getJsonObject("Type")?.getLong("Id") ?: return@forEach
|
||||
val typeObject = data.attendanceTypes.get(type)
|
||||
val typeObject = data.attendanceTypes[type] ?: null
|
||||
val topic = typeObject?.name ?: ""
|
||||
|
||||
val startTime = data.lessonRanges.get(lessonNo).startTime
|
||||
val startTime = data.lessonRanges.get(lessonNo)?.startTime
|
||||
|
||||
val lesson = if (lessonId != -1L)
|
||||
data.librusLessons.singleOrNull { it.lessonId == lessonId }
|
||||
@ -52,19 +55,19 @@ class LibrusApiAttendances(override val data: DataLibrus,
|
||||
val attendanceObject = Attendance(
|
||||
profileId,
|
||||
id,
|
||||
lesson?.teacherId ?: -1,
|
||||
teacherId ?: lesson?.teacherId ?: -1,
|
||||
lesson?.subjectId ?: -1,
|
||||
semester,
|
||||
topic,
|
||||
lessonDate,
|
||||
startTime,
|
||||
typeObject.type
|
||||
startTime ?: Time(0, 0, 0),
|
||||
typeObject?.type ?: Attendance.TYPE_CUSTOM
|
||||
)
|
||||
|
||||
val addedDate = Date.fromIso(attendance.getString("AddDate") ?: return@forEach)
|
||||
|
||||
data.attendanceList.add(attendanceObject)
|
||||
if(typeObject.type != Attendance.TYPE_PRESENT) {
|
||||
if(typeObject?.type != Attendance.TYPE_PRESENT) {
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_ATTENDANCE,
|
||||
@ -77,7 +80,7 @@ class LibrusApiAttendances(override val data: DataLibrus,
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_ATTENDANCES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_LIBRUS_API_ATTENDANCES)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,9 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
|
||||
class LibrusApiBehaviourGradeCategories(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : LibrusApi(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiBehaviourGradeCategories"
|
||||
}
|
||||
@ -40,7 +42,7 @@ class LibrusApiBehaviourGradeCategories(override val data: DataLibrus,
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES, 1 * WEEK)
|
||||
onSuccess()
|
||||
onSuccess(ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user