Compare commits

..

3 Commits

410 changed files with 16967 additions and 15439 deletions

2
.gitignore vendored
View File

@ -81,5 +81,3 @@ lint/generated/
lint/outputs/ lint/outputs/
lint/tmp/ lint/tmp/
# lint/reports/ # lint/reports/
app/schemas/

7
.idea/misc.xml generated
View File

@ -6,9 +6,8 @@
</configurations> </configurations>
</component> </component>
<component name="EntryPointsManager"> <component name="EntryPointsManager">
<list size="2"> <list size="1">
<item index="0" class="java.lang.String" itemvalue="androidx.databinding.BindingAdapter" /> <item index="0" class="java.lang.String" itemvalue="org.greenrobot.eventbus.Subscribe" />
<item index="1" class="java.lang.String" itemvalue="org.greenrobot.eventbus.Subscribe" />
</list> </list>
</component> </component>
<component name="NullableNotNullManager"> <component name="NullableNotNullManager">
@ -50,7 +49,7 @@
</value> </value>
</option> </option>
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="JDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

View File

@ -1,6 +1,7 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
apply plugin: 'io.fabric' apply plugin: 'io.fabric'
@ -91,7 +92,7 @@ tasks.whenTaskAdded { task ->
dependencies { dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
annotationProcessor "androidx.room:room-compiler:${versions.room}" kapt "androidx.room:room-compiler:${versions.room}"
debugImplementation "com.amitshekhar.android:debug-db:1.0.5" debugImplementation "com.amitshekhar.android:debug-db:1.0.5"
implementation "android.arch.navigation:navigation-fragment-ktx:${versions.navigationFragment}" implementation "android.arch.navigation:navigation-fragment-ktx:${versions.navigationFragment}"
@ -131,7 +132,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.2" implementation "com.squareup.okhttp3:okhttp:3.12.0"
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,20 +160,16 @@ 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' api "com.google.dagger:dagger:${versions.dagger}"
api "com.google.dagger:dagger-android-support:${versions.dagger}"
implementation 'com.github.kuba2k2:RecyclerTabLayout:700f980584' kapt "com.google.dagger:dagger-compiler:${versions.dagger}"
kapt "com.google.dagger:dagger-android-processor:${versions.dagger}"
implementation 'com.github.kuba2k2:Tachyon:551943a6b5'
implementation "com.squareup.retrofit2:retrofit:${versions.retrofit}"
implementation "com.squareup.retrofit2:converter-gson:${versions.retrofit}"
} }
repositories { repositories {
mavenCentral() mavenCentral()

View File

@ -24,7 +24,6 @@
-keep class pl.szczodrzynski.edziennik.utils.models.** { *; } -keep class pl.szczodrzynski.edziennik.utils.models.** { *; }
-keep class pl.szczodrzynski.edziennik.data.db.modules.events.Event { *; } -keep class pl.szczodrzynski.edziennik.data.db.modules.events.Event { *; }
-keep class pl.szczodrzynski.edziennik.data.db.modules.events.EventFull { *; } -keep class pl.szczodrzynski.edziennik.data.db.modules.events.EventFull { *; }
-keep class pl.szczodrzynski.edziennik.ui.modules.home.HomeCardModel { *; }
-keepclassmembers class pl.szczodrzynski.edziennik.widgets.WidgetConfig { public *; } -keepclassmembers class pl.szczodrzynski.edziennik.widgets.WidgetConfig { public *; }
-keepnames class pl.szczodrzynski.edziennik.WidgetTimetable -keepnames class pl.szczodrzynski.edziennik.WidgetTimetable
-keepnames class pl.szczodrzynski.edziennik.notifications.WidgetNotifications -keepnames class pl.szczodrzynski.edziennik.notifications.WidgetNotifications
@ -40,13 +39,4 @@
-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>;
}

View File

@ -1,9 +0,0 @@
<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>

View File

@ -1,13 +0,0 @@
<!--
~ 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>

View File

@ -15,14 +15,10 @@
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:configChanges="orientation|screenSize"
android:label="@string/app_name" android:label="@string/app_name"
android:configChanges="orientation|screenSize"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@style/SplashTheme"> android:theme="@style/SplashTheme">
<intent-filter> <intent-filter>
@ -33,7 +29,7 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".ui.modules.messages.MessagesComposeActivity" android:name="pl.szczodrzynski.edziennik.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" />
@ -43,7 +39,7 @@
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/AppTheme" /> android:theme="@style/AppTheme" />
<activity <activity
android:name=".ui.modules.login.LoginActivity" android:name="pl.szczodrzynski.edziennik.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" />
@ -105,23 +101,22 @@
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" />
@ -174,6 +169,7 @@
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">
@ -192,6 +188,7 @@
<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" />
@ -199,24 +196,6 @@
<action android:name="android.intent.action.QUICKBOOT_POWERON" /> <action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver
android:name=".sync.FirebaseBroadcastReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</receiver>
<receiver
android:name=".receivers.SzkolnyReceiver"
android:exported="true">
<intent-filter>
<action android:name="pl.szczodrzynski.edziennik.SZKOLNY_MAIN" />
</intent-filter>
</receiver>
<service <service
android:name=".sync.MyFirebaseMessagingService" android:name=".sync.MyFirebaseMessagingService"
android:exported="false"> android:exported="false">
@ -225,6 +204,14 @@
<action android:name="com.google.firebase.MESSAGING_EVENT" /> <action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter> </intent-filter>
</service> </service>
<receiver
android:name=".sync.FirebaseBroadcastReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</receiver>
<service <service
android:name=".widgets.timetable.WidgetTimetableService" android:name=".widgets.timetable.WidgetTimetableService"
android:permission="android.permission.BIND_REMOTEVIEWS" /> android:permission="android.permission.BIND_REMOTEVIEWS" />
@ -235,6 +222,14 @@
<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" />
@ -249,4 +244,4 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
</manifest> </manifest>

View File

@ -31,11 +31,57 @@
</head> </head>
<body> <body>
<h3>Wersja 4.0, 2019-jeszcze-nie-wiem-kiedy</h3> <h3>Wersja 3.1.1, 2019-10-09</h3>
<ul> <ul>
<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>Librus: poprawiona synchronizacja kategorii i kolorów ocen.</li>
z wersji 3.x. Proszę o cierpliwość oraz <b>nie udostępnianie</b> tej wersji <u>nikomu</u>.</li> <li>Zmieniony kolor dolnego paska w ciemnym motywie.</li>
<li>Bardzo dużo zmian</li> <li>Zaktualizowany licznik czasu lekcji.</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>

View File

@ -18,9 +18,11 @@ import android.os.Handler;
import android.provider.Settings; import android.provider.Settings;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
import android.util.Pair;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatDelegate; import androidx.appcompat.app.AppCompatDelegate;
import androidx.multidex.MultiDex;
import androidx.work.Configuration; import androidx.work.Configuration;
import com.chuckerteam.chucker.api.ChuckerCollector; import com.chuckerteam.chucker.api.ChuckerCollector;
@ -35,7 +37,6 @@ 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;
@ -59,6 +60,8 @@ import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager; import javax.net.ssl.X509TrustManager;
import cat.ereza.customactivityoncrash.config.CaocConfig; import cat.ereza.customactivityoncrash.config.CaocConfig;
import dagger.android.AndroidInjector;
import dagger.android.support.DaggerApplication;
import im.wangchao.mhttp.MHttp; import im.wangchao.mhttp.MHttp;
import im.wangchao.mhttp.internal.cookie.PersistentCookieJar; import im.wangchao.mhttp.internal.cookie.PersistentCookieJar;
import im.wangchao.mhttp.internal.cookie.cache.SetCookieCache; import im.wangchao.mhttp.internal.cookie.cache.SetCookieCache;
@ -67,24 +70,31 @@ 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.config.Config; 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.profiles.Profile; 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.profiles.ProfileFull;
import pl.szczodrzynski.edziennik.di.DaggerAppComponent;
import pl.szczodrzynski.edziennik.network.NetworkUtils; 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;
import pl.szczodrzynski.edziennik.utils.models.AppConfig; import pl.szczodrzynski.edziennik.utils.models.AppConfig;
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_LIBRUS;
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_MOBIDZIENNIK; import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_MOBIDZIENNIK;
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_VULCAN;
public class App extends androidx.multidex.MultiDexApplication implements Configuration.Provider { public class App extends DaggerApplication implements Configuration.Provider {
private static final String TAG = "App"; private static final String TAG = "App";
public static int profileId = -1; public static int profileId = -1;
private Context mContext; private Context mContext;
@ -133,6 +143,12 @@ 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
@ -142,11 +158,6 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
//public Register register; // REGISTER for current profile, read from registerStore //public Register register; // REGISTER for current profile, read from registerStore
public ProfileFull profile; public ProfileFull profile;
public Config config;
private static Config mConfig;
public static Config getConfig() {
return mConfig;
}
// other stuff // other stuff
public Gson gson; public Gson gson;
@ -174,6 +185,17 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
return Icon.createWithBitmap(bitmap); return Icon.createWithBitmap(bitmap);
} }
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerAppComponent.factory().create(this);
}
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
@ -195,10 +217,12 @@ 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);
config = new Config(db); //apiJakdojade = new Jakdojade(this);
config.migrate(this); apiMobidziennik = new Mobidziennik(this);
mConfig = config; 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);
@ -214,7 +238,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
loadConfig(); loadConfig();
Themes.INSTANCE.setThemeInt(config.getUi().getTheme()); Themes.INSTANCE.setThemeInt(appConfig.appTheme);
try { try {
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES); PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
@ -222,7 +246,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
byte[] signatureBytes = signature.toByteArray(); byte[] signatureBytes = signature.toByteArray();
MessageDigest md = MessageDigest.getInstance("SHA"); MessageDigest md = MessageDigest.getInstance("SHA");
md.update(signatureBytes); md.update(signatureBytes);
this.signature = Base64.encodeToString(md.digest(), Base64.NO_WRAP); this.signature = Base64.encodeToString(md.digest(), Base64.DEFAULT);
//Log.d(TAG, "Signature is "+this.signature); //Log.d(TAG, "Signature is "+this.signature);
} }
} }
@ -233,7 +257,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
if ("f054761fbdb6a238".equals(deviceId) || BuildConfig.DEBUG) { if ("f054761fbdb6a238".equals(deviceId) || BuildConfig.DEBUG) {
devMode = true; devMode = true;
} }
else if (config.getDevModePassword() != null) { else if (appConfig.devModePassword != null) {
checkDevModePassword(); checkDevModePassword();
} }
@ -285,10 +309,6 @@ 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);
@ -304,7 +324,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
//profileLoadById(appSharedPrefs.getInt("current_profile_id", 1)); //profileLoadById(appSharedPrefs.getInt("current_profile_id", 1));
if (config.getSync().getEnabled()) { if (appConfig.registerSyncEnabled) {
SyncWorker.Companion.scheduleNext(this, false); SyncWorker.Companion.scheduleNext(this, false);
} }
else { else {
@ -368,10 +388,11 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
shortcutManager.setDynamicShortcuts(Arrays.asList(shortcutTimetable, shortcutAgenda, shortcutGrades, shortcutHomework, shortcutMessages)); shortcutManager.setDynamicShortcuts(Arrays.asList(shortcutTimetable, shortcutAgenda, shortcutGrades, shortcutHomework, shortcutMessages));
} }
if (config.getAppInstalledTime() == 0) { if (appConfig.appInstalledTime == 0) {
try { try {
config.setAppInstalledTime(getPackageManager().getPackageInfo(getPackageName(), 0).firstInstallTime); appConfig.appInstalledTime = getPackageManager().getPackageInfo(getPackageName(), 0).firstInstallTime;
config.setAppRateSnackbarTime(config.getAppInstalledTime() + 7 * 24 * 60 * 60 * 1000); appConfig.appRateSnackbarTime = appConfig.appInstalledTime + 7 * 24 * 60 * 60 * 1000;
saveConfig("appInstalledTime", "appRateSnackbarTime");
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -439,9 +460,9 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
final long startTime = System.currentTimeMillis(); final long startTime = System.currentTimeMillis();
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(instanceIdResult -> { FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(instanceIdResult -> {
Log.d(TAG, "Token for App is " + instanceIdResult.getToken() + ", ID is " + instanceIdResult.getId()+". Time is "+(System.currentTimeMillis() - startTime)); Log.d(TAG, "Token for App is " + instanceIdResult.getToken() + ", ID is " + instanceIdResult.getId()+". Time is "+(System.currentTimeMillis() - startTime));
config.getSync().setTokenApp(instanceIdResult.getToken()); appConfig.fcmToken = instanceIdResult.getToken();
}); });
/*FirebaseInstanceId.getInstance(pushMobidziennikApp).getInstanceId().addOnSuccessListener(instanceIdResult -> { FirebaseInstanceId.getInstance(pushMobidziennikApp).getInstanceId().addOnSuccessListener(instanceIdResult -> {
Log.d(TAG, "Token for Mobidziennik is " + instanceIdResult.getToken() + ", ID is " + instanceIdResult.getId()); Log.d(TAG, "Token for Mobidziennik is " + instanceIdResult.getToken() + ", ID is " + instanceIdResult.getId());
appConfig.fcmTokens.put(LOGIN_TYPE_MOBIDZIENNIK, new Pair<>(instanceIdResult.getToken(), new ArrayList<>())); appConfig.fcmTokens.put(LOGIN_TYPE_MOBIDZIENNIK, new Pair<>(instanceIdResult.getToken(), new ArrayList<>()));
}); });
@ -455,7 +476,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
if (pair == null || pair.first == null || !pair.first.equals(instanceIdResult.getToken())) { if (pair == null || pair.first == null || !pair.first.equals(instanceIdResult.getToken())) {
appConfig.fcmTokens.put(LOGIN_TYPE_VULCAN, new Pair<>(instanceIdResult.getToken(), new ArrayList<>())); appConfig.fcmTokens.put(LOGIN_TYPE_VULCAN, new Pair<>(instanceIdResult.getToken(), new ArrayList<>()));
} }
});*/ });
FirebaseMessaging.getInstance().subscribeToTopic(getPackageName()); FirebaseMessaging.getInstance().subscribeToTopic(getPackageName());
@ -518,8 +539,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
e.printStackTrace(); e.printStackTrace();
} catch (NoSuchFieldException e) { } catch (NoSuchFieldException e) {
e.printStackTrace(); e.printStackTrace();
Log.w(TAG, "Should remove app.appConfig."+fieldName); appSharedPrefs.edit().remove("app.appConfig."+fieldName).apply();
//appSharedPrefs.edit().remove("app.appConfig."+fieldName).apply(); TODO migration
} }
} }
} }
@ -538,6 +558,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
appConfig = new AppConfig(this); appConfig = new AppConfig(this);
} }
} }
public void saveConfig() public void saveConfig()
{ {
try { try {
@ -591,11 +612,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
//appSharedPrefs.edit().putString("config", gson.toJson(appConfig)).apply(); //appSharedPrefs.edit().putString("config", gson.toJson(appConfig)).apply();
} }
public void profileSave() {
AsyncTask.execute(() -> {
db.profileDao().add(profile);
});
}
public void profileSaveAsync() { public void profileSaveAsync() {
AsyncTask.execute(() -> { AsyncTask.execute(() -> {
@ -616,6 +633,14 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
db.profileDao().add(profileFull); db.profileDao().add(profileFull);
db.loginStoreDao().add(profileFull); db.loginStoreDao().add(profileFull);
} }
public void profileSaveFull(Profile profile, LoginStore loginStore) {
db.profileDao().add(profile);
db.loginStoreDao().add(loginStore);
}
public ProfileFull profileGetOrNull(int id) {
return db.profileDao().getFullByIdNow(id);
}
public void profileLoadById(int id) { public void profileLoadById(int id) {
profileLoadById(id, false); profileLoadById(id, false);
@ -638,7 +663,6 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
MainActivity.Companion.setUseOldMessages(profile.getLoginStoreType() == LOGIN_TYPE_MOBIDZIENNIK && appConfig.mobidziennikOldMessages == 1); MainActivity.Companion.setUseOldMessages(profile.getLoginStoreType() == LOGIN_TYPE_MOBIDZIENNIK && appConfig.mobidziennikOldMessages == 1);
profileId = profile.getId(); profileId = profile.getId();
appSharedPrefs.edit().putInt("current_profile_id", profile.getId()).apply(); appSharedPrefs.edit().putInt("current_profile_id", profile.getId()).apply();
config.setProfile(profileId);
} }
else if (!loadedLast) { else if (!loadedLast) {
profileLoadById(profileLastId(), true); profileLoadById(profileLastId(), true);
@ -709,12 +733,11 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
public void checkDevModePassword() { public void checkDevModePassword() {
try { try {
devMode = Utils.AESCrypt.decrypt("nWFVxY65Pa8/aRrT7EylNAencmOD+IxUY2Gg/beiIWY=", config.getDevModePassword()).equals("ok here you go it's enabled now") devMode = Utils.AESCrypt.decrypt("nWFVxY65Pa8/aRrT7EylNAencmOD+IxUY2Gg/beiIWY=", appConfig.devModePassword).equals("ok here you go it's enabled now")
|| BuildConfig.DEBUG; || BuildConfig.DEBUG;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
devMode = false; devMode = false;
} }
} }
} }

View File

@ -1,319 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
*/
package pl.szczodrzynski.edziennik
import android.util.Log
import androidx.work.Configuration
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlin.coroutines.CoroutineContext
class Szkolny : /*MultiDexApplication(),*/ Configuration.Provider, CoroutineScope {
companion object {
var devMode = false
}
//lateinit var db: AppDb
//val config by lazy { Config(db); // TODO migrate }
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun getWorkManagerConfiguration() = Configuration.Builder()
.setMinimumLoggingLevel(Log.VERBOSE)
.build()
/*val preferences by lazy { getSharedPreferences(getString(R.string.preference_file), Context.MODE_PRIVATE) }
val notifier by lazy { Notifier(this) }
val permissionChecker by lazy { PermissionChecker(this) }
lateinit var profile: ProfileFull
/* _ _ _______ _______ _____
| | | |__ __|__ __| __ \
| |__| | | | | | | |__) |
| __ | | | | | | ___/
| | | | | | | | | |
|_| |_| |_| |_| |*/
val http: OkHttpClient by lazy {
val builder = OkHttpClient.Builder()
.cache(null)
.followRedirects(true)
.followSslRedirects(true)
.retryOnConnectionFailure(true)
.cookieJar(cookieJar)
.connectTimeout(20, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
builder.installHttpsSupport()
if (devMode || BuildConfig.DEBUG) {
HyperLog.initialize(this)
HyperLog.setLogLevel(Log.VERBOSE)
HyperLog.setLogFormat(DebugLogFormat(this))
val chuckerCollector = ChuckerCollector(this, true, Period.ONE_HOUR)
val chuckerInterceptor = ChuckerInterceptor(this, chuckerCollector)
builder.addInterceptor(chuckerInterceptor)
}
builder.build()
}
val httpLazy: OkHttpClient by lazy {
http.newBuilder()
.followRedirects(false)
.followSslRedirects(false)
.build()
}
val cookieJar by lazy { PersistentCookieJar(SetCookieCache(), SharedPrefsCookiePersistor(this)) }
/* _____ _ _
/ ____(_) | |
| (___ _ __ _ _ __ __ _| |_ _ _ _ __ ___
\___ \| |/ _` | '_ \ / _` | __| | | | '__/ _ \
____) | | (_| | | | | (_| | |_| |_| | | | __/
|_____/|_|\__, |_| |_|\__,_|\__|\__,_|_| \___|
__/ |
|__*/
private val deviceId: String by lazy { Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID) ?: "" }
private val signature: String by lazy {
var str = ""
try {
val packageInfo: PackageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES)
for (signature in packageInfo.signatures) {
val signatureBytes = signature.toByteArray()
val md = MessageDigest.getInstance("SHA")
md.update(signatureBytes)
str = Base64.encodeToString(md.digest(), Base64.DEFAULT)
}
} catch (e: Exception) {
e.printStackTrace()
}
str
}
private var unreadBadgesAvailable = true
/* _____ _
/ ____| | |
___ _ __ | | _ __ ___ __ _| |_ ___
/ _ \| '_ \| | | '__/ _ \/ _` | __/ _ \
| (_) | | | | |____| | | __/ (_| | || __/
\___/|_| |_|\_____|_| \___|\__,_|\__\__*/
override fun onCreate() {
super.onCreate()
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
CaocConfig.Builder.create()
.backgroundMode(CaocConfig.BACKGROUND_MODE_SHOW_CUSTOM)
.enabled(true)
.showErrorDetails(true)
.showRestartButton(true)
.logErrorOnRestart(true)
.trackActivities(true)
.minTimeBetweenCrashesMs(60*1000)
.errorDrawable(R.drawable.ic_rip)
.restartActivity(MainActivity::class.java)
.errorActivity(CrashActivity::class.java)
.apply()
Iconics.init(applicationContext)
Iconics.registerFont(SzkolnyFont)
db = AppDb.getDatabase(this)
Themes.themeInt = config.ui.theme
MHttp.instance().customOkHttpClient(http)
devMode = "f054761fbdb6a238" == deviceId || BuildConfig.DEBUG
if (config.devModePassword != null)
checkDevModePassword()
launch { async(Dispatchers.Default) {
if (config.sync.enabled) {
scheduleNext(this@App, false)
} else {
cancelNext(this@App)
}
db.metadataDao().countUnseen().observeForever { count: Int ->
if (unreadBadgesAvailable)
unreadBadgesAvailable = ShortcutBadger.applyCount(this@App, count)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
val shortcutManager = getSystemService(ShortcutManager::class.java)
val shortcutTimetable = ShortcutInfo.Builder(this@App, "item_timetable")
.setShortLabel(getString(R.string.shortcut_timetable)).setLongLabel(getString(R.string.shortcut_timetable))
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_timetable))
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE))
.build()
val shortcutAgenda = ShortcutInfo.Builder(this@App, "item_agenda")
.setShortLabel(getString(R.string.shortcut_agenda)).setLongLabel(getString(R.string.shortcut_agenda))
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_agenda))
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_AGENDA))
.build()
val shortcutGrades = ShortcutInfo.Builder(this@App, "item_grades")
.setShortLabel(getString(R.string.shortcut_grades)).setLongLabel(getString(R.string.shortcut_grades))
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_grades))
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_GRADES))
.build()
val shortcutHomework = ShortcutInfo.Builder(this@App, "item_homeworks")
.setShortLabel(getString(R.string.shortcut_homework)).setLongLabel(getString(R.string.shortcut_homework))
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_homework))
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_HOMEWORK))
.build()
val shortcutMessages = ShortcutInfo.Builder(this@App, "item_messages")
.setShortLabel(getString(R.string.shortcut_messages)).setLongLabel(getString(R.string.shortcut_messages))
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_messages))
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_MESSAGES))
.build()
shortcutManager.dynamicShortcuts = listOf(
shortcutTimetable,
shortcutAgenda,
shortcutGrades,
shortcutHomework,
shortcutMessages
)
} // shortcuts - end
if (config.appInstalledTime == 0L)
try {
config.appInstalledTime = packageManager.getPackageInfo(packageName, 0).firstInstallTime
config.appRateSnackbarTime = config.appInstalledTime + 7*DAY*MS
} catch (e: NameNotFoundException) {
e.printStackTrace()
}
val pushMobidziennikApp = FirebaseApp.initializeApp(
this@App,
FirebaseOptions.Builder()
.setApiKey("AIzaSyCi5LmsZ5BBCQnGtrdvWnp1bWLCNP8OWQE")
.setApplicationId("1:747285019373:android:f6341bf7b158621d")
.build(),
"Mobidziennik2"
)
val pushLibrusApp = FirebaseApp.initializeApp(
this@App,
FirebaseOptions.Builder()
.setApiKey("AIzaSyDfTuEoYPKdv4aceEws1CO3n0-HvTndz-o")
.setApplicationId("1:513056078587:android:1e29083b760af544")
.build(),
"Librus"
)
val pushVulcanApp = FirebaseApp.initializeApp(
this@App,
FirebaseOptions.Builder()
.setApiKey("AIzaSyDW8MUtanHy64_I0oCpY6cOxB3jrvJd_iA")
.setApplicationId("1:987828170337:android:ac97431a0a4578c3")
.build(),
"Vulcan"
)
try {
FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener { instanceIdResult ->
val token = instanceIdResult.token
config.sync.tokenApp = token
}
FirebaseInstanceId.getInstance(pushMobidziennikApp).instanceId.addOnSuccessListener { instanceIdResult ->
val token = instanceIdResult.token
if (token != config.sync.tokenMobidziennik) {
config.sync.tokenMobidziennik = token
config.sync.tokenMobidziennikList = listOf()
}
}
FirebaseInstanceId.getInstance(pushLibrusApp).instanceId.addOnSuccessListener { instanceIdResult ->
val token = instanceIdResult.token
if (token != config.sync.tokenLibrus) {
config.sync.tokenLibrus = token
config.sync.tokenLibrusList = listOf()
}
}
FirebaseInstanceId.getInstance(pushVulcanApp).instanceId.addOnSuccessListener { instanceIdResult ->
val token = instanceIdResult.token
if (token != config.sync.tokenVulcan) {
config.sync.tokenVulcan = token
config.sync.tokenVulcanList = listOf()
}
}
FirebaseMessaging.getInstance().subscribeToTopic(packageName)
} catch (e: IllegalStateException) {
e.printStackTrace()
}
}}
}
private fun profileLoad(profileId: Int) {
db.profileDao().getFullByIdNow(profileId)?.also {
profile = it
} ?: run {
if (!::profile.isInitialized) {
profile = ProfileFull(-1, "", "", -1)
}
}
}
fun profileLoad(profileId: Int, onSuccess: (profile: ProfileFull) -> Unit) {
launch {
val deferred = async(Dispatchers.Default) {
profileLoad(profileId)
}
deferred.await()
onSuccess(profile)
}
}
private fun OkHttpClient.Builder.installHttpsSupport() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
try {
try {
ProviderInstaller.installIfNeeded(this@App)
} catch (e: Exception) {
Log.e("OkHttpTLSCompat", "Play Services not found or outdated")
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
trustManagerFactory.init(null as KeyStore?)
val x509TrustManager = trustManagerFactory.trustManagers.singleOrNull { it is X509TrustManager } as X509TrustManager?
?: return
val sc = SSLContext.getInstance("TLSv1.2")
sc.init(null, null, null)
sslSocketFactory(TLSSocketFactory(sc.socketFactory), x509TrustManager)
val cs: ConnectionSpec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_0)
.tlsVersions(TlsVersion.TLS_1_1)
.tlsVersions(TlsVersion.TLS_1_2)
.build()
val specs: MutableList<ConnectionSpec> = ArrayList()
specs.add(cs)
specs.add(ConnectionSpec.COMPATIBLE_TLS)
specs.add(ConnectionSpec.CLEARTEXT)
connectionSpecs(specs)
}
} catch (exc: Exception) {
Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc)
}
}
}
fun checkDevModePassword() {
devMode = try {
Utils.AESCrypt.decrypt("nWFVxY65Pa8/aRrT7EylNAencmOD+IxUY2Gg/beiIWY=", config.devModePassword) == "ok here you go it's enabled now" || BuildConfig.DEBUG
} catch (e: Exception) {
e.printStackTrace()
false
}
}*/
}

