Compare commits

...

37 Commits

Author SHA1 Message Date
65e0e10db6 [4.1] Update build.gradle, signing and changelog. 2020-05-09 15:23:44 +02:00
62e0e53354 [DB] Force attendance sync in models migration. 2020-05-09 10:59:25 +02:00
a5461a488a [UI] Fix attendance type list crash. 2020-05-09 10:53:19 +02:00
192dd0c4c7 [UI] Add listing attendance by type. 2020-05-08 22:19:55 +02:00
c49755c0eb [API/Librus] Fix messages login when ReCaptcha is needed. 2020-05-08 20:46:51 +02:00
c8c758958d [API/Mobidziennik] Fix web attendance without lesson topic. 2020-05-07 15:48:16 +02:00
e068f1944f [UI] Add attendance summary page. Disable presence notifications. 2020-05-05 22:57:24 +02:00
97412a3736 [UI] Add German translation. 2020-05-05 21:46:18 +02:00
9167d53a1a [UI] Add new attendance UI module. 2020-05-04 22:47:27 +02:00
6436a17036 [API] Fix signatures for nightly versions. 2020-05-04 09:28:39 +02:00
5ab5dbe940 [UI] Show nightly version badge in main activity. 2020-05-03 13:11:04 +02:00
d68ab0d010 [Fix] Suppress i18n warning in GradesConfigDialog. 2020-05-02 23:55:20 +02:00
f70a1f5730 [DB] Fix homework added date migration. 2020-05-01 22:03:13 +02:00
85106a01d7 [API/Librus] Add online lesson URL to events description. 2020-04-30 21:41:42 +02:00
90e99e241a [UI/Home] Show textual period grades in grades card. 2020-04-29 15:23:30 +02:00
3f61ab8299 [DB] Refactor database and entities. 2020-04-29 15:14:45 +02:00
13a3f66db3 Merge branch 'api-v2' into develop
# Conflicts:
#	.gitignore
#	app/build.gradle
#	app/src/main/assets/pl-changelog.html
#	app/src/main/java/pl/szczodrzynski/edziennik/App.java
#	app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt
#	app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt
#	app/src/main/java/pl/szczodrzynski/edziennik/data/api/Librus.java
#	app/src/main/java/pl/szczodrzynski/edziennik/data/api/Mobidziennik.java
#	app/src/main/java/pl/szczodrzynski/edziennik/data/api/Vulcan.java
#	app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java
#	app/src/main/java/pl/szczodrzynski/edziennik/utils/models/AppConfig.java
#	app/src/main/res/values-en/strings.xml
#	app/src/main/res/values/strings.xml
#	build.gradle
#	gradle/wrapper/gradle-wrapper.properties
2020-04-20 19:00:53 +02:00
dc9e6081c5 [4.0] Update build.gradle, signing and changelog. 2020-04-19 22:06:19 +02:00
26f8c03570 [UI] Show class name and school year in subname. Fix setting language. 2020-04-19 22:01:29 +02:00
97e0f36f09 [UI] Fix semester grades overlapping when scrolling. 2020-04-19 21:37:39 +02:00
9b13552b73 [API/Mobidziennik] Fix downloading attachments. 2020-04-16 09:45:28 +02:00
d8559637a5 [Strings] Fix HTML tags missing in translations. 2020-04-13 22:43:26 +02:00
00a90a14dc [API] Fix downloading attachments with different name. Handle UTF encoded download names. 2020-04-07 13:57:12 +02:00
d56afb034b [API] Add Vulcan OneDrive attachment downloading. Add asking for permissions on demand. 2020-04-07 12:16:48 +02:00
0327ba37f1 [Strings] Update English translation. 2020-04-07 09:10:38 +02:00
12a54e58b5 [API] Add Vulcan message & homework attachments. Fix Mobidziennik homework attachments. 2020-04-06 22:50:00 +02:00
238250e8c9 [API/Mobidziennik] Fix homework attachment downloading. 2020-04-06 19:28:04 +02:00
3c8afb0609 [3.2.2] Update build.gradle and changelog. Update Librus Client ID and user agent. 2020-02-24 16:55:24 +01:00
27f9b8a04e Update gradle. Add Chucker. 2020-01-10 09:30:02 +01:00
86669a491a Update .gitignore 2020-01-09 21:14:08 +01:00
6a2c863fcc [3.2.1] Update build.gradle and changelog 2019-12-15 19:05:22 +01:00
cf69273de1 [APIv1/Mobidziennik] Add API key. 2019-12-14 14:17:37 +01:00
fa99b7fd11 [3.2] Update build.gradle and changelog 2019-10-31 17:57:41 +01:00
9c5653b52e [Gradle] Fix AgendaCalendarView dependencies. 2019-10-31 17:20:07 +01:00
88ad8523a0 [UI] Disable bottom menu gain attention ripple. 2019-10-31 17:19:25 +01:00
a15f59fbd1 [API/Vulcan] Add edu.lublin.eu register support. 2019-10-31 15:40:59 +01:00
188470a043 [UI/Settings] Add option to change app language. 2019-10-28 16:33:25 +01:00
218 changed files with 7277 additions and 2366 deletions

1
.gitignore vendored
View File

@ -87,3 +87,4 @@ app/schemas/
signatures/ signatures/
app/.cxx app/.cxx
/i18n/

View File

@ -41,5 +41,15 @@
<option name="name" value="MavenRepo" /> <option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" /> <option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository> </remote-repository>
<remote-repository>
<option name="id" value="maven4" />
<option name="name" value="maven4" />
<option name="url" value="https://dl.bintray.com/undervoid/Powerpermission" />
</remote-repository>
<remote-repository>
<option name="id" value="maven4" />
<option name="name" value="maven4" />
<option name="url" value="https://dl.bintray.com/undervoid/PowerPermission" />
</remote-repository>
</component> </component>
</project> </project>

View File

@ -198,6 +198,9 @@ dependencies {
kapt project(":codegen") kapt project(":codegen")
implementation 'com.google.android:flexbox:2.0.1' implementation 'com.google.android:flexbox:2.0.1'
implementation 'com.qifan.powerpermission:powerpermission:1.0.0'
implementation 'com.qifan.powerpermission:powerpermission-coroutines:1.0.0'
} }
repositories { repositories {
mavenCentral() mavenCentral()

View File

@ -14,6 +14,9 @@
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- PowerPermission uses minSdk 21, it's safe to override as it is used only in >= 23 -->
<uses-sdk tools:overrideLibrary="com.qifan.powerpermission.coroutines, com.qifan.powerpermission.core" />
<application <application
android:name=".App" android:name=".App"
android:allowBackup="true" android:allowBackup="true"

View File

@ -1,35 +1,9 @@
<h3>Wersja 4.0-rc.5, 2020-04-05</h3> <h3>Wersja 4.1, 2020-05-09</h3>
<ul> <ul>
<li>Możliwość pobierania załączników do zadań domowych (Librus, MobiDziennik, iDziennik).</li> <li>Naprawiona synchronizacja Wiadomości w Librusie.</li>
<li>Widok pełnej treści zadań domowych (iDziennik, EduDziennik).</li> <li>Widok adresu dołączenia do lekcji online w kalendarzu (jeżeli nauczyciel wpisze adres).</li>
<li>Wyszukiwarka wiadomości, pozwalająca na łatwe znalezienie potrzebnej konwersacji.</li> <li>Nowy moduł Frekwencji, obsługujący również lekcje zdalne.</li>
<li>Możliwość usuwania odebranych wiadomości w aplikacji.</li>
</ul> </ul>
<!--<h3>Wersja 4.0-rc.3, 2020-03-29</h3>
<ul>
<li><b><u>Wysyłanie wiadomości</u></b> - funkcja, na którą czekał każdy. Od teraz w Szkolnym można wysyłać oraz odpowiadać na wiadomości do nauczycieli &#x1F44F;</li>
<li><b>Przebudowaliśmy cały moduł synchronizacji</b>, co oznacza większą stabilność aplikacji, szybkość oraz poprawność pobieranych danych</li>
<li>Udoskonalony wygląd Szkolnego - sprawi, że korzystanie z aplikacji będzie jeszcze przyjemniejsze</li>
<li>Nowa <b>Strona główna</b> - ładniejszy wygląd oraz możliwość przestawiania kart na każdym profilu</li>
<li>Nowy <b>Plan lekcji</b> - z doskonałą obsługą lekcji przesuniętych oraz dwóch lekcji o tej samej godzinie</li>
<li>Nowe <b>Oceny</b> - z możliwością zmiany wartości plusów oraz minusów oraz wyłączenia niektórych ocen ze średniej</li>
<li>Opcja wyłączenia wybranych powiadomień z aplikacji</li>
<li>Znaczki nieprzeczytanych informacji na obrazkach profili.</li>
<br>
<br>
<li>Nowe okienka informacji o wydarzeniach oraz lekcjach</li>
<li>Nowe, przyjemniejsze powiadomienia</li>
<li>Dużo poprawek w widoku <b>Wiadomości</b> oraz <b>Ogłoszeń</b></li>
<li>Częściowa <b>Obsługa dziennika EduDziennik</b></li>
<li>Librus: opcja logowania w dziennikach <b>Jednostek Samorządu Terytorialnego</b> oraz <b>Oświata w Radomiu</b></li>
<li>Librus: <b>poprawione obliczanie frekwencji</b></li>
<li>Librus: obsługa Zadań domowych bez posiadania Mobilnych dodatków (przez system Synergia)</li>
<li>Lepsze <b>przekazywanie powiadomień na komputer</b> oraz łatwiejsze parowanie</li>
<li>Łatwiejsze dodawanie własnych wydarzeń</li>
<li>Poprawiliśmy synchronizację w tle na niektórych telefonach</li>
<li>Usunąłem denerwujący brak zaznaczenia w lewym menu</li>
<li>Znaczna ilość błędów z poprzednich wersji już nie występuje</li>
</ul>-->
<br> <br>
<br> <br>
Dzięki za korzystanie ze Szkolnego!<br> Dzięki za korzystanie ze Szkolnego!<br>

View File

@ -9,7 +9,7 @@
/*secret password - removed for source code publication*/ /*secret password - removed for source code publication*/
static toys AES_IV[16] = { static toys AES_IV[16] = {
0x7b, 0x51, 0x86, 0xc5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 0xec, 0xc0, 0x3e, 0x4e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat); unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);

View File

@ -65,6 +65,8 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
val gradesManager by lazy { GradesManager(this) } val gradesManager by lazy { GradesManager(this) }
val timetableManager by lazy { TimetableManager(this) } val timetableManager by lazy { TimetableManager(this) }
val eventManager by lazy { EventManager(this) } val eventManager by lazy { EventManager(this) }
val permissionManager by lazy { PermissionManager(this) }
val attendanceManager by lazy { AttendanceManager(this) }
val db val db
get() = App.db get() = App.db
@ -166,6 +168,10 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
db.profileDao().firstId?.let { profileLoadById(it) } db.profileDao().firstId?.let { profileLoadById(it) }
} }
config.ui.language?.let {
setLanguage(it)
}
devMode = BuildConfig.DEBUG devMode = BuildConfig.DEBUG
Signing.getCert(this) Signing.getCert(this)

View File

@ -454,7 +454,7 @@ operator fun MatchResult.get(group: Int): String {
return groupValues[group] return groupValues[group]
} }
fun Activity.setLanguage(language: String) { fun Context.setLanguage(language: String) {
val locale = Locale(language.toLowerCase(Locale.ROOT)) val locale = Locale(language.toLowerCase(Locale.ROOT))
val configuration = resources.configuration val configuration = resources.configuration
Locale.setDefault(locale) Locale.setDefault(locale)
@ -463,7 +463,6 @@ fun Activity.setLanguage(language: String) {
} }
configuration.locale = locale configuration.locale = locale
resources.updateConfiguration(configuration, resources.displayMetrics) resources.updateConfiguration(configuration, resources.displayMetrics)
baseContext.resources.updateConfiguration(configuration, baseContext.resources.displayMetrics)
} }
/* /*

View File

@ -18,6 +18,7 @@ import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity 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.core.view.isVisible
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.navigation.NavOptions import androidx.navigation.NavOptions
import com.danimahardhika.cafebar.CafeBar import com.danimahardhika.cafebar.CafeBar
@ -226,8 +227,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
list += NavTarget(TARGET_MESSAGES_DETAILS, R.string.menu_message, MessageFragment::class).withPopTo(DRAWER_ITEM_MESSAGES) list += NavTarget(TARGET_MESSAGES_DETAILS, R.string.menu_message, MessageFragment::class).withPopTo(DRAWER_ITEM_MESSAGES)
list += NavTarget(TARGET_MESSAGES_COMPOSE, R.string.menu_message_compose, MessagesComposeFragment::class) list += NavTarget(TARGET_MESSAGES_COMPOSE, R.string.menu_message_compose, MessagesComposeFragment::class)
list += NavTarget(TARGET_WEB_PUSH, R.string.menu_web_push, WebPushFragment::class) list += NavTarget(TARGET_WEB_PUSH, R.string.menu_web_push, WebPushFragment::class)
if (App.debugMode) {
list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class) list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class)
if (App.devMode) {
list += NavTarget(TARGET_LAB, R.string.menu_lab, LabFragment::class) list += NavTarget(TARGET_LAB, R.string.menu_lab, LabFragment::class)
.withIcon(CommunityMaterial.Icon.cmd_flask_outline) .withIcon(CommunityMaterial.Icon.cmd_flask_outline)
.isInDrawer(true) .isInDrawer(true)
@ -294,6 +295,13 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
mainSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar) mainSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar) errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
if (BuildConfig.VERSION_NAME.contains("nightly")) {
b.nightlyText.isVisible = true
b.nightlyText.text = "Nightly\n"+BuildConfig.VERSION_NAME.substringAfterLast(".")
}
else
b.nightlyText.isVisible = false
navLoading = true navLoading = true
b.navView.apply { b.navView.apply {
@ -414,8 +422,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
R.color.md_green_500 R.color.md_green_500
) )
isStoragePermissionGranted()
SyncWorker.scheduleNext(app) SyncWorker.scheduleNext(app)
UpdateWorker.scheduleNext(app) UpdateWorker.scheduleNext(app)

View File

@ -30,6 +30,7 @@ class ProfileConfig(val db: AppDb, val profileId: Int, rawEntries: List<ConfigEn
val grades by lazy { ProfileConfigGrades(this) } val grades by lazy { ProfileConfigGrades(this) }
val ui by lazy { ProfileConfigUI(this) } val ui by lazy { ProfileConfigUI(this) }
val sync by lazy { ProfileConfigSync(this) } val sync by lazy { ProfileConfigSync(this) }
val attendance by lazy { ProfileConfigAttendance(this) }
/* /*
val timetable by lazy { ConfigTimetable(this) } val timetable by lazy { ConfigTimetable(this) }
val grades by lazy { ConfigGrades(this) }*/ val grades by lazy { ConfigGrades(this) }*/

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-29.
*/
package pl.szczodrzynski.edziennik.config
import pl.szczodrzynski.edziennik.config.utils.get
import pl.szczodrzynski.edziennik.config.utils.set
class ProfileConfigAttendance(private val config: ProfileConfig) {
private var mAttendancePageSelection: Int? = null
var attendancePageSelection: Int
get() { mAttendancePageSelection = mAttendancePageSelection ?: config.values.get("attendancePageSelection", 1); return mAttendancePageSelection ?: 1 }
set(value) { config.set("attendancePageSelection", value); mAttendancePageSelection = value }
private var mUseSymbols: Boolean? = null
var useSymbols: Boolean
get() { mUseSymbols = mUseSymbols ?: config.values.get("useSymbols", false); return mUseSymbols ?: false }
set(value) { config.set("useSymbols", value); mUseSymbols = value }
private var mGroupConsecutiveDays: Boolean? = null
var groupConsecutiveDays: Boolean
get() { mGroupConsecutiveDays = mGroupConsecutiveDays ?: config.values.get("groupConsecutiveDays", true); return mGroupConsecutiveDays ?: true }
set(value) { config.set("groupConsecutiveDays", value); mGroupConsecutiveDays = value }
private var mShowPresenceInMonth: Boolean? = null
var showPresenceInMonth: Boolean
get() { mShowPresenceInMonth = mShowPresenceInMonth ?: config.values.get("showPresenceInMonth", false); return mShowPresenceInMonth ?: false }
set(value) { config.set("showPresenceInMonth", value); mShowPresenceInMonth = value }
}

View File

@ -111,5 +111,7 @@ const val VULCAN_API_ENDPOINT_MESSAGES_SENT = "mobile-api/Uczen.v3.Uczen/Wiadomo
const val VULCAN_API_ENDPOINT_MESSAGES_CHANGE_STATUS = "mobile-api/Uczen.v3.Uczen/ZmienStatusWiadomosci" const val VULCAN_API_ENDPOINT_MESSAGES_CHANGE_STATUS = "mobile-api/Uczen.v3.Uczen/ZmienStatusWiadomosci"
const val VULCAN_API_ENDPOINT_MESSAGES_ADD = "mobile-api/Uczen.v3.Uczen/DodajWiadomosc" const val VULCAN_API_ENDPOINT_MESSAGES_ADD = "mobile-api/Uczen.v3.Uczen/DodajWiadomosc"
const val VULCAN_API_ENDPOINT_PUSH = "mobile-api/Uczen.v3.Uczen/UstawPushToken" const val VULCAN_API_ENDPOINT_PUSH = "mobile-api/Uczen.v3.Uczen/UstawPushToken"
const val VULCAN_API_ENDPOINT_MESSAGES_ATTACHMENTS = "mobile-api/Uczen.v3.Uczen/WiadomosciZalacznik"
const val VULCAN_API_ENDPOINT_HOMEWORK_ATTACHMENTS = "mobile-api/Uczen.v3.Uczen/ZadaniaDomoweZalacznik"
const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}" const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}"

View File

