forked from github/szkolny
Compare commits
103 Commits
code-refor
...
v3.9.12-de
Author | SHA1 | Date | |
---|---|---|---|
462b1df767 | |||
d17d2c8417 | |||
6892832fff | |||
66d54c7c45 | |||
d432685aa8 | |||
37f3d76fb8 | |||
7961a74995 | |||
9d590508ad | |||
f79b7eaf83 | |||
ae13bf946f | |||
f116c4f1f4 | |||
867c8920a8 | |||
6e6dd34872 | |||
0759468fa7 | |||
1b1fb09211 | |||
de414c912c | |||
d274a2fed1 | |||
285b7e9b9e | |||
875efcff7e | |||
07ae37167d | |||
f689f4d427 | |||
19bc2b8b37 | |||
673116e27e | |||
59fcb0a050 | |||
cd76f99bbf | |||
6a4994b9c2 | |||
63960c5e05 | |||
540afb6a28 | |||
ae10b8abbd | |||
db2ebab879 | |||
6ec3d062df | |||
86b6060a09 | |||
83d123e341 | |||
34061695f9 | |||
de68476442 | |||
678a81a44b | |||
cfb3096d53 | |||
9b7aca745a | |||
82852389fa | |||
ce06084e6f | |||
3ca051983f | |||
cd379e4175 | |||
62fdfa2b6f | |||
9866017f7e | |||
67f98b08c6 | |||
fdb5f7ec02 | |||
04c3c7ca6e | |||
f424315d97 | |||
c907a8df37 | |||
37ea65e3fc | |||
a3e5f824c8 | |||
e0c850a455 | |||
1c6815f708 | |||
9a20511935 | |||
965f5e73d9 | |||
13b58a1d56 | |||
0a3261b8b3 | |||
dbdfc7fdd8 | |||
56062f5bfa | |||
0cbba2eb45 | |||
aa84356dd6 | |||
efaad0a4dd | |||
71015c0137 | |||
85b5667a7e | |||
dfdc6817a1 | |||
058345b9c9 | |||
831b7876b4 | |||
729cf6f08e | |||
860a16b32d | |||
9f871c077b | |||
a8f89abf7d | |||
16102de619 | |||
472e768369 | |||
131a769c26 | |||
4a0a6c54e4 | |||
c83abe57d5 | |||
c6e2519dcc | |||
74db524db6 | |||
810976d976 | |||
eb0540b5cb | |||
124437fd73 | |||
69b512e3d1 | |||
29d74e14bd | |||
f42ec8435a | |||
1052b824db | |||
0742a6a74c | |||
d4e9e1730f | |||
4eeaa54a47 | |||
5fa7409317 | |||
0bcd190714 | |||
563f08b0ab | |||
1b75424604 | |||
01ac26e67b | |||
434ddd1342 | |||
3925496595 | |||
5711c02170 | |||
ca1c691bf0 | |||
39c8a743bb | |||
14cd548dff | |||
b72324805f | |||
a049effa61 | |||
23d55ec571 | |||
385fe21d16 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -81,3 +81,5 @@ lint/generated/
|
|||||||
lint/outputs/
|
lint/outputs/
|
||||||
lint/tmp/
|
lint/tmp/
|
||||||
# lint/reports/
|
# lint/reports/
|
||||||
|
|
||||||
|
app/schemas/
|
||||||
|
5
.idea/misc.xml
generated
5
.idea/misc.xml
generated
@ -6,8 +6,9 @@
|
|||||||
</configurations>
|
</configurations>
|
||||||
</component>
|
</component>
|
||||||
<component name="EntryPointsManager">
|
<component name="EntryPointsManager">
|
||||||
<list size="1">
|
<list size="2">
|
||||||
<item index="0" class="java.lang.String" itemvalue="org.greenrobot.eventbus.Subscribe" />
|
<item index="0" class="java.lang.String" itemvalue="androidx.databinding.BindingAdapter" />
|
||||||
|
<item index="1" class="java.lang.String" itemvalue="org.greenrobot.eventbus.Subscribe" />
|
||||||
</list>
|
</list>
|
||||||
</component>
|
</component>
|
||||||
<component name="NullableNotNullManager">
|
<component name="NullableNotNullManager">
|
||||||
|
@ -131,7 +131,7 @@ dependencies {
|
|||||||
implementation("com.github.ozodrukh:CircularReveal:2.0.1@aar") {transitive = true}
|
implementation("com.github.ozodrukh:CircularReveal:2.0.1@aar") {transitive = true}
|
||||||
implementation "com.heinrichreimersoftware:material-intro:1.5.8" // do not update
|
implementation "com.heinrichreimersoftware:material-intro:1.5.8" // do not update
|
||||||
implementation "com.jaredrummler:colorpicker:1.0.2"
|
implementation "com.jaredrummler:colorpicker:1.0.2"
|
||||||
implementation "com.squareup.okhttp3:okhttp:3.12.0"
|
implementation "com.squareup.okhttp3:okhttp:3.12.2"
|
||||||
implementation "com.theartofdev.edmodo:android-image-cropper:2.8.0" // do not update
|
implementation "com.theartofdev.edmodo:android-image-cropper:2.8.0" // do not update
|
||||||
implementation "com.wdullaer:materialdatetimepicker:4.1.2"
|
implementation "com.wdullaer:materialdatetimepicker:4.1.2"
|
||||||
implementation "com.yuyh.json:jsonviewer:1.0.6"
|
implementation "com.yuyh.json:jsonviewer:1.0.6"
|
||||||
@ -159,11 +159,17 @@ dependencies {
|
|||||||
//implementation 'com.github.wulkanowy:uonet-request-signer:master-SNAPSHOT'
|
//implementation 'com.github.wulkanowy:uonet-request-signer:master-SNAPSHOT'
|
||||||
//implementation 'com.github.kuba2k2.uonet-request-signer:android:master-63f094b14a-1'
|
//implementation 'com.github.kuba2k2.uonet-request-signer:android:master-63f094b14a-1'
|
||||||
|
|
||||||
implementation "org.redundent:kotlin-xml-builder:1.5.3"
|
//implementation "org.redundent:kotlin-xml-builder:1.5.3"
|
||||||
|
|
||||||
implementation "io.github.wulkanowy:signer-android:0.1.1"
|
implementation "io.github.wulkanowy:signer-android:0.1.1"
|
||||||
|
|
||||||
implementation "androidx.work:work-runtime-ktx:${versions.work}"
|
implementation "androidx.work:work-runtime-ktx:${versions.work}"
|
||||||
|
|
||||||
|
implementation 'com.hypertrack:hyperlog:0.0.10'
|
||||||
|
|
||||||
|
implementation 'com.github.kuba2k2:RecyclerTabLayout:700f980584'
|
||||||
|
|
||||||
|
implementation 'com.github.kuba2k2:Tachyon:551943a6b5'
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
@ -39,4 +39,13 @@
|
|||||||
|
|
||||||
-keep class okhttp3.** { *; }
|
-keep class okhttp3.** { *; }
|
||||||
|
|
||||||
-keep class com.google.android.material.tabs.** {*;}
|
-keep class com.google.android.material.tabs.** {*;}
|
||||||
|
|
||||||
|
# ServiceLoader support
|
||||||
|
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
|
||||||
|
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
|
||||||
|
|
||||||
|
# Most of volatile fields are updated with AFU and should not be mangled
|
||||||
|
-keepclassmembernames class kotlinx.** {
|
||||||
|
volatile <fields>;
|
||||||
|
}
|
9
app/sampledata/check/ic_check.xml
Normal file
9
app/sampledata/check/ic_check.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF4caf50"
|
||||||
|
android:pathData="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"/>
|
||||||
|
</vector>
|
13
app/sampledata/settings/ic_settings.xml
Normal file
13
app/sampledata/settings/ic_settings.xml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (c) Kuba Szczodrzyński 2019-11-25.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M12,8A4,4 0,0 1,16 12A4,4 0,0 1,12 16A4,4 0,0 1,8 12A4,4 0,0 1,12 8M12,10A2,2 0,0 0,10 12A2,2 0,0 0,12 14A2,2 0,0 0,14 12A2,2 0,0 0,12 10M10,22C9.75,22 9.54,21.82 9.5,21.58L9.13,18.93C8.5,18.68 7.96,18.34 7.44,17.94L4.95,18.95C4.73,19.03 4.46,18.95 4.34,18.73L2.34,15.27C2.21,15.05 2.27,14.78 2.46,14.63L4.57,12.97L4.5,12L4.57,11L2.46,9.37C2.27,9.22 2.21,8.95 2.34,8.73L4.34,5.27C4.46,5.05 4.73,4.96 4.95,5.05L7.44,6.05C7.96,5.66 8.5,5.32 9.13,5.07L9.5,2.42C9.54,2.18 9.75,2 10,2H14C14.25,2 14.46,2.18 14.5,2.42L14.87,5.07C15.5,5.32 16.04,5.66 16.56,6.05L19.05,5.05C19.27,4.96 19.54,5.05 19.66,5.27L21.66,8.73C21.79,8.95 21.73,9.22 21.54,9.37L19.43,11L19.5,12L19.43,13L21.54,14.63C21.73,14.78 21.79,15.05 21.66,15.27L19.66,18.73C19.54,18.95 19.27,19.04 19.05,18.95L16.56,17.95C16.04,18.34 15.5,18.68 14.87,18.93L14.5,21.58C14.46,21.82 14.25,22 14,22H10M11.25,4L10.88,6.61C9.68,6.86 8.62,7.5 7.85,8.39L5.44,7.35L4.69,8.65L6.8,10.2C6.4,11.37 6.4,12.64 6.8,13.8L4.68,15.36L5.43,16.66L7.86,15.62C8.63,16.5 9.68,17.14 10.87,17.38L11.24,20H12.76L13.13,17.39C14.32,17.14 15.37,16.5 16.14,15.62L18.57,16.66L19.32,15.36L17.2,13.81C17.6,12.64 17.6,11.37 17.2,10.2L19.31,8.65L18.56,7.35L16.15,8.39C15.38,7.5 14.32,6.86 13.12,6.62L12.75,4H11.25Z"/>
|
||||||
|
</vector>
|
@ -15,10 +15,14 @@
|
|||||||
android:theme="@style/SplashTheme"
|
android:theme="@style/SplashTheme"
|
||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
tools:ignore="UnusedAttribute">
|
tools:ignore="UnusedAttribute">
|
||||||
|
<activity
|
||||||
|
android:name=".ui.modules.login.LoginLibrusCaptchaActivity"
|
||||||
|
android:theme="@android:style/Theme.Dialog"
|
||||||
|
android:excludeFromRecents="true"/>
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:label="@string/app_name"
|
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
|
android:label="@string/app_name"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/SplashTheme">
|
android:theme="@style/SplashTheme">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
@ -29,7 +33,7 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name="pl.szczodrzynski.edziennik.ui.modules.messages.MessagesComposeActivity"
|
android:name=".ui.modules.messages.MessagesComposeActivity"
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:label="@string/messages_compose_title"
|
android:label="@string/messages_compose_title"
|
||||||
android:theme="@style/AppTheme.Black" />
|
android:theme="@style/AppTheme.Black" />
|
||||||
@ -39,7 +43,7 @@
|
|||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/AppTheme" />
|
android:theme="@style/AppTheme" />
|
||||||
<activity
|
<activity
|
||||||
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity"
|
android:name=".ui.modules.login.LoginActivity"
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/AppTheme.Light" />
|
android:theme="@style/AppTheme.Light" />
|
||||||
@ -101,22 +105,23 @@
|
|||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:noHistory="true"
|
android:noHistory="true"
|
||||||
android:theme="@style/AppTheme.NoDisplay" />
|
android:theme="@style/AppTheme.NoDisplay" />
|
||||||
|
<activity android:name=".widgets.timetable.LessonDialogActivity"
|
||||||
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:noHistory="true"
|
||||||
|
android:theme="@style/AppTheme.NoDisplay" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.modules.settings.SettingsLicenseActivity"
|
android:name=".ui.modules.settings.SettingsLicenseActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:theme="@style/AppTheme" />
|
android:theme="@style/AppTheme" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
|
android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:theme="@style/Base.Theme.AppCompat" />
|
android:theme="@style/Base.Theme.AppCompat" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.modules.webpush.WebPushConfigActivity"
|
android:name=".ui.modules.webpush.WebPushConfigActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:theme="@style/AppTheme.Dark" />
|
android:theme="@style/AppTheme.Dark" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.modules.home.CounterActivity"
|
android:name=".ui.modules.home.CounterActivity"
|
||||||
android:theme="@style/AppTheme.Black" />
|
android:theme="@style/AppTheme.Black" />
|
||||||
@ -169,7 +174,6 @@
|
|||||||
android:name="android.appwidget.provider"
|
android:name="android.appwidget.provider"
|
||||||
android:resource="@xml/widget_notifications_info" />
|
android:resource="@xml/widget_notifications_info" />
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".widgets.luckynumber.WidgetLuckyNumber"
|
android:name=".widgets.luckynumber.WidgetLuckyNumber"
|
||||||
android:label="@string/widget_lucky_number_title">
|
android:label="@string/widget_lucky_number_title">
|
||||||
@ -188,7 +192,6 @@
|
|||||||
<action android:name="android.intent.action.USER_PRESENT" />
|
<action android:name="android.intent.action.USER_PRESENT" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<receiver android:name=".receivers.BootReceiver">
|
<receiver android:name=".receivers.BootReceiver">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
@ -196,14 +199,7 @@
|
|||||||
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
<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>
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".sync.FirebaseBroadcastReceiver"
|
android:name=".sync.FirebaseBroadcastReceiver"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
@ -212,6 +208,23 @@
|
|||||||
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
|
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name=".receivers.SzkolnyReceiver"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="pl.szczodrzynski.edziennik.SZKOLNY_MAIN" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<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
|
<service
|
||||||
android:name=".widgets.timetable.WidgetTimetableService"
|
android:name=".widgets.timetable.WidgetTimetableService"
|
||||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||||
@ -222,14 +235,6 @@
|
|||||||
|
|
||||||
<service android:name=".Notifier$GetDataRetryService" />
|
<service android:name=".Notifier$GetDataRetryService" />
|
||||||
|
|
||||||
<receiver
|
|
||||||
android:name=".receivers.SzkolnyReceiver"
|
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="pl.szczodrzynski.edziennik.SZKOLNY_MAIN" />
|
|
||||||
</intent-filter>
|
|
||||||
</receiver>
|
|
||||||
|
|
||||||
<service android:name=".api.v2.ApiService" />
|
<service android:name=".api.v2.ApiService" />
|
||||||
</application>
|
</application>
|
||||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||||
@ -244,4 +249,4 @@
|
|||||||
|
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
@ -31,57 +31,11 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<h3>Wersja 3.1.1, 2019-10-09</h3>
|
<h3>Wersja 4.0, 2019-jeszcze-nie-wiem-kiedy</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Librus: poprawiona synchronizacja kategorii i kolorów ocen.</li>
|
<li>UWAGA. To jest wersja in-development. Wiele funkcji może nie działać prawidłowo (lub wcale), co oznacza tylko że nie zostały jeszcze przeniesione
|
||||||
<li>Zmieniony kolor dolnego paska w ciemnym motywie.</li>
|
z wersji 3.x. Proszę o cierpliwość oraz <b>nie udostępnianie</b> tej wersji <u>nikomu</u>.</li>
|
||||||
<li>Zaktualizowany licznik czasu lekcji.</li>
|
<li>Bardzo dużo zmian</li>
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3>Wersja 3.1, 2019-09-29</h3>
|
|
||||||
<ul>
|
|
||||||
<li>Poprawiony interfejs zadań domowych.</li>
|
|
||||||
<li>Librus: wyświetlanie komentarzy ocen.</li>
|
|
||||||
<li>Librus: wyświetlanie nieobecności nauczycieli w Terminarzu.</li>
|
|
||||||
<li>Librus: usprawniona synchronizacja ocen.</li>
|
|
||||||
<li>Poprawki angielskiego tłumaczenia.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3>Wersja 3.0.3, 2019-09-26</h3>
|
|
||||||
<ul>
|
|
||||||
<li>Librus: poprawka kilku błędów synchronizacji.</li>
|
|
||||||
<li>Vulcan: prawidłowe oznaczanie wiadomości jako przeczytana.</li>
|
|
||||||
<li>Vulcan: poprawiona synchronizacja wiadomości i frekwencji.</li>
|
|
||||||
<li>Vulcan: poprawka błędów logowania.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3>Wersja 3.0.2, 2019-09-24</h3>
|
|
||||||
<ul>
|
|
||||||
<li>Librus: pobieranie Bieżących ocen opisowych.</li>
|
|
||||||
<li>Poprawki UI: kolor ikon paska statusu w jasnym motywie.</li>
|
|
||||||
<li>Poprawka braku skanera QR do przekazywania powiadomień.</li>
|
|
||||||
<li>Poprawka wyboru koloru i daty własnego wydarzenia, które crashowały aplikację.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3>Wersja 3.0.1, 2019-09-19</h3>
|
|
||||||
<ul>
|
|
||||||
<li>Librus: Poprawa błędu synchronizacji.</li>
|
|
||||||
<li>Poprawki UI związane z paskiem nawigacji.</li>
|
|
||||||
<li>Mobidziennik: Pobieranie ocen w niektórych przedmiotach.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3>Wersja 3.0, 2019-09-13</h3>
|
|
||||||
<ul>
|
|
||||||
<li><b>Nowy wygląd i sposób nawigacji</b> w całej aplikacji.</li>
|
|
||||||
<li>Menu nawigacji można teraz otworzyć przyciskiem na <b>dolnym pasku</b>. Pociągnięcie w górę tego paska wyświetla <b>menu kontekstowe</b> dotyczące danego widoku.</li>
|
|
||||||
<li>Założyliśmy serwer Discord! <a href="https://discord.gg/n9e8pWr">https://discord.gg/n9e8pWr</a></li>
|
|
||||||
<br>
|
|
||||||
<li>Librus: poprawka powielonych ogłoszeń szkolnych.</li>
|
|
||||||
<li>Naprawiłem błąd nieskończonej synchronizacji w Vulcanie.</li>
|
|
||||||
<li>Naprawiłem crash launchera przy dodaniu widgetu.</li>
|
|
||||||
<li>Naprawiłem częste crashe związane z widokiem kalendarza.</li>
|
|
||||||
<li>Nowe, ładniejsze (choć trochę) motywy kolorów.</li>
|
|
||||||
<li>Dużo drobnych poprawek UI i działania aplikacji.</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<!--<i>
|
<!--<i>
|
||||||
|
@ -36,6 +36,7 @@ import com.google.gson.Gson;
|
|||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonSyntaxException;
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
import com.hypertrack.hyperlog.HyperLog;
|
||||||
import com.mikepenz.iconics.Iconics;
|
import com.mikepenz.iconics.Iconics;
|
||||||
import com.mikepenz.iconics.IconicsColor;
|
import com.mikepenz.iconics.IconicsColor;
|
||||||
import com.mikepenz.iconics.IconicsDrawable;
|
import com.mikepenz.iconics.IconicsDrawable;
|
||||||
@ -67,11 +68,6 @@ import me.leolin.shortcutbadger.ShortcutBadger;
|
|||||||
import okhttp3.ConnectionSpec;
|
import okhttp3.ConnectionSpec;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.TlsVersion;
|
import okhttp3.TlsVersion;
|
||||||
import pl.szczodrzynski.edziennik.data.api.Edziennik;
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Iuczniowie;
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Librus;
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Mobidziennik;
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Vulcan;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.AppDb;
|
import pl.szczodrzynski.edziennik.data.db.AppDb;
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.debuglog.DebugLog;
|
import pl.szczodrzynski.edziennik.data.db.modules.debuglog.DebugLog;
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
||||||
@ -81,6 +77,7 @@ import pl.szczodrzynski.edziennik.network.NetworkUtils;
|
|||||||
import pl.szczodrzynski.edziennik.network.TLSSocketFactory;
|
import pl.szczodrzynski.edziennik.network.TLSSocketFactory;
|
||||||
import pl.szczodrzynski.edziennik.sync.SyncWorker;
|
import pl.szczodrzynski.edziennik.sync.SyncWorker;
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity;
|
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.PermissionChecker;
|
||||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||||
@ -139,12 +136,6 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
|||||||
public PersistentCookieJar cookieJar;
|
public PersistentCookieJar cookieJar;
|
||||||
public OkHttpClient http;
|
public OkHttpClient http;
|
||||||
public OkHttpClient httpLazy;
|
public OkHttpClient httpLazy;
|
||||||
//public Jakdojade apiJakdojade;
|
|
||||||
public Edziennik apiEdziennik;
|
|
||||||
public Mobidziennik apiMobidziennik;
|
|
||||||
public Iuczniowie apiIuczniowie;
|
|
||||||
public Librus apiLibrus;
|
|
||||||
public Vulcan apiVulcan;
|
|
||||||
|
|
||||||
public SharedPreferences appSharedPrefs; // sharedPreferences for APPCONFIG + JOBS STORE
|
public SharedPreferences appSharedPrefs; // sharedPreferences for APPCONFIG + JOBS STORE
|
||||||
public AppConfig appConfig; // APPCONFIG: common for all profiles
|
public AppConfig appConfig; // APPCONFIG: common for all profiles
|
||||||
@ -202,12 +193,6 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
|||||||
db = AppDb.getDatabase(this);
|
db = AppDb.getDatabase(this);
|
||||||
gson = new Gson();
|
gson = new Gson();
|
||||||
networkUtils = new NetworkUtils(this);
|
networkUtils = new NetworkUtils(this);
|
||||||
apiEdziennik = new Edziennik(this);
|
|
||||||
//apiJakdojade = new Jakdojade(this);
|
|
||||||
apiMobidziennik = new Mobidziennik(this);
|
|
||||||
apiIuczniowie = new Iuczniowie(this);
|
|
||||||
apiLibrus = new Librus(this);
|
|
||||||
apiVulcan = new Vulcan(this);
|
|
||||||
|
|
||||||
Iconics.init(getApplicationContext());
|
Iconics.init(getApplicationContext());
|
||||||
Iconics.registerFont(SzkolnyFont.INSTANCE);
|
Iconics.registerFont(SzkolnyFont.INSTANCE);
|
||||||
@ -294,6 +279,10 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (App.devMode || BuildConfig.DEBUG) {
|
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);
|
ChuckerCollector chuckerCollector = new ChuckerCollector(this, true, RetentionManager.Period.ONE_HOUR);
|
||||||
ChuckerInterceptor chuckerInterceptor = new ChuckerInterceptor(this, chuckerCollector);
|
ChuckerInterceptor chuckerInterceptor = new ChuckerInterceptor(this, chuckerCollector);
|
||||||
httpBuilder.addInterceptor(chuckerInterceptor);
|
httpBuilder.addInterceptor(chuckerInterceptor);
|
||||||
|
21
app/src/main/java/pl/szczodrzynski/edziennik/Binding.java
Normal file
21
app/src/main/java/pl/szczodrzynski/edziennik/Binding.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,20 +4,38 @@ import android.Manifest
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.graphics.Typeface
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.text.*
|
||||||
|
import android.text.style.ForegroundColorSpan
|
||||||
|
import android.text.style.StrikethroughSpan
|
||||||
|
import android.text.style.StyleSpan
|
||||||
import android.util.LongSparseArray
|
import android.util.LongSparseArray
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
|
import android.util.TypedValue
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.CompoundButton
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.annotation.*
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.core.util.forEach
|
import androidx.core.util.forEach
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
import com.google.gson.JsonArray
|
import com.google.gson.JsonArray
|
||||||
import com.google.gson.JsonElement
|
import com.google.gson.JsonElement
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import im.wangchao.mhttp.Response
|
import im.wangchao.mhttp.Response
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||||
import pl.szczodrzynski.navlib.R
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
import pl.szczodrzynski.navlib.getColorFromRes
|
import pl.szczodrzynski.navlib.getColorFromRes
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -84,6 +102,15 @@ fun String.swapFirstLastName(): String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun String.getFirstLastName(): Pair<String, String>? {
|
||||||
|
return this.split(" ").let {
|
||||||
|
if (it.size >= 2) Pair(it[0], it[1])
|
||||||
|
else null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.getLastFirstName() = this.getFirstLastName()
|
||||||
|
|
||||||
fun changeStringCase(s: String): String {
|
fun changeStringCase(s: String): String {
|
||||||
val delimiters = " '-/"
|
val delimiters = " '-/"
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
@ -142,8 +169,9 @@ fun colorFromName(context: Context, name: String?): Int {
|
|||||||
return context.getColorFromRes(color)
|
return context.getColorFromRes(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MutableList<out Profile>.filterOutArchived() {
|
fun MutableList<Profile>.filterOutArchived(): MutableList<Profile> {
|
||||||
this.removeAll { it.archived }
|
this.removeAll { it.archived }
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Activity.isStoragePermissionGranted(): Boolean {
|
fun Activity.isStoragePermissionGranted(): Boolean {
|
||||||
@ -326,4 +354,236 @@ fun String.crc32(): Long {
|
|||||||
return crc.value
|
return crc.value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Long.formatDate(format: String = "yyyy-MM-dd HH:mm:ss"): String = SimpleDateFormat(format).format(this)
|
fun Long.formatDate(format: String = "yyyy-MM-dd HH:mm:ss"): String = SimpleDateFormat(format).format(this)
|
||||||
|
|
||||||
|
fun CharSequence?.asColoredSpannable(colorInt: Int): Spannable {
|
||||||
|
val spannable = SpannableString(this)
|
||||||
|
spannable.setSpan(ForegroundColorSpan(colorInt), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
return spannable
|
||||||
|
}
|
||||||
|
fun CharSequence?.asStrikethroughSpannable(): Spannable {
|
||||||
|
val spannable = SpannableString(this)
|
||||||
|
spannable.setSpan(StrikethroughSpan(), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
return spannable
|
||||||
|
}
|
||||||
|
fun CharSequence?.asItalicSpannable(): Spannable {
|
||||||
|
val spannable = SpannableString(this)
|
||||||
|
spannable.setSpan(StyleSpan(Typeface.ITALIC), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
return spannable
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new read-only list only of those given elements, that are not empty.
|
||||||
|
* Applies for CharSequence and descendants.
|
||||||
|
*/
|
||||||
|
fun <T : CharSequence> listOfNotEmpty(vararg elements: T): List<T> = elements.filterNot { it.isEmpty() }
|
||||||
|
|
||||||
|
fun List<CharSequence?>.concat(delimiter: String? = null): CharSequence {
|
||||||
|
if (this.isEmpty()) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.size == 1) {
|
||||||
|
return this[0] ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var spanned = false
|
||||||
|
for (piece in this) {
|
||||||
|
if (piece is Spanned) {
|
||||||
|
spanned = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var first = true
|
||||||
|
if (spanned) {
|
||||||
|
val ssb = SpannableStringBuilder()
|
||||||
|
for (piece in this) {
|
||||||
|
if (piece == null)
|
||||||
|
continue
|
||||||
|
if (!first && delimiter != null)
|
||||||
|
ssb.append(delimiter)
|
||||||
|
first = false
|
||||||
|
ssb.append(piece)
|
||||||
|
}
|
||||||
|
return SpannedString(ssb)
|
||||||
|
} else {
|
||||||
|
val sb = StringBuilder()
|
||||||
|
for (piece in this) {
|
||||||
|
if (piece == null)
|
||||||
|
continue
|
||||||
|
if (!first && delimiter != null)
|
||||||
|
sb.append(delimiter)
|
||||||
|
first = false
|
||||||
|
sb.append(piece)
|
||||||
|
}
|
||||||
|
return sb.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun TextView.setText(@StringRes resid: Int, vararg formatArgs: Any) {
|
||||||
|
text = context.getString(resid, *formatArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun JsonObject(vararg properties: Pair<String, Any?>): JsonObject {
|
||||||
|
return JsonObject().apply {
|
||||||
|
for (property in properties) {
|
||||||
|
when (property.second) {
|
||||||
|
is JsonElement -> add(property.first, property.second as JsonElement?)
|
||||||
|
is String -> addProperty(property.first, property.second as String?)
|
||||||
|
is Char -> addProperty(property.first, property.second as Char?)
|
||||||
|
is Number -> addProperty(property.first, property.second as Number?)
|
||||||
|
is Boolean -> addProperty(property.first, property.second as Boolean?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun JsonArray?.isNullOrEmpty(): Boolean = (this?.size() ?: 0) == 0
|
||||||
|
fun JsonArray.isEmpty(): Boolean = this.size() == 0
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
inline fun <T : View> T.onClick(crossinline onClickListener: (v: T) -> Unit) {
|
||||||
|
setOnClickListener { v: View ->
|
||||||
|
onClickListener(v as T)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
inline fun <T : CompoundButton> T.onChange(crossinline onChangeListener: (v: T, isChecked: Boolean) -> Unit) {
|
||||||
|
setOnCheckedChangeListener { buttonView, isChecked ->
|
||||||
|
onChangeListener(buttonView as T, isChecked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> LiveData<T>.observeOnce(lifecycleOwner: LifecycleOwner, observer: Observer<T>) {
|
||||||
|
observe(lifecycleOwner, object : Observer<T> {
|
||||||
|
override fun onChanged(t: T?) {
|
||||||
|
observer.onChanged(t)
|
||||||
|
removeObserver(this)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a value in dp to pixels.
|
||||||
|
*/
|
||||||
|
val Int.dp: Int
|
||||||
|
get() = (this * Resources.getSystem().displayMetrics.density).toInt()
|
||||||
|
/**
|
||||||
|
* Convert a value in pixels to dp.
|
||||||
|
*/
|
||||||
|
val Int.px: Int
|
||||||
|
get() = (this / Resources.getSystem().displayMetrics.density).toInt()
|
||||||
|
|
||||||
|
@ColorInt
|
||||||
|
fun @receiver:AttrRes Int.resolveAttr(context: Context?): Int {
|
||||||
|
val typedValue = TypedValue()
|
||||||
|
context?.theme?.resolveAttribute(this, typedValue, true)
|
||||||
|
return typedValue.data
|
||||||
|
}
|
||||||
|
@ColorInt
|
||||||
|
fun @receiver:ColorRes Int.resolveColor(context: Context): Int {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
context.resources.getColor(this, context.theme)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
context.resources.getColor(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun @receiver:DrawableRes Int.resolveDrawable(context: Context): Drawable {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
context.resources.getDrawable(this, context.theme)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
context.resources.getDrawable(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun View.findParentById(targetId: Int): View? {
|
||||||
|
if (id == targetId) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
val viewParent = this.parent ?: return null
|
||||||
|
if (viewParent is View) {
|
||||||
|
return viewParent.findParentById(targetId)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun CoroutineScope.startCoroutineTimer(delayMillis: Long = 0, repeatMillis: Long = 0, action: () -> Unit) = launch {
|
||||||
|
delay(delayMillis)
|
||||||
|
if (repeatMillis > 0) {
|
||||||
|
while (true) {
|
||||||
|
action()
|
||||||
|
delay(repeatMillis)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun Time?.compareTo(other: Time?): Int {
|
||||||
|
if (this == null && other == null)
|
||||||
|
return 0
|
||||||
|
if (this == null)
|
||||||
|
return -1
|
||||||
|
if (other == null)
|
||||||
|
return 1
|
||||||
|
return this.compareTo(other)
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun StringBuilder.plusAssign(str: String?) {
|
||||||
|
this.append(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.timeTill(time: Int, delimiter: String = " "): String {
|
||||||
|
val parts = mutableListOf<Pair<Int, Int>>()
|
||||||
|
|
||||||
|
val hours = time / 3600
|
||||||
|
val minutes = (time - hours*3600) / 60
|
||||||
|
val seconds = time - minutes*60 - hours*3600
|
||||||
|
|
||||||
|
var prefixAdded = false
|
||||||
|
if (hours > 0) {
|
||||||
|
if (!prefixAdded) parts += R.plurals.time_till_text to hours; prefixAdded = true
|
||||||
|
parts += R.plurals.time_till_hours to hours
|
||||||
|
}
|
||||||
|
if (minutes > 0) {
|
||||||
|
if (!prefixAdded) parts += R.plurals.time_till_text to minutes; prefixAdded = true
|
||||||
|
parts += R.plurals.time_till_minutes to minutes
|
||||||
|
}
|
||||||
|
if (hours == 0 && minutes < 10) {
|
||||||
|
if (!prefixAdded) parts += R.plurals.time_till_text to seconds; prefixAdded = true
|
||||||
|
parts += R.plurals.time_till_seconds to seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.joinToString(delimiter) { resources.getQuantityString(it.first, it.second, it.second) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.timeLeft(time: Int, delimiter: String = " "): String {
|
||||||
|
val parts = mutableListOf<Pair<Int, Int>>()
|
||||||
|
|
||||||
|
val hours = time / 3600
|
||||||
|
val minutes = (time - hours*3600) / 60
|
||||||
|
val seconds = time - minutes*60 - hours*3600
|
||||||
|
|
||||||
|
var prefixAdded = false
|
||||||
|
if (hours > 0) {
|
||||||
|
if (!prefixAdded) parts += R.plurals.time_left_text to hours
|
||||||
|
prefixAdded = true
|
||||||
|
parts += R.plurals.time_left_hours to hours
|
||||||
|
}
|
||||||
|
if (minutes > 0) {
|
||||||
|
if (!prefixAdded) parts += R.plurals.time_left_text to minutes
|
||||||
|
prefixAdded = true
|
||||||
|
parts += R.plurals.time_left_minutes to minutes
|
||||||
|
}
|
||||||
|
if (hours == 0 && minutes < 10) {
|
||||||
|
if (!prefixAdded) parts += R.plurals.time_left_text to seconds
|
||||||
|
prefixAdded = true
|
||||||
|
parts += R.plurals.time_left_seconds to seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.joinToString(delimiter) { resources.getQuantityString(it.first, it.second, it.second) }
|
||||||
|
}
|
||||||
|
@ -2,10 +2,15 @@ package pl.szczodrzynski.edziennik
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.ActivityManager
|
import android.app.ActivityManager
|
||||||
import android.content.*
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.content.pm.PackageManager
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.graphics.drawable.BitmapDrawable
|
import android.graphics.drawable.BitmapDrawable
|
||||||
import android.os.*
|
import android.os.*
|
||||||
|
import android.provider.Settings
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
@ -31,39 +36,41 @@ import org.greenrobot.eventbus.Subscribe
|
|||||||
import org.greenrobot.eventbus.ThreadMode
|
import org.greenrobot.eventbus.ThreadMode
|
||||||
import pl.droidsonroids.gif.GifDrawable
|
import pl.droidsonroids.gif.GifDrawable
|
||||||
import pl.szczodrzynski.edziennik.App.APP_URL
|
import pl.szczodrzynski.edziennik.App.APP_URL
|
||||||
import pl.szczodrzynski.edziennik.api.v2.ApiService
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.events.*
|
import pl.szczodrzynski.edziennik.api.v2.events.*
|
||||||
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask
|
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata.*
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata.*
|
||||||
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
|
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
|
||||||
import pl.szczodrzynski.edziennik.network.ServerRequest
|
import pl.szczodrzynski.edziennik.network.ServerRequest
|
||||||
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
|
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
|
||||||
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
|
||||||
|
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.agenda.AgendaFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment
|
import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.attendance.AttendanceFragment
|
import pl.szczodrzynski.edziennik.ui.modules.attendance.AttendanceFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.base.DebugFragment
|
import pl.szczodrzynski.edziennik.ui.modules.base.DebugFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment
|
import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment
|
||||||
|
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment
|
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment
|
import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesFragment
|
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.grades.editor.GradesEditorFragment
|
import pl.szczodrzynski.edziennik.ui.modules.grades.editor.GradesEditorFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment
|
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragmentV2
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment
|
import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
|
import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesDetailsFragment
|
import pl.szczodrzynski.edziennik.ui.modules.messages.MessageFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
|
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsFragment
|
import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment
|
import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsNewFragment
|
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsNewFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.timetable.TimetableFragment
|
import pl.szczodrzynski.edziennik.ui.modules.timetable.v2.TimetableFragment
|
||||||
import pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoTouch
|
import pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoTouch
|
||||||
import pl.szczodrzynski.edziennik.utils.Themes
|
import pl.szczodrzynski.edziennik.utils.Themes
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.dpToPx
|
import pl.szczodrzynski.edziennik.utils.Utils.dpToPx
|
||||||
|
import pl.szczodrzynski.edziennik.utils.appManagerIntentList
|
||||||
import pl.szczodrzynski.edziennik.utils.models.NavTarget
|
import pl.szczodrzynski.edziennik.utils.models.NavTarget
|
||||||
import pl.szczodrzynski.navlib.*
|
import pl.szczodrzynski.navlib.*
|
||||||
import pl.szczodrzynski.navlib.SystemBarsUtil.Companion.COLOR_HALF_TRANSPARENT
|
import pl.szczodrzynski.navlib.SystemBarsUtil.Companion.COLOR_HALF_TRANSPARENT
|
||||||
@ -115,9 +122,9 @@ class MainActivity : AppCompatActivity() {
|
|||||||
val list: MutableList<NavTarget> = mutableListOf()
|
val list: MutableList<NavTarget> = mutableListOf()
|
||||||
|
|
||||||
// home item
|
// home item
|
||||||
list += NavTarget(DRAWER_ITEM_HOME, R.string.menu_home_page, HomeFragment::class)
|
list += NavTarget(DRAWER_ITEM_HOME, R.string.menu_home_page, HomeFragmentV2::class)
|
||||||
.withTitle(R.string.app_name)
|
.withTitle(R.string.app_name)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_home)
|
.withIcon(CommunityMaterial.Icon2.cmd_home_outline)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
.isStatic(true)
|
.isStatic(true)
|
||||||
.withPopToHome(false)
|
.withPopToHome(false)
|
||||||
@ -128,50 +135,50 @@ class MainActivity : AppCompatActivity() {
|
|||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_ITEM_AGENDA, R.string.menu_agenda, AgendaFragment::class)
|
list += NavTarget(DRAWER_ITEM_AGENDA, R.string.menu_agenda, AgendaFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_calendar)
|
.withIcon(CommunityMaterial.Icon.cmd_calendar_outline)
|
||||||
.withBadgeTypeId(TYPE_EVENT)
|
.withBadgeTypeId(TYPE_EVENT)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesFragment::class)
|
list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_numeric_5_box)
|
.withIcon(CommunityMaterial.Icon2.cmd_numeric_5_box_outline)
|
||||||
.withBadgeTypeId(TYPE_GRADE)
|
.withBadgeTypeId(TYPE_GRADE)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_ITEM_MESSAGES, R.string.menu_messages, MessagesFragment::class)
|
list += NavTarget(DRAWER_ITEM_MESSAGES, R.string.menu_messages, MessagesFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_email)
|
.withIcon(CommunityMaterial.Icon.cmd_email_outline)
|
||||||
.withBadgeTypeId(TYPE_MESSAGE)
|
.withBadgeTypeId(TYPE_MESSAGE)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_ITEM_HOMEWORK, R.string.menu_homework, HomeworkFragment::class)
|
list += NavTarget(DRAWER_ITEM_HOMEWORK, R.string.menu_homework, HomeworkFragment::class)
|
||||||
.withIcon(SzkolnyFont.Icon.szf_file_document_edit)
|
.withIcon(SzkolnyFont.Icon.szf_notebook_outline)
|
||||||
.withBadgeTypeId(TYPE_HOMEWORK)
|
.withBadgeTypeId(TYPE_HOMEWORK)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_ITEM_BEHAVIOUR, R.string.menu_notices, BehaviourFragment::class)
|
list += NavTarget(DRAWER_ITEM_BEHAVIOUR, R.string.menu_notices, BehaviourFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_message_alert)
|
.withIcon(CommunityMaterial.Icon.cmd_emoticon_outline)
|
||||||
.withBadgeTypeId(TYPE_NOTICE)
|
.withBadgeTypeId(TYPE_NOTICE)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_ITEM_ATTENDANCE, R.string.menu_attendance, AttendanceFragment::class)
|
list += NavTarget(DRAWER_ITEM_ATTENDANCE, R.string.menu_attendance, AttendanceFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_calendar_remove)
|
.withIcon(CommunityMaterial.Icon.cmd_calendar_remove_outline)
|
||||||
.withBadgeTypeId(TYPE_ATTENDANCE)
|
.withBadgeTypeId(TYPE_ATTENDANCE)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_ITEM_ANNOUNCEMENTS, R.string.menu_announcements, AnnouncementsFragment::class)
|
list += NavTarget(DRAWER_ITEM_ANNOUNCEMENTS, R.string.menu_announcements, AnnouncementsFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_bulletin_board)
|
.withIcon(CommunityMaterial.Icon.cmd_bullhorn_outline)
|
||||||
.withBadgeTypeId(TYPE_ANNOUNCEMENT)
|
.withBadgeTypeId(TYPE_ANNOUNCEMENT)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
|
|
||||||
|
|
||||||
// static drawer items
|
// static drawer items
|
||||||
list += NavTarget(DRAWER_ITEM_NOTIFICATIONS, R.string.menu_notifications, NotificationsFragment::class)
|
list += NavTarget(DRAWER_ITEM_NOTIFICATIONS, R.string.menu_notifications, NotificationsFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_bell_ring)
|
.withIcon(CommunityMaterial.Icon.cmd_bell_ring_outline)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
.isStatic(true)
|
.isStatic(true)
|
||||||
.isBelowSeparator(true)
|
.isBelowSeparator(true)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsNewFragment::class)
|
list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsNewFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_settings)
|
.withIcon(CommunityMaterial.Icon2.cmd_settings_outline)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
.isStatic(true)
|
.isStatic(true)
|
||||||
.isBelowSeparator(true)
|
.isBelowSeparator(true)
|
||||||
@ -190,7 +197,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
.isInProfileList(false)
|
.isInProfileList(false)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_PROFILE_SYNC_ALL, R.string.menu_sync_all, null)
|
list += NavTarget(DRAWER_PROFILE_SYNC_ALL, R.string.menu_sync_all, null)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_sync)
|
.withIcon(CommunityMaterial.Icon.cmd_download_outline)
|
||||||
.isInProfileList(true)
|
.isInProfileList(true)
|
||||||
|
|
||||||
|
|
||||||
@ -198,7 +205,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
list += NavTarget(TARGET_GRADES_EDITOR, R.string.menu_grades_editor, GradesEditorFragment::class)
|
list += NavTarget(TARGET_GRADES_EDITOR, R.string.menu_grades_editor, GradesEditorFragment::class)
|
||||||
list += NavTarget(TARGET_HELP, R.string.menu_help, HelpFragment::class)
|
list += NavTarget(TARGET_HELP, R.string.menu_help, HelpFragment::class)
|
||||||
list += NavTarget(TARGET_FEEDBACK, R.string.menu_feedback, FeedbackFragment::class)
|
list += NavTarget(TARGET_FEEDBACK, R.string.menu_feedback, FeedbackFragment::class)
|
||||||
list += NavTarget(TARGET_MESSAGES_DETAILS, R.string.menu_message, MessagesDetailsFragment::class)
|
list += NavTarget(TARGET_MESSAGES_DETAILS, R.string.menu_message, MessageFragment::class)
|
||||||
list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class)
|
list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class)
|
||||||
|
|
||||||
list
|
list
|
||||||
@ -209,6 +216,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
val navView: NavView by lazy { b.navView }
|
val navView: NavView by lazy { b.navView }
|
||||||
val drawer: NavDrawer by lazy { navView.drawer }
|
val drawer: NavDrawer by lazy { navView.drawer }
|
||||||
val bottomSheet: NavBottomSheet by lazy { navView.bottomSheet }
|
val bottomSheet: NavBottomSheet by lazy { navView.bottomSheet }
|
||||||
|
val errorSnackbar: ErrorSnackbar by lazy { ErrorSnackbar(this) }
|
||||||
|
|
||||||
val swipeRefreshLayout: SwipeRefreshLayoutNoTouch by lazy { b.swipeRefreshLayout }
|
val swipeRefreshLayout: SwipeRefreshLayoutNoTouch by lazy { b.swipeRefreshLayout }
|
||||||
|
|
||||||
@ -241,6 +249,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
setContentView(b.root)
|
setContentView(b.root)
|
||||||
|
|
||||||
|
errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
|
||||||
|
|
||||||
navLoading = true
|
navLoading = true
|
||||||
|
|
||||||
b.navView.apply {
|
b.navView.apply {
|
||||||
@ -340,7 +350,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
if (!profileListEmpty) {
|
if (!profileListEmpty) {
|
||||||
handleIntent(intent?.extras)
|
handleIntent(intent?.extras)
|
||||||
}
|
}
|
||||||
app.db.profileDao().getAllFull().observe(this, Observer { profiles ->
|
app.db.profileDao().allFull.observe(this, Observer { profiles ->
|
||||||
// TODO fix weird -1 profiles ???
|
// TODO fix weird -1 profiles ???
|
||||||
profiles.removeAll { it.id < 0 }
|
profiles.removeAll { it.id < 0 }
|
||||||
drawer.setProfileList(profiles)
|
drawer.setProfileList(profiles)
|
||||||
@ -357,7 +367,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
if (app.profile != null)
|
if (app.profile != null)
|
||||||
setDrawerItems()
|
setDrawerItems()
|
||||||
|
|
||||||
app.db.metadataDao().getUnreadCounts().observe(this, Observer { unreadCounters ->
|
app.db.metadataDao().unreadCounts.observe(this, Observer { unreadCounters ->
|
||||||
unreadCounters.map {
|
unreadCounters.map {
|
||||||
it.type = it.thingType
|
it.type = it.thingType
|
||||||
}
|
}
|
||||||
@ -366,6 +376,11 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
b.swipeRefreshLayout.isEnabled = true
|
b.swipeRefreshLayout.isEnabled = true
|
||||||
b.swipeRefreshLayout.setOnRefreshListener { this.syncCurrentFeature() }
|
b.swipeRefreshLayout.setOnRefreshListener { this.syncCurrentFeature() }
|
||||||
|
b.swipeRefreshLayout.setColorSchemeResources(
|
||||||
|
R.color.md_blue_500,
|
||||||
|
R.color.md_amber_500,
|
||||||
|
R.color.md_green_500
|
||||||
|
)
|
||||||
|
|
||||||
isStoragePermissionGranted()
|
isStoragePermissionGranted()
|
||||||
|
|
||||||
@ -419,7 +434,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
navView.coordinator.postDelayed({
|
navView.coordinator.postDelayed({
|
||||||
CafeBar.builder(this)
|
CafeBar.builder(this)
|
||||||
.content(R.string.rate_snackbar_text)
|
.content(R.string.rate_snackbar_text)
|
||||||
.icon(IconicsDrawable(this).icon(CommunityMaterial.Icon2.cmd_star).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.getPrimaryTextColor(this))))
|
.icon(IconicsDrawable(this).icon(CommunityMaterial.Icon2.cmd_star_outline).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.getPrimaryTextColor(this))))
|
||||||
.positiveText(R.string.rate_snackbar_positive)
|
.positiveText(R.string.rate_snackbar_positive)
|
||||||
.positiveColor(-0xb350b0)
|
.positiveColor(-0xb350b0)
|
||||||
.negativeText(R.string.rate_snackbar_negative)
|
.negativeText(R.string.rate_snackbar_negative)
|
||||||
@ -456,25 +471,25 @@ class MainActivity : AppCompatActivity() {
|
|||||||
bottomSheet.appendItems(
|
bottomSheet.appendItems(
|
||||||
BottomSheetPrimaryItem(false)
|
BottomSheetPrimaryItem(false)
|
||||||
.withTitle(R.string.menu_sync)
|
.withTitle(R.string.menu_sync)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_sync)
|
.withIcon(CommunityMaterial.Icon.cmd_download_outline)
|
||||||
.withOnClickListener(View.OnClickListener {
|
.withOnClickListener(View.OnClickListener {
|
||||||
bottomSheet.close()
|
bottomSheet.close()
|
||||||
app.apiEdziennik.guiSyncFeature(app, this, App.profileId, R.string.sync_dialog_title, R.string.sync_dialog_text, R.string.sync_done, fragmentToFeature(navTargetId))
|
SyncViewListDialog(this, navTargetId)
|
||||||
}),
|
}),
|
||||||
BottomSheetSeparatorItem(false),
|
BottomSheetSeparatorItem(false),
|
||||||
BottomSheetPrimaryItem(false)
|
BottomSheetPrimaryItem(false)
|
||||||
.withTitle(R.string.menu_settings)
|
.withTitle(R.string.menu_settings)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_settings)
|
.withIcon(CommunityMaterial.Icon2.cmd_settings_outline)
|
||||||
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_SETTINGS) }),
|
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_SETTINGS) }),
|
||||||
BottomSheetPrimaryItem(false)
|
BottomSheetPrimaryItem(false)
|
||||||
.withTitle(R.string.menu_feedback)
|
.withTitle(R.string.menu_feedback)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_help_circle)
|
.withIcon(CommunityMaterial.Icon2.cmd_help_circle_outline)
|
||||||
.withOnClickListener(View.OnClickListener { loadTarget(TARGET_FEEDBACK) })
|
.withOnClickListener(View.OnClickListener { loadTarget(TARGET_FEEDBACK) })
|
||||||
)
|
)
|
||||||
if (App.devMode) {
|
if (App.devMode) {
|
||||||
bottomSheet += BottomSheetPrimaryItem(false)
|
bottomSheet += BottomSheetPrimaryItem(false)
|
||||||
.withTitle(R.string.menu_debug)
|
.withTitle(R.string.menu_debug)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_android_debug_bridge)
|
.withIcon(CommunityMaterial.Icon.cmd_android_studio)
|
||||||
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_DEBUG) })
|
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_DEBUG) })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -518,17 +533,19 @@ class MainActivity : AppCompatActivity() {
|
|||||||
fun syncCurrentFeature() {
|
fun syncCurrentFeature() {
|
||||||
swipeRefreshLayout.isRefreshing = true
|
swipeRefreshLayout.isRefreshing = true
|
||||||
Toast.makeText(this, fragmentToSyncName(navTargetId), Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, fragmentToSyncName(navTargetId), Toast.LENGTH_SHORT).show()
|
||||||
ApiService.start(this)
|
|
||||||
val fragmentParam = when (navTargetId) {
|
val fragmentParam = when (navTargetId) {
|
||||||
DRAWER_ITEM_MESSAGES -> MessagesFragment.pageSelection
|
DRAWER_ITEM_MESSAGES -> MessagesFragment.pageSelection
|
||||||
else -> 0
|
else -> 0
|
||||||
}
|
}
|
||||||
EventBus.getDefault().postSticky(
|
val arguments = when (navTargetId) {
|
||||||
EdziennikTask.syncProfile(
|
DRAWER_ITEM_TIMETABLE -> JsonObject("weekStart" to TimetableFragment.pageSelection?.weekStart?.stringY_m_d)
|
||||||
App.profileId,
|
else -> null
|
||||||
listOf(navTargetId to fragmentParam)
|
}
|
||||||
)
|
EdziennikTask.syncProfile(
|
||||||
)
|
App.profileId,
|
||||||
|
listOf(navTargetId to fragmentParam),
|
||||||
|
arguments
|
||||||
|
).enqueue(this)
|
||||||
}
|
}
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onSyncStartedEvent(event: ApiTaskStartedEvent) {
|
fun onSyncStartedEvent(event: ApiTaskStartedEvent) {
|
||||||
@ -571,7 +588,12 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onSyncErrorEvent(event: ApiTaskErrorEvent) {
|
fun onSyncErrorEvent(event: ApiTaskErrorEvent) {
|
||||||
|
navView.toolbar.apply {
|
||||||
|
subtitleFormat = R.string.toolbar_subtitle
|
||||||
|
subtitleFormatWithUnread = R.plurals.toolbar_subtitle_with_unread
|
||||||
|
subtitle = "Gotowe"
|
||||||
|
}
|
||||||
|
errorSnackbar.addError(event.error).show()
|
||||||
}
|
}
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||||
fun onAppManagerDetectedEvent(event: AppManagerDetectedEvent) {
|
fun onAppManagerDetectedEvent(event: AppManagerDetectedEvent) {
|
||||||
@ -582,29 +604,18 @@ class MainActivity : AppCompatActivity() {
|
|||||||
.setMessage(R.string.app_manager_dialog_text)
|
.setMessage(R.string.app_manager_dialog_text)
|
||||||
.setPositiveButton(R.string.ok) { dialog, which ->
|
.setPositiveButton(R.string.ok) { dialog, which ->
|
||||||
try {
|
try {
|
||||||
val intent = Intent()
|
for (intent in appManagerIntentList) {
|
||||||
intent.component = ComponentName(
|
if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
|
||||||
"com.huawei.systemmanager",
|
startActivity(intent)
|
||||||
"com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity"
|
|
||||||
)
|
|
||||||
startActivity(intent)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
try {
|
|
||||||
val intent = Intent()
|
|
||||||
intent.component = ComponentName(
|
|
||||||
"com.asus.mobilemanager",
|
|
||||||
"com.asus.mobilemanager.MainActivity"
|
|
||||||
)
|
|
||||||
startActivity(intent)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
try {
|
|
||||||
startActivity(Intent(android.provider.Settings.ACTION_SETTINGS))
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
Toast.makeText(this, R.string.app_manager_open_failed, Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
try {
|
||||||
|
startActivity(Intent(Settings.ACTION_SETTINGS))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
Toast.makeText(this, R.string.app_manager_open_failed, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.setNeutralButton(R.string.dont_ask_again) { dialog, which ->
|
.setNeutralButton(R.string.dont_ask_again) { dialog, which ->
|
||||||
@ -614,22 +625,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
private fun fragmentToFeature(currentFragment: Int): Int {
|
|
||||||
return when (currentFragment) {
|
|
||||||
DRAWER_ITEM_TIMETABLE -> FEATURE_TIMETABLE
|
|
||||||
DRAWER_ITEM_AGENDA -> FEATURE_AGENDA
|
|
||||||
DRAWER_ITEM_GRADES -> FEATURE_GRADES
|
|
||||||
DRAWER_ITEM_HOMEWORK -> FEATURE_HOMEWORK
|
|
||||||
DRAWER_ITEM_BEHAVIOUR -> FEATURE_NOTICES
|
|
||||||
DRAWER_ITEM_ATTENDANCE -> FEATURE_ATTENDANCE
|
|
||||||
DRAWER_ITEM_MESSAGES -> when (MessagesFragment.pageSelection) {
|
|
||||||
1 -> FEATURE_MESSAGES_OUTBOX
|
|
||||||
else -> FEATURE_MESSAGES_INBOX
|
|
||||||
}
|
|
||||||
DRAWER_ITEM_ANNOUNCEMENTS -> FEATURE_ANNOUNCEMENTS
|
|
||||||
else -> FEATURE_ALL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private fun fragmentToSyncName(currentFragment: Int): Int {
|
private fun fragmentToSyncName(currentFragment: Int): Int {
|
||||||
return when (currentFragment) {
|
return when (currentFragment) {
|
||||||
DRAWER_ITEM_TIMETABLE -> R.string.sync_feature_timetable
|
DRAWER_ITEM_TIMETABLE -> R.string.sync_feature_timetable
|
||||||
@ -703,14 +699,18 @@ class MainActivity : AppCompatActivity() {
|
|||||||
app.profile == null -> {
|
app.profile == null -> {
|
||||||
if (intentProfileId == -1)
|
if (intentProfileId == -1)
|
||||||
intentProfileId = app.appSharedPrefs.getInt("current_profile_id", 1)
|
intentProfileId = app.appSharedPrefs.getInt("current_profile_id", 1)
|
||||||
loadProfile(intentProfileId, intentTargetId)
|
loadProfile(intentProfileId, intentTargetId, extras)
|
||||||
}
|
}
|
||||||
intentProfileId != -1 -> {
|
intentProfileId != -1 -> {
|
||||||
loadProfile(intentProfileId, intentTargetId)
|
if (app.profile.id != intentProfileId)
|
||||||
|
loadProfile(intentProfileId, intentTargetId, extras)
|
||||||
|
else
|
||||||
|
loadTarget(intentTargetId, extras)
|
||||||
}
|
}
|
||||||
intentTargetId != -1 -> {
|
intentTargetId != -1 -> {
|
||||||
drawer.currentProfile = app.profile.id
|
drawer.currentProfile = app.profile.id
|
||||||
loadTarget(intentTargetId, extras)
|
if (navTargetId != intentTargetId)
|
||||||
|
loadTarget(intentTargetId, extras)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
drawer.currentProfile = app.profile.id
|
drawer.currentProfile = app.profile.id
|
||||||
@ -788,7 +788,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
fun loadProfile(id: Int) = loadProfile(id, navTargetId)
|
fun loadProfile(id: Int) = loadProfile(id, navTargetId)
|
||||||
fun loadProfile(id: Int, arguments: Bundle?) = loadProfile(id, navTargetId, arguments)
|
fun loadProfile(id: Int, arguments: Bundle?) = loadProfile(id, navTargetId, arguments)
|
||||||
fun loadProfile(id: Int, drawerSelection: Int, arguments: Bundle? = null) {
|
fun loadProfile(id: Int, drawerSelection: Int, arguments: Bundle? = null) {
|
||||||
d("NavDebug", "loadProfile(id = $id, drawerSelection = $drawerSelection)")
|
//d("NavDebug", "loadProfile(id = $id, drawerSelection = $drawerSelection)")
|
||||||
if (app.profile != null && App.profileId == id) {
|
if (app.profile != null && App.profileId == id) {
|
||||||
drawer.currentProfile = app.profile.id
|
drawer.currentProfile = app.profile.id
|
||||||
loadTarget(drawerSelection, arguments)
|
loadTarget(drawerSelection, arguments)
|
||||||
@ -1051,7 +1051,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
loadTarget(DRAWER_ITEM_SETTINGS, null)
|
loadTarget(DRAWER_ITEM_SETTINGS, null)
|
||||||
} else if (item.itemId == 2) {
|
} else if (item.itemId == 2) {
|
||||||
app.apiEdziennik.guiRemoveProfile(this@MainActivity, profileId, profile.name?.getText(this).toString())
|
ProfileRemoveDialog(this, profileId, profile.name?.getText(this)?.toString() ?: "?")
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -311,13 +311,14 @@ public class Notifier {
|
|||||||
\____/| .__/ \__,_|\__,_|\__\___||___/
|
\____/| .__/ \__,_|\__,_|\__\___||___/
|
||||||
| |
|
| |
|
||||||
|*/
|
|*/
|
||||||
public void notificationUpdatesShow(String updateVersion, String updateUrl, String updateFilename) {
|
public void notificationUpdatesShow(String updateVersion, String updateUrl, String updateFilename, boolean updateDirect) {
|
||||||
if (!app.appConfig.notifyAboutUpdates)
|
if (!app.appConfig.notifyAboutUpdates)
|
||||||
return;
|
return;
|
||||||
Intent notificationIntent = new Intent(app.getContext(), BootReceiver.NotificationActionService.class)
|
Intent notificationIntent = new Intent(app.getContext(), BootReceiver.NotificationActionService.class)
|
||||||
.putExtra("update_version", updateVersion)
|
.putExtra("update_version", updateVersion)
|
||||||
.putExtra("update_url", updateUrl)
|
.putExtra("update_url", updateUrl)
|
||||||
.putExtra("update_filename", updateFilename);
|
.putExtra("update_filename", updateFilename)
|
||||||
|
.putExtra("update_direct", updateDirect);
|
||||||
|
|
||||||
PendingIntent pendingIntent = PendingIntent.getService(app.getContext(), 0,
|
PendingIntent pendingIntent = PendingIntent.getService(app.getContext(), 0,
|
||||||
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||||
|
@ -1,450 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik;
|
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.appwidget.AppWidgetManager;
|
|
||||||
import android.appwidget.AppWidgetProvider;
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.graphics.PorterDuff;
|
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.util.SparseArray;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.RemoteViews;
|
|
||||||
|
|
||||||
import com.mikepenz.iconics.IconicsColor;
|
|
||||||
import com.mikepenz.iconics.IconicsDrawable;
|
|
||||||
import com.mikepenz.iconics.IconicsSize;
|
|
||||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment;
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.ItemWidgetTimetableModel;
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Week;
|
|
||||||
import pl.szczodrzynski.edziennik.widgets.WidgetConfig;
|
|
||||||
import pl.szczodrzynski.edziennik.widgets.timetable.LessonDetailsActivity;
|
|
||||||
import pl.szczodrzynski.edziennik.widgets.timetable.WidgetTimetableService;
|
|
||||||
|
|
||||||
import static pl.szczodrzynski.edziennik.ExtensionsKt.filterOutArchived;
|
|
||||||
import static pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_HOMEWORK;
|
|
||||||
import static pl.szczodrzynski.edziennik.utils.Utils.bs;
|
|
||||||
|
|
||||||
|
|
||||||
public class WidgetTimetable extends AppWidgetProvider {
|
|
||||||
|
|
||||||
|
|
||||||
public static final String ACTION_SYNC_DATA = "ACTION_SYNC_DATA";
|
|
||||||
private static final String TAG = "WidgetTimetable";
|
|
||||||
private static int modeInt = 0;
|
|
||||||
|
|
||||||
public WidgetTimetable() {
|
|
||||||
// Start the worker thread
|
|
||||||
//HandlerThread sWorkerThread = new HandlerThread("WidgetTimetable-worker");
|
|
||||||
//sWorkerThread.start();
|
|
||||||
//Handler sWorkerQueue = new Handler(sWorkerThread.getLooper());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SparseArray<List<ItemWidgetTimetableModel>> timetables = null;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
if (ACTION_SYNC_DATA.equals(intent.getAction())) {
|
|
||||||
EdziennikTask.Companion.sync().enqueue(context);
|
|
||||||
}
|
|
||||||
super.onReceive(context, intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PendingIntent getPendingSelfIntent(Context context, String action) {
|
|
||||||
Intent intent = new Intent(context, WidgetTimetable.class);
|
|
||||||
intent.setAction(action);
|
|
||||||
return getPendingSelfIntent(context, intent);
|
|
||||||
}
|
|
||||||
public static PendingIntent getPendingSelfIntent(Context context, Intent intent) {
|
|
||||||
return PendingIntent.getBroadcast(context, 0, intent, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Bitmap drawableToBitmap (Drawable drawable) {
|
|
||||||
|
|
||||||
if (drawable instanceof BitmapDrawable) {
|
|
||||||
return ((BitmapDrawable)drawable).getBitmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
|
||||||
Canvas canvas = new Canvas(bitmap);
|
|
||||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
|
||||||
drawable.draw(canvas);
|
|
||||||
|
|
||||||
return bitmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
|
||||||
ComponentName thisWidget = new ComponentName(context, WidgetTimetable.class);
|
|
||||||
|
|
||||||
timetables = new SparseArray<>();
|
|
||||||
//timetables.clear();
|
|
||||||
|
|
||||||
App app = (App)context.getApplicationContext();
|
|
||||||
|
|
||||||
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
|
|
||||||
// There may be multiple widgets active, so update all of them
|
|
||||||
for (int appWidgetId : allWidgetIds) {
|
|
||||||
|
|
||||||
//d(TAG, "thr "+Thread.currentThread().getName());
|
|
||||||
|
|
||||||
WidgetConfig widgetConfig = app.appConfig.widgetTimetableConfigs.get(appWidgetId);
|
|
||||||
if (widgetConfig == null) {
|
|
||||||
widgetConfig = new WidgetConfig(app.profileFirstId());
|
|
||||||
app.appConfig.widgetTimetableConfigs.put(appWidgetId, widgetConfig);
|
|
||||||
app.appConfig.savePending = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoteViews views;
|
|
||||||
if (widgetConfig.bigStyle) {
|
|
||||||
views = new RemoteViews(context.getPackageName(), widgetConfig.darkTheme ? R.layout.widget_timetable_dark_big : R.layout.widget_timetable_big);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
views = new RemoteViews(context.getPackageName(), widgetConfig.darkTheme ? R.layout.widget_timetable_dark : R.layout.widget_timetable);
|
|
||||||
}
|
|
||||||
|
|
||||||
PorterDuff.Mode mode = PorterDuff.Mode.DST_IN;
|
|
||||||
/*if (widgetConfig.darkTheme) {
|
|
||||||
switch (modeInt) {
|
|
||||||
case 0:
|
|
||||||
mode = PorterDuff.Mode.ADD;
|
|
||||||
d(TAG, "ADD");
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
mode = PorterDuff.Mode.DST_ATOP;
|
|
||||||
d(TAG, "DST_ATOP");
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
mode = PorterDuff.Mode.DST_IN;
|
|
||||||
d(TAG, "DST_IN");
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
mode = PorterDuff.Mode.DST_OUT;
|
|
||||||
d(TAG, "DST_OUT");
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
mode = PorterDuff.Mode.DST_OVER;
|
|
||||||
d(TAG, "DST_OVER");
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
mode = PorterDuff.Mode.LIGHTEN;
|
|
||||||
d(TAG, "LIGHTEN");
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
mode = PorterDuff.Mode.MULTIPLY;
|
|
||||||
d(TAG, "MULTIPLY");
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
mode = PorterDuff.Mode.OVERLAY;
|
|
||||||
d(TAG, "OVERLAY");
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
mode = PorterDuff.Mode.SCREEN;
|
|
||||||
d(TAG, "SCREEN");
|
|
||||||
break;
|
|
||||||
case 9:
|
|
||||||
mode = PorterDuff.Mode.SRC_ATOP;
|
|
||||||
d(TAG, "SRC_ATOP");
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
mode = PorterDuff.Mode.SRC_IN;
|
|
||||||
d(TAG, "SRC_IN");
|
|
||||||
break;
|
|
||||||
case 11:
|
|
||||||
mode = PorterDuff.Mode.SRC_OUT;
|
|
||||||
d(TAG, "SRC_OUT");
|
|
||||||
break;
|
|
||||||
case 12:
|
|
||||||
mode = PorterDuff.Mode.SRC_OVER;
|
|
||||||
d(TAG, "SRC_OVER");
|
|
||||||
break;
|
|
||||||
case 13:
|
|
||||||
mode = PorterDuff.Mode.XOR;
|
|
||||||
d(TAG, "XOR");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
modeInt = 0;
|
|
||||||
mode = PorterDuff.Mode.ADD;
|
|
||||||
d(TAG, "ADD");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
|
||||||
// this code seems to crash the launcher on >= P
|
|
||||||
float transparency = widgetConfig.opacity; //0...1
|
|
||||||
long colorFilter = 0x01000000L * (long) (255f * transparency);
|
|
||||||
try {
|
|
||||||
final Method[] declaredMethods = Class.forName("android.widget.RemoteViews").getDeclaredMethods();
|
|
||||||
final int len = declaredMethods.length;
|
|
||||||
if (len > 0) {
|
|
||||||
for (int m = 0; m < len; m++) {
|
|
||||||
final Method method = declaredMethods[m];
|
|
||||||
if (method.getName().equals("setDrawableParameters")) {
|
|
||||||
method.setAccessible(true);
|
|
||||||
method.invoke(views, R.id.widgetTimetableListView, true, -1, (int) colorFilter, mode, -1);
|
|
||||||
method.invoke(views, R.id.widgetTimetableHeader, true, -1, (int) colorFilter, mode, -1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Intent refreshIntent = new Intent(context, WidgetTimetable.class);
|
|
||||||
refreshIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
|
|
||||||
refreshIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
|
|
||||||
PendingIntent pendingRefreshIntent = PendingIntent.getBroadcast(context,
|
|
||||||
0, refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
views.setOnClickPendingIntent(R.id.widgetTimetableRefresh, pendingRefreshIntent);
|
|
||||||
|
|
||||||
views.setOnClickPendingIntent(R.id.widgetTimetableSync, WidgetTimetable.getPendingSelfIntent(context, ACTION_SYNC_DATA));
|
|
||||||
|
|
||||||
views.setImageViewBitmap(R.id.widgetTimetableRefresh, new IconicsDrawable(context, CommunityMaterial.Icon2.cmd_refresh)
|
|
||||||
.color(IconicsColor.colorInt(Color.WHITE))
|
|
||||||
.size(IconicsSize.dp(widgetConfig.bigStyle ? 24 : 16)).toBitmap());
|
|
||||||
|
|
||||||
views.setImageViewBitmap(R.id.widgetTimetableSync, new IconicsDrawable(context, CommunityMaterial.Icon2.cmd_sync)
|
|
||||||
.color(IconicsColor.colorInt(Color.WHITE))
|
|
||||||
.size(IconicsSize.dp(widgetConfig.bigStyle ? 24 : 16)).toBitmap());
|
|
||||||
|
|
||||||
boolean unified = widgetConfig.profileId == -1;
|
|
||||||
|
|
||||||
List<Profile> profileList = new ArrayList<>();
|
|
||||||
if (unified) {
|
|
||||||
profileList = app.db.profileDao().getAllNow();
|
|
||||||
filterOutArchived(profileList);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Profile profile = app.db.profileDao().getFullByIdNow(widgetConfig.profileId);
|
|
||||||
if (profile != null) {
|
|
||||||
profileList.add(profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//d(TAG, "Profiles: "+ Arrays.toString(profileList.toArray()));
|
|
||||||
|
|
||||||
if (profileList == null || profileList.size() == 0) {
|
|
||||||
views.setViewVisibility(R.id.widgetTimetableLoading, View.VISIBLE);
|
|
||||||
views.setTextViewText(R.id.widgetTimetableLoading, app.getString(R.string.widget_timetable_profile_doesnt_exist));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
views.setViewVisibility(R.id.widgetTimetableLoading, View.GONE);
|
|
||||||
//Register profile;
|
|
||||||
|
|
||||||
long bellSyncDiffMillis = 0;
|
|
||||||
if (app.appConfig.bellSyncDiff != null) {
|
|
||||||
bellSyncDiffMillis = app.appConfig.bellSyncDiff.hour * 60 * 60 * 1000 + app.appConfig.bellSyncDiff.minute * 60 * 1000 + app.appConfig.bellSyncDiff.second * 1000;
|
|
||||||
bellSyncDiffMillis *= app.appConfig.bellSyncMultiplier;
|
|
||||||
bellSyncDiffMillis *= -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ItemWidgetTimetableModel> lessonList = new ArrayList<>();
|
|
||||||
|
|
||||||
Time syncedNow = Time.fromMillis(Time.getNow().getInMillis() + bellSyncDiffMillis);
|
|
||||||
|
|
||||||
Date today = Date.getToday();
|
|
||||||
|
|
||||||
int openProfileId = -1;
|
|
||||||
Date displayingDate = null;
|
|
||||||
int displayingWeekDay = 0;
|
|
||||||
if (unified) {
|
|
||||||
views.setTextViewText(R.id.widgetTimetableSubtitle, app.getString(R.string.widget_timetable_title_unified));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
views.setTextViewText(R.id.widgetTimetableSubtitle, profileList.get(0).getName());
|
|
||||||
openProfileId = profileList.get(0).getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<LessonFull> lessons = app.db.lessonDao().getAllWeekNow(unified ? -1 : openProfileId, today.clone().stepForward(0, 0, -today.getWeekDay()), today);
|
|
||||||
|
|
||||||
int scrollPos = 0;
|
|
||||||
|
|
||||||
for (Profile profile: profileList) {
|
|
||||||
Date profileDisplayingDate = HomeFragment.findDateWithLessons(profile.getId(), lessons, syncedNow, 1);
|
|
||||||
int profileDisplayingWeekDay = profileDisplayingDate.getWeekDay();
|
|
||||||
int dayDiff = Date.diffDays(profileDisplayingDate, Date.getToday());
|
|
||||||
|
|
||||||
//d(TAG, "For profile "+profile.name+" displayingDate is "+profileDisplayingDate.getStringY_m_d());
|
|
||||||
if (displayingDate == null || profileDisplayingDate.getValue() < displayingDate.getValue()) {
|
|
||||||
displayingDate = profileDisplayingDate;
|
|
||||||
displayingWeekDay = profileDisplayingWeekDay;
|
|
||||||
//d(TAG, "Setting as global dd");
|
|
||||||
if (dayDiff == 0) {
|
|
||||||
views.setTextViewText(R.id.widgetTimetableTitle, app.getString(R.string.day_today_format, Week.getFullDayName(displayingWeekDay)));
|
|
||||||
} else if (dayDiff == 1) {
|
|
||||||
views.setTextViewText(R.id.widgetTimetableTitle, app.getString(R.string.day_tomorrow_format, Week.getFullDayName(displayingWeekDay)));
|
|
||||||
} else {
|
|
||||||
views.setTextViewText(R.id.widgetTimetableTitle, Week.getFullDayName(displayingWeekDay) + " " + profileDisplayingDate.getStringDm());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Profile profile: profileList) {
|
|
||||||
int pos = 0;
|
|
||||||
|
|
||||||
List<EventFull> events = app.db.eventDao().getAllByDateNow(profile.getId(), displayingDate);
|
|
||||||
if (events == null)
|
|
||||||
events = new ArrayList<>();
|
|
||||||
|
|
||||||
if (unified) {
|
|
||||||
ItemWidgetTimetableModel separator = new ItemWidgetTimetableModel();
|
|
||||||
separator.profileId = profile.getId();
|
|
||||||
separator.bigStyle = widgetConfig.bigStyle;
|
|
||||||
separator.darkTheme = widgetConfig.darkTheme;
|
|
||||||
separator.separatorProfileName = profile.getName();
|
|
||||||
lessonList.add(separator);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (LessonFull lesson : lessons) {
|
|
||||||
//d(TAG, "Profile "+profile.id+" Lesson profileId "+lesson.profileId+" weekDay "+lesson.weekDay+", "+lesson);
|
|
||||||
if (profile.getId() != lesson.profileId || displayingWeekDay != lesson.weekDay)
|
|
||||||
continue;
|
|
||||||
//d(TAG, "Not skipped");
|
|
||||||
ItemWidgetTimetableModel model = new ItemWidgetTimetableModel();
|
|
||||||
|
|
||||||
model.bigStyle = widgetConfig.bigStyle;
|
|
||||||
model.darkTheme = widgetConfig.darkTheme;
|
|
||||||
|
|
||||||
model.profileId = profile.getId();
|
|
||||||
|
|
||||||
model.lessonDate = displayingDate;
|
|
||||||
model.startTime = lesson.startTime;
|
|
||||||
model.endTime = lesson.endTime;
|
|
||||||
|
|
||||||
model.lessonPassed = (syncedNow.getValue() > lesson.endTime.getValue()) && displayingWeekDay == Week.getTodayWeekDay();
|
|
||||||
model.lessonCurrent = (Time.inRange(lesson.startTime, lesson.endTime, syncedNow)) && displayingWeekDay == Week.getTodayWeekDay();
|
|
||||||
|
|
||||||
if (model.lessonCurrent) {
|
|
||||||
scrollPos = pos;
|
|
||||||
} else if (model.lessonPassed) {
|
|
||||||
scrollPos = pos + 1;
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
|
|
||||||
model.subjectName = bs(lesson.subjectLongName);
|
|
||||||
model.classroomName = lesson.classroomName;
|
|
||||||
|
|
||||||
model.bellSyncDiffMillis = bellSyncDiffMillis;
|
|
||||||
|
|
||||||
if (lesson.changeId != 0) {
|
|
||||||
if (lesson.changeType == LessonChange.TYPE_CHANGE) {
|
|
||||||
model.lessonChange = true;
|
|
||||||
if (lesson.changedClassroomName()) {
|
|
||||||
model.newClassroomName = lesson.changeClassroomName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lesson.changedSubjectLongName()) {
|
|
||||||
model.newSubjectName = lesson.changeSubjectLongName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (lesson.changeType == LessonChange.TYPE_CANCELLED) {
|
|
||||||
model.lessonCancelled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (EventFull event : events) {
|
|
||||||
if (event.startTime == null)
|
|
||||||
continue;
|
|
||||||
if (event.eventDate.getValue() == displayingDate.getValue()
|
|
||||||
&& event.startTime.getValue() == lesson.startTime.getValue()) {
|
|
||||||
model.eventColors.add(event.type == TYPE_HOMEWORK ? ItemWidgetTimetableModel.EVENT_COLOR_HOMEWORK : event.getColor());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lessonList.add(model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lessonList.size() == 0) {
|
|
||||||
views.setViewVisibility(R.id.widgetTimetableLoading, View.VISIBLE);
|
|
||||||
views.setRemoteAdapter(R.id.widgetTimetableListView, new Intent());
|
|
||||||
views.setTextViewText(R.id.widgetTimetableLoading, app.getString(R.string.widget_timetable_no_lessons));
|
|
||||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
views.setViewVisibility(R.id.widgetTimetableLoading, View.GONE);
|
|
||||||
|
|
||||||
timetables.put(appWidgetId, lessonList);
|
|
||||||
//WidgetTimetableListProvider.widgetsLessons.put(appWidgetId, lessons);
|
|
||||||
//views.setRemoteAdapter(R.id.widgetTimetableListView, new Intent());
|
|
||||||
Intent listIntent = new Intent(context, WidgetTimetableService.class);
|
|
||||||
listIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
|
|
||||||
listIntent.setData(Uri.parse(listIntent.toUri(Intent.URI_INTENT_SCHEME)));
|
|
||||||
views.setRemoteAdapter(R.id.widgetTimetableListView, listIntent);
|
|
||||||
|
|
||||||
// template to handle the click listener for each item
|
|
||||||
Intent intentTemplate = new Intent(context, LessonDetailsActivity.class);
|
|
||||||
// Old activities shouldn't be in the history stack
|
|
||||||
intentTemplate.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
|
||||||
PendingIntent pendingIntentTimetable = PendingIntent.getActivity(context,
|
|
||||||
0,
|
|
||||||
intentTemplate,
|
|
||||||
0);
|
|
||||||
views.setPendingIntentTemplate(R.id.widgetTimetableListView, pendingIntentTimetable);
|
|
||||||
|
|
||||||
Intent openIntent = new Intent(context, MainActivity.class);
|
|
||||||
openIntent.setAction("android.intent.action.MAIN");
|
|
||||||
if (!unified) {
|
|
||||||
openIntent.putExtra("profileId", openProfileId);
|
|
||||||
openIntent.putExtra("timetableDate", displayingDate.getValue());
|
|
||||||
}
|
|
||||||
openIntent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE);
|
|
||||||
PendingIntent pendingOpenIntent = PendingIntent.getActivity(context,
|
|
||||||
appWidgetId, openIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
views.setOnClickPendingIntent(R.id.widgetTimetableHeader, pendingOpenIntent);
|
|
||||||
|
|
||||||
if (!unified)
|
|
||||||
views.setScrollPosition(R.id.widgetTimetableListView, scrollPos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
|
||||||
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widgetTimetableListView);
|
|
||||||
}
|
|
||||||
//modeInt++;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEnabled(Context context) {
|
|
||||||
// Enter relevant functionality for when the first widget is created
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDeleted(Context context, int[] appWidgetIds) {
|
|
||||||
App app = (App) context.getApplicationContext();
|
|
||||||
for (int appWidgetId: appWidgetIds) {
|
|
||||||
app.appConfig.widgetTimetableConfigs.remove(appWidgetId);
|
|
||||||
}
|
|
||||||
app.saveConfig("widgetTimetableConfigs");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
371
app/src/main/java/pl/szczodrzynski/edziennik/WidgetTimetable.kt
Normal file
371
app/src/main/java/pl/szczodrzynski/edziennik/WidgetTimetable.kt
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
package pl.szczodrzynski.edziennik
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.appwidget.AppWidgetManager
|
||||||
|
import android.appwidget.AppWidgetProvider
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.PorterDuff
|
||||||
|
import android.graphics.drawable.BitmapDrawable
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.SparseArray
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.RemoteViews
|
||||||
|
import com.mikepenz.iconics.IconicsDrawable
|
||||||
|
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||||
|
import com.mikepenz.iconics.utils.colorInt
|
||||||
|
import com.mikepenz.iconics.utils.sizeDp
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_HOMEWORK
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.ItemWidgetTimetableModel
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||||
|
import pl.szczodrzynski.edziennik.widgets.WidgetConfig
|
||||||
|
import pl.szczodrzynski.edziennik.widgets.timetable.LessonDialogActivity
|
||||||
|
import pl.szczodrzynski.edziennik.widgets.timetable.WidgetTimetableService
|
||||||
|
import java.lang.reflect.InvocationTargetException
|
||||||
|
|
||||||
|
|
||||||
|
class WidgetTimetable : AppWidgetProvider() {
|
||||||
|
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
if (ACTION_SYNC_DATA == intent.action) {
|
||||||
|
EdziennikTask.sync().enqueue(context)
|
||||||
|
}
|
||||||
|
super.onReceive(context, intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
|
||||||
|
val thisWidget = ComponentName(context, WidgetTimetable::class.java)
|
||||||
|
|
||||||
|
timetables = SparseArray()
|
||||||
|
//timetables.clear();
|
||||||
|
|
||||||
|
val app = context.applicationContext as App
|
||||||
|
|
||||||
|
var bellSyncDiffMillis: Long = 0
|
||||||
|
if (app.appConfig.bellSyncDiff != null) {
|
||||||
|
bellSyncDiffMillis = (app.appConfig.bellSyncDiff.hour * 60 * 60 * 1000 + app.appConfig.bellSyncDiff.minute * 60 * 1000 + app.appConfig.bellSyncDiff.second * 1000).toLong()
|
||||||
|
bellSyncDiffMillis *= app.appConfig.bellSyncMultiplier.toLong()
|
||||||
|
bellSyncDiffMillis *= -1
|
||||||
|
}
|
||||||
|
|
||||||
|
val allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget)
|
||||||
|
|
||||||
|
allWidgetIds?.forEach { appWidgetId ->
|
||||||
|
var widgetConfig = app.appConfig.widgetTimetableConfigs[appWidgetId]
|
||||||
|
if (widgetConfig == null) {
|
||||||
|
widgetConfig = WidgetConfig(app.profileFirstId())
|
||||||
|
app.appConfig.widgetTimetableConfigs[appWidgetId] = widgetConfig
|
||||||
|
app.appConfig.savePending = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val views = if (widgetConfig.bigStyle) {
|
||||||
|
RemoteViews(context.packageName, if (widgetConfig.darkTheme) R.layout.widget_timetable_dark_big else R.layout.widget_timetable_big)
|
||||||
|
} else {
|
||||||
|
RemoteViews(context.packageName, if (widgetConfig.darkTheme) R.layout.widget_timetable_dark else R.layout.widget_timetable)
|
||||||
|
}
|
||||||
|
|
||||||
|
val refreshIntent = Intent(app, WidgetTimetable::class.java)
|
||||||
|
refreshIntent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||||
|
refreshIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds)
|
||||||
|
val pendingRefreshIntent = PendingIntent.getBroadcast(context,
|
||||||
|
0, refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
views.setOnClickPendingIntent(R.id.widgetTimetableRefresh, pendingRefreshIntent)
|
||||||
|
|
||||||
|
views.setOnClickPendingIntent(R.id.widgetTimetableSync, getPendingSelfIntent(context, ACTION_SYNC_DATA))
|
||||||
|
|
||||||
|
views.setImageViewBitmap(R.id.widgetTimetableRefresh, IconicsDrawable(context, CommunityMaterial.Icon2.cmd_refresh)
|
||||||
|
.colorInt(Color.WHITE)
|
||||||
|
.sizeDp(if (widgetConfig.bigStyle) 24 else 16).toBitmap())
|
||||||
|
|
||||||
|
views.setImageViewBitmap(R.id.widgetTimetableSync, IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline)
|
||||||
|
.colorInt(Color.WHITE)
|
||||||
|
.sizeDp(if (widgetConfig.bigStyle) 24 else 16).toBitmap())
|
||||||
|
|
||||||
|
prepareAppWidget(app, appWidgetId, views, widgetConfig, bellSyncDiffMillis)
|
||||||
|
|
||||||
|
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||||
|
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widgetTimetableListView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun prepareAppWidget(
|
||||||
|
app: App,
|
||||||
|
appWidgetId: Int,
|
||||||
|
views: RemoteViews,
|
||||||
|
widgetConfig: WidgetConfig,
|
||||||
|
bellSyncDiffMillis: Long
|
||||||
|
) {
|
||||||
|
// get the current bell-synced time
|
||||||
|
val now = Time.fromMillis(Time.getNow().inMillis + bellSyncDiffMillis)
|
||||||
|
|
||||||
|
// set the widget transparency
|
||||||
|
val mode = PorterDuff.Mode.DST_IN
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
||||||
|
// this code seems to crash the launcher on >= P
|
||||||
|
val transparency = widgetConfig.opacity //0...1
|
||||||
|
val colorFilter = 0x01000000L * (255f * transparency).toLong()
|
||||||
|
try {
|
||||||
|
val declaredMethods = Class.forName("android.widget.RemoteViews").declaredMethods
|
||||||
|
val len = declaredMethods.size
|
||||||
|
if (len > 0) {
|
||||||
|
for (m in 0 until len) {
|
||||||
|
val method = declaredMethods[m]
|
||||||
|
if (method.name == "setDrawableParameters") {
|
||||||
|
method.isAccessible = true
|
||||||
|
method.invoke(views, R.id.widgetTimetableListView, true, -1, colorFilter.toInt(), mode, -1)
|
||||||
|
method.invoke(views, R.id.widgetTimetableHeader, true, -1, colorFilter.toInt(), mode, -1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: ClassNotFoundException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
} catch (e: InvocationTargetException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
} catch (e: IllegalAccessException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val unified = widgetConfig.profileId == -1
|
||||||
|
|
||||||
|
// get all profiles or one profile with the specified id
|
||||||
|
val profileList = if (unified)
|
||||||
|
app.db.profileDao().allNow.filterOutArchived()
|
||||||
|
else
|
||||||
|
listOfNotNull(app.db.profileDao().getByIdNow(widgetConfig.profileId))
|
||||||
|
|
||||||
|
// no profile was found
|
||||||
|
if (profileList.isEmpty()) {
|
||||||
|
views.setViewVisibility(R.id.widgetTimetableLoading, View.VISIBLE)
|
||||||
|
views.setTextViewText(R.id.widgetTimetableLoading, app.getString(R.string.widget_timetable_profile_doesnt_exist))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
views.setViewVisibility(R.id.widgetTimetableLoading, View.GONE)
|
||||||
|
|
||||||
|
// set lesson search bounds
|
||||||
|
val today = Date.getToday()
|
||||||
|
val searchEnd = today.clone().stepForward(0, 0, 7)
|
||||||
|
|
||||||
|
var scrollPos = 0
|
||||||
|
|
||||||
|
var profileId: Int? = null
|
||||||
|
var displayingDate: Date? = null
|
||||||
|
|
||||||
|
val models = mutableListOf<ItemWidgetTimetableModel>()
|
||||||
|
|
||||||
|
// get all lessons within the search bounds
|
||||||
|
val lessonList = app.db.timetableDao().getBetweenDatesNow(today, searchEnd)
|
||||||
|
|
||||||
|
for (profile in profileList) {
|
||||||
|
|
||||||
|
// add a profile separator with its name
|
||||||
|
if (unified) {
|
||||||
|
val separator = ItemWidgetTimetableModel()
|
||||||
|
separator.profileId = profile.id
|
||||||
|
separator.bigStyle = widgetConfig.bigStyle
|
||||||
|
separator.darkTheme = widgetConfig.darkTheme
|
||||||
|
separator.separatorProfileName = profile.name
|
||||||
|
models.add(separator)
|
||||||
|
}
|
||||||
|
|
||||||
|
// search for lessons to display
|
||||||
|
val timetableDate = Date.getToday()
|
||||||
|
var checkedDays = 0
|
||||||
|
var lessons = lessonList.filter { it.profileId == profile.id && it.displayDate == timetableDate && it.type != Lesson.TYPE_NO_LESSONS }
|
||||||
|
while ((lessons.isEmpty() || lessons.none {
|
||||||
|
it.displayDate != today || (it.displayDate == today && it.displayEndTime != null && it.displayEndTime!! >= now)
|
||||||
|
}) && checkedDays < 7) {
|
||||||
|
timetableDate.stepForward(0, 0, 1)
|
||||||
|
lessons = lessonList.filter { it.profileId == profile.id && it.displayDate == timetableDate && it.type != Lesson.TYPE_NO_LESSONS }
|
||||||
|
checkedDays++
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the displayingDate to show in the header
|
||||||
|
if (!unified) {
|
||||||
|
if (lessons.isNotEmpty())
|
||||||
|
displayingDate = timetableDate
|
||||||
|
profileId = profile.id
|
||||||
|
}
|
||||||
|
|
||||||
|
// get all events for the current date
|
||||||
|
val events = app.db.eventDao().getAllByDateNow(profile.id, timetableDate)?.filterNotNull() ?: emptyList()
|
||||||
|
|
||||||
|
lessons.forEachIndexed { pos, lesson ->
|
||||||
|
val model = ItemWidgetTimetableModel()
|
||||||
|
|
||||||
|
model.bigStyle = widgetConfig.bigStyle
|
||||||
|
model.darkTheme = widgetConfig.darkTheme
|
||||||
|
|
||||||
|
model.profileId = profile.id
|
||||||
|
|
||||||
|
model.lessonId = lesson.id
|
||||||
|
model.lessonDate = timetableDate
|
||||||
|
model.startTime = lesson.displayStartTime
|
||||||
|
model.endTime = lesson.displayEndTime
|
||||||
|
|
||||||
|
// check if the lesson has already passed or it's currently in progress
|
||||||
|
if (lesson.displayDate == today) {
|
||||||
|
lesson.displayEndTime?.let { endTime ->
|
||||||
|
model.lessonPassed = now > endTime
|
||||||
|
lesson.displayStartTime?.let { startTime ->
|
||||||
|
model.lessonCurrent = now in startTime..endTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set where should the list view scroll to
|
||||||
|
if (model.lessonCurrent) {
|
||||||
|
scrollPos = pos
|
||||||
|
} else if (model.lessonPassed) {
|
||||||
|
scrollPos = pos + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the subject and classroom name
|
||||||
|
model.subjectName = lesson.displaySubjectName
|
||||||
|
model.classroomName = lesson.displayClassroom
|
||||||
|
|
||||||
|
// set the bell sync to calculate progress in ListProvider
|
||||||
|
model.bellSyncDiffMillis = bellSyncDiffMillis
|
||||||
|
|
||||||
|
// make the model aware of the lesson type
|
||||||
|
when (lesson.type) {
|
||||||
|
Lesson.TYPE_CANCELLED -> {
|
||||||
|
model.lessonCancelled = true
|
||||||
|
}
|
||||||
|
Lesson.TYPE_CHANGE,
|
||||||
|
Lesson.TYPE_SHIFTED_SOURCE,
|
||||||
|
Lesson.TYPE_SHIFTED_TARGET -> {
|
||||||
|
model.lessonChange = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add every event on this lesson
|
||||||
|
for (event in events) {
|
||||||
|
if (event.startTime != null && event.startTime != lesson.displayStartTime)
|
||||||
|
continue
|
||||||
|
model.eventColors.add(if (event.type == TYPE_HOMEWORK) ItemWidgetTimetableModel.EVENT_COLOR_HOMEWORK else event.getColor())
|
||||||
|
}
|
||||||
|
|
||||||
|
models += model
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unified) {
|
||||||
|
// set the title for an unified widget
|
||||||
|
views.setTextViewText(R.id.widgetTimetableTitle, app.getString(R.string.widget_timetable_title_unified))
|
||||||
|
views.setViewVisibility(R.id.widgetTimetableSubtitle, View.GONE)
|
||||||
|
} else {
|
||||||
|
// set the title to present the widget's profile
|
||||||
|
views.setTextViewText(R.id.widgetTimetableTitle, profileList[0].name)
|
||||||
|
views.setViewVisibility(R.id.widgetTimetableTitle, View.VISIBLE)
|
||||||
|
// make the subtitle show current date for these lessons
|
||||||
|
displayingDate?.let {
|
||||||
|
when (Date.diffDays(it, Date.getToday())) {
|
||||||
|
0 -> views.setTextViewText(R.id.widgetTimetableSubtitle, app.getString(R.string.day_today_format, Week.getFullDayName(it.weekDay)))
|
||||||
|
1 -> views.setTextViewText(R.id.widgetTimetableSubtitle, app.getString(R.string.day_tomorrow_format, Week.getFullDayName(it.weekDay)))
|
||||||
|
else -> views.setTextViewText(R.id.widgetTimetableSubtitle, Week.getFullDayName(it.weekDay) + " " + it.formattedString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// intent running when the header is clicked
|
||||||
|
val openIntent = Intent(app, MainActivity::class.java)
|
||||||
|
openIntent.action = "android.intent.action.MAIN"
|
||||||
|
if (!unified) {
|
||||||
|
// per-profile widget should redirect to it + correct day
|
||||||
|
profileId?.let {
|
||||||
|
openIntent.putExtra("profileId", it)
|
||||||
|
}
|
||||||
|
displayingDate?.let {
|
||||||
|
openIntent.putExtra("timetableDate", it.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
openIntent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE)
|
||||||
|
val pendingOpenIntent = PendingIntent.getActivity(app, appWidgetId, openIntent, 0)
|
||||||
|
views.setOnClickPendingIntent(R.id.widgetTimetableHeader, pendingOpenIntent)
|
||||||
|
|
||||||
|
if (lessonList.isEmpty()) {
|
||||||
|
views.setViewVisibility(R.id.widgetTimetableLoading, View.VISIBLE)
|
||||||
|
views.setRemoteAdapter(R.id.widgetTimetableListView, Intent())
|
||||||
|
views.setTextViewText(R.id.widgetTimetableLoading, app.getString(R.string.widget_timetable_no_lessons))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
timetables!!.put(appWidgetId, models)
|
||||||
|
|
||||||
|
// apply the list service to the list view
|
||||||
|
val listIntent = Intent(app, WidgetTimetableService::class.java)
|
||||||
|
listIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
|
||||||
|
listIntent.data = Uri.parse(listIntent.toUri(Intent.URI_INTENT_SCHEME))
|
||||||
|
views.setRemoteAdapter(R.id.widgetTimetableListView, listIntent)
|
||||||
|
|
||||||
|
// create an intent used to display the lesson details dialog
|
||||||
|
val intentTemplate = Intent(app, LessonDialogActivity::class.java)
|
||||||
|
intentTemplate.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||||
|
val pendingIntentTimetable = PendingIntent.getActivity(app, appWidgetId, intentTemplate, 0)
|
||||||
|
views.setPendingIntentTemplate(R.id.widgetTimetableListView, pendingIntentTimetable)
|
||||||
|
|
||||||
|
if (!unified)
|
||||||
|
views.setScrollPosition(R.id.widgetTimetableListView, scrollPos)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEnabled(context: Context) {
|
||||||
|
// Enter relevant functionality for when the first widget is created
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDeleted(context: Context, appWidgetIds: IntArray) {
|
||||||
|
val app = context.applicationContext as App
|
||||||
|
for (appWidgetId in appWidgetIds) {
|
||||||
|
app.appConfig.widgetTimetableConfigs.remove(appWidgetId)
|
||||||
|
}
|
||||||
|
app.saveConfig("widgetTimetableConfigs")
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
|
||||||
|
val ACTION_SYNC_DATA = "ACTION_SYNC_DATA"
|
||||||
|
private val TAG = "WidgetTimetable"
|
||||||
|
private val modeInt = 0
|
||||||
|
|
||||||
|
var timetables: SparseArray<List<ItemWidgetTimetableModel>>? = null
|
||||||
|
|
||||||
|
fun getPendingSelfIntent(context: Context, action: String): PendingIntent {
|
||||||
|
val intent = Intent(context, WidgetTimetable::class.java)
|
||||||
|
intent.action = action
|
||||||
|
return getPendingSelfIntent(context, intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPendingSelfIntent(context: Context, intent: Intent): PendingIntent {
|
||||||
|
return PendingIntent.getBroadcast(context, 0, intent, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun drawableToBitmap(drawable: Drawable): Bitmap {
|
||||||
|
|
||||||
|
if (drawable is BitmapDrawable) {
|
||||||
|
return drawable.bitmap
|
||||||
|
}
|
||||||
|
|
||||||
|
val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
|
||||||
|
val canvas = Canvas(bitmap)
|
||||||
|
drawable.setBounds(0, 0, canvas.width, canvas.height)
|
||||||
|
drawable.draw(canvas)
|
||||||
|
|
||||||
|
return bitmap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -60,6 +60,9 @@ class ApiService : Service() {
|
|||||||
|
|
||||||
private val notification by lazy { EdziennikNotification(this) }
|
private val notification by lazy { EdziennikNotification(this) }
|
||||||
|
|
||||||
|
private var lastEventTime = System.currentTimeMillis()
|
||||||
|
private var taskCancelTries = 0
|
||||||
|
|
||||||
/* ______ _ _ _ _ _____ _ _ _ _
|
/* ______ _ _ _ _ _____ _ _ _ _
|
||||||
| ____| | | (_) (_) | / ____| | | | | | |
|
| ____| | | (_) (_) | / ____| | | | | | |
|
||||||
| |__ __| |_____ ___ _ __ _ __ _| | __ | | __ _| | | |__ __ _ ___| | __
|
| |__ __| |_____ ___ _ __ _ __ _| | __ | | __ _| | | |__ __ _ ___| | __
|
||||||
@ -68,32 +71,26 @@ class ApiService : Service() {
|
|||||||
|______\__,_/___|_|\___|_| |_|_| |_|_|_|\_\ \_____\__,_|_|_|_.__/ \__,_|\___|_|\*/
|
|______\__,_/___|_|\___|_| |_|_| |_|_|_|\_\ \_____\__,_|_|_|_.__/ \__,_|\___|_|\*/
|
||||||
private val taskCallback = object : EdziennikCallback {
|
private val taskCallback = object : EdziennikCallback {
|
||||||
override fun onCompleted() {
|
override fun onCompleted() {
|
||||||
|
lastEventTime = System.currentTimeMillis()
|
||||||
d(TAG, "Task $taskRunningId (profile $taskProfileId) - $taskProgressText - finished")
|
d(TAG, "Task $taskRunningId (profile $taskProfileId) - $taskProgressText - finished")
|
||||||
//if (!taskCancelled) {
|
EventBus.getDefault().post(ApiTaskFinishedEvent(taskProfileId))
|
||||||
EventBus.getDefault().post(ApiTaskFinishedEvent(taskProfileId))
|
clearTask()
|
||||||
//}
|
|
||||||
taskIsRunning = false
|
|
||||||
taskRunningId = -1
|
|
||||||
taskRunning = null
|
|
||||||
taskProfileId = -1
|
|
||||||
taskProgress = -1f
|
|
||||||
taskProgressText = null
|
|
||||||
|
|
||||||
notification.setIdle().post()
|
notification.setIdle().post()
|
||||||
runTask()
|
runTask()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onError(apiError: ApiError) {
|
override fun onError(apiError: ApiError) {
|
||||||
|
lastEventTime = System.currentTimeMillis()
|
||||||
d(TAG, "Task $taskRunningId threw an error - $apiError")
|
d(TAG, "Task $taskRunningId threw an error - $apiError")
|
||||||
apiError.profileId = taskProfileId
|
apiError.profileId = taskProfileId
|
||||||
EventBus.getDefault().post(ApiTaskErrorEvent(apiError))
|
EventBus.getDefault().post(ApiTaskErrorEvent(apiError))
|
||||||
errorList.add(apiError)
|
errorList.add(apiError)
|
||||||
apiError.throwable?.printStackTrace()
|
apiError.throwable?.printStackTrace()
|
||||||
if (apiError.isCritical) {
|
if (apiError.isCritical) {
|
||||||
|
taskRunning?.cancel()
|
||||||
notification.setCriticalError().post()
|
notification.setCriticalError().post()
|
||||||
taskRunning = null
|
clearTask()
|
||||||
taskIsRunning = false
|
|
||||||
taskRunningId = -1
|
|
||||||
runTask()
|
runTask()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -102,6 +99,7 @@ class ApiService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onProgress(step: Float) {
|
override fun onProgress(step: Float) {
|
||||||
|
lastEventTime = System.currentTimeMillis()
|
||||||
if (step <= 0)
|
if (step <= 0)
|
||||||
return
|
return
|
||||||
if (taskProgress < 0)
|
if (taskProgress < 0)
|
||||||
@ -114,6 +112,7 @@ class ApiService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onStartProgress(stringRes: Int) {
|
override fun onStartProgress(stringRes: Int) {
|
||||||
|
lastEventTime = System.currentTimeMillis()
|
||||||
taskProgressText = getString(stringRes)
|
taskProgressText = getString(stringRes)
|
||||||
d(TAG, "Task $taskRunningId progress: $taskProgressText")
|
d(TAG, "Task $taskRunningId progress: $taskProgressText")
|
||||||
EventBus.getDefault().post(ApiTaskProgressEvent(taskProfileId, taskProgress, taskProgressText))
|
EventBus.getDefault().post(ApiTaskProgressEvent(taskProfileId, taskProgress, taskProgressText))
|
||||||
@ -128,6 +127,7 @@ class ApiService : Service() {
|
|||||||
| | (_| \__ \ < | __/> < __/ (__| |_| | |_| | (_) | | | |
|
| | (_| \__ \ < | __/> < __/ (__| |_| | |_| | (_) | | | |
|
||||||
|_|\__,_|___/_|\_\ \___/_/\_\___|\___|\__,_|\__|_|\___/|_| |*/
|
|_|\__,_|___/_|\_\ \___/_/\_\___|\___|\__,_|\__|_|\___/|_| |*/
|
||||||
private fun runTask() {
|
private fun runTask() {
|
||||||
|
checkIfTaskFrozen()
|
||||||
if (taskIsRunning)
|
if (taskIsRunning)
|
||||||
return
|
return
|
||||||
if (taskCancelled || serviceClosed || (taskQueue.isEmpty() && finishingTaskQueue.isEmpty())) {
|
if (taskCancelled || serviceClosed || (taskQueue.isEmpty() && finishingTaskQueue.isEmpty())) {
|
||||||
@ -136,6 +136,8 @@ class ApiService : Service() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastEventTime = System.currentTimeMillis()
|
||||||
|
|
||||||
val task = if (taskQueue.isEmpty()) finishingTaskQueue.removeAt(0) else taskQueue.removeAt(0)
|
val task = if (taskQueue.isEmpty()) finishingTaskQueue.removeAt(0) else taskQueue.removeAt(0)
|
||||||
task.taskId = ++taskMaximumId
|
task.taskId = ++taskMaximumId
|
||||||
task.prepare(app)
|
task.prepare(app)
|
||||||
@ -154,13 +156,59 @@ class ApiService : Service() {
|
|||||||
// post an event
|
// post an event
|
||||||
EventBus.getDefault().post(ApiTaskStartedEvent(taskProfileId, task.profile))
|
EventBus.getDefault().post(ApiTaskStartedEvent(taskProfileId, task.profile))
|
||||||
|
|
||||||
when (task) {
|
try {
|
||||||
is EdziennikTask -> task.run(app, taskCallback)
|
when (task) {
|
||||||
is NotifyTask -> task.run(app, taskCallback)
|
is EdziennikTask -> task.run(app, taskCallback)
|
||||||
is ErrorReportTask -> task.run(app, taskCallback, notification, errorList)
|
is NotifyTask -> task.run(app, taskCallback)
|
||||||
|
is ErrorReportTask -> task.run(app, taskCallback, notification, errorList)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
taskCallback.onError(ApiError(TAG, EXCEPTION_API_TASK).withThrowable(e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a task is inactive for more than 30 seconds.
|
||||||
|
* If the user tries to cancel a task with no success at least three times,
|
||||||
|
* consider it frozen as well.
|
||||||
|
*
|
||||||
|
* This usually means it is broken and won't become active again.
|
||||||
|
* This method cancels the task and removes any pointers to it.
|
||||||
|
*/
|
||||||
|
private fun checkIfTaskFrozen(): Boolean {
|
||||||
|
if (System.currentTimeMillis() - lastEventTime > 30*1000
|
||||||
|
|| taskCancelTries >= 3) {
|
||||||
|
val time = System.currentTimeMillis() - lastEventTime
|
||||||
|
d(TAG, "!!! Task $taskRunningId froze for $time ms. $taskRunning")
|
||||||
|
clearTask()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the service if the current task is frozen/broken.
|
||||||
|
*/
|
||||||
|
private fun stopIfTaskFrozen() {
|
||||||
|
if (checkIfTaskFrozen()) {
|
||||||
|
stopSelf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove any task descriptors or pointers from the service.
|
||||||
|
*/
|
||||||
|
private fun clearTask() {
|
||||||
|
taskIsRunning = false
|
||||||
|
taskRunningId = -1
|
||||||
|
taskRunning = null
|
||||||
|
taskProfileId = -1
|
||||||
|
taskProgress = -1f
|
||||||
|
taskProgressText = null
|
||||||
|
taskCancelled = false
|
||||||
|
taskCancelTries = 0
|
||||||
|
}
|
||||||
|
|
||||||
private fun allCompleted() {
|
private fun allCompleted() {
|
||||||
EventBus.getDefault().post(ApiTaskAllFinishedEvent())
|
EventBus.getDefault().post(ApiTaskAllFinishedEvent())
|
||||||
stopSelf()
|
stopSelf()
|
||||||
@ -206,8 +254,10 @@ class ApiService : Service() {
|
|||||||
EventBus.getDefault().removeStickyEvent(request)
|
EventBus.getDefault().removeStickyEvent(request)
|
||||||
d(TAG, request.toString())
|
d(TAG, request.toString())
|
||||||
|
|
||||||
|
taskCancelTries++
|
||||||
taskCancelled = true
|
taskCancelled = true
|
||||||
taskRunning?.cancel()
|
taskRunning?.cancel()
|
||||||
|
stopIfTaskFrozen()
|
||||||
}
|
}
|
||||||
@Subscribe(sticky = true, threadMode = ThreadMode.ASYNC)
|
@Subscribe(sticky = true, threadMode = ThreadMode.ASYNC)
|
||||||
fun onServiceCloseRequest(request: ServiceCloseRequest) {
|
fun onServiceCloseRequest(request: ServiceCloseRequest) {
|
||||||
@ -227,11 +277,13 @@ class ApiService : Service() {
|
|||||||
____) | __/ | \ V /| | (_| __/ | (_) \ V / __/ | | | | | (_| | __/\__ \
|
____) | __/ | \ V /| | (_| __/ | (_) \ V / __/ | | | | | (_| | __/\__ \
|
||||||
|_____/ \___|_| \_/ |_|\___\___| \___/ \_/ \___|_| |_| |_|\__,_|\___||__*/
|
|_____/ \___|_| \_/ |_|\___\___| \___/ \_/ \___|_| |_| |_|\__,_|\___||__*/
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
|
d(TAG, "Service created")
|
||||||
EventBus.getDefault().register(this)
|
EventBus.getDefault().register(this)
|
||||||
notification.setIdle().setCloseAction()
|
notification.setIdle().setCloseAction()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
d(TAG, "Foreground service onStartCommand")
|
||||||
startForeground(EdziennikNotification.NOTIFICATION_ID, notification.notification)
|
startForeground(EdziennikNotification.NOTIFICATION_ID, notification.notification)
|
||||||
return START_NOT_STICKY
|
return START_NOT_STICKY
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,14 @@ val SYSTEM_USER_AGENT = System.getProperty("http.agent") ?: "Dalvik/2.1.0 Androi
|
|||||||
|
|
||||||
val SERVER_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME} $SYSTEM_USER_AGENT"
|
val SERVER_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME} $SYSTEM_USER_AGENT"
|
||||||
|
|
||||||
|
const val FAKE_LIBRUS_API = "http://librus.szkolny.eu/api"
|
||||||
|
const val FAKE_LIBRUS_PORTAL = "http://librus.szkolny.eu"
|
||||||
|
const val FAKE_LIBRUS_AUTHORIZE = "http://librus.szkolny.eu/authorize.php"
|
||||||
|
const val FAKE_LIBRUS_LOGIN = "http://librus.szkolny.eu/login_action.php"
|
||||||
|
const val FAKE_LIBRUS_TOKEN = "http://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 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 = "wmSyUMo8llDAs4y9tJVYY92oyZ6h4lAt7KCuy0Gv"
|
||||||
@ -56,6 +64,7 @@ const val IDZIENNIK_WEB_TIMETABLE = "mod_panelRodzica/plan/WS_Plan.asmx/pobierzP
|
|||||||
const val IDZIENNIK_WEB_GRADES = "mod_panelRodzica/oceny/WS_ocenyUcznia.asmx/pobierzOcenyUcznia"
|
const val IDZIENNIK_WEB_GRADES = "mod_panelRodzica/oceny/WS_ocenyUcznia.asmx/pobierzOcenyUcznia"
|
||||||
const val IDZIENNIK_WEB_MISSING_GRADES = "mod_panelRodzica/brak_ocen/WS_BrakOcenUcznia.asmx/pobierzBrakujaceOcenyUcznia"
|
const val IDZIENNIK_WEB_MISSING_GRADES = "mod_panelRodzica/brak_ocen/WS_BrakOcenUcznia.asmx/pobierzBrakujaceOcenyUcznia"
|
||||||
const val IDZIENNIK_WEB_EXAMS = "mod_panelRodzica/sprawdziany/mod_sprawdzianyPanel.asmx/pobierzListe"
|
const val IDZIENNIK_WEB_EXAMS = "mod_panelRodzica/sprawdziany/mod_sprawdzianyPanel.asmx/pobierzListe"
|
||||||
|
const val IDZIENNIK_WEB_HOMEWORK = "mod_panelRodzica/pracaDomowa/WS_pracaDomowa.asmx/pobierzPraceDomowe"
|
||||||
const val IDZIENNIK_WEB_NOTICES = "mod_panelRodzica/uwagi/WS_uwagiUcznia.asmx/pobierzUwagiUcznia"
|
const val IDZIENNIK_WEB_NOTICES = "mod_panelRodzica/uwagi/WS_uwagiUcznia.asmx/pobierzUwagiUcznia"
|
||||||
const val IDZIENNIK_WEB_ATTENDANCE = "mod_panelRodzica/obecnosci/WS_obecnosciUcznia.asmx/pobierzObecnosciUcznia"
|
const val IDZIENNIK_WEB_ATTENDANCE = "mod_panelRodzica/obecnosci/WS_obecnosciUcznia.asmx/pobierzObecnosciUcznia"
|
||||||
const val IDZIENNIK_WEB_ANNOUNCEMENTS = "mod_panelRodzica/tabOgl/WS_tablicaOgloszen.asmx/GetOgloszenia"
|
const val IDZIENNIK_WEB_ANNOUNCEMENTS = "mod_panelRodzica/tabOgl/WS_tablicaOgloszen.asmx/GetOgloszenia"
|
||||||
|
@ -45,8 +45,8 @@ class DataNotifications(val data: Data) {
|
|||||||
return@run
|
return@run
|
||||||
}
|
}
|
||||||
|
|
||||||
for (change in app.db.lessonChangeDao().getNotNotifiedNow(profileId)) {
|
for (lesson in app.db.timetableDao().getNotNotifiedNow(profileId)) {
|
||||||
val text = app.getString(R.string.notification_lesson_change_format, change.changeTypeStr(app), if (change.lessonDate == null) "" else change.lessonDate!!.formattedString, change.subjectLongName)
|
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(
|
data.notifications += Notification(
|
||||||
title = app.getNotificationTitle(TYPE_TIMETABLE_LESSON_CHANGE),
|
title = app.getNotificationTitle(TYPE_TIMETABLE_LESSON_CHANGE),
|
||||||
text = text,
|
text = text,
|
||||||
@ -54,8 +54,8 @@ class DataNotifications(val data: Data) {
|
|||||||
profileId = profileId,
|
profileId = profileId,
|
||||||
profileName = profileName,
|
profileName = profileName,
|
||||||
viewId = DRAWER_ITEM_TIMETABLE,
|
viewId = DRAWER_ITEM_TIMETABLE,
|
||||||
addedDate = change.addedDate
|
addedDate = lesson.addedDate
|
||||||
).addExtra("timetableDate", change.lessonDate?.value?.toLong())
|
).addExtra("timetableDate", lesson.displayDate?.stringY_m_d ?: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
for (event in app.db.eventDao().getNotNotifiedNow(profileId)) {
|
for (event in app.db.eventDao().getNotNotifiedNow(profileId)) {
|
||||||
@ -186,10 +186,10 @@ class DataNotifications(val data: Data) {
|
|||||||
val luckyNumbers = app.db.luckyNumberDao().getNotNotifiedNow(profileId)
|
val luckyNumbers = app.db.luckyNumberDao().getNotNotifiedNow(profileId)
|
||||||
luckyNumbers?.removeAll { it.date < today }
|
luckyNumbers?.removeAll { it.date < today }
|
||||||
luckyNumbers?.forEach { luckyNumber ->
|
luckyNumbers?.forEach { luckyNumber ->
|
||||||
val text = when {
|
val text = when (luckyNumber.date.value) {
|
||||||
luckyNumber.date.value == todayValue -> // LN for today
|
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)
|
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)
|
||||||
luckyNumber.date.value == todayValue + 1 -> // LN for tomorrow
|
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)
|
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
|
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)
|
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)
|
||||||
@ -207,4 +207,4 @@ class DataNotifications(val data: Data) {
|
|||||||
|
|
||||||
data.db.metadataDao().setAllNotified(profileId, true)
|
data.db.metadataDao().setAllNotified(profileId, true)
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -39,13 +39,16 @@ const val ERROR_REQUEST_HTTP_404 = 54
|
|||||||
const val ERROR_REQUEST_HTTP_405 = 55
|
const val ERROR_REQUEST_HTTP_405 = 55
|
||||||
const val ERROR_REQUEST_HTTP_410 = 56
|
const val ERROR_REQUEST_HTTP_410 = 56
|
||||||
const val ERROR_REQUEST_HTTP_500 = 57
|
const val ERROR_REQUEST_HTTP_500 = 57
|
||||||
|
const val ERROR_REQUEST_FAILURE_HOSTNAME_NOT_FOUND = 60
|
||||||
|
const val ERROR_REQUEST_FAILURE_TIMEOUT = 61
|
||||||
|
const val ERROR_REQUEST_FAILURE_NO_INTERNET = 62
|
||||||
const val ERROR_RESPONSE_EMPTY = 100
|
const val ERROR_RESPONSE_EMPTY = 100
|
||||||
const val ERROR_LOGIN_DATA_MISSING = 101
|
const val ERROR_LOGIN_DATA_MISSING = 101
|
||||||
const val ERROR_LOGIN_DATA_INVALID = 102
|
|
||||||
const val ERROR_PROFILE_MISSING = 105
|
const val ERROR_PROFILE_MISSING = 105
|
||||||
const val ERROR_INVALID_LOGIN_MODE = 110
|
const val ERROR_INVALID_LOGIN_MODE = 110
|
||||||
const val ERROR_LOGIN_METHOD_NOT_SATISFIED = 111
|
const val ERROR_LOGIN_METHOD_NOT_SATISFIED = 111
|
||||||
const val ERROR_NOT_IMPLEMENTED = 112
|
const val ERROR_NOT_IMPLEMENTED = 112
|
||||||
|
const val ERROR_FILE_DOWNLOAD = 113
|
||||||
|
|
||||||
const val ERROR_NO_STUDENTS_IN_ACCOUNT = 115
|
const val ERROR_NO_STUDENTS_IN_ACCOUNT = 115
|
||||||
|
|
||||||
@ -99,6 +102,13 @@ const val ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_INVALID = 172
|
|||||||
const val ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_REVOKED = 173
|
const val ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_REVOKED = 173
|
||||||
const val ERROR_LIBRUS_SYNERGIA_OTHER = 174
|
const val ERROR_LIBRUS_SYNERGIA_OTHER = 174
|
||||||
const val ERROR_LIBRUS_SYNERGIA_MAINTENANCE = 175
|
const val ERROR_LIBRUS_SYNERGIA_MAINTENANCE = 175
|
||||||
|
const val ERROR_LIBRUS_MESSAGES_MAINTENANCE = 176
|
||||||
|
const val ERROR_LIBRUS_MESSAGES_ERROR = 177
|
||||||
|
const val ERROR_LIBRUS_MESSAGES_OTHER = 178
|
||||||
|
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_LOGIN_MOBIDZIENNIK_WEB_INVALID_LOGIN = 201
|
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_LOGIN = 201
|
||||||
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_OLD_PASSWORD = 202
|
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_OLD_PASSWORD = 202
|
||||||
@ -109,7 +119,7 @@ const val ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_ADDRESS = 206
|
|||||||
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_OTHER = 210
|
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_OTHER = 210
|
||||||
const val ERROR_MOBIDZIENNIK_WEB_ACCESS_DENIED = 211
|
const val ERROR_MOBIDZIENNIK_WEB_ACCESS_DENIED = 211
|
||||||
const val ERROR_MOBIDZIENNIK_WEB_NO_SESSION_KEY = 212
|
const val ERROR_MOBIDZIENNIK_WEB_NO_SESSION_KEY = 212
|
||||||
const val ERROR_MOBIDZIENNIK_WEB_NO_SESSION_VALUE = 212
|
const val ERROR_MOBIDZIENNIK_WEB_NO_SESSION_VALUE = 216
|
||||||
const val ERROR_MOBIDZIENNIK_WEB_NO_SERVER_ID = 213
|
const val ERROR_MOBIDZIENNIK_WEB_NO_SERVER_ID = 213
|
||||||
const val ERROR_MOBIDZIENNIK_WEB_INVALID_RESPONSE = 214
|
const val ERROR_MOBIDZIENNIK_WEB_INVALID_RESPONSE = 214
|
||||||
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_NO_SESSION_ID = 215
|
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_NO_SESSION_ID = 215
|
||||||
@ -150,6 +160,7 @@ const val ERROR_IDZIENNIK_API_OTHER = 451
|
|||||||
|
|
||||||
const val ERROR_TEMPLATE_WEB_OTHER = 801
|
const val ERROR_TEMPLATE_WEB_OTHER = 801
|
||||||
|
|
||||||
|
const val EXCEPTION_API_TASK = 900
|
||||||
const val EXCEPTION_LOGIN_LIBRUS_API_TOKEN = 901
|
const val EXCEPTION_LOGIN_LIBRUS_API_TOKEN = 901
|
||||||
const val EXCEPTION_LOGIN_LIBRUS_PORTAL_TOKEN = 902
|
const val EXCEPTION_LOGIN_LIBRUS_PORTAL_TOKEN = 902
|
||||||
const val EXCEPTION_LIBRUS_PORTAL_SYNERGIA_TOKEN = 903
|
const val EXCEPTION_LIBRUS_PORTAL_SYNERGIA_TOKEN = 903
|
||||||
@ -162,3 +173,5 @@ const val EXCEPTION_LIBRUS_MESSAGES_REQUEST = 911
|
|||||||
const val EXCEPTION_IDZIENNIK_WEB_REQUEST = 912
|
const val EXCEPTION_IDZIENNIK_WEB_REQUEST = 912
|
||||||
const val EXCEPTION_IDZIENNIK_WEB_API_REQUEST = 913
|
const val EXCEPTION_IDZIENNIK_WEB_API_REQUEST = 913
|
||||||
const val EXCEPTION_IDZIENNIK_API_REQUEST = 914
|
const val EXCEPTION_IDZIENNIK_API_REQUEST = 914
|
||||||
|
|
||||||
|
const val LOGIN_NO_ARGUMENTS = 1201
|
||||||
|
@ -7,39 +7,36 @@ package pl.szczodrzynski.edziennik.api.v2
|
|||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
|
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_ANNOUNCEMENTS
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE
|
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_GRADES
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME
|
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_HOMEWORK
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR
|
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
||||||
|
|
||||||
const val FEATURE_ALL = 0
|
internal const val FEATURE_TIMETABLE = 1
|
||||||
const val FEATURE_TIMETABLE = 1
|
internal const val FEATURE_AGENDA = 2
|
||||||
const val FEATURE_AGENDA = 2
|
internal const val FEATURE_GRADES = 3
|
||||||
const val FEATURE_GRADES = 3
|
internal const val FEATURE_HOMEWORK = 4
|
||||||
const val FEATURE_HOMEWORK = 4
|
internal const val FEATURE_BEHAVIOUR = 5
|
||||||
const val FEATURE_BEHAVIOUR = 5
|
internal const val FEATURE_ATTENDANCE = 6
|
||||||
const val FEATURE_ATTENDANCE = 6
|
internal const val FEATURE_MESSAGES_INBOX = 7
|
||||||
const val FEATURE_MESSAGES_INBOX = 7
|
internal const val FEATURE_MESSAGES_SENT = 8
|
||||||
const val FEATURE_MESSAGES_SENT = 8
|
internal const val FEATURE_ANNOUNCEMENTS = 9
|
||||||
const val FEATURE_ANNOUNCEMENTS = 9
|
|
||||||
|
|
||||||
const val FEATURE_ALWAYS_NEEDED = 100
|
internal const val FEATURE_ALWAYS_NEEDED = 100
|
||||||
const val FEATURE_STUDENT_INFO = 101
|
internal const val FEATURE_STUDENT_INFO = 101
|
||||||
const val FEATURE_STUDENT_NUMBER = 109
|
internal const val FEATURE_STUDENT_NUMBER = 109
|
||||||
const val FEATURE_SCHOOL_INFO = 102
|
internal const val FEATURE_SCHOOL_INFO = 102
|
||||||
const val FEATURE_CLASS_INFO = 103
|
internal const val FEATURE_CLASS_INFO = 103
|
||||||
const val FEATURE_TEAM_INFO = 104
|
internal const val FEATURE_TEAM_INFO = 104
|
||||||
const val FEATURE_LUCKY_NUMBER = 105
|
internal const val FEATURE_LUCKY_NUMBER = 105
|
||||||
const val FEATURE_TEACHERS = 106
|
internal const val FEATURE_TEACHERS = 106
|
||||||
const val FEATURE_SUBJECTS = 107
|
internal const val FEATURE_SUBJECTS = 107
|
||||||
const val FEATURE_CLASSROOMS = 108
|
internal const val FEATURE_CLASSROOMS = 108
|
||||||
const val FEATURE_PUSH_CONFIG = 120
|
internal const val FEATURE_PUSH_CONFIG = 120
|
||||||
|
|
||||||
const val FEATURE_MESSAGE_GET = 201
|
|
||||||
|
|
||||||
object Features {
|
object Features {
|
||||||
private fun getAllNecessary(): List<Int> = listOf(
|
private fun getAllNecessary(): List<Int> = listOf(
|
||||||
|
@ -66,13 +66,13 @@ val librusLoginMethods = listOf(
|
|||||||
},
|
},
|
||||||
|
|
||||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_SYNERGIA, LibrusLoginSynergia::class.java)
|
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_SYNERGIA, LibrusLoginSynergia::class.java)
|
||||||
.withIsPossible { _, _ -> true }
|
.withIsPossible { _, loginStore -> !loginStore.hasLoginData("fakeLogin") }
|
||||||
.withRequiredLoginMethod { profile, _ ->
|
.withRequiredLoginMethod { profile, _ ->
|
||||||
if (profile?.hasStudentData("accountPassword") == false) LOGIN_METHOD_LIBRUS_API else LOGIN_METHOD_NOT_NEEDED
|
if (profile?.hasStudentData("accountPassword") == false) LOGIN_METHOD_LIBRUS_API else LOGIN_METHOD_NOT_NEEDED
|
||||||
},
|
},
|
||||||
|
|
||||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_MESSAGES, LibrusLoginMessages::class.java)
|
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_MESSAGES, LibrusLoginMessages::class.java)
|
||||||
.withIsPossible { _, _ -> true }
|
.withIsPossible { _, loginStore -> !loginStore.hasLoginData("fakeLogin") }
|
||||||
.withRequiredLoginMethod { profile, _ ->
|
.withRequiredLoginMethod { profile, _ ->
|
||||||
if (profile?.hasStudentData("accountPassword") == false) LOGIN_METHOD_LIBRUS_SYNERGIA else LOGIN_METHOD_NOT_NEEDED
|
if (profile?.hasStudentData("accountPassword") == false) LOGIN_METHOD_LIBRUS_SYNERGIA else LOGIN_METHOD_NOT_NEEDED
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,16 @@ object Regexes {
|
|||||||
"""events: (.+),$""".toRegex(RegexOption.MULTILINE)
|
"""events: (.+),$""".toRegex(RegexOption.MULTILINE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val MOBIDZIENNIK_MESSAGE_READ_DATE by lazy {
|
||||||
|
"""czas przeczytania:.+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||||
|
}
|
||||||
|
val MOBIDZIENNIK_MESSAGE_SENT_READ_DATE by lazy {
|
||||||
|
""".+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||||
|
}
|
||||||
|
val MOBIDZIENNIK_MESSAGE_ATTACHMENT by lazy {
|
||||||
|
"""href="https://.+?\.mobidziennik.pl/.+?&(?:amp;)?zalacznik=([0-9]+)"(?:.+?<small.+?\(([0-9.]+)\s(M|K|G|)B\))*""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val IDZIENNIK_LOGIN_HIDDEN_FIELDS by lazy {
|
val IDZIENNIK_LOGIN_HIDDEN_FIELDS by lazy {
|
||||||
@ -60,4 +70,16 @@ object Regexes {
|
|||||||
val IDZIENNIK_LOGIN_FIRST_STUDENT by lazy {
|
val IDZIENNIK_LOGIN_FIRST_STUDENT by lazy {
|
||||||
"""<option.*?value="([0-9]+)"\sdata-id-ucznia="([A-z0-9]+?)".*?>(.+?)\s(.+?)\s*\((.+?),\s*(.+?)\)</option>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
"""<option.*?value="([0-9]+)"\sdata-id-ucznia="([A-z0-9]+?)".*?>(.+?)\s(.+?)\s*\((.+?),\s*(.+?)\)</option>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
val VULCAN_SHITFT_ANNOTATION by lazy {
|
||||||
|
"""\(przeniesiona (z|na) lekcj[ię] ([0-9]+), (.+)\)""".toRegex()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
val LIBRUS_ATTACHMENT_KEY by lazy {
|
||||||
|
"""singleUseKey=([0-9A-f_]+)""".toRegex()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.events
|
||||||
|
|
||||||
|
data class AttachmentGetEvent(val profileId: Int, val messageId: Long, val attachmentId: Long,
|
||||||
|
var eventType: Int = TYPE_PROGRESS, val fileName: String? = null,
|
||||||
|
val bytesWritten: Long = 0) {
|
||||||
|
companion object {
|
||||||
|
const val TYPE_PROGRESS = 0
|
||||||
|
const val TYPE_FINISHED = 1
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2019-11-12.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.events
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||||
|
|
||||||
|
data class MessageGetEvent(val message: MessageFull)
|
@ -1,5 +1,6 @@
|
|||||||
package pl.szczodrzynski.edziennik.api.v2.events.task
|
package pl.szczodrzynski.edziennik.api.v2.events.task
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.api.v2.*
|
import pl.szczodrzynski.edziennik.api.v2.*
|
||||||
@ -11,6 +12,7 @@ import pl.szczodrzynski.edziennik.api.v2.mobidziennik.Mobidziennik
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.template.Template
|
import pl.szczodrzynski.edziennik.api.v2.template.Template
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.Vulcan
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.Vulcan
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||||
|
|
||||||
open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTask(profileId) {
|
open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTask(profileId) {
|
||||||
companion object {
|
companion object {
|
||||||
@ -18,10 +20,11 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
|||||||
|
|
||||||
fun firstLogin(loginStore: LoginStore) = EdziennikTask(-1, FirstLoginRequest(loginStore))
|
fun firstLogin(loginStore: LoginStore) = EdziennikTask(-1, FirstLoginRequest(loginStore))
|
||||||
fun sync() = EdziennikTask(-1, SyncRequest())
|
fun sync() = EdziennikTask(-1, SyncRequest())
|
||||||
fun syncProfile(profileId: Int, viewIds: List<Pair<Int, Int>>? = null) = EdziennikTask(profileId, SyncProfileRequest(viewIds))
|
fun syncProfile(profileId: Int, viewIds: List<Pair<Int, Int>>? = null, arguments: JsonObject? = null) = EdziennikTask(profileId, SyncProfileRequest(viewIds, arguments))
|
||||||
fun syncProfileList(profileList: List<Int>) = EdziennikTask(-1, SyncProfileListRequest(profileList))
|
fun syncProfileList(profileList: List<Int>) = EdziennikTask(-1, SyncProfileListRequest(profileList))
|
||||||
fun messageGet(profileId: Int, messageId: Int) = EdziennikTask(profileId, MessageGetRequest(messageId))
|
fun messageGet(profileId: Int, message: MessageFull) = EdziennikTask(profileId, MessageGetRequest(message))
|
||||||
fun announcementsRead(profileId: Int) = EdziennikTask(profileId, AnnouncementsReadRequest())
|
fun announcementsRead(profileId: Int) = EdziennikTask(profileId, AnnouncementsReadRequest())
|
||||||
|
fun attachmentGet(profileId: Int, messageId: Long, attachmentId: Long, attachmentName: String) = EdziennikTask(profileId, AttachmentGetRequest(messageId, attachmentId, attachmentName))
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var loginStore: LoginStore
|
private lateinit var loginStore: LoginStore
|
||||||
@ -33,12 +36,11 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
|||||||
loginStore = request.loginStore
|
loginStore = request.loginStore
|
||||||
// save the profile ID and name as the current task's
|
// save the profile ID and name as the current task's
|
||||||
taskName = app.getString(R.string.edziennik_notification_api_first_login_title)
|
taskName = app.getString(R.string.edziennik_notification_api_first_login_title)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// get the requested profile and login store
|
// get the requested profile and login store
|
||||||
val profile = app.db.profileDao().getByIdNow(profileId)
|
val profile = app.db.profileDao().getByIdNow(profileId)
|
||||||
this.profile = profile
|
this.profile = profile
|
||||||
if (profile == null || !profile.syncEnabled) {
|
if (profile == null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val loginStore = app.db.loginStoreDao().getByIdNow(profile.loginStoreId) ?: return
|
val loginStore = app.db.loginStoreDao().getByIdNow(profile.loginStoreId) ?: return
|
||||||
@ -50,7 +52,7 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
|||||||
|
|
||||||
private var edziennikInterface: EdziennikInterface? = null
|
private var edziennikInterface: EdziennikInterface? = null
|
||||||
|
|
||||||
fun run(app: App, taskCallback: EdziennikCallback) {
|
internal fun run(app: App, taskCallback: EdziennikCallback) {
|
||||||
edziennikInterface = when (loginStore.type) {
|
edziennikInterface = when (loginStore.type) {
|
||||||
LOGIN_TYPE_LIBRUS -> Librus(app, profile, loginStore, taskCallback)
|
LOGIN_TYPE_LIBRUS -> Librus(app, profile, loginStore, taskCallback)
|
||||||
LOGIN_TYPE_MOBIDZIENNIK -> Mobidziennik(app, profile, loginStore, taskCallback)
|
LOGIN_TYPE_MOBIDZIENNIK -> Mobidziennik(app, profile, loginStore, taskCallback)
|
||||||
@ -65,11 +67,14 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
|||||||
|
|
||||||
when (request) {
|
when (request) {
|
||||||
is SyncProfileRequest -> edziennikInterface?.sync(
|
is SyncProfileRequest -> edziennikInterface?.sync(
|
||||||
featureIds = request.viewIds?.flatMap { Features.getIdsByView(it.first, it.second) } ?: Features.getAllIds(),
|
featureIds = request.viewIds?.flatMap { Features.getIdsByView(it.first, it.second) }
|
||||||
viewId = request.viewIds?.get(0)?.first)
|
?: Features.getAllIds(),
|
||||||
is MessageGetRequest -> edziennikInterface?.getMessage(request.messageId)
|
viewId = request.viewIds?.get(0)?.first,
|
||||||
|
arguments = request.arguments)
|
||||||
|
is MessageGetRequest -> edziennikInterface?.getMessage(request.message)
|
||||||
is FirstLoginRequest -> edziennikInterface?.firstLogin()
|
is FirstLoginRequest -> edziennikInterface?.firstLogin()
|
||||||
is AnnouncementsReadRequest -> edziennikInterface?.markAllAnnouncementsAsRead()
|
is AnnouncementsReadRequest -> edziennikInterface?.markAllAnnouncementsAsRead()
|
||||||
|
is AttachmentGetRequest -> edziennikInterface?.getAttachment(request.messageId, request.attachmentId, request.attachmentName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,8 +88,9 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
|||||||
|
|
||||||
data class FirstLoginRequest(val loginStore: LoginStore)
|
data class FirstLoginRequest(val loginStore: LoginStore)
|
||||||
class SyncRequest
|
class SyncRequest
|
||||||
data class SyncProfileRequest(val viewIds: List<Pair<Int, Int>>? = null)
|
data class SyncProfileRequest(val viewIds: List<Pair<Int, Int>>? = null, val arguments: JsonObject? = null)
|
||||||
data class SyncProfileListRequest(val profileList: List<Int>)
|
data class SyncProfileListRequest(val profileList: List<Int>)
|
||||||
data class MessageGetRequest(val messageId: Int)
|
data class MessageGetRequest(val message: MessageFull)
|
||||||
class AnnouncementsReadRequest
|
class AnnouncementsReadRequest
|
||||||
}
|
data class AttachmentGetRequest(val messageId: Long, val attachmentId: Long, val attachmentName: String)
|
||||||
|
}
|
||||||
|
@ -6,6 +6,8 @@ package pl.szczodrzynski.edziennik.api.v2.events.task
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Build.VERSION.SDK_INT
|
||||||
|
import android.os.Build.VERSION_CODES.O
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.api.v2.ApiService
|
import pl.szczodrzynski.edziennik.api.v2.ApiService
|
||||||
@ -25,7 +27,12 @@ abstract class IApiTask(open val profileId: Int) {
|
|||||||
abstract fun cancel()
|
abstract fun cancel()
|
||||||
|
|
||||||
fun enqueue(context: Context) {
|
fun enqueue(context: Context) {
|
||||||
context.startService(Intent(context, ApiService::class.java))
|
Intent(context, ApiService::class.java).let {
|
||||||
|
if (SDK_INT >= O)
|
||||||
|
context.startForegroundService(it)
|
||||||
|
else
|
||||||
|
context.startService(it)
|
||||||
|
}
|
||||||
EventBus.getDefault().postSticky(this)
|
EventBus.getDefault().postSticky(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.MainActivity
|
|||||||
import pl.szczodrzynski.edziennik.Notifier.ID_NOTIFICATIONS
|
import pl.szczodrzynski.edziennik.Notifier.ID_NOTIFICATIONS
|
||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.notification.getNotificationTitle
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Notification
|
import pl.szczodrzynski.edziennik.utils.models.Notification
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
@ -33,9 +34,9 @@ class NotifyTask : IApiTask(-1) {
|
|||||||
val pendingIntent = PendingIntent.getActivity(app, notification.id, intent, 0)
|
val pendingIntent = PendingIntent.getActivity(app, notification.id, intent, 0)
|
||||||
val notificationBuilder = NotificationCompat.Builder(app, app.notifier.notificationGroup)
|
val notificationBuilder = NotificationCompat.Builder(app, app.notifier.notificationGroup)
|
||||||
// title, text, type, date
|
// title, text, type, date
|
||||||
.setContentTitle(notification.title)
|
.setContentTitle(notification.profileName)
|
||||||
.setContentText(notification.text)
|
.setContentText(notification.text)
|
||||||
.setSubText(Notification.stringType(app, notification.type))
|
.setSubText(app.getNotificationTitle(notification.type))
|
||||||
.setWhen(notification.addedDate)
|
.setWhen(notification.addedDate)
|
||||||
.setTicker(app.getString(R.string.notification_ticker_format, Notification.stringType(app, notification.type)))
|
.setTicker(app.getString(R.string.notification_ticker_format, Notification.stringType(app, notification.type)))
|
||||||
// icon, color, lights, priority
|
// icon, color, lights, priority
|
||||||
|
@ -138,10 +138,12 @@ class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(
|
|||||||
val teacher = teacherList.singleOrNull { it.fullName == "$firstName $lastName" }
|
val teacher = teacherList.singleOrNull { it.fullName == "$firstName $lastName" }
|
||||||
return validateTeacher(teacher, firstName, lastName)
|
return validateTeacher(teacher, firstName, lastName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTeacher(firstNameChar: Char, lastName: String): Teacher {
|
fun getTeacher(firstNameChar: Char, lastName: String): Teacher {
|
||||||
val teacher = teacherList.singleOrNull { it.shortName == "$firstNameChar.$lastName" }
|
val teacher = teacherList.singleOrNull { it.shortName == "$firstNameChar.$lastName" }
|
||||||
return validateTeacher(teacher, firstNameChar.toString(), lastName)
|
return validateTeacher(teacher, firstNameChar.toString(), lastName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTeacherByLastFirst(nameLastFirst: String): Teacher {
|
fun getTeacherByLastFirst(nameLastFirst: String): Teacher {
|
||||||
val nameParts = nameLastFirst.split(" ")
|
val nameParts = nameLastFirst.split(" ")
|
||||||
return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[1], nameParts[0])
|
return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[1], nameParts[0])
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.idziennik
|
package pl.szczodrzynski.edziennik.api.v2.idziennik
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
||||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikData
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikData
|
||||||
@ -15,6 +16,7 @@ import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
import pl.szczodrzynski.edziennik.api.v2.prepare
|
import pl.szczodrzynski.edziennik.api.v2.prepare
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
|
||||||
@ -48,7 +50,8 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
|||||||
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
||||||
__/ |
|
__/ |
|
||||||
|__*/
|
|__*/
|
||||||
override fun sync(featureIds: List<Int>, viewId: Int?) {
|
override fun sync(featureIds: List<Int>, viewId: Int?, arguments: JsonObject?) {
|
||||||
|
data.arguments = arguments
|
||||||
data.prepare(idziennikLoginMethods, IdziennikFeatures, featureIds, viewId)
|
data.prepare(idziennikLoginMethods, IdziennikFeatures, featureIds, viewId)
|
||||||
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
||||||
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
||||||
@ -59,7 +62,7 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getMessage(messageId: Int) {
|
override fun getMessage(message: MessageFull) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,6 +70,10 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
override fun firstLogin() {
|
override fun firstLogin() {
|
||||||
IdziennikFirstLogin(data) {
|
IdziennikFirstLogin(data) {
|
||||||
completed()
|
completed()
|
||||||
|
@ -11,6 +11,7 @@ const val ENDPOINT_IDZIENNIK_WEB_TIMETABLE = 1030
|
|||||||
const val ENDPOINT_IDZIENNIK_WEB_GRADES = 1040
|
const val ENDPOINT_IDZIENNIK_WEB_GRADES = 1040
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES = 1050
|
const val ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES = 1050
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_EXAMS = 1060
|
const val ENDPOINT_IDZIENNIK_WEB_EXAMS = 1060
|
||||||
|
const val ENDPOINT_IDZIENNIK_WEB_HOMEWORK = 1061
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_NOTICES = 1070
|
const val ENDPOINT_IDZIENNIK_WEB_NOTICES = 1070
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS = 1080
|
const val ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS = 1080
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_ATTENDANCE = 1090
|
const val ENDPOINT_IDZIENNIK_WEB_ATTENDANCE = 1090
|
||||||
@ -34,6 +35,10 @@ val IdziennikFeatures = listOf(
|
|||||||
ENDPOINT_IDZIENNIK_WEB_EXAMS to LOGIN_METHOD_IDZIENNIK_WEB
|
ENDPOINT_IDZIENNIK_WEB_EXAMS to LOGIN_METHOD_IDZIENNIK_WEB
|
||||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
||||||
|
|
||||||
|
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_HOMEWORK, listOf(
|
||||||
|
ENDPOINT_IDZIENNIK_WEB_HOMEWORK to LOGIN_METHOD_IDZIENNIK_WEB
|
||||||
|
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
||||||
|
|
||||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_BEHAVIOUR, listOf(
|
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_BEHAVIOUR, listOf(
|
||||||
ENDPOINT_IDZIENNIK_WEB_NOTICES to LOGIN_METHOD_IDZIENNIK_WEB
|
ENDPOINT_IDZIENNIK_WEB_NOTICES to LOGIN_METHOD_IDZIENNIK_WEB
|
||||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
||||||
|
@ -41,43 +41,47 @@ class IdziennikData(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
|||||||
when (endpointId) {
|
when (endpointId) {
|
||||||
ENDPOINT_IDZIENNIK_WEB_TIMETABLE -> {
|
ENDPOINT_IDZIENNIK_WEB_TIMETABLE -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
||||||
IdziennikWebTimetable(data) { onSuccess() }
|
IdziennikWebTimetable(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_IDZIENNIK_WEB_GRADES -> {
|
ENDPOINT_IDZIENNIK_WEB_GRADES -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
||||||
IdziennikWebGrades(data) { onSuccess() }
|
IdziennikWebGrades(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES -> {
|
ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_proposed_grades)
|
data.startProgress(R.string.edziennik_progress_endpoint_proposed_grades)
|
||||||
IdziennikWebProposedGrades(data) { onSuccess() }
|
IdziennikWebProposedGrades(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_IDZIENNIK_WEB_EXAMS -> {
|
ENDPOINT_IDZIENNIK_WEB_EXAMS -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_exams)
|
data.startProgress(R.string.edziennik_progress_endpoint_exams)
|
||||||
IdziennikWebExams(data) { onSuccess() }
|
IdziennikWebExams(data, onSuccess)
|
||||||
|
}
|
||||||
|
ENDPOINT_IDZIENNIK_WEB_HOMEWORK -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
||||||
|
IdziennikWebHomework(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_IDZIENNIK_WEB_NOTICES -> {
|
ENDPOINT_IDZIENNIK_WEB_NOTICES -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
||||||
IdziennikWebNotices(data) { onSuccess() }
|
IdziennikWebNotices(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS -> {
|
ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_announcements)
|
data.startProgress(R.string.edziennik_progress_endpoint_announcements)
|
||||||
IdziennikWebAnnouncements(data) { onSuccess() }
|
IdziennikWebAnnouncements(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_IDZIENNIK_WEB_ATTENDANCE -> {
|
ENDPOINT_IDZIENNIK_WEB_ATTENDANCE -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
||||||
IdziennikWebAttendance(data) { onSuccess() }
|
IdziennikWebAttendance(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER -> {
|
ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
|
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
|
||||||
IdziennikApiCurrentRegister(data) { onSuccess() }
|
IdziennikApiCurrentRegister(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX -> {
|
ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
||||||
IdziennikApiMessagesInbox(data) { onSuccess() }
|
IdziennikApiMessagesInbox(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_IDZIENNIK_API_MESSAGES_SENT -> {
|
ENDPOINT_IDZIENNIK_API_MESSAGES_SENT -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
|
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
|
||||||
IdziennikApiMessagesSent(data) { onSuccess() }
|
IdziennikApiMessagesSent(data, onSuccess)
|
||||||
}
|
}
|
||||||
else -> onSuccess()
|
else -> onSuccess()
|
||||||
}
|
}
|
||||||
|
@ -94,6 +94,7 @@ open class IdziennikWeb(open val data: DataIdziennik) {
|
|||||||
is Long -> json.addProperty(name, value)
|
is Long -> json.addProperty(name, value)
|
||||||
is Float -> json.addProperty(name, value)
|
is Float -> json.addProperty(name, value)
|
||||||
is Char -> json.addProperty(name, value)
|
is Char -> json.addProperty(name, value)
|
||||||
|
is Boolean -> json.addProperty(name, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setJsonBody(json)
|
setJsonBody(json)
|
||||||
|
@ -75,7 +75,7 @@ class IdziennikApiMessagesInbox(override val data: DataIdziennik,
|
|||||||
/*messageId*/ messageId
|
/*messageId*/ messageId
|
||||||
)
|
)
|
||||||
|
|
||||||
data.messageList.add(message)
|
data.messageIgnoreList.add(message)
|
||||||
data.messageRecipientList.add(messageRecipient)
|
data.messageRecipientList.add(messageRecipient)
|
||||||
data.messageMetadataList.add(Metadata(
|
data.messageMetadataList.add(Metadata(
|
||||||
profileId,
|
profileId,
|
||||||
|
@ -74,7 +74,7 @@ class IdziennikApiMessagesSent(override val data: DataIdziennik,
|
|||||||
data.messageRecipientIgnoreList.add(messageRecipient)
|
data.messageRecipientIgnoreList.add(messageRecipient)
|
||||||
}
|
}
|
||||||
|
|
||||||
data.messageList.add(message)
|
data.messageIgnoreList.add(message)
|
||||||
data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true, sentDate))
|
data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true, sentDate))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,21 +5,21 @@
|
|||||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||||
|
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.*
|
||||||
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
||||||
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_EXAMS
|
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_EXAMS
|
||||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_EXAMS
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_EXAMS
|
||||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.Lesson
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
import pl.szczodrzynski.edziennik.getJsonObject
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
class IdziennikWebExams(override val data: DataIdziennik,
|
class IdziennikWebExams(override val data: DataIdziennik,
|
||||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "IdziennikWebExams"
|
private const val TAG = "IdziennikWebExams"
|
||||||
}
|
}
|
||||||
@ -34,14 +34,15 @@ class IdziennikWebExams(override val data: DataIdziennik,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getExams() {
|
private fun getExams() {
|
||||||
val param = JsonObject()
|
val param = JsonObject().apply {
|
||||||
param.addProperty("strona", 1)
|
addProperty("strona", 1)
|
||||||
param.addProperty("iloscNaStrone", "99")
|
addProperty("iloscNaStrone", "99")
|
||||||
param.addProperty("iloscRekordow", -1)
|
addProperty("iloscRekordow", -1)
|
||||||
param.addProperty("kolumnaSort", "ss.Nazwa,sp.Data_sprawdzianu")
|
addProperty("kolumnaSort", "ss.Nazwa,sp.Data_sprawdzianu")
|
||||||
param.addProperty("kierunekSort", 0)
|
addProperty("kierunekSort", 0)
|
||||||
param.addProperty("maxIloscZaznaczonych", 0)
|
addProperty("maxIloscZaznaczonych", 0)
|
||||||
param.addProperty("panelFiltrow", 0)
|
addProperty("panelFiltrow", 0)
|
||||||
|
}
|
||||||
|
|
||||||
webApiGet(TAG, IDZIENNIK_WEB_EXAMS, mapOf(
|
webApiGet(TAG, IDZIENNIK_WEB_EXAMS, mapOf(
|
||||||
"idP" to data.registerId,
|
"idP" to data.registerId,
|
||||||
@ -55,28 +56,33 @@ class IdziennikWebExams(override val data: DataIdziennik,
|
|||||||
return@webApiGet
|
return@webApiGet
|
||||||
}
|
}
|
||||||
|
|
||||||
for (jExamEl in json.getAsJsonArray("ListK")) {
|
json.getJsonArray("ListK")?.asJsonObjectList()?.forEach { exam ->
|
||||||
val jExam = jExamEl.asJsonObject
|
val id = exam.getLong("_recordId") ?: return@forEach
|
||||||
// jExam
|
val examDate = Date.fromY_m_d(exam.getString("data") ?: return@forEach)
|
||||||
val eventId = jExam.get("_recordId").asLong
|
val subjectId = data.getSubject(exam.getString("przedmiot") ?: return@forEach,
|
||||||
val rSubject = data.getSubject(jExam.get("przedmiot").asString, -1, "")
|
-1, "").id
|
||||||
val rTeacher = data.getTeacherByLastFirst(jExam.get("wpisal").asString)
|
val teacherId = data.getTeacherByLastFirst(exam.getString("wpisal")
|
||||||
val examDate = Date.fromY_m_d(jExam.get("data").asString)
|
?: return@forEach).id
|
||||||
val lessonObject = Lesson.getByWeekDayAndSubject(data.lessonList, examDate.weekDay, rSubject.id)
|
val lessonList = data.db.timetableDao().getForDateNow(profileId, examDate)
|
||||||
val examTime = lessonObject?.startTime
|
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime
|
||||||
|
val topic = exam.getString("zakres") ?: ""
|
||||||
|
|
||||||
|
val eventType = when (exam.getString("rodzaj")) {
|
||||||
|
"sprawdzian/praca klasowa" -> Event.TYPE_EXAM
|
||||||
|
else -> Event.TYPE_SHORT_QUIZ
|
||||||
|
}
|
||||||
|
|
||||||
val eventType = if (jExam.get("rodzaj").asString == "sprawdzian/praca klasowa") Event.TYPE_EXAM else Event.TYPE_SHORT_QUIZ
|
|
||||||
val eventObject = Event(
|
val eventObject = Event(
|
||||||
profileId,
|
profileId,
|
||||||
eventId,
|
id,
|
||||||
examDate,
|
examDate,
|
||||||
examTime,
|
startTime,
|
||||||
jExam.get("zakres").asString,
|
topic,
|
||||||
-1,
|
-1,
|
||||||
eventType,
|
eventType,
|
||||||
false,
|
false,
|
||||||
rTeacher.id,
|
teacherId,
|
||||||
rSubject.id,
|
subjectId,
|
||||||
data.teamClass?.id ?: -1
|
data.teamClass?.id ?: -1
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -106,9 +112,11 @@ class IdziennikWebExams(override val data: DataIdziennik,
|
|||||||
examsNextMonthChecked = true
|
examsNextMonthChecked = true
|
||||||
getExams()
|
getExams()
|
||||||
} else {
|
} else {
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_EXAMS, SYNC_ALWAYS)
|
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_EXAMS, SYNC_ALWAYS)
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.*
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_HOMEWORK
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_HOMEWORK
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
|
class IdziennikWebHomework(override val data: DataIdziennik,
|
||||||
|
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "IdziennikWebHomework"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val param = JsonObject().apply {
|
||||||
|
addProperty("strona", 1)
|
||||||
|
addProperty("iloscNaStrone", 997)
|
||||||
|
addProperty("iloscRekordow", -1)
|
||||||
|
addProperty("kolumnaSort", "DataZadania")
|
||||||
|
addProperty("kierunekSort", 0)
|
||||||
|
addProperty("maxIloscZaznaczonych", 0)
|
||||||
|
addProperty("panelFiltrow", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
webApiGet(TAG, IDZIENNIK_WEB_HOMEWORK, mapOf(
|
||||||
|
"idP" to data.registerId,
|
||||||
|
"data" to Date.getToday().stringY_m_d,
|
||||||
|
"wszystkie" to true,
|
||||||
|
"param" to param
|
||||||
|
)) { result ->
|
||||||
|
val json = result.getJsonObject("d") ?: run {
|
||||||
|
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
||||||
|
.withApiResponse(result))
|
||||||
|
return@webApiGet
|
||||||
|
}
|
||||||
|
|
||||||
|
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 subjectId = data.getSubject(homework.getString("przed") ?: return@forEach,
|
||||||
|
-1, "").id
|
||||||
|
val teacherId = data.getTeacherByLastFirst(homework.getString("usr")
|
||||||
|
?: return@forEach).id
|
||||||
|
val lessonList = data.db.timetableDao().getForDateNow(profileId, eventDate)
|
||||||
|
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.displayStartTime
|
||||||
|
val topic = homework.getString("tytul") ?: ""
|
||||||
|
|
||||||
|
val seen = when (profile?.empty) {
|
||||||
|
true -> true
|
||||||
|
else -> eventDate < Date.getToday()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val eventObject = Event(
|
||||||
|
profileId,
|
||||||
|
id,
|
||||||
|
eventDate,
|
||||||
|
startTime,
|
||||||
|
topic,
|
||||||
|
-1,
|
||||||
|
Event.TYPE_HOMEWORK,
|
||||||
|
false,
|
||||||
|
teacherId,
|
||||||
|
subjectId,
|
||||||
|
data.teamClass?.id ?: -1
|
||||||
|
)
|
||||||
|
|
||||||
|
data.eventList.add(eventObject)
|
||||||
|
data.metadataList.add(Metadata(
|
||||||
|
profileId,
|
||||||
|
Metadata.TYPE_HOMEWORK,
|
||||||
|
eventObject.id,
|
||||||
|
seen,
|
||||||
|
seen,
|
||||||
|
System.currentTimeMillis()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||||
|
|
||||||
|
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_HOMEWORK, SYNC_ALWAYS)
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-27.
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-22
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||||
@ -12,33 +12,38 @@ import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_TIMETABLE
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_TIMETABLE
|
||||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.Lesson
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange.TYPE_CANCELLED
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange.TYPE_CHANGE
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonRange
|
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonRange
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||||
|
|
||||||
class IdziennikWebTimetable(override val data: DataIdziennik,
|
class IdziennikWebTimetable(override val data: DataIdziennik,
|
||||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "IdziennikWebTimetable"
|
private const val TAG = "IdziennikWebTimetable"
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init { data.profile?.also { profile ->
|
||||||
val weekStart = Week.getWeekStart()
|
val currentWeekStart = Week.getWeekStart()
|
||||||
|
|
||||||
if (Date.getToday().weekDay > 4) {
|
if (Date.getToday().weekDay > 4) {
|
||||||
weekStart.stepForward(0, 0, 7)
|
currentWeekStart.stepForward(0, 0, 7)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
||||||
|
|
||||||
|
val weekStart = Date.fromY_m_d(getDate)
|
||||||
|
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||||
|
|
||||||
webApiGet(TAG, IDZIENNIK_WEB_TIMETABLE, mapOf(
|
webApiGet(TAG, IDZIENNIK_WEB_TIMETABLE, mapOf(
|
||||||
"idPozDziennika" to data.registerId,
|
"idPozDziennika" to data.registerId,
|
||||||
"pidRokSzkolny" to data.schoolYearId,
|
"pidRokSzkolny" to data.schoolYearId,
|
||||||
"data" to weekStart.stringY_m_d+"T10:00:00.000Z"
|
"data" to "${weekStart.stringY_m_d}T10:00:00.000Z"
|
||||||
)) { result ->
|
)) { result ->
|
||||||
val json = result.getJsonObject("d") ?: run {
|
val json = result.getJsonObject("d") ?: run {
|
||||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
||||||
@ -56,73 +61,132 @@ class IdziennikWebTimetable(override val data: DataIdziennik,
|
|||||||
data.lessonRanges[lessonRange.lessonNumber] = lessonRange
|
data.lessonRanges[lessonRange.lessonNumber] = lessonRange
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val dates = mutableSetOf<Int>()
|
||||||
|
val lessons = mutableListOf<Lesson>()
|
||||||
|
|
||||||
json.getJsonArray("Przedmioty")?.asJsonObjectList()?.forEach { lesson ->
|
json.getJsonArray("Przedmioty")?.asJsonObjectList()?.forEach { lesson ->
|
||||||
val subject = data.getSubject(
|
val subject = data.getSubject(
|
||||||
lesson.getString("Nazwa") ?: return@forEach,
|
lesson.getString("Nazwa") ?: return@forEach,
|
||||||
lesson.getLong("Id"),
|
lesson.getLong("Id"),
|
||||||
lesson.getString("Skrot") ?: ""
|
lesson.getString("Skrot") ?: ""
|
||||||
)
|
)
|
||||||
val teacher = data.getTeacherByFDotLast(lesson.getString("Nauczyciel") ?: return@forEach)
|
val teacher = data.getTeacherByFDotLast(lesson.getString("Nauczyciel")
|
||||||
val weekDay = lesson.getInt("DzienTygodnia")?.minus(1) ?: return@forEach
|
?: return@forEach)
|
||||||
val lessonRange = data.lessonRanges[lesson.getInt("Godzina")?.plus(1) ?: return@forEach]
|
|
||||||
|
|
||||||
val lessonObject = Lesson(
|
val newSubjectName = lesson.getString("PrzedmiotZastepujacy")
|
||||||
profileId,
|
val newSubject = when (newSubjectName.isNullOrBlank()) {
|
||||||
weekDay,
|
true -> null
|
||||||
lessonRange.startTime,
|
else -> data.getSubject(newSubjectName, null, newSubjectName)
|
||||||
lessonRange.endTime
|
|
||||||
).apply {
|
|
||||||
subjectId = subject.id
|
|
||||||
teacherId = teacher.id
|
|
||||||
teamId = data.teamClass?.id ?: -1
|
|
||||||
classroomName = lesson.getString("NazwaSali") ?: ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data.lessonList.add(lessonObject)
|
val newTeacherName = lesson.getString("NauZastepujacy")
|
||||||
|
val newTeacher = when (newTeacherName.isNullOrBlank()) {
|
||||||
|
true -> null
|
||||||
|
else -> data.getTeacherByFDotLast(newTeacherName)
|
||||||
|
}
|
||||||
|
|
||||||
|
val weekDay = lesson.getInt("DzienTygodnia")?.minus(1) ?: return@forEach
|
||||||
|
val lessonRange = data.lessonRanges[lesson.getInt("Godzina")?.plus(1)
|
||||||
|
?: return@forEach]
|
||||||
|
val lessonDate = weekStart.clone().stepForward(0, 0, weekDay)
|
||||||
|
val classroom = lesson.getString("NazwaSali")
|
||||||
|
|
||||||
val type = lesson.getInt("TypZastepstwa") ?: -1
|
val type = lesson.getInt("TypZastepstwa") ?: -1
|
||||||
if (type != -1) {
|
|
||||||
// we have a lesson change to process
|
|
||||||
val lessonChangeObject = LessonChange(
|
|
||||||
profileId,
|
|
||||||
weekStart.clone().stepForward(0, 0, weekDay),
|
|
||||||
lessonObject.startTime,
|
|
||||||
lessonObject.endTime
|
|
||||||
)
|
|
||||||
|
|
||||||
lessonChangeObject.teamId = lessonObject.teamId
|
val lessonObject = Lesson(profileId, -1)
|
||||||
lessonChangeObject.teacherId = lessonObject.teacherId
|
|
||||||
lessonChangeObject.subjectId = lessonObject.subjectId
|
when (type) {
|
||||||
lessonChangeObject.classroomName = lessonObject.classroomName
|
1, 2, 3, 4, 5 -> {
|
||||||
when (type) {
|
lessonObject.apply {
|
||||||
0 -> lessonChangeObject.type = TYPE_CANCELLED
|
this.type = Lesson.TYPE_CHANGE
|
||||||
1, 2, 3, 4, 5 -> {
|
|
||||||
lessonChangeObject.type = TYPE_CHANGE
|
this.date = lessonDate
|
||||||
val newTeacher = lesson.getString("NauZastepujacy")
|
this.lessonNumber = lessonRange.lessonNumber
|
||||||
val newSubject = lesson.getString("PrzedmiotZastepujacy")
|
this.startTime = lessonRange.startTime
|
||||||
if (newTeacher != null) {
|
this.endTime = lessonRange.endTime
|
||||||
lessonChangeObject.teacherId = data.getTeacherByFDotLast(newTeacher).id
|
this.subjectId = newSubject?.id
|
||||||
}
|
this.teacherId = newTeacher?.id
|
||||||
if (newSubject != null) {
|
this.teamId = data.teamClass?.id
|
||||||
lessonChangeObject.subjectId = data.getSubject(newSubject, null, "").id
|
this.classroom = classroom
|
||||||
}
|
|
||||||
|
this.oldDate = lessonDate
|
||||||
|
this.oldLessonNumber = lessonRange.lessonNumber
|
||||||
|
this.oldStartTime = lessonRange.startTime
|
||||||
|
this.oldEndTime = lessonRange.endTime
|
||||||
|
this.oldSubjectId = subject.id
|
||||||
|
this.oldTeacherId = teacher.id
|
||||||
|
this.oldTeamId = data.teamClass?.id
|
||||||
|
this.oldClassroom = classroom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
0 -> {
|
||||||
|
lessonObject.apply {
|
||||||
|
this.type = Lesson.TYPE_CANCELLED
|
||||||
|
|
||||||
data.lessonChangeList.add(lessonChangeObject)
|
this.oldDate = lessonDate
|
||||||
|
this.oldLessonNumber = lessonRange.lessonNumber
|
||||||
|
this.oldStartTime = lessonRange.startTime
|
||||||
|
this.oldEndTime = lessonRange.endTime
|
||||||
|
this.oldSubjectId = subject.id
|
||||||
|
this.oldTeacherId = teacher.id
|
||||||
|
this.oldTeamId = data.teamClass?.id
|
||||||
|
this.oldClassroom = classroom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
lessonObject.apply {
|
||||||
|
this.type = Lesson.TYPE_NORMAL
|
||||||
|
|
||||||
|
this.date = lessonDate
|
||||||
|
this.lessonNumber = lessonRange.lessonNumber
|
||||||
|
this.startTime = lessonRange.startTime
|
||||||
|
this.endTime = lessonRange.endTime
|
||||||
|
this.subjectId = subject.id
|
||||||
|
this.teacherId = teacher.id
|
||||||
|
this.teamId = data.teamClass?.id
|
||||||
|
this.classroom = classroom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lessonObject.id = lessonObject.buildId()
|
||||||
|
|
||||||
|
dates.add(lessonDate.value)
|
||||||
|
lessons.add(lessonObject)
|
||||||
|
|
||||||
|
val seen = profile.empty || lessonDate < Date.getToday()
|
||||||
|
|
||||||
|
if (lessonObject.type != Lesson.TYPE_NORMAL && lessonDate >= Date.getToday()) {
|
||||||
data.metadataList.add(Metadata(
|
data.metadataList.add(Metadata(
|
||||||
profileId,
|
profileId,
|
||||||
Metadata.TYPE_LESSON_CHANGE,
|
Metadata.TYPE_LESSON_CHANGE,
|
||||||
lessonChangeObject.id,
|
lessonObject.id,
|
||||||
profile?.empty ?: false,
|
seen,
|
||||||
profile?.empty ?: false,
|
seen,
|
||||||
System.currentTimeMillis()
|
System.currentTimeMillis()
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val date: Date = weekStart.clone()
|
||||||
|
while (date <= weekEnd) {
|
||||||
|
if (!dates.contains(date.value)) {
|
||||||
|
lessons.add(Lesson(profileId, date.value.toLong()).apply {
|
||||||
|
this.type = Lesson.TYPE_NO_LESSONS
|
||||||
|
this.date = date.clone()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
date.stepForward(0, 0, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
||||||
|
|
||||||
|
data.lessonNewList.addAll(lessons)
|
||||||
|
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
|
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,14 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.interfaces
|
package pl.szczodrzynski.edziennik.api.v2.interfaces
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||||
|
|
||||||
interface EdziennikInterface {
|
interface EdziennikInterface {
|
||||||
fun sync(featureIds: List<Int>, viewId: Int? = null)
|
fun sync(featureIds: List<Int>, viewId: Int? = null, arguments: JsonObject? = null)
|
||||||
fun getMessage(messageId: Int)
|
fun getMessage(message: MessageFull)
|
||||||
fun markAllAnnouncementsAsRead()
|
fun markAllAnnouncementsAsRead()
|
||||||
|
fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String)
|
||||||
fun firstLogin()
|
fun firstLogin()
|
||||||
fun cancel()
|
fun cancel()
|
||||||
}
|
}
|
||||||
|
@ -4,20 +4,20 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.librus
|
package pl.szczodrzynski.edziennik.api.v2.librus
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
import pl.szczodrzynski.edziennik.api.v2.*
|
||||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusData
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusData
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.messages.LibrusMessagesGetAttachment
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.messages.LibrusMessagesGetMessage
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.synergia.LibrusSynergiaMarkAllAnnouncementsAsRead
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.synergia.LibrusSynergiaMarkAllAnnouncementsAsRead
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.firstlogin.LibrusFirstLogin
|
import pl.szczodrzynski.edziennik.api.v2.librus.firstlogin.LibrusFirstLogin
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLogin
|
import pl.szczodrzynski.edziennik.api.v2.librus.login.*
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginApi
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginSynergia
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librusLoginMethods
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
import pl.szczodrzynski.edziennik.api.v2.prepare
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
|
||||||
@ -51,26 +51,69 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
|||||||
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
||||||
__/ |
|
__/ |
|
||||||
|__*/
|
|__*/
|
||||||
override fun sync(featureIds: List<Int>, viewId: Int?) {
|
override fun sync(featureIds: List<Int>, viewId: Int?, arguments: JsonObject?) {
|
||||||
|
data.arguments = arguments
|
||||||
data.prepare(librusLoginMethods, LibrusFeatures, featureIds, viewId)
|
data.prepare(librusLoginMethods, LibrusFeatures, featureIds, viewId)
|
||||||
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
login()
|
||||||
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
}
|
||||||
|
|
||||||
|
private fun login() {
|
||||||
|
d(TAG, "Trying to login with ${data.targetLoginMethodIds}")
|
||||||
|
if (internalErrorList.isNotEmpty()) {
|
||||||
|
d(TAG, " - Internal errors:")
|
||||||
|
internalErrorList.forEach { d(TAG, " - code $it") }
|
||||||
|
}
|
||||||
LibrusLogin(data) {
|
LibrusLogin(data) {
|
||||||
LibrusData(data) {
|
data()
|
||||||
completed()
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun data() {
|
||||||
|
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
||||||
|
if (internalErrorList.isNotEmpty()) {
|
||||||
|
d(TAG, " - Internal errors:")
|
||||||
|
internalErrorList.forEach { d(TAG, " - code $it") }
|
||||||
|
}
|
||||||
|
LibrusData(data) {
|
||||||
|
completed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMessage(message: MessageFull) {
|
||||||
|
LibrusLoginPortal(data) {
|
||||||
|
LibrusLoginApi(data) {
|
||||||
|
LibrusLoginSynergia(data) {
|
||||||
|
LibrusLoginMessages(data) {
|
||||||
|
LibrusMessagesGetMessage(data, message) {
|
||||||
|
completed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getMessage(messageId: Int) {
|
override fun markAllAnnouncementsAsRead() {
|
||||||
|
LibrusLoginPortal(data) {
|
||||||
|
LibrusLoginApi(data) {
|
||||||
|
LibrusLoginSynergia(data) {
|
||||||
|
LibrusSynergiaMarkAllAnnouncementsAsRead(data) {
|
||||||
|
completed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun markAllAnnouncementsAsRead() {
|
override fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String) {
|
||||||
LibrusLoginApi(data) {
|
LibrusLoginPortal(data) {
|
||||||
LibrusLoginSynergia(data) {
|
LibrusLoginApi(data) {
|
||||||
LibrusSynergiaMarkAllAnnouncementsAsRead(data) {
|
LibrusLoginSynergia(data) {
|
||||||
completed()
|
LibrusLoginMessages(data) {
|
||||||
|
LibrusMessagesGetAttachment(data, messageId, attachmentId, attachmentName) {
|
||||||
|
completed()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,15 +145,70 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onError(apiError: ApiError) {
|
override fun onError(apiError: ApiError) {
|
||||||
|
if (apiError.errorCode in internalErrorList) {
|
||||||
|
// finish immediately if the same error occurs twice during the same sync
|
||||||
|
callback.onError(apiError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
internalErrorList.add(apiError.errorCode)
|
||||||
when (apiError.errorCode) {
|
when (apiError.errorCode) {
|
||||||
in internalErrorList -> {
|
ERROR_LIBRUS_PORTAL_ACCESS_DENIED -> {
|
||||||
// finish immediately if the same error occurs twice during the same sync
|
data.loginMethods.remove(LOGIN_METHOD_LIBRUS_PORTAL)
|
||||||
callback.onError(apiError)
|
data.targetLoginMethodIds.add(LOGIN_METHOD_LIBRUS_PORTAL)
|
||||||
|
data.targetLoginMethodIds.sort()
|
||||||
|
data.portalTokenExpiryTime = 0
|
||||||
|
login()
|
||||||
}
|
}
|
||||||
CODE_INTERNAL_LIBRUS_ACCOUNT_410 -> {
|
ERROR_LIBRUS_API_ACCESS_DENIED,
|
||||||
internalErrorList.add(apiError.errorCode)
|
ERROR_LIBRUS_API_TOKEN_EXPIRED -> {
|
||||||
loginStore.removeLoginData("refreshToken") // force a clean login
|
data.loginMethods.remove(LOGIN_METHOD_LIBRUS_API)
|
||||||
//loginLibrus()
|
data.targetLoginMethodIds.add(LOGIN_METHOD_LIBRUS_API)
|
||||||
|
data.targetLoginMethodIds.sort()
|
||||||
|
data.apiTokenExpiryTime = 0
|
||||||
|
login()
|
||||||
|
}
|
||||||
|
ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED -> {
|
||||||
|
data.loginMethods.remove(LOGIN_METHOD_LIBRUS_SYNERGIA)
|
||||||
|
data.targetLoginMethodIds.add(LOGIN_METHOD_LIBRUS_SYNERGIA)
|
||||||
|
data.targetLoginMethodIds.sort()
|
||||||
|
data.synergiaSessionIdExpiryTime = 0
|
||||||
|
login()
|
||||||
|
}
|
||||||
|
ERROR_LIBRUS_MESSAGES_ACCESS_DENIED -> {
|
||||||
|
data.loginMethods.remove(LOGIN_METHOD_LIBRUS_MESSAGES)
|
||||||
|
data.targetLoginMethodIds.add(LOGIN_METHOD_LIBRUS_MESSAGES)
|
||||||
|
data.targetLoginMethodIds.sort()
|
||||||
|
data.messagesSessionIdExpiryTime = 0
|
||||||
|
login()
|
||||||
|
}
|
||||||
|
ERROR_LOGIN_LIBRUS_PORTAL_NO_CODE,
|
||||||
|
ERROR_LOGIN_LIBRUS_PORTAL_CSRF_MISSING,
|
||||||
|
ERROR_LOGIN_LIBRUS_PORTAL_CODE_REVOKED,
|
||||||
|
ERROR_LOGIN_LIBRUS_PORTAL_CODE_EXPIRED -> {
|
||||||
|
login()
|
||||||
|
}
|
||||||
|
ERROR_LOGIN_LIBRUS_PORTAL_NO_REFRESH,
|
||||||
|
ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_REVOKED,
|
||||||
|
ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_INVALID -> {
|
||||||
|
data.portalRefreshToken = null
|
||||||
|
login()
|
||||||
|
}
|
||||||
|
ERROR_LOGIN_LIBRUS_SYNERGIA_TOKEN_INVALID,
|
||||||
|
ERROR_LOGIN_LIBRUS_SYNERGIA_NO_TOKEN,
|
||||||
|
ERROR_LOGIN_LIBRUS_SYNERGIA_NO_SESSION_ID -> {
|
||||||
|
login()
|
||||||
|
}
|
||||||
|
ERROR_LOGIN_LIBRUS_MESSAGES_NO_SESSION_ID -> {
|
||||||
|
login()
|
||||||
|
}
|
||||||
|
// TODO PORTAL CAPTCHA
|
||||||
|
ERROR_LIBRUS_API_TIMETABLE_NOT_PUBLIC -> {
|
||||||
|
loginStore.putLoginData("timetableNotPublic", true)
|
||||||
|
data()
|
||||||
|
}
|
||||||
|
ERROR_LIBRUS_API_LUCKY_NUMBER_NOT_ACTIVE,
|
||||||
|
ERROR_LIBRUS_API_NOTES_NOT_ACTIVE -> {
|
||||||
|
data()
|
||||||
}
|
}
|
||||||
else -> callback.onError(apiError)
|
else -> callback.onError(apiError)
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_GC = 1023
|
|||||||
const val ENDPOINT_LIBRUS_API_TEXT_GC = 1024
|
const val ENDPOINT_LIBRUS_API_TEXT_GC = 1024
|
||||||
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GC = 1025
|
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GC = 1025
|
||||||
const val ENDPOINT_LIBRUS_API_BEHAVIOUR_GC = 1026
|
const val ENDPOINT_LIBRUS_API_BEHAVIOUR_GC = 1026
|
||||||
|
const val ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS = 1030
|
||||||
const val ENDPOINT_LIBRUS_API_NORMAL_GRADES = 1031
|
const val ENDPOINT_LIBRUS_API_NORMAL_GRADES = 1031
|
||||||
const val ENDPOINT_LIBRUS_API_POINT_GRADES = 1032
|
const val ENDPOINT_LIBRUS_API_POINT_GRADES = 1032
|
||||||
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES = 1033
|
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES = 1033
|
||||||
@ -97,6 +98,7 @@ val LibrusFeatures = listOf(
|
|||||||
ENDPOINT_LIBRUS_API_TEXT_GC to LOGIN_METHOD_LIBRUS_API,
|
ENDPOINT_LIBRUS_API_TEXT_GC to LOGIN_METHOD_LIBRUS_API,
|
||||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GC to LOGIN_METHOD_LIBRUS_API,
|
ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GC to LOGIN_METHOD_LIBRUS_API,
|
||||||
ENDPOINT_LIBRUS_API_BEHAVIOUR_GC to LOGIN_METHOD_LIBRUS_API,
|
ENDPOINT_LIBRUS_API_BEHAVIOUR_GC to LOGIN_METHOD_LIBRUS_API,
|
||||||
|
ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS to LOGIN_METHOD_LIBRUS_API,
|
||||||
ENDPOINT_LIBRUS_API_NORMAL_GRADES to LOGIN_METHOD_LIBRUS_API,
|
ENDPOINT_LIBRUS_API_NORMAL_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||||
ENDPOINT_LIBRUS_API_POINT_GRADES to LOGIN_METHOD_LIBRUS_API,
|
ENDPOINT_LIBRUS_API_POINT_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES to LOGIN_METHOD_LIBRUS_API,
|
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||||
|
@ -28,10 +28,17 @@ open class LibrusApi(open val data: DataLibrus) {
|
|||||||
|
|
||||||
fun apiGet(tag: String, endpoint: String, method: Int = GET, payload: JsonObject? = null, onSuccess: (json: JsonObject) -> Unit) {
|
fun apiGet(tag: String, endpoint: String, method: Int = GET, payload: JsonObject? = null, onSuccess: (json: JsonObject) -> Unit) {
|
||||||
|
|
||||||
d(tag, "Request: Librus/Api - $LIBRUS_API_URL/$endpoint")
|
d(tag, "Request: Librus/Api - ${if (data.fakeLogin) FAKE_LIBRUS_API else LIBRUS_API_URL}/$endpoint")
|
||||||
|
|
||||||
val callback = object : JsonCallbackHandler() {
|
val callback = object : JsonCallbackHandler() {
|
||||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||||
|
if (response?.code() == HTTP_UNAVAILABLE) {
|
||||||
|
data.error(ApiError(tag, ERROR_LIBRUS_API_MAINTENANCE)
|
||||||
|
.withApiResponse(json)
|
||||||
|
.withResponse(response))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (json == null && response?.parserErrorBody == null) {
|
if (json == null && response?.parserErrorBody == null) {
|
||||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||||
.withResponse(response))
|
.withResponse(response))
|
||||||
@ -90,7 +97,7 @@ open class LibrusApi(open val data: DataLibrus) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Request.builder()
|
Request.builder()
|
||||||
.url("$LIBRUS_API_URL/$endpoint")
|
.url("${if (data.fakeLogin) FAKE_LIBRUS_API else LIBRUS_API_URL}/$endpoint")
|
||||||
.userAgent(LIBRUS_USER_AGENT)
|
.userAgent(LIBRUS_USER_AGENT)
|
||||||
.addHeader("Authorization", "Bearer ${data.apiAccessToken}")
|
.addHeader("Authorization", "Bearer ${data.apiAccessToken}")
|
||||||
.apply {
|
.apply {
|
||||||
@ -104,6 +111,7 @@ open class LibrusApi(open val data: DataLibrus) {
|
|||||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||||
.allowErrorCode(HTTP_FORBIDDEN)
|
.allowErrorCode(HTTP_FORBIDDEN)
|
||||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||||
|
.allowErrorCode(HTTP_UNAVAILABLE)
|
||||||
.callback(callback)
|
.callback(callback)
|
||||||
.build()
|
.build()
|
||||||
.enqueue()
|
.enqueue()
|
||||||
|
@ -45,92 +45,103 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
*/
|
*/
|
||||||
ENDPOINT_LIBRUS_API_ME -> {
|
ENDPOINT_LIBRUS_API_ME -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_student_info)
|
data.startProgress(R.string.edziennik_progress_endpoint_student_info)
|
||||||
LibrusApiMe(data) { onSuccess() }
|
LibrusApiMe(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_SCHOOLS -> {
|
ENDPOINT_LIBRUS_API_SCHOOLS -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_school_info)
|
data.startProgress(R.string.edziennik_progress_endpoint_school_info)
|
||||||
LibrusApiSchools(data) { onSuccess() }
|
LibrusApiSchools(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_CLASSES -> {
|
ENDPOINT_LIBRUS_API_CLASSES -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_classes)
|
data.startProgress(R.string.edziennik_progress_endpoint_classes)
|
||||||
LibrusApiClasses(data) { onSuccess() }
|
LibrusApiClasses(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES -> {
|
ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_teams)
|
data.startProgress(R.string.edziennik_progress_endpoint_teams)
|
||||||
LibrusApiVirtualClasses(data) { onSuccess() }
|
LibrusApiVirtualClasses(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_UNITS -> {
|
ENDPOINT_LIBRUS_API_UNITS -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_units)
|
data.startProgress(R.string.edziennik_progress_endpoint_units)
|
||||||
LibrusApiUnits(data) { onSuccess() }
|
LibrusApiUnits(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_USERS -> {
|
ENDPOINT_LIBRUS_API_USERS -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_teachers)
|
data.startProgress(R.string.edziennik_progress_endpoint_teachers)
|
||||||
LibrusApiUsers(data) { onSuccess() }
|
LibrusApiUsers(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_SUBJECTS -> {
|
ENDPOINT_LIBRUS_API_SUBJECTS -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_subjects)
|
data.startProgress(R.string.edziennik_progress_endpoint_subjects)
|
||||||
LibrusApiSubjects(data) { onSuccess() }
|
LibrusApiSubjects(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_CLASSROOMS -> {
|
ENDPOINT_LIBRUS_API_CLASSROOMS -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_classrooms)
|
data.startProgress(R.string.edziennik_progress_endpoint_classrooms)
|
||||||
LibrusApiClassrooms(data) { onSuccess() }
|
LibrusApiClassrooms(data, onSuccess)
|
||||||
}
|
}
|
||||||
// TODO push config
|
// TODO push config
|
||||||
// TODO timetable
|
ENDPOINT_LIBRUS_API_TIMETABLES -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
||||||
|
LibrusApiTimetables(data, onSuccess)
|
||||||
|
}
|
||||||
|
|
||||||
ENDPOINT_LIBRUS_API_NORMAL_GRADES -> {
|
ENDPOINT_LIBRUS_API_NORMAL_GRADES -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
||||||
LibrusApiGrades(data) { onSuccess() }
|
LibrusApiGrades(data, onSuccess)
|
||||||
|
}
|
||||||
|
ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_grade_comments)
|
||||||
|
LibrusApiGradeComments(data, onSuccess)
|
||||||
|
}
|
||||||
|
ENDPOINT_LIBRUS_API_NORMAL_GC -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_grade_categories)
|
||||||
|
LibrusApiGradeCategories(data, onSuccess)
|
||||||
}
|
}
|
||||||
// TODO grades
|
// TODO grades
|
||||||
|
|
||||||
ENDPOINT_LIBRUS_API_EVENT_TYPES -> {
|
ENDPOINT_LIBRUS_API_EVENT_TYPES -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_event_types)
|
data.startProgress(R.string.edziennik_progress_endpoint_event_types)
|
||||||
LibrusApiEventTypes(data) { onSuccess() }
|
LibrusApiEventTypes(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_EVENTS -> {
|
ENDPOINT_LIBRUS_API_EVENTS -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_events)
|
data.startProgress(R.string.edziennik_progress_endpoint_events)
|
||||||
LibrusApiEvents(data) { onSuccess() }
|
LibrusApiEvents(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_HOMEWORK -> {
|
ENDPOINT_LIBRUS_API_HOMEWORK -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
||||||
LibrusApiHomework(data) { onSuccess() }
|
LibrusApiHomework(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_LUCKY_NUMBER -> {
|
ENDPOINT_LIBRUS_API_LUCKY_NUMBER -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
|
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
|
||||||
LibrusApiLuckyNumber(data) { onSuccess() }
|
LibrusApiLuckyNumber(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_NOTICE_TYPES -> {
|
ENDPOINT_LIBRUS_API_NOTICE_TYPES -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_notice_types)
|
data.startProgress(R.string.edziennik_progress_endpoint_notice_types)
|
||||||
LibrusApiNoticeTypes(data) { onSuccess() }
|
LibrusApiNoticeTypes(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_NOTICES -> {
|
ENDPOINT_LIBRUS_API_NOTICES -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
||||||
LibrusApiNotices(data) { onSuccess() }
|
LibrusApiNotices(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES -> {
|
ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance_types)
|
data.startProgress(R.string.edziennik_progress_endpoint_attendance_types)
|
||||||
LibrusApiAttendanceTypes(data) { onSuccess() }
|
LibrusApiAttendanceTypes(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_ATTENDANCES -> {
|
ENDPOINT_LIBRUS_API_ATTENDANCES -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
||||||
LibrusApiAttendances(data) { onSuccess() }
|
LibrusApiAttendances(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_ANNOUNCEMENTS -> {
|
ENDPOINT_LIBRUS_API_ANNOUNCEMENTS -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_announcements)
|
data.startProgress(R.string.edziennik_progress_endpoint_announcements)
|
||||||
LibrusApiAnnouncements(data) { onSuccess() }
|
LibrusApiAnnouncements(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_PT_MEETINGS -> {
|
ENDPOINT_LIBRUS_API_PT_MEETINGS -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_pt_meetings)
|
data.startProgress(R.string.edziennik_progress_endpoint_pt_meetings)
|
||||||
LibrusApiPtMeetings(data) { onSuccess() }
|
LibrusApiPtMeetings(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES -> {
|
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_teacher_free_day_types)
|
data.startProgress(R.string.edziennik_progress_endpoint_teacher_free_day_types)
|
||||||
LibrusApiTeacherFreeDayTypes(data) { onSuccess() }
|
LibrusApiTeacherFreeDayTypes(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS -> {
|
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_teacher_free_days)
|
data.startProgress(R.string.edziennik_progress_endpoint_teacher_free_days)
|
||||||
LibrusApiTeacherFreeDays(data) { onSuccess() }
|
LibrusApiTeacherFreeDays(data, onSuccess)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -138,11 +149,11 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
*/
|
*/
|
||||||
ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK -> {
|
ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
||||||
LibrusSynergiaHomework(data) { onSuccess() }
|
LibrusSynergiaHomework(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_SYNERGIA_INFO -> {
|
ENDPOINT_LIBRUS_SYNERGIA_INFO -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_student_info)
|
data.startProgress(R.string.edziennik_progress_endpoint_student_info)
|
||||||
LibrusSynergiaInfo(data) { onSuccess() }
|
LibrusSynergiaInfo(data, onSuccess)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -150,11 +161,11 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
*/
|
*/
|
||||||
ENDPOINT_LIBRUS_MESSAGES_RECEIVED -> {
|
ENDPOINT_LIBRUS_MESSAGES_RECEIVED -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
||||||
LibrusMessagesGetList(data, type = Message.TYPE_RECEIVED) { onSuccess() }
|
LibrusMessagesGetList(data, type = Message.TYPE_RECEIVED, onSuccess = onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_MESSAGES_SENT -> {
|
ENDPOINT_LIBRUS_MESSAGES_SENT -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
|
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
|
||||||
LibrusMessagesGetList(data, type = Message.TYPE_SENT) { onSuccess() }
|
LibrusMessagesGetList(data, type = Message.TYPE_SENT, onSuccess = onSuccess)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> onSuccess()
|
else -> onSuccess()
|
||||||
|
@ -4,21 +4,28 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.librus.data
|
package pl.szczodrzynski.edziennik.api.v2.librus.data
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
import im.wangchao.mhttp.Request
|
import im.wangchao.mhttp.Request
|
||||||
import im.wangchao.mhttp.Response
|
import im.wangchao.mhttp.Response
|
||||||
import im.wangchao.mhttp.body.MediaTypeUtils
|
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 im.wangchao.mhttp.callback.TextCallbackHandler
|
||||||
import okhttp3.Cookie
|
import okhttp3.Cookie
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.parser.Parser
|
import org.jsoup.parser.Parser
|
||||||
import org.redundent.kotlin.xml.PrintOptions
|
|
||||||
import org.redundent.kotlin.xml.xml
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.*
|
import pl.szczodrzynski.edziennik.api.v2.*
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
import pl.szczodrzynski.edziennik.get
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
import java.io.File
|
||||||
|
import java.io.StringWriter
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory
|
||||||
|
import javax.xml.transform.OutputKeys
|
||||||
|
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) {
|
||||||
companion object {
|
companion object {
|
||||||
@ -39,19 +46,19 @@ open class LibrusMessages(open val data: DataLibrus) {
|
|||||||
val callback = object : TextCallbackHandler() {
|
val callback = object : TextCallbackHandler() {
|
||||||
override fun onSuccess(text: String?, response: Response?) {
|
override fun onSuccess(text: String?, response: Response?) {
|
||||||
if (text.isNullOrEmpty()) {
|
if (text.isNullOrEmpty()) {
|
||||||
data.error(ApiError(LibrusSynergia.TAG, ERROR_RESPONSE_EMPTY)
|
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||||
.withResponse(response))
|
.withResponse(response))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Finish error handling
|
when {
|
||||||
|
text.contains("<message>Niepoprawny login i/lub hasło.</message>") -> data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN, response, text)
|
||||||
if ("error" in text) {
|
text.contains("stop.png") -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
|
||||||
when ("<type>(.*)</type>".toRegex().find(text)?.get(1)) {
|
text.contains("eAccessDeny") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||||
"eAccessDeny" -> data.error(ApiError(tag, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED)
|
text.contains("OffLine") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_MAINTENANCE, response, text)
|
||||||
.withResponse(response)
|
text.contains("<status>error</status>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ERROR, response, text)
|
||||||
.withApiResponse(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)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -80,7 +87,27 @@ open class LibrusMessages(open val data: DataLibrus) {
|
|||||||
.secure().httpOnly().build()
|
.secure().httpOnly().build()
|
||||||
))
|
))
|
||||||
|
|
||||||
val requestXml = xml("service") {
|
|
||||||
|
val docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||||
|
val doc = docBuilder.newDocument()
|
||||||
|
val serviceElement = doc.createElement("service")
|
||||||
|
val headerElement = doc.createElement("header")
|
||||||
|
val dataElement = doc.createElement("data")
|
||||||
|
for ((key, value) in parameters.orEmpty()) {
|
||||||
|
val element = doc.createElement(key)
|
||||||
|
element.appendChild(doc.createTextNode(value.toString()))
|
||||||
|
dataElement.appendChild(element)
|
||||||
|
}
|
||||||
|
serviceElement.appendChild(headerElement)
|
||||||
|
serviceElement.appendChild(dataElement)
|
||||||
|
doc.appendChild(serviceElement)
|
||||||
|
val transformer = TransformerFactory.newInstance().newTransformer()
|
||||||
|
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes")
|
||||||
|
val stringWriter = StringWriter()
|
||||||
|
transformer.transform(DOMSource(doc), StreamResult(stringWriter))
|
||||||
|
val requestXml = stringWriter.toString()
|
||||||
|
|
||||||
|
/*val requestXml = xml("service") {
|
||||||
"header" { }
|
"header" { }
|
||||||
"data" {
|
"data" {
|
||||||
for ((key, value) in parameters.orEmpty()) {
|
for ((key, value) in parameters.orEmpty()) {
|
||||||
@ -92,7 +119,7 @@ open class LibrusMessages(open val data: DataLibrus) {
|
|||||||
}.toString(PrintOptions(
|
}.toString(PrintOptions(
|
||||||
singleLineTextElements = true,
|
singleLineTextElements = true,
|
||||||
useSelfClosingTags = true
|
useSelfClosingTags = true
|
||||||
))
|
))*/
|
||||||
|
|
||||||
Request.builder()
|
Request.builder()
|
||||||
.url("$LIBRUS_MESSAGES_URL/$endpoint")
|
.url("$LIBRUS_MESSAGES_URL/$endpoint")
|
||||||
@ -108,4 +135,95 @@ open class LibrusMessages(open val data: DataLibrus) {
|
|||||||
.build()
|
.build()
|
||||||
.enqueue()
|
.enqueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun sandboxGet(tag: String, action: String, parameters: Map<String, Any>? = null,
|
||||||
|
onSuccess: (json: JsonObject) -> Unit) {
|
||||||
|
|
||||||
|
d(tag, "Request: Librus/Messages - $LIBRUS_SANDBOX_URL$action")
|
||||||
|
|
||||||
|
val callback = object : JsonCallbackHandler() {
|
||||||
|
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||||
|
if (json == null) {
|
||||||
|
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||||
|
.withResponse(response))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
onSuccess(json)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(e)
|
||||||
|
.withApiResponse(json))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||||
|
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(throwable))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Request.builder()
|
||||||
|
.url("$LIBRUS_SANDBOX_URL$action")
|
||||||
|
.userAgent(SYNERGIA_USER_AGENT)
|
||||||
|
.apply {
|
||||||
|
parameters?.forEach { (k, v) ->
|
||||||
|
addParameter(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.post()
|
||||||
|
.callback(callback)
|
||||||
|
.build()
|
||||||
|
.enqueue()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sandboxGetFile(tag: String, action: String, targetFile: File, onSuccess: (file: File) -> Unit,
|
||||||
|
onProgress: (written: Long, total: Long) -> Unit) {
|
||||||
|
|
||||||
|
d(tag, "Request: Librus/Messages - $LIBRUS_SANDBOX_URL$action")
|
||||||
|
|
||||||
|
val callback = object : FileCallbackHandler(targetFile) {
|
||||||
|
override fun onSuccess(file: File?, response: Response?) {
|
||||||
|
if (file == null) {
|
||||||
|
data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
|
||||||
|
.withResponse(response))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
onSuccess(file)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onProgress(bytesWritten: Long, bytesTotal: Long) {
|
||||||
|
try {
|
||||||
|
onProgress(bytesWritten, bytesTotal)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
|
||||||
|
.withThrowable(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||||
|
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(throwable))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Request.builder()
|
||||||
|
.url("$LIBRUS_SANDBOX_URL$action")
|
||||||
|
.userAgent(SYNERGIA_USER_AGENT)
|
||||||
|
.post()
|
||||||
|
.callback(callback)
|
||||||
|
.build()
|
||||||
|
.enqueue()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ open class LibrusPortal(open val data: DataLibrus) {
|
|||||||
|
|
||||||
fun portalGet(tag: String, endpoint: String, method: Int = GET, payload: JsonObject? = null, onSuccess: (json: JsonObject, response: Response?) -> Unit) {
|
fun portalGet(tag: String, endpoint: String, method: Int = GET, payload: JsonObject? = null, onSuccess: (json: JsonObject, response: Response?) -> Unit) {
|
||||||
|
|
||||||
d(tag, "Request: Librus/Portal - $LIBRUS_PORTAL_URL$endpoint")
|
d(tag, "Request: Librus/Portal - ${if (data.fakeLogin) FAKE_LIBRUS_PORTAL else LIBRUS_PORTAL_URL}$endpoint")
|
||||||
|
|
||||||
val callback = object : JsonCallbackHandler() {
|
val callback = object : JsonCallbackHandler() {
|
||||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||||
@ -44,7 +44,10 @@ open class LibrusPortal(open val data: DataLibrus) {
|
|||||||
"Access token is invalid" -> ERROR_LIBRUS_PORTAL_ACCESS_DENIED
|
"Access token is invalid" -> ERROR_LIBRUS_PORTAL_ACCESS_DENIED
|
||||||
"ApiDisabled" -> ERROR_LIBRUS_PORTAL_API_DISABLED
|
"ApiDisabled" -> ERROR_LIBRUS_PORTAL_API_DISABLED
|
||||||
"Account not found" -> ERROR_LIBRUS_PORTAL_SYNERGIA_NOT_FOUND
|
"Account not found" -> ERROR_LIBRUS_PORTAL_SYNERGIA_NOT_FOUND
|
||||||
else -> ERROR_LIBRUS_PORTAL_OTHER
|
else -> when (json.getString("hint")) {
|
||||||
|
"Error while decoding to JSON" -> ERROR_LIBRUS_PORTAL_ACCESS_DENIED
|
||||||
|
else -> ERROR_LIBRUS_PORTAL_OTHER
|
||||||
|
}
|
||||||
}.let { errorCode ->
|
}.let { errorCode ->
|
||||||
data.error(ApiError(tag, errorCode)
|
data.error(ApiError(tag, errorCode)
|
||||||
.withApiResponse(json)
|
.withApiResponse(json)
|
||||||
@ -78,7 +81,7 @@ open class LibrusPortal(open val data: DataLibrus) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Request.builder()
|
Request.builder()
|
||||||
.url(LIBRUS_PORTAL_URL + endpoint)
|
.url((if (data.fakeLogin) FAKE_LIBRUS_PORTAL else LIBRUS_PORTAL_URL) + endpoint)
|
||||||
.userAgent(LIBRUS_USER_AGENT)
|
.userAgent(LIBRUS_USER_AGENT)
|
||||||
.addHeader("Authorization", "Bearer ${data.portalAccessToken}")
|
.addHeader("Authorization", "Bearer ${data.portalAccessToken}")
|
||||||
.apply {
|
.apply {
|
||||||
|
@ -14,7 +14,7 @@ import pl.szczodrzynski.edziennik.utils.Utils.d
|
|||||||
|
|
||||||
open class LibrusSynergia(open val data: DataLibrus) {
|
open class LibrusSynergia(open val data: DataLibrus) {
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "LibrusSynergia"
|
private const val TAG = "LibrusSynergia"
|
||||||
}
|
}
|
||||||
|
|
||||||
val profileId
|
val profileId
|
||||||
|
@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.*
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_EVENTS
|
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_EVENTS
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
@ -69,6 +70,8 @@ class LibrusApiEvents(override val data: DataLibrus,
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_LIBRUS_API_EVENTS, SYNC_ALWAYS)
|
data.setSyncNext(ENDPOINT_LIBRUS_API_EVENTS, SYNC_ALWAYS)
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-5
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import pl.szczodrzynski.edziennik.*
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_NORMAL_GC
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
|
||||||
|
|
||||||
|
class LibrusApiGradeCategories(override val data: DataLibrus,
|
||||||
|
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "LibrusApiGradeCategories"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
apiGet(TAG, "Grades/Categories") { json ->
|
||||||
|
json.getJsonArray("Categories")?.asJsonObjectList()?.forEach { category ->
|
||||||
|
val id = category.getLong("Id") ?: return@forEach
|
||||||
|
val name = category.getString("Name") ?: ""
|
||||||
|
val weight = when (category.getBoolean("CountToTheAverage")) {
|
||||||
|
true -> category.getFloat("Weight") ?: 0f
|
||||||
|
else -> 0f
|
||||||
|
}
|
||||||
|
val color = category.getJsonObject("Color")?.getInt("Id")
|
||||||
|
?.let { data.getColor(it) } ?: Color.BLUE
|
||||||
|
|
||||||
|
val gradeCategoryObject = GradeCategory(
|
||||||
|
profileId,
|
||||||
|
id,
|
||||||
|
weight,
|
||||||
|
color,
|
||||||
|
name
|
||||||
|
)
|
||||||
|
|
||||||
|
data.gradeCategories.put(id, gradeCategoryObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
data.setSyncNext(ENDPOINT_LIBRUS_API_NORMAL_GC, SYNC_ALWAYS)
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-20
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||||
|
import pl.szczodrzynski.edziennik.asJsonObjectList
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
|
||||||
|
import pl.szczodrzynski.edziennik.getJsonArray
|
||||||
|
import pl.szczodrzynski.edziennik.getLong
|
||||||
|
import pl.szczodrzynski.edziennik.getString
|
||||||
|
|
||||||
|
class LibrusApiGradeComments(override val data: DataLibrus,
|
||||||
|
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "LibrusApiGradeComments"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
apiGet(TAG, "Grades/Comments") { json ->
|
||||||
|
|
||||||
|
json.getJsonArray("Comments")?.asJsonObjectList()?.forEach { comment ->
|
||||||
|
val id = comment.getLong("Id") ?: return@forEach
|
||||||
|
val text = comment.getString("Text")
|
||||||
|
|
||||||
|
val gradeCategoryObject = GradeCategory(
|
||||||
|
profileId,
|
||||||
|
id,
|
||||||
|
-1f,
|
||||||
|
-1,
|
||||||
|
text
|
||||||
|
).apply {
|
||||||
|
type = GradeCategory.TYPE_COMMENT
|
||||||
|
}
|
||||||
|
|
||||||
|
data.gradeCategories.put(id, gradeCategoryObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
data.setSyncNext(ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS, SYNC_ALWAYS)
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADE
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
@ -42,12 +43,21 @@ class LibrusApiGrades(override val data: DataLibrus,
|
|||||||
weight = 0f
|
weight = 0f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val description = grade.getJsonArray("Comments")?.asJsonObjectList()?.let { comments ->
|
||||||
|
if (comments.isNotEmpty()) {
|
||||||
|
data.gradeCategories.singleOrNull {
|
||||||
|
it.type == GradeCategory.TYPE_COMMENT
|
||||||
|
&& it.categoryId == comments[0].asJsonObject.getLong("Id")
|
||||||
|
}?.text
|
||||||
|
} else null
|
||||||
|
} ?: ""
|
||||||
|
|
||||||
val gradeObject = Grade(
|
val gradeObject = Grade(
|
||||||
profileId,
|
profileId,
|
||||||
id,
|
id,
|
||||||
categoryName,
|
categoryName,
|
||||||
color,
|
color,
|
||||||
"",
|
description,
|
||||||
name,
|
name,
|
||||||
value,
|
value,
|
||||||
weight,
|
weight,
|
||||||
|
@ -8,6 +8,7 @@ import pl.szczodrzynski.edziennik.*
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_HOMEWORK
|
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_HOMEWORK
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
@ -55,6 +56,8 @@ class LibrusApiHomework(override val data: DataLibrus,
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_LIBRUS_API_HOMEWORK, SYNC_ALWAYS)
|
data.setSyncNext(ENDPOINT_LIBRUS_API_HOMEWORK, SYNC_ALWAYS)
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2019-11-10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||||
|
|
||||||
|
import androidx.core.util.isEmpty
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.*
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_TIMETABLES
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||||
|
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 LibrusApiTimetables(override val data: DataLibrus,
|
||||||
|
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "LibrusApiTimetables"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (data.classrooms.isEmpty()) {
|
||||||
|
data.db.classroomDao().getAllNow(profileId).toSparseArray(data.classrooms) { it.id }
|
||||||
|
}
|
||||||
|
|
||||||
|
val currentWeekStart = Week.getWeekStart()
|
||||||
|
|
||||||
|
if (Date.getToday().weekDay > 4) {
|
||||||
|
currentWeekStart.stepForward(0, 0, 7)
|
||||||
|
}
|
||||||
|
|
||||||
|
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
||||||
|
|
||||||
|
val weekStart = Date.fromY_m_d(getDate)
|
||||||
|
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||||
|
|
||||||
|
apiGet(TAG, "Timetables?weekStart=${weekStart.stringY_m_d}") { json ->
|
||||||
|
val days = json.getJsonObject("Timetable")
|
||||||
|
|
||||||
|
days?.entrySet()?.forEach { (dateString, dayEl) ->
|
||||||
|
val day = dayEl?.asJsonArray
|
||||||
|
|
||||||
|
val lessonDate = dateString?.let { Date.fromY_m_d(it) } ?: return@forEach
|
||||||
|
|
||||||
|
var lessonsFound = false
|
||||||
|
day?.forEach { lessonRangeEl ->
|
||||||
|
val lessonRange = lessonRangeEl?.asJsonArray?.asJsonObjectList()
|
||||||
|
if (lessonRange?.isNullOrEmpty() == false)
|
||||||
|
lessonsFound = true
|
||||||
|
lessonRange?.forEach { lesson ->
|
||||||
|
parseLesson(lessonDate, lesson)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (day.isNullOrEmpty() || !lessonsFound) {
|
||||||
|
data.lessonNewList.add(Lesson(profileId, lessonDate.value.toLong()).apply {
|
||||||
|
type = Lesson.TYPE_NO_LESSONS
|
||||||
|
date = lessonDate
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||||
|
data.setSyncNext(ENDPOINT_LIBRUS_API_TIMETABLES, SYNC_ALWAYS)
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseLesson(lessonDate: Date, lesson: JsonObject) { data.profile?.also { profile ->
|
||||||
|
val isSubstitution = lesson.getBoolean("IsSubstitutionClass") ?: false
|
||||||
|
val isCancelled = lesson.getBoolean("IsCanceled") ?: false
|
||||||
|
|
||||||
|
val lessonNo = lesson.getInt("LessonNo") ?: return
|
||||||
|
val startTime = lesson.getString("HourFrom")?.let { Time.fromH_m(it) } ?: return
|
||||||
|
val endTime = lesson.getString("HourTo")?.let { Time.fromH_m(it) } ?: return
|
||||||
|
val subjectId = lesson.getJsonObject("Subject")?.getLong("Id")
|
||||||
|
val teacherId = lesson.getJsonObject("Teacher")?.getLong("Id")
|
||||||
|
val classroomId = lesson.getJsonObject("Classroom")?.getLong("Id") ?: -1
|
||||||
|
val virtualClassId = lesson.getJsonObject("VirtualClass")?.getLong("Id")
|
||||||
|
val teamId = lesson.getJsonObject("Class")?.getLong("Id") ?: virtualClassId
|
||||||
|
|
||||||
|
val lessonObject = Lesson(profileId, -1)
|
||||||
|
|
||||||
|
if (isSubstitution && isCancelled) {
|
||||||
|
// shifted lesson - source
|
||||||
|
val newDate = lesson.getString("NewDate")?.let { Date.fromY_m_d(it) } ?: return
|
||||||
|
val newLessonNo = lesson.getInt("NewLessonNo") ?: return
|
||||||
|
val newStartTime = lesson.getString("NewHourFrom")?.let { Time.fromH_m(it) } ?: return
|
||||||
|
val newEndTime = lesson.getString("NewHourTo")?.let { Time.fromH_m(it) } ?: return
|
||||||
|
val newSubjectId = lesson.getJsonObject("NewSubject")?.getLong("Id")
|
||||||
|
val newTeacherId = lesson.getJsonObject("NewTeacher")?.getLong("Id")
|
||||||
|
val newClassroomId = lesson.getJsonObject("NewClassroom")?.getLong("Id") ?: -1
|
||||||
|
val newVirtualClassId = lesson.getJsonObject("NewVirtualClass")?.getLong("Id")
|
||||||
|
val newTeamId = lesson.getJsonObject("NewClass")?.getLong("Id") ?: newVirtualClassId
|
||||||
|
|
||||||
|
lessonObject.let {
|
||||||
|
it.type = Lesson.TYPE_SHIFTED_SOURCE
|
||||||
|
it.oldDate = lessonDate
|
||||||
|
it.oldLessonNumber = lessonNo
|
||||||
|
it.oldStartTime = startTime
|
||||||
|
it.oldEndTime = endTime
|
||||||
|
it.oldSubjectId = subjectId
|
||||||
|
it.oldTeacherId = teacherId
|
||||||
|
it.oldTeamId = teamId
|
||||||
|
it.oldClassroom = data.classrooms[classroomId]?.name
|
||||||
|
|
||||||
|
it.date = newDate
|
||||||
|
it.lessonNumber = newLessonNo
|
||||||
|
it.startTime = newStartTime
|
||||||
|
it.endTime = newEndTime
|
||||||
|
it.subjectId = newSubjectId
|
||||||
|
it.teacherId = newTeacherId
|
||||||
|
it.teamId = newTeamId
|
||||||
|
it.classroom = data.classrooms[newClassroomId]?.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isSubstitution) {
|
||||||
|
// lesson change OR shifted lesson - target
|
||||||
|
val oldDate = lesson.getString("OrgDate")?.let { Date.fromY_m_d(it) } ?: return
|
||||||
|
val oldLessonNo = lesson.getInt("OrgLessonNo") ?: return
|
||||||
|
val oldStartTime = lesson.getString("OrgHourFrom")?.let { Time.fromH_m(it) } ?: return
|
||||||
|
val oldEndTime = lesson.getString("OrgHourTo")?.let { Time.fromH_m(it) } ?: return
|
||||||
|
val oldSubjectId = lesson.getJsonObject("OrgSubject")?.getLong("Id")
|
||||||
|
val oldTeacherId = lesson.getJsonObject("OrgTeacher")?.getLong("Id")
|
||||||
|
val oldClassroomId = lesson.getJsonObject("OrgClassroom")?.getLong("Id") ?: -1
|
||||||
|
val oldVirtualClassId = lesson.getJsonObject("OrgVirtualClass")?.getLong("Id")
|
||||||
|
val oldTeamId = lesson.getJsonObject("OrgClass")?.getLong("Id") ?: oldVirtualClassId
|
||||||
|
|
||||||
|
lessonObject.let {
|
||||||
|
it.type = if (lessonDate == oldDate && lessonNo == oldLessonNo) Lesson.TYPE_CHANGE else Lesson.TYPE_SHIFTED_TARGET
|
||||||
|
it.oldDate = oldDate
|
||||||
|
it.oldLessonNumber = oldLessonNo
|
||||||
|
it.oldStartTime = oldStartTime
|
||||||
|
it.oldEndTime = oldEndTime
|
||||||
|
it.oldSubjectId = oldSubjectId
|
||||||
|
it.oldTeacherId = oldTeacherId
|
||||||
|
it.oldTeamId = oldTeamId
|
||||||
|
it.oldClassroom = data.classrooms[oldClassroomId]?.name
|
||||||
|
|
||||||
|
it.date = lessonDate
|
||||||
|
it.lessonNumber = lessonNo
|
||||||
|
it.startTime = startTime
|
||||||
|
it.endTime = endTime
|
||||||
|
it.subjectId = subjectId
|
||||||
|
it.teacherId = teacherId
|
||||||
|
it.teamId = teamId
|
||||||
|
it.classroom = data.classrooms[classroomId]?.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isCancelled) {
|
||||||
|
lessonObject.let {
|
||||||
|
it.type = Lesson.TYPE_CANCELLED
|
||||||
|
it.oldDate = lessonDate
|
||||||
|
it.oldLessonNumber = lessonNo
|
||||||
|
it.oldStartTime = startTime
|
||||||
|
it.oldEndTime = endTime
|
||||||
|
it.oldSubjectId = subjectId
|
||||||
|
it.oldTeacherId = teacherId
|
||||||
|
it.oldTeamId = teamId
|
||||||
|
it.oldClassroom = data.classrooms[classroomId]?.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lessonObject.let {
|
||||||
|
it.type = Lesson.TYPE_NORMAL
|
||||||
|
it.date = lessonDate
|
||||||
|
it.lessonNumber = lessonNo
|
||||||
|
it.startTime = startTime
|
||||||
|
it.endTime = endTime
|
||||||
|
it.subjectId = subjectId
|
||||||
|
it.teacherId = teacherId
|
||||||
|
it.teamId = teamId
|
||||||
|
it.classroom = data.classrooms[classroomId]?.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lessonObject.id = lessonObject.buildId()
|
||||||
|
|
||||||
|
val seen = profile.empty || lessonDate < Date.getToday()
|
||||||
|
|
||||||
|
if (lessonObject.type != Lesson.TYPE_NORMAL) {
|
||||||
|
data.metadataList.add(
|
||||||
|
Metadata(
|
||||||
|
profileId,
|
||||||
|
Metadata.TYPE_LESSON_CHANGE,
|
||||||
|
lessonObject.id,
|
||||||
|
seen,
|
||||||
|
seen,
|
||||||
|
System.currentTimeMillis()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
data.lessonNewList.add(lessonObject)
|
||||||
|
}}
|
||||||
|
}
|
@ -22,8 +22,8 @@ class LibrusApiUsers(override val data: DataLibrus,
|
|||||||
|
|
||||||
users?.forEach { user ->
|
users?.forEach { user ->
|
||||||
val id = user.getLong("Id") ?: return@forEach
|
val id = user.getLong("Id") ?: return@forEach
|
||||||
val firstName = user.getString("FirstName")?.fixWhiteSpaces() ?: ""
|
val firstName = user.getString("FirstName")?.fixName() ?: ""
|
||||||
val lastName = user.getString("LastName")?.fixWhiteSpaces() ?: ""
|
val lastName = user.getString("LastName")?.fixName() ?: ""
|
||||||
|
|
||||||
data.teacherList.put(id, Teacher(profileId, id, firstName, lastName))
|
data.teacherList.put(id, Teacher(profileId, id, firstName, lastName))
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.librus.data.messages
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.ERROR_FILE_DOWNLOAD
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.EXCEPTION_LIBRUS_MESSAGES_REQUEST
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.Regexes
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.events.AttachmentGetEvent
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.events.AttachmentGetEvent.Companion.TYPE_FINISHED
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.events.AttachmentGetEvent.Companion.TYPE_PROGRESS
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusMessages
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.get
|
||||||
|
import pl.szczodrzynski.edziennik.getString
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
|
||||||
|
class LibrusMessagesGetAttachment(override val data: DataLibrus, val messageId: Long, val attachmentId: Long,
|
||||||
|
val attachmentName: String, val onSuccess: () -> Unit) : LibrusMessages(data), CoroutineScope {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "LibrusMessagesGetAttachment"
|
||||||
|
}
|
||||||
|
|
||||||
|
private var job = Job()
|
||||||
|
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = job + Dispatchers.Default
|
||||||
|
|
||||||
|
private var getAttachmentCheckKeyTries = 0
|
||||||
|
|
||||||
|
init {
|
||||||
|
messagesGet(TAG, "GetFileDownloadLink", parameters = mapOf(
|
||||||
|
"fileId" to attachmentId,
|
||||||
|
"msgId" to messageId,
|
||||||
|
"archive" to 0
|
||||||
|
)) { doc ->
|
||||||
|
val downloadLink = doc.select("response GetFileDownloadLink downloadLink").text()
|
||||||
|
val keyMatcher = Regexes.LIBRUS_ATTACHMENT_KEY.find(downloadLink)
|
||||||
|
|
||||||
|
if (keyMatcher != null) {
|
||||||
|
getAttachmentCheckKeyTries = 0
|
||||||
|
|
||||||
|
val attachmentKey = keyMatcher[1]
|
||||||
|
getAttachmentCheckKey(attachmentKey) {
|
||||||
|
downloadAttachment(attachmentKey)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
|
||||||
|
.withApiResponse(doc.toString()))
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAttachmentCheckKey(attachmentKey: String, callback: () -> Unit) {
|
||||||
|
sandboxGet(TAG, "CSCheckKey",
|
||||||
|
parameters = mapOf("singleUseKey" to attachmentKey)) { json ->
|
||||||
|
|
||||||
|
when (json.getString("status")) {
|
||||||
|
"not_downloaded_yet" -> {
|
||||||
|
if (getAttachmentCheckKeyTries++ > 5) {
|
||||||
|
data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
|
||||||
|
.withApiResponse(json))
|
||||||
|
return@sandboxGet
|
||||||
|
}
|
||||||
|
launch {
|
||||||
|
delay(2000)
|
||||||
|
getAttachmentCheckKey(attachmentKey, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"ready" -> {
|
||||||
|
launch { callback() }
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
data.error(ApiError(TAG, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
|
||||||
|
.withApiResponse(json))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun downloadAttachment(attachmentKey: String) {
|
||||||
|
val targetFile = File(Utils.getStorageDir(), attachmentName)
|
||||||
|
|
||||||
|
sandboxGetFile(TAG, "CSDownload&singleUseKey=$attachmentKey",
|
||||||
|
targetFile, { file ->
|
||||||
|
|
||||||
|
val event = AttachmentGetEvent(
|
||||||
|
profileId,
|
||||||
|
messageId,
|
||||||
|
attachmentId,
|
||||||
|
TYPE_FINISHED,
|
||||||
|
file.absolutePath
|
||||||
|
)
|
||||||
|
|
||||||
|
val attachmentDataFile = File(Utils.getStorageDir(), ".${profileId}_${event.messageId}_${event.attachmentId}")
|
||||||
|
Utils.writeStringToFile(attachmentDataFile, event.fileName)
|
||||||
|
|
||||||
|
EventBus.getDefault().post(event)
|
||||||
|
|
||||||
|
}) { written, _ ->
|
||||||
|
val event = AttachmentGetEvent(
|
||||||
|
profileId,
|
||||||
|
messageId,
|
||||||
|
attachmentId,
|
||||||
|
TYPE_PROGRESS,
|
||||||
|
bytesWritten = written
|
||||||
|
)
|
||||||
|
|
||||||
|
EventBus.getDefault().post(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,7 @@ import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_MESSAGES_SENT
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusMessages
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusMessages
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||||
@ -20,7 +21,7 @@ import pl.szczodrzynski.edziennik.singleOrNull
|
|||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int = Message.TYPE_RECEIVED,
|
class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int = TYPE_RECEIVED,
|
||||||
archived: Boolean = false, val onSuccess: () -> Unit) : LibrusMessages(data) {
|
archived: Boolean = false, val onSuccess: () -> Unit) : LibrusMessages(data) {
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "LibrusMessagesGetList"
|
const val TAG = "LibrusMessagesGetList"
|
||||||
@ -28,7 +29,7 @@ class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
val endpoint = when (type) {
|
val endpoint = when (type) {
|
||||||
Message.TYPE_RECEIVED -> "Inbox/action/GetList"
|
TYPE_RECEIVED -> "Inbox/action/GetList"
|
||||||
Message.TYPE_SENT -> "Outbox/action/GetList"
|
Message.TYPE_SENT -> "Outbox/action/GetList"
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
@ -46,34 +47,38 @@ class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int
|
|||||||
else -> 0
|
else -> 0
|
||||||
}
|
}
|
||||||
val sentDate = Date.fromIso(element.select("sendDate").text().trim())
|
val sentDate = Date.fromIso(element.select("sendDate").text().trim())
|
||||||
var senderId: Long = -1
|
|
||||||
var receiverId: Long = -1
|
|
||||||
|
|
||||||
when (type) {
|
val recipientFirstName = element.select(when (type) {
|
||||||
Message.TYPE_RECEIVED -> {
|
TYPE_RECEIVED -> "senderFirstName"
|
||||||
val senderFirstName = element.select("senderFirstName").text().trim()
|
else -> "receiverFirstName"
|
||||||
val senderLastName = element.select("senderLastName").text().trim()
|
}).text().trim()
|
||||||
senderId = data.teacherList.singleOrNull {
|
|
||||||
it.name == senderFirstName && it.surname == senderLastName
|
|
||||||
}?.id ?: -1
|
|
||||||
}
|
|
||||||
|
|
||||||
Message.TYPE_SENT -> {
|
val recipientLastName = element.select(when (type) {
|
||||||
val receiverFirstName = element.select("receiverFirstName").text().trim()
|
TYPE_RECEIVED -> "senderLastName"
|
||||||
val receiverLastName = element.select("receiverLastName").text().trim()
|
else -> "receiverLastName"
|
||||||
receiverId = data.teacherList.singleOrNull {
|
}).text().trim()
|
||||||
it.name == receiverFirstName && it.surname == receiverLastName
|
|
||||||
}?.id ?: {
|
val recipientId = data.teacherList.singleOrNull {
|
||||||
val teacherObject = Teacher(
|
it.name == recipientFirstName && it.surname == recipientLastName
|
||||||
profileId,
|
}?.id ?: {
|
||||||
-1 * Utils.crc16("$receiverFirstName $receiverLastName".toByteArray()).toLong(),
|
val teacherObject = Teacher(
|
||||||
receiverFirstName,
|
profileId,
|
||||||
receiverLastName
|
-1 * Utils.crc16("$recipientFirstName $recipientLastName".toByteArray()).toLong(),
|
||||||
)
|
recipientFirstName,
|
||||||
data.teacherList.put(teacherObject.id, teacherObject)
|
recipientLastName
|
||||||
teacherObject.id
|
)
|
||||||
}.invoke()
|
data.teacherList.put(teacherObject.id, teacherObject)
|
||||||
}
|
teacherObject.id
|
||||||
|
}.invoke()
|
||||||
|
|
||||||
|
val senderId = when (type) {
|
||||||
|
TYPE_RECEIVED -> recipientId
|
||||||
|
else -> -1
|
||||||
|
}
|
||||||
|
|
||||||
|
val receiverId = when (type) {
|
||||||
|
TYPE_RECEIVED -> -1
|
||||||
|
else -> recipientId
|
||||||
}
|
}
|
||||||
|
|
||||||
val notified = when (type) {
|
val notified = when (type) {
|
||||||
@ -99,7 +104,7 @@ class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int
|
|||||||
id
|
id
|
||||||
)
|
)
|
||||||
|
|
||||||
data.messageList.add(messageObject)
|
data.messageIgnoreList.add(messageObject)
|
||||||
data.messageRecipientList.add(messageRecipientObject)
|
data.messageRecipientList.add(messageRecipientObject)
|
||||||
data.metadataList.add(Metadata(
|
data.metadataList.add(Metadata(
|
||||||
profileId,
|
profileId,
|
||||||
@ -112,7 +117,7 @@ class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int
|
|||||||
}
|
}
|
||||||
|
|
||||||
when (type) {
|
when (type) {
|
||||||
Message.TYPE_RECEIVED -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_RECEIVED, SYNC_ALWAYS)
|
TYPE_RECEIVED -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_RECEIVED, SYNC_ALWAYS)
|
||||||
Message.TYPE_SENT -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_SENT, DAY, DRAWER_ITEM_MESSAGES)
|
Message.TYPE_SENT -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_SENT, DAY, DRAWER_ITEM_MESSAGES)
|
||||||
}
|
}
|
||||||
onSuccess()
|
onSuccess()
|
||||||
|
@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-11
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.librus.data.messages
|
||||||
|
|
||||||
|
import android.util.Base64
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.events.MessageGetEvent
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusMessages
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipientFull
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.fixName
|
||||||
|
import pl.szczodrzynski.edziennik.singleOrNull
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
|
||||||
|
class LibrusMessagesGetMessage(
|
||||||
|
override val data: DataLibrus,
|
||||||
|
private val messageObject: MessageFull,
|
||||||
|
val onSuccess: () -> Unit
|
||||||
|
) : LibrusMessages(data) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "LibrusMessagesGetMessage"
|
||||||
|
}
|
||||||
|
|
||||||
|
init { data.profile?.also { profile ->
|
||||||
|
messagesGet(TAG, "GetMessage", parameters = mapOf(
|
||||||
|
"messageId" to messageObject.id,
|
||||||
|
"archive" to 0
|
||||||
|
)) { doc ->
|
||||||
|
val message = doc.select("response GetMessage data").first()
|
||||||
|
|
||||||
|
val body = Base64.decode(message.select("Message").text(), Base64.DEFAULT)
|
||||||
|
.toString(Charset.defaultCharset())
|
||||||
|
.replace("\n", "<br>")
|
||||||
|
.replace("<!\\[CDATA\\[", "")
|
||||||
|
.replace("]]>", "")
|
||||||
|
|
||||||
|
messageObject.apply {
|
||||||
|
this.body = body
|
||||||
|
|
||||||
|
clearAttachments()
|
||||||
|
message.select("attachments ArrayItem").forEach {
|
||||||
|
val attachmentId = it.select("id").text().toLong()
|
||||||
|
val attachmentName = it.select("filename").text()
|
||||||
|
addAttachment(attachmentId, attachmentName, -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val messageRecipientList = mutableListOf<MessageRecipientFull>()
|
||||||
|
|
||||||
|
when (messageObject.type) {
|
||||||
|
TYPE_RECEIVED -> {
|
||||||
|
val senderLoginId = message.select("senderId").text()
|
||||||
|
data.teacherList.singleOrNull { it.id == messageObject.senderId }?.loginId = senderLoginId
|
||||||
|
|
||||||
|
val readDateText = message.select("readDate").text()
|
||||||
|
val readDate = when (readDateText.isNotEmpty()) {
|
||||||
|
true -> Date.fromIso(readDateText)
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
|
||||||
|
val messageRecipientObject = MessageRecipientFull(
|
||||||
|
profileId,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
readDate,
|
||||||
|
messageObject.id
|
||||||
|
)
|
||||||
|
|
||||||
|
messageRecipientObject.fullName = profile.accountNameLong ?: profile.studentNameLong
|
||||||
|
|
||||||
|
messageRecipientList.add(messageRecipientObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPE_SENT -> {
|
||||||
|
|
||||||
|
message.select("receivers ArrayItem").forEach { receiver ->
|
||||||
|
val receiverFirstName = receiver.select("firstName").text().fixName()
|
||||||
|
val receiverLastName = receiver.select("lastName").text().fixName()
|
||||||
|
val receiverLoginId = receiver.select("receiverId").text()
|
||||||
|
|
||||||
|
val teacher = data.teacherList.singleOrNull { it.name == receiverFirstName && it.surname == receiverLastName }
|
||||||
|
val receiverId = teacher?.id ?: -1
|
||||||
|
teacher?.loginId = receiverLoginId
|
||||||
|
|
||||||
|
val readDateText = message.select("readed").text()
|
||||||
|
val readDate = when (readDateText.isNotEmpty()) {
|
||||||
|
true -> Date.fromIso(readDateText)
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
|
||||||
|
val messageRecipientObject = MessageRecipientFull(
|
||||||
|
profileId,
|
||||||
|
receiverId,
|
||||||
|
-1,
|
||||||
|
readDate,
|
||||||
|
messageObject.id
|
||||||
|
)
|
||||||
|
|
||||||
|
messageRecipientObject.fullName = "$receiverFirstName $receiverLastName"
|
||||||
|
|
||||||
|
messageRecipientList.add(messageRecipientObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!messageObject.seen) {
|
||||||
|
data.messageMetadataList.add(Metadata(
|
||||||
|
messageObject.profileId,
|
||||||
|
Metadata.TYPE_MESSAGE,
|
||||||
|
messageObject.id,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
messageObject.addedDate
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
messageObject.recipients = messageRecipientList
|
||||||
|
data.messageRecipientList.addAll(messageRecipientList)
|
||||||
|
data.messageList.add(messageObject)
|
||||||
|
|
||||||
|
EventBus.getDefault().postSticky(MessageGetEvent(messageObject))
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
} ?: onSuccess()}
|
||||||
|
}
|
@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.api.v2.POST
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK
|
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusSynergia
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusSynergia
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
import pl.szczodrzynski.edziennik.get
|
import pl.szczodrzynski.edziennik.get
|
||||||
@ -55,19 +56,18 @@ class LibrusSynergiaHomework(override val data: DataLibrus, val onSuccess: () ->
|
|||||||
val id = "/podglad/([0-9]+)'".toRegex().find(
|
val id = "/podglad/([0-9]+)'".toRegex().find(
|
||||||
elements[9].select("input").attr("onclick")
|
elements[9].select("input").attr("onclick")
|
||||||
)?.get(1)?.toLong() ?: return@forEachIndexed
|
)?.get(1)?.toLong() ?: return@forEachIndexed
|
||||||
val startTime = data.lessonList.singleOrNull {
|
|
||||||
it.weekDay == eventDate.weekDay && it.subjectId == subjectId
|
val lessons = data.db.timetableDao().getForDateNow(profileId, eventDate)
|
||||||
}?.startTime
|
val startTime = lessons.firstOrNull { it.subjectId == subjectId }?.startTime
|
||||||
|
|
||||||
val moreInfo = graphElements[2 * i + 1].select("td[title]")
|
val moreInfo = graphElements[2 * i + 1].select("td[title]")
|
||||||
.attr("title").trim()
|
.attr("title").trim()
|
||||||
val description = "Treść: (.*)".toRegex(RegexOption.DOT_MATCHES_ALL).find(moreInfo)
|
val description = "Treść: (.*)".toRegex(RegexOption.DOT_MATCHES_ALL).find(moreInfo)
|
||||||
?.get(1)?.replace("<br.*/>".toRegex(), "\n")?.trim()
|
?.get(1)?.replace("<br.*/>".toRegex(), "\n")?.trim()
|
||||||
|
|
||||||
val notified = when (profile?.empty) {
|
val seen = when (profile?.empty) {
|
||||||
true -> true
|
true -> true
|
||||||
false -> Date.getToday() < eventDate
|
else -> eventDate < Date.getToday()
|
||||||
else -> false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val eventObject = Event(
|
val eventObject = Event(
|
||||||
@ -89,13 +89,15 @@ class LibrusSynergiaHomework(override val data: DataLibrus, val onSuccess: () ->
|
|||||||
profileId,
|
profileId,
|
||||||
Metadata.TYPE_HOMEWORK,
|
Metadata.TYPE_HOMEWORK,
|
||||||
id,
|
id,
|
||||||
notified,
|
seen,
|
||||||
notified,
|
seen,
|
||||||
addedDate
|
addedDate
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||||
|
|
||||||
// because this requires a synergia login (2 more requests) sync this every two hours or if explicit :D
|
// because this requires a synergia login (2 more requests) sync this every two hours or if explicit :D
|
||||||
data.setSyncNext(ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK, 2 * HOUR, DRAWER_ITEM_HOMEWORK)
|
data.setSyncNext(ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK, 2 * HOUR, DRAWER_ITEM_HOMEWORK)
|
||||||
onSuccess()
|
onSuccess()
|
||||||
|
@ -3,6 +3,7 @@ package pl.szczodrzynski.edziennik.api.v2.librus.firstlogin
|
|||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
import pl.szczodrzynski.edziennik.*
|
import pl.szczodrzynski.edziennik.*
|
||||||
import pl.szczodrzynski.edziennik.api.v2.ERROR_NO_STUDENTS_IN_ACCOUNT
|
import pl.szczodrzynski.edziennik.api.v2.ERROR_NO_STUDENTS_IN_ACCOUNT
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.FAKE_LIBRUS_ACCOUNTS
|
||||||
import pl.szczodrzynski.edziennik.api.v2.LIBRUS_ACCOUNTS_URL
|
import pl.szczodrzynski.edziennik.api.v2.LIBRUS_ACCOUNTS_URL
|
||||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_MODE_LIBRUS_EMAIL
|
import pl.szczodrzynski.edziennik.api.v2.LOGIN_MODE_LIBRUS_EMAIL
|
||||||
import pl.szczodrzynski.edziennik.api.v2.events.FirstLoginFinishedEvent
|
import pl.szczodrzynski.edziennik.api.v2.events.FirstLoginFinishedEvent
|
||||||
@ -29,7 +30,7 @@ class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
if (data.loginStore.mode == LOGIN_MODE_LIBRUS_EMAIL) {
|
if (data.loginStore.mode == LOGIN_MODE_LIBRUS_EMAIL) {
|
||||||
// email login: use Portal for account list
|
// email login: use Portal for account list
|
||||||
LibrusLoginPortal(data) {
|
LibrusLoginPortal(data) {
|
||||||
portal.portalGet(TAG, LIBRUS_ACCOUNTS_URL) { json, response ->
|
portal.portalGet(TAG, if (data.fakeLogin) FAKE_LIBRUS_ACCOUNTS else LIBRUS_ACCOUNTS_URL) { json, response ->
|
||||||
val accounts = json.getJsonArray("accounts")
|
val accounts = json.getJsonArray("accounts")
|
||||||
|
|
||||||
if (accounts == null || accounts.size() < 1) {
|
if (accounts == null || accounts.size() < 1) {
|
||||||
|
@ -16,8 +16,7 @@ import pl.szczodrzynski.edziennik.getInt
|
|||||||
import pl.szczodrzynski.edziennik.getString
|
import pl.szczodrzynski.edziennik.getString
|
||||||
import pl.szczodrzynski.edziennik.getUnixDate
|
import pl.szczodrzynski.edziennik.getUnixDate
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import java.net.HttpURLConnection.HTTP_BAD_REQUEST
|
import java.net.HttpURLConnection.*
|
||||||
import java.net.HttpURLConnection.HTTP_UNAUTHORIZED
|
|
||||||
|
|
||||||
class LibrusLoginApi {
|
class LibrusLoginApi {
|
||||||
companion object {
|
companion object {
|
||||||
@ -117,6 +116,13 @@ class LibrusLoginApi {
|
|||||||
|
|
||||||
private val tokenCallback = object : JsonCallbackHandler() {
|
private val tokenCallback = object : JsonCallbackHandler() {
|
||||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||||
|
if (response?.code() == HTTP_UNAVAILABLE) {
|
||||||
|
data.error(ApiError(TAG, ERROR_LIBRUS_API_MAINTENANCE)
|
||||||
|
.withApiResponse(json)
|
||||||
|
.withResponse(response))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (json == null) {
|
if (json == null) {
|
||||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||||
.withResponse(response))
|
.withResponse(response))
|
||||||
@ -176,6 +182,7 @@ class LibrusLoginApi {
|
|||||||
.post()
|
.post()
|
||||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||||
|
.allowErrorCode(HTTP_UNAVAILABLE)
|
||||||
.callback(tokenCallback)
|
.callback(tokenCallback)
|
||||||
.build()
|
.build()
|
||||||
.enqueue()
|
.enqueue()
|
||||||
|
@ -6,20 +6,57 @@ package pl.szczodrzynski.edziennik.api.v2.librus.login
|
|||||||
|
|
||||||
import im.wangchao.mhttp.Request
|
import im.wangchao.mhttp.Request
|
||||||
import im.wangchao.mhttp.Response
|
import im.wangchao.mhttp.Response
|
||||||
|
import im.wangchao.mhttp.body.MediaTypeUtils
|
||||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||||
import okhttp3.Cookie
|
import okhttp3.Cookie
|
||||||
import pl.szczodrzynski.edziennik.api.v2.*
|
import pl.szczodrzynski.edziennik.api.v2.*
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
import pl.szczodrzynski.edziennik.getUnixDate
|
import pl.szczodrzynski.edziennik.getUnixDate
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
import java.io.StringWriter
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory
|
||||||
|
import javax.xml.transform.OutputKeys
|
||||||
|
import javax.xml.transform.TransformerFactory
|
||||||
|
import javax.xml.transform.dom.DOMSource
|
||||||
|
import javax.xml.transform.stream.StreamResult
|
||||||
|
|
||||||
class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "LoginLibrusMessages"
|
private const val TAG = "LoginLibrusMessages"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val callback by lazy { object : TextCallbackHandler() {
|
||||||
|
override fun onSuccess(text: String?, response: Response?) {
|
||||||
|
val location = response?.headers()?.get("Location")
|
||||||
|
when {
|
||||||
|
location?.contains("MultiDomainLogon") == true -> loginWithSynergia(location)
|
||||||
|
location?.contains("AutoLogon") == true -> {
|
||||||
|
saveSessionId(response, text)
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
text?.contains("<status>ok</status>") == true -> {
|
||||||
|
saveSessionId(response, text)
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
text?.contains("<message>Niepoprawny login i/lub hasło.</message>") == true -> data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN, response, text)
|
||||||
|
text?.contains("stop.png") == true -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
|
||||||
|
text?.contains("eAccessDeny") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||||
|
text?.contains("OffLine") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_MAINTENANCE, response, text)
|
||||||
|
text?.contains("<status>error</status>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ERROR, response, text)
|
||||||
|
text?.contains("<type>eVarWhitThisNameNotExists</type>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||||
|
text?.contains("<error>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||||
|
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(throwable))
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
init { run {
|
init { run {
|
||||||
if (data.profile == null) {
|
if (data.profile == null) {
|
||||||
data.error(ApiError(TAG, ERROR_PROFILE_MISSING))
|
data.error(ApiError(TAG, ERROR_PROFILE_MISSING))
|
||||||
@ -41,7 +78,7 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
if (data.loginMethods.contains(LOGIN_METHOD_LIBRUS_SYNERGIA)) {
|
if (data.loginMethods.contains(LOGIN_METHOD_LIBRUS_SYNERGIA)) {
|
||||||
loginWithSynergia()
|
loginWithSynergia()
|
||||||
}
|
}
|
||||||
else if (data.apiLogin != null && data.apiPassword != null && false) {
|
else if (data.apiLogin != null && data.apiPassword != null) {
|
||||||
loginWithCredentials()
|
loginWithCredentials()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -54,7 +91,44 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
* XML (Flash messages website) login method. Uses a Synergia login and password.
|
* XML (Flash messages website) login method. Uses a Synergia login and password.
|
||||||
*/
|
*/
|
||||||
private fun loginWithCredentials() {
|
private fun loginWithCredentials() {
|
||||||
|
d(TAG, "Request: Librus/Login/Messages - $LIBRUS_MESSAGES_URL/Login")
|
||||||
|
|
||||||
|
val docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||||
|
val doc = docBuilder.newDocument()
|
||||||
|
val serviceElement = doc.createElement("service")
|
||||||
|
val headerElement = doc.createElement("header")
|
||||||
|
val dataElement = doc.createElement("data")
|
||||||
|
val loginElement = doc.createElement("login")
|
||||||
|
loginElement.appendChild(doc.createTextNode(data.apiLogin))
|
||||||
|
dataElement.appendChild(loginElement)
|
||||||
|
val passwordElement = doc.createElement("password")
|
||||||
|
passwordElement.appendChild(doc.createTextNode(data.apiPassword))
|
||||||
|
dataElement.appendChild(passwordElement)
|
||||||
|
val keyStrokeElement = doc.createElement("KeyStroke")
|
||||||
|
val keysElement = doc.createElement("Keys")
|
||||||
|
val upElement = doc.createElement("Up")
|
||||||
|
keysElement.appendChild(upElement)
|
||||||
|
val downElement = doc.createElement("Down")
|
||||||
|
keysElement.appendChild(downElement)
|
||||||
|
keyStrokeElement.appendChild(keysElement)
|
||||||
|
dataElement.appendChild(keyStrokeElement)
|
||||||
|
serviceElement.appendChild(headerElement)
|
||||||
|
serviceElement.appendChild(dataElement)
|
||||||
|
doc.appendChild(serviceElement)
|
||||||
|
val transformer = TransformerFactory.newInstance().newTransformer()
|
||||||
|
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes")
|
||||||
|
val stringWriter = StringWriter()
|
||||||
|
transformer.transform(DOMSource(doc), StreamResult(stringWriter))
|
||||||
|
val requestXml = stringWriter.toString()
|
||||||
|
|
||||||
|
Request.builder()
|
||||||
|
.url("$LIBRUS_MESSAGES_URL/Login")
|
||||||
|
.userAgent(SYNERGIA_USER_AGENT)
|
||||||
|
.setTextBody(requestXml, MediaTypeUtils.APPLICATION_XML)
|
||||||
|
.post()
|
||||||
|
.callback(callback)
|
||||||
|
.build()
|
||||||
|
.enqueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,37 +137,6 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
private fun loginWithSynergia(url: String = "https://synergia.librus.pl/wiadomosci2") {
|
private fun loginWithSynergia(url: String = "https://synergia.librus.pl/wiadomosci2") {
|
||||||
d(TAG, "Request: Librus/Login/Messages - $url")
|
d(TAG, "Request: Librus/Login/Messages - $url")
|
||||||
|
|
||||||
val callback = object : TextCallbackHandler() {
|
|
||||||
override fun onSuccess(text: String?, response: Response?) {
|
|
||||||
val location = response?.headers()?.get("Location")
|
|
||||||
when {
|
|
||||||
location?.contains("MultiDomainLogon") == true -> loginWithSynergia(location)
|
|
||||||
location?.contains("AutoLogon") == true -> {
|
|
||||||
var sessionId = data.app.cookieJar.getCookie("wiadomosci.librus.pl", "DZIENNIKSID")
|
|
||||||
sessionId = sessionId?.replace("-MAINT", "")
|
|
||||||
if (sessionId == null) {
|
|
||||||
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_NO_SESSION_ID)
|
|
||||||
.withResponse(response)
|
|
||||||
.withApiResponse(text))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data.messagesSessionId = sessionId
|
|
||||||
data.messagesSessionIdExpiryTime = response.getUnixDate() + 45 * 60 /* 45min */
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
text?.contains("eAccessDeny") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
|
||||||
text?.contains("stop.png") == true -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
|
||||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
|
||||||
.withResponse(response)
|
|
||||||
.withThrowable(throwable))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Request.builder()
|
Request.builder()
|
||||||
.url(url)
|
.url(url)
|
||||||
.userAgent(SYNERGIA_USER_AGENT)
|
.userAgent(SYNERGIA_USER_AGENT)
|
||||||
@ -103,4 +146,18 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
.build()
|
.build()
|
||||||
.enqueue()
|
.enqueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun saveSessionId(response: Response?, text: String?) {
|
||||||
|
var sessionId = data.app.cookieJar.getCookie("wiadomosci.librus.pl", "DZIENNIKSID")
|
||||||
|
sessionId = sessionId?.replace("-MAINT", "") // dunno what's this
|
||||||
|
sessionId = sessionId?.replace("MAINT", "") // dunno what's this
|
||||||
|
if (sessionId == null) {
|
||||||
|
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_NO_SESSION_ID)
|
||||||
|
.withResponse(response)
|
||||||
|
.withApiResponse(text))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data.messagesSessionId = sessionId
|
||||||
|
data.messagesSessionIdExpiryTime = response.getUnixDate() + 45 * 60 /* 45min */
|
||||||
|
}
|
||||||
}
|
}
|
@ -7,14 +7,15 @@ import im.wangchao.mhttp.Response
|
|||||||
import im.wangchao.mhttp.body.MediaTypeUtils
|
import im.wangchao.mhttp.body.MediaTypeUtils
|
||||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||||
import pl.szczodrzynski.edziennik.*
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.*
|
import pl.szczodrzynski.edziennik.api.v2.*
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
import pl.szczodrzynski.edziennik.getInt
|
||||||
|
import pl.szczodrzynski.edziennik.getString
|
||||||
|
import pl.szczodrzynski.edziennik.getUnixDate
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import java.net.HttpURLConnection.HTTP_UNAUTHORIZED
|
import java.net.HttpURLConnection.HTTP_UNAUTHORIZED
|
||||||
import java.util.ArrayList
|
import java.util.*
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||||
@ -42,7 +43,7 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
data.app.cookieJar.clearForDomain("portal.librus.pl")
|
data.app.cookieJar.clearForDomain("portal.librus.pl")
|
||||||
authorize(LIBRUS_AUTHORIZE_URL)
|
authorize(if (data.fakeLogin) FAKE_LIBRUS_AUTHORIZE else LIBRUS_AUTHORIZE_URL)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@ -86,10 +87,10 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun login(csrfToken: String) {
|
private fun login(csrfToken: String) {
|
||||||
d(TAG, "Request: Librus/Login/Portal - $LIBRUS_LOGIN_URL")
|
d(TAG, "Request: Librus/Login/Portal - ${if (data.fakeLogin) FAKE_LIBRUS_LOGIN else LIBRUS_LOGIN_URL}")
|
||||||
|
|
||||||
Request.builder()
|
Request.builder()
|
||||||
.url(LIBRUS_LOGIN_URL)
|
.url(if (data.fakeLogin) FAKE_LIBRUS_LOGIN else LIBRUS_LOGIN_URL)
|
||||||
.userAgent(LIBRUS_USER_AGENT)
|
.userAgent(LIBRUS_USER_AGENT)
|
||||||
.addParameter("email", data.portalEmail)
|
.addParameter("email", data.portalEmail)
|
||||||
.addParameter("password", data.portalPassword)
|
.addParameter("password", data.portalPassword)
|
||||||
@ -98,6 +99,14 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
.post()
|
.post()
|
||||||
.callback(object : JsonCallbackHandler() {
|
.callback(object : JsonCallbackHandler() {
|
||||||
override fun onSuccess(json: JsonObject?, response: Response) {
|
override fun onSuccess(json: JsonObject?, response: Response) {
|
||||||
|
val location = response.headers()?.get("Location")
|
||||||
|
if (location == "http://localhost/bar?command=close") {
|
||||||
|
data.error(ApiError(TAG, ERROR_LIBRUS_PORTAL_MAINTENANCE)
|
||||||
|
.withApiResponse(json)
|
||||||
|
.withResponse(response))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (json == null) {
|
if (json == null) {
|
||||||
if (response.parserErrorBody?.contains("wciąż nieaktywne") == true) {
|
if (response.parserErrorBody?.contains("wciąż nieaktywne") == true) {
|
||||||
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED)
|
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED)
|
||||||
@ -119,7 +128,7 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
|
|
||||||
override fun onFailure(response: Response, throwable: Throwable) {
|
override fun onFailure(response: Response, throwable: Throwable) {
|
||||||
if (response.code() == 403 || response.code() == 401) {
|
if (response.code() == 403 || response.code() == 401) {
|
||||||
data.error(ApiError(TAG, ERROR_LOGIN_DATA_INVALID)
|
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN)
|
||||||
.withResponse(response)
|
.withResponse(response)
|
||||||
.withThrowable(throwable))
|
.withThrowable(throwable))
|
||||||
return
|
return
|
||||||
@ -135,7 +144,7 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
|
|
||||||
private var refreshTokenFailed = false
|
private var refreshTokenFailed = false
|
||||||
private fun accessToken(code: String?, refreshToken: String?) {
|
private fun accessToken(code: String?, refreshToken: String?) {
|
||||||
d(TAG, "Request: Librus/Login/Portal - $LIBRUS_TOKEN_URL")
|
d(TAG, "Request: Librus/Login/Portal - ${if (data.fakeLogin) FAKE_LIBRUS_TOKEN else LIBRUS_TOKEN_URL}")
|
||||||
|
|
||||||
val onSuccess = { json: JsonObject, response: Response? ->
|
val onSuccess = { json: JsonObject, response: Response? ->
|
||||||
data.portalAccessToken = json.getString("access_token")
|
data.portalAccessToken = json.getString("access_token")
|
||||||
@ -204,7 +213,7 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Request.builder()
|
Request.builder()
|
||||||
.url(LIBRUS_TOKEN_URL)
|
.url(if (data.fakeLogin) FAKE_LIBRUS_TOKEN else LIBRUS_TOKEN_URL)
|
||||||
.userAgent(LIBRUS_USER_AGENT)
|
.userAgent(LIBRUS_USER_AGENT)
|
||||||
.addParams(params)
|
.addParams(params)
|
||||||
.post()
|
.post()
|
||||||
|
@ -7,7 +7,6 @@ package pl.szczodrzynski.edziennik.api.v2.librus.login
|
|||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import im.wangchao.mhttp.Request
|
import im.wangchao.mhttp.Request
|
||||||
import im.wangchao.mhttp.Response
|
import im.wangchao.mhttp.Response
|
||||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
|
||||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||||
import okhttp3.Cookie
|
import okhttp3.Cookie
|
||||||
import pl.szczodrzynski.edziennik.api.v2.*
|
import pl.szczodrzynski.edziennik.api.v2.*
|
||||||
@ -16,7 +15,6 @@ import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
import pl.szczodrzynski.edziennik.getString
|
import pl.szczodrzynski.edziennik.getString
|
||||||
import pl.szczodrzynski.edziennik.getUnixDate
|
import pl.szczodrzynski.edziennik.getUnixDate
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
|
|
||||||
@ -86,6 +84,13 @@ class LibrusLoginSynergia(override val data: DataLibrus, val onSuccess: () -> Un
|
|||||||
val callback = object : TextCallbackHandler() {
|
val callback = object : TextCallbackHandler() {
|
||||||
override fun onSuccess(json: String?, response: Response?) {
|
override fun onSuccess(json: String?, response: Response?) {
|
||||||
val location = response?.headers()?.get("Location")
|
val location = response?.headers()?.get("Location")
|
||||||
|
if (location?.endsWith("przerwa_techniczna") == true) {
|
||||||
|
data.error(ApiError(TAG, ERROR_LIBRUS_SYNERGIA_MAINTENANCE)
|
||||||
|
.withApiResponse(json)
|
||||||
|
.withResponse(response))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (location?.endsWith("centrum_powiadomien") == true) {
|
if (location?.endsWith("centrum_powiadomien") == true) {
|
||||||
val sessionId = data.app.cookieJar.getCookie("synergia.librus.pl", "DZIENNIKSID")
|
val sessionId = data.app.cookieJar.getCookie("synergia.librus.pl", "DZIENNIKSID")
|
||||||
if (sessionId == null) {
|
if (sessionId == null) {
|
||||||
|
@ -43,7 +43,7 @@ class SynergiaTokenExtractor(override val data: DataLibrus, val onSuccess: () ->
|
|||||||
val accountLogin = data.apiLogin ?: return false
|
val accountLogin = data.apiLogin ?: return false
|
||||||
data.portalAccessToken ?: return false
|
data.portalAccessToken ?: return false
|
||||||
|
|
||||||
d(TAG, "Request: Librus/SynergiaTokenExtractor - $LIBRUS_ACCOUNT_URL$accountLogin")
|
d(TAG, "Request: Librus/SynergiaTokenExtractor - ${if (data.fakeLogin) FAKE_LIBRUS_ACCOUNT else LIBRUS_ACCOUNT_URL}$accountLogin")
|
||||||
|
|
||||||
val onSuccess = { json: JsonObject, response: Response? ->
|
val onSuccess = { json: JsonObject, response: Response? ->
|
||||||
// synergiaAccount is executed when a synergia token needs a refresh
|
// synergiaAccount is executed when a synergia token needs a refresh
|
||||||
@ -67,7 +67,7 @@ class SynergiaTokenExtractor(override val data: DataLibrus, val onSuccess: () ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
portalGet(TAG, LIBRUS_ACCOUNT_URL+accountLogin, onSuccess = onSuccess)
|
portalGet(TAG, (if (data.fakeLogin) FAKE_LIBRUS_ACCOUNT else LIBRUS_ACCOUNT_URL)+accountLogin, onSuccess = onSuccess)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,17 +4,21 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.mobidziennik
|
package pl.szczodrzynski.edziennik.api.v2.mobidziennik
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
||||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.MobidziennikData
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.MobidziennikData
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.web.MobidziennikWebGetMessage
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.firstlogin.MobidziennikFirstLogin
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.firstlogin.MobidziennikFirstLogin
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.login.MobidziennikLogin
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.login.MobidziennikLogin
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.login.MobidziennikLoginWeb
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennikLoginMethods
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennikLoginMethods
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
import pl.szczodrzynski.edziennik.api.v2.prepare
|
import pl.szczodrzynski.edziennik.api.v2.prepare
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
|
||||||
@ -48,7 +52,8 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto
|
|||||||
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
||||||
__/ |
|
__/ |
|
||||||
|__*/
|
|__*/
|
||||||
override fun sync(featureIds: List<Int>, viewId: Int?) {
|
override fun sync(featureIds: List<Int>, viewId: Int?, arguments: JsonObject?) {
|
||||||
|
data.arguments = arguments
|
||||||
data.prepare(mobidziennikLoginMethods, MobidziennikFeatures, featureIds, viewId)
|
data.prepare(mobidziennikLoginMethods, MobidziennikFeatures, featureIds, viewId)
|
||||||
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
||||||
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
||||||
@ -59,14 +64,22 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getMessage(messageId: Int) {
|
override fun getMessage(message: MessageFull) {
|
||||||
|
MobidziennikLoginWeb(data) {
|
||||||
|
MobidziennikWebGetMessage(data, message) {
|
||||||
|
completed()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun markAllAnnouncementsAsRead() {
|
override fun markAllAnnouncementsAsRead() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
override fun firstLogin() {
|
override fun firstLogin() {
|
||||||
MobidziennikFirstLogin(data) {
|
MobidziennikFirstLogin(data) {
|
||||||
completed()
|
completed()
|
||||||
|
@ -21,10 +21,10 @@ const val ENDPOINT_MOBIDZIENNIK_API2_MAIN = 3000
|
|||||||
|
|
||||||
val MobidziennikFeatures = listOf(
|
val MobidziennikFeatures = listOf(
|
||||||
// always synced
|
// always synced
|
||||||
/*Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_ALWAYS_NEEDED, listOf(
|
Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_ALWAYS_NEEDED, listOf(
|
||||||
ENDPOINT_MOBIDZIENNIK_API_MAIN to LOGIN_METHOD_MOBIDZIENNIK_WEB,
|
ENDPOINT_MOBIDZIENNIK_API_MAIN to LOGIN_METHOD_MOBIDZIENNIK_WEB,
|
||||||
ENDPOINT_MOBIDZIENNIK_WEB_ACCOUNT_EMAIL to LOGIN_METHOD_MOBIDZIENNIK_WEB
|
ENDPOINT_MOBIDZIENNIK_WEB_ACCOUNT_EMAIL to LOGIN_METHOD_MOBIDZIENNIK_WEB
|
||||||
), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)),*/
|
), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), // TODO divide features into separate view IDs (all with API_MAIN)
|
||||||
|
|
||||||
// push config
|
// push config
|
||||||
/*Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_PUSH_CONFIG, listOf(
|
/*Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_PUSH_CONFIG, listOf(
|
||||||
|
@ -42,7 +42,7 @@ class MobidziennikData(val data: DataMobidziennik, val onSuccess: () -> Unit) {
|
|||||||
when (endpointId) {
|
when (endpointId) {
|
||||||
ENDPOINT_MOBIDZIENNIK_API_MAIN -> {
|
ENDPOINT_MOBIDZIENNIK_API_MAIN -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_data)
|
data.startProgress(R.string.edziennik_progress_endpoint_data)
|
||||||
MobidziennikApi(data) { onSuccess() }
|
MobidziennikApi(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_INBOX -> {
|
ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_INBOX -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
||||||
@ -75,4 +75,4 @@ class MobidziennikData(val data: DataMobidziennik, val onSuccess: () -> Unit) {
|
|||||||
else -> onSuccess()
|
else -> onSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.api
|
|||||||
import androidx.core.util.contains
|
import androidx.core.util.contains
|
||||||
import pl.szczodrzynski.edziennik.api.v2.Regexes
|
import pl.szczodrzynski.edziennik.api.v2.Regexes
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
@ -74,5 +75,7 @@ class MobidziennikApiEvents(val data: DataMobidziennik, rows: List<String>) {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.api
|
|||||||
|
|
||||||
import androidx.core.util.contains
|
import androidx.core.util.contains
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
@ -53,5 +54,7 @@ class MobidziennikApiHomework(val data: DataMobidziennik, rows: List<String>) {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.api
|
package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.api
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.App.profileId
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||||
import pl.szczodrzynski.edziennik.getById
|
import pl.szczodrzynski.edziennik.getById
|
||||||
@ -25,7 +24,7 @@ class MobidziennikApiTeams(val data: DataMobidziennik, tableTeams: List<String>?
|
|||||||
val teacherId = cols[4].toLongOrNull() ?: -1
|
val teacherId = cols[4].toLongOrNull() ?: -1
|
||||||
|
|
||||||
val teamObject = Team(
|
val teamObject = Team(
|
||||||
profileId,
|
data.profileId,
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
|
@ -5,15 +5,103 @@
|
|||||||
package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.api
|
package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.api
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.Lesson
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||||
import pl.szczodrzynski.edziennik.fixName
|
import pl.szczodrzynski.edziennik.fixName
|
||||||
import pl.szczodrzynski.edziennik.singleOrNull
|
import pl.szczodrzynski.edziennik.singleOrNull
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
|
|
||||||
class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
||||||
init {
|
init { data.profile?.also { profile ->
|
||||||
for (lessonStr in rows) {
|
val lessons = rows.filterNot { it.isEmpty() }.map { it.split("|") }
|
||||||
|
|
||||||
|
val dataStart = Date.getToday()
|
||||||
|
val dataEnd = dataStart.clone().stepForward(0, 0, 7 + (6 - dataStart.weekDay))
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Timetable.between(dataStart.clone(), dataEnd))
|
||||||
|
|
||||||
|
val dataDays = mutableListOf<Int>()
|
||||||
|
while (dataStart <= dataEnd) {
|
||||||
|
dataDays += dataStart.value
|
||||||
|
dataStart.stepForward(0, 0, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (lesson in lessons) {
|
||||||
|
val date = Date.fromYmd(lesson[2])
|
||||||
|
val startTime = Time.fromYmdHm(lesson[3])
|
||||||
|
val endTime = Time.fromYmdHm(lesson[4])
|
||||||
|
|
||||||
|
dataDays.remove(date.value)
|
||||||
|
|
||||||
|
val subjectId = data.subjectList.singleOrNull { it.longName == lesson[5] }?.id ?: -1
|
||||||
|
val teacherId = data.teacherList.singleOrNull { it.fullNameLastFirst == (lesson[7]+" "+lesson[6]).fixName() }?.id ?: -1
|
||||||
|
val teamId = data.teamList.singleOrNull { it.name == lesson[8]+lesson[9] }?.id ?: -1
|
||||||
|
val classroom = lesson[11]
|
||||||
|
|
||||||
|
Lesson(data.profileId, -1).also {
|
||||||
|
when (lesson[1]) {
|
||||||
|
"plan_lekcji", "lekcja" -> {
|
||||||
|
it.type = Lesson.TYPE_NORMAL
|
||||||
|
it.date = date
|
||||||
|
it.startTime = startTime
|
||||||
|
it.endTime = endTime
|
||||||
|
it.subjectId = subjectId
|
||||||
|
it.teacherId = teacherId
|
||||||
|
it.teamId = teamId
|
||||||
|
it.classroom = classroom
|
||||||
|
}
|
||||||
|
"lekcja_odwolana" -> {
|
||||||
|
it.type = Lesson.TYPE_CANCELLED
|
||||||
|
it.date = date
|
||||||
|
it.startTime = startTime
|
||||||
|
it.endTime = endTime
|
||||||
|
it.oldSubjectId = subjectId
|
||||||
|
//it.oldTeacherId = teacherId
|
||||||
|
it.oldTeamId = teamId
|
||||||
|
//it.oldClassroom = classroom
|
||||||
|
}
|
||||||
|
"zastepstwo" -> {
|
||||||
|
it.type = Lesson.TYPE_CHANGE
|
||||||
|
it.date = date
|
||||||
|
it.startTime = startTime
|
||||||
|
it.endTime = endTime
|
||||||
|
it.subjectId = subjectId
|
||||||
|
it.teacherId = teacherId
|
||||||
|
it.teamId = teamId
|
||||||
|
it.classroom = classroom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it.id = it.buildId()
|
||||||
|
|
||||||
|
val seen = profile.empty || date < Date.getToday()
|
||||||
|
|
||||||
|
if (it.type != Lesson.TYPE_NORMAL) {
|
||||||
|
data.metadataList.add(
|
||||||
|
Metadata(
|
||||||
|
data.profileId,
|
||||||
|
Metadata.TYPE_LESSON_CHANGE,
|
||||||
|
it.id,
|
||||||
|
seen,
|
||||||
|
seen,
|
||||||
|
System.currentTimeMillis()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
data.lessonNewList += it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (day in dataDays) {
|
||||||
|
val lessonDate = Date.fromValue(day)
|
||||||
|
data.lessonNewList += Lesson(data.profileId, lessonDate.value.toLong()).apply {
|
||||||
|
type = Lesson.TYPE_NO_LESSONS
|
||||||
|
date = lessonDate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*for (lessonStr in rows) {
|
||||||
if (lessonStr.isNotEmpty()) {
|
if (lessonStr.isNotEmpty()) {
|
||||||
val lesson = lessonStr.split("|")
|
val lesson = lessonStr.split("|")
|
||||||
|
|
||||||
@ -76,9 +164,9 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
|||||||
if (originalLesson == null) {
|
if (originalLesson == null) {
|
||||||
// original lesson doesn't exist, save a new addition
|
// original lesson doesn't exist, save a new addition
|
||||||
// TODO
|
// TODO
|
||||||
/*if (!RegisterLessonChange.existsAddition(app.profile, registerLessonChange)) {
|
*//*if (!RegisterLessonChange.existsAddition(app.profile, registerLessonChange)) {
|
||||||
app.profile.timetable.addLessonAddition(registerLessonChange);
|
app.profile.timetable.addLessonAddition(registerLessonChange);
|
||||||
}*/
|
}*//*
|
||||||
} else {
|
} else {
|
||||||
// original lesson exists, so we need to compare them
|
// original lesson exists, so we need to compare them
|
||||||
if (!lessonChange.matches(originalLesson)) {
|
if (!lessonChange.matches(originalLesson)) {
|
||||||
@ -108,6 +196,6 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2019-11-18.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.web
|
||||||
|
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.Regexes
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.events.MessageGetEvent
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.MobidziennikWeb
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipientFull
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.get
|
||||||
|
import pl.szczodrzynski.edziennik.singleOrNull
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.monthFromName
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
|
|
||||||
|
class MobidziennikWebGetMessage(
|
||||||
|
override val data: DataMobidziennik,
|
||||||
|
private val message: MessageFull,
|
||||||
|
val onSuccess: () -> Unit) : MobidziennikWeb(data) {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "MobidziennikWebGetMessage"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val typeUrl = if (message.type == Message.TYPE_SENT)
|
||||||
|
"wiadwyslana"
|
||||||
|
else
|
||||||
|
"wiadodebrana"
|
||||||
|
webGet(TAG, "/dziennik/$typeUrl/?id=${message.id}") { text ->
|
||||||
|
MobidziennikLuckyNumberExtractor(data, text)
|
||||||
|
|
||||||
|
val messageRecipientList = mutableListOf<MessageRecipientFull>()
|
||||||
|
|
||||||
|
val doc = Jsoup.parse(text)
|
||||||
|
|
||||||
|
val content = doc.select("#content").first()
|
||||||
|
|
||||||
|
val body = content.select(".wiadomosc_tresc").first()
|
||||||
|
|
||||||
|
if (message.type == TYPE_RECEIVED) {
|
||||||
|
var readDate = System.currentTimeMillis()
|
||||||
|
Regexes.MOBIDZIENNIK_MESSAGE_READ_DATE.find(body.html())?.let {
|
||||||
|
val date = Date(
|
||||||
|
it[3].toIntOrNull() ?: 2019,
|
||||||
|
monthFromName(it[2]),
|
||||||
|
it[1].toIntOrNull() ?: 1
|
||||||
|
)
|
||||||
|
val time = Time.fromH_m_s(
|
||||||
|
it[4] // TODO blank string safety
|
||||||
|
)
|
||||||
|
readDate = date.combineWith(time)
|
||||||
|
}
|
||||||
|
|
||||||
|
val recipient = MessageRecipientFull(
|
||||||
|
profileId,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
readDate,
|
||||||
|
message.id
|
||||||
|
)
|
||||||
|
|
||||||
|
recipient.fullName = profile?.accountNameLong ?: profile?.studentNameLong
|
||||||
|
|
||||||
|
messageRecipientList.add(recipient)
|
||||||
|
} else {
|
||||||
|
message.senderId = -1
|
||||||
|
message.senderReplyId = -1
|
||||||
|
|
||||||
|
content.select("table.spis tr:has(td)")?.forEach { recipientEl ->
|
||||||
|
val senderEl = recipientEl.select("td:eq(0)").first()
|
||||||
|
val senderName = senderEl.text()
|
||||||
|
|
||||||
|
val teacher = data.teacherList.singleOrNull { it.fullNameLastFirst == senderName }
|
||||||
|
val receiverId = teacher?.id ?: -1
|
||||||
|
|
||||||
|
var readDate = 0L
|
||||||
|
val isReadEl = recipientEl.select("td:eq(2)").first()
|
||||||
|
if (isReadEl.ownText() != "NIE") {
|
||||||
|
val readDateEl = recipientEl.select("td:eq(3) small").first()
|
||||||
|
Regexes.MOBIDZIENNIK_MESSAGE_SENT_READ_DATE.find(readDateEl.ownText())?.let {
|
||||||
|
val date = Date(
|
||||||
|
it[3].toIntOrNull() ?: 2019,
|
||||||
|
monthFromName(it[2]),
|
||||||
|
it[1].toIntOrNull() ?: 1
|
||||||
|
)
|
||||||
|
val time = Time.fromH_m_s(
|
||||||
|
it[4] // TODO blank string safety
|
||||||
|
)
|
||||||
|
readDate = date.combineWith(time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val recipient = MessageRecipientFull(
|
||||||
|
profileId,
|
||||||
|
receiverId,
|
||||||
|
-1,
|
||||||
|
readDate,
|
||||||
|
message.id
|
||||||
|
)
|
||||||
|
|
||||||
|
recipient.fullName = teacher?.fullName ?: "?"
|
||||||
|
|
||||||
|
messageRecipientList.add(recipient)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this line removes the sender and read date details
|
||||||
|
body.select("div").remove()
|
||||||
|
|
||||||
|
// this needs to be at the end
|
||||||
|
message.apply {
|
||||||
|
this.body = body.html()
|
||||||
|
|
||||||
|
clearAttachments()
|
||||||
|
content.select("ul li").map { it.select("a").first() }.forEach {
|
||||||
|
val attachmentName = it.ownText()
|
||||||
|
Regexes.MOBIDZIENNIK_MESSAGE_ATTACHMENT.find(it.outerHtml())?.let { match ->
|
||||||
|
val attachmentId = match[1].toLong()
|
||||||
|
var size = match[2].toFloatOrNull() ?: 0f
|
||||||
|
when (match[3]) {
|
||||||
|
"K" -> size *= 1024f
|
||||||
|
"M" -> size *= 1024f * 1024f
|
||||||
|
"G" -> size *= 1024f * 1024f * 1024f
|
||||||
|
}
|
||||||
|
message.addAttachment(attachmentId, attachmentName, size.toLong())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!message.seen) { // TODO discover why this monstrosity instead of MetadataDao.setSeen
|
||||||
|
data.messageMetadataList.add(Metadata(
|
||||||
|
message.profileId,
|
||||||
|
Metadata.TYPE_MESSAGE,
|
||||||
|
message.id,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
message.addedDate
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
message.recipients = messageRecipientList
|
||||||
|
data.messageRecipientList.addAll(messageRecipientList)
|
||||||
|
data.messageList.add(message)
|
||||||
|
|
||||||
|
EventBus.getDefault().postSticky(MessageGetEvent(message))
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,9 +8,7 @@ import org.jsoup.Jsoup
|
|||||||
import pl.szczodrzynski.edziennik.DAY
|
import pl.szczodrzynski.edziennik.DAY
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_ALL
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_ALL
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_INBOX
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.MobidziennikWeb
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.MobidziennikWeb
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
||||||
@ -79,7 +77,7 @@ class MobidziennikWebMessagesAll(override val data: DataMobidziennik,
|
|||||||
-1
|
-1
|
||||||
)
|
)
|
||||||
|
|
||||||
data.messageList.add(message)
|
data.messageIgnoreList.add(message)
|
||||||
data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true, addedDate))
|
data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true, addedDate))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ class MobidziennikWebMessagesInbox(override val data: DataMobidziennik,
|
|||||||
if (hasAttachments)
|
if (hasAttachments)
|
||||||
message.setHasAttachments()
|
message.setHasAttachments()
|
||||||
|
|
||||||
data.messageList.add(message)
|
data.messageIgnoreList.add(message)
|
||||||
data.messageMetadataList.add(
|
data.messageMetadataList.add(
|
||||||
Metadata(
|
Metadata(
|
||||||
profileId,
|
profileId,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.models
|
package pl.szczodrzynski.edziennik.api.v2.models
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import im.wangchao.mhttp.Request
|
import im.wangchao.mhttp.Request
|
||||||
import im.wangchao.mhttp.Response
|
import im.wangchao.mhttp.Response
|
||||||
@ -52,6 +53,15 @@ class ApiError(val tag: String, val errorCode: Int) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getStringReason(context: Context): String {
|
||||||
|
return context.resources.getIdentifier("error_${errorCode}_reason", "string", context.packageName).let {
|
||||||
|
if (it != 0)
|
||||||
|
context.getString(it)
|
||||||
|
else
|
||||||
|
"?"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "ApiError(tag='$tag', errorCode=$errorCode, profileId=$profileId, throwable=$throwable, apiResponse=$apiResponse, request=$request, response=$response, isCritical=$isCritical)"
|
return "ApiError(tag='$tag', errorCode=$errorCode, profileId=$profileId, throwable=$throwable, apiResponse=$apiResponse, request=$request, response=$response, isCritical=$isCritical)"
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,8 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
|||||||
val profileId
|
val profileId
|
||||||
get() = profile?.id ?: -1
|
get() = profile?.id ?: -1
|
||||||
|
|
||||||
|
var arguments: JsonObject? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A callback passed to all [Feature]s and [LoginMethod]s
|
* A callback passed to all [Feature]s and [LoginMethod]s
|
||||||
*/
|
*/
|
||||||
@ -133,23 +135,20 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
|||||||
mTeamClass = value
|
mTeamClass = value
|
||||||
}
|
}
|
||||||
|
|
||||||
var lessonsToRemove: DataRemoveModel? = null
|
var toRemove = mutableListOf<DataRemoveModel>()
|
||||||
|
|
||||||
val lessonList = mutableListOf<Lesson>()
|
val lessonList = mutableListOf<Lesson>()
|
||||||
val lessonChangeList = mutableListOf<LessonChange>()
|
val lessonChangeList = mutableListOf<LessonChange>()
|
||||||
|
val lessonNewList = mutableListOf<pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson>()
|
||||||
|
|
||||||
var gradesToRemove: DataRemoveModel? = null
|
|
||||||
val gradeList = mutableListOf<Grade>()
|
val gradeList = mutableListOf<Grade>()
|
||||||
|
|
||||||
var eventsToRemove: DataRemoveModel? = null
|
|
||||||
val eventList = mutableListOf<Event>()
|
val eventList = mutableListOf<Event>()
|
||||||
|
|
||||||
var noticesToRemove: DataRemoveModel? = null
|
|
||||||
val noticeList = mutableListOf<Notice>()
|
val noticeList = mutableListOf<Notice>()
|
||||||
|
|
||||||
var attendancesToRemove: DataRemoveModel? = null
|
|
||||||
val attendanceList = mutableListOf<Attendance>()
|
val attendanceList = mutableListOf<Attendance>()
|
||||||
|
|
||||||
var announcementsToRemove: DataRemoveModel? = null
|
|
||||||
val announcementList = mutableListOf<Announcement>()
|
val announcementList = mutableListOf<Announcement>()
|
||||||
|
|
||||||
val luckyNumberList = mutableListOf<LuckyNumber>()
|
val luckyNumberList = mutableListOf<LuckyNumber>()
|
||||||
@ -157,6 +156,7 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
|||||||
val teacherAbsenceList = mutableListOf<TeacherAbsence>()
|
val teacherAbsenceList = mutableListOf<TeacherAbsence>()
|
||||||
|
|
||||||
val messageList = mutableListOf<Message>()
|
val messageList = mutableListOf<Message>()
|
||||||
|
val messageIgnoreList = mutableListOf<Message>()
|
||||||
val messageRecipientList = mutableListOf<MessageRecipient>()
|
val messageRecipientList = mutableListOf<MessageRecipient>()
|
||||||
val messageRecipientIgnoreList = mutableListOf<MessageRecipient>()
|
val messageRecipientIgnoreList = mutableListOf<MessageRecipient>()
|
||||||
|
|
||||||
@ -166,6 +166,9 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
|||||||
val db: AppDb by lazy { app.db }
|
val db: AppDb by lazy { app.db }
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
if (App.devMode) {
|
||||||
|
fakeLogin = loginStore.hasLoginData("fakeLogin")
|
||||||
|
}
|
||||||
clear()
|
clear()
|
||||||
if (profile != null) {
|
if (profile != null) {
|
||||||
endpointTimers = db.endpointTimerDao().getAllNow(profile.id).toMutableList()
|
endpointTimers = db.endpointTimerDao().getAllNow(profile.id).toMutableList()
|
||||||
@ -180,6 +183,7 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
|||||||
fun clear() {
|
fun clear() {
|
||||||
loginMethods.clear()
|
loginMethods.clear()
|
||||||
|
|
||||||
|
toRemove.clear()
|
||||||
endpointTimers.clear()
|
endpointTimers.clear()
|
||||||
teacherList.clear()
|
teacherList.clear()
|
||||||
subjectList.clear()
|
subjectList.clear()
|
||||||
@ -195,13 +199,14 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
|||||||
|
|
||||||
lessonList.clear()
|
lessonList.clear()
|
||||||
lessonChangeList.clear()
|
lessonChangeList.clear()
|
||||||
|
lessonNewList.clear()
|
||||||
gradeList.clear()
|
gradeList.clear()
|
||||||
noticeList.clear()
|
noticeList.clear()
|
||||||
attendanceList.clear()
|
attendanceList.clear()
|
||||||
announcementList.clear()
|
announcementList.clear()
|
||||||
luckyNumberList.clear()
|
luckyNumberList.clear()
|
||||||
teacherAbsenceList.clear()
|
teacherAbsenceList.clear()
|
||||||
messageList.clear()
|
messageIgnoreList.clear()
|
||||||
messageRecipientList.clear()
|
messageRecipientList.clear()
|
||||||
messageRecipientIgnoreList.clear()
|
messageRecipientIgnoreList.clear()
|
||||||
metadataList.clear()
|
metadataList.clear()
|
||||||
@ -248,6 +253,7 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
|||||||
app.profile.loginStoreData = loginStore.data
|
app.profile.loginStoreData = loginStore.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// always present and not empty, during every sync
|
||||||
db.endpointTimerDao().addAll(endpointTimers)
|
db.endpointTimerDao().addAll(endpointTimers)
|
||||||
db.teacherDao().clear(profileId)
|
db.teacherDao().clear(profileId)
|
||||||
db.teacherDao().addAll(teacherList.values())
|
db.teacherDao().addAll(teacherList.values())
|
||||||
@ -260,6 +266,7 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
|||||||
db.gradeCategoryDao().clear(profileId)
|
db.gradeCategoryDao().clear(profileId)
|
||||||
db.gradeCategoryDao().addAll(gradeCategories.values())
|
db.gradeCategoryDao().addAll(gradeCategories.values())
|
||||||
|
|
||||||
|
// may be empty - extracted from DB on demand, by an endpoint
|
||||||
if (classrooms.size > 0)
|
if (classrooms.size > 0)
|
||||||
db.classroomDao().addAll(classrooms.values())
|
db.classroomDao().addAll(classrooms.values())
|
||||||
if (attendanceTypes.size > 0)
|
if (attendanceTypes.size > 0)
|
||||||
@ -271,22 +278,34 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
|||||||
if (teacherAbsenceTypes.size > 0)
|
if (teacherAbsenceTypes.size > 0)
|
||||||
db.teacherAbsenceTypeDao().addAll(teacherAbsenceTypes.values())
|
db.teacherAbsenceTypeDao().addAll(teacherAbsenceTypes.values())
|
||||||
|
|
||||||
gradesToRemove?.let { it ->
|
// clear DB with DataRemoveModels added by endpoints
|
||||||
it.removeAll?.let { _ -> db.gradeDao().clear(profileId) }
|
for (model in toRemove) {
|
||||||
it.removeSemester?.let { semester -> db.gradeDao().clearForSemester(profileId, semester) }
|
when (model) {
|
||||||
|
is DataRemoveModel.Timetable -> model.commit(profileId, db.timetableDao())
|
||||||
|
is DataRemoveModel.Grades -> model.commit(profileId, db.gradeDao())
|
||||||
|
is DataRemoveModel.Events -> model.commit(profileId, db.eventDao())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (metadataList.isNotEmpty())
|
||||||
|
db.metadataDao().addAllIgnore(metadataList)
|
||||||
|
if (messageMetadataList.isNotEmpty())
|
||||||
|
db.metadataDao().setSeen(messageMetadataList)
|
||||||
|
|
||||||
|
// not extracted from DB - always new data
|
||||||
if (lessonList.isNotEmpty()) {
|
if (lessonList.isNotEmpty()) {
|
||||||
db.lessonDao().clear(profile.id)
|
db.lessonDao().clear(profile.id)
|
||||||
db.lessonDao().addAll(lessonList)
|
db.lessonDao().addAll(lessonList)
|
||||||
}
|
}
|
||||||
if (lessonChangeList.isNotEmpty())
|
if (lessonChangeList.isNotEmpty())
|
||||||
db.lessonChangeDao().addAll(lessonChangeList)
|
db.lessonChangeDao().addAll(lessonChangeList)
|
||||||
|
if (lessonNewList.isNotEmpty()) {
|
||||||
|
db.timetableDao() += lessonNewList
|
||||||
|
}
|
||||||
if (gradeList.isNotEmpty()) {
|
if (gradeList.isNotEmpty()) {
|
||||||
db.gradeDao().addAll(gradeList)
|
db.gradeDao().addAll(gradeList)
|
||||||
}
|
}
|
||||||
if (eventList.isNotEmpty()) {
|
if (eventList.isNotEmpty()) {
|
||||||
db.eventDao().removeFuture(profile.id, Date.getToday())
|
|
||||||
db.eventDao().addAll(eventList)
|
db.eventDao().addAll(eventList)
|
||||||
}
|
}
|
||||||
if (noticeList.isNotEmpty()) {
|
if (noticeList.isNotEmpty()) {
|
||||||
@ -303,15 +322,13 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
|||||||
db.teacherAbsenceDao().addAll(teacherAbsenceList)
|
db.teacherAbsenceDao().addAll(teacherAbsenceList)
|
||||||
|
|
||||||
if (messageList.isNotEmpty())
|
if (messageList.isNotEmpty())
|
||||||
db.messageDao().addAllIgnore(messageList)
|
db.messageDao().addAll(messageList)
|
||||||
|
if (messageIgnoreList.isNotEmpty())
|
||||||
|
db.messageDao().addAllIgnore(messageIgnoreList)
|
||||||
if (messageRecipientList.isNotEmpty())
|
if (messageRecipientList.isNotEmpty())
|
||||||
db.messageRecipientDao().addAll(messageRecipientList)
|
db.messageRecipientDao().addAll(messageRecipientList)
|
||||||
if (messageRecipientIgnoreList.isNotEmpty())
|
if (messageRecipientIgnoreList.isNotEmpty())
|
||||||
db.messageRecipientDao().addAllIgnore(messageRecipientIgnoreList)
|
db.messageRecipientDao().addAllIgnore(messageRecipientIgnoreList)
|
||||||
if (metadataList.isNotEmpty())
|
|
||||||
db.metadataDao().addAllIgnore(metadataList)
|
|
||||||
if (messageMetadataList.isNotEmpty())
|
|
||||||
db.metadataDao().setSeen(messageMetadataList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun notifyAndSyncEvents(onSuccess: () -> Unit) {
|
fun notifyAndSyncEvents(onSuccess: () -> Unit) {
|
||||||
@ -358,7 +375,7 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun shouldSyncLuckyNumber(): Boolean {
|
fun shouldSyncLuckyNumber(): Boolean {
|
||||||
return (db.luckyNumberDao().getNearestFutureNow(profileId, Date.getToday()) ?: -1) == -1
|
return (db.luckyNumberDao().getNearestFutureNow(profileId, Date.getToday().value) ?: -1) == -1
|
||||||
}
|
}
|
||||||
|
|
||||||
fun error(tag: String, errorCode: Int, response: Response? = null, throwable: Throwable? = null, apiResponse: JsonObject? = null) {
|
fun error(tag: String, errorCode: Int, response: Response? = null, throwable: Throwable? = null, apiResponse: JsonObject? = null) {
|
||||||
@ -390,8 +407,6 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun error(apiError: ApiError) {
|
fun error(apiError: ApiError) {
|
||||||
if (apiError.isCritical)
|
|
||||||
cancel()
|
|
||||||
callback.onError(apiError)
|
callback.onError(apiError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,28 +4,52 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.models
|
package pl.szczodrzynski.edziennik.api.v2.models
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.events.EventDao
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeDao
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.timetable.TimetableDao
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
class DataRemoveModel {
|
open class DataRemoveModel {
|
||||||
var removeAll: Boolean? = null
|
class Timetable(private val dateFrom: Date?, private val dateTo: Date?) : DataRemoveModel() {
|
||||||
var removeSemester: Int? = null
|
companion object {
|
||||||
var removeDateFrom: Date? = null
|
fun from(dateFrom: Date) = Timetable(dateFrom, null)
|
||||||
var removeDateTo: Date? = null
|
fun to(dateTo: Date) = Timetable(null, dateTo)
|
||||||
|
fun between(dateFrom: Date, dateTo: Date) = Timetable(dateFrom, dateTo)
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
fun commit(profileId: Int, dao: TimetableDao) {
|
||||||
this.removeAll = true
|
if (dateFrom != null && dateTo != null) {
|
||||||
|
dao.clearBetweenDates(profileId, dateFrom, dateTo)
|
||||||
|
} else {
|
||||||
|
dateFrom?.let { dateFrom -> dao.clearFromDate(profileId, dateFrom) }
|
||||||
|
dateTo?.let { dateTo -> dao.clearToDate(profileId, dateTo) }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(semester: Int) {
|
class Grades(private val all: Boolean, private val semester: Int?) : DataRemoveModel() {
|
||||||
this.removeSemester = semester
|
companion object {
|
||||||
|
fun all() = Grades(true, null)
|
||||||
|
fun semester(semester: Int) = Grades(false, semester)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun commit(profileId: Int, dao: GradeDao) {
|
||||||
|
if (all) {
|
||||||
|
dao.clear(profileId)
|
||||||
|
}
|
||||||
|
semester?.let { dao.clearForSemester(profileId, it) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(dateFrom: Date?, dateTo: Date) {
|
class Events(private val type: Int?, private val exceptType: Int?) : DataRemoveModel() {
|
||||||
this.removeDateFrom = dateFrom
|
companion object {
|
||||||
this.removeDateTo = dateTo
|
fun futureExceptType(exceptType: Int) = Events(null, exceptType)
|
||||||
}
|
fun futureWithType(type: Int) = Events(type, null)
|
||||||
|
}
|
||||||
|
|
||||||
constructor(dateFrom: Date) {
|
fun commit(profileId: Int, dao: EventDao) {
|
||||||
this.removeDateFrom = dateFrom
|
type?.let { dao.removeFutureWithType(profileId, Date.getToday(), it) }
|
||||||
|
exceptType?.let { dao.removeFutureExceptType(profileId, Date.getToday(), it) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.template
|
package pl.szczodrzynski.edziennik.api.v2.template
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
||||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||||
@ -15,6 +16,7 @@ import pl.szczodrzynski.edziennik.api.v2.template.firstlogin.TemplateFirstLogin
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.template.login.TemplateLogin
|
import pl.szczodrzynski.edziennik.api.v2.template.login.TemplateLogin
|
||||||
import pl.szczodrzynski.edziennik.api.v2.templateLoginMethods
|
import pl.szczodrzynski.edziennik.api.v2.templateLoginMethods
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
|
||||||
@ -48,7 +50,8 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
|||||||
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
||||||
__/ |
|
__/ |
|
||||||
|__*/
|
|__*/
|
||||||
override fun sync(featureIds: List<Int>, viewId: Int?) {
|
override fun sync(featureIds: List<Int>, viewId: Int?, arguments: JsonObject?) {
|
||||||
|
data.arguments = arguments
|
||||||
data.prepare(templateLoginMethods, TemplateFeatures, featureIds, viewId)
|
data.prepare(templateLoginMethods, TemplateFeatures, featureIds, viewId)
|
||||||
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
||||||
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
||||||
@ -59,7 +62,7 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getMessage(messageId: Int) {
|
override fun getMessage(message: MessageFull) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,6 +70,10 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
override fun firstLogin() {
|
override fun firstLogin() {
|
||||||
TemplateFirstLogin(data) {
|
TemplateFirstLogin(data) {
|
||||||
completed()
|
completed()
|
||||||
|
@ -7,15 +7,14 @@ package pl.szczodrzynski.edziennik.api.v2.vulcan
|
|||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_VULCAN_API
|
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_VULCAN_API
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||||
import pl.szczodrzynski.edziennik.currentTimeUnix
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||||
|
|
||||||
class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
||||||
|
|
||||||
fun isApiLoginValid() = apiCertificateExpiryTime-30 > currentTimeUnix()
|
fun isApiLoginValid() = /*apiCertificateExpiryTime-30 > currentTimeUnix()
|
||||||
&& apiCertificateKey.isNotNullNorEmpty()
|
&&*/ apiCertificateKey.isNotNullNorEmpty()
|
||||||
&& apiCertificatePrivate.isNotNullNorEmpty()
|
&& apiCertificatePrivate.isNotNullNorEmpty()
|
||||||
&& symbol.isNotNullNorEmpty()
|
&& symbol.isNotNullNorEmpty()
|
||||||
|
|
||||||
@ -165,6 +164,8 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
|||||||
"GD1" -> "https://uonetplus-komunikacja.edu.gdansk.pl"
|
"GD1" -> "https://uonetplus-komunikacja.edu.gdansk.pl"
|
||||||
"KA1" -> "https://uonetplus-komunikacja.mcuw.katowice.eu"
|
"KA1" -> "https://uonetplus-komunikacja.mcuw.katowice.eu"
|
||||||
"KA2" -> "https://uonetplus-komunikacja-test.mcuw.katowice.eu"
|
"KA2" -> "https://uonetplus-komunikacja-test.mcuw.katowice.eu"
|
||||||
|
"LU1" -> "https://uonetplus-komunikacja.edu.lublin.eu"
|
||||||
|
"LU2" -> "https://test-uonetplus-komunikacja.edu.lublin.eu"
|
||||||
"P03" -> "https://efeb-komunikacja-pro-efebmobile.pro.vulcan.pl"
|
"P03" -> "https://efeb-komunikacja-pro-efebmobile.pro.vulcan.pl"
|
||||||
"P01" -> "http://efeb-komunikacja.pro-hudson.win.vulcan.pl"
|
"P01" -> "http://efeb-komunikacja.pro-hudson.win.vulcan.pl"
|
||||||
"P02" -> "http://efeb-komunikacja.pro-hudsonrc.win.vulcan.pl"
|
"P02" -> "http://efeb-komunikacja.pro-hudsonrc.win.vulcan.pl"
|
||||||
@ -173,7 +174,7 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
|||||||
"SZ9" -> "http://vulcan.szkolny.eu"
|
"SZ9" -> "http://vulcan.szkolny.eu"
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
return if (url != null) "$url/$symbol" else null
|
return if (url != null) "$url/$symbol" else loginStore.getLoginData("apiUrl", null)
|
||||||
}
|
}
|
||||||
|
|
||||||
val fullApiUrl: String?
|
val fullApiUrl: String?
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.vulcan
|
package pl.szczodrzynski.edziennik.api.v2.vulcan
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
||||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||||
@ -11,10 +12,13 @@ import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
import pl.szczodrzynski.edziennik.api.v2.prepare
|
import pl.szczodrzynski.edziennik.api.v2.prepare
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanData
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanData
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.api.VulcanApiMessagesChangeStatus
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.firstlogin.VulcanFirstLogin
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.firstlogin.VulcanFirstLogin
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.login.VulcanLogin
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.login.VulcanLogin
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.login.VulcanLoginApi
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcanLoginMethods
|
import pl.szczodrzynski.edziennik.api.v2.vulcanLoginMethods
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
|
||||||
@ -48,7 +52,8 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
|||||||
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
||||||
__/ |
|
__/ |
|
||||||
|__*/
|
|__*/
|
||||||
override fun sync(featureIds: List<Int>, viewId: Int?) {
|
override fun sync(featureIds: List<Int>, viewId: Int?, arguments: JsonObject?) {
|
||||||
|
data.arguments = arguments
|
||||||
data.prepare(vulcanLoginMethods, VulcanFeatures, featureIds, viewId)
|
data.prepare(vulcanLoginMethods, VulcanFeatures, featureIds, viewId)
|
||||||
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
||||||
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
||||||
@ -59,14 +64,22 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getMessage(messageId: Int) {
|
override fun getMessage(message: MessageFull) {
|
||||||
|
VulcanLoginApi(data) {
|
||||||
|
VulcanApiMessagesChangeStatus(data, message) {
|
||||||
|
completed()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun markAllAnnouncementsAsRead() {
|
override fun markAllAnnouncementsAsRead() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
override fun firstLogin() {
|
override fun firstLogin() {
|
||||||
VulcanFirstLogin(data) {
|
VulcanFirstLogin(data) {
|
||||||
completed()
|
completed()
|
||||||
|
@ -38,35 +38,43 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
|
|||||||
when (endpointId) {
|
when (endpointId) {
|
||||||
ENDPOINT_VULCAN_API_DICTIONARIES -> {
|
ENDPOINT_VULCAN_API_DICTIONARIES -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_dictionaries)
|
data.startProgress(R.string.edziennik_progress_endpoint_dictionaries)
|
||||||
VulcanApiDictionaries(data) { onSuccess() }
|
VulcanApiDictionaries(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_VULCAN_API_GRADES -> {
|
ENDPOINT_VULCAN_API_GRADES -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
||||||
VulcanApiGrades(data) { onSuccess() }
|
VulcanApiGrades(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_VULCAN_API_GRADES_SUMMARY -> {
|
ENDPOINT_VULCAN_API_GRADES_SUMMARY -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_proposed_grades)
|
data.startProgress(R.string.edziennik_progress_endpoint_proposed_grades)
|
||||||
VulcanApiProposedGrades(data) { onSuccess() }
|
VulcanApiProposedGrades(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_VULCAN_API_EVENTS -> {
|
ENDPOINT_VULCAN_API_EVENTS -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_events)
|
data.startProgress(R.string.edziennik_progress_endpoint_events)
|
||||||
VulcanApiEvents(data, isHomework = false) { onSuccess() }
|
VulcanApiEvents(data, isHomework = false, onSuccess = onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_VULCAN_API_HOMEWORK -> {
|
ENDPOINT_VULCAN_API_HOMEWORK -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
||||||
VulcanApiEvents(data, isHomework = true) { onSuccess() }
|
VulcanApiEvents(data, isHomework = true, onSuccess = onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_VULCAN_API_NOTICES -> {
|
ENDPOINT_VULCAN_API_NOTICES -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
||||||
VulcanApiNotices(data) { onSuccess() }
|
VulcanApiNotices(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_VULCAN_API_ATTENDANCE -> {
|
ENDPOINT_VULCAN_API_ATTENDANCE -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
||||||
VulcanApiAttendance(data) { onSuccess() }
|
VulcanApiAttendance(data, onSuccess)
|
||||||
|
}
|
||||||
|
ENDPOINT_VULCAN_API_TIMETABLE -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
||||||
|
VulcanApiTimetable(data, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_VULCAN_API_MESSAGES_INBOX -> {
|
ENDPOINT_VULCAN_API_MESSAGES_INBOX -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
||||||
VulcanApiMessagesInbox(data) { onSuccess() }
|
VulcanApiMessagesInbox(data, onSuccess)
|
||||||
|
}
|
||||||
|
ENDPOINT_VULCAN_API_MESSAGES_SENT -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
|
||||||
|
VulcanApiMessagesSent(data, onSuccess)
|
||||||
}
|
}
|
||||||
else -> onSuccess()
|
else -> onSuccess()
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ class VulcanApiAttendance(override val data: DataVulcan, val onSuccess: () -> Un
|
|||||||
lessonSemester,
|
lessonSemester,
|
||||||
attendance.getString("PrzedmiotNazwa") + attendanceCategory.name.let { " - $it" },
|
attendance.getString("PrzedmiotNazwa") + attendanceCategory.name.let { " - $it" },
|
||||||
lessonDate,
|
lessonDate,
|
||||||
data.lessonRanges.get(attendance.getInt("IdPoraLekcji") ?: 0)?.startTime,
|
data.lessonRanges.get(attendance.getInt("Numer") ?: 0)?.startTime,
|
||||||
type)
|
type)
|
||||||
|
|
||||||
data.attendanceList.add(attendanceObject)
|
data.attendanceList.add(attendanceObject)
|
||||||
|
@ -35,7 +35,7 @@ class VulcanApiDictionaries(override val data: DataVulcan, val onSuccess: () ->
|
|||||||
elements?.getJsonArray("KategorieUwag")?.forEach { saveNoticeType(it.asJsonObject) }
|
elements?.getJsonArray("KategorieUwag")?.forEach { saveNoticeType(it.asJsonObject) }
|
||||||
elements?.getJsonArray("KategorieFrekwencji")?.forEach { saveAttendanceType(it.asJsonObject) }
|
elements?.getJsonArray("KategorieFrekwencji")?.forEach { saveAttendanceType(it.asJsonObject) }
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_VULCAN_API_DICTIONARIES, 4*DAY)
|
data.setSyncNext(ENDPOINT_VULCAN_API_DICTIONARIES, 4 * DAY)
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ class VulcanApiDictionaries(override val data: DataVulcan, val onSuccess: () ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun saveLessonRange(lessonRange: JsonObject) {
|
private fun saveLessonRange(lessonRange: JsonObject) {
|
||||||
val lessonNumber = lessonRange.getInt("Id") ?: return
|
val lessonNumber = lessonRange.getInt("Numer") ?: return
|
||||||
val startTime = lessonRange.getString("PoczatekTekst")?.let { Time.fromH_m(it) } ?: return
|
val startTime = lessonRange.getString("PoczatekTekst")?.let { Time.fromH_m(it) } ?: return
|
||||||
val endTime = lessonRange.getString("KoniecTekst")?.let { Time.fromH_m(it) } ?: return
|
val endTime = lessonRange.getString("KoniecTekst")?.let { Time.fromH_m(it) } ?: return
|
||||||
|
|
||||||
@ -126,8 +126,7 @@ class VulcanApiDictionaries(override val data: DataVulcan, val onSuccess: () ->
|
|||||||
Attendance.TYPE_ABSENT_EXCUSED
|
Attendance.TYPE_ABSENT_EXCUSED
|
||||||
else
|
else
|
||||||
Attendance.TYPE_ABSENT
|
Attendance.TYPE_ABSENT
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val belated = attendanceType.getBoolean("Spoznienie") ?: false
|
val belated = attendanceType.getBoolean("Spoznienie") ?: false
|
||||||
val released = attendanceType.getBoolean("Zwolnienie") ?: false
|
val released = attendanceType.getBoolean("Zwolnienie") ?: false
|
||||||
val present = attendanceType.getBoolean("Obecnosc") ?: true
|
val present = attendanceType.getBoolean("Obecnosc") ?: true
|
||||||
|
@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api
|
|||||||
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_EVENTS
|
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_EVENTS
|
||||||
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_HOMEWORK
|
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_HOMEWORK
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_EVENTS
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_EVENTS
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_HOMEWORK
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_HOMEWORK
|
||||||
@ -91,8 +92,14 @@ class VulcanApiEvents(override val data: DataVulcan, private val isHomework: Boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
when (isHomework) {
|
when (isHomework) {
|
||||||
true -> data.setSyncNext(ENDPOINT_VULCAN_API_HOMEWORK, SYNC_ALWAYS)
|
true -> {
|
||||||
false -> data.setSyncNext(ENDPOINT_VULCAN_API_EVENTS, SYNC_ALWAYS)
|
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||||
|
data.setSyncNext(ENDPOINT_VULCAN_API_HOMEWORK, SYNC_ALWAYS)
|
||||||
|
}
|
||||||
|
false -> {
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
|
||||||
|
data.setSyncNext(ENDPOINT_VULCAN_API_EVENTS, SYNC_ALWAYS)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-12
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_MESSAGES_CHANGE_STATUS
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
|
||||||
|
class VulcanApiMessagesChangeStatus(
|
||||||
|
override val data: DataVulcan,
|
||||||
|
private val messageObject: MessageFull,
|
||||||
|
val onSuccess: () -> Unit
|
||||||
|
) : VulcanApi(data) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "VulcanApiMessagesChangeStatus"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
data.profile?.also { profile ->
|
||||||
|
apiGet(TAG, VULCAN_API_ENDPOINT_MESSAGES_CHANGE_STATUS, parameters = mapOf(
|
||||||
|
"WiadomoscId" to messageObject.id,
|
||||||
|
"FolderWiadomosci" to "Odebrane",
|
||||||
|
"Status" to "Widoczna",
|
||||||
|
"LoginId" to data.studentLoginId,
|
||||||
|
"IdUczen" to data.studentId
|
||||||
|
)) { _, _ ->
|
||||||
|
|
||||||
|
if (!messageObject.seen) {
|
||||||
|
data.messageMetadataList.add(Metadata(
|
||||||
|
profileId,
|
||||||
|
Metadata.TYPE_MESSAGE,
|
||||||
|
messageObject.id,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
messageObject.addedDate
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageObject.type != TYPE_SENT) {
|
||||||
|
val messageRecipientObject = MessageRecipient(
|
||||||
|
profileId,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
messageObject.id
|
||||||
|
)
|
||||||
|
|
||||||
|
data.messageRecipientList.add(messageRecipientObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,8 +11,11 @@ import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_MESSAGES_INB
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
class VulcanApiMessagesInbox(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
class VulcanApiMessagesInbox(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
||||||
@ -20,64 +23,83 @@ class VulcanApiMessagesInbox(override val data: DataVulcan, val onSuccess: () ->
|
|||||||
const val TAG = "VulcanApiMessagesInbox"
|
const val TAG = "VulcanApiMessagesInbox"
|
||||||
}
|
}
|
||||||
|
|
||||||
init { data.profile?.also { profile ->
|
init {
|
||||||
|
data.profile?.also { profile ->
|
||||||
|
|
||||||
val startDate: String = when (profile.empty) {
|
val startDate: String = when (profile.empty) {
|
||||||
true -> profile.getSemesterStart(profile.currentSemester).stringY_m_d
|
true -> profile.getSemesterStart(profile.currentSemester).stringY_m_d
|
||||||
else -> Date.getToday().stepForward(0, -1, 0).stringY_m_d
|
else -> Date.getToday().stepForward(0, -1, 0).stringY_m_d
|
||||||
}
|
|
||||||
val endDate: String = profile.getSemesterEnd(profile.currentSemester).stringY_m_d
|
|
||||||
|
|
||||||
apiGet(TAG, VULCAN_API_ENDPOINT_MESSAGES_RECEIVED, parameters = mapOf(
|
|
||||||
"DataPoczatkowa" to startDate,
|
|
||||||
"DataKoncowa" to endDate,
|
|
||||||
"LoginId" to data.studentLoginId,
|
|
||||||
"IdUczen" to data.studentId
|
|
||||||
)) { json, _ ->
|
|
||||||
json.getJsonArray("Data").asJsonObjectList()?.forEach { message ->
|
|
||||||
val id = message.getLong("WiadomoscId") ?: return@forEach
|
|
||||||
val subject = message.getString("Tytul") ?: ""
|
|
||||||
val body = message.getString("Tresc") ?: ""
|
|
||||||
|
|
||||||
val senderLoginId = message.getString("NadawcaId") ?: return@forEach
|
|
||||||
val senderId = data.teacherList
|
|
||||||
.singleOrNull { it.loginId == senderLoginId }?.id ?: return@forEach
|
|
||||||
|
|
||||||
val addedDate = message.getLong("DataWyslaniaUnixEpoch")?.let { it * 1000 } ?: -1
|
|
||||||
val readDate = message.getLong("DataPrzeczytaniaUnixEpoch")?.let { it * 1000 } ?: -1
|
|
||||||
|
|
||||||
val messageObject = Message(
|
|
||||||
profileId,
|
|
||||||
id,
|
|
||||||
subject,
|
|
||||||
body,
|
|
||||||
Message.TYPE_RECEIVED,
|
|
||||||
senderId,
|
|
||||||
-1
|
|
||||||
)
|
|
||||||
|
|
||||||
val messageRecipientObject = MessageRecipient(
|
|
||||||
profileId,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
readDate,
|
|
||||||
id
|
|
||||||
)
|
|
||||||
|
|
||||||
data.messageList.add(messageObject)
|
|
||||||
data.messageRecipientList.add(messageRecipientObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_MESSAGE,
|
|
||||||
id,
|
|
||||||
readDate > 0,
|
|
||||||
readDate > 0,
|
|
||||||
addedDate
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
val endDate: String = profile.getSemesterEnd(profile.currentSemester).stringY_m_d
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_VULCAN_API_MESSAGES_INBOX, SYNC_ALWAYS)
|
apiGet(TAG, VULCAN_API_ENDPOINT_MESSAGES_RECEIVED, parameters = mapOf(
|
||||||
onSuccess()
|
"DataPoczatkowa" to startDate,
|
||||||
}
|
"DataKoncowa" to endDate,
|
||||||
} ?: onSuccess()}
|
"LoginId" to data.studentLoginId,
|
||||||
|
"IdUczen" to data.studentId
|
||||||
|
)) { json, _ ->
|
||||||
|
json.getJsonArray("Data").asJsonObjectList()?.forEach { message ->
|
||||||
|
val id = message.getLong("WiadomoscId") ?: return@forEach
|
||||||
|
val subject = message.getString("Tytul") ?: ""
|
||||||
|
val body = message.getString("Tresc") ?: ""
|
||||||
|
|
||||||
|
val senderLoginId = message.getString("NadawcaId") ?: return@forEach
|
||||||
|
val senderId = data.teacherList
|
||||||
|
.singleOrNull { it.loginId == senderLoginId }?.id ?: {
|
||||||
|
|
||||||
|
val senderName = message.getString("Nadawca") ?: ""
|
||||||
|
|
||||||
|
senderName.getLastFirstName()?.let { (senderLastName, senderFirstName) ->
|
||||||
|
val teacherObject = Teacher(
|
||||||
|
profileId,
|
||||||
|
-1 * Utils.crc16(senderName.toByteArray()).toLong(),
|
||||||
|
senderFirstName,
|
||||||
|
senderLastName,
|
||||||
|
senderLoginId
|
||||||
|
)
|
||||||
|
data.teacherList.put(teacherObject.id, teacherObject)
|
||||||
|
teacherObject.id
|
||||||
|
}
|
||||||
|
}.invoke() ?: -1
|
||||||
|
|
||||||
|
val sentDate = message.getLong("DataWyslaniaUnixEpoch")?.let { it * 1000 }
|
||||||
|
?: -1
|
||||||
|
val readDate = message.getLong("DataPrzeczytaniaUnixEpoch")?.let { it * 1000 }
|
||||||
|
?: -1
|
||||||
|
|
||||||
|
val messageObject = Message(
|
||||||
|
profileId,
|
||||||
|
id,
|
||||||
|
subject,
|
||||||
|
body,
|
||||||
|
TYPE_RECEIVED,
|
||||||
|
senderId,
|
||||||
|
-1
|
||||||
|
)
|
||||||
|
|
||||||
|
val messageRecipientObject = MessageRecipient(
|
||||||
|
profileId,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
readDate,
|
||||||
|
id
|
||||||
|
)
|
||||||
|
|
||||||
|
data.messageIgnoreList.add(messageObject)
|
||||||
|
data.messageRecipientList.add(messageRecipientObject)
|
||||||
|
data.metadataList.add(Metadata(
|
||||||
|
profileId,
|
||||||
|
Metadata.TYPE_MESSAGE,
|
||||||
|
id,
|
||||||
|
readDate > 0,
|
||||||
|
readDate > 0,
|
||||||
|
sentDate
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
data.setSyncNext(ENDPOINT_VULCAN_API_MESSAGES_INBOX, SYNC_ALWAYS)
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
} ?: onSuccess()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-5
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.*
|
||||||
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_MESSAGES_SENT
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_MESSAGES_SENT
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
|
class VulcanApiMessagesSent(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "VulcanApiMessagesSent"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
data.profile?.also { profile ->
|
||||||
|
val startDate: Long = when (profile.empty) {
|
||||||
|
true -> profile.getSemesterStart(profile.currentSemester).inUnix
|
||||||
|
else -> Date.getToday().stepForward(0, -1, 0).inUnix
|
||||||
|
}
|
||||||
|
val endDate: Long = profile.getSemesterEnd(profile.currentSemester).inUnix
|
||||||
|
|
||||||
|
apiGet(TAG, VULCAN_API_ENDPOINT_MESSAGES_SENT, parameters = mapOf(
|
||||||
|
"DataPoczatkowa" to startDate,
|
||||||
|
"DataKoncowa" to endDate,
|
||||||
|
"LoginId" to data.studentLoginId,
|
||||||
|
"IdUczen" to data.studentId
|
||||||
|
)) { json, _ ->
|
||||||
|
json.getJsonArray("Data")?.asJsonObjectList()?.forEach { message ->
|
||||||
|
val id = message.getLong("WiadomoscId") ?: return@forEach
|
||||||
|
val subject = message.getString("Tytul") ?: ""
|
||||||
|
val body = message.getString("Tresc") ?: ""
|
||||||
|
val readBy = message.getInt("Przeczytane") ?: 0
|
||||||
|
val unreadBy = message.getInt("Nieprzeczytane") ?: 0
|
||||||
|
val sentDate = message.getLong("DataWyslaniaUnixEpoch")?.let { it * 1000 } ?: -1
|
||||||
|
|
||||||
|
message.getJsonArray("Adresaci")?.asJsonObjectList()
|
||||||
|
?.onEach { receiver ->
|
||||||
|
|
||||||
|
val receiverLoginId = receiver.getString("LoginId")
|
||||||
|
?: return@onEach
|
||||||
|
val receiverId = data.teacherList.singleOrNull { it.loginId == receiverLoginId }?.id
|
||||||
|
?: {
|
||||||
|
val receiverName = receiver.getString("Nazwa") ?: ""
|
||||||
|
|
||||||
|
receiverName.getLastFirstName()?.let { (receiverLastName, receiverFirstName) ->
|
||||||
|
val teacherObject = Teacher(
|
||||||
|
profileId,
|
||||||
|
-1 * Utils.crc16(receiverName.toByteArray()).toLong(),
|
||||||
|
receiverFirstName,
|
||||||
|
receiverLastName,
|
||||||
|
receiverLoginId
|
||||||
|
)
|
||||||
|
data.teacherList.put(teacherObject.id, teacherObject)
|
||||||
|
teacherObject.id
|
||||||
|
}
|
||||||
|
}.invoke() ?: -1
|
||||||
|
|
||||||
|
val readDate: Long = when (readBy) {
|
||||||
|
0 -> 0
|
||||||
|
else -> when (unreadBy) {
|
||||||
|
0 -> 1
|
||||||
|
else -> -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val messageRecipientObject = MessageRecipient(
|
||||||
|
profileId,
|
||||||
|
receiverId,
|
||||||
|
-1,
|
||||||
|
readDate,
|
||||||
|
id
|
||||||
|
)
|
||||||
|
|
||||||
|
data.messageRecipientList.add(messageRecipientObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
val messageObject = Message(
|
||||||
|
profileId,
|
||||||
|
id,
|
||||||
|
subject,
|
||||||
|
body,
|
||||||
|
TYPE_SENT,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
)
|
||||||
|
|
||||||
|
data.messageIgnoreList.add(messageObject)
|
||||||
|
data.metadataList.add(Metadata(
|
||||||
|
profileId,
|
||||||
|
Metadata.TYPE_MESSAGE,
|
||||||
|
id,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
sentDate
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
data.setSyncNext(ENDPOINT_VULCAN_API_MESSAGES_SENT, 1 * DAY, DRAWER_ITEM_MESSAGES)
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,8 +6,6 @@ package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api
|
|||||||
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
|
||||||
import pl.szczodrzynski.edziennik.getJsonArray
|
|
||||||
|
|
||||||
class VulcanApiTemplate(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
class VulcanApiTemplate(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
||||||
companion object {
|
companion object {
|
||||||
@ -15,10 +13,12 @@ class VulcanApiTemplate(override val data: DataVulcan, val onSuccess: () -> Unit
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
/* apiGet(TAG, VULCAN_API_ENDPOINT_) { json, _ ->
|
/* data.profile?.also { profile ->
|
||||||
|
apiGet(TAG, VULCAN_API_ENDPOINT_) { json, _ ->
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_VULCAN_API_, SYNC_ALWAYS)
|
data.setSyncNext(ENDPOINT_VULCAN_API_, SYNC_ALWAYS)
|
||||||
onSuccess()
|
onSuccess()
|
||||||
|
}
|
||||||
} */
|
} */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-13
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api
|
||||||
|
|
||||||
|
import androidx.core.util.set
|
||||||
|
import pl.szczodrzynski.edziennik.*
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.Regexes
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_TIMETABLE
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_TIMETABLE
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.crc16
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||||
|
|
||||||
|
class VulcanApiTimetable(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "VulcanApiTimetable"
|
||||||
|
}
|
||||||
|
|
||||||
|
init { data.profile?.also { profile ->
|
||||||
|
val currentWeekStart = Week.getWeekStart()
|
||||||
|
|
||||||
|
if (Date.getToday().weekDay > 4) {
|
||||||
|
currentWeekStart.stepForward(0, 0, 7)
|
||||||
|
}
|
||||||
|
|
||||||
|
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
||||||
|
|
||||||
|
val weekStart = Date.fromY_m_d(getDate)
|
||||||
|
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||||
|
|
||||||
|
apiGet(TAG, VULCAN_API_ENDPOINT_TIMETABLE, parameters = mapOf(
|
||||||
|
"DataPoczatkowa" to weekStart.stringY_m_d,
|
||||||
|
"DataKoncowa" to weekEnd.stringY_m_d,
|
||||||
|
"IdUczen" to data.studentId,
|
||||||
|
"IdOddzial" to data.studentClassId,
|
||||||
|
"IdOkresKlasyfikacyjny" to data.studentSemesterId
|
||||||
|
)) { json, _ ->
|
||||||
|
val dates = mutableSetOf<Int>()
|
||||||
|
val lessons = mutableListOf<Lesson>()
|
||||||
|
|
||||||
|
json.getJsonArray("Data")?.asJsonObjectList()?.forEach { lesson ->
|
||||||
|
if (lesson.getBoolean("PlanUcznia") != true)
|
||||||
|
return@forEach
|
||||||
|
val lessonDate = Date.fromY_m_d(lesson.getString("DzienTekst"))
|
||||||
|
val lessonNumber = lesson.getInt("NumerLekcji")
|
||||||
|
val lessonRange = data.lessonRanges.singleOrNull { it.lessonNumber == lessonNumber }
|
||||||
|
val startTime = lessonRange?.startTime
|
||||||
|
val endTime = lessonRange?.endTime
|
||||||
|
val teacherId = lesson.getLong("IdPracownik")
|
||||||
|
val classroom = lesson.getString("Sala")
|
||||||
|
|
||||||
|
val oldTeacherId = lesson.getLong("IdPracownikOld")
|
||||||
|
|
||||||
|
val changeAnnotation = lesson.getString("AdnotacjaOZmianie") ?: ""
|
||||||
|
val type = when {
|
||||||
|
changeAnnotation.startsWith("(przeniesiona z") -> Lesson.TYPE_SHIFTED_TARGET
|
||||||
|
changeAnnotation.startsWith("(przeniesiona na") -> Lesson.TYPE_SHIFTED_SOURCE
|
||||||
|
changeAnnotation.startsWith("(zastępstwo") -> Lesson.TYPE_CHANGE
|
||||||
|
lesson.getBoolean("PrzekreslonaNazwa") == true -> Lesson.TYPE_CANCELLED
|
||||||
|
else -> Lesson.TYPE_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
val teamId = lesson.getString("PodzialSkrot")?.let { teamName ->
|
||||||
|
val name = "${data.teamClass?.name} $teamName"
|
||||||
|
val id = name.crc16().toLong()
|
||||||
|
var team = data.teamList.singleOrNull { it.name == name }
|
||||||
|
if (team == null) {
|
||||||
|
team = Team(
|
||||||
|
profileId,
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
Team.TYPE_VIRTUAL,
|
||||||
|
"${data.schoolName}:$name",
|
||||||
|
teacherId ?: oldTeacherId ?: -1
|
||||||
|
)
|
||||||
|
data.teamList[id] = team
|
||||||
|
}
|
||||||
|
team.id
|
||||||
|
} ?: data.studentClassId.toLong()
|
||||||
|
|
||||||
|
val subjectId = lesson.getLong("IdPrzedmiot")?.let {
|
||||||
|
when (it) {
|
||||||
|
0L -> {
|
||||||
|
val subjectName = lesson.getString("PrzedmiotNazwa") ?: ""
|
||||||
|
|
||||||
|
data.subjectList.singleOrNull { subject -> subject.longName == subjectName }?.id
|
||||||
|
?: {
|
||||||
|
/**
|
||||||
|
* CREATE A NEW SUBJECT IF IT DOESN'T EXIST
|
||||||
|
*/
|
||||||
|
|
||||||
|
val subjectObject = Subject(
|
||||||
|
profileId,
|
||||||
|
-1 * crc16(subjectName.toByteArray()).toLong(),
|
||||||
|
subjectName,
|
||||||
|
subjectName
|
||||||
|
)
|
||||||
|
data.subjectList.put(subjectObject.id, subjectObject)
|
||||||
|
subjectObject.id
|
||||||
|
}.invoke()
|
||||||
|
}
|
||||||
|
else -> it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val lessonObject = Lesson(profileId, -1).apply {
|
||||||
|
this.type = type
|
||||||
|
|
||||||
|
when (type) {
|
||||||
|
Lesson.TYPE_NORMAL, Lesson.TYPE_CHANGE, Lesson.TYPE_SHIFTED_TARGET -> {
|
||||||
|
this.date = lessonDate
|
||||||
|
this.lessonNumber = lessonNumber
|
||||||
|
this.startTime = startTime
|
||||||
|
this.endTime = endTime
|
||||||
|
this.subjectId = subjectId
|
||||||
|
this.teacherId = teacherId
|
||||||
|
this.teamId = teamId
|
||||||
|
this.classroom = classroom
|
||||||
|
|
||||||
|
this.oldTeacherId = oldTeacherId
|
||||||
|
}
|
||||||
|
|
||||||
|
Lesson.TYPE_CANCELLED, Lesson.TYPE_SHIFTED_SOURCE -> {
|
||||||
|
this.oldDate = lessonDate
|
||||||
|
this.oldLessonNumber = lessonNumber
|
||||||
|
this.oldStartTime = startTime
|
||||||
|
this.oldEndTime = endTime
|
||||||
|
this.oldSubjectId = subjectId
|
||||||
|
this.oldTeacherId = teacherId
|
||||||
|
this.oldTeamId = teamId
|
||||||
|
this.oldClassroom = classroom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == Lesson.TYPE_SHIFTED_SOURCE || type == Lesson.TYPE_SHIFTED_TARGET) {
|
||||||
|
val shift = Regexes.VULCAN_SHITFT_ANNOTATION.find(changeAnnotation)
|
||||||
|
val oldLessonNumber = shift?.get(2)?.toInt()
|
||||||
|
val oldLessonDate = shift?.get(3)?.let { Date.fromd_m_Y(it) }
|
||||||
|
|
||||||
|
val oldLessonRange = data.lessonRanges.singleOrNull { it.lessonNumber == oldLessonNumber }
|
||||||
|
val oldStartTime = oldLessonRange?.startTime
|
||||||
|
val oldEndTime = oldLessonRange?.endTime
|
||||||
|
|
||||||
|
when (type) {
|
||||||
|
Lesson.TYPE_SHIFTED_SOURCE -> {
|
||||||
|
this.lessonNumber = oldLessonNumber
|
||||||
|
this.date = oldLessonDate
|
||||||
|
this.startTime = oldStartTime
|
||||||
|
this.endTime = oldEndTime
|
||||||
|
}
|
||||||
|
|
||||||
|
Lesson.TYPE_SHIFTED_TARGET -> {
|
||||||
|
this.oldLessonNumber = oldLessonNumber
|
||||||
|
this.oldDate = oldLessonDate
|
||||||
|
this.oldStartTime = oldStartTime
|
||||||
|
this.oldEndTime = oldEndTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.id = buildId()
|
||||||
|
}
|
||||||
|
|
||||||
|
val seen = profile.empty || lessonDate < Date.getToday()
|
||||||
|
|
||||||
|
if (type != Lesson.TYPE_NORMAL) {
|
||||||
|
data.metadataList.add(Metadata(
|
||||||
|
profileId,
|
||||||
|
Metadata.TYPE_LESSON_CHANGE,
|
||||||
|
lessonObject.id,
|
||||||
|
seen,
|
||||||
|
seen,
|
||||||
|
System.currentTimeMillis()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
dates.add(lessonDate.value)
|
||||||
|
lessons.add(lessonObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
val date: Date = weekStart.clone()
|
||||||
|
while (date <= weekEnd) {
|
||||||
|
if (!dates.contains(date.value)) {
|
||||||
|
lessons.add(Lesson(profileId, date.value.toLong()).apply {
|
||||||
|
this.type = Lesson.TYPE_NO_LESSONS
|
||||||
|
this.date = date.clone()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
date.stepForward(0, 0, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
||||||
|
|
||||||
|
data.lessonNewList.addAll(lessons)
|
||||||
|
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||||
|
|
||||||
|
data.setSyncNext(ENDPOINT_VULCAN_API_TIMETABLE, SYNC_ALWAYS)
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}
|
@ -38,10 +38,12 @@ class VulcanLoginApi(val data: DataVulcan, val onSuccess: () -> Unit) {
|
|||||||
if (data.apiToken?.get(0) == 'F') VULCAN_API_PASSWORD_FAKELOG else VULCAN_API_PASSWORD,
|
if (data.apiToken?.get(0) == 'F') VULCAN_API_PASSWORD_FAKELOG else VULCAN_API_PASSWORD,
|
||||||
data.apiCertificatePfx ?: ""
|
data.apiCertificatePfx ?: ""
|
||||||
)
|
)
|
||||||
onSuccess()
|
data.loginStore.removeLoginData("certificatePfx")
|
||||||
return@run
|
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
} finally {
|
||||||
|
onSuccess()
|
||||||
|
return@run
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (data.symbol.isNotNullNorEmpty() && data.apiToken.isNotNullNorEmpty() && data.apiPin.isNotNullNorEmpty()) {
|
if (data.symbol.isNotNullNorEmpty() && data.apiToken.isNotNullNorEmpty() && data.apiPin.isNotNullNorEmpty()) {
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
|
||||||
|
|
||||||
import im.wangchao.mhttp.Request;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback containing a {@link Request.Builder} which has correct headers and body to download a corresponding message attachment when ran.
|
|
||||||
* {@code onSuccess} has to be ran on the UI thread.
|
|
||||||
*/
|
|
||||||
public interface AttachmentGetCallback {
|
|
||||||
void onSuccess(Request.Builder builder);
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher;
|
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesComposeInfo;
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Endpoint;
|
|
||||||
|
|
||||||
public interface EdziennikInterface {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sync all Edziennik data.
|
|
||||||
* Ran always on worker thread.
|
|
||||||
*
|
|
||||||
* @param activityContext a {@link Context}, used for resource extractions, passed back to {@link SyncCallback}
|
|
||||||
* @param callback ran on worker thread.
|
|
||||||
* @param profileId
|
|
||||||
* @param profile
|
|
||||||
* @param loginStore
|
|
||||||
*/
|
|
||||||
void sync(@NonNull Context activityContext, @NonNull SyncCallback callback, int profileId, @Nullable Profile profile, @NonNull LoginStore loginStore);
|
|
||||||
void syncMessages(@NonNull Context activityContext, @NonNull SyncCallback errorCallback, @NonNull ProfileFull profile);
|
|
||||||
void syncFeature(@NonNull Context activityContext, @NonNull SyncCallback callback, @NonNull ProfileFull profile, int ... featureList);
|
|
||||||
|
|
||||||
int FEATURE_ALL = 0;
|
|
||||||
int FEATURE_TIMETABLE = 1;
|
|
||||||
int FEATURE_AGENDA = 2;
|
|
||||||
int FEATURE_GRADES = 3;
|
|
||||||
int FEATURE_HOMEWORK = 4;
|
|
||||||
int FEATURE_NOTICES = 5;
|
|
||||||
int FEATURE_ATTENDANCE = 6;
|
|
||||||
int FEATURE_MESSAGES_INBOX = 7;
|
|
||||||
int FEATURE_MESSAGES_OUTBOX = 8;
|
|
||||||
int FEATURE_ANNOUNCEMENTS = 9;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Download a single message or get its recipient list if it's already downloaded.
|
|
||||||
*
|
|
||||||
* May be executed on any thread.
|
|
||||||
*
|
|
||||||
* @param activityContext
|
|
||||||
* @param errorCallback used for error reporting. Ran on a background thread.
|
|
||||||
* @param profile
|
|
||||||
* @param message a message of which body and recipient list should be downloaded.
|
|
||||||
* @param messageCallback always executed on UI thread.
|
|
||||||
*/
|
|
||||||
void getMessage(@NonNull Context activityContext, @NonNull SyncCallback errorCallback, @NonNull ProfileFull profile, @NonNull MessageFull message, @NonNull MessageGetCallback messageCallback);
|
|
||||||
void getAttachment(@NonNull Context activityContext, @NonNull SyncCallback errorCallback, @NonNull ProfileFull profile, @NonNull MessageFull message, long attachmentId, @NonNull AttachmentGetCallback attachmentCallback);
|
|
||||||
//void getMessageList(@NonNull Context activityContext, @NonNull SyncCallback errorCallback, @NonNull ProfileFull profile, int type, @NonNull MessageListCallback messageCallback);
|
|
||||||
/**
|
|
||||||
* Download a list of available message recipients.
|
|
||||||
*
|
|
||||||
* Updates a database-saved {@code teacherList} with {@code loginId}s.
|
|
||||||
*
|
|
||||||
* A {@link Teacher} is considered as a recipient when its {@code loginId} is not null.
|
|
||||||
*
|
|
||||||
* May be executed on any thread.
|
|
||||||
*
|
|
||||||
* @param activityContext
|
|
||||||
* @param errorCallback used for error reporting. Ran on a background thread.
|
|
||||||
* @param profile
|
|
||||||
* @param recipientListGetCallback always executed on UI thread.
|
|
||||||
*/
|
|
||||||
void getRecipientList(@NonNull Context activityContext, @NonNull SyncCallback errorCallback, @NonNull ProfileFull profile, @NonNull RecipientListGetCallback recipientListGetCallback);
|
|
||||||
MessagesComposeInfo getComposeInfo(@NonNull ProfileFull profile);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param profile a {@link Profile} containing already changed endpoints
|
|
||||||
* @return a map of configurable {@link Endpoint}s along with their names, {@code null} when unsupported
|
|
||||||
*/
|
|
||||||
Map<String, Endpoint> getConfigurableEndpoints(Profile profile);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the specified endpoint is enabled for the current profile.
|
|
||||||
*
|
|
||||||
* @param profile a {@link Profile} containing already changed endpoints
|
|
||||||
* @param defaultActive if the endpoint is enabled by default.
|
|
||||||
* @param name the endpoint's name
|
|
||||||
* @return {@code true} if the endpoint is enabled, {@code false} when it's not. Return {@code defaultActive} if unsupported.
|
|
||||||
*/
|
|
||||||
boolean isEndpointEnabled(Profile profile, boolean defaultActive, String name);
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.AppError;
|
|
||||||
|
|
||||||
public interface ErrorCallback {
|
|
||||||
void onError(Context activityContext, @NonNull AppError error);
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
|
||||||
|
|
||||||
public interface LoginCallback {
|
|
||||||
void onSuccess();
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback containing a {@link MessageFull} which already has its {@code body} and {@code recipients}.
|
|
||||||
* {@code onSuccess} is always ran on the UI thread.
|
|
||||||
*/
|
|
||||||
public interface MessageGetCallback {
|
|
||||||
void onSuccess(MessageFull message);
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull;
|
|
||||||
|
|
||||||
public interface MessageListCallback {
|
|
||||||
void onSuccess(List<MessageFull> messageList);
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
|
||||||
|
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
|
|
||||||
public interface ProgressCallback extends ErrorCallback {
|
|
||||||
void onProgress(int progressStep);
|
|
||||||
void onActionStarted(@StringRes int stringResId);
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user