View File

@ -1,21 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-11.
*/
package pl.szczodrzynski.edziennik;
import android.graphics.Paint;
import android.widget.TextView;
import androidx.databinding.BindingAdapter;
public class Binding {
@BindingAdapter("strikeThrough")
public static void strikeThrough(TextView textView, Boolean strikeThrough) {
if (strikeThrough) {
textView.setPaintFlags(textView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
} else {
textView.setPaintFlags(textView.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
}
}
}

View File

@ -4,52 +4,24 @@ 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.PorterDuff
import android.graphics.PorterDuffColorFilter
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.Base64.NO_WRAP
import android.util.Base64.encodeToString
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 okhttp3.RequestBody
import okio.Buffer
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.edziennik.utils.models.Time import pl.szczodrzynski.navlib.R
import pl.szczodrzynski.navlib.getColorFromRes import pl.szczodrzynski.navlib.getColorFromRes
import java.math.BigInteger
import java.security.MessageDigest
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import java.util.zip.CRC32 import java.util.zip.CRC32
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
fun List<Teacher>.byId(id: Long) = firstOrNull { it.id == id } fun List<Teacher>.byId(id: Long) = firstOrNull { it.id == id }
@ -112,15 +84,6 @@ 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()
@ -179,9 +142,8 @@ fun colorFromName(context: Context, name: String?): Int {
return context.getColorFromRes(color) return context.getColorFromRes(color)
} }
fun MutableList<Profile>.filterOutArchived(): MutableList<Profile> { fun MutableList<out Profile>.filterOutArchived() {
this.removeAll { it.archived } this.removeAll { it.archived }
return this
} }
fun Activity.isStoragePermissionGranted(): Boolean { fun Activity.isStoragePermissionGranted(): Boolean {
@ -210,7 +172,6 @@ const val DAY = 24L*HOUR
const val WEEK = 7L*DAY const val WEEK = 7L*DAY
const val MONTH = 30L*DAY const val MONTH = 30L*DAY
const val YEAR = 365L*DAY const val YEAR = 365L*DAY
const val MS = 1000L
fun <T> LongSparseArray<T>.values(): List<T> { fun <T> LongSparseArray<T>.values(): List<T> {
val result = mutableListOf<T>() val result = mutableListOf<T>()
@ -365,273 +326,4 @@ fun String.crc32(): Long {
return crc.value return crc.value
} }
fun String.hmacSHA1(password: String): String { fun Long.formatDate(format: String = "yyyy-MM-dd HH:mm:ss"): String = SimpleDateFormat(format).format(this)
val key = SecretKeySpec(password.toByteArray(), "HmacSHA1")
val mac = Mac.getInstance("HmacSHA1").apply {
init(key)
update(this@hmacSHA1.toByteArray())
}
return encodeToString(mac.doFinal(), NO_WRAP)
}
fun String.md5(): String {
val md = MessageDigest.getInstance("MD5")
return BigInteger(1, md.digest(toByteArray())).toString(16).padStart(32, '0')
}
fun RequestBody.bodyToString(): String {
val buffer = Buffer()
writeTo(buffer)
return buffer.readUtf8()
}
fun Long.formatDate(format: String = "yyyy-MM-dd HH:mm:ss"): String = SimpleDateFormat(format).format(this)
fun CharSequence?.asColoredSpannable(colorInt: Int): Spannable {
val spannable = SpannableString(this)
spannable.setSpan(ForegroundColorSpan(colorInt), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
return spannable
}
fun CharSequence?.asStrikethroughSpannable(): Spannable {
val spannable = SpannableString(this)
spannable.setSpan(StrikethroughSpan(), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
return spannable
}
fun CharSequence?.asItalicSpannable(): Spannable {
val spannable = SpannableString(this)
spannable.setSpan(StyleSpan(Typeface.ITALIC), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
return spannable
}
/**
* 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) }
}
inline fun <reified T> Any?.instanceOfOrNull(): T? {
return when (this) {
is T -> this
else -> null
}
}
fun Drawable.setTintColor(color: Int): Drawable {
colorFilter = PorterDuffColorFilter(
color,
PorterDuff.Mode.SRC_ATOP
)
return this
}

View File

@ -2,19 +2,13 @@ package pl.szczodrzynski.edziennik
import android.app.Activity import android.app.Activity
import android.app.ActivityManager import android.app.ActivityManager
import android.content.BroadcastReceiver import android.content.*
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
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.core.graphics.ColorUtils import androidx.core.graphics.ColorUtils
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
@ -31,46 +25,45 @@ import com.mikepenz.materialdrawer.model.ProfileDrawerItem
import com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem import com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem
import com.mikepenz.materialdrawer.model.interfaces.IProfile import com.mikepenz.materialdrawer.model.interfaces.IProfile
import dagger.android.support.DaggerAppCompatActivity
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe 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.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.HomeFragmentV2 import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment
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.MessageFragment import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesDetailsFragment
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.v2.TimetableFragment import pl.szczodrzynski.edziennik.ui.modules.timetable.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
@ -85,7 +78,7 @@ import java.io.IOException
import java.util.* import java.util.*
import kotlin.math.roundToInt import kotlin.math.roundToInt
class MainActivity : AppCompatActivity() { class MainActivity : DaggerAppCompatActivity() {
companion object { companion object {
var useOldMessages = false var useOldMessages = false
@ -122,9 +115,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, HomeFragmentV2::class) list += NavTarget(DRAWER_ITEM_HOME, R.string.menu_home_page, HomeFragment::class)
.withTitle(R.string.app_name) .withTitle(R.string.app_name)
.withIcon(CommunityMaterial.Icon2.cmd_home_outline) .withIcon(CommunityMaterial.Icon2.cmd_home)
.isInDrawer(true) .isInDrawer(true)
.isStatic(true) .isStatic(true)
.withPopToHome(false) .withPopToHome(false)
@ -135,50 +128,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_outline) .withIcon(CommunityMaterial.Icon.cmd_calendar)
.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_outline) .withIcon(CommunityMaterial.Icon2.cmd_numeric_5_box)
.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_outline) .withIcon(CommunityMaterial.Icon.cmd_email)
.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_notebook_outline) .withIcon(SzkolnyFont.Icon.szf_file_document_edit)
.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.Icon.cmd_emoticon_outline) .withIcon(CommunityMaterial.Icon2.cmd_message_alert)
.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_outline) .withIcon(CommunityMaterial.Icon.cmd_calendar_remove)
.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_bullhorn_outline) .withIcon(CommunityMaterial.Icon.cmd_bulletin_board)
.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_outline) .withIcon(CommunityMaterial.Icon.cmd_bell_ring)
.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_outline) .withIcon(CommunityMaterial.Icon2.cmd_settings)
.isInDrawer(true) .isInDrawer(true)
.isStatic(true) .isStatic(true)
.isBelowSeparator(true) .isBelowSeparator(true)
@ -197,7 +190,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.Icon.cmd_download_outline) .withIcon(CommunityMaterial.Icon2.cmd_sync)
.isInProfileList(true) .isInProfileList(true)
@ -205,7 +198,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, MessageFragment::class) list += NavTarget(TARGET_MESSAGES_DETAILS, R.string.menu_message, MessagesDetailsFragment::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
@ -216,7 +209,6 @@ 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 }
@ -243,14 +235,12 @@ class MainActivity : AppCompatActivity() {
setTheme(Themes.appTheme) setTheme(Themes.appTheme)
app.config.ui.language?.let { app.appConfig.language?.let {
setLanguage(it) setLanguage(it)
} }
setContentView(b.root) setContentView(b.root)
errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
navLoading = true navLoading = true
b.navView.apply { b.navView.apply {
@ -306,10 +296,10 @@ class MainActivity : AppCompatActivity() {
} }
drawer.apply { drawer.apply {
setAccountHeaderBackground(app.config.ui.headerBackground) setAccountHeaderBackground(app.appConfig.headerBackground)
drawerProfileListEmptyListener = { drawerProfileListEmptyListener = {
app.config.loginFinished = false app.appConfig.loginFinished = false
app.saveConfig("loginFinished") app.saveConfig("loginFinished")
profileListEmptyListener() profileListEmptyListener()
} }
@ -334,7 +324,7 @@ class MainActivity : AppCompatActivity() {
drawerProfileSettingClickListener = this@MainActivity.profileSettingClickListener drawerProfileSettingClickListener = this@MainActivity.profileSettingClickListener
miniDrawerVisibleLandscape = null miniDrawerVisibleLandscape = null
miniDrawerVisiblePortrait = app.config.ui.miniMenuVisible miniDrawerVisiblePortrait = app.appConfig.miniDrawerVisible
} }
} }
@ -376,34 +366,27 @@ 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()
SyncWorker.scheduleNext(app) SyncWorker.scheduleNext(app)
// APP BACKGROUND // APP BACKGROUND
if (app.config.ui.appBackground != null) { if (app.appConfig.appBackground != null) {
try { try {
app.config.ui.appBackground?.let { var bg = app.appConfig.appBackground
var bg = it val bgDir = File(Environment.getExternalStoragePublicDirectory("Szkolny.eu"), "bg")
val bgDir = File(Environment.getExternalStoragePublicDirectory("Szkolny.eu"), "bg") if (bgDir.exists()) {
if (bgDir.exists()) { val files = bgDir.listFiles()
val files = bgDir.listFiles() val r = Random()
val r = Random() val i = r.nextInt(files.size)
val i = r.nextInt(files.size) bg = files[i].toString()
bg = files[i].toString() }
} val linearLayout = b.root
val linearLayout = b.root if (bg.endsWith(".gif")) {
if (bg.endsWith(".gif")) { linearLayout.background = GifDrawable(bg)
linearLayout.background = GifDrawable(bg) } else {
} else { linearLayout.background = BitmapDrawable.createFromPath(bg)
linearLayout.background = BitmapDrawable.createFromPath(bg)
}
} }
} catch (e: IOException) { } catch (e: IOException) {
e.printStackTrace() e.printStackTrace()
@ -411,7 +394,7 @@ class MainActivity : AppCompatActivity() {
} }
// WHAT'S NEW DIALOG // WHAT'S NEW DIALOG
if (app.config.appVersion < BuildConfig.VERSION_CODE) { if (app.appConfig.lastAppVersion != BuildConfig.VERSION_CODE) {
ServerRequest(app, app.requestScheme + APP_URL + "main.php?just_updated", "MainActivity/JU") ServerRequest(app, app.requestScheme + APP_URL + "main.php?just_updated", "MainActivity/JU")
.run { e, result -> .run { e, result ->
Handler(Looper.getMainLooper()).post { Handler(Looper.getMainLooper()).post {
@ -422,20 +405,21 @@ class MainActivity : AppCompatActivity() {
} }
} }
} }
if (app.config.appVersion < 170) { if (app.appConfig.lastAppVersion < 170) {
//Intent intent = new Intent(this, ChangelogIntroActivity.class); //Intent intent = new Intent(this, ChangelogIntroActivity.class);
//startActivity(intent); //startActivity(intent);
} else { } else {
app.config.appVersion = BuildConfig.VERSION_CODE app.appConfig.lastAppVersion = BuildConfig.VERSION_CODE
app.saveConfig("lastAppVersion")
} }
} }
// RATE SNACKBAR // RATE SNACKBAR
if (app.config.appRateSnackbarTime != 0L && app.config.appRateSnackbarTime <= System.currentTimeMillis()) { if (app.appConfig.appRateSnackbarTime != 0L && app.appConfig.appRateSnackbarTime <= System.currentTimeMillis()) {
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_outline).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.getPrimaryTextColor(this)))) .icon(IconicsDrawable(this).icon(CommunityMaterial.Icon2.cmd_star).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)
@ -445,17 +429,20 @@ class MainActivity : AppCompatActivity() {
.onPositive { cafeBar -> .onPositive { cafeBar ->
Utils.openGooglePlay(this) Utils.openGooglePlay(this)
cafeBar.dismiss() cafeBar.dismiss()
app.config.appRateSnackbarTime = 0 app.appConfig.appRateSnackbarTime = 0
app.saveConfig("appRateSnackbarTime")
} }
.onNegative { cafeBar -> .onNegative { cafeBar ->
Toast.makeText(this, "Szkoda, opinie innych pomagają mi rozwijać aplikację.", Toast.LENGTH_LONG).show() Toast.makeText(this, "Szkoda, opinie innych pomagają mi rozwijać aplikację.", Toast.LENGTH_LONG).show()
cafeBar.dismiss() cafeBar.dismiss()
app.config.appRateSnackbarTime = 0 app.appConfig.appRateSnackbarTime = 0
app.saveConfig("appRateSnackbarTime")
} }
.onNeutral { cafeBar -> .onNeutral { cafeBar ->
Toast.makeText(this, "OK", Toast.LENGTH_LONG).show() Toast.makeText(this, "OK", Toast.LENGTH_LONG).show()
cafeBar.dismiss() cafeBar.dismiss()
app.config.appRateSnackbarTime = System.currentTimeMillis() + 7 * 24 * 60 * 60 * 1000 app.appConfig.appRateSnackbarTime = System.currentTimeMillis() + 7 * 24 * 60 * 60 * 1000
app.saveConfig("appRateSnackbarTime")
} }
.autoDismiss(false) .autoDismiss(false)
.swipeToDismiss(true) .swipeToDismiss(true)
@ -469,25 +456,25 @@ class MainActivity : AppCompatActivity() {
bottomSheet.appendItems( bottomSheet.appendItems(
BottomSheetPrimaryItem(false) BottomSheetPrimaryItem(false)
.withTitle(R.string.menu_sync) .withTitle(R.string.menu_sync)
.withIcon(CommunityMaterial.Icon.cmd_download_outline) .withIcon(CommunityMaterial.Icon2.cmd_sync)
.withOnClickListener(View.OnClickListener { .withOnClickListener(View.OnClickListener {
bottomSheet.close() bottomSheet.close()
SyncViewListDialog(this, navTargetId) app.apiEdziennik.guiSyncFeature(app, this, App.profileId, R.string.sync_dialog_title, R.string.sync_dialog_text, R.string.sync_done, fragmentToFeature(navTargetId))
}), }),
BottomSheetSeparatorItem(false), BottomSheetSeparatorItem(false),
BottomSheetPrimaryItem(false) BottomSheetPrimaryItem(false)
.withTitle(R.string.menu_settings) .withTitle(R.string.menu_settings)
.withIcon(CommunityMaterial.Icon2.cmd_settings_outline) .withIcon(CommunityMaterial.Icon2.cmd_settings)
.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_outline) .withIcon(CommunityMaterial.Icon2.cmd_help_circle)
.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_studio) .withIcon(CommunityMaterial.Icon.cmd_android_debug_bridge)
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_DEBUG) }) .withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_DEBUG) })
} }
@ -531,19 +518,17 @@ 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
} }
val arguments = when (navTargetId) { EventBus.getDefault().postSticky(
DRAWER_ITEM_TIMETABLE -> JsonObject("weekStart" to TimetableFragment.pageSelection?.weekStart?.stringY_m_d) EdziennikTask.syncProfile(
else -> null App.profileId,
} 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) {
@ -586,12 +571,7 @@ 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) {
@ -602,17 +582,28 @@ 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 {
for (intent in appManagerIntentList) { val intent = Intent()
if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) { intent.component = ComponentName(
startActivity(intent) "com.huawei.systemmanager",
} "com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity"
} )
startActivity(intent)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace()
try { try {
startActivity(Intent(Settings.ACTION_SETTINGS)) val intent = Intent()
intent.component = ComponentName(
"com.asus.mobilemanager",
"com.asus.mobilemanager.MainActivity"
)
startActivity(intent)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() try {
Toast.makeText(this, R.string.app_manager_open_failed, Toast.LENGTH_SHORT).show() 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()
}
} }
} }
} }
@ -623,7 +614,22 @@ 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
@ -687,33 +693,29 @@ class MainActivity : AppCompatActivity() {
}*/ }*/
if (navLoading) { if (navLoading) {
navLoading = false
b.fragment.removeAllViews() b.fragment.removeAllViews()
if (intentTargetId == -1) if (intentTargetId == -1)
intentTargetId = HOME_ID intentTargetId = HOME_ID
} }
when { when {
app.profile == null || app.profile.id == -1 -> { 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, extras) loadProfile(intentProfileId, intentTargetId)
} }
intentProfileId != -1 -> { intentProfileId != -1 -> {
if (app.profile.id != intentProfileId) loadProfile(intentProfileId, intentTargetId)
loadProfile(intentProfileId, intentTargetId, extras)
else
loadTarget(intentTargetId, extras)
} }
intentTargetId != -1 -> { intentTargetId != -1 -> {
drawer.currentProfile = app.profile.id drawer.currentProfile = app.profile.id
if (navTargetId != intentTargetId || navLoading) loadTarget(intentTargetId, extras)
loadTarget(intentTargetId, extras)
} }
else -> { else -> {
drawer.currentProfile = app.profile.id drawer.currentProfile = app.profile.id
} }
} }
navLoading = false
} }
override fun recreate() { override fun recreate() {
@ -761,7 +763,7 @@ class MainActivity : AppCompatActivity() {
finish() finish()
} }
else { else {
if (!app.config.loginFinished) if (!app.appConfig.loginFinished)
finish() finish()
else { else {
handleIntent(data?.extras) handleIntent(data?.extras)
@ -786,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)
@ -798,16 +800,13 @@ class MainActivity : AppCompatActivity() {
this.runOnUiThread { this.runOnUiThread {
if (app.profile == null) { if (app.profile == null) {
LoginActivity.firstCompleted = false LoginActivity.firstCompleted = false
if (app.config.loginFinished) { if (app.appConfig.loginFinished) {
// this shouldn't run // this shouldn't run
profileListEmptyListener() profileListEmptyListener()
} }
} else { } else {
setDrawerItems() setDrawerItems()
// the drawer profile is updated automatically when the drawer item is clicked drawer.currentProfile = app.profile.id
// update it manually when switching profiles from other source
//if (drawer.currentProfile != app.profile.id)
drawer.currentProfile = app.profile.id
loadTarget(drawerSelection, arguments) loadTarget(drawerSelection, arguments)
} }
} }
@ -974,7 +973,7 @@ class MainActivity : AppCompatActivity() {
val item = DrawerPrimaryItem() val item = DrawerPrimaryItem()
.withIdentifier(target.id.toLong()) .withIdentifier(target.id.toLong())
.withName(target.name) .withName(target.name)
.withHiddenInMiniDrawer(!app.config.ui.miniMenuButtons.contains(target.id)) .withHiddenInMiniDrawer(!app.appConfig.miniDrawerButtonIds.contains(target.id))
.also { if (target.description != null) it.withDescription(target.description!!) } .also { if (target.description != null) it.withDescription(target.description!!) }
.also { if (target.icon != null) it.withIcon(target.icon!!) } .also { if (target.icon != null) it.withIcon(target.icon!!) }
.also { if (target.title != null) it.withAppTitle(getString(target.title!!)) } .also { if (target.title != null) it.withAppTitle(getString(target.title!!)) }
@ -1052,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) {
ProfileRemoveDialog(this, profileId, profile.name?.getText(this)?.toString() ?: "?") app.apiEdziennik.guiRemoveProfile(this@MainActivity, profileId, profile.name?.getText(this).toString())
} }
true true
} }
@ -1063,11 +1062,30 @@ class MainActivity : AppCompatActivity() {
private var targetHomeId: Int = -1 private var targetHomeId: Int = -1
override fun onBackPressed() { override fun onBackPressed() {
if (!b.navView.onBackPressed()) { if (!b.navView.onBackPressed()) {
if (App.getConfig().ui.openDrawerOnBackPressed) {
b.navView.drawer.toggle() navigateUp()
/*val currentDestinationId = navController.currentDestination?.id
if (if (targetHomeId != -1 && targetPopToHomeList.contains(navController.currentDestination?.id)) {
if (!navController.popBackStack(targetHomeId, false)) {
navController.navigateUp()
}
true
} else {
navController.navigateUp()
}) {
val currentId = navController.currentDestination?.id ?: -1
val drawerSelection = navTargetList
.singleOrNull {
it.navGraphId == currentId
}?.also {
navView.toolbar.setTitle(it.title ?: it.name)
}?.id ?: -1
drawer.setSelection(drawerSelection, false)
} else { } else {
navigateUp() super.onBackPressed()
} }*/
} }
} }
} }

View File

@ -93,8 +93,8 @@ public class Notifier {
public boolean shouldBeQuiet() { public boolean shouldBeQuiet() {
long now = Time.getNow().getInMillis(); long now = Time.getNow().getInMillis();
long start = app.config.getSync().getQuietHoursStart(); long start = app.appConfig.quietHoursStart;
long end = app.config.getSync().getQuietHoursEnd(); long end = app.appConfig.quietHoursEnd;
if (start > end) { if (start > end) {
end += 1000 * 60 * 60 * 24; end += 1000 * 60 * 60 * 24;
//Log.d(TAG, "Night passing"); //Log.d(TAG, "Night passing");
@ -104,7 +104,7 @@ public class Notifier {
//Log.d(TAG, "Now is smaller"); //Log.d(TAG, "Now is smaller");
} }
//Log.d(TAG, "Start is "+start+", now is "+now+", end is "+end); //Log.d(TAG, "Start is "+start+", now is "+now+", end is "+end);
return start > 0 && now >= start && now <= end; return app.appConfig.quietHoursStart > 0 && now >= start && now <= end;
} }
public int getNotificationDefaults() { public int getNotificationDefaults() {
@ -311,14 +311,13 @@ public class Notifier {
\____/| .__/ \__,_|\__,_|\__\___||___/ \____/| .__/ \__,_|\__,_|\__\___||___/
| | | |
|*/ |*/
public void notificationUpdatesShow(String updateVersion, String updateUrl, String updateFilename, boolean updateDirect) { public void notificationUpdatesShow(String updateVersion, String updateUrl, String updateFilename) {
if (!app.config.getSync().getNotifyAboutUpdates()) 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);
@ -340,7 +339,7 @@ public class Notifier {
} }
public void notificationUpdatesHide() { public void notificationUpdatesHide() {
if (!app.config.getSync().getNotifyAboutUpdates()) if (!app.appConfig.notifyAboutUpdates)
return; return;
notificationManager.cancel(ID_UPDATES); notificationManager.cancel(ID_UPDATES);
} }

View File

@ -0,0 +1,450 @@
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");
}
}

View File

@ -1,371 +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.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.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
app.config.timetable.bellSyncDiff?.let {
bellSyncDiffMillis = (it.hour * 60 * 60 * 1000 + it.minute * 60 * 1000 + it.second * 1000).toLong()
bellSyncDiffMillis *= app.config.timetable.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
}
}
}

View File

@ -15,10 +15,12 @@ import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.api.v2.events.* import pl.szczodrzynski.edziennik.api.v2.events.*
import pl.szczodrzynski.edziennik.api.v2.events.requests.ServiceCloseRequest import pl.szczodrzynski.edziennik.api.v2.events.requests.ServiceCloseRequest
import pl.szczodrzynski.edziennik.api.v2.events.requests.TaskCancelRequest import pl.szczodrzynski.edziennik.api.v2.events.requests.TaskCancelRequest
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask
import pl.szczodrzynski.edziennik.api.v2.events.task.ErrorReportTask
import pl.szczodrzynski.edziennik.api.v2.events.task.IApiTask
import pl.szczodrzynski.edziennik.api.v2.events.task.NotifyTask
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
import pl.szczodrzynski.edziennik.api.v2.models.ApiError import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.api.v2.task.*
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
import kotlin.math.min import kotlin.math.min
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -38,11 +40,9 @@ class ApiService : Service() {
private val app by lazy { applicationContext as App } private val app by lazy { applicationContext as App }
private val syncingProfiles = mutableListOf<ProfileFull>()
private val finishingTaskQueue = mutableListOf( private val finishingTaskQueue = mutableListOf(
SzkolnyTask.sync(syncingProfiles), NotifyTask(),
NotifyTask() ErrorReportTask()
) )
private val taskQueue = mutableListOf<IApiTask>() private val taskQueue = mutableListOf<IApiTask>()
private val errorList = mutableListOf<ApiError>() private val errorList = mutableListOf<ApiError>()
@ -60,9 +60,6 @@ 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
/* ______ _ _ _ _ _____ _ _ _ _ /* ______ _ _ _ _ _____ _ _ _ _
| ____| | | (_) (_) | / ____| | | | | | | | ____| | | (_) (_) | / ____| | | | | | |
| |__ __| |_____ ___ _ __ _ __ _| | __ | | __ _| | | |__ __ _ ___| | __ | |__ __| |_____ ___ _ __ _ __ _| | __ | | __ _| | | |__ __ _ ___| | __
@ -71,26 +68,32 @@ 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")
EventBus.getDefault().post(ApiTaskFinishedEvent(taskProfileId)) //if (!taskCancelled) {
clearTask() EventBus.getDefault().post(ApiTaskFinishedEvent(taskProfileId))
//}
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()
clearTask() taskRunning = null
taskIsRunning = false
taskRunningId = -1
runTask() runTask()
} }
else { else {
@ -99,7 +102,6 @@ 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)
@ -112,7 +114,6 @@ 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))
@ -127,7 +128,6 @@ 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,8 +136,6 @@ 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)
@ -156,62 +154,13 @@ class ApiService : Service() {
// post an event // post an event
EventBus.getDefault().post(ApiTaskStartedEvent(taskProfileId, task.profile)) EventBus.getDefault().post(ApiTaskStartedEvent(taskProfileId, task.profile))
task.profile?.let { syncingProfiles.add(it) } when (task) {
is EdziennikTask -> task.run(app, taskCallback)
try { is NotifyTask -> task.run(app, taskCallback)
when (task) { is ErrorReportTask -> task.run(app, taskCallback, notification, errorList)
is EdziennikTask -> task.run(app, taskCallback)
is NotifyTask -> task.run(app, taskCallback)
is ErrorReportTask -> task.run(app, taskCallback, notification, errorList)
is SzkolnyTask -> task.run(app, taskCallback)
}
} 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()
@ -257,10 +206,8 @@ 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) {
@ -280,13 +227,11 @@ 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
} }

View File

@ -14,14 +14,6 @@ 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"
@ -64,7 +56,6 @@ 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"

View File

@ -45,8 +45,8 @@ class DataNotifications(val data: Data) {
return@run return@run
} }
for (lesson in app.db.timetableDao().getNotNotifiedNow(profileId)) { for (change in app.db.lessonChangeDao().getNotNotifiedNow(profileId)) {
val text = app.getString(R.string.notification_lesson_change_format, lesson.getDisplayChangeType(app), if (lesson.displayDate == null) "" else lesson.displayDate!!.formattedString, lesson.changeSubjectName) val text = app.getString(R.string.notification_lesson_change_format, change.changeTypeStr(app), if (change.lessonDate == null) "" else change.lessonDate!!.formattedString, change.subjectLongName)
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 = lesson.addedDate addedDate = change.addedDate
).addExtra("timetableDate", lesson.displayDate?.stringY_m_d ?: "") ).addExtra("timetableDate", change.lessonDate?.value?.toLong())
} }
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 (luckyNumber.date.value) { val text = when {
todayValue -> // LN for today luckyNumber.date.value == todayValue -> // LN for today
app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_format else R.string.notification_lucky_number_format, luckyNumber.number) app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_format else R.string.notification_lucky_number_format, luckyNumber.number)
todayValue + 1 -> // LN for tomorrow luckyNumber.date.value == 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)
}} }}
} }

View File

@ -39,16 +39,13 @@ 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
@ -102,13 +99,6 @@ 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
@ -119,7 +109,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 = 216 const val ERROR_MOBIDZIENNIK_WEB_NO_SESSION_VALUE = 212
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
@ -160,7 +150,6 @@ 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
@ -168,12 +157,8 @@ const val EXCEPTION_LIBRUS_API_REQUEST = 904
const val EXCEPTION_LIBRUS_SYNERGIA_REQUEST = 905 const val EXCEPTION_LIBRUS_SYNERGIA_REQUEST = 905
const val EXCEPTION_MOBIDZIENNIK_WEB_REQUEST = 906 const val EXCEPTION_MOBIDZIENNIK_WEB_REQUEST = 906
const val EXCEPTION_VULCAN_API_REQUEST = 907 const val EXCEPTION_VULCAN_API_REQUEST = 907
const val EXCEPTION_MOBIDZIENNIK_WEB_FILE_REQUEST = 908 const val EXCEPTION_NOTIFY_AND_SYNC = 910
const val EXCEPTION_LIBRUS_MESSAGES_FILE_REQUEST = 909
const val EXCEPTION_NOTIFY = 910
const val EXCEPTION_LIBRUS_MESSAGES_REQUEST = 911 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

View File

@ -7,36 +7,39 @@ 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
internal const val FEATURE_TIMETABLE = 1 const val FEATURE_ALL = 0
internal const val FEATURE_AGENDA = 2 const val FEATURE_TIMETABLE = 1
internal const val FEATURE_GRADES = 3 const val FEATURE_AGENDA = 2
internal const val FEATURE_HOMEWORK = 4 const val FEATURE_GRADES = 3
internal const val FEATURE_BEHAVIOUR = 5 const val FEATURE_HOMEWORK = 4
internal const val FEATURE_ATTENDANCE = 6 const val FEATURE_BEHAVIOUR = 5
internal const val FEATURE_MESSAGES_INBOX = 7 const val FEATURE_ATTENDANCE = 6
internal const val FEATURE_MESSAGES_SENT = 8 const val FEATURE_MESSAGES_INBOX = 7
internal const val FEATURE_ANNOUNCEMENTS = 9 const val FEATURE_MESSAGES_SENT = 8
const val FEATURE_ANNOUNCEMENTS = 9
internal const val FEATURE_ALWAYS_NEEDED = 100 const val FEATURE_ALWAYS_NEEDED = 100
internal const val FEATURE_STUDENT_INFO = 101 const val FEATURE_STUDENT_INFO = 101
internal const val FEATURE_STUDENT_NUMBER = 109 const val FEATURE_STUDENT_NUMBER = 109
internal const val FEATURE_SCHOOL_INFO = 102 const val FEATURE_SCHOOL_INFO = 102
internal const val FEATURE_CLASS_INFO = 103 const val FEATURE_CLASS_INFO = 103
internal const val FEATURE_TEAM_INFO = 104 const val FEATURE_TEAM_INFO = 104
internal const val FEATURE_LUCKY_NUMBER = 105 const val FEATURE_LUCKY_NUMBER = 105
internal const val FEATURE_TEACHERS = 106 const val FEATURE_TEACHERS = 106
internal const val FEATURE_SUBJECTS = 107 const val FEATURE_SUBJECTS = 107
internal const val FEATURE_CLASSROOMS = 108 const val FEATURE_CLASSROOMS = 108
internal const val FEATURE_PUSH_CONFIG = 120 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(

View File

@ -4,17 +4,17 @@
package pl.szczodrzynski.edziennik.api.v2 package pl.szczodrzynski.edziennik.api.v2
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.login.IdziennikLoginApi import pl.szczodrzynski.edziennik.api.v2.idziennik.login.IdziennikLoginApi
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.login.IdziennikLoginWeb import pl.szczodrzynski.edziennik.api.v2.idziennik.login.IdziennikLoginWeb
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.login.LibrusLoginApi import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginApi
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.login.LibrusLoginMessages import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginMessages
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.login.LibrusLoginPortal import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginPortal
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.login.LibrusLoginSynergia import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginSynergia
import pl.szczodrzynski.edziennik.api.v2.edziennik.mobidziennik.login.MobidziennikLoginWeb import pl.szczodrzynski.edziennik.api.v2.mobidziennik.login.MobidziennikLoginWeb
import pl.szczodrzynski.edziennik.api.v2.edziennik.template.login.TemplateLoginApi
import pl.szczodrzynski.edziennik.api.v2.edziennik.template.login.TemplateLoginWeb
import pl.szczodrzynski.edziennik.api.v2.edziennik.vulcan.login.VulcanLoginApi
import pl.szczodrzynski.edziennik.api.v2.models.LoginMethod import pl.szczodrzynski.edziennik.api.v2.models.LoginMethod
import pl.szczodrzynski.edziennik.api.v2.template.login.TemplateLoginApi
import pl.szczodrzynski.edziennik.api.v2.template.login.TemplateLoginWeb
import pl.szczodrzynski.edziennik.api.v2.vulcan.login.VulcanLoginApi
// librus // librus
// mobidziennik // mobidziennik
@ -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 { _, loginStore -> !loginStore.hasLoginData("fakeLogin") } .withIsPossible { _, _ -> true }
.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 { _, loginStore -> !loginStore.hasLoginData("fakeLogin") } .withIsPossible { _, _ -> true }
.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
} }
@ -138,4 +138,4 @@ val templateLoginMethods = listOf(
LoginMethod(LOGIN_TYPE_TEMPLATE, LOGIN_METHOD_TEMPLATE_API, TemplateLoginApi::class.java) LoginMethod(LOGIN_TYPE_TEMPLATE, LOGIN_METHOD_TEMPLATE_API, TemplateLoginApi::class.java)
.withIsPossible { _, _ -> true } .withIsPossible { _, _ -> true }
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_TEMPLATE_WEB } .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_TEMPLATE_WEB }
) )

View File

@ -24,7 +24,7 @@ object Regexes {
"""Liczona do średniej:.*?<strong>nie<br/?></strong>""".toRegex(RegexOption.DOT_MATCHES_ALL) """Liczona do średniej:.*?<strong>nie<br/?></strong>""".toRegex(RegexOption.DOT_MATCHES_ALL)
} }
val MOBIDZIENNIK_GRADES_DETAILS by lazy { val MOBIDZIENNIK_GRADES_DETAILS by lazy {
"""<strong.*?>(.+?)</strong>.*?<sup>.+?</sup>.*?(?:<small>\((.+?)\)</small>.*?)?<span>.*?Wartość oceny:.*?<strong>([0-9.]+)</strong>.*?Wpisał\(a\):.*?<strong>(.+?)</strong>.*?(?:Komentarz:.*?<strong>(.+?)</strong>)?</span>""".toRegex(RegexOption.DOT_MATCHES_ALL) """<strong.*?>(.+?)</strong>.*?<sup>.+?</sup>.*?<small>\((.+?)\)</small>.*?<span>.*?Wartość oceny:.*?<strong>([0-9.]+)</strong>.*?Wpisał\(a\):.*?<strong>(.+?)</strong>""".toRegex(RegexOption.DOT_MATCHES_ALL)
} }
val MOBIDZIENNIK_EVENT_TYPE by lazy { val MOBIDZIENNIK_EVENT_TYPE by lazy {
@ -37,16 +37,6 @@ 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 {
@ -70,16 +60,4 @@ 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()
}
} }

View File

@ -0,0 +1,179 @@
package pl.szczodrzynski.edziennik.api.v2
import pl.szczodrzynski.edziennik.App.APP_URL
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.api.v2.models.Data
import pl.szczodrzynski.edziennik.data.api.AppError.CODE_APP_SERVER_ERROR
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
import pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_HOMEWORK
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_SHARED_EVENT
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_SHARED_HOMEWORK
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_SERVER_MESSAGE
import pl.szczodrzynski.edziennik.data.db.modules.notification.getNotificationTitle
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
import pl.szczodrzynski.edziennik.getJsonArray
import pl.szczodrzynski.edziennik.getLong
import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.network.ServerRequest
class ServerSync(val data: Data, val onSuccess: () -> Unit) {
companion object {
private const val TAG = "ServerSync"
}
val app = data.app
val profileId = data.profile?.id ?: -1
val profileName = data.profile?.name ?: ""
val profile = data.profile
val loginStore = data.loginStore
private fun getUsernameId(): String {
if (loginStore.data == null) {
return "NO_LOGIN_STORE"
}
if (profile?.studentData == null) {
return "NO_STUDENT_STORE"
}
return when (data.loginStore.type) {
LoginStore.LOGIN_TYPE_MOBIDZIENNIK -> loginStore.getLoginData("serverName", "MOBI_UN") + ":" + loginStore.getLoginData("username", "MOBI_UN") + ":" + profile.getStudentData("studentId", -1)
LoginStore.LOGIN_TYPE_LIBRUS -> profile.getStudentData("schoolName", "LIBRUS_UN") + ":" + profile.getStudentData("accountLogin", "LIBRUS_LOGIN_UN")
LoginStore.LOGIN_TYPE_IUCZNIOWIE -> loginStore.getLoginData("schoolName", "IUCZNIOWIE_UN") + ":" + loginStore.getLoginData("username", "IUCZNIOWIE_UN") + ":" + profile.getStudentData("registerId", -1)
LoginStore.LOGIN_TYPE_VULCAN -> profile.getStudentData("schoolName", "VULCAN_UN") + ":" + profile.getStudentData("studentId", -1)
LoginStore.LOGIN_TYPE_DEMO -> loginStore.getLoginData("serverName", "DEMO_UN") + ":" + loginStore.getLoginData("username", "DEMO_UN") + ":" + profile.getStudentData("studentId", -1)
else -> "TYPE_UNKNOWN"
}
}
init { run {
if (profile?.registration != Profile.REGISTRATION_ENABLED) {
onSuccess()
return@run
}
val request = ServerRequest(
app,
app.requestScheme+APP_URL+"main.php?sync",
"Edziennik2/REG",
profile,
data.loginStore.type,
getUsernameId()
)
if (profile.empty) {
request.setBodyParameter("first_run", "true")
}
var hasNotifications = true
if (app.appConfig.webPushEnabled) {
data.notifications
.filterNot { it.posted }
.let {
if (it.isEmpty()) {
hasNotifications = false
null
}
else
it
}?.forEachIndexed { index, notification ->
if (notification.type != TYPE_NEW_SHARED_EVENT
&& notification.type != TYPE_SERVER_MESSAGE
&& notification.type != TYPE_NEW_SHARED_HOMEWORK) {
request.setBodyParameter("notify[$index][type]", notification.type.toString())
request.setBodyParameter("notify[$index][title]", notification.title)
request.setBodyParameter("notify[$index][text]", notification.text)
}
}
}
if ((!app.appConfig.webPushEnabled || !hasNotifications) && !profile.enableSharedEvents) {
onSuccess()
return@run
}
val result = request.runSync()
if (result == null) {
data.error(ApiError(TAG, CODE_APP_SERVER_ERROR)
.setCritical(false))
onSuccess()
return@run
}
var apiResponse = result.toString()
if (result.getString("success") != "true") {
data.error(ApiError(TAG, CODE_APP_SERVER_ERROR)
.setCritical(false))
onSuccess()
return@run
}
// HERE PROCESS ALL THE RECEIVED EVENTS
// add them to the profile and create appropriate notifications
result.getJsonArray("events")?.forEach { jEventEl ->
val event = jEventEl.asJsonObject
val teamCode = event.getString("team")
// get the target Team from teamCode
val team = app.db.teamDao().getByCodeNow(profile.id, teamCode)
if (team != null) {
// create the event from Json. Add the missing teamId and !!profileId!!
val eventObject = app.gson.fromJson(event.toString(), Event::class.java)
// proguard. disable for Event.class
if (eventObject.eventDate == null) {
apiResponse += "\n\nEventDate == null\n$event"
}
eventObject.profileId = profileId
eventObject.teamId = team.id
eventObject.addedManually = true
if (eventObject.sharedBy == getUsernameId()) {
eventObject.sharedBy = "self"
eventObject.sharedByName = profile.studentNameLong
}
val typeObject = app.db.eventTypeDao().getByIdNow(profileId, eventObject.type)
app.db.eventDao().add(eventObject)
val metadata = Metadata(
profileId,
if (eventObject.type == TYPE_HOMEWORK) Metadata.TYPE_HOMEWORK else Metadata.TYPE_EVENT,
eventObject.id,
profile.empty,
true,
event.getLong("addedDate") ?: 0
)
val metadataId = app.db.metadataDao().add(metadata)
// notify if the event is new and not first sync
if (metadataId != -1L && !profile.empty) {
val text = app.getString(
R.string.notification_shared_event_format,
eventObject.sharedByName,
if (typeObject != null) typeObject.name else "wydarzenie",
if (eventObject.eventDate == null) "???" else eventObject.eventDate.formattedString,
eventObject.topic
)
val type = if (eventObject.type == TYPE_HOMEWORK) TYPE_NEW_SHARED_HOMEWORK else TYPE_NEW_SHARED_EVENT
data.notifications += Notification(
title = app.getNotificationTitle(type),
text = text,
type = type,
profileId = profileId,
profileName = profileName,
viewId = if (eventObject.type == TYPE_HOMEWORK) DRAWER_ITEM_HOMEWORK else DRAWER_ITEM_AGENDA,
addedDate = metadata.addedDate
).addExtra("eventId", eventObject.id).addExtra("eventDate", eventObject.eventDate.value.toLong())
}
}
}
onSuccess()
}}
}

View File

@ -1,98 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2019-11-25
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.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.edziennik.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_HOMEWORK
import pl.szczodrzynski.edziennik.api.v2.edziennik.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 subjectName = homework.getString("przed") ?: return@forEach
val subjectId = data.getSubject(subjectName, null, subjectName).id
val teacherName = homework.getString("usr") ?: return@forEach
val teacherId = data.getTeacherByLastFirst(teacherName).id
val lessonList = data.db.timetableDao().getForDateNow(profileId, eventDate)
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.displayStartTime
val topic = homework.getString("tytul") ?: ""
val 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()
}
}
}

View File

@ -1,192 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2019-11-22
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.web
import androidx.core.util.set
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_TIMETABLE
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_TIMETABLE
import pl.szczodrzynski.edziennik.api.v2.edziennik.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.lessons.LessonRange
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 IdziennikWebTimetable(override val data: DataIdziennik,
val onSuccess: () -> Unit) : IdziennikWeb(data) {
companion object {
private const val TAG = "IdziennikWebTimetable"
}
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)
webApiGet(TAG, IDZIENNIK_WEB_TIMETABLE, mapOf(
"idPozDziennika" to data.registerId,
"pidRokSzkolny" to data.schoolYearId,
"data" to "${weekStart.stringY_m_d}T10:00:00.000Z"
)) { result ->
val json = result.getJsonObject("d") ?: run {
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
.withApiResponse(result))
return@webApiGet
}
json.getJsonArray("GodzinyLekcyjne")?.asJsonObjectList()?.forEach { range ->
val lessonRange = LessonRange(
profileId,
range.getInt("LiczbaP") ?: return@forEach,
range.getString("Poczatek")?.let { Time.fromH_m(it) } ?: return@forEach,
range.getString("Koniec")?.let { Time.fromH_m(it) } ?: return@forEach
)
data.lessonRanges[lessonRange.lessonNumber] = lessonRange
}
val dates = mutableSetOf<Int>()
val lessons = mutableListOf<Lesson>()
json.getJsonArray("Przedmioty")?.asJsonObjectList()?.forEach { lesson ->
val subject = data.getSubject(
lesson.getString("Nazwa") ?: return@forEach,
lesson.getLong("Id"),
lesson.getString("Skrot") ?: ""
)
val teacher = data.getTeacherByFDotLast(lesson.getString("Nauczyciel")
?: return@forEach)
val newSubjectName = lesson.getString("PrzedmiotZastepujacy")
val newSubject = when (newSubjectName.isNullOrBlank()) {
true -> null
else -> data.getSubject(newSubjectName, null, newSubjectName)
}
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 lessonObject = Lesson(profileId, -1)
when (type) {
1, 2, 3, 4, 5 -> {
lessonObject.apply {
this.type = Lesson.TYPE_CHANGE
this.date = lessonDate
this.lessonNumber = lessonRange.lessonNumber
this.startTime = lessonRange.startTime
this.endTime = lessonRange.endTime
this.subjectId = newSubject?.id
this.teacherId = newTeacher?.id
this.teamId = data.teamClass?.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
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(
profileId,
Metadata.TYPE_LESSON_CHANGE,
lessonObject.id,
seen,
seen,
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)
onSuccess()
}
}}
}

View File

@ -1,219 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus
import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusData
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.messages.LibrusMessagesGetAttachment
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.messages.LibrusMessagesGetMessage
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.synergia.LibrusSynergiaMarkAllAnnouncementsAsRead
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.firstlogin.LibrusFirstLogin
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.login.*
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
import pl.szczodrzynski.edziennik.utils.Utils.d
class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
companion object {
private const val TAG = "Librus"
}
val internalErrorList = mutableListOf<Int>()
val data: DataLibrus
init {
data = DataLibrus(app, profile, loginStore).apply {
callback = wrapCallback(this@Librus.callback)
satisfyLoginMethods()
}
}
private fun completed() {
data.saveData()
data.notify {
callback.onCompleted()
}
}
/* _______ _ _ _ _ _
|__ __| | /\ | | (_) | | |
| | | |__ ___ / \ | | __ _ ___ _ __ _| |_| |__ _ __ ___
| | | '_ \ / _ \ / /\ \ | |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \
| | | | | | __/ / ____ \| | (_| | (_) | | | | |_| | | | | | | | |
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
__/ |
|__*/
override fun sync(featureIds: List<Int>, viewId: Int?, arguments: JsonObject?) {
data.arguments = arguments
data.prepare(librusLoginMethods, LibrusFeatures, featureIds, viewId)
login()
}
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) {
data()
}
}
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 markAllAnnouncementsAsRead() {
LibrusLoginPortal(data) {
LibrusLoginApi(data) {
LibrusLoginSynergia(data) {
LibrusSynergiaMarkAllAnnouncementsAsRead(data) {
completed()
}
}
}
}
}
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
LibrusLoginPortal(data) {
LibrusLoginApi(data) {
LibrusLoginSynergia(data) {
LibrusLoginMessages(data) {
LibrusMessagesGetAttachment(data, message, attachmentId, attachmentName) {
completed()
}
}
}
}
}
}
override fun firstLogin() {
LibrusFirstLogin(data) {
completed()
}
}
override fun cancel() {
d(TAG, "Cancelled")
data.cancel()
}
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
return object : EdziennikCallback {
override fun onCompleted() {
callback.onCompleted()
}
override fun onProgress(step: Float) {
callback.onProgress(step)
}
override fun onStartProgress(stringRes: Int) {
callback.onStartProgress(stringRes)
}
override fun onError(apiError: ApiError) {
if (apiError.errorCode in internalErrorList) {
// finish immediately if the same error occurs twice during the same sync
callback.onError(apiError)
return
}
internalErrorList.add(apiError.errorCode)
when (apiError.errorCode) {
ERROR_LIBRUS_PORTAL_ACCESS_DENIED -> {
data.loginMethods.remove(LOGIN_METHOD_LIBRUS_PORTAL)
data.targetLoginMethodIds.add(LOGIN_METHOD_LIBRUS_PORTAL)
data.targetLoginMethodIds.sort()
data.portalTokenExpiryTime = 0
login()
}
ERROR_LIBRUS_API_ACCESS_DENIED,
ERROR_LIBRUS_API_TOKEN_EXPIRED -> {
data.loginMethods.remove(LOGIN_METHOD_LIBRUS_API)
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)
}
}
}
}
}

View File

@ -1,229 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2019-10-24
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data
import com.google.gson.JsonObject
import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response
import im.wangchao.mhttp.body.MediaTypeUtils
import im.wangchao.mhttp.callback.FileCallbackHandler
import im.wangchao.mhttp.callback.JsonCallbackHandler
import im.wangchao.mhttp.callback.TextCallbackHandler
import okhttp3.Cookie
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.parser.Parser
import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
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) {
companion object {
private const val TAG = "LibrusMessages"
}
val profileId
get() = data.profile?.id ?: -1
val profile
get() = data.profile
fun messagesGet(tag: String, endpoint: String, method: Int = POST,
parameters: Map<String, Any>? = null, onSuccess: (doc: Document) -> Unit) {
d(tag, "Request: Librus/Messages - $LIBRUS_MESSAGES_URL/$endpoint")
val callback = object : TextCallbackHandler() {
override fun onSuccess(text: String?, response: Response?) {
if (text.isNullOrEmpty()) {
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
.withResponse(response))
return
}
when {
text.contains("<message>Niepoprawny login i/lub hasło.</message>") -> data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN, response, text)
text.contains("stop.png") -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
text.contains("eAccessDeny") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
text.contains("OffLine") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_MAINTENANCE, response, text)
text.contains("<status>error</status>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ERROR, response, text)
text.contains("<type>eVarWhitThisNameNotExists</type>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
text.contains("<error>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
}
try {
val doc = Jsoup.parse(text, "", Parser.xmlParser())
onSuccess(doc)
} catch (e: Exception) {
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
.withResponse(response)
.withThrowable(e)
.withApiResponse(text))
}
}
override fun onFailure(response: Response?, throwable: Throwable?) {
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable))
}
}
data.app.cookieJar.saveFromResponse(null, listOf(
Cookie.Builder()
.name("DZIENNIKSID")
.value(data.messagesSessionId!!)
.domain("wiadomosci.librus.pl")
.secure().httpOnly().build()
))
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" { }
"data" {
for ((key, value) in parameters.orEmpty()) {
key {
-value.toString()
}
}
}
}.toString(PrintOptions(
singleLineTextElements = true,
useSelfClosingTags = true
))*/
Request.builder()
.url("$LIBRUS_MESSAGES_URL/$endpoint")
.userAgent(SYNERGIA_USER_AGENT)
.setTextBody(requestXml, MediaTypeUtils.APPLICATION_XML)
.apply {
when (method) {
GET -> get()
POST -> post()
}
}
.callback(callback)
.build()
.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_FILE_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_FILE_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()
}
}