@ -127,6 +127,7 @@ const val ERROR_LIBRUS_API_DEVICE_REGISTERED = 185
const val ERROR_LIBRUS_MESSAGES_NOT_FOUND = 186 const val ERROR_LIBRUS_MESSAGES_NOT_FOUND = 186
const val ERROR_LOGIN_LIBRUS_API_INVALID_REQUEST = 187 const val ERROR_LOGIN_LIBRUS_API_INVALID_REQUEST = 187
const val ERROR_LIBRUS_MESSAGES_ATTACHMENT_NOT_FOUND = 188 const val ERROR_LIBRUS_MESSAGES_ATTACHMENT_NOT_FOUND = 188
const val ERROR_LOGIN_LIBRUS_MESSAGES_TIMEOUT = 189
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
@ -158,6 +159,7 @@ const val ERROR_LOGIN_VULCAN_NO_PUPILS = 331
const val ERROR_VULCAN_API_MAINTENANCE = 340 const val ERROR_VULCAN_API_MAINTENANCE = 340
const val ERROR_VULCAN_API_BAD_REQUEST = 341 const val ERROR_VULCAN_API_BAD_REQUEST = 341
const val ERROR_VULCAN_API_OTHER = 342 const val ERROR_VULCAN_API_OTHER = 342
const val ERROR_VULCAN_ATTACHMENT_DOWNLOAD = 343
const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN = 401 const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN = 401
const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME = 402 const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME = 402
@ -207,5 +209,6 @@ const val EXCEPTION_IDZIENNIK_WEB_API_REQUEST = 913
const val EXCEPTION_IDZIENNIK_API_REQUEST = 914 const val EXCEPTION_IDZIENNIK_API_REQUEST = 914
const val EXCEPTION_EDUDZIENNIK_WEB_REQUEST = 920 const val EXCEPTION_EDUDZIENNIK_WEB_REQUEST = 920
const val EXCEPTION_EDUDZIENNIK_FILE_REQUEST = 921 const val EXCEPTION_EDUDZIENNIK_FILE_REQUEST = 921
const val ERROR_ONEDRIVE_DOWNLOAD = 930
const val LOGIN_NO_ARGUMENTS = 1201 const val LOGIN_NO_ARGUMENTS = 1201

View File

@ -68,6 +68,9 @@ object Regexes {
} }
val MOBIDZIENNIK_ATTENDANCE_TYPES by lazy {
"""Legenda:.+?normal;">(.+?)</span>""".toRegex(DOT_MATCHES_ALL)
}
val MOBIDZIENNIK_ATTENDANCE_TABLE by lazy { val MOBIDZIENNIK_ATTENDANCE_TABLE by lazy {
"""<table .+?id="obecnosci_tabela">(.+?)</table>""".toRegex(DOT_MATCHES_ALL) """<table .+?id="obecnosci_tabela">(.+?)</table>""".toRegex(DOT_MATCHES_ALL)
} }
@ -81,7 +84,7 @@ object Regexes {
"""<span>([0-9:]+) - .+? (.+?)</span></a>""".toRegex(DOT_MATCHES_ALL) """<span>([0-9:]+) - .+? (.+?)</span></a>""".toRegex(DOT_MATCHES_ALL)
} }
val MOBIDZIENNIK_ATTENDANCE_LESSON by lazy { val MOBIDZIENNIK_ATTENDANCE_LESSON by lazy {
"""<strong>(.+?) - (.*?)</strong>.+?<small>.+?\((.+?), .+?(.+?)\)""".toRegex(DOT_MATCHES_ALL) """<strong>(.+?)</strong>\s*<small>\s*\((.+?),\s*(.+?)\)""".toRegex(DOT_MATCHES_ALL)
} }
val MOBIDZIENNIK_HOMEWORK_ROW by lazy { val MOBIDZIENNIK_HOMEWORK_ROW by lazy {
@ -97,7 +100,7 @@ object Regexes {
"""zadanieFormularz\(([0-9]+),""".toRegex(DOT_MATCHES_ALL) """zadanieFormularz\(([0-9]+),""".toRegex(DOT_MATCHES_ALL)
} }
val MOBIDZIENNIK_HOMEWORK_ATTACHMENT by lazy { val MOBIDZIENNIK_HOMEWORK_ATTACHMENT by lazy {
"""zalacznik=([0-9]+)'.+?word-break">(.+?)</td>""".toRegex(DOT_MATCHES_ALL) """zalacznik(_zadania)?=([0-9]+)'.+?word-break">(.+?)</td>""".toRegex(DOT_MATCHES_ALL)
} }

View File

@ -45,24 +45,25 @@ class EdudziennikWebAnnouncements(override val data: DataEdudziennik,
val addedDate = Date.fromIsoHm(dateString) val addedDate = Date.fromIsoHm(dateString)
val announcementObject = Announcement( val announcementObject = Announcement(
profileId, profileId = profileId,
id, id = id,
subject, subject = subject,
null, text = null,
startDate, startDate = startDate,
null, endDate = null,
teacher.id, teacherId = teacher.id,
longId addedDate = addedDate
) ).also {
it.idString = longId
}
data.announcementIgnoreList.add(announcementObject) data.announcementList.add(announcementObject)
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_ANNOUNCEMENT, Metadata.TYPE_ANNOUNCEMENT,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }
} }

View File

@ -39,12 +39,12 @@ class EdudziennikWebAttendance(override val data: DataEdudziennik,
val attendanceTypes = EDUDZIENNIK_ATTENDANCE_TYPES.find(text)?.get(1)?.split(',')?.map { val attendanceTypes = EDUDZIENNIK_ATTENDANCE_TYPES.find(text)?.get(1)?.split(',')?.map {
val type = EDUDZIENNIK_ATTENDANCE_TYPE.find(it.trim()) val type = EDUDZIENNIK_ATTENDANCE_TYPE.find(it.trim())
val symbol = type?.get(1)?.trim() val symbol = type?.get(1)?.trim() ?: "?"
val name = type?.get(2)?.trim() val name = type?.get(2)?.trim() ?: "nieznany rodzaj"
return@map Triple( return@map Triple(
symbol, symbol,
name, name,
when (name?.toLowerCase(Locale.ROOT)) { when (name.toLowerCase(Locale.ROOT)) {
"obecność" -> Attendance.TYPE_PRESENT "obecność" -> Attendance.TYPE_PRESENT
"nieobecność" -> Attendance.TYPE_ABSENT "nieobecność" -> Attendance.TYPE_ABSENT
"spóźnienie" -> Attendance.TYPE_BELATED "spóźnienie" -> Attendance.TYPE_BELATED
@ -52,7 +52,7 @@ class EdudziennikWebAttendance(override val data: DataEdudziennik,
"dzień wolny" -> Attendance.TYPE_DAY_FREE "dzień wolny" -> Attendance.TYPE_DAY_FREE
"brak zajęć" -> Attendance.TYPE_DAY_FREE "brak zajęć" -> Attendance.TYPE_DAY_FREE
"oddelegowany" -> Attendance.TYPE_RELEASED "oddelegowany" -> Attendance.TYPE_RELEASED
else -> Attendance.TYPE_CUSTOM else -> Attendance.TYPE_UNKNOWN
} }
) )
} ?: emptyList() } ?: emptyList()
@ -62,38 +62,42 @@ class EdudziennikWebAttendance(override val data: DataEdudziennik,
val lessonNumber = attendanceElement[2].toInt() val lessonNumber = attendanceElement[2].toInt()
val attendanceSymbol = attendanceElement[3] val attendanceSymbol = attendanceElement[3]
val lessons = data.app.db.timetableDao().getForDateNow(profileId, date) val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
val lesson = lessons.firstOrNull { it.lessonNumber == lessonNumber } val lesson = lessons.firstOrNull { it.lessonNumber == lessonNumber }
val id = "${date.stringY_m_d}:$lessonNumber:$attendanceSymbol".crc32() val id = "${date.stringY_m_d}:$lessonNumber:$attendanceSymbol".crc32()
val (_, name, type) = attendanceTypes.firstOrNull { (symbol, _, _) -> symbol == attendanceSymbol } val (typeSymbol, typeName, baseType) = attendanceTypes.firstOrNull { (symbol, _, _) -> symbol == attendanceSymbol }
?: return@forEach ?: return@forEach
val startTime = data.lessonRanges.singleOrNull { it.lessonNumber == lessonNumber }?.startTime val startTime = data.lessonRanges.singleOrNull { it.lessonNumber == lessonNumber }?.startTime
?: return@forEach ?: return@forEach
val attendanceObject = Attendance( val attendanceObject = Attendance(
profileId, profileId = profileId,
id, id = id,
lesson?.displayTeacherId ?: -1, baseType = baseType,
lesson?.displaySubjectId ?: -1, typeName = typeName,
profile.currentSemester, typeShort = data.app.attendanceManager.getTypeShort(baseType),
name, typeSymbol = typeSymbol,
date, typeColor = null,
lesson?.displayStartTime ?: startTime, date = date,
type startTime = lesson?.displayStartTime ?: startTime,
) semester = profile.currentSemester,
teacherId = lesson?.displayTeacherId ?: -1,
subjectId = lesson?.displaySubjectId ?: -1
).also {
it.lessonNumber = lessonNumber
}
data.attendanceList.add(attendanceObject) data.attendanceList.add(attendanceObject)
if(type != Attendance.TYPE_PRESENT) { if (baseType != Attendance.TYPE_PRESENT) {
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_ATTENDANCE, Metadata.TYPE_ATTENDANCE,
id, id,
profile.empty, profile.empty || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN,
profile.empty, profile.empty || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -57,8 +57,7 @@ class EdudziennikWebEvents(override val data: DataEdudziennik,
Metadata.TYPE_EVENT, Metadata.TYPE_EVENT,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
System.currentTimeMillis()
)) ))
} }

View File

@ -46,7 +46,7 @@ class EdudziennikWebExams(override val data: DataEdudziennik,
if (dateString.isBlank()) return@forEach if (dateString.isBlank()) return@forEach
val date = Date.fromY_m_d(dateString) val date = Date.fromY_m_d(dateString)
val lessons = data.app.db.timetableDao().getForDateNow(profileId, date) val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
val startTime = lessons.firstOrNull { it.displaySubjectId == subject.id }?.displayStartTime val startTime = lessons.firstOrNull { it.displaySubjectId == subject.id }?.displayStartTime
val eventTypeElement = examElement.child(3).child(0) val eventTypeElement = examElement.child(3).child(0)
@ -74,8 +74,7 @@ class EdudziennikWebExams(override val data: DataEdudziennik,
Metadata.TYPE_EVENT, Metadata.TYPE_EVENT,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
System.currentTimeMillis()
)) ))
} }

View File

@ -126,7 +126,8 @@ class EdudziennikWebGrades(override val data: DataEdudziennik,
comment = null, comment = null,
semester = semester, semester = semester,
teacherId = teacher.id, teacherId = teacher.id,
subjectId = subject.id subjectId = subject.id,
addedDate = addedDate
) )
data.gradeList.add(gradeObject) data.gradeList.add(gradeObject)
@ -135,8 +136,7 @@ class EdudziennikWebGrades(override val data: DataEdudziennik,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }
@ -168,8 +168,7 @@ class EdudziennikWebGrades(override val data: DataEdudziennik,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
proposedGradeObject.id, proposedGradeObject.id,
profile.empty, profile.empty,
profile.empty, profile.empty
System.currentTimeMillis()
)) ))
} }
@ -201,8 +200,7 @@ class EdudziennikWebGrades(override val data: DataEdudziennik,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
finalGradeObject.id, finalGradeObject.id,
profile.empty, profile.empty,
profile.empty, profile.empty
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -43,7 +43,7 @@ class EdudziennikWebHomework(override val data: DataEdudziennik,
val subjectName = subjectElement.text() val subjectName = subjectElement.text()
val subject = data.getSubject(subjectId, subjectName) val subject = data.getSubject(subjectId, subjectName)
val lessons = data.app.db.timetableDao().getForDateNow(profileId, date) val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
val startTime = lessons.firstOrNull { it.subjectId == subject.id }?.displayStartTime val startTime = lessons.firstOrNull { it.subjectId == subject.id }?.displayStartTime
val teacherName = homeworkElement.child(2).text() val teacherName = homeworkElement.child(2).text()
@ -72,8 +72,7 @@ class EdudziennikWebHomework(override val data: DataEdudziennik,
Metadata.TYPE_HOMEWORK, Metadata.TYPE_HOMEWORK,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -24,9 +24,9 @@ class EdudziennikWebLuckyNumber(override val data: DataEdudziennik,
webGet(TAG, data.schoolEndpoint + "Lucky", xhr = true) { text -> webGet(TAG, data.schoolEndpoint + "Lucky", xhr = true) { text ->
text.toIntOrNull()?.also { luckyNumber -> text.toIntOrNull()?.also { luckyNumber ->
val luckyNumberObject = LuckyNumber( val luckyNumberObject = LuckyNumber(
profileId, profileId = profileId,
Date.getToday(), date = Date.getToday(),
luckyNumber number = luckyNumber
) )
data.luckyNumberList.add(luckyNumberObject) data.luckyNumberList.add(luckyNumberObject)
@ -35,8 +35,7 @@ class EdudziennikWebLuckyNumber(override val data: DataEdudziennik,
Metadata.TYPE_LUCKY_NUMBER, Metadata.TYPE_LUCKY_NUMBER,
luckyNumberObject.date.value.toLong(), luckyNumberObject.date.value.toLong(),
true, true,
profile.empty, profile.empty
System.currentTimeMillis()
)) ))
} }

View File

@ -41,12 +41,15 @@ class EdudziennikWebNotes(override val data: DataEdudziennik,
val description = noteElement.child(3).text() val description = noteElement.child(3).text()
val noticeObject = Notice( val noticeObject = Notice(
profileId, profileId = profileId,
id, id = id,
description, type = Notice.TYPE_NEUTRAL,
profile.currentSemester, semester = profile.currentSemester,
Notice.TYPE_NEUTRAL, text = description,
teacher.id category = null,
points = null,
teacherId = teacher.id,
addedDate = addedDate
) )
data.noticeList.add(noticeObject) data.noticeList.add(noticeObject)
@ -55,8 +58,7 @@ class EdudziennikWebNotes(override val data: DataEdudziennik,
Metadata.TYPE_NOTICE, Metadata.TYPE_NOTICE,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }

View File

@ -124,8 +124,7 @@ class EdudziennikWebTimetable(override val data: DataEdudziennik,
Metadata.TYPE_LESSON_CHANGE, Metadata.TYPE_LESSON_CHANGE,
lessonObject.id, lessonObject.id,
seen, seen,
seen, seen
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-7.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.helper
import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response
import im.wangchao.mhttp.callback.FileCallbackHandler
import im.wangchao.mhttp.callback.TextCallbackHandler
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.data.api.ERROR_ONEDRIVE_DOWNLOAD
import pl.szczodrzynski.edziennik.data.api.ERROR_REQUEST_FAILURE
import pl.szczodrzynski.edziennik.data.api.SYSTEM_USER_AGENT
import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.utils.Utils
import java.io.File
class OneDriveDownloadAttachment(
app: App,
fileUrl: String,
val onSuccess: (file: File) -> Unit,
val onProgress: (written: Long, total: Long) -> Unit,
val onError: (apiError: ApiError) -> Unit
) {
companion object {
private const val TAG = "OneDriveDownloadAttachment"
}
init {
Request.builder()
.url(fileUrl)
.userAgent(SYSTEM_USER_AGENT)
.withClient(app.httpLazy)
.callback(object : TextCallbackHandler() {
override fun onSuccess(text: String, response: Response) {
val location = response.headers().get("Location")
// https://onedrive.live.com/redir?resid=D75496A2EB87531C!706&authkey=!ABjZeh3pHMqj11Q
if (location?.contains("onedrive.live.com/redir?resid=") != true) {
onError(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD)
.withApiResponse(text)
.withResponse(response))
return
}
val url = location
.replace("onedrive.live.com/redir?resid=", "storage.live.com/items/")
.replace("?", "&")
.replaceFirst("&", "?")
downloadFile(url)
}
override fun onFailure(response: Response, throwable: Throwable) {
onError(ApiError(TAG, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable))
}
})
.build()
.enqueue()
}
private fun downloadFile(url: String) {
val targetFile = Utils.getStorageDir()
val callback = object : FileCallbackHandler(targetFile) {
override fun onSuccess(file: File?, response: Response?) {
if (file == null) {
onError(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD)
.withResponse(response))
return
}
try {
onSuccess(file)
} catch (e: Exception) {
onError(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD)
.withResponse(response)
.withThrowable(e))
}
}
override fun onProgress(bytesWritten: Long, bytesTotal: Long) {
try {
this@OneDriveDownloadAttachment.onProgress(bytesWritten, bytesTotal)
} catch (e: Exception) {
onError(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD)
.withThrowable(e))
}
}
override fun onFailure(response: Response?, throwable: Throwable?) {
onError(ApiError(TAG, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable))
}
}
Request.builder()
.url(url)
.userAgent(SYSTEM_USER_AGENT)
.callback(callback)
.build()
.enqueue()
}
}

View File

@ -68,9 +68,9 @@ class IdziennikApiCurrentRegister(override val data: DataIdziennik,
val luckyNumberObject = LuckyNumber( val luckyNumberObject = LuckyNumber(
data.profileId, profileId = data.profileId,
luckyNumberDate, date = luckyNumberDate,
luckyNumber number = luckyNumber
) )
data.luckyNumberList.add(luckyNumberObject) data.luckyNumberList.add(luckyNumberObject)
@ -80,8 +80,7 @@ class IdziennikApiCurrentRegister(override val data: DataIdziennik,
Metadata.TYPE_LUCKY_NUMBER, Metadata.TYPE_LUCKY_NUMBER,
luckyNumberObject.date.value.toLong(), luckyNumberObject.date.value.toLong(),
true, true,
data.profile?.empty ?: false, data.profile?.empty ?: false
System.currentTimeMillis()
)) ))
} }

View File

@ -69,7 +69,8 @@ class IdziennikApiMessagesInbox(override val data: DataIdziennik,
type = if (jMessage.getBoolean("rekordUsuniety") == true) TYPE_DELETED else TYPE_RECEIVED, type = if (jMessage.getBoolean("rekordUsuniety") == true) TYPE_DELETED else TYPE_RECEIVED,
subject = subject, subject = subject,
body = body, body = body,
senderId = rTeacher.id senderId = rTeacher.id,
addedDate = sentDate
) )
val messageRecipient = MessageRecipient( val messageRecipient = MessageRecipient(
@ -87,8 +88,7 @@ class IdziennikApiMessagesInbox(override val data: DataIdziennik,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
message.id, message.id,
readDate > 0, readDate > 0,
readDate > 0 || profile?.empty ?: false, readDate > 0 || profile?.empty ?: false
sentDate
)) ))
} }

View File

@ -51,7 +51,8 @@ class IdziennikApiMessagesSent(override val data: DataIdziennik,
type = TYPE_SENT, type = TYPE_SENT,
subject = subject, subject = subject,
body = body, body = body,
senderId = null senderId = null,
addedDate = sentDate
) )
for (recipientEl in jMessage.getAsJsonArray("odbiorcy")) { for (recipientEl in jMessage.getAsJsonArray("odbiorcy")) {
@ -76,7 +77,7 @@ class IdziennikApiMessagesSent(override val data: DataIdziennik,
} }
data.messageList.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))
} }
data.setSyncNext(ENDPOINT_IDZIENNIK_API_MESSAGES_SENT, DAY, DRAWER_ITEM_MESSAGES) data.setSyncNext(ENDPOINT_IDZIENNIK_API_MESSAGES_SENT, DAY, DRAWER_ITEM_MESSAGES)

View File

@ -52,14 +52,14 @@ class IdziennikWebAnnouncements(override val data: DataIdziennik,
val startDate = jAnnouncement.getString("DataWydarzenia")?.replace("[^\\d]".toRegex(), "")?.toLongOrNull()?.let { Date.fromMillis(it) } val startDate = jAnnouncement.getString("DataWydarzenia")?.replace("[^\\d]".toRegex(), "")?.toLongOrNull()?.let { Date.fromMillis(it) }
val announcementObject = Announcement( val announcementObject = Announcement(
profileId, profileId = profileId,
announcementId, id = announcementId,
jAnnouncement.get("Temat").asString, subject = jAnnouncement.get("Temat").asString,
jAnnouncement.get("Tresc").asString, text = jAnnouncement.get("Tresc").asString,
startDate, startDate = startDate,
null, endDate = null,
rTeacher.id, teacherId = rTeacher.id,
null addedDate = addedDate
) )
data.announcementList.add(announcementObject) data.announcementList.add(announcementObject)
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
@ -67,8 +67,7 @@ class IdziennikWebAnnouncements(override val data: DataIdziennik,
Metadata.TYPE_ANNOUNCEMENT, Metadata.TYPE_ANNOUNCEMENT,
announcementObject.id, announcementObject.id,
profile?.empty ?: false, profile?.empty ?: false,
profile?.empty ?: false, profile?.empty ?: false
addedDate
)) ))
} }

View File

@ -12,10 +12,18 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNI
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.data.db.entity.Attendance import pl.szczodrzynski.edziennik.data.db.entity.Attendance
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.* import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSENT
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSENT_EXCUSED
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_BELATED
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESENT
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESENT_CUSTOM
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_RELEASED
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_UNKNOWN
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.getInt
import pl.szczodrzynski.edziennik.getJsonObject import pl.szczodrzynski.edziennik.getJsonObject
import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time import pl.szczodrzynski.edziennik.utils.models.Time
@ -51,71 +59,97 @@ class IdziennikWebAttendance(override val data: DataIdziennik,
for (jAttendanceEl in json.getAsJsonArray("Obecnosci")) { for (jAttendanceEl in json.getAsJsonArray("Obecnosci")) {
val jAttendance = jAttendanceEl.asJsonObject val jAttendance = jAttendanceEl.asJsonObject
// jAttendance // jAttendance
val attendanceTypeIdziennik = jAttendance.get("TypObecnosci").asInt val type = jAttendance.get("TypObecnosci").asInt
if (attendanceTypeIdziennik == 5 || attendanceTypeIdziennik == 7)
continue // skip "zajęcia nie odbyły się" and "Ferie"
val attendanceDate = Date.fromY_m_d(jAttendance.get("Data").asString) if (type == 5 || type == 7)
val attendanceTime = Time.fromH_m(jAttendance.get("OdDoGodziny").asString)
if (attendanceDate.combineWith(attendanceTime) > System.currentTimeMillis())
continue continue
val attendanceId = jAttendance.get("IdLesson").asString.crc16().toLong() val date = Date.fromY_m_d(jAttendance.get("Data").asString)
val time = Time.fromH_m(jAttendance.get("OdDoGodziny").asString)
if (date.combineWith(time) > System.currentTimeMillis())
continue
val id = jAttendance.get("IdLesson").asString.crc16().toLong()
val rSubject = data.getSubject(jAttendance.get("Przedmiot").asString, jAttendance.get("IdPrzedmiot").asLong, "") val rSubject = data.getSubject(jAttendance.get("Przedmiot").asString, jAttendance.get("IdPrzedmiot").asLong, "")
val rTeacher = data.getTeacherByFDotSpaceLast(jAttendance.get("PrzedmiotNauczyciel").asString) val rTeacher = data.getTeacherByFDotSpaceLast(jAttendance.get("PrzedmiotNauczyciel").asString)
var attendanceName = "obecność" var baseType = TYPE_UNKNOWN
var attendanceType = Attendance.TYPE_CUSTOM var typeName = "nieznany rodzaj"
var typeSymbol: String? = null
var typeColor: Long? = null
when (attendanceTypeIdziennik) { /* https://iuczniowie.progman.pl/idziennik/mod_panelRodzica/obecnosci/obecnosciUcznia_lmt637231494660000000.js */
1 /* nieobecność usprawiedliwiona */ -> { /* https://iuczniowie.progman.pl/idziennik/mod_panelRodzica/obecnosci/obecnosci_lmt637231494660000000.css */
attendanceName = "nieobecność usprawiedliwiona" when (type) {
attendanceType = TYPE_ABSENT_EXCUSED 1 -> {
baseType = TYPE_ABSENT_EXCUSED
typeName = "nieobecność usprawiedliwiona"
typeColor = 0xffffe099
} }
2 /* spóźnienie */ -> { 2 -> {
attendanceName = "spóźnienie" baseType = TYPE_BELATED
attendanceType = TYPE_BELATED typeName = "spóźnienie"
typeColor = 0xffffffaa
} }
3 /* nieobecność nieusprawiedliwiona */ -> { 3 -> {
attendanceName = "nieobecność nieusprawiedliwiona" baseType = TYPE_ABSENT
attendanceType = TYPE_ABSENT typeName = "nieobecność nieusprawiedliwiona"
typeColor = 0xffffad99
} }
4 /* zwolnienie */, 9 /* zwolniony / obecny */ -> { 4, 9 -> {
attendanceType = TYPE_RELEASED baseType = TYPE_RELEASED
if (attendanceTypeIdziennik == 4) if (type == 4) {
attendanceName = "zwolnienie" typeName = "zwolnienie"
if (attendanceTypeIdziennik == 9) typeColor = 0xffa8beff
attendanceName = "zwolnienie / obecność"
} }
0 /* obecny */, 8 /* Wycieczka */ -> { if (type == 9) {
attendanceType = TYPE_PRESENT typeName = "zwolniony / obecny"
if (attendanceTypeIdziennik == 8) typeSymbol = "zb"
attendanceName = "wycieczka" typeColor = 0xffff69b4
}
}
8 -> {
baseType = TYPE_PRESENT_CUSTOM
typeName = "wycieczka"
typeSymbol = "w"
typeColor = null
}
0 -> {
baseType = TYPE_PRESENT
typeName = "obecny"
typeColor = 0xffccffcc
} }
} }
val semester = profile?.dateToSemester(attendanceDate) ?: 1 val semester = profile?.dateToSemester(date) ?: 1
val attendanceObject = Attendance( val attendanceObject = Attendance(
profileId, profileId = profileId,
attendanceId, id = id,
rTeacher.id, baseType = baseType,
rSubject.id, typeName = typeName,
semester, typeShort = typeSymbol ?: data.app.attendanceManager.getTypeShort(baseType),
attendanceName, typeSymbol = typeSymbol ?: data.app.attendanceManager.getTypeShort(baseType),
attendanceDate, typeColor = typeColor?.toInt(),
attendanceTime, date = date,
attendanceType startTime = time,
) semester = semester,
teacherId = rTeacher.id,
subjectId = rSubject.id
).also {
it.lessonTopic = jAttendance.getString("PrzedmiotTemat")
it.lessonNumber = jAttendance.getInt("Godzina")
}
data.attendanceList.add(attendanceObject) data.attendanceList.add(attendanceObject)
if (attendanceObject.type != TYPE_PRESENT) { if (attendanceObject.baseType != TYPE_PRESENT) {
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_ATTENDANCE, Metadata.TYPE_ATTENDANCE,
attendanceObject.id, attendanceObject.id,
profile?.empty ?: false, profile?.empty ?: false || baseType == TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN,
profile?.empty ?: false, profile?.empty ?: false || baseType == TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -68,7 +68,7 @@ class IdziennikWebExams(override val data: DataIdziennik,
val teacherId = data.getTeacherByLastFirst(teacherName).id val teacherId = data.getTeacherByLastFirst(teacherName).id
val topic = exam.getString("zakres")?.trim() ?: "" val topic = exam.getString("zakres")?.trim() ?: ""
val lessonList = data.db.timetableDao().getForDateNow(profileId, examDate) val lessonList = data.db.timetableDao().getAllForDateNow(profileId, examDate)
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime
val eventType = when (exam.getString("rodzaj")?.toLowerCase(Locale.getDefault())) { val eventType = when (exam.getString("rodzaj")?.toLowerCase(Locale.getDefault())) {
@ -98,8 +98,7 @@ class IdziennikWebExams(override val data: DataIdziennik,
Metadata.TYPE_EVENT, Metadata.TYPE_EVENT,
eventObject.id, eventObject.id,
profile?.empty ?: false, profile?.empty ?: false,
profile?.empty ?: false, profile?.empty ?: false
System.currentTimeMillis()
)) ))
} }

View File

@ -94,8 +94,7 @@ class IdziennikWebGetMessage(override val data: DataIdziennik,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
message.id, message.id,
message.seen, message.seen,
message.notified, message.notified
message.addedDate
)) ))
} }

View File

@ -63,6 +63,8 @@ class IdziennikWebGrades(override val data: DataIdziennik,
colorInt = Color.parseColor("#$gradeColor") colorInt = Color.parseColor("#$gradeColor")
} }
val addedDate = grade.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis()
val gradeObject = Grade( val gradeObject = Grade(
profileId = profileId, profileId = profileId,
id = id, id = id,
@ -76,7 +78,9 @@ class IdziennikWebGrades(override val data: DataIdziennik,
comment = null, comment = null,
semester = semester, semester = semester,
teacherId = teacher.id, teacherId = teacher.id,
subjectId = subject.id) subjectId = subject.id,
addedDate = addedDate
)
when (grade.getInt("Typ")) { when (grade.getInt("Typ")) {
0 -> { 0 -> {
@ -100,6 +104,8 @@ class IdziennikWebGrades(override val data: DataIdziennik,
colorInt = Color.parseColor("#$historyColor") colorInt = Color.parseColor("#$historyColor")
} }
val addedDate = historyItem.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis()
val historyObject = Grade( val historyObject = Grade(
profileId = profileId, profileId = profileId,
id = gradeObject.id * -1, id = gradeObject.id * -1,
@ -113,19 +119,18 @@ class IdziennikWebGrades(override val data: DataIdziennik,
comment = null, comment = null,
semester = historyItem.getInt("Semestr") ?: 1, semester = historyItem.getInt("Semestr") ?: 1,
teacherId = teacher.id, teacherId = teacher.id,
subjectId = subject.id) subjectId = subject.id,
addedDate = addedDate
)
historyObject.parentId = gradeObject.id historyObject.parentId = gradeObject.id
val addedDate = historyItem.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis()
data.gradeList.add(historyObject) data.gradeList.add(historyObject)
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
historyObject.id, historyObject.id,
true, true,
true, true
addedDate
)) ))
} }
// update the current grade's value with an average of all historical grades and itself // update the current grade's value with an average of all historical grades and itself
@ -147,8 +152,6 @@ class IdziennikWebGrades(override val data: DataIdziennik,
} }
} }
val addedDate = grade.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis()
data.gradeList.add(gradeObject) data.gradeList.add(gradeObject)
data.metadataList.add( data.metadataList.add(
Metadata( Metadata(
@ -156,8 +159,7 @@ class IdziennikWebGrades(override val data: DataIdziennik,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
data.profile.empty, data.profile.empty,
data.profile.empty, data.profile.empty
addedDate
)) ))
} }
} }

View File

@ -57,7 +57,7 @@ class IdziennikWebHomework(override val data: DataIdziennik,
val subjectId = data.getSubject(subjectName, null, subjectName).id val subjectId = data.getSubject(subjectName, null, subjectName).id
val teacherName = homework.getString("usr") ?: return@forEach val teacherName = homework.getString("usr") ?: return@forEach
val teacherId = data.getTeacherByLastFirst(teacherName).id val teacherId = data.getTeacherByLastFirst(teacherName).id
val lessonList = data.db.timetableDao().getForDateNow(profileId, eventDate) val lessonList = data.db.timetableDao().getAllForDateNow(profileId, eventDate)
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.displayStartTime val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.displayStartTime
val topic = homework.getString("tytul")?.trim() ?: "" val topic = homework.getString("tytul")?.trim() ?: ""
@ -77,7 +77,8 @@ class IdziennikWebHomework(override val data: DataIdziennik,
type = Event.TYPE_HOMEWORK, type = Event.TYPE_HOMEWORK,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId, subjectId = subjectId,
teamId = data.teamClass?.id ?: -1 teamId = data.teamClass?.id ?: -1,
addedDate = addedDate.inMillis
) )
data.eventList.add(eventObject) data.eventList.add(eventObject)
@ -86,8 +87,7 @@ class IdziennikWebHomework(override val data: DataIdziennik,
Metadata.TYPE_HOMEWORK, Metadata.TYPE_HOMEWORK,
eventObject.id, eventObject.id,
seen, seen,
seen, seen
addedDate.inMillis
)) ))
} }

View File

@ -13,9 +13,12 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.Notice import pl.szczodrzynski.edziennik.data.db.entity.Notice
import pl.szczodrzynski.edziennik.data.db.entity.Notice.* import pl.szczodrzynski.edziennik.data.db.entity.Notice.Companion.TYPE_NEGATIVE
import pl.szczodrzynski.edziennik.data.db.entity.Notice.Companion.TYPE_NEUTRAL
import pl.szczodrzynski.edziennik.data.db.entity.Notice.Companion.TYPE_POSITIVE
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.getJsonObject import pl.szczodrzynski.edziennik.getJsonObject
import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
class IdziennikWebNotices(override val data: DataIdziennik, class IdziennikWebNotices(override val data: DataIdziennik,
@ -53,20 +56,24 @@ class IdziennikWebNotices(override val data: DataIdziennik,
} }
val noticeObject = Notice( val noticeObject = Notice(
profileId, profileId = profileId,
noticeId, id = noticeId,
jNotice.get("Tresc").asString, type = nType,
jNotice.get("Semestr").asInt, semester = jNotice.get("Semestr").asInt,
nType, text = jNotice.getString("Tresc") ?: "",
rTeacher.id) category = null,
points = null,
teacherId = rTeacher.id,
addedDate = addedDate.inMillis
)
data.noticeList.add(noticeObject) data.noticeList.add(noticeObject)
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_NOTICE, Metadata.TYPE_NOTICE,
noticeObject.id, noticeObject.id,
profile?.empty ?: false, profile?.empty ?: false,
profile?.empty ?: false, profile?.empty ?: false
addedDate.inMillis
)) ))
} }

View File

@ -76,6 +76,11 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
else -1 else -1
if (semester1Proposed != "") { if (semester1Proposed != "") {
val addedDate = if (data.profile.empty)
data.profile.dateSemester1Start.inMillis
else
System.currentTimeMillis()
val gradeObject = Grade( val gradeObject = Grade(
profileId = profileId, profileId = profileId,
id = semester1Id, id = semester1Id,
@ -89,26 +94,26 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
comment = null, comment = null,
semester = 1, semester = 1,
teacherId = -1, teacherId = -1,
subjectId = subjectObject.id subjectId = subjectObject.id,
addedDate = addedDate
) )
val addedDate = if (data.profile.empty)
data.profile.dateSemester1Start.inMillis
else
System.currentTimeMillis()
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,
profile.empty, profile.empty
addedDate
)) ))
} }
if (semester2Proposed != "") { if (semester2Proposed != "") {
val addedDate = if (data.profile.empty)
data.profile.dateSemester2Start.inMillis
else
System.currentTimeMillis()
val gradeObject = Grade( val gradeObject = Grade(
profileId = profileId, profileId = profileId,
id = semester2Id, id = semester2Id,
@ -122,22 +127,17 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
comment = null, comment = null,
semester = 2, semester = 2,
teacherId = -1, teacherId = -1,
subjectId = subjectObject.id subjectId = subjectObject.id,
addedDate = addedDate
) )
val addedDate = if (data.profile.empty)
data.profile.dateSemester2Start.inMillis
else
System.currentTimeMillis()
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,
profile.empty, profile.empty
addedDate
)) ))
} }
} }

View File

@ -59,7 +59,7 @@ class IdziennikWebSendMessage(override val data: DataIdziennik,
IdziennikApiMessagesSent(data, null) { IdziennikApiMessagesSent(data, null) {
val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject } val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject }
val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id } val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id }
val event = MessageSentEvent(data.profileId, message, metadata?.addedDate) val event = MessageSentEvent(data.profileId, message, message?.addedDate)
EventBus.getDefault().postSticky(event) EventBus.getDefault().postSticky(event)
onSuccess() onSuccess()

View File