View File

@ -1,46 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2019-12-3
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api
import android.graphics.Color
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
class LibrusApiBehaviourGradeCategories(override val data: DataLibrus,
val onSuccess: () -> Unit) : LibrusApi(data) {
companion object {
const val TAG = "LibrusApiBehaviourGradeCategories"
}
init {
apiGet(TAG, "BehaviourGrades/Points/Categories") { json ->
json.getJsonArray("Categories")?.asJsonObjectList()?.forEach { category ->
val id = category.getLong("Id") ?: return@forEach
val name = category.getString("Name") ?: ""
val valueFrom = category.getFloat("ValueFrom") ?: 0f
val valueTo = category.getFloat("ValueTo") ?: 0f
val gradeCategoryObject = GradeCategory(
profileId,
id,
-1f,
Color.BLUE,
name
).apply {
type = GradeCategory.TYPE_BEHAVIOUR
setValueRange(valueFrom, valueTo)
}
data.gradeCategories.put(id, gradeCategoryObject)
}
data.setSyncNext(ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES, 1 * WEEK)
onSuccess()
}
}
}

View File

@ -1,44 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2019-12-7
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_COMMENTS
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
class LibrusApiBehaviourGradeComments(override val data: DataLibrus,
val onSuccess: () -> Unit) : LibrusApi(data) {
companion object {
const val TAG = "LibrusApiBehaviourGradeComments"
}
init {
apiGet(TAG, "BehaviourGrades/Points/Comments") { json ->
json.getJsonArray("Comments")?.asJsonObjectList()?.forEach { comment ->
val id = comment.getLong("Id") ?: return@forEach
val text = comment.getString("Text")?.fixWhiteSpaces() ?: return@forEach
val gradeCategoryObject = GradeCategory(
profileId,
id,
-1f,
-1,
text
).apply {
type = GradeCategory.TYPE_BEHAVIOUR_COMMENT
}
data.gradeCategories.put(id, gradeCategoryObject)
}
data.setSyncNext(ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_COMMENTS, SYNC_ALWAYS)
onSuccess()
}
}
}

View File

@ -1,150 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2019-12-3
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi
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.GradeCategory
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
import pl.szczodrzynski.edziennik.utils.models.Date
import java.text.DecimalFormat
class LibrusApiBehaviourGrades(override val data: DataLibrus,
val onSuccess: () -> Unit) : LibrusApi(data) {
companion object {
const val TAG = "LibrusApiBehaviourGrades"
}
private val nameFormat by lazy { DecimalFormat("#.##") }
init { data.profile?.let { profile ->
apiGet(TAG, "BehaviourGrades/Points") { json ->
val semester1StartGradeObject = Grade(
profileId,
-101,
data.app.getString(R.string.grade_start_points),
0xffbdbdbd.toInt(),
data.app.getString(R.string.grade_start_points_format, 1),
nameFormat.format(data.startPointsSemester1),
data.startPointsSemester1.toFloat(),
-1f,
1,
-1,
1
).apply { type = Grade.TYPE_BEHAVIOUR }
data.gradeList.add(semester1StartGradeObject)
data.metadataList.add(Metadata(
profileId,
Metadata.TYPE_GRADE,
semester1StartGradeObject.id,
true,
true,
profile.getSemesterStart(1).inMillis
))
val semester2StartGradeObject = Grade(
profileId,
-102,
data.app.getString(R.string.grade_start_points),
0xffbdbdbd.toInt(),
data.app.getString(R.string.grade_start_points_format, 2),
nameFormat.format(data.startPointsSemester2),
data.startPointsSemester2.toFloat(),
-1f,
2,
-1,
1
).apply { type = Grade.TYPE_BEHAVIOUR }
data.gradeList.add(semester2StartGradeObject)
data.metadataList.add(Metadata(
profileId,
Metadata.TYPE_GRADE,
semester2StartGradeObject.id,
true,
true,
profile.getSemesterStart(2).inMillis
))
json.getJsonArray("Grades")?.asJsonObjectList()?.forEach { grade ->
val id = grade.getLong("Id") ?: return@forEach
val value = grade.getFloat("Value")
val shortName = grade.getString("ShortName")
val semester = grade.getInt("Semester") ?: profile.currentSemester
val teacherId = grade.getJsonObject("AddedBy")?.getLong("Id") ?: -1
val addedDate = grade.getString("AddDate")?.let { Date.fromIso(it) }
?: System.currentTimeMillis()
val name = when {
value != null -> (if (value >= 0) "+" else "") + nameFormat.format(value)
shortName != null -> shortName
else -> return@forEach
}
val color = data.getColor(when {
value == null || value == 0f -> 12
value > 0 -> 16
value < 0 -> 26
else -> 12
})
val categoryId = grade.getJsonObject("Category")?.getLong("Id") ?: -1
val category = data.gradeCategories.singleOrNull {
it.categoryId == categoryId && it.type == GradeCategory.TYPE_BEHAVIOUR
}
val categoryName = category?.text ?: ""
val description = grade.getJsonArray("Comments")?.asJsonObjectList()?.let { comments ->
if (comments.isNotEmpty()) {
data.gradeCategories.singleOrNull {
it.type == GradeCategory.TYPE_BEHAVIOUR_COMMENT
&& it.categoryId == comments[0].asJsonObject.getLong("Id")
}?.text
} else null
} ?: ""
val valueFrom = value ?: category?.valueFrom ?: 0f
val valueTo = category?.valueTo ?: 0f
val gradeObject = Grade(
profileId,
id,
categoryName,
color,
description,
name,
valueFrom,
-1f,
semester,
teacherId,
1
).apply {
type = Grade.TYPE_BEHAVIOUR
valueMax = valueTo
}
data.gradeList.add(gradeObject)
data.metadataList.add(Metadata(
profileId,
Metadata.TYPE_GRADE,
id,
profile.empty,
profile.empty,
addedDate
))
}
data.setSyncNext(ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES, SYNC_ALWAYS)
onSuccess()
}
}}
}