@ -165,8 +165,7 @@ class IdziennikWebTimetable(override val data: DataIdziennik,
Metadata.TYPE_LESSON_CHANGE, Metadata.TYPE_LESSON_CHANGE,
lessonObject.id, lessonObject.id,
seen, seen,
seen, seen
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -74,9 +74,9 @@ class IdziennikLoginWeb(val data: DataIdziennik, val onSuccess: () -> Unit) {
Regexes.IDZIENNIK_WEB_LUCKY_NUMBER.find(text)?.also { Regexes.IDZIENNIK_WEB_LUCKY_NUMBER.find(text)?.also {
val number = it[1].toIntOrNull() ?: return@also val number = it[1].toIntOrNull() ?: return@also
val luckyNumberObject = LuckyNumber( val luckyNumberObject = LuckyNumber(
data.profileId, profileId = data.profileId,
Date.getToday(), date = Date.getToday(),
number number = number
) )
data.luckyNumberList.add(luckyNumberObject) data.luckyNumberList.add(luckyNumberObject)
@ -86,8 +86,7 @@ class IdziennikLoginWeb(val data: DataIdziennik, val onSuccess: () -> Unit) {
Metadata.TYPE_LUCKY_NUMBER, Metadata.TYPE_LUCKY_NUMBER,
luckyNumberObject.date.value.toLong(), luckyNumberObject.date.value.toLong(),
true, true,
profile.empty, profile.empty
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-5-8.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.librus
import android.content.Context
import android.webkit.WebView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import pl.szczodrzynski.edziennik.startCoroutineTimer
import kotlin.coroutines.CoroutineContext
class LibrusRecaptchaHelper(
val context: Context,
url: String,
html: String,
val onSuccess: (url: String) -> Unit,
val onTimeout: () -> Unit
) : CoroutineScope {
companion object {
private const val TAG = "LibrusRecaptchaHelper"
}
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Default
private val webView by lazy {
WebView(context).also {
it.settings.javaScriptEnabled = true
it.webViewClient = WebViewClient()
}
}
private var timeout: Job? = null
inner class WebViewClient : android.webkit.WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
timeout?.cancel()
onSuccess(url)
return true
}
}
init {
launch(Dispatchers.Main) {
webView.loadDataWithBaseURL(url, html, "text/html", "UTF-8", null)
}
timeout = startCoroutineTimer(delayMillis = 10000L) {
onTimeout()
}
}
}

View File

@ -37,8 +37,7 @@ class LibrusApiAnnouncementMarkAsRead(override val data: DataLibrus,
Metadata.TYPE_ANNOUNCEMENT, Metadata.TYPE_ANNOUNCEMENT,
announcement.id, announcement.id,
announcement.seen, announcement.seen,
announcement.notified, announcement.notified
announcement.addedDate
)) ))
onSuccess() onSuccess()
} }

View File

@ -38,15 +38,17 @@ class LibrusApiAnnouncements(override val data: DataLibrus,
val read = announcement.getBoolean("WasRead") ?: false val read = announcement.getBoolean("WasRead") ?: false
val announcementObject = Announcement( val announcementObject = Announcement(
profileId, profileId = profileId,
id, id = id,
subject, subject = subject,
text, text = text,
startDate, startDate = startDate,
endDate, endDate = endDate,
teacherId, teacherId = teacherId,
longId addedDate = addedDate
) ).also {
it.idString = longId
}
data.announcementList.add(announcementObject) data.announcementList.add(announcementObject)
data.setSeenMetadataList.add(Metadata( data.setSeenMetadataList.add(Metadata(
@ -54,8 +56,7 @@ class LibrusApiAnnouncements(override val data: DataLibrus,
Metadata.TYPE_ANNOUNCEMENT, Metadata.TYPE_ANNOUNCEMENT,
id, id,
read, read,
profile.empty || read, profile.empty || read
addedDate
)) ))
} }

View File

@ -26,25 +26,39 @@ class LibrusApiAttendanceTypes(override val data: DataLibrus,
attendanceTypes?.forEach { attendanceType -> attendanceTypes?.forEach { attendanceType ->
val id = attendanceType.getLong("Id") ?: return@forEach val id = attendanceType.getLong("Id") ?: return@forEach
val name = attendanceType.getString("Name") ?: ""
val color = attendanceType.getString("ColorRGB")?.let { Color.parseColor("#$it") } ?: -1
val standardId = when (attendanceType.getBoolean("Standard") ?: false) { val typeName = attendanceType.getString("Name") ?: ""
true -> id val typeSymbol = attendanceType.getString("Short") ?: ""
false -> attendanceType.getJsonObject("StandardType")?.getLong("Id") ?: id val typeColor = attendanceType.getString("ColorRGB")?.let { Color.parseColor("#$it") }
}
val type = when (standardId) { val isStandard = attendanceType.getBoolean("Standard") ?: false
val baseType = when (attendanceType.getJsonObject("StandardType")?.getLong("Id") ?: id) {
1L -> Attendance.TYPE_ABSENT 1L -> Attendance.TYPE_ABSENT
2L -> Attendance.TYPE_BELATED 2L -> Attendance.TYPE_BELATED
3L -> Attendance.TYPE_ABSENT_EXCUSED 3L -> Attendance.TYPE_ABSENT_EXCUSED
4L -> Attendance.TYPE_RELEASED 4L -> Attendance.TYPE_RELEASED
/*100*/else -> Attendance.TYPE_PRESENT /*100*/else -> when (isStandard) {
true -> Attendance.TYPE_PRESENT
false -> Attendance.TYPE_PRESENT_CUSTOM
}
}
val typeShort = when (isStandard) {
true -> data.app.attendanceManager.getTypeShort(baseType)
false -> typeSymbol
} }
data.attendanceTypes.put(id, AttendanceType(profileId, id, name, type, color)) data.attendanceTypes.put(id, AttendanceType(
profileId,
id,
baseType,
typeName,
typeShort,
typeSymbol,
typeColor
))
} }
data.setSyncNext(ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES, 4*DAY) data.setSyncNext(ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES, 2*DAY)
onSuccess(ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES) onSuccess(ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES)
} }
} }

View File

@ -13,7 +13,6 @@ import pl.szczodrzynski.edziennik.data.db.entity.Attendance
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time
class LibrusApiAttendances(override val data: DataLibrus, class LibrusApiAttendances(override val data: DataLibrus,
override val lastSync: Long?, override val lastSync: Long?,
@ -42,9 +41,9 @@ class LibrusApiAttendances(override val data: DataLibrus,
val lessonDate = Date.fromY_m_d(attendance.getString("Date")) val lessonDate = Date.fromY_m_d(attendance.getString("Date"))
val teacherId = attendance.getJsonObject("AddedBy")?.getLong("Id") val teacherId = attendance.getJsonObject("AddedBy")?.getLong("Id")
val semester = attendance.getInt("Semester") ?: return@forEach val semester = attendance.getInt("Semester") ?: return@forEach
val type = attendance.getJsonObject("Type")?.getLong("Id") ?: return@forEach
val typeObject = data.attendanceTypes[type] ?: null val typeId = attendance.getJsonObject("Type")?.getLong("Id") ?: return@forEach
val topic = typeObject?.name ?: "" val type = data.attendanceTypes[typeId] ?: null
val startTime = data.lessonRanges.get(lessonNo)?.startTime val startTime = data.lessonRanges.get(lessonNo)?.startTime
@ -52,29 +51,34 @@ class LibrusApiAttendances(override val data: DataLibrus,
data.librusLessons.singleOrNull { it.lessonId == lessonId } data.librusLessons.singleOrNull { it.lessonId == lessonId }
else null else null
val attendanceObject = Attendance(
profileId,
id,
teacherId ?: lesson?.teacherId ?: -1,
lesson?.subjectId ?: -1,
semester,
topic,
lessonDate,
startTime ?: Time(0, 0, 0),
typeObject?.type ?: Attendance.TYPE_CUSTOM
)
val addedDate = Date.fromIso(attendance.getString("AddDate") ?: return@forEach) val addedDate = Date.fromIso(attendance.getString("AddDate") ?: return@forEach)
val attendanceObject = Attendance(
profileId = profileId,
id = id,
baseType = type?.baseType ?: Attendance.TYPE_UNKNOWN,
typeName = type?.typeName ?: "nieznany rodzaj",
typeShort = type?.typeShort ?: "?",
typeSymbol = type?.typeSymbol ?: "?",
typeColor = type?.typeColor,
date = lessonDate,
startTime = startTime,
semester = semester,
teacherId = teacherId ?: lesson?.teacherId ?: -1,
subjectId = lesson?.subjectId ?: -1,
addedDate = addedDate
).also {
it.lessonNumber = lessonNo
}
data.attendanceList.add(attendanceObject) data.attendanceList.add(attendanceObject)
if(typeObject?.type != Attendance.TYPE_PRESENT) { if(type?.baseType != Attendance.TYPE_PRESENT) {
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_ATTENDANCE, Metadata.TYPE_ATTENDANCE,
id, id,
profile?.empty ?: false, profile?.empty ?: false || type?.baseType == Attendance.TYPE_PRESENT_CUSTOM || type?.baseType == Attendance.TYPE_UNKNOWN,
profile?.empty ?: false, profile?.empty ?: false || type?.baseType == Attendance.TYPE_PRESENT_CUSTOM || type?.baseType == Attendance.TYPE_UNKNOWN
addedDate
)) ))
} }
} }

View File

@ -55,7 +55,8 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
comment = null, comment = null,
semester = 1, semester = 1,
teacherId = -1, teacherId = -1,
subjectId = 1 subjectId = 1,
addedDate = profile.getSemesterStart(1).inMillis
) )
data.gradeList.add(semester1StartGradeObject) data.gradeList.add(semester1StartGradeObject)
@ -64,8 +65,7 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
semester1StartGradeObject.id, semester1StartGradeObject.id,
true, true,
true, true
profile.getSemesterStart(1).inMillis
)) ))
} }
@ -83,7 +83,8 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
comment = null, comment = null,
semester = 2, semester = 2,
teacherId = -1, teacherId = -1,
subjectId = 1 subjectId = 1,
addedDate = profile.getSemesterStart(2).inMillis
) )
data.gradeList.add(semester2StartGradeObject) data.gradeList.add(semester2StartGradeObject)
@ -92,8 +93,7 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
semester2StartGradeObject.id, semester2StartGradeObject.id,
true, true,
true, true
profile.getSemesterStart(2).inMillis
)) ))
} }
@ -155,7 +155,8 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
comment = if (text != null) description.join(" - ") else null, comment = if (text != null) description.join(" - ") else null,
semester = semester, semester = semester,
teacherId = teacherId, teacherId = teacherId,
subjectId = 1 subjectId = 1,
addedDate = addedDate
).apply { ).apply {
valueMax = valueTo valueMax = valueTo
} }
@ -166,8 +167,7 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }

View File

@ -65,7 +65,8 @@ class LibrusApiDescriptiveGrades(override val data: DataLibrus,
comment = null, comment = null,
semester = semester, semester = semester,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId subjectId = subjectId,
addedDate = addedDate
) )
data.gradeList.add(gradeObject) data.gradeList.add(gradeObject)
@ -74,8 +75,7 @@ class LibrusApiDescriptiveGrades(override val data: DataLibrus,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }

View File

@ -35,7 +35,7 @@ class LibrusApiEvents(override val data: DataLibrus,
events?.forEach { event -> events?.forEach { event ->
val id = event.getLong("Id") ?: return@forEach val id = event.getLong("Id") ?: return@forEach
val eventDate = Date.fromY_m_d(event.getString("Date")) val eventDate = Date.fromY_m_d(event.getString("Date"))
val topic = event.getString("Content")?.trim() ?: "" var topic = event.getString("Content")?.trim() ?: ""
val type = event.getJsonObject("Category")?.getLong("Id") ?: -1 val type = event.getJsonObject("Category")?.getLong("Id") ?: -1
val teacherId = event.getJsonObject("CreatedBy")?.getLong("Id") ?: -1 val teacherId = event.getJsonObject("CreatedBy")?.getLong("Id") ?: -1
val subjectId = event.getJsonObject("Subject")?.getLong("Id") ?: -1 val subjectId = event.getJsonObject("Subject")?.getLong("Id") ?: -1
@ -46,6 +46,12 @@ class LibrusApiEvents(override val data: DataLibrus,
val startTime = lessonRange?.startTime ?: Time.fromH_m(event.getString("TimeFrom")) val startTime = lessonRange?.startTime ?: Time.fromH_m(event.getString("TimeFrom"))
val addedDate = Date.fromIso(event.getString("AddDate")) val addedDate = Date.fromIso(event.getString("AddDate"))
event.getJsonObject("onlineLessonUrl")?.let { onlineLesson ->
val text = onlineLesson.getString("text")?.let { "$it - " } ?: ""
val url = onlineLesson.getString("url")
topic += "\n\n$text$url"
}
val eventObject = Event( val eventObject = Event(
profileId = profileId, profileId = profileId,
id = id, id = id,
@ -56,7 +62,8 @@ class LibrusApiEvents(override val data: DataLibrus,
type = type, type = type,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId, subjectId = subjectId,
teamId = teamId teamId = teamId,
addedDate = addedDate
) )
data.eventList.add(eventObject) data.eventList.add(eventObject)
@ -66,8 +73,7 @@ class LibrusApiEvents(override val data: DataLibrus,
Metadata.TYPE_EVENT, Metadata.TYPE_EVENT,
id, id,
profile?.empty ?: false, profile?.empty ?: false,
profile?.empty ?: false, profile?.empty ?: false
addedDate
)) ))
} }

View File

@ -79,7 +79,8 @@ class LibrusApiGrades(override val data: DataLibrus,
comment = null, comment = null,
semester = semester, semester = semester,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId subjectId = subjectId,
addedDate = addedDate
) )
grade.getJsonObject("Improvement")?.also { grade.getJsonObject("Improvement")?.also {
@ -98,8 +99,7 @@ class LibrusApiGrades(override val data: DataLibrus,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }

View File

@ -43,7 +43,8 @@ class LibrusApiHomework(override val data: DataLibrus,
type = -1, type = -1,
teacherId = teacherId, teacherId = teacherId,
subjectId = -1, subjectId = -1,
teamId = -1 teamId = -1,
addedDate = addedDate.inMillis
) )
data.eventList.add(eventObject) data.eventList.add(eventObject)
@ -52,8 +53,7 @@ class LibrusApiHomework(override val data: DataLibrus,
Metadata.TYPE_HOMEWORK, Metadata.TYPE_HOMEWORK,
id, id,
profile?.empty ?: false, profile?.empty ?: false,
profile?.empty ?: false, profile?.empty ?: false
addedDate.inMillis
)) ))
} }

View File

@ -33,9 +33,9 @@ class LibrusApiLuckyNumber(override val data: DataLibrus,
val luckyNumberDate = Date.fromY_m_d(luckyNumberEl.getString("LuckyNumberDay")) ?: Date.getToday() val luckyNumberDate = Date.fromY_m_d(luckyNumberEl.getString("LuckyNumberDay")) ?: Date.getToday()
val luckyNumber = luckyNumberEl.getInt("LuckyNumber") ?: -1 val luckyNumber = luckyNumberEl.getInt("LuckyNumber") ?: -1
val luckyNumberObject = LuckyNumber( val luckyNumberObject = LuckyNumber(
profileId, profileId = profileId,
luckyNumberDate, date = luckyNumberDate,
luckyNumber number = luckyNumber
) )
if (luckyNumberDate >= Date.getToday()) if (luckyNumberDate >= Date.getToday())
@ -50,8 +50,7 @@ class LibrusApiLuckyNumber(override val data: DataLibrus,
Metadata.TYPE_LUCKY_NUMBER, Metadata.TYPE_LUCKY_NUMBER,
luckyNumberObject.date.value.toLong(), luckyNumberObject.date.value.toLong(),
true, true,
profile?.empty ?: false, profile?.empty ?: false
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -46,12 +46,15 @@ class LibrusApiNotices(override val data: DataLibrus,
val semester = profile?.dateToSemester(addedDate) ?: 1 val semester = profile?.dateToSemester(addedDate) ?: 1
val noticeObject = Notice( val noticeObject = Notice(
profileId, profileId = profileId,
id, id = id,
categoryText + "\n" + text, type = type,
semester, semester = semester,
type, text = text,
teacherId category = categoryText,
points = null,
teacherId = teacherId,
addedDate = addedDate.inMillis
) )
data.noticeList.add(noticeObject) data.noticeList.add(noticeObject)
@ -61,8 +64,7 @@ class LibrusApiNotices(override val data: DataLibrus,
Metadata.TYPE_NOTICE, Metadata.TYPE_NOTICE,
id, id,
profile?.empty ?: false, profile?.empty ?: false,
profile?.empty ?: false, profile?.empty ?: false
addedDate.inMillis
)) ))
} }

View File

@ -56,7 +56,8 @@ class LibrusApiPointGrades(override val data: DataLibrus,
comment = null, comment = null,
semester = semester, semester = semester,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId subjectId = subjectId,
addedDate = addedDate
).apply { ).apply {
valueMax = category?.valueTo ?: 0f valueMax = category?.valueTo ?: 0f
} }
@ -67,8 +68,7 @@ class LibrusApiPointGrades(override val data: DataLibrus,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }

View File

@ -58,8 +58,7 @@ class LibrusApiPtMeetings(override val data: DataLibrus,
Metadata.TYPE_EVENT, Metadata.TYPE_EVENT,
id, id,
profile?.empty ?: false, profile?.empty ?: false,
profile?.empty ?: false, profile?.empty ?: false
System.currentTimeMillis()
)) ))
} }

View File