View File

@ -1,48 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2019-11-5
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api
import android.graphics.Color
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADE_CATEGORIES
import pl.szczodrzynski.edziennik.api.v2.edziennik.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")?.fixWhiteSpaces() ?: ""
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_GRADE_CATEGORIES, SYNC_ALWAYS)
onSuccess()
}
}
}

View File

@ -1,44 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2019-11-20
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
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")?.fixWhiteSpaces() ?: return@forEach
val gradeCategoryObject = GradeCategory(
profileId,
id,
-1f,
-1,
text
).apply {
type = GradeCategory.TYPE_NORMAL_COMMENT
}
data.gradeCategories.put(id, gradeCategoryObject)
}
data.setSyncNext(ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS, SYNC_ALWAYS)
onSuccess()
}
}
}

View File

@ -1,203 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-10.
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api
import androidx.core.util.isEmpty
import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_TIMETABLES
import pl.szczodrzynski.edziennik.api.v2.edziennik.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)
}}
}

View File

@ -1,123 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2019-11-24
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.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.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusMessages
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.models.ApiError
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
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 message: Message, 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 message.id,
"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()))
}
}
}
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,
message.id,
attachmentId,
TYPE_FINISHED,
file.absolutePath
)
val attachmentDataFile = File(Utils.getStorageDir(), ".${profileId}_${event.messageId}_${event.attachmentId}")
Utils.writeStringToFile(attachmentDataFile, event.fileName)
EventBus.getDefault().post(event)
onSuccess()
}) { written, _ ->
val event = AttachmentGetEvent(
profileId,
message.id,
attachmentId,
TYPE_PROGRESS,
bytesWritten = written
)
EventBus.getDefault().post(event)
}
}
}

View File

@ -1,132 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2019-11-11
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.messages
import android.util.Base64
import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusMessages
import pl.szczodrzynski.edziennik.api.v2.events.MessageGetEvent
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()}
}

View File

@ -1,163 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-9-20.
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.login
import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response
import im.wangchao.mhttp.body.MediaTypeUtils
import im.wangchao.mhttp.callback.TextCallbackHandler
import okhttp3.Cookie
import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.getUnixDate
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) {
companion object {
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 {
if (data.profile == null) {
data.error(ApiError(TAG, ERROR_PROFILE_MISSING))
return@run
}
if (data.isMessagesLoginValid()) {
data.app.cookieJar.saveFromResponse(null, listOf(
Cookie.Builder()
.name("DZIENNIKSID")
.value(data.messagesSessionId!!)
.domain("wiadomosci.librus.pl")
.secure().httpOnly().build()
))
onSuccess()
}
else {
data.app.cookieJar.clearForDomain("wiadomosci.librus.pl")
if (data.loginMethods.contains(LOGIN_METHOD_LIBRUS_SYNERGIA)) {
loginWithSynergia()
}
else if (data.apiLogin != null && data.apiPassword != null) {
loginWithCredentials()
}
else {
data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
}
}
}}
/**
* XML (Flash messages website) login method. Uses a Synergia login and password.
*/
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()
}
/**
* A login method using the Synergia website (/wiadomosci2 Auto Login).
*/
private fun loginWithSynergia(url: String = "https://synergia.librus.pl/wiadomosci2") {
d(TAG, "Request: Librus/Login/Messages - $url")
Request.builder()
.url(url)
.userAgent(SYNERGIA_USER_AGENT)
.get()
.callback(callback)
.withClient(data.app.httpLazy)
.build()
.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 */
}
}

View File

@ -1,60 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-28.
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.mobidziennik.data.web
import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.api.v2.edziennik.mobidziennik.DataMobidziennik
import pl.szczodrzynski.edziennik.api.v2.edziennik.mobidziennik.data.MobidziennikWeb
import pl.szczodrzynski.edziennik.api.v2.events.AttachmentGetEvent
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
import pl.szczodrzynski.edziennik.utils.Utils
import java.io.File
class MobidziennikWebGetAttachment(
override val data: DataMobidziennik, val message: Message, val attachmentId: Long,
val attachmentName: String, val onSuccess: () -> Unit) : MobidziennikWeb(data) {
companion object {
private const val TAG = "MobidziennikWebGetAttachment"
}
init {
val targetFile = File(Utils.getStorageDir(), attachmentName)
val typeUrl = if (message.type == Message.TYPE_SENT)
"wiadwyslana"
else
"wiadodebrana"
webGetFile(TAG, "/dziennik/$typeUrl/?id=${message.id}&zalacznik=$attachmentId", targetFile, { file ->
val event = AttachmentGetEvent(
profileId,
message.id,
attachmentId,
AttachmentGetEvent.TYPE_FINISHED,
file.absolutePath
)
val attachmentDataFile = File(Utils.getStorageDir(), ".${profileId}_${event.messageId}_${event.attachmentId}")
Utils.writeStringToFile(attachmentDataFile, event.fileName)
EventBus.getDefault().post(event)
onSuccess()
}) { written, _ ->
// TODO make use of bytesTotal
val event = AttachmentGetEvent(
profileId,
message.id,
attachmentId,
AttachmentGetEvent.TYPE_PROGRESS,
bytesWritten = written
)
EventBus.getDefault().post(event)
}
}
}

View File

@ -1,157 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-18.
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.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.edziennik.mobidziennik.DataMobidziennik
import pl.szczodrzynski.edziennik.api.v2.edziennik.mobidziennik.data.MobidziennikWeb
import pl.szczodrzynski.edziennik.api.v2.events.MessageGetEvent
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() ?: -1f
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()
}
}
}

View File

@ -1,61 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2019-11-12
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.vulcan.data.api
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_MESSAGES_CHANGE_STATUS
import pl.szczodrzynski.edziennik.api.v2.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.api.v2.edziennik.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()
}
}
}
}

View File

@ -1,105 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2019-11-01
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.vulcan.data.api
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_MESSAGES_RECEIVED
import pl.szczodrzynski.edziennik.api.v2.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.api.v2.edziennik.vulcan.ENDPOINT_VULCAN_API_MESSAGES_INBOX
import pl.szczodrzynski.edziennik.api.v2.edziennik.vulcan.data.VulcanApi
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.TYPE_RECEIVED
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 VulcanApiMessagesInbox(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
companion object {
const val TAG = "VulcanApiMessagesInbox"
}
init {
data.profile?.also { profile ->
val startDate: String = when (profile.empty) {
true -> profile.getSemesterStart(profile.currentSemester).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 ?: {
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()
}
}

View File

@ -1,115 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2019-11-5
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.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.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.api.v2.edziennik.vulcan.ENDPOINT_VULCAN_API_MESSAGES_SENT
import pl.szczodrzynski.edziennik.api.v2.edziennik.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()
}
}
}
}

View File

@ -1,24 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2019-10-20
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.vulcan.data.api
import pl.szczodrzynski.edziennik.api.v2.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.api.v2.edziennik.vulcan.data.VulcanApi
class VulcanApiTemplate(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
companion object {
const val TAG = "VulcanApi"
}
init {
/* data.profile?.also { profile ->
apiGet(TAG, VULCAN_API_ENDPOINT_) { json, _ ->
data.setSyncNext(ENDPOINT_VULCAN_API_, SYNC_ALWAYS)
onSuccess()
}
} */
}
}

View File

@ -1,213 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2019-11-13
*/
package pl.szczodrzynski.edziennik.api.v2.edziennik.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.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.api.v2.edziennik.vulcan.ENDPOINT_VULCAN_API_TIMETABLE
import pl.szczodrzynski.edziennik.api.v2.edziennik.vulcan.data.VulcanApi
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.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()
}
}}
}

View File

@ -1,14 +0,0 @@
/*
* 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
}
}

View File

@ -1,9 +0,0 @@
/*
* 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)

View File

@ -1,19 +1,16 @@
package pl.szczodrzynski.edziennik.api.v2.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.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.Idziennik import pl.szczodrzynski.edziennik.api.v2.idziennik.Idziennik
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.Librus
import pl.szczodrzynski.edziennik.api.v2.edziennik.mobidziennik.Mobidziennik
import pl.szczodrzynski.edziennik.api.v2.edziennik.template.Template
import pl.szczodrzynski.edziennik.api.v2.edziennik.vulcan.Vulcan
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.Librus
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.Mobidziennik
import pl.szczodrzynski.edziennik.api.v2.template.Template
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.Message
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 {
@ -21,11 +18,10 @@ 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, arguments: JsonObject? = null) = EdziennikTask(profileId, SyncProfileRequest(viewIds, arguments)) fun syncProfile(profileId: Int, viewIds: List<Pair<Int, Int>>? = null) = EdziennikTask(profileId, SyncProfileRequest(viewIds))
fun syncProfileList(profileList: List<Int>) = EdziennikTask(-1, SyncProfileListRequest(profileList)) fun syncProfileList(profileList: List<Int>) = EdziennikTask(-1, SyncProfileListRequest(profileList))
fun messageGet(profileId: Int, message: MessageFull) = EdziennikTask(profileId, MessageGetRequest(message)) fun messageGet(profileId: Int, messageId: Int) = EdziennikTask(profileId, MessageGetRequest(messageId))
fun announcementsRead(profileId: Int) = EdziennikTask(profileId, AnnouncementsReadRequest()) fun announcementsRead(profileId: Int) = EdziennikTask(profileId, AnnouncementsReadRequest())
fun attachmentGet(profileId: Int, message: Message, attachmentId: Long, attachmentName: String) = EdziennikTask(profileId, AttachmentGetRequest(message, attachmentId, attachmentName))
} }
private lateinit var loginStore: LoginStore private lateinit var loginStore: LoginStore
@ -37,11 +33,12 @@ 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().getFullByIdNow(profileId) val profile = app.db.profileDao().getByIdNow(profileId)
this.profile = profile this.profile = profile
if (profile == null) { if (profile == null || !profile.syncEnabled) {
return return
} }
val loginStore = app.db.loginStoreDao().getByIdNow(profile.loginStoreId) ?: return val loginStore = app.db.loginStoreDao().getByIdNow(profile.loginStoreId) ?: return
@ -53,7 +50,7 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
private var edziennikInterface: EdziennikInterface? = null private var edziennikInterface: EdziennikInterface? = null
internal fun run(app: App, taskCallback: EdziennikCallback) { 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)
@ -68,14 +65,11 @@ 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) } featureIds = request.viewIds?.flatMap { Features.getIdsByView(it.first, it.second) } ?: Features.getAllIds(),
?: Features.getAllIds(), viewId = request.viewIds?.get(0)?.first)
viewId = request.viewIds?.get(0)?.first, is MessageGetRequest -> edziennikInterface?.getMessage(request.messageId)
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.message, request.attachmentId, request.attachmentName)
} }
} }
@ -89,9 +83,8 @@ 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, val arguments: JsonObject? = null) data class SyncProfileRequest(val viewIds: List<Pair<Int, Int>>? = null)
data class SyncProfileListRequest(val profileList: List<Int>) data class SyncProfileListRequest(val profileList: List<Int>)
data class MessageGetRequest(val message: MessageFull) data class MessageGetRequest(val messageId: Int)
class AnnouncementsReadRequest class AnnouncementsReadRequest
data class AttachmentGetRequest(val message: Message, val attachmentId: Long, val attachmentName: String) }
}

View File

@ -2,7 +2,7 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-1. * Copyright (c) Kuba Szczodrzyński 2019-10-1.
*/ */
package pl.szczodrzynski.edziennik.api.v2.task package pl.szczodrzynski.edziennik.api.v2.events.task
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
@ -31,4 +31,4 @@ class ErrorReportTask : IApiTask(-1) {
} }
} }

View File