@ -43,15 +43,15 @@ class LibrusApiTeacherFreeDays(override val data: DataLibrus,
val timeTo = teacherAbsence.getString("TimeTo")?.let { Time.fromH_m_s(it) } val timeTo = teacherAbsence.getString("TimeTo")?.let { Time.fromH_m_s(it) }
val teacherAbsenceObject = TeacherAbsence( val teacherAbsenceObject = TeacherAbsence(
profileId, profileId = profileId,
id, id = id,
teacherId, type = type,
type, name = name,
name, dateFrom = dateFrom,
dateFrom, dateTo = dateTo,
dateTo, timeFrom = timeFrom,
timeFrom, timeTo = timeTo,
timeTo teacherId = teacherId
) )
data.teacherAbsenceList.add(teacherAbsenceObject) data.teacherAbsenceList.add(teacherAbsenceObject)
@ -60,8 +60,7 @@ class LibrusApiTeacherFreeDays(override val data: DataLibrus,
Metadata.TYPE_TEACHER_ABSENCE, Metadata.TYPE_TEACHER_ABSENCE,
id, id,
true, true,
profile?.empty ?: false, profile?.empty ?: false
System.currentTimeMillis()
)) ))
} }

View File

@ -60,7 +60,8 @@ class LibrusApiTextGrades(override val data: DataLibrus,
comment = grade.getString("Phrase") /* whatever it is */, comment = grade.getString("Phrase") /* whatever it is */,
semester = semester, semester = semester,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId subjectId = subjectId,
addedDate = addedDate
) )
data.gradeList.add(gradeObject) data.gradeList.add(gradeObject)
@ -69,8 +70,7 @@ class LibrusApiTextGrades(override val data: DataLibrus,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }

View File

@ -198,8 +198,7 @@ class LibrusApiTimetables(override val data: DataLibrus,
Metadata.TYPE_LESSON_CHANGE, Metadata.TYPE_LESSON_CHANGE,
lessonObject.id, lessonObject.id,
seen, seen,
seen, seen
System.currentTimeMillis()
)) ))
} }
data.lessonList.add(lessonObject) data.lessonList.add(lessonObject)

View File

@ -97,7 +97,8 @@ class LibrusMessagesGetList(override val data: DataLibrus,
type = type, type = type,
subject = subject, subject = subject,
body = null, body = null,
senderId = senderId senderId = senderId,
addedDate = sentDate
) )
val messageRecipientObject = MessageRecipient( val messageRecipientObject = MessageRecipient(
@ -120,8 +121,7 @@ class LibrusMessagesGetList(override val data: DataLibrus,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
id, id,
notified, notified,
notified, notified
sentDate
)) ))
} }

View File

@ -150,8 +150,7 @@ class LibrusMessagesGetMessage(override val data: DataLibrus,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
messageObject.id, messageObject.id,
true, true,
true, true
messageObject.addedDate
)) ))
} }

View File

@ -50,7 +50,7 @@ class LibrusMessagesSendMessage(override val data: DataLibrus,
LibrusMessagesGetList(data, type = Message.TYPE_SENT, lastSync = null) { LibrusMessagesGetList(data, type = Message.TYPE_SENT, lastSync = null) {
val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.id == id } val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.id == id }
val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id } val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id }
val event = MessageSentEvent(data.profileId, message, metadata?.addedDate) val event = MessageSentEvent(data.profileId, message, message?.addedDate)
EventBus.getDefault().postSticky(event) EventBus.getDefault().postSticky(event)
onSuccess() onSuccess()

View File

@ -54,13 +54,13 @@ class LibrusSandboxDownloadAttachment(override val data: DataLibrus,
} }
private fun getAttachmentCheckKey(attachmentKey: String, callback: () -> Unit) { private fun getAttachmentCheckKey(attachmentKey: String, callback: () -> Unit) {
sandboxGet(LibrusMessagesGetAttachment.TAG, "CSCheckKey", sandboxGet(TAG, "CSCheckKey",
parameters = mapOf("singleUseKey" to attachmentKey)) { json -> parameters = mapOf("singleUseKey" to attachmentKey)) { json ->
when (json.getString("status")) { when (json.getString("status")) {
"not_downloaded_yet" -> { "not_downloaded_yet" -> {
if (getAttachmentCheckKeyTries++ > 5) { if (getAttachmentCheckKeyTries++ > 5) {
data.error(ApiError(LibrusMessagesGetAttachment.TAG, ERROR_FILE_DOWNLOAD) data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
.withApiResponse(json)) .withApiResponse(json))
return@sandboxGet return@sandboxGet
} }
@ -75,7 +75,7 @@ class LibrusSandboxDownloadAttachment(override val data: DataLibrus,
} }
else -> { else -> {
data.error(ApiError(LibrusMessagesGetAttachment.TAG, EXCEPTION_LIBRUS_MESSAGES_REQUEST) data.error(ApiError(TAG, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
.withApiResponse(json)) .withApiResponse(json))
} }
} }
@ -85,7 +85,7 @@ class LibrusSandboxDownloadAttachment(override val data: DataLibrus,
private fun downloadAttachment(url: String, method: Int = GET) { private fun downloadAttachment(url: String, method: Int = GET) {
val targetFile = File(Utils.getStorageDir(), attachmentName) val targetFile = File(Utils.getStorageDir(), attachmentName)
sandboxGetFile(LibrusMessagesGetAttachment.TAG, url, targetFile, { file -> sandboxGetFile(TAG, url, targetFile, { file ->
val event = AttachmentGetEvent( val event = AttachmentGetEvent(
profileId, profileId,

View File

@ -58,7 +58,7 @@ class LibrusSynergiaHomework(override val data: DataLibrus,
elements[9].select("input").attr("onclick") elements[9].select("input").attr("onclick")
)?.get(1)?.toLong() ?: return@forEachIndexed )?.get(1)?.toLong() ?: return@forEachIndexed
val lessons = data.db.timetableDao().getForDateNow(profileId, eventDate) val lessons = data.db.timetableDao().getAllForDateNow(profileId, eventDate)
val startTime = lessons.firstOrNull { it.subjectId == subjectId }?.startTime val startTime = lessons.firstOrNull { it.subjectId == subjectId }?.startTime
val seen = when (profile.empty) { val seen = when (profile.empty) {
@ -76,7 +76,8 @@ class LibrusSynergiaHomework(override val data: DataLibrus,
type = Event.TYPE_HOMEWORK, type = Event.TYPE_HOMEWORK,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId, subjectId = subjectId,
teamId = data.teamClass?.id ?: -1 teamId = data.teamClass?.id ?: -1,
addedDate = addedDate.inMillis
) )
data.eventList.add(eventObject) data.eventList.add(eventObject)
@ -85,8 +86,7 @@ class LibrusSynergiaHomework(override val data: DataLibrus,
Metadata.TYPE_HOMEWORK, Metadata.TYPE_HOMEWORK,
id, id,
seen, seen,
seen, seen
addedDate.inMillis
)) ))
} }
} }

View File

@ -10,6 +10,7 @@ import im.wangchao.mhttp.body.MediaTypeUtils
import im.wangchao.mhttp.callback.TextCallbackHandler import im.wangchao.mhttp.callback.TextCallbackHandler
import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.LibrusRecaptchaHelper
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.getUnixDate import pl.szczodrzynski.edziennik.getUnixDate
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
@ -35,6 +36,19 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
onSuccess() onSuccess()
} }
text?.contains("grecaptcha.ready") == true -> {
val url = response?.request()?.url()?.toString() ?: run {
data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
return
}
LibrusRecaptchaHelper(data.app, url, text, onSuccess = { newUrl ->
loginWithSynergia(newUrl)
}, onTimeout = {
data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_TIMEOUT, response, text)
})
}
text?.contains("<status>ok</status>") == true -> { text?.contains("<status>ok</status>") == true -> {
saveSessionId(response, text) saveSessionId(response, text)
onSuccess() onSuccess()
@ -46,6 +60,7 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
text?.contains("<status>error</status>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ERROR, 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("<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) text?.contains("<error>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
else -> data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
} }
} }

View File

@ -6,7 +6,10 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.api
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik
import pl.szczodrzynski.edziennik.data.db.entity.Attendance import pl.szczodrzynski.edziennik.data.db.entity.Attendance
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.* import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSENT
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSENT_EXCUSED
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESENT
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_RELEASED
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
class MobidziennikApiAttendance(val data: DataMobidziennik, rows: List<String>) { class MobidziennikApiAttendance(val data: DataMobidziennik, rows: List<String>) {
@ -23,7 +26,7 @@ class MobidziennikApiAttendance(val data: DataMobidziennik, rows: List<String>)
val id = cols[0].toLong() val id = cols[0].toLong()
val lessonId = cols[1].toLong() val lessonId = cols[1].toLong()
data.mobiLessons.singleOrNull { it.id == lessonId }?.let { lesson -> data.mobiLessons.singleOrNull { it.id == lessonId }?.let { lesson ->
val type = when (cols[4]) { val baseType = when (cols[4]) {
"2" -> TYPE_ABSENT "2" -> TYPE_ABSENT
"5" -> TYPE_ABSENT_EXCUSED "5" -> TYPE_ABSENT_EXCUSED
"4" -> TYPE_RELEASED "4" -> TYPE_RELEASED
@ -31,16 +34,37 @@ class MobidziennikApiAttendance(val data: DataMobidziennik, rows: List<String>)
} }
val semester = data.profile?.dateToSemester(lesson.date) ?: 1 val semester = data.profile?.dateToSemester(lesson.date) ?: 1
val typeName = when (baseType) {
TYPE_ABSENT -> "nieobecność"
TYPE_ABSENT_EXCUSED -> "nieobecność usprawiedliwiona"
TYPE_RELEASED -> "zwolnienie"
TYPE_PRESENT -> "obecność"
else -> "nieznany rodzaj"
}
val typeSymbol = when (baseType) {
TYPE_ABSENT -> "|"
TYPE_ABSENT_EXCUSED -> "+"
TYPE_RELEASED -> "z"
TYPE_PRESENT -> "."
else -> "?"
}
val attendanceObject = Attendance( val attendanceObject = Attendance(
data.profileId, profileId = data.profileId,
id, id = id,
lesson.teacherId, baseType = baseType,
lesson.subjectId, typeName = typeName,
semester, typeShort = data.app.attendanceManager.getTypeShort(baseType),
lesson.topic, typeSymbol = typeSymbol,
lesson.date, typeColor = null,
lesson.startTime, date = lesson.date,
type) startTime = lesson.startTime,
semester = semester,
teacherId = lesson.teacherId,
subjectId = lesson.subjectId
).also {
it.lessonTopic = lesson.topic
}
data.attendanceList.add(attendanceObject) data.attendanceList.add(attendanceObject)
data.metadataList.add( data.metadataList.add(
@ -48,9 +72,8 @@ class MobidziennikApiAttendance(val data: DataMobidziennik, rows: List<String>)
data.profileId, data.profileId,
Metadata.TYPE_ATTENDANCE, Metadata.TYPE_ATTENDANCE,
id, id,
data.profile?.empty ?: false, data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN,
data.profile?.empty ?: false, data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -60,7 +60,9 @@ class MobidziennikApiEvents(val data: DataMobidziennik, rows: List<String>) {
type = type, type = type,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId, subjectId = subjectId,
teamId = teamId) teamId = teamId,
addedDate = addedDate
)
data.eventList.add(eventObject) data.eventList.add(eventObject)
data.metadataList.add( data.metadataList.add(
@ -69,8 +71,7 @@ class MobidziennikApiEvents(val data: DataMobidziennik, rows: List<String>) {
Metadata.TYPE_EVENT, Metadata.TYPE_EVENT,
id, id,
data.profile?.empty ?: false, data.profile?.empty ?: false,
data.profile?.empty ?: false, data.profile?.empty ?: false
addedDate
)) ))
} }
} }

View File

@ -79,7 +79,9 @@ class MobidziennikApiGrades(val data: DataMobidziennik, rows: List<String>) {
comment = null, comment = null,
semester = semester, semester = semester,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId) subjectId = subjectId,
addedDate = addedDate
)
if (data.profile?.empty == true) { if (data.profile?.empty == true) {
addedDate = data.profile.dateSemester1Start.inMillis addedDate = data.profile.dateSemester1Start.inMillis
@ -92,8 +94,7 @@ class MobidziennikApiGrades(val data: DataMobidziennik, rows: List<String>) {
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
data.profile?.empty ?: false, data.profile?.empty ?: false,
data.profile?.empty ?: false, data.profile?.empty ?: false
addedDate
)) ))
addedDate++ addedDate++
} }

View File

@ -40,7 +40,8 @@ class MobidziennikApiHomework(val data: DataMobidziennik, rows: List<String>) {
type = Event.TYPE_HOMEWORK, type = Event.TYPE_HOMEWORK,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId, subjectId = subjectId,
teamId = teamId) teamId = teamId
)
data.eventList.add(eventObject) data.eventList.add(eventObject)
data.metadataList.add( data.metadataList.add(
@ -49,8 +50,7 @@ class MobidziennikApiHomework(val data: DataMobidziennik, rows: List<String>) {
Metadata.TYPE_HOMEWORK, Metadata.TYPE_HOMEWORK,
id, id,
data.profile?.empty ?: false, data.profile?.empty ?: false,
data.profile?.empty ?: false, data.profile?.empty ?: false
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -33,12 +33,16 @@ class MobidziennikApiNotices(val data: DataMobidziennik, rows: List<String>) {
val addedDate = Date.fromYmd(cols[7]).inMillis val addedDate = Date.fromYmd(cols[7]).inMillis
val noticeObject = Notice( val noticeObject = Notice(
data.profileId, profileId = data.profileId,
id, id = id,
text, type = type,
semester, semester = semester,
type, text = text,
teacherId) category = null,
points = null,
teacherId = teacherId,
addedDate = addedDate
)
data.noticeList.add(noticeObject) data.noticeList.add(noticeObject)
data.metadataList.add( data.metadataList.add(
@ -47,8 +51,7 @@ class MobidziennikApiNotices(val data: DataMobidziennik, rows: List<String>) {
Metadata.TYPE_NOTICE, Metadata.TYPE_NOTICE,
id, id,
data.profile?.empty ?: false, data.profile?.empty ?: false,
data.profile?.empty ?: false, data.profile?.empty ?: false
addedDate
)) ))
} }
}} }}

View File

@ -8,9 +8,9 @@ import android.util.SparseArray
import androidx.core.util.set import androidx.core.util.set
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
import pl.szczodrzynski.edziennik.data.db.entity.LessonRange import pl.szczodrzynski.edziennik.data.db.entity.LessonRange
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
import pl.szczodrzynski.edziennik.fixName import pl.szczodrzynski.edziennik.fixName
import pl.szczodrzynski.edziennik.keys import pl.szczodrzynski.edziennik.keys
import pl.szczodrzynski.edziennik.singleOrNull import pl.szczodrzynski.edziennik.singleOrNull
@ -97,8 +97,7 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
Metadata.TYPE_LESSON_CHANGE, Metadata.TYPE_LESSON_CHANGE,
it.id, it.id,
seen, seen,
seen, seen
System.currentTimeMillis()
)) ))
} }
data.lessonList += it data.lessonList += it

View File

@ -17,9 +17,9 @@ class MobidziennikLuckyNumberExtractor(val data: DataMobidziennik, text: String)
val luckyNumber = it.groupValues[1].toInt() val luckyNumber = it.groupValues[1].toInt()
val luckyNumberObject = LuckyNumber( val luckyNumberObject = LuckyNumber(
data.profileId, profileId = data.profileId,
Date.getToday(), date = Date.getToday(),
luckyNumber number = luckyNumber
) )
data.luckyNumberList.add(luckyNumberObject) data.luckyNumberList.add(luckyNumberObject)
@ -29,8 +29,7 @@ class MobidziennikLuckyNumberExtractor(val data: DataMobidziennik, text: String)
Metadata.TYPE_LUCKY_NUMBER, Metadata.TYPE_LUCKY_NUMBER,
luckyNumberObject.date.value.toLong(), luckyNumberObject.date.value.toLong(),
true, true,
data.profile?.empty ?: false, data.profile?.empty ?: false
System.currentTimeMillis()
)) ))
} catch (_: Exception){} } catch (_: Exception){}
} }

View File

@ -11,7 +11,13 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.ENDPOINT_MOBID
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikWeb import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikWeb
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
import pl.szczodrzynski.edziennik.data.db.entity.Attendance import pl.szczodrzynski.edziennik.data.db.entity.Attendance
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.* import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSENT
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSENT_EXCUSED
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_BELATED
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESENT
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESENT_CUSTOM
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_RELEASED
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_UNKNOWN
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.fixName import pl.szczodrzynski.edziennik.fixName
@ -71,6 +77,18 @@ class MobidziennikWebAttendance(override val data: DataMobidziennik,
val start = System.currentTimeMillis() val start = System.currentTimeMillis()
val types = Regexes.MOBIDZIENNIK_ATTENDANCE_TYPES
.find(text)
?.get(1)
?.split("<br/>")
?.map {
it.trimEnd(',')
.split(" ", limit = 2)
.let { it.getOrNull(0) to it.getOrNull(1) }
}
?.toMap()
val typeSymbols = types?.keys?.filterNotNull() ?: listOf()
Regexes.MOBIDZIENNIK_ATTENDANCE_TABLE.findAll(text).forEach { tableResult -> Regexes.MOBIDZIENNIK_ATTENDANCE_TABLE.findAll(text).forEach { tableResult ->
val table = tableResult[1] val table = tableResult[1]
val lessonDates = mutableListOf<Date>() val lessonDates = mutableListOf<Date>()
@ -92,55 +110,84 @@ class MobidziennikWebAttendance(override val data: DataMobidziennik,
return@forEach return@forEach
ranges.forEach { range -> ranges.forEach { range ->
val lessonDate = dateIterator.next() val lessonDate = dateIterator.next()
val entry = entriesIterator.next() var entry = entriesIterator.next()
if (entry.isBlank()) if (entry.isBlank())
return@forEach return@forEach
val startTime = Time.fromH_m(range[1]) val startTime = Time.fromH_m(range[1])
val entryIterator = entry.iterator()
range[2].split(" / ").mapNotNull { Regexes.MOBIDZIENNIK_ATTENDANCE_LESSON.find(it) }.forEachIndexed { index, lesson -> range[2].split(" / ").mapNotNull { Regexes.MOBIDZIENNIK_ATTENDANCE_LESSON.find(it) }.forEachIndexed { index, lesson ->
val topic = lesson[2] val topic = lesson[1].substringAfter(" - ", missingDelimiterValue = "").takeIf { it.isNotBlank() }
if (topic.startsWith("Lekcja odwołana: ") || !entryIterator.hasNext()) if (topic?.startsWith("Lekcja odwołana: ") == true || entry.isEmpty())
return@forEachIndexed return@forEachIndexed
val subjectName = lesson[1] val subjectName = lesson[1].substringBefore(" - ")
//val team = lesson[3] //val team = lesson[3]
val teacherName = lesson[4].fixName() val teacherName = lesson[3].fixName()
val teacherId = data.teacherList.singleOrNull { it.fullNameLastFirst == teacherName }?.id ?: -1 val teacherId = data.teacherList.singleOrNull { it.fullNameLastFirst == teacherName }?.id ?: -1
val subjectId = data.subjectList.singleOrNull { it.longName == subjectName }?.id ?: -1 val subjectId = data.subjectList.singleOrNull { it.longName == subjectName }?.id ?: -1
val type = when (entryIterator.nextChar()) { var typeSymbol = ""
'.' -> TYPE_PRESENT for (symbol in typeSymbols) {
'|' -> TYPE_ABSENT if (entry.startsWith(symbol) && symbol.length > typeSymbol.length)
'+' -> TYPE_ABSENT_EXCUSED typeSymbol = symbol
's' -> TYPE_BELATED
'z' -> TYPE_RELEASED
else -> TYPE_PRESENT
} }
entry = entry.removePrefix(typeSymbol)
var isCounted = true
val baseType = when (typeSymbol) {
"." -> TYPE_PRESENT
"|" -> TYPE_ABSENT
"+" -> TYPE_ABSENT_EXCUSED
"s" -> TYPE_BELATED
"z" -> TYPE_RELEASED
else -> {
isCounted = false
when (typeSymbol) {
"e" -> TYPE_PRESENT_CUSTOM
"en" -> TYPE_ABSENT
"ep" -> TYPE_PRESENT_CUSTOM
else -> TYPE_UNKNOWN
}
}
}
val typeName = types?.get(typeSymbol) ?: ""
val typeShort = when (baseType) {
TYPE_UNKNOWN -> typeSymbol
else -> data.app.attendanceManager.getTypeShort(baseType)
}
val semester = data.profile?.dateToSemester(lessonDate) ?: 1 val semester = data.profile?.dateToSemester(lessonDate) ?: 1
val id = lessonDate.combineWith(startTime) / 6L * 10L + (lesson[0].hashCode() and 0xFFFF) + index val id = lessonDate.combineWith(startTime) / 6L * 10L + (lesson[0].hashCode() and 0xFFFF) + index
val attendanceObject = Attendance( val attendanceObject = Attendance(
data.profileId, profileId = profileId,
id, id = id,
teacherId, baseType = baseType,
subjectId, typeName = typeName,
semester, typeShort = typeShort,
topic, typeSymbol = typeSymbol,
lessonDate, typeColor = null,
startTime, date = lessonDate,
type) startTime = startTime,
semester = semester,
teacherId = teacherId,
subjectId = subjectId
).also {
it.lessonTopic = topic
it.isCounted = isCounted
}
data.attendanceList.add(attendanceObject) data.attendanceList.add(attendanceObject)
if (type != TYPE_PRESENT) { if (baseType != TYPE_PRESENT) {
data.metadataList.add( data.metadataList.add(
Metadata( Metadata(
data.profileId, data.profileId,
Metadata.TYPE_ATTENDANCE, Metadata.TYPE_ATTENDANCE,
id, id,
data.profile?.empty ?: false, data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN,
data.profile?.empty ?: false, data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -89,8 +89,8 @@ class MobidziennikWebCalendar(override val data: DataMobidziennik,
Metadata.TYPE_EVENT, Metadata.TYPE_EVENT,
eventObject.id, eventObject.id,
profile?.empty ?: false, profile?.empty ?: false,
profile?.empty ?: false, profile?.empty ?: false
System.currentTimeMillis() /* no addedDate here though */ /* no addedDate here though */
)) ))
} }
} }

View File

@ -29,14 +29,14 @@ class MobidziennikWebGetAttachment(override val data: DataMobidziennik,
val typeUrl = when (owner) { val typeUrl = when (owner) {
is Message -> if (owner.type == Message.TYPE_SENT) is Message -> if (owner.type == Message.TYPE_SENT)
"dziennik/wiadwyslana?id=" "dziennik/wiadwyslana/?id="
else else
"dziennik/wiadodebrana?id=" "dziennik/wiadodebrana/?id="
is Event -> if (owner.date >= Date.getToday()) is Event -> if (owner.date >= Date.getToday())
"mobile/zadaniadomowe?id_zadania=" "dziennik/wyslijzadanie/?id_zadania="
else else
"mobile/zadaniadomowearchiwalne?id_zadania=" "dziennik/wyslijzadanie/?id_zadania="
else -> "" else -> ""
} }
@ -47,7 +47,7 @@ class MobidziennikWebGetAttachment(override val data: DataMobidziennik,
else -> -1 else -> -1
} }
webGetFile(TAG, "/$typeUrl${ownerId}&zalacznik=$attachmentId", targetFile, { file -> webGetFile(TAG, "/$typeUrl${ownerId}&uczen=${data.studentId}&zalacznik=$attachmentId", targetFile, { file ->
val event = AttachmentGetEvent( val event = AttachmentGetEvent(
profileId, profileId,

View File

@ -39,9 +39,9 @@ class MobidziennikWebGetHomework(override val data: DataMobidziennik,
event.attachmentIds = mutableListOf() event.attachmentIds = mutableListOf()
event.attachmentNames = mutableListOf() event.attachmentNames = mutableListOf()
Regexes.MOBIDZIENNIK_HOMEWORK_ATTACHMENT.findAll(tableRow).onEach { Regexes.MOBIDZIENNIK_HOMEWORK_ATTACHMENT.findAll(tableRow).forEach {
event.attachmentIds?.add(it[1].toLongOrNull() ?: return@onEach) event.attachmentIds?.add(it[2].toLongOrNull() ?: return@forEach)
event.attachmentNames?.add(it[2]) event.attachmentNames?.add(it[3])
} }
event.homeworkBody = "" event.homeworkBody = ""

View File

@ -139,8 +139,7 @@ class MobidziennikWebGetMessage(override val data: DataMobidziennik,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
message.id, message.id,
true, true,
true, true
message.addedDate
)) ))
} }

View File

@ -125,7 +125,8 @@ class MobidziennikWebGrades(override val data: DataMobidziennik,
comment = null, comment = null,
semester = gradeSemester, semester = gradeSemester,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId subjectId = subjectId,
addedDate = gradeAddedDateMillis
) )
gradeObject.classAverage = gradeClassAverage gradeObject.classAverage = gradeClassAverage
@ -137,8 +138,7 @@ class MobidziennikWebGrades(override val data: DataMobidziennik,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
gradeObject.id, gradeObject.id,
profile.empty, profile.empty,
profile.empty, profile.empty
gradeAddedDateMillis
)) ))
} }
} }

View File

@ -77,11 +77,12 @@ class MobidziennikWebMessagesAll(override val data: DataMobidziennik,
type = type, type = type,
subject = subject, subject = subject,
body = null, body = null,
senderId = senderId senderId = senderId,
addedDate = addedDate
) )
data.messageList.add(message) data.messageList.add(message)
data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true, addedDate)) data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true))
} }
// sync every 7 days as we probably don't expect more than // sync every 7 days as we probably don't expect more than

View File

@ -63,7 +63,8 @@ class MobidziennikWebMessagesInbox(override val data: DataMobidziennik,
type = Message.TYPE_RECEIVED, type = Message.TYPE_RECEIVED,
subject = subject, subject = subject,
body = null, body = null,
senderId = senderId senderId = senderId,
addedDate = addedDate
) )
if (hasAttachments) if (hasAttachments)
@ -76,8 +77,7 @@ class MobidziennikWebMessagesInbox(override val data: DataMobidziennik,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
message.id, message.id,
isRead, isRead,
isRead || profile?.empty ?: false, isRead || profile?.empty ?: false
addedDate
)) ))
} }

View File

@ -78,7 +78,8 @@ class MobidziennikWebMessagesSent(override val data: DataMobidziennik,
type = Message.TYPE_SENT, type = Message.TYPE_SENT,
subject = subject, subject = subject,
body = null, body = null,
senderId = null senderId = null,
addedDate = addedDate
) )
if (hasAttachments) if (hasAttachments)
@ -91,8 +92,7 @@ class MobidziennikWebMessagesSent(override val data: DataMobidziennik,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
message.id, message.id,
true, true,
true, true
addedDate
)) ))
} }

View File

@ -45,7 +45,7 @@ class MobidziennikWebSendMessage(override val data: DataMobidziennik,
MobidziennikWebMessagesAll(data, null) { MobidziennikWebMessagesAll(data, null) {
val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject } val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject }
val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id } val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id }
val event = MessageSentEvent(data.profileId, message, metadata?.addedDate) val event = MessageSentEvent(data.profileId, message, message?.addedDate)
EventBus.getDefault().postSticky(event) EventBus.getDefault().postSticky(event)
onSuccess() onSuccess()

View File

@ -5,26 +5,31 @@
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan
import com.google.gson.JsonObject import com.google.gson.JsonObject
import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_API import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.data.api.edziennik.helper.OneDriveDownloadAttachment
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanData import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanData
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiAttachments
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiMessagesChangeStatus import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiMessagesChangeStatus
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiSendMessage import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiSendMessage
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.firstlogin.VulcanFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.firstlogin.VulcanFirstLogin
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLogin import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLogin
import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.data.api.prepare
import pl.szczodrzynski.edziennik.data.api.prepareFor
import pl.szczodrzynski.edziennik.data.api.vulcanLoginMethods
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.entity.Teacher import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.EventFull
import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull
import pl.szczodrzynski.edziennik.utils.Utils
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
import java.io.File
class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface { class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
companion object { companion object {
@ -87,9 +92,30 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
override fun getMessage(message: MessageFull) { override fun getMessage(message: MessageFull) {
login(LOGIN_METHOD_VULCAN_API) { login(LOGIN_METHOD_VULCAN_API) {
if (message.attachmentIds != null) {
VulcanApiMessagesChangeStatus(data, message) { VulcanApiMessagesChangeStatus(data, message) {
completed() completed()
} }
return@login
}
val list = data.app.db.messageDao().getAllNow(data.profileId)
VulcanApiAttachments(data, list, message, MessageFull::class) { _ ->
list.forEach {
if (it.attachmentIds == null)
it.attachmentIds = mutableListOf()
data.messageList.add(it)
}
data.messageListReplace = true
if (message.seen) {
EventBus.getDefault().postSticky(MessageGetEvent(message))
completed()
return@VulcanApiAttachments
}
VulcanApiMessagesChangeStatus(data, message) {
completed()
}
}
} }
} }
@ -103,9 +129,66 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
override fun markAllAnnouncementsAsRead() {} override fun markAllAnnouncementsAsRead() {}
override fun getAnnouncement(announcement: AnnouncementFull) {} override fun getAnnouncement(announcement: AnnouncementFull) {}
override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {}
override fun getRecipientList() {} override fun getRecipientList() {}
override fun getEvent(eventFull: EventFull) {}
override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {
val fileUrl = attachmentName.substringAfter(":")
if (attachmentName == fileUrl) {
data.error(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD))
return
}
OneDriveDownloadAttachment(
app,
fileUrl,
onSuccess = { file ->
val event = AttachmentGetEvent(
data.profileId,
owner,
attachmentId,
AttachmentGetEvent.TYPE_FINISHED,
file.absolutePath
)
val attachmentDataFile = File(Utils.getStorageDir(), ".${data.profileId}_${event.ownerId}_${event.attachmentId}")
Utils.writeStringToFile(attachmentDataFile, event.fileName)
EventBus.getDefault().postSticky(event)
completed()
},
onProgress = { written, total ->
val event = AttachmentGetEvent(
data.profileId,
owner,
attachmentId,
AttachmentGetEvent.TYPE_PROGRESS,
bytesWritten = written
)
EventBus.getDefault().postSticky(event)
},
onError = { apiError ->
data.error(apiError)
}
)
}
override fun getEvent(eventFull: EventFull) {
login(LOGIN_METHOD_VULCAN_API) {
val list = data.app.db.eventDao().getAllNow(data.profileId).filter { !it.addedManually }
VulcanApiAttachments(data, list, eventFull, EventFull::class) { _ ->
list.forEach {
it.homeworkBody = ""
data.eventList.add(it)
}
data.eventListReplace = true
EventBus.getDefault().postSticky(EventGetEvent(eventFull))
completed()
}
}
}
override fun firstLogin() { VulcanFirstLogin(data) { completed() } } override fun firstLogin() { VulcanFirstLogin(data) { completed() } }
override fun cancel() { override fun cancel() {

View File

@ -0,0 +1,124 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-6.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api
import pl.szczodrzynski.edziennik.asJsonObjectList
import pl.szczodrzynski.edziennik.data.api.VULCAN_API_ENDPOINT_HOMEWORK_ATTACHMENTS
import pl.szczodrzynski.edziennik.data.api.VULCAN_API_ENDPOINT_MESSAGES_ATTACHMENTS
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi
import pl.szczodrzynski.edziennik.data.db.full.EventFull
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
import pl.szczodrzynski.edziennik.getJsonArray
import pl.szczodrzynski.edziennik.getLong
import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.models.Date
import kotlin.reflect.KClass
class VulcanApiAttachments(override val data: DataVulcan,
val list: List<*>,
val owner: Any?,
val ownerClass: KClass<*>,
val onSuccess: (list: List<*>) -> Unit
) : VulcanApi(data, null) {
companion object {
const val TAG = "VulcanApiAttachments"
}
init { run {
val endpoint = when (ownerClass) {
MessageFull::class -> VULCAN_API_ENDPOINT_MESSAGES_ATTACHMENTS
EventFull::class -> VULCAN_API_ENDPOINT_HOMEWORK_ATTACHMENTS
else -> null
} ?: return@run
val idName = when (ownerClass) {
MessageFull::class -> "IdWiadomosc"
EventFull::class -> "IdZadanieDomowe"
else -> null
} ?: return@run
val startDate = profile?.getSemesterStart(profile?.currentSemester ?: 1)?.inUnix ?: 0
val endDate = Date.getToday().stepForward(0, 1, 0).inUnix
apiGet(TAG, endpoint, parameters = mapOf(
"DataPoczatkowa" to startDate,
"DataKoncowa" to endDate,
"LoginId" to data.studentLoginId,
"IdUczen" to data.studentId
)) { json, _ ->
json.getJsonArray("Data")?.asJsonObjectList()?.forEach { attachment ->
val id = attachment.getLong("Id") ?: return@forEach
val itemId = attachment.getLong(idName) ?: return@forEach
val url = attachment.getString("Url") ?: return@forEach
val fileName = "${attachment.getString("NazwaPliku")}:$url"
list.forEach {
if (it is MessageFull
&& it.profileId == profileId
&& it.id == itemId
&& it.attachmentIds?.contains(id) != true) {
if (it.attachmentIds == null)
it.attachmentIds = mutableListOf()
if (it.attachmentNames == null)
it.attachmentNames = mutableListOf()
it.attachmentIds?.add(id)
it.attachmentNames?.add(fileName)
}
if (it is EventFull
&& it.profileId == profileId
&& it.id == itemId
&& it.attachmentIds?.contains(id) != true) {
if (it.attachmentIds == null)
it.attachmentIds = mutableListOf()
if (it.attachmentNames == null)
it.attachmentNames = mutableListOf()
it.attachmentIds?.add(id)
it.attachmentNames?.add(fileName)
}
if (owner is MessageFull
&& it is MessageFull
&& owner.profileId == it.profileId
&& owner.id == it.id) {
owner.attachmentIds = it.attachmentIds
owner.attachmentNames = it.attachmentNames
}
if (owner is EventFull
&& it is EventFull
&& owner.profileId == it.profileId
&& owner.id == it.id) {
owner.attachmentIds = it.attachmentIds
owner.attachmentNames = it.attachmentNames
}
}
}
/*if (owner is MessageFull) {
list.forEach {
(it as? MessageFull)?.let { message ->
data.messageList.add(message)
}
}
data.messageListReplace = true
}
if (owner is EventFull) {
list.forEach {
(it as? EventFull)?.let { it1 ->
it1.homeworkBody = ""
data.eventList.add(it1)
}
}
data.eventListReplace = true
}*/
onSuccess(list)
}
}}
}

View File

@ -7,7 +7,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_API_ATTENDANCE import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_API_ATTENDANCE
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi
import pl.szczodrzynski.edziennik.data.db.entity.Attendance import pl.szczodrzynski.edziennik.data.db.entity.Attendance
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.TYPE_PRESENT import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESENT
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
@ -38,38 +38,43 @@ class VulcanApiAttendance(override val data: DataVulcan,
json.getJsonObject("Data")?.getJsonArray("Frekwencje")?.forEach { attendanceEl -> json.getJsonObject("Data")?.getJsonArray("Frekwencje")?.forEach { attendanceEl ->
val attendance = attendanceEl.asJsonObject val attendance = attendanceEl.asJsonObject
val attendanceCategory = data.attendanceTypes.get(attendance.getLong("IdKategoria") ?: return@forEach) val type = data.attendanceTypes.get(attendance.getLong("IdKategoria") ?: return@forEach)
?: return@forEach ?: return@forEach
val type = attendanceCategory.type
val id = (attendance.getInt("Dzien") ?: 0) + (attendance.getInt("Numer") ?: 0) val id = (attendance.getInt("Dzien") ?: 0) + (attendance.getInt("Numer") ?: 0)
val lessonDateMillis = Date.fromY_m_d(attendance.getString("DzienTekst")).inMillis val lessonDateMillis = Date.fromY_m_d(attendance.getString("DzienTekst")).inMillis
val lessonDate = Date.fromMillis(lessonDateMillis) val lessonDate = Date.fromMillis(lessonDateMillis)
val startTime = data.lessonRanges.get(attendance.getInt("Numer") ?: 0)?.startTime
val lessonSemester = profile.dateToSemester(lessonDate) val lessonSemester = profile.dateToSemester(lessonDate)
val attendanceObject = Attendance( val attendanceObject = Attendance(
profileId, profileId = profileId,
id.toLong(), id = id.toLong(),
-1, baseType = type.baseType,
attendance.getLong("IdPrzedmiot") ?: -1, typeName = type.typeName,
lessonSemester, typeShort = type.typeShort,
attendance.getString("PrzedmiotNazwa") + attendanceCategory.name.let { " - $it" }, typeSymbol = type.typeSymbol,
lessonDate, typeColor = type.typeColor,
data.lessonRanges.get(attendance.getInt("Numer") ?: 0)?.startTime, date = lessonDate,
type) startTime = startTime,
semester = lessonSemester,
teacherId = -1,
subjectId = attendance.getLong("IdPrzedmiot") ?: -1,
addedDate = lessonDate.combineWith(startTime)
).also {
it.lessonNumber = attendance.getInt("Numer")
}
data.attendanceList.add(attendanceObject) data.attendanceList.add(attendanceObject)
if (attendanceObject.type != TYPE_PRESENT) { if (type.baseType != TYPE_PRESENT) {
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_ATTENDANCE, Metadata.TYPE_ATTENDANCE,
attendanceObject.id, attendanceObject.id,
profile.empty, profile.empty || type.baseType == Attendance.TYPE_PRESENT_CUSTOM || type.baseType == Attendance.TYPE_UNKNOWN,
profile.empty, profile.empty || type.baseType == Attendance.TYPE_PRESENT_CUSTOM || type.baseType == Attendance.TYPE_UNKNOWN
attendanceObject.lessonDate.combineWith(attendanceObject.startTime)
)) ))
} }
} }

View File

@ -114,11 +114,11 @@ class VulcanApiDictionaries(override val data: DataVulcan,
private fun saveAttendanceType(attendanceType: JsonObject) { private fun saveAttendanceType(attendanceType: JsonObject) {
val id = attendanceType.getLong("Id") ?: return val id = attendanceType.getLong("Id") ?: return
val name = attendanceType.getString("Nazwa") ?: "" val typeName = attendanceType.getString("Nazwa") ?: ""
val absent = attendanceType.getBoolean("Nieobecnosc") ?: false val absent = attendanceType.getBoolean("Nieobecnosc") ?: false
val excused = attendanceType.getBoolean("Usprawiedliwione") ?: false val excused = attendanceType.getBoolean("Usprawiedliwione") ?: false
val type = if (absent) { val baseType = if (absent) {
if (excused) if (excused)
Attendance.TYPE_ABSENT_EXCUSED Attendance.TYPE_ABSENT_EXCUSED
else else
@ -137,15 +137,35 @@ class VulcanApiDictionaries(override val data: DataVulcan,
else if (present) else if (present)
Attendance.TYPE_PRESENT Attendance.TYPE_PRESENT
else else
Attendance.TYPE_CUSTOM Attendance.TYPE_UNKNOWN
}
val (typeColor, typeSymbol) = when (id.toInt()) {
1 -> 0xffffffff to "" // obecność
2 -> 0xffffa687 to "" // nieobecność
3 -> 0xfffcc150 to "u" // nieobecność usprawiedliwiona
4 -> 0xffede049 to "s" // spóźnienie
5 -> 0xffbbdd5f to "su" // spóźnienie usprawiedliwione
6 -> 0xffa9c9fd to "ns" // nieobecny z przyczyn szkolnych
7 -> 0xffddbbe5 to "z" // zwolniony
8 -> 0xffffffff to "" // usunięty wpis
else -> null to "?"
}
val typeShort = when (id.toInt()) {
6 -> "ns" // nieobecny z przyczyn szkolnych
8 -> "" // usunięty wpis
else -> data.app.attendanceManager.getTypeShort(baseType)
} }
val attendanceTypeObject = AttendanceType( val attendanceTypeObject = AttendanceType(
profileId, profileId,
id, id,
name, baseType,
type, typeName,
-1 typeShort,
typeSymbol,
typeColor?.toInt()
) )
data.attendanceTypes.put(id, attendanceTypeObject) data.attendanceTypes.put(id, attendanceTypeObject)

View File

@ -59,7 +59,7 @@ class VulcanApiEvents(override val data: DataVulcan,
val teacherId = event.getLong("IdPracownik") ?: -1 val teacherId = event.getLong("IdPracownik") ?: -1
val topic = event.getString("Opis")?.trim() ?: "" val topic = event.getString("Opis")?.trim() ?: ""
val lessonList = data.db.timetableDao().getForDateNow(profileId, eventDate) val lessonList = data.db.timetableDao().getAllForDateNow(profileId, eventDate)
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime
val type = when (isHomework) { val type = when (isHomework) {
@ -90,8 +90,7 @@ class VulcanApiEvents(override val data: DataVulcan,
if (isHomework) Metadata.TYPE_HOMEWORK else Metadata.TYPE_EVENT, if (isHomework) Metadata.TYPE_HOMEWORK else Metadata.TYPE_EVENT,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
System.currentTimeMillis()
)) ))
} }

View File

@ -101,7 +101,8 @@ class VulcanApiGrades(override val data: DataVulcan,
comment = null, comment = null,
semester = data.studentSemesterNumber, semester = data.studentSemesterNumber,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId subjectId = subjectId,
addedDate = addedDate
) )
data.gradeList.add(gradeObject) data.gradeList.add(gradeObject)
@ -110,9 +111,7 @@ class VulcanApiGrades(override val data: DataVulcan,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }

View File

@ -37,8 +37,7 @@ class VulcanApiMessagesChangeStatus(override val data: DataVulcan,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
messageObject.id, messageObject.id,
true, true,
true, true
messageObject.addedDate
)) ))
messageObject.seen = true messageObject.seen = true