@ -2,20 +2,18 @@
* Copyright (c) Kuba Szczodrzyński 2019-9-28. * Copyright (c) Kuba Szczodrzyński 2019-9-28.
*/ */
package pl.szczodrzynski.edziennik.api.v2.task 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
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
abstract class IApiTask(open val profileId: Int) { abstract class IApiTask(open val profileId: Int) {
var taskId: Int = 0 var taskId: Int = 0
var profile: ProfileFull? = null var profile: Profile? = null
var taskName: String? = null var taskName: String? = null
/** /**
@ -27,16 +25,11 @@ abstract class IApiTask(open val profileId: Int) {
abstract fun cancel() abstract fun cancel()
fun enqueue(context: Context) { fun enqueue(context: Context) {
Intent(context, ApiService::class.java).let { context.startService(Intent(context, ApiService::class.java))
if (SDK_INT >= O)
context.startForegroundService(it)
else
context.startService(it)
}
EventBus.getDefault().postSticky(this) EventBus.getDefault().postSticky(this)
} }
override fun toString(): String { override fun toString(): String {
return "IApiTask(profileId=$profileId, taskId=$taskId, profile=$profile, taskName=$taskName)" return "IApiTask(profileId=$profileId, taskId=$taskId, profile=$profile, taskName=$taskName)"
} }
} }

View File

@ -1,4 +1,4 @@
package pl.szczodrzynski.edziennik.api.v2.task package pl.szczodrzynski.edziennik.api.v2.events.task
import android.app.PendingIntent import android.app.PendingIntent
import android.content.Intent import android.content.Intent
@ -9,7 +9,6 @@ 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
@ -34,9 +33,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.profileName) .setContentTitle(notification.title)
.setContentText(notification.text) .setContentText(notification.text)
.setSubText(app.getNotificationTitle(notification.type)) .setSubText(Notification.stringType(app, 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
@ -87,4 +86,4 @@ class NotifyTask : IApiTask(-1) {
taskCallback.onCompleted() taskCallback.onCompleted()
} }
} }

View File

@ -2,7 +2,7 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-25. * Copyright (c) Kuba Szczodrzyński 2019-10-25.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik package pl.szczodrzynski.edziennik.api.v2.idziennik
import androidx.core.util.set import androidx.core.util.set
import okhttp3.Cookie import okhttp3.Cookie
@ -138,12 +138,10 @@ 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])

View File

@ -2,22 +2,19 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-25. * Copyright (c) Kuba Szczodrzyński 2019-10-25.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.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.edziennik.idziennik.data.IdziennikData import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikData
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.firstlogin.IdziennikFirstLogin import pl.szczodrzynski.edziennik.api.v2.idziennik.firstlogin.IdziennikFirstLogin
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.login.IdziennikLogin import pl.szczodrzynski.edziennik.api.v2.idziennik.login.IdziennikLogin
import pl.szczodrzynski.edziennik.api.v2.idziennikLoginMethods import pl.szczodrzynski.edziennik.api.v2.idziennikLoginMethods
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.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.Message
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
@ -38,7 +35,7 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
private fun completed() { private fun completed() {
data.saveData() data.saveData()
data.notify { data.notifyAndSyncEvents {
callback.onCompleted() callback.onCompleted()
} }
} }
@ -51,8 +48,7 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_| |_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
__/ | __/ |
|__*/ |__*/
override fun sync(featureIds: List<Int>, viewId: Int?, arguments: JsonObject?) { override fun sync(featureIds: List<Int>, viewId: Int?) {
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}")
@ -63,7 +59,7 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
} }
} }
override fun getMessage(message: MessageFull) { override fun getMessage(messageId: Int) {
} }
@ -71,10 +67,6 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
} }
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
}
override fun firstLogin() { override fun firstLogin() {
IdziennikFirstLogin(data) { IdziennikFirstLogin(data) {
completed() completed()

View File

@ -2,7 +2,7 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-25. * Copyright (c) Kuba Szczodrzyński 2019-10-25.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik package pl.szczodrzynski.edziennik.api.v2.idziennik
import pl.szczodrzynski.edziennik.api.v2.* import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.models.Feature import pl.szczodrzynski.edziennik.api.v2.models.Feature
@ -11,7 +11,6 @@ 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
@ -35,10 +34,6 @@ 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)),

View File

@ -2,7 +2,7 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-29. * Copyright (c) Kuba Szczodrzyński 2019-10-29.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data package pl.szczodrzynski.edziennik.api.v2.idziennik.data
import com.google.gson.JsonArray import com.google.gson.JsonArray
import com.google.gson.JsonElement import com.google.gson.JsonElement
@ -12,7 +12,7 @@ import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response import im.wangchao.mhttp.Response
import im.wangchao.mhttp.callback.TextCallbackHandler import im.wangchao.mhttp.callback.TextCallbackHandler
import pl.szczodrzynski.edziennik.api.v2.* import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
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.utils.Utils import pl.szczodrzynski.edziennik.utils.Utils

View File

@ -2,14 +2,14 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-25. * Copyright (c) Kuba Szczodrzyński 2019-10-25.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data package pl.szczodrzynski.edziennik.api.v2.idziennik.data
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.* import pl.szczodrzynski.edziennik.api.v2.idziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.api.IdziennikApiCurrentRegister import pl.szczodrzynski.edziennik.api.v2.idziennik.data.api.IdziennikApiCurrentRegister
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.api.IdziennikApiMessagesInbox import pl.szczodrzynski.edziennik.api.v2.idziennik.data.api.IdziennikApiMessagesInbox
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.api.IdziennikApiMessagesSent import pl.szczodrzynski.edziennik.api.v2.idziennik.data.api.IdziennikApiMessagesSent
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.web.* import pl.szczodrzynski.edziennik.api.v2.idziennik.data.web.*
import pl.szczodrzynski.edziennik.utils.Utils import pl.szczodrzynski.edziennik.utils.Utils
class IdziennikData(val data: DataIdziennik, val onSuccess: () -> Unit) { class IdziennikData(val data: DataIdziennik, val onSuccess: () -> Unit) {
@ -41,47 +41,43 @@ 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()
} }

View File

@ -2,7 +2,7 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-25. * Copyright (c) Kuba Szczodrzyński 2019-10-25.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data package pl.szczodrzynski.edziennik.api.v2.idziennik.data
import com.google.gson.JsonArray import com.google.gson.JsonArray
import com.google.gson.JsonObject import com.google.gson.JsonObject
@ -11,7 +11,7 @@ import im.wangchao.mhttp.Response
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.api.v2.* import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.api.v2.models.ApiError import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
import java.net.HttpURLConnection.HTTP_INTERNAL_ERROR import java.net.HttpURLConnection.HTTP_INTERNAL_ERROR
@ -94,7 +94,6 @@ 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)

View File

@ -2,14 +2,14 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-29. * Copyright (c) Kuba Szczodrzyński 2019-10-29.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.api package pl.szczodrzynski.edziennik.api.v2.idziennik.data.api
import com.google.gson.JsonObject import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.DAY import pl.szczodrzynski.edziennik.DAY
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_API_CURRENT_REGISTER import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_API_CURRENT_REGISTER
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.IdziennikApi import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikApi
import pl.szczodrzynski.edziennik.data.db.modules.luckynumber.LuckyNumber import pl.szczodrzynski.edziennik.data.db.modules.luckynumber.LuckyNumber
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
import pl.szczodrzynski.edziennik.getInt import pl.szczodrzynski.edziennik.getInt

View File

@ -2,13 +2,13 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-30. * Copyright (c) Kuba Szczodrzyński 2019-10-30.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.api package pl.szczodrzynski.edziennik.api.v2.idziennik.data.api
import com.google.gson.JsonArray import com.google.gson.JsonArray
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_API_MESSAGES_INBOX import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_API_MESSAGES_INBOX
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.IdziennikApi import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikApi
import pl.szczodrzynski.edziennik.asJsonObjectList import pl.szczodrzynski.edziennik.asJsonObjectList
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
@ -75,7 +75,7 @@ class IdziennikApiMessagesInbox(override val data: DataIdziennik,
/*messageId*/ messageId /*messageId*/ messageId
) )
data.messageIgnoreList.add(message) data.messageList.add(message)
data.messageRecipientList.add(messageRecipient) data.messageRecipientList.add(messageRecipient)
data.messageMetadataList.add(Metadata( data.messageMetadataList.add(Metadata(
profileId, profileId,

View File

@ -2,15 +2,15 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-30. * Copyright (c) Kuba Szczodrzyński 2019-10-30.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.api package pl.szczodrzynski.edziennik.api.v2.idziennik.data.api
import com.google.gson.JsonArray import com.google.gson.JsonArray
import pl.szczodrzynski.edziennik.DAY import pl.szczodrzynski.edziennik.DAY
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_API_MESSAGES_SENT import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_API_MESSAGES_SENT
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_SENT import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_SENT
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.IdziennikApi import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikApi
import pl.szczodrzynski.edziennik.asJsonObjectList import pl.szczodrzynski.edziennik.asJsonObjectList
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_SENT import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
@ -74,7 +74,7 @@ class IdziennikApiMessagesSent(override val data: DataIdziennik,
data.messageRecipientIgnoreList.add(messageRecipient) data.messageRecipientIgnoreList.add(messageRecipient)
} }
data.messageIgnoreList.add(message) data.messageList.add(message)
data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true, sentDate)) data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true, sentDate))
} }

View File

@ -2,15 +2,15 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-28. * Copyright (c) Kuba Szczodrzyński 2019-10-28.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.web package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
import com.google.gson.JsonArray import com.google.gson.JsonArray
import com.google.gson.JsonObject import com.google.gson.JsonObject
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_ANNOUNCEMENTS import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_ANNOUNCEMENTS
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS
import pl.szczodrzynski.edziennik.api.v2.edziennik.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.data.db.modules.announcements.Announcement import pl.szczodrzynski.edziennik.data.db.modules.announcements.Announcement
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS

View File

@ -2,13 +2,13 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-28. * Copyright (c) Kuba Szczodrzyński 2019-10-28.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.web package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
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_ATTENDANCE import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_ATTENDANCE
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_ATTENDANCE import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_ATTENDANCE
import pl.szczodrzynski.edziennik.api.v2.edziennik.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.crc16 import pl.szczodrzynski.edziennik.crc16
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS

View File

@ -2,24 +2,24 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-28. * Copyright (c) Kuba Szczodrzyński 2019-10-28.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.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.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_EXAMS import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_EXAMS
import pl.szczodrzynski.edziennik.api.v2.edziennik.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,15 +34,14 @@ class IdziennikWebExams(override val data: DataIdziennik,
} }
private fun getExams() { private fun getExams() {
val param = JsonObject().apply { val param = JsonObject()
addProperty("strona", 1) param.addProperty("strona", 1)
addProperty("iloscNaStrone", "99") param.addProperty("iloscNaStrone", "99")
addProperty("iloscRekordow", -1) param.addProperty("iloscRekordow", -1)
addProperty("kolumnaSort", "ss.Nazwa,sp.Data_sprawdzianu") param.addProperty("kolumnaSort", "ss.Nazwa,sp.Data_sprawdzianu")
addProperty("kierunekSort", 0) param.addProperty("kierunekSort", 0)
addProperty("maxIloscZaznaczonych", 0) param.addProperty("maxIloscZaznaczonych", 0)
addProperty("panelFiltrow", 0) param.addProperty("panelFiltrow", 0)
}
webApiGet(TAG, IDZIENNIK_WEB_EXAMS, mapOf( webApiGet(TAG, IDZIENNIK_WEB_EXAMS, mapOf(
"idP" to data.registerId, "idP" to data.registerId,
@ -56,34 +55,28 @@ class IdziennikWebExams(override val data: DataIdziennik,
return@webApiGet return@webApiGet
} }
json.getJsonArray("ListK")?.asJsonObjectList()?.forEach { exam -> for (jExamEl in json.getAsJsonArray("ListK")) {
val id = exam.getLong("_recordId") ?: return@forEach val jExam = jExamEl.asJsonObject
val examDate = Date.fromY_m_d(exam.getString("data") ?: return@forEach) // jExam
val subjectName = exam.getString("przedmiot") ?: return@forEach val eventId = jExam.get("_recordId").asLong
val subjectId = data.getSubject(subjectName, null, subjectName).id val rSubject = data.getSubject(jExam.get("przedmiot").asString, -1, "")
val teacherName = exam.getString("wpisal") ?: return@forEach val rTeacher = data.getTeacherByLastFirst(jExam.get("wpisal").asString)
val teacherId = data.getTeacherByLastFirst(teacherName).id val examDate = Date.fromY_m_d(jExam.get("data").asString)
val topic = exam.getString("zakres") ?: "" val lessonObject = Lesson.getByWeekDayAndSubject(data.lessonList, examDate.weekDay, rSubject.id)
val examTime = lessonObject?.startTime
val lessonList = data.db.timetableDao().getForDateNow(profileId, examDate)
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime
val eventType = when (exam.getString("rodzaj")) {
"sprawdzian/praca klasowa" -> Event.TYPE_EXAM
else -> Event.TYPE_SHORT_QUIZ
}
val eventType = if (jExam.get("rodzaj").asString == "sprawdzian/praca klasowa") Event.TYPE_EXAM else Event.TYPE_SHORT_QUIZ
val eventObject = Event( val eventObject = Event(
profileId, profileId,
id, eventId,
examDate, examDate,
startTime, examTime,
topic, jExam.get("zakres").asString,
-1, -1,
eventType, eventType,
false, false,
teacherId, rTeacher.id,
subjectId, rSubject.id,
data.teamClass?.id ?: -1 data.teamClass?.id ?: -1
) )
@ -113,11 +106,9 @@ 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()
} }
} }
} }
} }

View File

@ -2,15 +2,15 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-28. * Copyright (c) Kuba Szczodrzyński 2019-10-28.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.web package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
import android.graphics.Color import android.graphics.Color
import pl.szczodrzynski.edziennik.* 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_GRADES import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_GRADES
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_GRADES import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_GRADES
import pl.szczodrzynski.edziennik.api.v2.edziennik.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.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

View File

@ -2,13 +2,13 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-28. * Copyright (c) Kuba Szczodrzyński 2019-10-28.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.web package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
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_NOTICES import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_NOTICES
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_NOTICES import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_NOTICES
import pl.szczodrzynski.edziennik.api.v2.edziennik.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.crc16 import pl.szczodrzynski.edziennik.crc16
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS

View File

@ -2,32 +2,29 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-28. * Copyright (c) Kuba Szczodrzyński 2019-10-28.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.web package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
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_MISSING_GRADES import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_MISSING_GRADES
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES
import pl.szczodrzynski.edziennik.api.v2.edziennik.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.asJsonObjectList
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.Grade.TYPE_SEMESTER1_PROPOSED import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_SEMESTER1_PROPOSED
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_YEAR_PROPOSED import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_YEAR_PROPOSED
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
import pl.szczodrzynski.edziennik.getJsonArray
import pl.szczodrzynski.edziennik.getJsonObject import pl.szczodrzynski.edziennik.getJsonObject
import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.Utils.getWordGradeValue import pl.szczodrzynski.edziennik.utils.Utils.getWordGradeValue
class IdziennikWebProposedGrades(override val data: DataIdziennik, class IdziennikWebProposedGrades(override val data: DataIdziennik,
val onSuccess: () -> Unit) : IdziennikWeb(data) { val onSuccess: () -> Unit) : IdziennikWeb(data) {
companion object { companion object {
private const val TAG = "IdziennikWebProposedGrades" private const val TAG = "IdziennikWebProposedGrades"
} }
init { data.profile?.also { profile -> init {
webApiGet(TAG, IDZIENNIK_WEB_MISSING_GRADES, mapOf( webApiGet(TAG, IDZIENNIK_WEB_MISSING_GRADES, mapOf(
"idPozDziennika" to data.registerId "idPozDziennika" to data.registerId
)) { result -> )) { result ->
@ -37,17 +34,17 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
return@webApiGet return@webApiGet
} }
json.getJsonArray("Przedmioty")?.asJsonObjectList()?.forEach { subject -> val jSubjects = json.getAsJsonArray("Przedmioty")
val subjectName = subject.getString("Przedmiot") ?: return@forEach for (jSubjectEl in jSubjects) {
val subjectObject = data.getSubject(subjectName, null, subjectName) val jSubject = jSubjectEl.getAsJsonObject()
// jSubject
val semester1Proposed = subject.getString("OcenaSem1") ?: "" val rSubject = data.getSubject(jSubject.get("Przedmiot").getAsString(), -1, jSubject.get("Przedmiot").getAsString())
val semester1Proposed = jSubject.get("OcenaSem1").getAsString()
val semester2Proposed = jSubject.get("OcenaSem2").getAsString()
val semester1Value = getWordGradeValue(semester1Proposed) val semester1Value = getWordGradeValue(semester1Proposed)
val semester1Id = subjectObject.id * (-100) - 1
val semester2Proposed = subject.getString("OcenaSem2") ?: ""
val semester2Value = getWordGradeValue(semester2Proposed) val semester2Value = getWordGradeValue(semester2Proposed)
val semester2Id = subjectObject.id * (-100) - 2 val semester1Id = rSubject.id * -100 - 1
val semester2Id = rSubject.id * -100 - 2
if (semester1Proposed != "") { if (semester1Proposed != "") {
val gradeObject = Grade( val gradeObject = Grade(
@ -61,18 +58,17 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
0f, 0f,
1, 1,
-1, -1,
subjectObject.id rSubject.id)
).apply {
type = TYPE_SEMESTER1_PROPOSED gradeObject.type = TYPE_SEMESTER1_PROPOSED
}
data.gradeList.add(gradeObject) data.gradeList.add(gradeObject)
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
gradeObject.id, gradeObject.id,
profile.empty, profile?.empty ?: false,
profile.empty, profile?.empty ?: false,
System.currentTimeMillis() System.currentTimeMillis()
)) ))
} }
@ -89,18 +85,17 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
0f, 0f,
2, 2,
-1, -1,
subjectObject.id rSubject.id)
).apply {
type = TYPE_YEAR_PROPOSED gradeObject.type = TYPE_YEAR_PROPOSED
}
data.gradeList.add(gradeObject) data.gradeList.add(gradeObject)
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
gradeObject.id, gradeObject.id,
profile.empty, profile?.empty ?: false,
profile.empty, profile?.empty ?: false,
System.currentTimeMillis() System.currentTimeMillis()
)) ))
} }
@ -109,5 +104,5 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES, SYNC_ALWAYS) data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES, SYNC_ALWAYS)
onSuccess() onSuccess()
} }
}} }
} }

View File

@ -0,0 +1,128 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-10-27.
*/
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
import androidx.core.util.set
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_TIMETABLE
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.data.IdziennikWeb
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
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.metadata.Metadata
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time
import pl.szczodrzynski.edziennik.utils.models.Week
class IdziennikWebTimetable(override val data: DataIdziennik,
val onSuccess: () -> Unit) : IdziennikWeb(data) {
companion object {
private const val TAG = "IdziennikWebTimetable"
}
init {
val weekStart = Week.getWeekStart()
if (Date.getToday().weekDay > 4) {
weekStart.stepForward(0, 0, 7)
}
webApiGet(TAG, IDZIENNIK_WEB_TIMETABLE, mapOf(
"idPozDziennika" to data.registerId,
"pidRokSzkolny" to data.schoolYearId,
"data" to weekStart.stringY_m_d+"T10:00:00.000Z"
)) { result ->
val json = result.getJsonObject("d") ?: run {
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
.withApiResponse(result))
return@webApiGet
}
json.getJsonArray("GodzinyLekcyjne")?.asJsonObjectList()?.forEach { range ->
val lessonRange = LessonRange(
profileId,
range.getInt("LiczbaP") ?: return@forEach,
range.getString("Poczatek")?.let { Time.fromH_m(it) } ?: return@forEach,
range.getString("Koniec")?.let { Time.fromH_m(it) } ?: return@forEach
)
data.lessonRanges[lessonRange.lessonNumber] = lessonRange
}
json.getJsonArray("Przedmioty")?.asJsonObjectList()?.forEach { lesson ->
val subject = data.getSubject(
lesson.getString("Nazwa") ?: return@forEach,
lesson.getLong("Id"),
lesson.getString("Skrot") ?: ""
)
val teacher = data.getTeacherByFDotLast(lesson.getString("Nauczyciel") ?: return@forEach)
val weekDay = lesson.getInt("DzienTygodnia")?.minus(1) ?: return@forEach
val lessonRange = data.lessonRanges[lesson.getInt("Godzina")?.plus(1) ?: return@forEach]
val lessonObject = Lesson(
profileId,
weekDay,
lessonRange.startTime,
lessonRange.endTime
).apply {
subjectId = subject.id
teacherId = teacher.id
teamId = data.teamClass?.id ?: -1
classroomName = lesson.getString("NazwaSali") ?: ""
}
data.lessonList.add(lessonObject)
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
lessonChangeObject.teacherId = lessonObject.teacherId
lessonChangeObject.subjectId = lessonObject.subjectId
lessonChangeObject.classroomName = lessonObject.classroomName
when (type) {
0 -> lessonChangeObject.type = TYPE_CANCELLED
1, 2, 3, 4, 5 -> {
lessonChangeObject.type = TYPE_CHANGE
val newTeacher = lesson.getString("NauZastepujacy")
val newSubject = lesson.getString("PrzedmiotZastepujacy")
if (newTeacher != null) {
lessonChangeObject.teacherId = data.getTeacherByFDotLast(newTeacher).id
}
if (newSubject != null) {
lessonChangeObject.subjectId = data.getSubject(newSubject, null, "").id
}
}
}
data.lessonChangeList.add(lessonChangeObject)
data.metadataList.add(Metadata(
profileId,
Metadata.TYPE_LESSON_CHANGE,
lessonChangeObject.id,
profile?.empty ?: false,
profile?.empty ?: false,
System.currentTimeMillis()
))
}
}
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
onSuccess()
}
}
}

View File