View File

@ -72,7 +72,8 @@ class VulcanApiMessagesInbox(override val data: DataVulcan,
type = TYPE_RECEIVED, type = TYPE_RECEIVED,
subject = subject, subject = subject,
body = body.replace("\n", "<br>"), body = body.replace("\n", "<br>"),
senderId = senderId senderId = senderId,
addedDate = sentDate
) )
val messageRecipientObject = MessageRecipient( val messageRecipientObject = MessageRecipient(
@ -90,8 +91,7 @@ class VulcanApiMessagesInbox(override val data: DataVulcan,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
id, id,
readDate > 0, readDate > 0,
readDate > 0, readDate > 0
sentDate
)) ))
} }

View File

@ -97,7 +97,8 @@ class VulcanApiMessagesSent(override val data: DataVulcan,
type = TYPE_SENT, type = TYPE_SENT,
subject = subject, subject = subject,
body = body.replace("\n", "<br>"), body = body.replace("\n", "<br>"),
senderId = null senderId = null,
addedDate = sentDate
) )
data.messageList.add(messageObject) data.messageList.add(messageObject)
@ -106,8 +107,7 @@ class VulcanApiMessagesSent(override val data: DataVulcan,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
id, id,
true, true,
true, true
sentDate
)) ))
} }

View File

@ -16,7 +16,6 @@ import pl.szczodrzynski.edziennik.getJsonArray
import pl.szczodrzynski.edziennik.getLong import pl.szczodrzynski.edziennik.getLong
import pl.szczodrzynski.edziennik.getString import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.toSparseArray import pl.szczodrzynski.edziennik.toSparseArray
import pl.szczodrzynski.edziennik.utils.models.Date
class VulcanApiNotices(override val data: DataVulcan, class VulcanApiNotices(override val data: DataVulcan,
override val lastSync: Long?, override val lastSync: Long?,
@ -41,15 +40,21 @@ class VulcanApiNotices(override val data: DataVulcan,
val id = notice.getLong("Id") ?: return@forEach val id = notice.getLong("Id") ?: return@forEach
val text = notice.getString("TrescUwagi") ?: return@forEach val text = notice.getString("TrescUwagi") ?: return@forEach
val teacherId = notice.getLong("IdPracownik") ?: -1 val teacherId = notice.getLong("IdPracownik") ?: -1
val addedDate = Date.fromY_m_d(notice.getString("DataWpisuTekst")).inMillis val addedDate = notice.getLong("DataModyfikacji")?.times(1000) ?: System.currentTimeMillis()
val categoryId = notice.getLong("IdKategoriaUwag") ?: -1
val categoryText = data.noticeTypes[categoryId]?.name ?: ""
val noticeObject = Notice( val noticeObject = Notice(
profileId, profileId = profileId,
id, id = id,
text, type = Notice.TYPE_NEUTRAL,
profile.currentSemester, semester = profile.currentSemester,
Notice.TYPE_NEUTRAL, text = text,
teacherId category = categoryText,
points = null,
teacherId = teacherId,
addedDate = addedDate
) )
data.noticeList.add(noticeObject) data.noticeList.add(noticeObject)
@ -58,8 +63,7 @@ class VulcanApiNotices(override val data: DataVulcan,
Metadata.TYPE_NOTICE, Metadata.TYPE_NOTICE,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }

View File

@ -82,8 +82,7 @@ class VulcanApiProposedGrades(override val data: DataVulcan,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
gradeObject.id, gradeObject.id,
data.profile?.empty ?: false, data.profile?.empty ?: false,
data.profile?.empty ?: false, data.profile?.empty ?: false
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -54,7 +54,7 @@ class VulcanApiSendMessage(override val data: DataVulcan,
VulcanApiMessagesSent(data, null) { VulcanApiMessagesSent(data, null) {
val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject } val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject }
val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == messageId } val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == messageId }
val event = MessageSentEvent(data.profileId, message, metadata?.addedDate) val event = MessageSentEvent(data.profileId, message, message?.addedDate)
EventBus.getDefault().postSticky(event) EventBus.getDefault().postSticky(event)
onSuccess() onSuccess()

View File

@ -184,8 +184,7 @@ class VulcanApiTimetable(override val data: DataVulcan,
Metadata.TYPE_LESSON_CHANGE, Metadata.TYPE_LESSON_CHANGE,
lessonObject.id, lessonObject.id,
seen, seen,
seen, seen
System.currentTimeMillis()
)) ))
} }

View File

@ -88,6 +88,7 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
var teacherOnConflictStrategy = OnConflictStrategy.IGNORE var teacherOnConflictStrategy = OnConflictStrategy.IGNORE
var eventListReplace = false var eventListReplace = false
var messageListReplace = false var messageListReplace = false
var announcementListReplace = false
val classrooms = LongSparseArray<Classroom>() val classrooms = LongSparseArray<Classroom>()
val attendanceTypes = LongSparseArray<AttendanceType>() val attendanceTypes = LongSparseArray<AttendanceType>()
@ -120,7 +121,6 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
val attendanceList = mutableListOf<Attendance>() val attendanceList = mutableListOf<Attendance>()
val announcementList = mutableListOf<Announcement>() val announcementList = mutableListOf<Announcement>()
val announcementIgnoreList = mutableListOf<Announcement>()
val luckyNumberList = mutableListOf<LuckyNumber>() val luckyNumberList = mutableListOf<LuckyNumber>()
@ -178,7 +178,6 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
noticeList.clear() noticeList.clear()
attendanceList.clear() attendanceList.clear()
announcementList.clear() announcementList.clear()
announcementIgnoreList.clear()
luckyNumberList.clear() luckyNumberList.clear()
teacherAbsenceList.clear() teacherAbsenceList.clear()
messageList.clear() messageList.clear()
@ -197,6 +196,13 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
profile.userCode = generateUserCode() profile.userCode = generateUserCode()
// update profile subname with class name, school year and account type
profile.subname = joinNotNullStrings(
" - ",
profile.studentClassName,
"${profile.studentSchoolYearStart}/${profile.studentSchoolYearStart + 1}"
) + " " + app.getString(if (profile.isParent) R.string.login_summary_account_parent else R.string.login_summary_account_child)
db.profileDao().add(profile) db.profileDao().add(profile)
db.loginStoreDao().add(loginStore) db.loginStoreDao().add(loginStore)
@ -277,39 +283,19 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
d("Metadata saved in ${System.currentTimeMillis()-startTime} ms") d("Metadata saved in ${System.currentTimeMillis()-startTime} ms")
startTime = System.currentTimeMillis() startTime = System.currentTimeMillis()
if (lessonList.isNotEmpty()) { db.timetableDao().putAll(lessonList, removeNotKept = true)
db.timetableDao() += lessonList db.gradeDao().putAll(gradeList, removeNotKept = true)
} db.eventDao().putAll(eventList, forceReplace = eventListReplace, removeNotKept = true)
if (gradeList.isNotEmpty()) {
db.gradeDao().addAll(gradeList)
}
if (eventList.isNotEmpty()) {
if (eventListReplace)
db.eventDao().replaceAll(eventList)
else
db.eventDao().upsertAll(eventList, removeNotKept = true)
}
if (noticeList.isNotEmpty()) { if (noticeList.isNotEmpty()) {
db.noticeDao().clear(profile.id) db.noticeDao().clear(profile.id)
db.noticeDao().addAll(noticeList) db.noticeDao().putAll(noticeList)
} }
if (attendanceList.isNotEmpty()) db.attendanceDao().putAll(attendanceList, removeNotKept = true)
db.attendanceDao().addAll(attendanceList) db.announcementDao().putAll(announcementList, forceReplace = announcementListReplace, removeNotKept = false)
if (announcementList.isNotEmpty()) db.luckyNumberDao().putAll(luckyNumberList)
db.announcementDao().addAll(announcementList) db.teacherAbsenceDao().putAll(teacherAbsenceList)
if (announcementIgnoreList.isNotEmpty())
db.announcementDao().addAllIgnore(announcementIgnoreList)
if (luckyNumberList.isNotEmpty())
db.luckyNumberDao().addAll(luckyNumberList)
if (teacherAbsenceList.isNotEmpty())
db.teacherAbsenceDao().addAll(teacherAbsenceList)
if (messageList.isNotEmpty()) { db.messageDao().putAll(messageList, forceReplace = messageListReplace, removeNotKept = false)
if (messageListReplace)
db.messageDao().replaceAll(messageList)
else
db.messageDao().upsertAll(messageList, removeNotKept = false) // TODO dataRemoveModel for messages
}
if (messageRecipientList.isNotEmpty()) if (messageRecipientList.isNotEmpty())
db.messageRecipientDao().addAll(messageRecipientList) db.messageRecipientDao().addAll(messageRecipientList)
if (messageRecipientIgnoreList.isNotEmpty()) if (messageRecipientIgnoreList.isNotEmpty())
@ -350,7 +336,7 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
} }
fun shouldSyncLuckyNumber(): Boolean { fun shouldSyncLuckyNumber(): Boolean {
return (db.luckyNumberDao().getNearestFutureNow(profileId, Date.getToday().value) ?: -1) == -1 return db.luckyNumberDao().getNearestFutureNow(profileId, Date.getToday()) == null
} }
/*fun error(tag: String, errorCode: Int, response: Response? = null, throwable: Throwable? = null, apiResponse: JsonObject? = null) { /*fun error(tag: String, errorCode: Int, response: Response? = null, throwable: Throwable? = null, apiResponse: JsonObject? = null) {

View File

@ -20,10 +20,10 @@ open class DataRemoveModel {
fun commit(profileId: Int, dao: TimetableDao) { fun commit(profileId: Int, dao: TimetableDao) {
if (dateFrom != null && dateTo != null) { if (dateFrom != null && dateTo != null) {
dao.clearBetweenDates(profileId, dateFrom, dateTo) dao.dontKeepBetweenDates(profileId, dateFrom, dateTo)
} else { } else {
dateFrom?.let { dateFrom -> dao.clearFromDate(profileId, dateFrom) } dateFrom?.let { dateFrom -> dao.dontKeepFromDate(profileId, dateFrom) }
dateTo?.let { dateTo -> dao.clearToDate(profileId, dateTo) } dateTo?.let { dateTo -> dao.dontKeepToDate(profileId, dateTo) }
} }
} }
} }
@ -69,7 +69,7 @@ open class DataRemoveModel {
fun commit(profileId: Int, dao: AttendanceDao) { fun commit(profileId: Int, dao: AttendanceDao) {
if (dateFrom != null) { if (dateFrom != null) {
dao.clearAfterDate(profileId, dateFrom) dao.dontKeepAfterDate(profileId, dateFrom)
} }
} }
} }

View File

@ -39,13 +39,13 @@ object Signing {
val appPassword by lazy { val appPassword by lazy {
iLoveApple( iLoveApple(
"ThisIsOurHardWorkPleaseDoNotCopyOrSteal(c)2019.KubaSz".sha256(), "ThisIsOurHardWorkPleaseDoNotCopyOrSteal(c)2019.KubaSz".sha256(),
BuildConfig.VERSION_NAME, BuildConfig.VERSION_NAME.substringBeforeLast('+'),
BuildConfig.VERSION_CODE.toLong() BuildConfig.VERSION_CODE.toLong()
) )
} }
/*fun provideKey(param1: String, param2: Long): ByteArray {*/ /*fun provideKey(param1: String, param2: Long): ByteArray {*/
fun pleaseStopRightNow(param1: String, param2: Long): ByteArray { fun pleaseStopRightNow(param1: String, param2: Long): ByteArray {
return "$param1.MTIzNDU2Nzg5MD43hCWBBS===.$param2".sha256() return "$param1.MTIzNDU2Nzg5MDwwzwp5Gx===.$param2".sha256()
} }
} }

View File

@ -40,8 +40,7 @@ class AppSync(val app: App, val notifications: MutableList<Notification>, val pr
Metadata.TYPE_EVENT, Metadata.TYPE_EVENT,
event.id, event.id,
isPast || markAsSeen || event.seen, isPast || markAsSeen || event.seen,
isPast || markAsSeen || event.notified, isPast || markAsSeen || event.notified
event.addedDate
) )
}) })
return app.db.eventDao().upsertAll(events).size return app.db.eventDao().upsertAll(events).size

View File

@ -53,7 +53,7 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
profileId = lesson.profileId, profileId = lesson.profileId,
profileName = profiles.singleOrNull { it.id == lesson.profileId }?.name, profileName = profiles.singleOrNull { it.id == lesson.profileId }?.name,
viewId = MainActivity.DRAWER_ITEM_TIMETABLE, viewId = MainActivity.DRAWER_ITEM_TIMETABLE,
addedDate = lesson.addedDate addedDate = System.currentTimeMillis()
).addExtra("timetableDate", lesson.displayDate?.stringY_m_d ?: "") ).addExtra("timetableDate", lesson.displayDate?.stringY_m_d ?: "")
} }
} }
@ -117,7 +117,7 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
} }
private fun gradeNotifications() { private fun gradeNotifications() {
for (grade in app.db.gradeDao().notNotifiedNow) { for (grade in app.db.gradeDao().getNotNotifiedNow()) {
val gradeName = when (grade.type) { val gradeName = when (grade.type) {
Grade.TYPE_SEMESTER1_PROPOSED, Grade.TYPE_SEMESTER2_PROPOSED -> app.getString(R.string.grade_semester_proposed_format_2, grade.name) Grade.TYPE_SEMESTER1_PROPOSED, Grade.TYPE_SEMESTER2_PROPOSED -> app.getString(R.string.grade_semester_proposed_format_2, grade.name)
Grade.TYPE_SEMESTER1_FINAL, Grade.TYPE_SEMESTER2_FINAL -> app.getString(R.string.grade_semester_final_format_2, grade.name) Grade.TYPE_SEMESTER1_FINAL, Grade.TYPE_SEMESTER2_FINAL -> app.getString(R.string.grade_semester_final_format_2, grade.name)
@ -144,7 +144,7 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
} }
private fun behaviourNotifications() { private fun behaviourNotifications() {
for (notice in app.db.noticeDao().notNotifiedNow) { for (notice in app.db.noticeDao().getNotNotifiedNow()) {
val noticeTypeStr = when (notice.type) { val noticeTypeStr = when (notice.type) {
Notice.TYPE_POSITIVE -> app.getString(R.string.notification_notice_praise) Notice.TYPE_POSITIVE -> app.getString(R.string.notification_notice_praise)
@ -155,7 +155,7 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
val text = app.getString( val text = app.getString(
R.string.notification_notice_format, R.string.notification_notice_format,
noticeTypeStr, noticeTypeStr,
notice.teacherFullName, notice.teacherName,
Date.fromMillis(notice.addedDate).formattedString Date.fromMillis(notice.addedDate).formattedString
) )
notifications += Notification( notifications += Notification(
@ -172,9 +172,9 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
} }
private fun attendanceNotifications() { private fun attendanceNotifications() {
for (attendance in app.db.attendanceDao().notNotifiedNow) { for (attendance in app.db.attendanceDao().getNotNotifiedNow()) {
val attendanceTypeStr = when (attendance.type) { val attendanceTypeStr = when (attendance.baseType) {
Attendance.TYPE_ABSENT -> app.getString(R.string.notification_absence) Attendance.TYPE_ABSENT -> app.getString(R.string.notification_absence)
Attendance.TYPE_ABSENT_EXCUSED -> app.getString(R.string.notification_absence_excused) Attendance.TYPE_ABSENT_EXCUSED -> app.getString(R.string.notification_absence_excused)
Attendance.TYPE_BELATED -> app.getString(R.string.notification_belated) Attendance.TYPE_BELATED -> app.getString(R.string.notification_belated)
@ -191,7 +191,7 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
R.string.notification_attendance_format, R.string.notification_attendance_format,
attendanceTypeStr, attendanceTypeStr,
attendance.subjectLongName, attendance.subjectLongName,
attendance.lessonDate.formattedString attendance.date.formattedString
) )
notifications += Notification( notifications += Notification(
id = Notification.buildId(attendance.profileId, Notification.TYPE_NEW_ATTENDANCE, attendance.id), id = Notification.buildId(attendance.profileId, Notification.TYPE_NEW_ATTENDANCE, attendance.id),
@ -207,10 +207,10 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
} }
private fun announcementNotifications() { private fun announcementNotifications() {
for (announcement in app.db.announcementDao().notNotifiedNow) { for (announcement in app.db.announcementDao().getNotNotifiedNow()) {
val text = app.getString( val text = app.getString(
R.string.notification_announcement_format, R.string.notification_announcement_format,
announcement.teacherFullName, announcement.teacherName,
announcement.subject announcement.subject
) )
notifications += Notification( notifications += Notification(
@ -247,9 +247,9 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
} }
private fun luckyNumberNotifications() { private fun luckyNumberNotifications() {
val luckyNumbers = app.db.luckyNumberDao().notNotifiedNow val luckyNumbers = app.db.luckyNumberDao().getNotNotifiedNow().toMutableList()
luckyNumbers?.removeAll { it.date < today } luckyNumbers.removeAll { it.date < today }
luckyNumbers?.forEach { luckyNumber -> luckyNumbers.forEach { luckyNumber ->
val profile = profiles.singleOrNull { it.id == luckyNumber.profileId } ?: return@forEach val profile = profiles.singleOrNull { it.id == luckyNumber.profileId } ?: return@forEach
val text = when (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) { val text = when (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) {
true -> when (luckyNumber.date.value) { true -> when (luckyNumber.date.value) {
@ -271,7 +271,7 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
profileId = luckyNumber.profileId, profileId = luckyNumber.profileId,
profileName = profile.name, profileName = profile.name,
viewId = MainActivity.DRAWER_ITEM_HOME, viewId = MainActivity.DRAWER_ITEM_HOME,
addedDate = luckyNumber.addedDate addedDate = System.currentTimeMillis()
) )
} }
} }
@ -280,7 +280,7 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
for (teacherAbsence in app.db.teacherAbsenceDao().getNotNotifiedNow()) { for (teacherAbsence in app.db.teacherAbsenceDao().getNotNotifiedNow()) {
val message = app.getString( val message = app.getString(
R.string.notification_teacher_absence_new_format, R.string.notification_teacher_absence_new_format,
teacherAbsence.teacherFullName teacherAbsence.teacherName
) )
notifications += Notification( notifications += Notification(
id = Notification.buildId(teacherAbsence.profileId, Notification.TYPE_TEACHER_ABSENCE, teacherAbsence.id), id = Notification.buildId(teacherAbsence.profileId, Notification.TYPE_TEACHER_ABSENCE, teacherAbsence.id),

View File

@ -43,7 +43,7 @@ import pl.szczodrzynski.edziennik.data.db.migration.*
LibrusLesson::class, LibrusLesson::class,
TimetableManual::class, TimetableManual::class,
Metadata::class Metadata::class
], version = 85) ], version = 87)
@TypeConverters( @TypeConverters(
ConverterTime::class, ConverterTime::class,
ConverterDate::class, ConverterDate::class,
@ -170,7 +170,9 @@ abstract class AppDb : RoomDatabase() {
Migration82(), Migration82(),
Migration83(), Migration83(),
Migration84(), Migration84(),
Migration85() Migration85(),
Migration86(),
Migration87()
).allowMainThreadQueries().build() ).allowMainThreadQueries().build()
} }
} }

View File

@ -1,82 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-1-6
*/
package pl.szczodrzynski.edziennik.data.db.dao;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import androidx.room.RawQuery;
import androidx.sqlite.db.SimpleSQLiteQuery;
import androidx.sqlite.db.SupportSQLiteQuery;
import java.util.List;
import pl.szczodrzynski.edziennik.data.db.entity.Announcement;
import pl.szczodrzynski.edziennik.data.db.entity.Metadata;
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull;
import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_ANNOUNCEMENT;
@Dao
public abstract class AnnouncementDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
public abstract long add(Announcement announcement);
@Insert(onConflict = OnConflictStrategy.REPLACE)
public abstract void addAll(List<Announcement> announcementList);
@Insert(onConflict = OnConflictStrategy.IGNORE)
public abstract void addAllIgnore(List<Announcement> announcementList);
@Query("DELETE FROM announcements WHERE profileId = :profileId")
public abstract void clear(int profileId);
@RawQuery(observedEntities = {Announcement.class, Metadata.class})
abstract LiveData<List<AnnouncementFull>> getAll(SupportSQLiteQuery query);
public LiveData<List<AnnouncementFull>> getAll(int profileId, String filter) {
return getAll(new SimpleSQLiteQuery("SELECT \n" +
"*, \n" +
"teachers.teacherName || ' ' || teachers.teacherSurname AS teacherFullName\n" +
"FROM announcements \n" +
"LEFT JOIN teachers USING(profileId, teacherId)\n" +
"LEFT JOIN metadata ON announcementId = thingId AND thingType = "+TYPE_ANNOUNCEMENT+" AND metadata.profileId = "+profileId+"\n" +
"WHERE announcements.profileId = "+profileId+" AND "+filter+"\n" +
"ORDER BY addedDate DESC"));
}
public LiveData<List<AnnouncementFull>> getAll(int profileId) {
return getAll(profileId, "1");
}
public LiveData<List<AnnouncementFull>> getAllWhere(int profileId, String filter) {
return getAll(profileId, filter);
}
@RawQuery(observedEntities = {Announcement.class, Metadata.class})
abstract List<AnnouncementFull> getAllNow(SupportSQLiteQuery query);
public List<AnnouncementFull> getAllNow(int profileId, String filter) {
return getAllNow(new SimpleSQLiteQuery("SELECT \n" +
"*, \n" +
"teachers.teacherName || ' ' || teachers.teacherSurname AS teacherFullName\n" +
"FROM announcements \n" +
"LEFT JOIN teachers USING(profileId, teacherId)\n" +
"LEFT JOIN metadata ON announcementId = thingId AND thingType = "+TYPE_ANNOUNCEMENT+" AND metadata.profileId = "+profileId+"\n" +
"WHERE announcements.profileId = "+profileId+" AND "+filter+"\n" +
"ORDER BY addedDate DESC"));
}
public List<AnnouncementFull> getNotNotifiedNow(int profileId) {
return getAllNow(profileId, "notified = 0");
}
@Query("SELECT " +
"*, " +
"teachers.teacherName || ' ' || teachers.teacherSurname AS teacherFullName " +
"FROM announcements " +
"LEFT JOIN teachers USING(profileId, teacherId) " +
"LEFT JOIN metadata ON announcementId = thingId AND thingType = "+TYPE_ANNOUNCEMENT+" AND metadata.profileId = announcements.profileId " +
"WHERE notified = 0 " +
"ORDER BY addedDate DESC")
public abstract List<AnnouncementFull> getNotNotifiedNow();
}

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-25.
*/
package pl.szczodrzynski.edziennik.data.db.dao
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Query
import androidx.room.RawQuery
import androidx.sqlite.db.SupportSQLiteQuery
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.annotation.SelectiveDao
import pl.szczodrzynski.edziennik.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.Announcement
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
@Dao
@SelectiveDao(db = AppDb::class)
abstract class AnnouncementDao : BaseDao<Announcement, AnnouncementFull> {
companion object {
private const val QUERY = """
SELECT
*,
teachers.teacherName ||" "|| teachers.teacherSurname AS teacherName
FROM announcements
LEFT JOIN teachers USING(profileId, teacherId)
LEFT JOIN metadata ON announcementId = thingId AND thingType = ${Metadata.TYPE_ANNOUNCEMENT} AND metadata.profileId = announcements.profileId
"""
private const val ORDER_BY = """ORDER BY addedDate DESC"""
}
private val selective by lazy { AnnouncementDaoSelective(App.db) }
@RawQuery(observedEntities = [Announcement::class])
abstract override fun getRaw(query: SupportSQLiteQuery): LiveData<List<AnnouncementFull>>
@RawQuery(observedEntities = [Announcement::class])
abstract override fun getOne(query: SupportSQLiteQuery): LiveData<AnnouncementFull?>
// SELECTIVE UPDATE
@UpdateSelective(primaryKeys = ["profileId", "announcementId"], skippedColumns = ["addedDate", "announcementText"])
override fun update(item: Announcement) = selective.update(item)
override fun updateAll(items: List<Announcement>) = selective.updateAll(items)
// CLEAR
@Query("DELETE FROM announcements WHERE profileId = :profileId")
abstract override fun clear(profileId: Int)
// REMOVE NOT KEPT
@Query("DELETE FROM announcements WHERE keep = 0")
abstract override fun removeNotKept()
// GET ALL - LIVE DATA
fun getAll(profileId: Int) =
getRaw("$QUERY WHERE announcements.profileId = $profileId $ORDER_BY")
// GET ALL - NOW
fun getAllNow(profileId: Int) =
getRawNow("$QUERY WHERE announcements.profileId = $profileId $ORDER_BY")
fun getNotNotifiedNow() =
getRawNow("$QUERY WHERE notified = 0 $ORDER_BY")
fun getNotNotifiedNow(profileId: Int) =
getRawNow("$QUERY WHERE announcements.profileId = $profileId AND notified = 0 $ORDER_BY")
// GET ONE - NOW
fun getByIdNow(profileId: Int, id: Long) =
getOneNow("$QUERY WHERE announcements.profileId = $profileId AND announcementId = $id")
}

View File

@ -1,108 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-1-6
*/
package pl.szczodrzynski.edziennik.data.db.dao;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import androidx.room.RawQuery;
import androidx.sqlite.db.SimpleSQLiteQuery;
import androidx.sqlite.db.SupportSQLiteQuery;
import java.util.List;
import pl.szczodrzynski.edziennik.data.db.entity.Attendance;
import pl.szczodrzynski.edziennik.data.db.full.AttendanceFull;
import pl.szczodrzynski.edziennik.utils.models.Date;
import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_ATTENDANCE;
@Dao
public abstract class AttendanceDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
public abstract long add(Attendance attendance);
@Insert(onConflict = OnConflictStrategy.REPLACE)
public abstract void addAll(List<Attendance> attendanceList);
@Query("DELETE FROM attendances WHERE profileId = :profileId")
public abstract void clear(int profileId);
@Query("DELETE FROM attendances WHERE profileId = :profileId AND attendanceLessonDate > :date")
public abstract void clearAfterDate(int profileId, Date date);
@RawQuery(observedEntities = {Attendance.class})
abstract LiveData<List<AttendanceFull>> getAll(SupportSQLiteQuery query);
public LiveData<List<AttendanceFull>> getAll(int profileId, String filter) {
return getAll(new SimpleSQLiteQuery("SELECT \n" +
"*, \n" +
"teachers.teacherName || ' ' || teachers.teacherSurname AS teacherFullName\n" +
"FROM attendances \n" +
"LEFT JOIN teachers USING(profileId, teacherId)\n" +
"LEFT JOIN subjects USING(profileId, subjectId)\n" +
"LEFT JOIN metadata ON attendanceId = thingId AND thingType = " + TYPE_ATTENDANCE + " AND metadata.profileId = "+profileId+"\n" +
"WHERE attendances.profileId = "+profileId+" AND "+filter+"\n" +
"ORDER BY attendanceLessonDate DESC, attendanceStartTime DESC"));
}
public LiveData<List<AttendanceFull>> getAll(int profileId) {
return getAll(profileId, "1");
}
public LiveData<List<AttendanceFull>> getAllWhere(int profileId, String filter) {
return getAll(profileId, filter);
}
@RawQuery
abstract List<AttendanceFull> getAllNow(SupportSQLiteQuery query);
public List<AttendanceFull> getAllNow(int profileId, String filter) {
return getAllNow(new SimpleSQLiteQuery("SELECT \n" +
"*, \n" +
"teachers.teacherName || ' ' || teachers.teacherSurname AS teacherFullName\n" +
"FROM attendances \n" +
"LEFT JOIN teachers USING(profileId, teacherId)\n" +
"LEFT JOIN subjects USING(profileId, subjectId)\n" +
"LEFT JOIN metadata ON attendanceId = thingId AND thingType = " + TYPE_ATTENDANCE + " AND metadata.profileId = "+profileId+"\n" +
"WHERE attendances.profileId = "+profileId+" AND "+filter+"\n" +
"ORDER BY attendanceLessonDate DESC, attendanceStartTime DESC"));
}
public List<AttendanceFull> getNotNotifiedNow(int profileId) {
return getAllNow(profileId, "notified = 0");
}
@Query("SELECT * FROM attendances " +
"LEFT JOIN subjects USING(profileId, subjectId) " +
"LEFT JOIN metadata ON attendanceId = thingId AND thingType = " + TYPE_ATTENDANCE + " AND metadata.profileId = attendances.profileId " +
"WHERE notified = 0 " +
"ORDER BY attendanceLessonDate DESC, attendanceStartTime DESC")
public abstract List<AttendanceFull> getNotNotifiedNow();
// only absent and absent_excused count as absences
// all the other types are counted as being present
@Query("SELECT \n" +
"CAST(SUM(CASE WHEN attendanceType != "+Attendance.TYPE_ABSENT+" AND attendanceType != "+ Attendance.TYPE_ABSENT_EXCUSED+" THEN 1 ELSE 0 END) AS float)\n" +
" / \n" +
"CAST(count() AS float)*100 \n" +
"FROM attendances \n" +
"WHERE profileId = :profileId")
public abstract LiveData<Float> getAttendancePercentage(int profileId);
@Query("SELECT \n" +
"CAST(SUM(CASE WHEN attendanceType != "+Attendance.TYPE_ABSENT+" AND attendanceType != "+Attendance.TYPE_ABSENT_EXCUSED+" THEN 1 ELSE 0 END) AS float)\n" +
" / \n" +
"CAST(count() AS float)*100 \n" +
"FROM attendances \n" +
"WHERE profileId = :profileId AND attendanceSemester = :semester")
public abstract float getAttendancePercentageNow(int profileId, int semester);
@Query("SELECT \n" +
"CAST(SUM(CASE WHEN attendanceType != "+Attendance.TYPE_ABSENT+" AND attendanceType != "+Attendance.TYPE_ABSENT_EXCUSED+" THEN 1 ELSE 0 END) AS float)\n" +
" / \n" +
"CAST(count() AS float)*100 \n" +
"FROM attendances \n" +
"WHERE profileId = :profileId")
public abstract float getAttendancePercentageNow(int profileId);
}

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