@ -2,16 +2,16 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-27. * Copyright (c) Kuba Szczodrzyński 2019-10-27.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.firstlogin package pl.szczodrzynski.edziennik.api.v2.idziennik.firstlogin
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.api.v2.ERROR_LOGIN_IDZIENNIK_FIRST_NO_SCHOOL_YEAR import pl.szczodrzynski.edziennik.api.v2.ERROR_LOGIN_IDZIENNIK_FIRST_NO_SCHOOL_YEAR
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_SETTINGS import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_SETTINGS
import pl.szczodrzynski.edziennik.api.v2.Regexes import pl.szczodrzynski.edziennik.api.v2.Regexes
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.data.IdziennikWeb
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.login.IdziennikLoginWeb
import pl.szczodrzynski.edziennik.api.v2.events.FirstLoginFinishedEvent import pl.szczodrzynski.edziennik.api.v2.events.FirstLoginFinishedEvent
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
import pl.szczodrzynski.edziennik.api.v2.idziennik.login.IdziennikLoginWeb
import pl.szczodrzynski.edziennik.api.v2.models.ApiError import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
import pl.szczodrzynski.edziennik.fixName import pl.szczodrzynski.edziennik.fixName

View File

@ -2,12 +2,12 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-25. * Copyright (c) Kuba Szczodrzyński 2019-10-25.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.login package pl.szczodrzynski.edziennik.api.v2.idziennik.login
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_IDZIENNIK_API import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_IDZIENNIK_API
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_IDZIENNIK_WEB import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_IDZIENNIK_WEB
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.utils.Utils import pl.szczodrzynski.edziennik.utils.Utils
class IdziennikLogin(val data: DataIdziennik, val onSuccess: () -> Unit) { class IdziennikLogin(val data: DataIdziennik, val onSuccess: () -> Unit) {

View File

@ -2,9 +2,9 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-27. * Copyright (c) Kuba Szczodrzyński 2019-10-27.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.login package pl.szczodrzynski.edziennik.api.v2.idziennik.login
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
class IdziennikLoginApi(val data: DataIdziennik, val onSuccess: () -> Unit) { class IdziennikLoginApi(val data: DataIdziennik, val onSuccess: () -> Unit) {
companion object { companion object {

View File

@ -2,7 +2,7 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-26. * Copyright (c) Kuba Szczodrzyński 2019-10-26.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.login package pl.szczodrzynski.edziennik.api.v2.idziennik.login
import im.wangchao.mhttp.Request import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response import im.wangchao.mhttp.Response
@ -11,7 +11,7 @@ import okhttp3.Cookie
import pl.szczodrzynski.edziennik.HOUR import pl.szczodrzynski.edziennik.HOUR
import pl.szczodrzynski.edziennik.MINUTE import pl.szczodrzynski.edziennik.MINUTE
import pl.szczodrzynski.edziennik.api.v2.* import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
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.get
import pl.szczodrzynski.edziennik.getUnixDate import pl.szczodrzynski.edziennik.getUnixDate

View File

@ -4,15 +4,10 @@
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.Message
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
interface EdziennikInterface { interface EdziennikInterface {
fun sync(featureIds: List<Int>, viewId: Int? = null, arguments: JsonObject? = null) fun sync(featureIds: List<Int>, viewId: Int? = null)
fun getMessage(message: MessageFull) fun getMessage(messageId: Int)
fun markAllAnnouncementsAsRead() fun markAllAnnouncementsAsRead()
fun getAttachment(message: Message, attachmentId: Long, attachmentName: String)
fun firstLogin() fun firstLogin()
fun cancel() fun cancel()
} }

View File

@ -2,7 +2,7 @@
* Copyright (c) Kuba Szczodrzyński 2019-9-21. * Copyright (c) Kuba Szczodrzyński 2019-9-21.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus package pl.szczodrzynski.edziennik.api.v2.librus
import okhttp3.Cookie import okhttp3.Cookie
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
@ -148,16 +148,16 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
*/ */
private var mApiCode: String? = null private var mApiCode: String? = null
var apiCode: String? var apiCode: String?
get() { mApiCode = mApiCode ?: loginStore.getLoginData("accountCode", null); return mApiCode } get() { mApiCode = mApiCode ?: profile?.getStudentData("accountCode", null); return mApiCode }
set(value) { loginStore.putLoginData("accountCode", value) ?: return; mApiCode = value } set(value) { profile?.putStudentData("accountCode", value) ?: return; mApiCode = value }
/** /**
* A JST login PIN. * A JST login PIN.
* Used only during first login in JST mode. * Used only during first login in JST mode.
*/ */
private var mApiPin: String? = null private var mApiPin: String? = null
var apiPin: String? var apiPin: String?
get() { mApiPin = mApiPin ?: loginStore.getLoginData("accountPin", null); return mApiPin } get() { mApiPin = mApiPin ?: profile?.getStudentData("accountPin", null); return mApiPin }
set(value) { loginStore.putLoginData("accountPin", value) ?: return; mApiPin = value } set(value) { profile?.putStudentData("accountPin", value) ?: return; mApiPin = value }
/** /**
* A Synergia API access token. * A Synergia API access token.
@ -168,7 +168,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiAccessToken: String? = null private var mApiAccessToken: String? = null
var apiAccessToken: String? var apiAccessToken: String?
get() { mApiAccessToken = mApiAccessToken ?: profile?.getStudentData("accountToken", null); return mApiAccessToken } get() { mApiAccessToken = mApiAccessToken ?: profile?.getStudentData("accountToken", null); return mApiAccessToken }
set(value) { mApiAccessToken = value; profile?.putStudentData("accountToken", value) ?: return; } set(value) { profile?.putStudentData("accountToken", value) ?: return; mApiAccessToken = value }
/** /**
* A Synergia API refresh token. * A Synergia API refresh token.
* Used when refreshing the [apiAccessToken] in JST, Synergia modes. * Used when refreshing the [apiAccessToken] in JST, Synergia modes.
@ -176,7 +176,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiRefreshToken: String? = null private var mApiRefreshToken: String? = null
var apiRefreshToken: String? var apiRefreshToken: String?
get() { mApiRefreshToken = mApiRefreshToken ?: profile?.getStudentData("accountRefreshToken", null); return mApiRefreshToken } get() { mApiRefreshToken = mApiRefreshToken ?: profile?.getStudentData("accountRefreshToken", null); return mApiRefreshToken }
set(value) { mApiRefreshToken = value; profile?.putStudentData("accountRefreshToken", value) ?: return; } set(value) { profile?.putStudentData("accountRefreshToken", value) ?: return; mApiRefreshToken = value }
/** /**
* The expiry time for [apiAccessToken], as a UNIX timestamp. * The expiry time for [apiAccessToken], as a UNIX timestamp.
* Used when refreshing the [apiAccessToken] in JST, Synergia modes. * Used when refreshing the [apiAccessToken] in JST, Synergia modes.
@ -185,7 +185,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiTokenExpiryTime: Long? = null private var mApiTokenExpiryTime: Long? = null
var apiTokenExpiryTime: Long var apiTokenExpiryTime: Long
get() { mApiTokenExpiryTime = mApiTokenExpiryTime ?: profile?.getStudentData("accountTokenTime", 0L); return mApiTokenExpiryTime ?: 0L } get() { mApiTokenExpiryTime = mApiTokenExpiryTime ?: profile?.getStudentData("accountTokenTime", 0L); return mApiTokenExpiryTime ?: 0L }
set(value) { mApiTokenExpiryTime = value; profile?.putStudentData("accountTokenTime", value) ?: return; } set(value) { profile?.putStudentData("accountTokenTime", value) ?: return; mApiTokenExpiryTime = value }
/* _____ _ /* _____ _
/ ____| (_) / ____| (_)
@ -269,4 +269,4 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
var enableDescriptiveGrades: Boolean var enableDescriptiveGrades: Boolean
get() { mEnableDescriptiveGrades = mEnableDescriptiveGrades ?: profile?.getStudentData("enableDescriptiveGrades", true); return mEnableDescriptiveGrades ?: true } get() { mEnableDescriptiveGrades = mEnableDescriptiveGrades ?: profile?.getStudentData("enableDescriptiveGrades", true); return mEnableDescriptiveGrades ?: true }
set(value) { profile?.putStudentData("enableDescriptiveGrades", value) ?: return; mEnableDescriptiveGrades = value } set(value) { profile?.putStudentData("enableDescriptiveGrades", value) ?: return; mEnableDescriptiveGrades = value }
} }

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
*/
package pl.szczodrzynski.edziennik.api.v2.librus
import pl.szczodrzynski.edziennik.App
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.EdziennikInterface
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusData
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.login.LibrusLogin
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.prepare
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
import pl.szczodrzynski.edziennik.utils.Utils.d
class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
companion object {
private const val TAG = "Librus"
}
val internalErrorList = mutableListOf<Int>()
val data: DataLibrus
init {
data = DataLibrus(app, profile, loginStore).apply {
callback = wrapCallback(this@Librus.callback)
satisfyLoginMethods()
}
}
private fun completed() {
data.saveData()
data.notifyAndSyncEvents {
callback.onCompleted()
}
}
/* _______ _ _ _ _ _
|__ __| | /\ | | (_) | | |
| | | |__ ___ / \ | | __ _ ___ _ __ _| |_| |__ _ __ ___
| | | '_ \ / _ \ / /\ \ | |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \
| | | | | | __/ / ____ \| | (_| | (_) | | | | |_| | | | | | | | |
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
__/ |
|__*/
override fun sync(featureIds: List<Int>, viewId: Int?) {
data.prepare(librusLoginMethods, LibrusFeatures, featureIds, viewId)
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
LibrusLogin(data) {
LibrusData(data) {
completed()
}
}
}
override fun getMessage(messageId: Int) {
}
override fun markAllAnnouncementsAsRead() {
LibrusLoginApi(data) {
LibrusLoginSynergia(data) {
LibrusSynergiaMarkAllAnnouncementsAsRead(data) {
completed()
}
}
}
}
override fun firstLogin() {
LibrusFirstLogin(data) {
completed()
}
}
override fun cancel() {
d(TAG, "Cancelled")
data.cancel()
}
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
return object : EdziennikCallback {
override fun onCompleted() {
callback.onCompleted()
}
override fun onProgress(step: Float) {
callback.onProgress(step)
}
override fun onStartProgress(stringRes: Int) {
callback.onStartProgress(stringRes)
}
override fun onError(apiError: ApiError) {
when (apiError.errorCode) {
in internalErrorList -> {
// finish immediately if the same error occurs twice during the same sync
callback.onError(apiError)
}
CODE_INTERNAL_LIBRUS_ACCOUNT_410 -> {
internalErrorList.add(apiError.errorCode)
loginStore.removeLoginData("refreshToken") // force a clean login
//loginLibrus()
}
else -> callback.onError(apiError)
}
}
}
}
}

View File

@ -2,58 +2,56 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-11. * Copyright (c) Kuba Szczodrzyński 2019-10-11.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus package pl.szczodrzynski.edziennik.api.v2.librus
import pl.szczodrzynski.edziennik.api.v2.* import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.models.Feature import pl.szczodrzynski.edziennik.api.v2.models.Feature
const val ENDPOINT_LIBRUS_API_ME = 1001 const val ENDPOINT_LIBRUS_API_ME = 1001
const val ENDPOINT_LIBRUS_API_SCHOOLS = 1002 const val ENDPOINT_LIBRUS_API_SCHOOLS = 1002
const val ENDPOINT_LIBRUS_API_CLASSES = 1003 const val ENDPOINT_LIBRUS_API_CLASSES = 1003
const val ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES = 1004 const val ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES = 1004
const val ENDPOINT_LIBRUS_API_UNITS = 1005 const val ENDPOINT_LIBRUS_API_UNITS = 1005
const val ENDPOINT_LIBRUS_API_USERS = 1006 const val ENDPOINT_LIBRUS_API_USERS = 1006
const val ENDPOINT_LIBRUS_API_SUBJECTS = 1007 const val ENDPOINT_LIBRUS_API_SUBJECTS = 1007
const val ENDPOINT_LIBRUS_API_CLASSROOMS = 1008 const val ENDPOINT_LIBRUS_API_CLASSROOMS = 1008
const val ENDPOINT_LIBRUS_API_PUSH_CONFIG = 1010 const val ENDPOINT_LIBRUS_API_PUSH_CONFIG = 1010
const val ENDPOINT_LIBRUS_API_TIMETABLES = 1015 const val ENDPOINT_LIBRUS_API_TIMETABLES = 1015
const val ENDPOINT_LIBRUS_API_SUBSTITUTIONS = 1016 const val ENDPOINT_LIBRUS_API_SUBSTITUTIONS = 1016
const val ENDPOINT_LIBRUS_API_NORMAL_GRADE_CATEGORIES = 1021 const val ENDPOINT_LIBRUS_API_NORMAL_GC = 1021
const val ENDPOINT_LIBRUS_API_POINT_GRADE_CATEGORIES = 1022 const val ENDPOINT_LIBRUS_API_POINT_GC = 1022
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADE_CATEGORIES = 1023 const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_GC = 1023
const val ENDPOINT_LIBRUS_API_TEXT_GRADE_CATEGORIES = 1024 const val ENDPOINT_LIBRUS_API_TEXT_GC = 1024
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADE_CATEGORIES = 1025 const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GC = 1025
const val ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES = 1026 const val ENDPOINT_LIBRUS_API_BEHAVIOUR_GC = 1026
const val ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_COMMENTS = 1027 const val ENDPOINT_LIBRUS_API_NORMAL_GRADES = 1031
const val ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS = 1030 const val ENDPOINT_LIBRUS_API_POINT_GRADES = 1032
const val ENDPOINT_LIBRUS_API_NORMAL_GRADES = 1031 const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES = 1033
const val ENDPOINT_LIBRUS_API_POINT_GRADES = 1032 const val ENDPOINT_LIBRUS_API_TEXT_GRADES = 1034
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES = 1033 const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADES = 1035
const val ENDPOINT_LIBRUS_API_TEXT_GRADES = 1034 const val ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES = 1036
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADES = 1035 const val ENDPOINT_LIBRUS_API_EVENT_TYPES = 1040
const val ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES = 1036 const val ENDPOINT_LIBRUS_API_EVENTS = 1041
const val ENDPOINT_LIBRUS_API_EVENT_TYPES = 1040 const val ENDPOINT_LIBRUS_API_HOMEWORK = 1050
const val ENDPOINT_LIBRUS_API_EVENTS = 1041 const val ENDPOINT_LIBRUS_API_LUCKY_NUMBER = 1060
const val ENDPOINT_LIBRUS_API_HOMEWORK = 1050 const val ENDPOINT_LIBRUS_API_NOTICE_TYPES = 1070
const val ENDPOINT_LIBRUS_API_LUCKY_NUMBER = 1060 const val ENDPOINT_LIBRUS_API_NOTICES = 1071
const val ENDPOINT_LIBRUS_API_NOTICE_TYPES = 1070 const val ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES = 1080
const val ENDPOINT_LIBRUS_API_NOTICES = 1071 const val ENDPOINT_LIBRUS_API_ATTENDANCES = 1081
const val ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES = 1080 const val ENDPOINT_LIBRUS_API_ANNOUNCEMENTS = 1090
const val ENDPOINT_LIBRUS_API_ATTENDANCES = 1081 const val ENDPOINT_LIBRUS_API_PT_MEETINGS = 1100
const val ENDPOINT_LIBRUS_API_ANNOUNCEMENTS = 1090 const val ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES = 1109
const val ENDPOINT_LIBRUS_API_PT_MEETINGS = 1100 const val ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS = 1110
const val ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES = 1109 const val ENDPOINT_LIBRUS_API_SCHOOL_FREE_DAYS = 1120
const val ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS = 1110 const val ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS = 1130
const val ENDPOINT_LIBRUS_API_SCHOOL_FREE_DAYS = 1120 const val ENDPOINT_LIBRUS_SYNERGIA_INFO = 2010
const val ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS = 1130 const val ENDPOINT_LIBRUS_SYNERGIA_GRADES = 2020
const val ENDPOINT_LIBRUS_SYNERGIA_INFO = 2010 const val ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK = 2030
const val ENDPOINT_LIBRUS_SYNERGIA_GRADES = 2020 const val ENDPOINT_LIBRUS_MESSAGES_RECEIVED = 3010
const val ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK = 2030 const val ENDPOINT_LIBRUS_MESSAGES_SENT = 3020
const val ENDPOINT_LIBRUS_MESSAGES_RECEIVED = 3010 const val ENDPOINT_LIBRUS_MESSAGES_TRASH = 3030
const val ENDPOINT_LIBRUS_MESSAGES_SENT = 3020 const val ENDPOINT_LIBRUS_MESSAGES_RECEIVERS = 3040
const val ENDPOINT_LIBRUS_MESSAGES_TRASH = 3030 const val ENDPOINT_LIBRUS_MESSAGES_GET = 3040
const val ENDPOINT_LIBRUS_MESSAGES_RECEIVERS = 3040
const val ENDPOINT_LIBRUS_MESSAGES_GET = 3040
val LibrusFeatures = listOf( val LibrusFeatures = listOf(
@ -61,7 +59,7 @@ val LibrusFeatures = listOf(
Feature(LOGIN_TYPE_LIBRUS, FEATURE_PUSH_CONFIG, listOf( Feature(LOGIN_TYPE_LIBRUS, FEATURE_PUSH_CONFIG, listOf(
ENDPOINT_LIBRUS_API_PUSH_CONFIG to LOGIN_METHOD_LIBRUS_API ENDPOINT_LIBRUS_API_PUSH_CONFIG to LOGIN_METHOD_LIBRUS_API
), listOf(LOGIN_METHOD_LIBRUS_API)).withShouldSync { data -> ), listOf(LOGIN_METHOD_LIBRUS_API)).withShouldSync { data ->
!data.app.config.sync.tokenLibrusList.contains(data.profileId) data.app.appConfig.fcmTokens[LOGIN_TYPE_LIBRUS]?.second?.contains(data.profileId) == false
}, },
@ -93,14 +91,12 @@ val LibrusFeatures = listOf(
* All grades + categories. * All grades + categories.
*/ */
Feature(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf( Feature(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf(
ENDPOINT_LIBRUS_API_NORMAL_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API, ENDPOINT_LIBRUS_API_NORMAL_GC to LOGIN_METHOD_LIBRUS_API,
ENDPOINT_LIBRUS_API_POINT_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API, ENDPOINT_LIBRUS_API_POINT_GC to LOGIN_METHOD_LIBRUS_API,
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API, ENDPOINT_LIBRUS_API_DESCRIPTIVE_GC to LOGIN_METHOD_LIBRUS_API,
ENDPOINT_LIBRUS_API_TEXT_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API, ENDPOINT_LIBRUS_API_TEXT_GC to LOGIN_METHOD_LIBRUS_API,
ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API, ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GC to LOGIN_METHOD_LIBRUS_API,
ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES 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_BEHAVIOUR_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,

View File

@ -2,14 +2,14 @@
* Copyright (c) Kuba Szczodrzyński 2019-9-21. * Copyright (c) Kuba Szczodrzyński 2019-9-21.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data package pl.szczodrzynski.edziennik.api.v2.librus.data
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.JsonCallbackHandler
import pl.szczodrzynski.edziennik.api.v2.* import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.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.getString import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
@ -28,17 +28,10 @@ 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 - ${if (data.fakeLogin) FAKE_LIBRUS_API else LIBRUS_API_URL}/$endpoint") d(tag, "Request: Librus/Api - $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))
@ -97,7 +90,7 @@ open class LibrusApi(open val data: DataLibrus) {
} }
Request.builder() Request.builder()
.url("${if (data.fakeLogin) FAKE_LIBRUS_API else LIBRUS_API_URL}/$endpoint") .url("$LIBRUS_API_URL/$endpoint")
.userAgent(LIBRUS_USER_AGENT) .userAgent(LIBRUS_USER_AGENT)
.addHeader("Authorization", "Bearer ${data.apiAccessToken}") .addHeader("Authorization", "Bearer ${data.apiAccessToken}")
.apply { .apply {
@ -111,9 +104,8 @@ 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()
} }
} }

View File

@ -2,14 +2,14 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-5. * Copyright (c) Kuba Szczodrzyński 2019-10-5.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data package pl.szczodrzynski.edziennik.api.v2.librus.data
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.* import pl.szczodrzynski.edziennik.api.v2.librus.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api.* import pl.szczodrzynski.edziennik.api.v2.librus.data.api.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.messages.LibrusMessagesGetList import pl.szczodrzynski.edziennik.api.v2.librus.data.messages.LibrusMessagesGetList
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.synergia.LibrusSynergiaHomework import pl.szczodrzynski.edziennik.api.v2.librus.data.synergia.LibrusSynergiaHomework
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.synergia.LibrusSynergiaInfo import pl.szczodrzynski.edziennik.api.v2.librus.data.synergia.LibrusSynergiaInfo
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
import pl.szczodrzynski.edziennik.utils.Utils import pl.szczodrzynski.edziennik.utils.Utils
@ -45,115 +45,92 @@ 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
ENDPOINT_LIBRUS_API_TIMETABLES -> { // TODO timetable
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
LibrusApiTimetables(data, onSuccess)
}
ENDPOINT_LIBRUS_API_NORMAL_GRADE_CATEGORIES -> {
data.startProgress(R.string.edziennik_progress_endpoint_grade_categories)
LibrusApiGradeCategories(data, onSuccess)
}
ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES -> {
data.startProgress(R.string.edziennik_progress_endpoint_grade_categories)
LibrusApiBehaviourGradeCategories(data, onSuccess)
}
ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS -> {
data.startProgress(R.string.edziennik_progress_endpoint_grade_comments)
LibrusApiGradeComments(data, onSuccess)
}
ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_COMMENTS -> {
data.startProgress(R.string.edziennik_progress_endpoint_grade_comments)
LibrusApiBehaviourGradeComments(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_BEHAVIOUR_GRADES -> {
data.startProgress(R.string.edziennik_progress_endpoint_behaviour_grades)
LibrusApiBehaviourGrades(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() }
} }
/** /**
@ -161,11 +138,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() }
} }
/** /**
@ -173,11 +150,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 = onSuccess) LibrusMessagesGetList(data, type = Message.TYPE_RECEIVED) { 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 = onSuccess) LibrusMessagesGetList(data, type = Message.TYPE_SENT) { onSuccess() }
} }
else -> onSuccess() else -> onSuccess()

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2019-10-24
*/
package pl.szczodrzynski.edziennik.api.v2.librus.data
import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response
import im.wangchao.mhttp.body.MediaTypeUtils
import im.wangchao.mhttp.callback.TextCallbackHandler
import okhttp3.Cookie
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
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.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.get
import pl.szczodrzynski.edziennik.utils.Utils.d
open class LibrusMessages(open val data: DataLibrus) {
companion object {
private const val TAG = "LibrusMessages"
}
val profileId
get() = data.profile?.id ?: -1
val profile
get() = data.profile
fun messagesGet(tag: String, endpoint: String, method: Int = POST,
parameters: Map<String, Any>? = null, onSuccess: (doc: Document) -> Unit) {
d(tag, "Request: Librus/Messages - $LIBRUS_MESSAGES_URL/$endpoint")
val callback = object : TextCallbackHandler() {
override fun onSuccess(text: String?, response: Response?) {
if (text.isNullOrEmpty()) {
data.error(ApiError(LibrusSynergia.TAG, ERROR_RESPONSE_EMPTY)
.withResponse(response))
return
}
// TODO: Finish error handling
if ("error" in text) {
when ("<type>(.*)</type>".toRegex().find(text)?.get(1)) {
"eAccessDeny" -> data.error(ApiError(tag, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED)
.withResponse(response)
.withApiResponse(text))
}
}
try {
val doc = Jsoup.parse(text, "", Parser.xmlParser())
onSuccess(doc)
} catch (e: Exception) {
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
.withResponse(response)
.withThrowable(e)
.withApiResponse(text))
}
}
override fun onFailure(response: Response?, throwable: Throwable?) {
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable))
}
}
data.app.cookieJar.saveFromResponse(null, listOf(
Cookie.Builder()
.name("DZIENNIKSID")
.value(data.messagesSessionId!!)
.domain("wiadomosci.librus.pl")
.secure().httpOnly().build()
))
val requestXml = xml("service") {
"header" { }
"data" {
for ((key, value) in parameters.orEmpty()) {
key {
-value.toString()
}
}
}
}.toString(PrintOptions(
singleLineTextElements = true,
useSelfClosingTags = true
))
Request.builder()
.url("$LIBRUS_MESSAGES_URL/$endpoint")
.userAgent(SYNERGIA_USER_AGENT)
.setTextBody(requestXml, MediaTypeUtils.APPLICATION_XML)
.apply {
when (method) {
GET -> get()
POST -> post()
}
}
.callback(callback)
.build()
.enqueue()
}
}

View File

@ -1,11 +1,11 @@
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data package pl.szczodrzynski.edziennik.api.v2.librus.data
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.JsonCallbackHandler
import pl.szczodrzynski.edziennik.api.v2.* import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.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.getString import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
@ -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 - ${if (data.fakeLogin) FAKE_LIBRUS_PORTAL else LIBRUS_PORTAL_URL}$endpoint") d(tag, "Request: Librus/Portal - $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,10 +44,7 @@ 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 -> when (json.getString("hint")) { else -> ERROR_LIBRUS_PORTAL_OTHER
"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)
@ -81,7 +78,7 @@ open class LibrusPortal(open val data: DataLibrus) {
} }
Request.builder() Request.builder()
.url((if (data.fakeLogin) FAKE_LIBRUS_PORTAL else LIBRUS_PORTAL_URL) + endpoint) .url(LIBRUS_PORTAL_URL + endpoint)
.userAgent(LIBRUS_USER_AGENT) .userAgent(LIBRUS_USER_AGENT)
.addHeader("Authorization", "Bearer ${data.portalAccessToken}") .addHeader("Authorization", "Bearer ${data.portalAccessToken}")
.apply { .apply {
@ -101,4 +98,4 @@ open class LibrusPortal(open val data: DataLibrus) {
.build() .build()
.enqueue() .enqueue()
} }
} }

View File

@ -2,19 +2,19 @@
* Copyright (c) Kacper Ziubryniewicz 2019-10-21. * Copyright (c) Kacper Ziubryniewicz 2019-10-21.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data package pl.szczodrzynski.edziennik.api.v2.librus.data
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.TextCallbackHandler import im.wangchao.mhttp.callback.TextCallbackHandler
import pl.szczodrzynski.edziennik.api.v2.* import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.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.d 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 {
private const val TAG = "LibrusSynergia" const val TAG = "LibrusSynergia"
} }
val profileId val profileId

View File

@ -2,15 +2,16 @@
* Copyright (c) Kacper Ziubryniewicz 2019-10-13 * Copyright (c) Kacper Ziubryniewicz 2019-10-13
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_ANNOUNCEMENTS import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_ANNOUNCEMENTS
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.modules.announcements.Announcement import pl.szczodrzynski.edziennik.data.db.modules.announcements.Announcement
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.metadata.Metadata import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
import pl.szczodrzynski.edziennik.utils.Utils
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
class LibrusApiAnnouncements(override val data: DataLibrus, class LibrusApiAnnouncements(override val data: DataLibrus,
@ -19,19 +20,19 @@ class LibrusApiAnnouncements(override val data: DataLibrus,
const val TAG = "LibrusApiAnnouncements" const val TAG = "LibrusApiAnnouncements"
} }
init { data.profile?.also { profile -> init {
apiGet(TAG, "SchoolNotices") { json -> apiGet(TAG, "SchoolNotices") { json ->
val announcements = json.getJsonArray("SchoolNotices").asJsonObjectList() val announcements = json.getJsonArray("SchoolNotices").asJsonObjectList()
announcements?.forEach { announcement -> announcements?.forEach { announcement ->
val id = announcement.getString("Id")?.crc32() ?: return@forEach val id = Utils.crc16(announcement.getString("Id")?.toByteArray()
?: return@forEach).toLong()
val subject = announcement.getString("Subject") ?: "" val subject = announcement.getString("Subject") ?: ""
val text = announcement.getString("Content") ?: "" val text = announcement.getString("Content") ?: ""
val startDate = Date.fromY_m_d(announcement.getString("StartDate")) val startDate = Date.fromY_m_d(announcement.getString("StartDate"))
val endDate = Date.fromY_m_d(announcement.getString("EndDate")) val endDate = Date.fromY_m_d(announcement.getString("EndDate"))
val teacherId = announcement.getJsonObject("AddedBy")?.getLong("Id") ?: -1 val teacherId = announcement.getJsonObject("AddedBy")?.getLong("Id") ?: -1
val addedDate = announcement.getString("CreationDate")?.let { Date.fromIso(it) } val addedDate = Date.fromIso(announcement.getString("CreationDate"))
?: System.currentTimeMillis()
val read = announcement.getBoolean("WasRead") ?: false val read = announcement.getBoolean("WasRead") ?: false
val announcementObject = Announcement( val announcementObject = Announcement(
@ -50,7 +51,7 @@ class LibrusApiAnnouncements(override val data: DataLibrus,
Metadata.TYPE_ANNOUNCEMENT, Metadata.TYPE_ANNOUNCEMENT,
id, id,
read, read,
profile.empty || read, read,
addedDate addedDate
)) ))
} }
@ -58,5 +59,5 @@ class LibrusApiAnnouncements(override val data: DataLibrus,
data.setSyncNext(ENDPOINT_LIBRUS_API_ANNOUNCEMENTS, SYNC_ALWAYS) data.setSyncNext(ENDPOINT_LIBRUS_API_ANNOUNCEMENTS, SYNC_ALWAYS)
onSuccess() onSuccess()
} }
}} }
} }

View File

@ -2,13 +2,13 @@
* Copyright (c) Kacper Ziubryniewicz 2019-10-13 * Copyright (c) Kacper Ziubryniewicz 2019-10-13
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import android.graphics.Color import android.graphics.Color
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.modules.attendance.Attendance import pl.szczodrzynski.edziennik.data.db.modules.attendance.Attendance
import pl.szczodrzynski.edziennik.data.db.modules.attendance.AttendanceType import pl.szczodrzynski.edziennik.data.db.modules.attendance.AttendanceType

View File

@ -2,13 +2,13 @@
* Copyright (c) Kacper Ziubryniewicz 2019-10-13 * Copyright (c) Kacper Ziubryniewicz 2019-10-13
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import androidx.core.util.isEmpty import androidx.core.util.isEmpty
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_ATTENDANCES import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_ATTENDANCES
import pl.szczodrzynski.edziennik.api.v2.edziennik.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.attendance.Attendance import pl.szczodrzynski.edziennik.data.db.modules.attendance.Attendance
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
@ -36,14 +36,14 @@ class LibrusApiAttendances(override val data: DataLibrus,
val lessonNo = attendance.getInt("LessonNo") ?: return@forEach val lessonNo = attendance.getInt("LessonNo") ?: return@forEach
val startTime = data.lessonRanges.get(lessonNo).startTime val startTime = data.lessonRanges.get(lessonNo).startTime
val lessonDate = Date.fromY_m_d(attendance.getString("Date")) val lessonDate = Date.fromY_m_d(attendance.getString("Date"))
val subjectId = data.lessonList.singleOrNull {
it.weekDay == lessonDate.weekDay && it.startTime.value == startTime.value
}?.subjectId ?: -1
val semester = attendance.getInt("Semester") ?: return@forEach val semester = attendance.getInt("Semester") ?: return@forEach
val type = attendance.getJsonObject("Type")?.getLong("Id") ?: return@forEach val type = attendance.getJsonObject("Type")?.getLong("Id") ?: return@forEach
val typeObject = data.attendanceTypes.get(type) val typeObject = data.attendanceTypes.get(type)
val topic = typeObject?.name ?: "" val topic = typeObject?.name ?: ""
val lessonList = data.db.timetableDao().getForDateNow(profileId, lessonDate)
val subjectId = lessonList.firstOrNull { it.startTime == startTime }?.subjectId ?: -1
val attendanceObject = Attendance( val attendanceObject = Attendance(
profileId, profileId,
id, id,

View File

@ -2,12 +2,12 @@
* Copyright (c) Kacper Ziubryniewicz 2019-10-14 * Copyright (c) Kacper Ziubryniewicz 2019-10-14
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import pl.szczodrzynski.edziennik.DAY import pl.szczodrzynski.edziennik.DAY
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_CLASSES import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_CLASSES
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
import pl.szczodrzynski.edziennik.getJsonObject import pl.szczodrzynski.edziennik.getJsonObject
import pl.szczodrzynski.edziennik.getLong import pl.szczodrzynski.edziennik.getLong

View File

@ -2,12 +2,12 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-24. * Copyright (c) Kuba Szczodrzyński 2019-10-24.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_CLASSROOMS import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_CLASSROOMS
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.modules.classrooms.Classroom import pl.szczodrzynski.edziennik.data.db.modules.classrooms.Classroom
import java.util.* import java.util.*

View File

@ -2,12 +2,12 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-24. * Copyright (c) Kuba Szczodrzyński 2019-10-24.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_EVENT_TYPES import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_EVENT_TYPES
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.modules.events.EventType import pl.szczodrzynski.edziennik.data.db.modules.events.EventType
class LibrusApiEventTypes(override val data: DataLibrus, class LibrusApiEventTypes(override val data: DataLibrus,

View File

@ -2,14 +2,13 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-4. * Copyright (c) Kuba Szczodrzyński 2019-10-4.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import androidx.core.util.isEmpty import androidx.core.util.isEmpty
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_EVENTS import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_EVENTS
import pl.szczodrzynski.edziennik.api.v2.edziennik.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
@ -70,8 +69,6 @@ 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()
} }

View File

@ -1,12 +1,11 @@
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADES import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADES
import pl.szczodrzynski.edziennik.api.v2.edziennik.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
@ -43,21 +42,12 @@ 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_NORMAL_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,

View File

@ -2,13 +2,12 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-12. * Copyright (c) Kuba Szczodrzyński 2019-10-12.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_HOMEWORK import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_HOMEWORK
import pl.szczodrzynski.edziennik.api.v2.edziennik.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
@ -56,8 +55,6 @@ 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()
} }

View File

@ -2,12 +2,12 @@
* Copyright (c) Kacper Ziubryniewicz 2019-10-14 * Copyright (c) Kacper Ziubryniewicz 2019-10-14
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import pl.szczodrzynski.edziennik.DAY import pl.szczodrzynski.edziennik.DAY
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_LUCKY_NUMBER import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_LUCKY_NUMBER
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.modules.luckynumber.LuckyNumber import pl.szczodrzynski.edziennik.data.db.modules.luckynumber.LuckyNumber
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
import pl.szczodrzynski.edziennik.getInt import pl.szczodrzynski.edziennik.getInt

View File

@ -2,12 +2,12 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-3. * Copyright (c) Kuba Szczodrzyński 2019-10-3.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_ME import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_ME
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
class LibrusApiMe(override val data: DataLibrus, class LibrusApiMe(override val data: DataLibrus,
val onSuccess: () -> Unit) : LibrusApi(data) { val onSuccess: () -> Unit) : LibrusApi(data) {

View File

@ -2,12 +2,12 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-24. * Copyright (c) Kuba Szczodrzyński 2019-10-24.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_NOTICE_TYPES import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_NOTICE_TYPES
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.modules.notices.NoticeType import pl.szczodrzynski.edziennik.data.db.modules.notices.NoticeType
class LibrusApiNoticeTypes(override val data: DataLibrus, class LibrusApiNoticeTypes(override val data: DataLibrus,

View File

@ -2,13 +2,13 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-24. * Copyright (c) Kuba Szczodrzyński 2019-10-24.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import androidx.core.util.isEmpty import androidx.core.util.isEmpty
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_NOTICES import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_NOTICES
import pl.szczodrzynski.edziennik.api.v2.edziennik.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.metadata.Metadata import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice

View File

@ -2,12 +2,12 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-24. * Copyright (c) Kuba Szczodrzyński 2019-10-24.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_PT_MEETINGS import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_PT_MEETINGS
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
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

View File

@ -2,12 +2,12 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-4. * Copyright (c) Kuba Szczodrzyński 2019-10-4.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_SCHOOLS
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_SCHOOLS import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonRange import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonRange
import pl.szczodrzynski.edziennik.utils.models.Time import pl.szczodrzynski.edziennik.utils.models.Time
import java.util.* import java.util.*

View File

@ -2,12 +2,12 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-23. * Copyright (c) Kuba Szczodrzyński 2019-10-23.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_SUBJECTS import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_SUBJECTS
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject
class LibrusApiSubjects(override val data: DataLibrus, class LibrusApiSubjects(override val data: DataLibrus,

View File

@ -2,12 +2,12 @@
* Copyright (c) Kacper Ziubryniewicz 2019-10-19 * Copyright (c) Kacper Ziubryniewicz 2019-10-19
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.modules.teachers.TeacherAbsenceType import pl.szczodrzynski.edziennik.data.db.modules.teachers.TeacherAbsenceType
class LibrusApiTeacherFreeDayTypes(override val data: DataLibrus, class LibrusApiTeacherFreeDayTypes(override val data: DataLibrus,

View File

@ -2,14 +2,14 @@
* Copyright (c) Kacper Ziubryniewicz 2019-10-4. * Copyright (c) Kacper Ziubryniewicz 2019-10-4.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import androidx.core.util.isEmpty import androidx.core.util.isEmpty
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
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.TeacherAbsence import pl.szczodrzynski.edziennik.data.db.modules.teachers.TeacherAbsence
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date

View File

@ -2,10 +2,11 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-4. * Copyright (c) Kuba Szczodrzyński 2019-10-4.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
class LibrusApiTemplate(override val data: DataLibrus, class LibrusApiTemplate(override val data: DataLibrus,
val onSuccess: () -> Unit) : LibrusApi(data) { val onSuccess: () -> Unit) : LibrusApi(data) {

View File

@ -2,12 +2,12 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-23. * Copyright (c) Kuba Szczodrzyński 2019-10-23.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_UNITS import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_UNITS
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
class LibrusApiUnits(override val data: DataLibrus, class LibrusApiUnits(override val data: DataLibrus,
val onSuccess: () -> Unit) : LibrusApi(data) { val onSuccess: () -> Unit) : LibrusApi(data) {

View File

@ -2,12 +2,12 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-23. * Copyright (c) Kuba Szczodrzyński 2019-10-23.
*/ */
package pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.api package pl.szczodrzynski.edziennik.api.v2.librus.data.api
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.ENDPOINT_LIBRUS_API_USERS import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_USERS
import pl.szczodrzynski.edziennik.api.v2.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
class LibrusApiUsers(override val data: DataLibrus, class LibrusApiUsers(override val data: DataLibrus,
@ -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")?.fixName() ?: "" val firstName = user.getString("FirstName")?.fixWhiteSpaces() ?: ""
val lastName = user.getString("LastName")?.fixName() ?: "" val lastName = user.getString("LastName")?.fixWhiteSpaces() ?: ""
data.teacherList.put(id, Teacher(profileId, id, firstName, lastName)) data.teacherList.put(id, Teacher(profileId, id, firstName, lastName))
} }

Some files were not shown because too many files have changed in this diff Show More