mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-06-21 09:33:06 +02:00
Compare commits
71 Commits
v3.9.5-dev
...
v3.9.12-de
Author | SHA1 | Date | |
---|---|---|---|
462b1df767 | |||
d17d2c8417 | |||
6892832fff | |||
66d54c7c45 | |||
d432685aa8 | |||
37f3d76fb8 | |||
7961a74995 | |||
9d590508ad | |||
f79b7eaf83 | |||
ae13bf946f | |||
f116c4f1f4 | |||
867c8920a8 | |||
6e6dd34872 | |||
0759468fa7 | |||
1b1fb09211 | |||
de414c912c | |||
d274a2fed1 | |||
285b7e9b9e | |||
875efcff7e | |||
07ae37167d | |||
f689f4d427 | |||
19bc2b8b37 | |||
673116e27e | |||
59fcb0a050 | |||
cd76f99bbf | |||
6a4994b9c2 | |||
63960c5e05 | |||
540afb6a28 | |||
ae10b8abbd | |||
db2ebab879 | |||
6ec3d062df | |||
86b6060a09 | |||
83d123e341 | |||
34061695f9 | |||
de68476442 | |||
678a81a44b | |||
cfb3096d53 | |||
9b7aca745a | |||
82852389fa | |||
ce06084e6f | |||
3ca051983f | |||
cd379e4175 | |||
62fdfa2b6f | |||
9866017f7e | |||
67f98b08c6 | |||
fdb5f7ec02 | |||
04c3c7ca6e | |||
f424315d97 | |||
c907a8df37 | |||
37ea65e3fc | |||
a3e5f824c8 | |||
e0c850a455 | |||
1c6815f708 | |||
9a20511935 | |||
965f5e73d9 | |||
13b58a1d56 | |||
0a3261b8b3 | |||
dbdfc7fdd8 | |||
56062f5bfa | |||
0cbba2eb45 | |||
aa84356dd6 | |||
efaad0a4dd | |||
71015c0137 | |||
85b5667a7e | |||
dfdc6817a1 | |||
058345b9c9 | |||
831b7876b4 | |||
729cf6f08e | |||
860a16b32d | |||
9f871c077b | |||
a8f89abf7d |
2
.gitignore
vendored
2
.gitignore
vendored
@ -81,3 +81,5 @@ lint/generated/
|
|||||||
lint/outputs/
|
lint/outputs/
|
||||||
lint/tmp/
|
lint/tmp/
|
||||||
# lint/reports/
|
# lint/reports/
|
||||||
|
|
||||||
|
app/schemas/
|
||||||
|
@ -169,7 +169,7 @@ dependencies {
|
|||||||
|
|
||||||
implementation 'com.github.kuba2k2:RecyclerTabLayout:700f980584'
|
implementation 'com.github.kuba2k2:RecyclerTabLayout:700f980584'
|
||||||
|
|
||||||
implementation 'com.linkedin.android.tachyon:tachyon:1.0.2'
|
implementation 'com.github.kuba2k2:Tachyon:551943a6b5'
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
13
app/sampledata/settings/ic_settings.xml
Normal file
13
app/sampledata/settings/ic_settings.xml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (c) Kuba Szczodrzyński 2019-11-25.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M12,8A4,4 0,0 1,16 12A4,4 0,0 1,12 16A4,4 0,0 1,8 12A4,4 0,0 1,12 8M12,10A2,2 0,0 0,10 12A2,2 0,0 0,12 14A2,2 0,0 0,14 12A2,2 0,0 0,12 10M10,22C9.75,22 9.54,21.82 9.5,21.58L9.13,18.93C8.5,18.68 7.96,18.34 7.44,17.94L4.95,18.95C4.73,19.03 4.46,18.95 4.34,18.73L2.34,15.27C2.21,15.05 2.27,14.78 2.46,14.63L4.57,12.97L4.5,12L4.57,11L2.46,9.37C2.27,9.22 2.21,8.95 2.34,8.73L4.34,5.27C4.46,5.05 4.73,4.96 4.95,5.05L7.44,6.05C7.96,5.66 8.5,5.32 9.13,5.07L9.5,2.42C9.54,2.18 9.75,2 10,2H14C14.25,2 14.46,2.18 14.5,2.42L14.87,5.07C15.5,5.32 16.04,5.66 16.56,6.05L19.05,5.05C19.27,4.96 19.54,5.05 19.66,5.27L21.66,8.73C21.79,8.95 21.73,9.22 21.54,9.37L19.43,11L19.5,12L19.43,13L21.54,14.63C21.73,14.78 21.79,15.05 21.66,15.27L19.66,18.73C19.54,18.95 19.27,19.04 19.05,18.95L16.56,17.95C16.04,18.34 15.5,18.68 14.87,18.93L14.5,21.58C14.46,21.82 14.25,22 14,22H10M11.25,4L10.88,6.61C9.68,6.86 8.62,7.5 7.85,8.39L5.44,7.35L4.69,8.65L6.8,10.2C6.4,11.37 6.4,12.64 6.8,13.8L4.68,15.36L5.43,16.66L7.86,15.62C8.63,16.5 9.68,17.14 10.87,17.38L11.24,20H12.76L13.13,17.39C14.32,17.14 15.37,16.5 16.14,15.62L18.57,16.66L19.32,15.36L17.2,13.81C17.6,12.64 17.6,11.37 17.2,10.2L19.31,8.65L18.56,7.35L16.15,8.39C15.38,7.5 14.32,6.86 13.12,6.62L12.75,4H11.25Z"/>
|
||||||
|
</vector>
|
@ -105,6 +105,11 @@
|
|||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:noHistory="true"
|
android:noHistory="true"
|
||||||
android:theme="@style/AppTheme.NoDisplay" />
|
android:theme="@style/AppTheme.NoDisplay" />
|
||||||
|
<activity android:name=".widgets.timetable.LessonDialogActivity"
|
||||||
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:noHistory="true"
|
||||||
|
android:theme="@style/AppTheme.NoDisplay" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.modules.settings.SettingsLicenseActivity"
|
android:name=".ui.modules.settings.SettingsLicenseActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
@ -68,11 +68,6 @@ import me.leolin.shortcutbadger.ShortcutBadger;
|
|||||||
import okhttp3.ConnectionSpec;
|
import okhttp3.ConnectionSpec;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.TlsVersion;
|
import okhttp3.TlsVersion;
|
||||||
import pl.szczodrzynski.edziennik.data.api.Edziennik;
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Iuczniowie;
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Librus;
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Mobidziennik;
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Vulcan;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.AppDb;
|
import pl.szczodrzynski.edziennik.data.db.AppDb;
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.debuglog.DebugLog;
|
import pl.szczodrzynski.edziennik.data.db.modules.debuglog.DebugLog;
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
||||||
@ -141,12 +136,6 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
|||||||
public PersistentCookieJar cookieJar;
|
public PersistentCookieJar cookieJar;
|
||||||
public OkHttpClient http;
|
public OkHttpClient http;
|
||||||
public OkHttpClient httpLazy;
|
public OkHttpClient httpLazy;
|
||||||
//public Jakdojade apiJakdojade;
|
|
||||||
public Edziennik apiEdziennik;
|
|
||||||
public Mobidziennik apiMobidziennik;
|
|
||||||
public Iuczniowie apiIuczniowie;
|
|
||||||
public Librus apiLibrus;
|
|
||||||
public Vulcan apiVulcan;
|
|
||||||
|
|
||||||
public SharedPreferences appSharedPrefs; // sharedPreferences for APPCONFIG + JOBS STORE
|
public SharedPreferences appSharedPrefs; // sharedPreferences for APPCONFIG + JOBS STORE
|
||||||
public AppConfig appConfig; // APPCONFIG: common for all profiles
|
public AppConfig appConfig; // APPCONFIG: common for all profiles
|
||||||
@ -204,12 +193,6 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
|||||||
db = AppDb.getDatabase(this);
|
db = AppDb.getDatabase(this);
|
||||||
gson = new Gson();
|
gson = new Gson();
|
||||||
networkUtils = new NetworkUtils(this);
|
networkUtils = new NetworkUtils(this);
|
||||||
apiEdziennik = new Edziennik(this);
|
|
||||||
//apiJakdojade = new Jakdojade(this);
|
|
||||||
apiMobidziennik = new Mobidziennik(this);
|
|
||||||
apiIuczniowie = new Iuczniowie(this);
|
|
||||||
apiLibrus = new Librus(this);
|
|
||||||
apiVulcan = new Vulcan(this);
|
|
||||||
|
|
||||||
Iconics.init(getApplicationContext());
|
Iconics.init(getApplicationContext());
|
||||||
Iconics.registerFont(SzkolnyFont.INSTANCE);
|
Iconics.registerFont(SzkolnyFont.INSTANCE);
|
||||||
|
@ -4,7 +4,9 @@ import android.Manifest
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.res.Resources
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.*
|
import android.text.*
|
||||||
@ -13,9 +15,11 @@ import android.text.style.StrikethroughSpan
|
|||||||
import android.text.style.StyleSpan
|
import android.text.style.StyleSpan
|
||||||
import android.util.LongSparseArray
|
import android.util.LongSparseArray
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
|
import android.util.TypedValue
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.widget.CompoundButton
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.*
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.core.util.forEach
|
import androidx.core.util.forEach
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
@ -25,10 +29,13 @@ import com.google.gson.JsonArray
|
|||||||
import com.google.gson.JsonElement
|
import com.google.gson.JsonElement
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import im.wangchao.mhttp.Response
|
import im.wangchao.mhttp.Response
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||||
import pl.szczodrzynski.navlib.R
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
import pl.szczodrzynski.navlib.getColorFromRes
|
import pl.szczodrzynski.navlib.getColorFromRes
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -95,6 +102,15 @@ fun String.swapFirstLastName(): String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun String.getFirstLastName(): Pair<String, String>? {
|
||||||
|
return this.split(" ").let {
|
||||||
|
if (it.size >= 2) Pair(it[0], it[1])
|
||||||
|
else null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.getLastFirstName() = this.getFirstLastName()
|
||||||
|
|
||||||
fun changeStringCase(s: String): String {
|
fun changeStringCase(s: String): String {
|
||||||
val delimiters = " '-/"
|
val delimiters = " '-/"
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
@ -153,8 +169,9 @@ fun colorFromName(context: Context, name: String?): Int {
|
|||||||
return context.getColorFromRes(color)
|
return context.getColorFromRes(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MutableList<out Profile>.filterOutArchived() {
|
fun MutableList<Profile>.filterOutArchived(): MutableList<Profile> {
|
||||||
this.removeAll { it.archived }
|
this.removeAll { it.archived }
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Activity.isStoragePermissionGranted(): Boolean {
|
fun Activity.isStoragePermissionGranted(): Boolean {
|
||||||
@ -361,13 +378,13 @@ fun CharSequence?.asItalicSpannable(): Spannable {
|
|||||||
*/
|
*/
|
||||||
fun <T : CharSequence> listOfNotEmpty(vararg elements: T): List<T> = elements.filterNot { it.isEmpty() }
|
fun <T : CharSequence> listOfNotEmpty(vararg elements: T): List<T> = elements.filterNot { it.isEmpty() }
|
||||||
|
|
||||||
fun List<CharSequence>.concat(delimiter: String? = null): CharSequence {
|
fun List<CharSequence?>.concat(delimiter: String? = null): CharSequence {
|
||||||
if (this.isEmpty()) {
|
if (this.isEmpty()) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.size == 1) {
|
if (this.size == 1) {
|
||||||
return this[0]
|
return this[0] ?: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
var spanned = false
|
var spanned = false
|
||||||
@ -382,6 +399,8 @@ fun List<CharSequence>.concat(delimiter: String? = null): CharSequence {
|
|||||||
if (spanned) {
|
if (spanned) {
|
||||||
val ssb = SpannableStringBuilder()
|
val ssb = SpannableStringBuilder()
|
||||||
for (piece in this) {
|
for (piece in this) {
|
||||||
|
if (piece == null)
|
||||||
|
continue
|
||||||
if (!first && delimiter != null)
|
if (!first && delimiter != null)
|
||||||
ssb.append(delimiter)
|
ssb.append(delimiter)
|
||||||
first = false
|
first = false
|
||||||
@ -391,6 +410,8 @@ fun List<CharSequence>.concat(delimiter: String? = null): CharSequence {
|
|||||||
} else {
|
} else {
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
for (piece in this) {
|
for (piece in this) {
|
||||||
|
if (piece == null)
|
||||||
|
continue
|
||||||
if (!first && delimiter != null)
|
if (!first && delimiter != null)
|
||||||
sb.append(delimiter)
|
sb.append(delimiter)
|
||||||
first = false
|
first = false
|
||||||
@ -404,15 +425,15 @@ fun TextView.setText(@StringRes resid: Int, vararg formatArgs: Any) {
|
|||||||
text = context.getString(resid, *formatArgs)
|
text = context.getString(resid, *formatArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun JsonObject(vararg properties: Pair<String, Any>): JsonObject {
|
fun JsonObject(vararg properties: Pair<String, Any?>): JsonObject {
|
||||||
return JsonObject().apply {
|
return JsonObject().apply {
|
||||||
for (property in properties) {
|
for (property in properties) {
|
||||||
when (property.second) {
|
when (property.second) {
|
||||||
is JsonElement -> add(property.first, property.second as JsonElement)
|
is JsonElement -> add(property.first, property.second as JsonElement?)
|
||||||
is String -> addProperty(property.first, property.second as String)
|
is String -> addProperty(property.first, property.second as String?)
|
||||||
is Char -> addProperty(property.first, property.second as Char)
|
is Char -> addProperty(property.first, property.second as Char?)
|
||||||
is Number -> addProperty(property.first, property.second as Number)
|
is Number -> addProperty(property.first, property.second as Number?)
|
||||||
is Boolean -> addProperty(property.first, property.second as Boolean)
|
is Boolean -> addProperty(property.first, property.second as Boolean?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -428,6 +449,13 @@ inline fun <T : View> T.onClick(crossinline onClickListener: (v: T) -> Unit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
inline fun <T : CompoundButton> T.onChange(crossinline onChangeListener: (v: T, isChecked: Boolean) -> Unit) {
|
||||||
|
setOnCheckedChangeListener { buttonView, isChecked ->
|
||||||
|
onChangeListener(buttonView as T, isChecked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun <T> LiveData<T>.observeOnce(lifecycleOwner: LifecycleOwner, observer: Observer<T>) {
|
fun <T> LiveData<T>.observeOnce(lifecycleOwner: LifecycleOwner, observer: Observer<T>) {
|
||||||
observe(lifecycleOwner, object : Observer<T> {
|
observe(lifecycleOwner, object : Observer<T> {
|
||||||
override fun onChanged(t: T?) {
|
override fun onChanged(t: T?) {
|
||||||
@ -435,4 +463,127 @@ fun <T> LiveData<T>.observeOnce(lifecycleOwner: LifecycleOwner, observer: Observ
|
|||||||
removeObserver(this)
|
removeObserver(this)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a value in dp to pixels.
|
||||||
|
*/
|
||||||
|
val Int.dp: Int
|
||||||
|
get() = (this * Resources.getSystem().displayMetrics.density).toInt()
|
||||||
|
/**
|
||||||
|
* Convert a value in pixels to dp.
|
||||||
|
*/
|
||||||
|
val Int.px: Int
|
||||||
|
get() = (this / Resources.getSystem().displayMetrics.density).toInt()
|
||||||
|
|
||||||
|
@ColorInt
|
||||||
|
fun @receiver:AttrRes Int.resolveAttr(context: Context?): Int {
|
||||||
|
val typedValue = TypedValue()
|
||||||
|
context?.theme?.resolveAttribute(this, typedValue, true)
|
||||||
|
return typedValue.data
|
||||||
|
}
|
||||||
|
@ColorInt
|
||||||
|
fun @receiver:ColorRes Int.resolveColor(context: Context): Int {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
context.resources.getColor(this, context.theme)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
context.resources.getColor(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun @receiver:DrawableRes Int.resolveDrawable(context: Context): Drawable {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
context.resources.getDrawable(this, context.theme)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
context.resources.getDrawable(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun View.findParentById(targetId: Int): View? {
|
||||||
|
if (id == targetId) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
val viewParent = this.parent ?: return null
|
||||||
|
if (viewParent is View) {
|
||||||
|
return viewParent.findParentById(targetId)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun CoroutineScope.startCoroutineTimer(delayMillis: Long = 0, repeatMillis: Long = 0, action: () -> Unit) = launch {
|
||||||
|
delay(delayMillis)
|
||||||
|
if (repeatMillis > 0) {
|
||||||
|
while (true) {
|
||||||
|
action()
|
||||||
|
delay(repeatMillis)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun Time?.compareTo(other: Time?): Int {
|
||||||
|
if (this == null && other == null)
|
||||||
|
return 0
|
||||||
|
if (this == null)
|
||||||
|
return -1
|
||||||
|
if (other == null)
|
||||||
|
return 1
|
||||||
|
return this.compareTo(other)
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun StringBuilder.plusAssign(str: String?) {
|
||||||
|
this.append(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.timeTill(time: Int, delimiter: String = " "): String {
|
||||||
|
val parts = mutableListOf<Pair<Int, Int>>()
|
||||||
|
|
||||||
|
val hours = time / 3600
|
||||||
|
val minutes = (time - hours*3600) / 60
|
||||||
|
val seconds = time - minutes*60 - hours*3600
|
||||||
|
|
||||||
|
var prefixAdded = false
|
||||||
|
if (hours > 0) {
|
||||||
|
if (!prefixAdded) parts += R.plurals.time_till_text to hours; prefixAdded = true
|
||||||
|
parts += R.plurals.time_till_hours to hours
|
||||||
|
}
|
||||||
|
if (minutes > 0) {
|
||||||
|
if (!prefixAdded) parts += R.plurals.time_till_text to minutes; prefixAdded = true
|
||||||
|
parts += R.plurals.time_till_minutes to minutes
|
||||||
|
}
|
||||||
|
if (hours == 0 && minutes < 10) {
|
||||||
|
if (!prefixAdded) parts += R.plurals.time_till_text to seconds; prefixAdded = true
|
||||||
|
parts += R.plurals.time_till_seconds to seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.joinToString(delimiter) { resources.getQuantityString(it.first, it.second, it.second) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.timeLeft(time: Int, delimiter: String = " "): String {
|
||||||
|
val parts = mutableListOf<Pair<Int, Int>>()
|
||||||
|
|
||||||
|
val hours = time / 3600
|
||||||
|
val minutes = (time - hours*3600) / 60
|
||||||
|
val seconds = time - minutes*60 - hours*3600
|
||||||
|
|
||||||
|
var prefixAdded = false
|
||||||
|
if (hours > 0) {
|
||||||
|
if (!prefixAdded) parts += R.plurals.time_left_text to hours
|
||||||
|
prefixAdded = true
|
||||||
|
parts += R.plurals.time_left_hours to hours
|
||||||
|
}
|
||||||
|
if (minutes > 0) {
|
||||||
|
if (!prefixAdded) parts += R.plurals.time_left_text to minutes
|
||||||
|
prefixAdded = true
|
||||||
|
parts += R.plurals.time_left_minutes to minutes
|
||||||
|
}
|
||||||
|
if (hours == 0 && minutes < 10) {
|
||||||
|
if (!prefixAdded) parts += R.plurals.time_left_text to seconds
|
||||||
|
prefixAdded = true
|
||||||
|
parts += R.plurals.time_left_seconds to seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.joinToString(delimiter) { resources.getQuantityString(it.first, it.second, it.second) }
|
||||||
|
}
|
||||||
|
@ -38,23 +38,25 @@ import pl.droidsonroids.gif.GifDrawable
|
|||||||
import pl.szczodrzynski.edziennik.App.APP_URL
|
import pl.szczodrzynski.edziennik.App.APP_URL
|
||||||
import pl.szczodrzynski.edziennik.api.v2.events.*
|
import pl.szczodrzynski.edziennik.api.v2.events.*
|
||||||
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask
|
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata.*
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata.*
|
||||||
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
|
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
|
||||||
import pl.szczodrzynski.edziennik.network.ServerRequest
|
import pl.szczodrzynski.edziennik.network.ServerRequest
|
||||||
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
|
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
|
||||||
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
|
||||||
|
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog
|
||||||
|
import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncViewListDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.agenda.AgendaFragment
|
import pl.szczodrzynski.edziennik.ui.modules.agenda.AgendaFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment
|
import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.attendance.AttendanceFragment
|
import pl.szczodrzynski.edziennik.ui.modules.attendance.AttendanceFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.base.DebugFragment
|
import pl.szczodrzynski.edziennik.ui.modules.base.DebugFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment
|
import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment
|
||||||
|
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment
|
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment
|
import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesFragment
|
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.grades.editor.GradesEditorFragment
|
import pl.szczodrzynski.edziennik.ui.modules.grades.editor.GradesEditorFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment
|
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragmentV2
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment
|
import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
|
import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessageFragment
|
import pl.szczodrzynski.edziennik.ui.modules.messages.MessageFragment
|
||||||
@ -120,9 +122,9 @@ class MainActivity : AppCompatActivity() {
|
|||||||
val list: MutableList<NavTarget> = mutableListOf()
|
val list: MutableList<NavTarget> = mutableListOf()
|
||||||
|
|
||||||
// home item
|
// home item
|
||||||
list += NavTarget(DRAWER_ITEM_HOME, R.string.menu_home_page, HomeFragment::class)
|
list += NavTarget(DRAWER_ITEM_HOME, R.string.menu_home_page, HomeFragmentV2::class)
|
||||||
.withTitle(R.string.app_name)
|
.withTitle(R.string.app_name)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_home)
|
.withIcon(CommunityMaterial.Icon2.cmd_home_outline)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
.isStatic(true)
|
.isStatic(true)
|
||||||
.withPopToHome(false)
|
.withPopToHome(false)
|
||||||
@ -133,50 +135,50 @@ class MainActivity : AppCompatActivity() {
|
|||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_ITEM_AGENDA, R.string.menu_agenda, AgendaFragment::class)
|
list += NavTarget(DRAWER_ITEM_AGENDA, R.string.menu_agenda, AgendaFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_calendar)
|
.withIcon(CommunityMaterial.Icon.cmd_calendar_outline)
|
||||||
.withBadgeTypeId(TYPE_EVENT)
|
.withBadgeTypeId(TYPE_EVENT)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesFragment::class)
|
list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_numeric_5_box)
|
.withIcon(CommunityMaterial.Icon2.cmd_numeric_5_box_outline)
|
||||||
.withBadgeTypeId(TYPE_GRADE)
|
.withBadgeTypeId(TYPE_GRADE)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_ITEM_MESSAGES, R.string.menu_messages, MessagesFragment::class)
|
list += NavTarget(DRAWER_ITEM_MESSAGES, R.string.menu_messages, MessagesFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_email)
|
.withIcon(CommunityMaterial.Icon.cmd_email_outline)
|
||||||
.withBadgeTypeId(TYPE_MESSAGE)
|
.withBadgeTypeId(TYPE_MESSAGE)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_ITEM_HOMEWORK, R.string.menu_homework, HomeworkFragment::class)
|
list += NavTarget(DRAWER_ITEM_HOMEWORK, R.string.menu_homework, HomeworkFragment::class)
|
||||||
.withIcon(SzkolnyFont.Icon.szf_file_document_edit)
|
.withIcon(SzkolnyFont.Icon.szf_notebook_outline)
|
||||||
.withBadgeTypeId(TYPE_HOMEWORK)
|
.withBadgeTypeId(TYPE_HOMEWORK)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_ITEM_BEHAVIOUR, R.string.menu_notices, BehaviourFragment::class)
|
list += NavTarget(DRAWER_ITEM_BEHAVIOUR, R.string.menu_notices, BehaviourFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_message_alert)
|
.withIcon(CommunityMaterial.Icon.cmd_emoticon_outline)
|
||||||
.withBadgeTypeId(TYPE_NOTICE)
|
.withBadgeTypeId(TYPE_NOTICE)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_ITEM_ATTENDANCE, R.string.menu_attendance, AttendanceFragment::class)
|
list += NavTarget(DRAWER_ITEM_ATTENDANCE, R.string.menu_attendance, AttendanceFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_calendar_remove)
|
.withIcon(CommunityMaterial.Icon.cmd_calendar_remove_outline)
|
||||||
.withBadgeTypeId(TYPE_ATTENDANCE)
|
.withBadgeTypeId(TYPE_ATTENDANCE)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_ITEM_ANNOUNCEMENTS, R.string.menu_announcements, AnnouncementsFragment::class)
|
list += NavTarget(DRAWER_ITEM_ANNOUNCEMENTS, R.string.menu_announcements, AnnouncementsFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_bulletin_board)
|
.withIcon(CommunityMaterial.Icon.cmd_bullhorn_outline)
|
||||||
.withBadgeTypeId(TYPE_ANNOUNCEMENT)
|
.withBadgeTypeId(TYPE_ANNOUNCEMENT)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
|
|
||||||
|
|
||||||
// static drawer items
|
// static drawer items
|
||||||
list += NavTarget(DRAWER_ITEM_NOTIFICATIONS, R.string.menu_notifications, NotificationsFragment::class)
|
list += NavTarget(DRAWER_ITEM_NOTIFICATIONS, R.string.menu_notifications, NotificationsFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_bell_ring)
|
.withIcon(CommunityMaterial.Icon.cmd_bell_ring_outline)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
.isStatic(true)
|
.isStatic(true)
|
||||||
.isBelowSeparator(true)
|
.isBelowSeparator(true)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsNewFragment::class)
|
list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsNewFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_settings)
|
.withIcon(CommunityMaterial.Icon2.cmd_settings_outline)
|
||||||
.isInDrawer(true)
|
.isInDrawer(true)
|
||||||
.isStatic(true)
|
.isStatic(true)
|
||||||
.isBelowSeparator(true)
|
.isBelowSeparator(true)
|
||||||
@ -195,7 +197,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
.isInProfileList(false)
|
.isInProfileList(false)
|
||||||
|
|
||||||
list += NavTarget(DRAWER_PROFILE_SYNC_ALL, R.string.menu_sync_all, null)
|
list += NavTarget(DRAWER_PROFILE_SYNC_ALL, R.string.menu_sync_all, null)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_sync)
|
.withIcon(CommunityMaterial.Icon.cmd_download_outline)
|
||||||
.isInProfileList(true)
|
.isInProfileList(true)
|
||||||
|
|
||||||
|
|
||||||
@ -214,6 +216,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
val navView: NavView by lazy { b.navView }
|
val navView: NavView by lazy { b.navView }
|
||||||
val drawer: NavDrawer by lazy { navView.drawer }
|
val drawer: NavDrawer by lazy { navView.drawer }
|
||||||
val bottomSheet: NavBottomSheet by lazy { navView.bottomSheet }
|
val bottomSheet: NavBottomSheet by lazy { navView.bottomSheet }
|
||||||
|
val errorSnackbar: ErrorSnackbar by lazy { ErrorSnackbar(this) }
|
||||||
|
|
||||||
val swipeRefreshLayout: SwipeRefreshLayoutNoTouch by lazy { b.swipeRefreshLayout }
|
val swipeRefreshLayout: SwipeRefreshLayoutNoTouch by lazy { b.swipeRefreshLayout }
|
||||||
|
|
||||||
@ -246,6 +249,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
setContentView(b.root)
|
setContentView(b.root)
|
||||||
|
|
||||||
|
errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
|
||||||
|
|
||||||
navLoading = true
|
navLoading = true
|
||||||
|
|
||||||
b.navView.apply {
|
b.navView.apply {
|
||||||
@ -371,6 +376,11 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
b.swipeRefreshLayout.isEnabled = true
|
b.swipeRefreshLayout.isEnabled = true
|
||||||
b.swipeRefreshLayout.setOnRefreshListener { this.syncCurrentFeature() }
|
b.swipeRefreshLayout.setOnRefreshListener { this.syncCurrentFeature() }
|
||||||
|
b.swipeRefreshLayout.setColorSchemeResources(
|
||||||
|
R.color.md_blue_500,
|
||||||
|
R.color.md_amber_500,
|
||||||
|
R.color.md_green_500
|
||||||
|
)
|
||||||
|
|
||||||
isStoragePermissionGranted()
|
isStoragePermissionGranted()
|
||||||
|
|
||||||
@ -424,7 +434,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
navView.coordinator.postDelayed({
|
navView.coordinator.postDelayed({
|
||||||
CafeBar.builder(this)
|
CafeBar.builder(this)
|
||||||
.content(R.string.rate_snackbar_text)
|
.content(R.string.rate_snackbar_text)
|
||||||
.icon(IconicsDrawable(this).icon(CommunityMaterial.Icon2.cmd_star).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.getPrimaryTextColor(this))))
|
.icon(IconicsDrawable(this).icon(CommunityMaterial.Icon2.cmd_star_outline).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.getPrimaryTextColor(this))))
|
||||||
.positiveText(R.string.rate_snackbar_positive)
|
.positiveText(R.string.rate_snackbar_positive)
|
||||||
.positiveColor(-0xb350b0)
|
.positiveColor(-0xb350b0)
|
||||||
.negativeText(R.string.rate_snackbar_negative)
|
.negativeText(R.string.rate_snackbar_negative)
|
||||||
@ -461,25 +471,25 @@ class MainActivity : AppCompatActivity() {
|
|||||||
bottomSheet.appendItems(
|
bottomSheet.appendItems(
|
||||||
BottomSheetPrimaryItem(false)
|
BottomSheetPrimaryItem(false)
|
||||||
.withTitle(R.string.menu_sync)
|
.withTitle(R.string.menu_sync)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_sync)
|
.withIcon(CommunityMaterial.Icon.cmd_download_outline)
|
||||||
.withOnClickListener(View.OnClickListener {
|
.withOnClickListener(View.OnClickListener {
|
||||||
bottomSheet.close()
|
bottomSheet.close()
|
||||||
app.apiEdziennik.guiSyncFeature(app, this, App.profileId, R.string.sync_dialog_title, R.string.sync_dialog_text, R.string.sync_done, fragmentToFeature(navTargetId))
|
SyncViewListDialog(this, navTargetId)
|
||||||
}),
|
}),
|
||||||
BottomSheetSeparatorItem(false),
|
BottomSheetSeparatorItem(false),
|
||||||
BottomSheetPrimaryItem(false)
|
BottomSheetPrimaryItem(false)
|
||||||
.withTitle(R.string.menu_settings)
|
.withTitle(R.string.menu_settings)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_settings)
|
.withIcon(CommunityMaterial.Icon2.cmd_settings_outline)
|
||||||
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_SETTINGS) }),
|
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_SETTINGS) }),
|
||||||
BottomSheetPrimaryItem(false)
|
BottomSheetPrimaryItem(false)
|
||||||
.withTitle(R.string.menu_feedback)
|
.withTitle(R.string.menu_feedback)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_help_circle)
|
.withIcon(CommunityMaterial.Icon2.cmd_help_circle_outline)
|
||||||
.withOnClickListener(View.OnClickListener { loadTarget(TARGET_FEEDBACK) })
|
.withOnClickListener(View.OnClickListener { loadTarget(TARGET_FEEDBACK) })
|
||||||
)
|
)
|
||||||
if (App.devMode) {
|
if (App.devMode) {
|
||||||
bottomSheet += BottomSheetPrimaryItem(false)
|
bottomSheet += BottomSheetPrimaryItem(false)
|
||||||
.withTitle(R.string.menu_debug)
|
.withTitle(R.string.menu_debug)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_android_debug_bridge)
|
.withIcon(CommunityMaterial.Icon.cmd_android_studio)
|
||||||
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_DEBUG) })
|
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_DEBUG) })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -527,9 +537,14 @@ class MainActivity : AppCompatActivity() {
|
|||||||
DRAWER_ITEM_MESSAGES -> MessagesFragment.pageSelection
|
DRAWER_ITEM_MESSAGES -> MessagesFragment.pageSelection
|
||||||
else -> 0
|
else -> 0
|
||||||
}
|
}
|
||||||
|
val arguments = when (navTargetId) {
|
||||||
|
DRAWER_ITEM_TIMETABLE -> JsonObject("weekStart" to TimetableFragment.pageSelection?.weekStart?.stringY_m_d)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
EdziennikTask.syncProfile(
|
EdziennikTask.syncProfile(
|
||||||
App.profileId,
|
App.profileId,
|
||||||
listOf(navTargetId to fragmentParam)
|
listOf(navTargetId to fragmentParam),
|
||||||
|
arguments
|
||||||
).enqueue(this)
|
).enqueue(this)
|
||||||
}
|
}
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
@ -573,7 +588,12 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onSyncErrorEvent(event: ApiTaskErrorEvent) {
|
fun onSyncErrorEvent(event: ApiTaskErrorEvent) {
|
||||||
|
navView.toolbar.apply {
|
||||||
|
subtitleFormat = R.string.toolbar_subtitle
|
||||||
|
subtitleFormatWithUnread = R.plurals.toolbar_subtitle_with_unread
|
||||||
|
subtitle = "Gotowe"
|
||||||
|
}
|
||||||
|
errorSnackbar.addError(event.error).show()
|
||||||
}
|
}
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||||
fun onAppManagerDetectedEvent(event: AppManagerDetectedEvent) {
|
fun onAppManagerDetectedEvent(event: AppManagerDetectedEvent) {
|
||||||
@ -605,22 +625,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
private fun fragmentToFeature(currentFragment: Int): Int {
|
|
||||||
return when (currentFragment) {
|
|
||||||
DRAWER_ITEM_TIMETABLE -> FEATURE_TIMETABLE
|
|
||||||
DRAWER_ITEM_AGENDA -> FEATURE_AGENDA
|
|
||||||
DRAWER_ITEM_GRADES -> FEATURE_GRADES
|
|
||||||
DRAWER_ITEM_HOMEWORK -> FEATURE_HOMEWORK
|
|
||||||
DRAWER_ITEM_BEHAVIOUR -> FEATURE_NOTICES
|
|
||||||
DRAWER_ITEM_ATTENDANCE -> FEATURE_ATTENDANCE
|
|
||||||
DRAWER_ITEM_MESSAGES -> when (MessagesFragment.pageSelection) {
|
|
||||||
1 -> FEATURE_MESSAGES_OUTBOX
|
|
||||||
else -> FEATURE_MESSAGES_INBOX
|
|
||||||
}
|
|
||||||
DRAWER_ITEM_ANNOUNCEMENTS -> FEATURE_ANNOUNCEMENTS
|
|
||||||
else -> FEATURE_ALL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private fun fragmentToSyncName(currentFragment: Int): Int {
|
private fun fragmentToSyncName(currentFragment: Int): Int {
|
||||||
return when (currentFragment) {
|
return when (currentFragment) {
|
||||||
DRAWER_ITEM_TIMETABLE -> R.string.sync_feature_timetable
|
DRAWER_ITEM_TIMETABLE -> R.string.sync_feature_timetable
|
||||||
@ -694,10 +699,13 @@ class MainActivity : AppCompatActivity() {
|
|||||||
app.profile == null -> {
|
app.profile == null -> {
|
||||||
if (intentProfileId == -1)
|
if (intentProfileId == -1)
|
||||||
intentProfileId = app.appSharedPrefs.getInt("current_profile_id", 1)
|
intentProfileId = app.appSharedPrefs.getInt("current_profile_id", 1)
|
||||||
loadProfile(intentProfileId, intentTargetId)
|
loadProfile(intentProfileId, intentTargetId, extras)
|
||||||
}
|
}
|
||||||
intentProfileId != -1 -> {
|
intentProfileId != -1 -> {
|
||||||
loadProfile(intentProfileId, intentTargetId)
|
if (app.profile.id != intentProfileId)
|
||||||
|
loadProfile(intentProfileId, intentTargetId, extras)
|
||||||
|
else
|
||||||
|
loadTarget(intentTargetId, extras)
|
||||||
}
|
}
|
||||||
intentTargetId != -1 -> {
|
intentTargetId != -1 -> {
|
||||||
drawer.currentProfile = app.profile.id
|
drawer.currentProfile = app.profile.id
|
||||||
@ -1043,7 +1051,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
loadTarget(DRAWER_ITEM_SETTINGS, null)
|
loadTarget(DRAWER_ITEM_SETTINGS, null)
|
||||||
} else if (item.itemId == 2) {
|
} else if (item.itemId == 2) {
|
||||||
app.apiEdziennik.guiRemoveProfile(this@MainActivity, profileId, profile.name?.getText(this).toString())
|
ProfileRemoveDialog(this, profileId, profile.name?.getText(this)?.toString() ?: "?")
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -311,13 +311,14 @@ public class Notifier {
|
|||||||
\____/| .__/ \__,_|\__,_|\__\___||___/
|
\____/| .__/ \__,_|\__,_|\__\___||___/
|
||||||
| |
|
| |
|
||||||
|*/
|
|*/
|
||||||
public void notificationUpdatesShow(String updateVersion, String updateUrl, String updateFilename) {
|
public void notificationUpdatesShow(String updateVersion, String updateUrl, String updateFilename, boolean updateDirect) {
|
||||||
if (!app.appConfig.notifyAboutUpdates)
|
if (!app.appConfig.notifyAboutUpdates)
|
||||||
return;
|
return;
|
||||||
Intent notificationIntent = new Intent(app.getContext(), BootReceiver.NotificationActionService.class)
|
Intent notificationIntent = new Intent(app.getContext(), BootReceiver.NotificationActionService.class)
|
||||||
.putExtra("update_version", updateVersion)
|
.putExtra("update_version", updateVersion)
|
||||||
.putExtra("update_url", updateUrl)
|
.putExtra("update_url", updateUrl)
|
||||||
.putExtra("update_filename", updateFilename);
|
.putExtra("update_filename", updateFilename)
|
||||||
|
.putExtra("update_direct", updateDirect);
|
||||||
|
|
||||||
PendingIntent pendingIntent = PendingIntent.getService(app.getContext(), 0,
|
PendingIntent pendingIntent = PendingIntent.getService(app.getContext(), 0,
|
||||||
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||||
|
@ -1,450 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik;
|
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.appwidget.AppWidgetManager;
|
|
||||||
import android.appwidget.AppWidgetProvider;
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.graphics.PorterDuff;
|
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.util.SparseArray;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.RemoteViews;
|
|
||||||
|
|
||||||
import com.mikepenz.iconics.IconicsColor;
|
|
||||||
import com.mikepenz.iconics.IconicsDrawable;
|
|
||||||
import com.mikepenz.iconics.IconicsSize;
|
|
||||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment;
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.ItemWidgetTimetableModel;
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Week;
|
|
||||||
import pl.szczodrzynski.edziennik.widgets.WidgetConfig;
|
|
||||||
import pl.szczodrzynski.edziennik.widgets.timetable.LessonDetailsActivity;
|
|
||||||
import pl.szczodrzynski.edziennik.widgets.timetable.WidgetTimetableService;
|
|
||||||
|
|
||||||
import static pl.szczodrzynski.edziennik.ExtensionsKt.filterOutArchived;
|
|
||||||
import static pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_HOMEWORK;
|
|
||||||
import static pl.szczodrzynski.edziennik.utils.Utils.bs;
|
|
||||||
|
|
||||||
|
|
||||||
public class WidgetTimetable extends AppWidgetProvider {
|
|
||||||
|
|
||||||
|
|
||||||
public static final String ACTION_SYNC_DATA = "ACTION_SYNC_DATA";
|
|
||||||
private static final String TAG = "WidgetTimetable";
|
|
||||||
private static int modeInt = 0;
|
|
||||||
|
|
||||||
public WidgetTimetable() {
|
|
||||||
// Start the worker thread
|
|
||||||
//HandlerThread sWorkerThread = new HandlerThread("WidgetTimetable-worker");
|
|
||||||
//sWorkerThread.start();
|
|
||||||
//Handler sWorkerQueue = new Handler(sWorkerThread.getLooper());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SparseArray<List<ItemWidgetTimetableModel>> timetables = null;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
if (ACTION_SYNC_DATA.equals(intent.getAction())) {
|
|
||||||
EdziennikTask.Companion.sync().enqueue(context);
|
|
||||||
}
|
|
||||||
super.onReceive(context, intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PendingIntent getPendingSelfIntent(Context context, String action) {
|
|
||||||
Intent intent = new Intent(context, WidgetTimetable.class);
|
|
||||||
intent.setAction(action);
|
|
||||||
return getPendingSelfIntent(context, intent);
|
|
||||||
}
|
|
||||||
public static PendingIntent getPendingSelfIntent(Context context, Intent intent) {
|
|
||||||
return PendingIntent.getBroadcast(context, 0, intent, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Bitmap drawableToBitmap (Drawable drawable) {
|
|
||||||
|
|
||||||
if (drawable instanceof BitmapDrawable) {
|
|
||||||
return ((BitmapDrawable)drawable).getBitmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
|
||||||
Canvas canvas = new Canvas(bitmap);
|
|
||||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
|
||||||
drawable.draw(canvas);
|
|
||||||
|
|
||||||
return bitmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
|
||||||
ComponentName thisWidget = new ComponentName(context, WidgetTimetable.class);
|
|
||||||
|
|
||||||
timetables = new SparseArray<>();
|
|
||||||
//timetables.clear();
|
|
||||||
|
|
||||||
App app = (App)context.getApplicationContext();
|
|
||||||
|
|
||||||
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
|
|
||||||
// There may be multiple widgets active, so update all of them
|
|
||||||
for (int appWidgetId : allWidgetIds) {
|
|
||||||
|
|
||||||
//d(TAG, "thr "+Thread.currentThread().getName());
|
|
||||||
|
|
||||||
WidgetConfig widgetConfig = app.appConfig.widgetTimetableConfigs.get(appWidgetId);
|
|
||||||
if (widgetConfig == null) {
|
|
||||||
widgetConfig = new WidgetConfig(app.profileFirstId());
|
|
||||||
app.appConfig.widgetTimetableConfigs.put(appWidgetId, widgetConfig);
|
|
||||||
app.appConfig.savePending = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoteViews views;
|
|
||||||
if (widgetConfig.bigStyle) {
|
|
||||||
views = new RemoteViews(context.getPackageName(), widgetConfig.darkTheme ? R.layout.widget_timetable_dark_big : R.layout.widget_timetable_big);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
views = new RemoteViews(context.getPackageName(), widgetConfig.darkTheme ? R.layout.widget_timetable_dark : R.layout.widget_timetable);
|
|
||||||
}
|
|
||||||
|
|
||||||
PorterDuff.Mode mode = PorterDuff.Mode.DST_IN;
|
|
||||||
/*if (widgetConfig.darkTheme) {
|
|
||||||
switch (modeInt) {
|
|
||||||
case 0:
|
|
||||||
mode = PorterDuff.Mode.ADD;
|
|
||||||
d(TAG, "ADD");
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
mode = PorterDuff.Mode.DST_ATOP;
|
|
||||||
d(TAG, "DST_ATOP");
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
mode = PorterDuff.Mode.DST_IN;
|
|
||||||
d(TAG, "DST_IN");
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
mode = PorterDuff.Mode.DST_OUT;
|
|
||||||
d(TAG, "DST_OUT");
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
mode = PorterDuff.Mode.DST_OVER;
|
|
||||||
d(TAG, "DST_OVER");
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
mode = PorterDuff.Mode.LIGHTEN;
|
|
||||||
d(TAG, "LIGHTEN");
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
mode = PorterDuff.Mode.MULTIPLY;
|
|
||||||
d(TAG, "MULTIPLY");
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
mode = PorterDuff.Mode.OVERLAY;
|
|
||||||
d(TAG, "OVERLAY");
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
mode = PorterDuff.Mode.SCREEN;
|
|
||||||
d(TAG, "SCREEN");
|
|
||||||
break;
|
|
||||||
case 9:
|
|
||||||
mode = PorterDuff.Mode.SRC_ATOP;
|
|
||||||
d(TAG, "SRC_ATOP");
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
mode = PorterDuff.Mode.SRC_IN;
|
|
||||||
d(TAG, "SRC_IN");
|
|
||||||
break;
|
|
||||||
case 11:
|
|
||||||
mode = PorterDuff.Mode.SRC_OUT;
|
|
||||||
d(TAG, "SRC_OUT");
|
|
||||||
break;
|
|
||||||
case 12:
|
|
||||||
mode = PorterDuff.Mode.SRC_OVER;
|
|
||||||
d(TAG, "SRC_OVER");
|
|
||||||
break;
|
|
||||||
case 13:
|
|
||||||
mode = PorterDuff.Mode.XOR;
|
|
||||||
d(TAG, "XOR");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
modeInt = 0;
|
|
||||||
mode = PorterDuff.Mode.ADD;
|
|
||||||
d(TAG, "ADD");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
|
||||||
// this code seems to crash the launcher on >= P
|
|
||||||
float transparency = widgetConfig.opacity; //0...1
|
|
||||||
long colorFilter = 0x01000000L * (long) (255f * transparency);
|
|
||||||
try {
|
|
||||||
final Method[] declaredMethods = Class.forName("android.widget.RemoteViews").getDeclaredMethods();
|
|
||||||
final int len = declaredMethods.length;
|
|
||||||
if (len > 0) {
|
|
||||||
for (int m = 0; m < len; m++) {
|
|
||||||
final Method method = declaredMethods[m];
|
|
||||||
if (method.getName().equals("setDrawableParameters")) {
|
|
||||||
method.setAccessible(true);
|
|
||||||
method.invoke(views, R.id.widgetTimetableListView, true, -1, (int) colorFilter, mode, -1);
|
|
||||||
method.invoke(views, R.id.widgetTimetableHeader, true, -1, (int) colorFilter, mode, -1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Intent refreshIntent = new Intent(context, WidgetTimetable.class);
|
|
||||||
refreshIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
|
|
||||||
refreshIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
|
|
||||||
PendingIntent pendingRefreshIntent = PendingIntent.getBroadcast(context,
|
|
||||||
0, refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
views.setOnClickPendingIntent(R.id.widgetTimetableRefresh, pendingRefreshIntent);
|
|
||||||
|
|
||||||
views.setOnClickPendingIntent(R.id.widgetTimetableSync, WidgetTimetable.getPendingSelfIntent(context, ACTION_SYNC_DATA));
|
|
||||||
|
|
||||||
views.setImageViewBitmap(R.id.widgetTimetableRefresh, new IconicsDrawable(context, CommunityMaterial.Icon2.cmd_refresh)
|
|
||||||
.color(IconicsColor.colorInt(Color.WHITE))
|
|
||||||
.size(IconicsSize.dp(widgetConfig.bigStyle ? 24 : 16)).toBitmap());
|
|
||||||
|
|
||||||
views.setImageViewBitmap(R.id.widgetTimetableSync, new IconicsDrawable(context, CommunityMaterial.Icon2.cmd_sync)
|
|
||||||
.color(IconicsColor.colorInt(Color.WHITE))
|
|
||||||
.size(IconicsSize.dp(widgetConfig.bigStyle ? 24 : 16)).toBitmap());
|
|
||||||
|
|
||||||
boolean unified = widgetConfig.profileId == -1;
|
|
||||||
|
|
||||||
List<Profile> profileList = new ArrayList<>();
|
|
||||||
if (unified) {
|
|
||||||
profileList = app.db.profileDao().getAllNow();
|
|
||||||
filterOutArchived(profileList);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Profile profile = app.db.profileDao().getFullByIdNow(widgetConfig.profileId);
|
|
||||||
if (profile != null) {
|
|
||||||
profileList.add(profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//d(TAG, "Profiles: "+ Arrays.toString(profileList.toArray()));
|
|
||||||
|
|
||||||
if (profileList == null || profileList.size() == 0) {
|
|
||||||
views.setViewVisibility(R.id.widgetTimetableLoading, View.VISIBLE);
|
|
||||||
views.setTextViewText(R.id.widgetTimetableLoading, app.getString(R.string.widget_timetable_profile_doesnt_exist));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
views.setViewVisibility(R.id.widgetTimetableLoading, View.GONE);
|
|
||||||
//Register profile;
|
|
||||||
|
|
||||||
long bellSyncDiffMillis = 0;
|
|
||||||
if (app.appConfig.bellSyncDiff != null) {
|
|
||||||
bellSyncDiffMillis = app.appConfig.bellSyncDiff.hour * 60 * 60 * 1000 + app.appConfig.bellSyncDiff.minute * 60 * 1000 + app.appConfig.bellSyncDiff.second * 1000;
|
|
||||||
bellSyncDiffMillis *= app.appConfig.bellSyncMultiplier;
|
|
||||||
bellSyncDiffMillis *= -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ItemWidgetTimetableModel> lessonList = new ArrayList<>();
|
|
||||||
|
|
||||||
Time syncedNow = Time.fromMillis(Time.getNow().getInMillis() + bellSyncDiffMillis);
|
|
||||||
|
|
||||||
Date today = Date.getToday();
|
|
||||||
|
|
||||||
int openProfileId = -1;
|
|
||||||
Date displayingDate = null;
|
|
||||||
int displayingWeekDay = 0;
|
|
||||||
if (unified) {
|
|
||||||
views.setTextViewText(R.id.widgetTimetableSubtitle, app.getString(R.string.widget_timetable_title_unified));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
views.setTextViewText(R.id.widgetTimetableSubtitle, profileList.get(0).getName());
|
|
||||||
openProfileId = profileList.get(0).getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<LessonFull> lessons = app.db.lessonDao().getAllWeekNow(unified ? -1 : openProfileId, today.clone().stepForward(0, 0, -today.getWeekDay()), today);
|
|
||||||
|
|
||||||
int scrollPos = 0;
|
|
||||||
|
|
||||||
for (Profile profile: profileList) {
|
|
||||||
Date profileDisplayingDate = HomeFragment.findDateWithLessons(profile.getId(), lessons, syncedNow, 1);
|
|
||||||
int profileDisplayingWeekDay = profileDisplayingDate.getWeekDay();
|
|
||||||
int dayDiff = Date.diffDays(profileDisplayingDate, Date.getToday());
|
|
||||||
|
|
||||||
//d(TAG, "For profile "+profile.name+" displayingDate is "+profileDisplayingDate.getStringY_m_d());
|
|
||||||
if (displayingDate == null || profileDisplayingDate.getValue() < displayingDate.getValue()) {
|
|
||||||
displayingDate = profileDisplayingDate;
|
|
||||||
displayingWeekDay = profileDisplayingWeekDay;
|
|
||||||
//d(TAG, "Setting as global dd");
|
|
||||||
if (dayDiff == 0) {
|
|
||||||
views.setTextViewText(R.id.widgetTimetableTitle, app.getString(R.string.day_today_format, Week.getFullDayName(displayingWeekDay)));
|
|
||||||
} else if (dayDiff == 1) {
|
|
||||||
views.setTextViewText(R.id.widgetTimetableTitle, app.getString(R.string.day_tomorrow_format, Week.getFullDayName(displayingWeekDay)));
|
|
||||||
} else {
|
|
||||||
views.setTextViewText(R.id.widgetTimetableTitle, Week.getFullDayName(displayingWeekDay) + " " + profileDisplayingDate.getStringDm());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Profile profile: profileList) {
|
|
||||||
int pos = 0;
|
|
||||||
|
|
||||||
List<EventFull> events = app.db.eventDao().getAllByDateNow(profile.getId(), displayingDate);
|
|
||||||
if (events == null)
|
|
||||||
events = new ArrayList<>();
|
|
||||||
|
|
||||||
if (unified) {
|
|
||||||
ItemWidgetTimetableModel separator = new ItemWidgetTimetableModel();
|
|
||||||
separator.profileId = profile.getId();
|
|
||||||
separator.bigStyle = widgetConfig.bigStyle;
|
|
||||||
separator.darkTheme = widgetConfig.darkTheme;
|
|
||||||
separator.separatorProfileName = profile.getName();
|
|
||||||
lessonList.add(separator);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (LessonFull lesson : lessons) {
|
|
||||||
//d(TAG, "Profile "+profile.id+" Lesson profileId "+lesson.profileId+" weekDay "+lesson.weekDay+", "+lesson);
|
|
||||||
if (profile.getId() != lesson.profileId || displayingWeekDay != lesson.weekDay)
|
|
||||||
continue;
|
|
||||||
//d(TAG, "Not skipped");
|
|
||||||
ItemWidgetTimetableModel model = new ItemWidgetTimetableModel();
|
|
||||||
|
|
||||||
model.bigStyle = widgetConfig.bigStyle;
|
|
||||||
model.darkTheme = widgetConfig.darkTheme;
|
|
||||||
|
|
||||||
model.profileId = profile.getId();
|
|
||||||
|
|
||||||
model.lessonDate = displayingDate;
|
|
||||||
model.startTime = lesson.startTime;
|
|
||||||
model.endTime = lesson.endTime;
|
|
||||||
|
|
||||||
model.lessonPassed = (syncedNow.getValue() > lesson.endTime.getValue()) && displayingWeekDay == Week.getTodayWeekDay();
|
|
||||||
model.lessonCurrent = (Time.inRange(lesson.startTime, lesson.endTime, syncedNow)) && displayingWeekDay == Week.getTodayWeekDay();
|
|
||||||
|
|
||||||
if (model.lessonCurrent) {
|
|
||||||
scrollPos = pos;
|
|
||||||
} else if (model.lessonPassed) {
|
|
||||||
scrollPos = pos + 1;
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
|
|
||||||
model.subjectName = bs(lesson.subjectLongName);
|
|
||||||
model.classroomName = lesson.classroomName;
|
|
||||||
|
|
||||||
model.bellSyncDiffMillis = bellSyncDiffMillis;
|
|
||||||
|
|
||||||
if (lesson.changeId != 0) {
|
|
||||||
if (lesson.changeType == LessonChange.TYPE_CHANGE) {
|
|
||||||
model.lessonChange = true;
|
|
||||||
if (lesson.changedClassroomName()) {
|
|
||||||
model.newClassroomName = lesson.changeClassroomName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lesson.changedSubjectLongName()) {
|
|
||||||
model.newSubjectName = lesson.changeSubjectLongName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (lesson.changeType == LessonChange.TYPE_CANCELLED) {
|
|
||||||
model.lessonCancelled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (EventFull event : events) {
|
|
||||||
if (event.startTime == null)
|
|
||||||
continue;
|
|
||||||
if (event.eventDate.getValue() == displayingDate.getValue()
|
|
||||||
&& event.startTime.getValue() == lesson.startTime.getValue()) {
|
|
||||||
model.eventColors.add(event.type == TYPE_HOMEWORK ? ItemWidgetTimetableModel.EVENT_COLOR_HOMEWORK : event.getColor());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lessonList.add(model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lessonList.size() == 0) {
|
|
||||||
views.setViewVisibility(R.id.widgetTimetableLoading, View.VISIBLE);
|
|
||||||
views.setRemoteAdapter(R.id.widgetTimetableListView, new Intent());
|
|
||||||
views.setTextViewText(R.id.widgetTimetableLoading, app.getString(R.string.widget_timetable_no_lessons));
|
|
||||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
views.setViewVisibility(R.id.widgetTimetableLoading, View.GONE);
|
|
||||||
|
|
||||||
timetables.put(appWidgetId, lessonList);
|
|
||||||
//WidgetTimetableListProvider.widgetsLessons.put(appWidgetId, lessons);
|
|
||||||
//views.setRemoteAdapter(R.id.widgetTimetableListView, new Intent());
|
|
||||||
Intent listIntent = new Intent(context, WidgetTimetableService.class);
|
|
||||||
listIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
|
|
||||||
listIntent.setData(Uri.parse(listIntent.toUri(Intent.URI_INTENT_SCHEME)));
|
|
||||||
views.setRemoteAdapter(R.id.widgetTimetableListView, listIntent);
|
|
||||||
|
|
||||||
// template to handle the click listener for each item
|
|
||||||
Intent intentTemplate = new Intent(context, LessonDetailsActivity.class);
|
|
||||||
// Old activities shouldn't be in the history stack
|
|
||||||
intentTemplate.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
|
||||||
PendingIntent pendingIntentTimetable = PendingIntent.getActivity(context,
|
|
||||||
0,
|
|
||||||
intentTemplate,
|
|
||||||
0);
|
|
||||||
views.setPendingIntentTemplate(R.id.widgetTimetableListView, pendingIntentTimetable);
|
|
||||||
|
|
||||||
Intent openIntent = new Intent(context, MainActivity.class);
|
|
||||||
openIntent.setAction("android.intent.action.MAIN");
|
|
||||||
if (!unified) {
|
|
||||||
openIntent.putExtra("profileId", openProfileId);
|
|
||||||
openIntent.putExtra("timetableDate", displayingDate.getValue());
|
|
||||||
}
|
|
||||||
openIntent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE);
|
|
||||||
PendingIntent pendingOpenIntent = PendingIntent.getActivity(context,
|
|
||||||
appWidgetId, openIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
views.setOnClickPendingIntent(R.id.widgetTimetableHeader, pendingOpenIntent);
|
|
||||||
|
|
||||||
if (!unified)
|
|
||||||
views.setScrollPosition(R.id.widgetTimetableListView, scrollPos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
|
||||||
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widgetTimetableListView);
|
|
||||||
}
|
|
||||||
//modeInt++;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEnabled(Context context) {
|
|
||||||
// Enter relevant functionality for when the first widget is created
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDeleted(Context context, int[] appWidgetIds) {
|
|
||||||
App app = (App) context.getApplicationContext();
|
|
||||||
for (int appWidgetId: appWidgetIds) {
|
|
||||||
app.appConfig.widgetTimetableConfigs.remove(appWidgetId);
|
|
||||||
}
|
|
||||||
app.saveConfig("widgetTimetableConfigs");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
371
app/src/main/java/pl/szczodrzynski/edziennik/WidgetTimetable.kt
Normal file
371
app/src/main/java/pl/szczodrzynski/edziennik/WidgetTimetable.kt
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
package pl.szczodrzynski.edziennik
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.appwidget.AppWidgetManager
|
||||||
|
import android.appwidget.AppWidgetProvider
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.PorterDuff
|
||||||
|
import android.graphics.drawable.BitmapDrawable
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.SparseArray
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.RemoteViews
|
||||||
|
import com.mikepenz.iconics.IconicsDrawable
|
||||||
|
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||||
|
import com.mikepenz.iconics.utils.colorInt
|
||||||
|
import com.mikepenz.iconics.utils.sizeDp
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_HOMEWORK
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.ItemWidgetTimetableModel
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||||
|
import pl.szczodrzynski.edziennik.widgets.WidgetConfig
|
||||||
|
import pl.szczodrzynski.edziennik.widgets.timetable.LessonDialogActivity
|
||||||
|
import pl.szczodrzynski.edziennik.widgets.timetable.WidgetTimetableService
|
||||||
|
import java.lang.reflect.InvocationTargetException
|
||||||
|
|
||||||
|
|
||||||
|
class WidgetTimetable : AppWidgetProvider() {
|
||||||
|
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
if (ACTION_SYNC_DATA == intent.action) {
|
||||||
|
EdziennikTask.sync().enqueue(context)
|
||||||
|
}
|
||||||
|
super.onReceive(context, intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
|
||||||
|
val thisWidget = ComponentName(context, WidgetTimetable::class.java)
|
||||||
|
|
||||||
|
timetables = SparseArray()
|
||||||
|
//timetables.clear();
|
||||||
|
|
||||||
|
val app = context.applicationContext as App
|
||||||
|
|
||||||
|
var bellSyncDiffMillis: Long = 0
|
||||||
|
if (app.appConfig.bellSyncDiff != null) {
|
||||||
|
bellSyncDiffMillis = (app.appConfig.bellSyncDiff.hour * 60 * 60 * 1000 + app.appConfig.bellSyncDiff.minute * 60 * 1000 + app.appConfig.bellSyncDiff.second * 1000).toLong()
|
||||||
|
bellSyncDiffMillis *= app.appConfig.bellSyncMultiplier.toLong()
|
||||||
|
bellSyncDiffMillis *= -1
|
||||||
|
}
|
||||||
|
|
||||||
|
val allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget)
|
||||||
|
|
||||||
|
allWidgetIds?.forEach { appWidgetId ->
|
||||||
|
var widgetConfig = app.appConfig.widgetTimetableConfigs[appWidgetId]
|
||||||
|
if (widgetConfig == null) {
|
||||||
|
widgetConfig = WidgetConfig(app.profileFirstId())
|
||||||
|
app.appConfig.widgetTimetableConfigs[appWidgetId] = widgetConfig
|
||||||
|
app.appConfig.savePending = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val views = if (widgetConfig.bigStyle) {
|
||||||
|
RemoteViews(context.packageName, if (widgetConfig.darkTheme) R.layout.widget_timetable_dark_big else R.layout.widget_timetable_big)
|
||||||
|
} else {
|
||||||
|
RemoteViews(context.packageName, if (widgetConfig.darkTheme) R.layout.widget_timetable_dark else R.layout.widget_timetable)
|
||||||
|
}
|
||||||
|
|
||||||
|
val refreshIntent = Intent(app, WidgetTimetable::class.java)
|
||||||
|
refreshIntent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||||
|
refreshIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds)
|
||||||
|
val pendingRefreshIntent = PendingIntent.getBroadcast(context,
|
||||||
|
0, refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
views.setOnClickPendingIntent(R.id.widgetTimetableRefresh, pendingRefreshIntent)
|
||||||
|
|
||||||
|
views.setOnClickPendingIntent(R.id.widgetTimetableSync, getPendingSelfIntent(context, ACTION_SYNC_DATA))
|
||||||
|
|
||||||
|
views.setImageViewBitmap(R.id.widgetTimetableRefresh, IconicsDrawable(context, CommunityMaterial.Icon2.cmd_refresh)
|
||||||
|
.colorInt(Color.WHITE)
|
||||||
|
.sizeDp(if (widgetConfig.bigStyle) 24 else 16).toBitmap())
|
||||||
|
|
||||||
|
views.setImageViewBitmap(R.id.widgetTimetableSync, IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline)
|
||||||
|
.colorInt(Color.WHITE)
|
||||||
|
.sizeDp(if (widgetConfig.bigStyle) 24 else 16).toBitmap())
|
||||||
|
|
||||||
|
prepareAppWidget(app, appWidgetId, views, widgetConfig, bellSyncDiffMillis)
|
||||||
|
|
||||||
|
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||||
|
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widgetTimetableListView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun prepareAppWidget(
|
||||||
|
app: App,
|
||||||
|
appWidgetId: Int,
|
||||||
|
views: RemoteViews,
|
||||||
|
widgetConfig: WidgetConfig,
|
||||||
|
bellSyncDiffMillis: Long
|
||||||
|
) {
|
||||||
|
// get the current bell-synced time
|
||||||
|
val now = Time.fromMillis(Time.getNow().inMillis + bellSyncDiffMillis)
|
||||||
|
|
||||||
|
// set the widget transparency
|
||||||
|
val mode = PorterDuff.Mode.DST_IN
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
||||||
|
// this code seems to crash the launcher on >= P
|
||||||
|
val transparency = widgetConfig.opacity //0...1
|
||||||
|
val colorFilter = 0x01000000L * (255f * transparency).toLong()
|
||||||
|
try {
|
||||||
|
val declaredMethods = Class.forName("android.widget.RemoteViews").declaredMethods
|
||||||
|
val len = declaredMethods.size
|
||||||
|
if (len > 0) {
|
||||||
|
for (m in 0 until len) {
|
||||||
|
val method = declaredMethods[m]
|
||||||
|
if (method.name == "setDrawableParameters") {
|
||||||
|
method.isAccessible = true
|
||||||
|
method.invoke(views, R.id.widgetTimetableListView, true, -1, colorFilter.toInt(), mode, -1)
|
||||||
|
method.invoke(views, R.id.widgetTimetableHeader, true, -1, colorFilter.toInt(), mode, -1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: ClassNotFoundException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
} catch (e: InvocationTargetException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
} catch (e: IllegalAccessException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val unified = widgetConfig.profileId == -1
|
||||||
|
|
||||||
|
// get all profiles or one profile with the specified id
|
||||||
|
val profileList = if (unified)
|
||||||
|
app.db.profileDao().allNow.filterOutArchived()
|
||||||
|
else
|
||||||
|
listOfNotNull(app.db.profileDao().getByIdNow(widgetConfig.profileId))
|
||||||
|
|
||||||
|
// no profile was found
|
||||||
|
if (profileList.isEmpty()) {
|
||||||
|
views.setViewVisibility(R.id.widgetTimetableLoading, View.VISIBLE)
|
||||||
|
views.setTextViewText(R.id.widgetTimetableLoading, app.getString(R.string.widget_timetable_profile_doesnt_exist))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
views.setViewVisibility(R.id.widgetTimetableLoading, View.GONE)
|
||||||
|
|
||||||
|
// set lesson search bounds
|
||||||
|
val today = Date.getToday()
|
||||||
|
val searchEnd = today.clone().stepForward(0, 0, 7)
|
||||||
|
|
||||||
|
var scrollPos = 0
|
||||||
|
|
||||||
|
var profileId: Int? = null
|
||||||
|
var displayingDate: Date? = null
|
||||||
|
|
||||||
|
val models = mutableListOf<ItemWidgetTimetableModel>()
|
||||||
|
|
||||||
|
// get all lessons within the search bounds
|
||||||
|
val lessonList = app.db.timetableDao().getBetweenDatesNow(today, searchEnd)
|
||||||
|
|
||||||
|
for (profile in profileList) {
|
||||||
|
|
||||||
|
// add a profile separator with its name
|
||||||
|
if (unified) {
|
||||||
|
val separator = ItemWidgetTimetableModel()
|
||||||
|
separator.profileId = profile.id
|
||||||
|
separator.bigStyle = widgetConfig.bigStyle
|
||||||
|
separator.darkTheme = widgetConfig.darkTheme
|
||||||
|
separator.separatorProfileName = profile.name
|
||||||
|
models.add(separator)
|
||||||
|
}
|
||||||
|
|
||||||
|
// search for lessons to display
|
||||||
|
val timetableDate = Date.getToday()
|
||||||
|
var checkedDays = 0
|
||||||
|
var lessons = lessonList.filter { it.profileId == profile.id && it.displayDate == timetableDate && it.type != Lesson.TYPE_NO_LESSONS }
|
||||||
|
while ((lessons.isEmpty() || lessons.none {
|
||||||
|
it.displayDate != today || (it.displayDate == today && it.displayEndTime != null && it.displayEndTime!! >= now)
|
||||||
|
}) && checkedDays < 7) {
|
||||||
|
timetableDate.stepForward(0, 0, 1)
|
||||||
|
lessons = lessonList.filter { it.profileId == profile.id && it.displayDate == timetableDate && it.type != Lesson.TYPE_NO_LESSONS }
|
||||||
|
checkedDays++
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the displayingDate to show in the header
|
||||||
|
if (!unified) {
|
||||||
|
if (lessons.isNotEmpty())
|
||||||
|
displayingDate = timetableDate
|
||||||
|
profileId = profile.id
|
||||||
|
}
|
||||||
|
|
||||||
|
// get all events for the current date
|
||||||
|
val events = app.db.eventDao().getAllByDateNow(profile.id, timetableDate)?.filterNotNull() ?: emptyList()
|
||||||
|
|
||||||
|
lessons.forEachIndexed { pos, lesson ->
|
||||||
|
val model = ItemWidgetTimetableModel()
|
||||||
|
|
||||||
|
model.bigStyle = widgetConfig.bigStyle
|
||||||
|
model.darkTheme = widgetConfig.darkTheme
|
||||||
|
|
||||||
|
model.profileId = profile.id
|
||||||
|
|
||||||
|
model.lessonId = lesson.id
|
||||||
|
model.lessonDate = timetableDate
|
||||||
|
model.startTime = lesson.displayStartTime
|
||||||
|
model.endTime = lesson.displayEndTime
|
||||||
|
|
||||||
|
// check if the lesson has already passed or it's currently in progress
|
||||||
|
if (lesson.displayDate == today) {
|
||||||
|
lesson.displayEndTime?.let { endTime ->
|
||||||
|
model.lessonPassed = now > endTime
|
||||||
|
lesson.displayStartTime?.let { startTime ->
|
||||||
|
model.lessonCurrent = now in startTime..endTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set where should the list view scroll to
|
||||||
|
if (model.lessonCurrent) {
|
||||||
|
scrollPos = pos
|
||||||
|
} else if (model.lessonPassed) {
|
||||||
|
scrollPos = pos + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the subject and classroom name
|
||||||
|
model.subjectName = lesson.displaySubjectName
|
||||||
|
model.classroomName = lesson.displayClassroom
|
||||||
|
|
||||||
|
// set the bell sync to calculate progress in ListProvider
|
||||||
|
model.bellSyncDiffMillis = bellSyncDiffMillis
|
||||||
|
|
||||||
|
// make the model aware of the lesson type
|
||||||
|
when (lesson.type) {
|
||||||
|
Lesson.TYPE_CANCELLED -> {
|
||||||
|
model.lessonCancelled = true
|
||||||
|
}
|
||||||
|
Lesson.TYPE_CHANGE,
|
||||||
|
Lesson.TYPE_SHIFTED_SOURCE,
|
||||||
|
Lesson.TYPE_SHIFTED_TARGET -> {
|
||||||
|
model.lessonChange = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add every event on this lesson
|
||||||
|
for (event in events) {
|
||||||
|
if (event.startTime != null && event.startTime != lesson.displayStartTime)
|
||||||
|
continue
|
||||||
|
model.eventColors.add(if (event.type == TYPE_HOMEWORK) ItemWidgetTimetableModel.EVENT_COLOR_HOMEWORK else event.getColor())
|
||||||
|
}
|
||||||
|
|
||||||
|
models += model
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unified) {
|
||||||
|
// set the title for an unified widget
|
||||||
|
views.setTextViewText(R.id.widgetTimetableTitle, app.getString(R.string.widget_timetable_title_unified))
|
||||||
|
views.setViewVisibility(R.id.widgetTimetableSubtitle, View.GONE)
|
||||||
|
} else {
|
||||||
|
// set the title to present the widget's profile
|
||||||
|
views.setTextViewText(R.id.widgetTimetableTitle, profileList[0].name)
|
||||||
|
views.setViewVisibility(R.id.widgetTimetableTitle, View.VISIBLE)
|
||||||
|
// make the subtitle show current date for these lessons
|
||||||
|
displayingDate?.let {
|
||||||
|
when (Date.diffDays(it, Date.getToday())) {
|
||||||
|
0 -> views.setTextViewText(R.id.widgetTimetableSubtitle, app.getString(R.string.day_today_format, Week.getFullDayName(it.weekDay)))
|
||||||
|
1 -> views.setTextViewText(R.id.widgetTimetableSubtitle, app.getString(R.string.day_tomorrow_format, Week.getFullDayName(it.weekDay)))
|
||||||
|
else -> views.setTextViewText(R.id.widgetTimetableSubtitle, Week.getFullDayName(it.weekDay) + " " + it.formattedString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// intent running when the header is clicked
|
||||||
|
val openIntent = Intent(app, MainActivity::class.java)
|
||||||
|
openIntent.action = "android.intent.action.MAIN"
|
||||||
|
if (!unified) {
|
||||||
|
// per-profile widget should redirect to it + correct day
|
||||||
|
profileId?.let {
|
||||||
|
openIntent.putExtra("profileId", it)
|
||||||
|
}
|
||||||
|
displayingDate?.let {
|
||||||
|
openIntent.putExtra("timetableDate", it.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
openIntent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE)
|
||||||
|
val pendingOpenIntent = PendingIntent.getActivity(app, appWidgetId, openIntent, 0)
|
||||||
|
views.setOnClickPendingIntent(R.id.widgetTimetableHeader, pendingOpenIntent)
|
||||||
|
|
||||||
|
if (lessonList.isEmpty()) {
|
||||||
|
views.setViewVisibility(R.id.widgetTimetableLoading, View.VISIBLE)
|
||||||
|
views.setRemoteAdapter(R.id.widgetTimetableListView, Intent())
|
||||||
|
views.setTextViewText(R.id.widgetTimetableLoading, app.getString(R.string.widget_timetable_no_lessons))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
timetables!!.put(appWidgetId, models)
|
||||||
|
|
||||||
|
// apply the list service to the list view
|
||||||
|
val listIntent = Intent(app, WidgetTimetableService::class.java)
|
||||||
|
listIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
|
||||||
|
listIntent.data = Uri.parse(listIntent.toUri(Intent.URI_INTENT_SCHEME))
|
||||||
|
views.setRemoteAdapter(R.id.widgetTimetableListView, listIntent)
|
||||||
|
|
||||||
|
// create an intent used to display the lesson details dialog
|
||||||
|
val intentTemplate = Intent(app, LessonDialogActivity::class.java)
|
||||||
|
intentTemplate.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||||
|
val pendingIntentTimetable = PendingIntent.getActivity(app, appWidgetId, intentTemplate, 0)
|
||||||
|
views.setPendingIntentTemplate(R.id.widgetTimetableListView, pendingIntentTimetable)
|
||||||
|
|
||||||
|
if (!unified)
|
||||||
|
views.setScrollPosition(R.id.widgetTimetableListView, scrollPos)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEnabled(context: Context) {
|
||||||
|
// Enter relevant functionality for when the first widget is created
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDeleted(context: Context, appWidgetIds: IntArray) {
|
||||||
|
val app = context.applicationContext as App
|
||||||
|
for (appWidgetId in appWidgetIds) {
|
||||||
|
app.appConfig.widgetTimetableConfigs.remove(appWidgetId)
|
||||||
|
}
|
||||||
|
app.saveConfig("widgetTimetableConfigs")
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
|
||||||
|
val ACTION_SYNC_DATA = "ACTION_SYNC_DATA"
|
||||||
|
private val TAG = "WidgetTimetable"
|
||||||
|
private val modeInt = 0
|
||||||
|
|
||||||
|
var timetables: SparseArray<List<ItemWidgetTimetableModel>>? = null
|
||||||
|
|
||||||
|
fun getPendingSelfIntent(context: Context, action: String): PendingIntent {
|
||||||
|
val intent = Intent(context, WidgetTimetable::class.java)
|
||||||
|
intent.action = action
|
||||||
|
return getPendingSelfIntent(context, intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPendingSelfIntent(context: Context, intent: Intent): PendingIntent {
|
||||||
|
return PendingIntent.getBroadcast(context, 0, intent, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun drawableToBitmap(drawable: Drawable): Bitmap {
|
||||||
|
|
||||||
|
if (drawable is BitmapDrawable) {
|
||||||
|
return drawable.bitmap
|
||||||
|
}
|
||||||
|
|
||||||
|
val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
|
||||||
|
val canvas = Canvas(bitmap)
|
||||||
|
drawable.setBounds(0, 0, canvas.width, canvas.height)
|
||||||
|
drawable.draw(canvas)
|
||||||
|
|
||||||
|
return bitmap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -60,6 +60,9 @@ class ApiService : Service() {
|
|||||||
|
|
||||||
private val notification by lazy { EdziennikNotification(this) }
|
private val notification by lazy { EdziennikNotification(this) }
|
||||||
|
|
||||||
|
private var lastEventTime = System.currentTimeMillis()
|
||||||
|
private var taskCancelTries = 0
|
||||||
|
|
||||||
/* ______ _ _ _ _ _____ _ _ _ _
|
/* ______ _ _ _ _ _____ _ _ _ _
|
||||||
| ____| | | (_) (_) | / ____| | | | | | |
|
| ____| | | (_) (_) | / ____| | | | | | |
|
||||||
| |__ __| |_____ ___ _ __ _ __ _| | __ | | __ _| | | |__ __ _ ___| | __
|
| |__ __| |_____ ___ _ __ _ __ _| | __ | | __ _| | | |__ __ _ ___| | __
|
||||||
@ -68,22 +71,17 @@ class ApiService : Service() {
|
|||||||
|______\__,_/___|_|\___|_| |_|_| |_|_|_|\_\ \_____\__,_|_|_|_.__/ \__,_|\___|_|\*/
|
|______\__,_/___|_|\___|_| |_|_| |_|_|_|\_\ \_____\__,_|_|_|_.__/ \__,_|\___|_|\*/
|
||||||
private val taskCallback = object : EdziennikCallback {
|
private val taskCallback = object : EdziennikCallback {
|
||||||
override fun onCompleted() {
|
override fun onCompleted() {
|
||||||
|
lastEventTime = System.currentTimeMillis()
|
||||||
d(TAG, "Task $taskRunningId (profile $taskProfileId) - $taskProgressText - finished")
|
d(TAG, "Task $taskRunningId (profile $taskProfileId) - $taskProgressText - finished")
|
||||||
//if (!taskCancelled) {
|
EventBus.getDefault().post(ApiTaskFinishedEvent(taskProfileId))
|
||||||
EventBus.getDefault().post(ApiTaskFinishedEvent(taskProfileId))
|
clearTask()
|
||||||
//}
|
|
||||||
taskIsRunning = false
|
|
||||||
taskRunningId = -1
|
|
||||||
taskRunning = null
|
|
||||||
taskProfileId = -1
|
|
||||||
taskProgress = -1f
|
|
||||||
taskProgressText = null
|
|
||||||
|
|
||||||
notification.setIdle().post()
|
notification.setIdle().post()
|
||||||
runTask()
|
runTask()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onError(apiError: ApiError) {
|
override fun onError(apiError: ApiError) {
|
||||||
|
lastEventTime = System.currentTimeMillis()
|
||||||
d(TAG, "Task $taskRunningId threw an error - $apiError")
|
d(TAG, "Task $taskRunningId threw an error - $apiError")
|
||||||
apiError.profileId = taskProfileId
|
apiError.profileId = taskProfileId
|
||||||
EventBus.getDefault().post(ApiTaskErrorEvent(apiError))
|
EventBus.getDefault().post(ApiTaskErrorEvent(apiError))
|
||||||
@ -92,9 +90,7 @@ class ApiService : Service() {
|
|||||||
if (apiError.isCritical) {
|
if (apiError.isCritical) {
|
||||||
taskRunning?.cancel()
|
taskRunning?.cancel()
|
||||||
notification.setCriticalError().post()
|
notification.setCriticalError().post()
|
||||||
taskRunning = null
|
clearTask()
|
||||||
taskIsRunning = false
|
|
||||||
taskRunningId = -1
|
|
||||||
runTask()
|
runTask()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -103,6 +99,7 @@ class ApiService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onProgress(step: Float) {
|
override fun onProgress(step: Float) {
|
||||||
|
lastEventTime = System.currentTimeMillis()
|
||||||
if (step <= 0)
|
if (step <= 0)
|
||||||
return
|
return
|
||||||
if (taskProgress < 0)
|
if (taskProgress < 0)
|
||||||
@ -115,6 +112,7 @@ class ApiService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onStartProgress(stringRes: Int) {
|
override fun onStartProgress(stringRes: Int) {
|
||||||
|
lastEventTime = System.currentTimeMillis()
|
||||||
taskProgressText = getString(stringRes)
|
taskProgressText = getString(stringRes)
|
||||||
d(TAG, "Task $taskRunningId progress: $taskProgressText")
|
d(TAG, "Task $taskRunningId progress: $taskProgressText")
|
||||||
EventBus.getDefault().post(ApiTaskProgressEvent(taskProfileId, taskProgress, taskProgressText))
|
EventBus.getDefault().post(ApiTaskProgressEvent(taskProfileId, taskProgress, taskProgressText))
|
||||||
@ -129,6 +127,7 @@ class ApiService : Service() {
|
|||||||
| | (_| \__ \ < | __/> < __/ (__| |_| | |_| | (_) | | | |
|
| | (_| \__ \ < | __/> < __/ (__| |_| | |_| | (_) | | | |
|
||||||
|_|\__,_|___/_|\_\ \___/_/\_\___|\___|\__,_|\__|_|\___/|_| |*/
|
|_|\__,_|___/_|\_\ \___/_/\_\___|\___|\__,_|\__|_|\___/|_| |*/
|
||||||
private fun runTask() {
|
private fun runTask() {
|
||||||
|
checkIfTaskFrozen()
|
||||||
if (taskIsRunning)
|
if (taskIsRunning)
|
||||||
return
|
return
|
||||||
if (taskCancelled || serviceClosed || (taskQueue.isEmpty() && finishingTaskQueue.isEmpty())) {
|
if (taskCancelled || serviceClosed || (taskQueue.isEmpty() && finishingTaskQueue.isEmpty())) {
|
||||||
@ -137,6 +136,8 @@ class ApiService : Service() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastEventTime = System.currentTimeMillis()
|
||||||
|
|
||||||
val task = if (taskQueue.isEmpty()) finishingTaskQueue.removeAt(0) else taskQueue.removeAt(0)
|
val task = if (taskQueue.isEmpty()) finishingTaskQueue.removeAt(0) else taskQueue.removeAt(0)
|
||||||
task.taskId = ++taskMaximumId
|
task.taskId = ++taskMaximumId
|
||||||
task.prepare(app)
|
task.prepare(app)
|
||||||
@ -166,6 +167,48 @@ class ApiService : Service() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a task is inactive for more than 30 seconds.
|
||||||
|
* If the user tries to cancel a task with no success at least three times,
|
||||||
|
* consider it frozen as well.
|
||||||
|
*
|
||||||
|
* This usually means it is broken and won't become active again.
|
||||||
|
* This method cancels the task and removes any pointers to it.
|
||||||
|
*/
|
||||||
|
private fun checkIfTaskFrozen(): Boolean {
|
||||||
|
if (System.currentTimeMillis() - lastEventTime > 30*1000
|
||||||
|
|| taskCancelTries >= 3) {
|
||||||
|
val time = System.currentTimeMillis() - lastEventTime
|
||||||
|
d(TAG, "!!! Task $taskRunningId froze for $time ms. $taskRunning")
|
||||||
|
clearTask()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the service if the current task is frozen/broken.
|
||||||
|
*/
|
||||||
|
private fun stopIfTaskFrozen() {
|
||||||
|
if (checkIfTaskFrozen()) {
|
||||||
|
stopSelf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove any task descriptors or pointers from the service.
|
||||||
|
*/
|
||||||
|
private fun clearTask() {
|
||||||
|
taskIsRunning = false
|
||||||
|
taskRunningId = -1
|
||||||
|
taskRunning = null
|
||||||
|
taskProfileId = -1
|
||||||
|
taskProgress = -1f
|
||||||
|
taskProgressText = null
|
||||||
|
taskCancelled = false
|
||||||
|
taskCancelTries = 0
|
||||||
|
}
|
||||||
|
|
||||||
private fun allCompleted() {
|
private fun allCompleted() {
|
||||||
EventBus.getDefault().post(ApiTaskAllFinishedEvent())
|
EventBus.getDefault().post(ApiTaskAllFinishedEvent())
|
||||||
stopSelf()
|
stopSelf()
|
||||||
@ -211,8 +254,10 @@ class ApiService : Service() {
|
|||||||
EventBus.getDefault().removeStickyEvent(request)
|
EventBus.getDefault().removeStickyEvent(request)
|
||||||
d(TAG, request.toString())
|
d(TAG, request.toString())
|
||||||
|
|
||||||
|
taskCancelTries++
|
||||||
taskCancelled = true
|
taskCancelled = true
|
||||||
taskRunning?.cancel()
|
taskRunning?.cancel()
|
||||||
|
stopIfTaskFrozen()
|
||||||
}
|
}
|
||||||
@Subscribe(sticky = true, threadMode = ThreadMode.ASYNC)
|
@Subscribe(sticky = true, threadMode = ThreadMode.ASYNC)
|
||||||
fun onServiceCloseRequest(request: ServiceCloseRequest) {
|
fun onServiceCloseRequest(request: ServiceCloseRequest) {
|
||||||
|
@ -64,6 +64,7 @@ const val IDZIENNIK_WEB_TIMETABLE = "mod_panelRodzica/plan/WS_Plan.asmx/pobierzP
|
|||||||
const val IDZIENNIK_WEB_GRADES = "mod_panelRodzica/oceny/WS_ocenyUcznia.asmx/pobierzOcenyUcznia"
|
const val IDZIENNIK_WEB_GRADES = "mod_panelRodzica/oceny/WS_ocenyUcznia.asmx/pobierzOcenyUcznia"
|
||||||
const val IDZIENNIK_WEB_MISSING_GRADES = "mod_panelRodzica/brak_ocen/WS_BrakOcenUcznia.asmx/pobierzBrakujaceOcenyUcznia"
|
const val IDZIENNIK_WEB_MISSING_GRADES = "mod_panelRodzica/brak_ocen/WS_BrakOcenUcznia.asmx/pobierzBrakujaceOcenyUcznia"
|
||||||
const val IDZIENNIK_WEB_EXAMS = "mod_panelRodzica/sprawdziany/mod_sprawdzianyPanel.asmx/pobierzListe"
|
const val IDZIENNIK_WEB_EXAMS = "mod_panelRodzica/sprawdziany/mod_sprawdzianyPanel.asmx/pobierzListe"
|
||||||
|
const val IDZIENNIK_WEB_HOMEWORK = "mod_panelRodzica/pracaDomowa/WS_pracaDomowa.asmx/pobierzPraceDomowe"
|
||||||
const val IDZIENNIK_WEB_NOTICES = "mod_panelRodzica/uwagi/WS_uwagiUcznia.asmx/pobierzUwagiUcznia"
|
const val IDZIENNIK_WEB_NOTICES = "mod_panelRodzica/uwagi/WS_uwagiUcznia.asmx/pobierzUwagiUcznia"
|
||||||
const val IDZIENNIK_WEB_ATTENDANCE = "mod_panelRodzica/obecnosci/WS_obecnosciUcznia.asmx/pobierzObecnosciUcznia"
|
const val IDZIENNIK_WEB_ATTENDANCE = "mod_panelRodzica/obecnosci/WS_obecnosciUcznia.asmx/pobierzObecnosciUcznia"
|
||||||
const val IDZIENNIK_WEB_ANNOUNCEMENTS = "mod_panelRodzica/tabOgl/WS_tablicaOgloszen.asmx/GetOgloszenia"
|
const val IDZIENNIK_WEB_ANNOUNCEMENTS = "mod_panelRodzica/tabOgl/WS_tablicaOgloszen.asmx/GetOgloszenia"
|
||||||
|
@ -45,8 +45,8 @@ class DataNotifications(val data: Data) {
|
|||||||
return@run
|
return@run
|
||||||
}
|
}
|
||||||
|
|
||||||
for (change in app.db.lessonChangeDao().getNotNotifiedNow(profileId)) {
|
for (lesson in app.db.timetableDao().getNotNotifiedNow(profileId)) {
|
||||||
val text = app.getString(R.string.notification_lesson_change_format, change.changeTypeStr(app), if (change.lessonDate == null) "" else change.lessonDate!!.formattedString, change.subjectLongName)
|
val text = app.getString(R.string.notification_lesson_change_format, lesson.getDisplayChangeType(app), if (lesson.displayDate == null) "" else lesson.displayDate!!.formattedString, lesson.changeSubjectName)
|
||||||
data.notifications += Notification(
|
data.notifications += Notification(
|
||||||
title = app.getNotificationTitle(TYPE_TIMETABLE_LESSON_CHANGE),
|
title = app.getNotificationTitle(TYPE_TIMETABLE_LESSON_CHANGE),
|
||||||
text = text,
|
text = text,
|
||||||
@ -54,8 +54,8 @@ class DataNotifications(val data: Data) {
|
|||||||
profileId = profileId,
|
profileId = profileId,
|
||||||
profileName = profileName,
|
profileName = profileName,
|
||||||
viewId = DRAWER_ITEM_TIMETABLE,
|
viewId = DRAWER_ITEM_TIMETABLE,
|
||||||
addedDate = change.addedDate
|
addedDate = lesson.addedDate
|
||||||
).addExtra("timetableDate", change.lessonDate?.value?.toLong())
|
).addExtra("timetableDate", lesson.displayDate?.stringY_m_d ?: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
for (event in app.db.eventDao().getNotNotifiedNow(profileId)) {
|
for (event in app.db.eventDao().getNotNotifiedNow(profileId)) {
|
||||||
@ -186,10 +186,10 @@ class DataNotifications(val data: Data) {
|
|||||||
val luckyNumbers = app.db.luckyNumberDao().getNotNotifiedNow(profileId)
|
val luckyNumbers = app.db.luckyNumberDao().getNotNotifiedNow(profileId)
|
||||||
luckyNumbers?.removeAll { it.date < today }
|
luckyNumbers?.removeAll { it.date < today }
|
||||||
luckyNumbers?.forEach { luckyNumber ->
|
luckyNumbers?.forEach { luckyNumber ->
|
||||||
val text = when {
|
val text = when (luckyNumber.date.value) {
|
||||||
luckyNumber.date.value == todayValue -> // LN for today
|
todayValue -> // LN for today
|
||||||
app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_format else R.string.notification_lucky_number_format, luckyNumber.number)
|
app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_format else R.string.notification_lucky_number_format, luckyNumber.number)
|
||||||
luckyNumber.date.value == todayValue + 1 -> // LN for tomorrow
|
todayValue + 1 -> // LN for tomorrow
|
||||||
app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_tomorrow_format else R.string.notification_lucky_number_tomorrow_format, luckyNumber.number)
|
app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_tomorrow_format else R.string.notification_lucky_number_tomorrow_format, luckyNumber.number)
|
||||||
else -> // LN for later
|
else -> // LN for later
|
||||||
app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_later_format else R.string.notification_lucky_number_later_format, luckyNumber.date.formattedString, luckyNumber.number)
|
app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_later_format else R.string.notification_lucky_number_later_format, luckyNumber.date.formattedString, luckyNumber.number)
|
||||||
@ -207,4 +207,4 @@ class DataNotifications(val data: Data) {
|
|||||||
|
|
||||||
data.db.metadataDao().setAllNotified(profileId, true)
|
data.db.metadataDao().setAllNotified(profileId, true)
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -39,13 +39,16 @@ const val ERROR_REQUEST_HTTP_404 = 54
|
|||||||
const val ERROR_REQUEST_HTTP_405 = 55
|
const val ERROR_REQUEST_HTTP_405 = 55
|
||||||
const val ERROR_REQUEST_HTTP_410 = 56
|
const val ERROR_REQUEST_HTTP_410 = 56
|
||||||
const val ERROR_REQUEST_HTTP_500 = 57
|
const val ERROR_REQUEST_HTTP_500 = 57
|
||||||
|
const val ERROR_REQUEST_FAILURE_HOSTNAME_NOT_FOUND = 60
|
||||||
|
const val ERROR_REQUEST_FAILURE_TIMEOUT = 61
|
||||||
|
const val ERROR_REQUEST_FAILURE_NO_INTERNET = 62
|
||||||
const val ERROR_RESPONSE_EMPTY = 100
|
const val ERROR_RESPONSE_EMPTY = 100
|
||||||
const val ERROR_LOGIN_DATA_MISSING = 101
|
const val ERROR_LOGIN_DATA_MISSING = 101
|
||||||
const val ERROR_LOGIN_DATA_INVALID = 102
|
|
||||||
const val ERROR_PROFILE_MISSING = 105
|
const val ERROR_PROFILE_MISSING = 105
|
||||||
const val ERROR_INVALID_LOGIN_MODE = 110
|
const val ERROR_INVALID_LOGIN_MODE = 110
|
||||||
const val ERROR_LOGIN_METHOD_NOT_SATISFIED = 111
|
const val ERROR_LOGIN_METHOD_NOT_SATISFIED = 111
|
||||||
const val ERROR_NOT_IMPLEMENTED = 112
|
const val ERROR_NOT_IMPLEMENTED = 112
|
||||||
|
const val ERROR_FILE_DOWNLOAD = 113
|
||||||
|
|
||||||
const val ERROR_NO_STUDENTS_IN_ACCOUNT = 115
|
const val ERROR_NO_STUDENTS_IN_ACCOUNT = 115
|
||||||
|
|
||||||
@ -99,6 +102,13 @@ const val ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_INVALID = 172
|
|||||||
const val ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_REVOKED = 173
|
const val ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_REVOKED = 173
|
||||||
const val ERROR_LIBRUS_SYNERGIA_OTHER = 174
|
const val ERROR_LIBRUS_SYNERGIA_OTHER = 174
|
||||||
const val ERROR_LIBRUS_SYNERGIA_MAINTENANCE = 175
|
const val ERROR_LIBRUS_SYNERGIA_MAINTENANCE = 175
|
||||||
|
const val ERROR_LIBRUS_MESSAGES_MAINTENANCE = 176
|
||||||
|
const val ERROR_LIBRUS_MESSAGES_ERROR = 177
|
||||||
|
const val ERROR_LIBRUS_MESSAGES_OTHER = 178
|
||||||
|
const val ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN = 179
|
||||||
|
const val ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN = 180
|
||||||
|
const val ERROR_LIBRUS_API_MAINTENANCE = 181
|
||||||
|
const val ERROR_LIBRUS_PORTAL_MAINTENANCE = 182
|
||||||
|
|
||||||
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_LOGIN = 201
|
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_LOGIN = 201
|
||||||
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_OLD_PASSWORD = 202
|
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_OLD_PASSWORD = 202
|
||||||
@ -109,7 +119,7 @@ const val ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_ADDRESS = 206
|
|||||||
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_OTHER = 210
|
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_OTHER = 210
|
||||||
const val ERROR_MOBIDZIENNIK_WEB_ACCESS_DENIED = 211
|
const val ERROR_MOBIDZIENNIK_WEB_ACCESS_DENIED = 211
|
||||||
const val ERROR_MOBIDZIENNIK_WEB_NO_SESSION_KEY = 212
|
const val ERROR_MOBIDZIENNIK_WEB_NO_SESSION_KEY = 212
|
||||||
const val ERROR_MOBIDZIENNIK_WEB_NO_SESSION_VALUE = 212
|
const val ERROR_MOBIDZIENNIK_WEB_NO_SESSION_VALUE = 216
|
||||||
const val ERROR_MOBIDZIENNIK_WEB_NO_SERVER_ID = 213
|
const val ERROR_MOBIDZIENNIK_WEB_NO_SERVER_ID = 213
|
||||||
const val ERROR_MOBIDZIENNIK_WEB_INVALID_RESPONSE = 214
|
const val ERROR_MOBIDZIENNIK_WEB_INVALID_RESPONSE = 214
|
||||||
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_NO_SESSION_ID = 215
|
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_NO_SESSION_ID = 215
|
||||||
@ -163,3 +173,5 @@ const val EXCEPTION_LIBRUS_MESSAGES_REQUEST = 911
|
|||||||
const val EXCEPTION_IDZIENNIK_WEB_REQUEST = 912
|
const val EXCEPTION_IDZIENNIK_WEB_REQUEST = 912
|
||||||
const val EXCEPTION_IDZIENNIK_WEB_API_REQUEST = 913
|
const val EXCEPTION_IDZIENNIK_WEB_API_REQUEST = 913
|
||||||
const val EXCEPTION_IDZIENNIK_API_REQUEST = 914
|
const val EXCEPTION_IDZIENNIK_API_REQUEST = 914
|
||||||
|
|
||||||
|
const val LOGIN_NO_ARGUMENTS = 1201
|
||||||
|
@ -7,39 +7,36 @@ package pl.szczodrzynski.edziennik.api.v2
|
|||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE
|
||||||
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR
|
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
||||||
|
|
||||||
const val FEATURE_ALL = 0
|
internal const val FEATURE_TIMETABLE = 1
|
||||||
const val FEATURE_TIMETABLE = 1
|
internal const val FEATURE_AGENDA = 2
|
||||||
const val FEATURE_AGENDA = 2
|
internal const val FEATURE_GRADES = 3
|
||||||
const val FEATURE_GRADES = 3
|
internal const val FEATURE_HOMEWORK = 4
|
||||||
const val FEATURE_HOMEWORK = 4
|
internal const val FEATURE_BEHAVIOUR = 5
|
||||||
const val FEATURE_BEHAVIOUR = 5
|
internal const val FEATURE_ATTENDANCE = 6
|
||||||
const val FEATURE_ATTENDANCE = 6
|
internal const val FEATURE_MESSAGES_INBOX = 7
|
||||||
const val FEATURE_MESSAGES_INBOX = 7
|
internal const val FEATURE_MESSAGES_SENT = 8
|
||||||
const val FEATURE_MESSAGES_SENT = 8
|
internal const val FEATURE_ANNOUNCEMENTS = 9
|
||||||
const val FEATURE_ANNOUNCEMENTS = 9
|
|
||||||
|
|
||||||
const val FEATURE_ALWAYS_NEEDED = 100
|
internal const val FEATURE_ALWAYS_NEEDED = 100
|
||||||
const val FEATURE_STUDENT_INFO = 101
|
internal const val FEATURE_STUDENT_INFO = 101
|
||||||
const val FEATURE_STUDENT_NUMBER = 109
|
internal const val FEATURE_STUDENT_NUMBER = 109
|
||||||
const val FEATURE_SCHOOL_INFO = 102
|
internal const val FEATURE_SCHOOL_INFO = 102
|
||||||
const val FEATURE_CLASS_INFO = 103
|
internal const val FEATURE_CLASS_INFO = 103
|
||||||
const val FEATURE_TEAM_INFO = 104
|
internal const val FEATURE_TEAM_INFO = 104
|
||||||
const val FEATURE_LUCKY_NUMBER = 105
|
internal const val FEATURE_LUCKY_NUMBER = 105
|
||||||
const val FEATURE_TEACHERS = 106
|
internal const val FEATURE_TEACHERS = 106
|
||||||
const val FEATURE_SUBJECTS = 107
|
internal const val FEATURE_SUBJECTS = 107
|
||||||
const val FEATURE_CLASSROOMS = 108
|
internal const val FEATURE_CLASSROOMS = 108
|
||||||
const val FEATURE_PUSH_CONFIG = 120
|
internal const val FEATURE_PUSH_CONFIG = 120
|
||||||
|
|
||||||
const val FEATURE_MESSAGE_GET = 201
|
|
||||||
|
|
||||||
object Features {
|
object Features {
|
||||||
private fun getAllNecessary(): List<Int> = listOf(
|
private fun getAllNecessary(): List<Int> = listOf(
|
||||||
|
@ -37,6 +37,16 @@ object Regexes {
|
|||||||
"""events: (.+),$""".toRegex(RegexOption.MULTILINE)
|
"""events: (.+),$""".toRegex(RegexOption.MULTILINE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val MOBIDZIENNIK_MESSAGE_READ_DATE by lazy {
|
||||||
|
"""czas przeczytania:.+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||||
|
}
|
||||||
|
val MOBIDZIENNIK_MESSAGE_SENT_READ_DATE by lazy {
|
||||||
|
""".+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||||
|
}
|
||||||
|
val MOBIDZIENNIK_MESSAGE_ATTACHMENT by lazy {
|
||||||
|
"""href="https://.+?\.mobidziennik.pl/.+?&(?:amp;)?zalacznik=([0-9]+)"(?:.+?<small.+?\(([0-9.]+)\s(M|K|G|)B\))*""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val IDZIENNIK_LOGIN_HIDDEN_FIELDS by lazy {
|
val IDZIENNIK_LOGIN_HIDDEN_FIELDS by lazy {
|
||||||
@ -60,4 +70,16 @@ object Regexes {
|
|||||||
val IDZIENNIK_LOGIN_FIRST_STUDENT by lazy {
|
val IDZIENNIK_LOGIN_FIRST_STUDENT by lazy {
|
||||||
"""<option.*?value="([0-9]+)"\sdata-id-ucznia="([A-z0-9]+?)".*?>(.+?)\s(.+?)\s*\((.+?),\s*(.+?)\)</option>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
"""<option.*?value="([0-9]+)"\sdata-id-ucznia="([A-z0-9]+?)".*?>(.+?)\s(.+?)\s*\((.+?),\s*(.+?)\)</option>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
val VULCAN_SHITFT_ANNOTATION by lazy {
|
||||||
|
"""\(przeniesiona (z|na) lekcj[ię] ([0-9]+), (.+)\)""".toRegex()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
val LIBRUS_ATTACHMENT_KEY by lazy {
|
||||||
|
"""singleUseKey=([0-9A-f_]+)""".toRegex()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.events
|
||||||
|
|
||||||
|
data class AttachmentGetEvent(val profileId: Int, val messageId: Long, val attachmentId: Long,
|
||||||
|
var eventType: Int = TYPE_PROGRESS, val fileName: String? = null,
|
||||||
|
val bytesWritten: Long = 0) {
|
||||||
|
companion object {
|
||||||
|
const val TYPE_PROGRESS = 0
|
||||||
|
const val TYPE_FINISHED = 1
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,7 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
|||||||
fun syncProfileList(profileList: List<Int>) = EdziennikTask(-1, SyncProfileListRequest(profileList))
|
fun syncProfileList(profileList: List<Int>) = EdziennikTask(-1, SyncProfileListRequest(profileList))
|
||||||
fun messageGet(profileId: Int, message: MessageFull) = EdziennikTask(profileId, MessageGetRequest(message))
|
fun messageGet(profileId: Int, message: MessageFull) = EdziennikTask(profileId, MessageGetRequest(message))
|
||||||
fun announcementsRead(profileId: Int) = EdziennikTask(profileId, AnnouncementsReadRequest())
|
fun announcementsRead(profileId: Int) = EdziennikTask(profileId, AnnouncementsReadRequest())
|
||||||
|
fun attachmentGet(profileId: Int, messageId: Long, attachmentId: Long, attachmentName: String) = EdziennikTask(profileId, AttachmentGetRequest(messageId, attachmentId, attachmentName))
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var loginStore: LoginStore
|
private lateinit var loginStore: LoginStore
|
||||||
@ -35,8 +36,7 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
|||||||
loginStore = request.loginStore
|
loginStore = request.loginStore
|
||||||
// save the profile ID and name as the current task's
|
// save the profile ID and name as the current task's
|
||||||
taskName = app.getString(R.string.edziennik_notification_api_first_login_title)
|
taskName = app.getString(R.string.edziennik_notification_api_first_login_title)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// get the requested profile and login store
|
// get the requested profile and login store
|
||||||
val profile = app.db.profileDao().getByIdNow(profileId)
|
val profile = app.db.profileDao().getByIdNow(profileId)
|
||||||
this.profile = profile
|
this.profile = profile
|
||||||
@ -67,12 +67,14 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
|||||||
|
|
||||||
when (request) {
|
when (request) {
|
||||||
is SyncProfileRequest -> edziennikInterface?.sync(
|
is SyncProfileRequest -> edziennikInterface?.sync(
|
||||||
featureIds = request.viewIds?.flatMap { Features.getIdsByView(it.first, it.second) } ?: Features.getAllIds(),
|
featureIds = request.viewIds?.flatMap { Features.getIdsByView(it.first, it.second) }
|
||||||
|
?: Features.getAllIds(),
|
||||||
viewId = request.viewIds?.get(0)?.first,
|
viewId = request.viewIds?.get(0)?.first,
|
||||||
arguments = request.arguments)
|
arguments = request.arguments)
|
||||||
is MessageGetRequest -> edziennikInterface?.getMessage(request.message)
|
is MessageGetRequest -> edziennikInterface?.getMessage(request.message)
|
||||||
is FirstLoginRequest -> edziennikInterface?.firstLogin()
|
is FirstLoginRequest -> edziennikInterface?.firstLogin()
|
||||||
is AnnouncementsReadRequest -> edziennikInterface?.markAllAnnouncementsAsRead()
|
is AnnouncementsReadRequest -> edziennikInterface?.markAllAnnouncementsAsRead()
|
||||||
|
is AttachmentGetRequest -> edziennikInterface?.getAttachment(request.messageId, request.attachmentId, request.attachmentName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,4 +92,5 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
|||||||
data class SyncProfileListRequest(val profileList: List<Int>)
|
data class SyncProfileListRequest(val profileList: List<Int>)
|
||||||
data class MessageGetRequest(val message: MessageFull)
|
data class MessageGetRequest(val message: MessageFull)
|
||||||
class AnnouncementsReadRequest
|
class AnnouncementsReadRequest
|
||||||
|
data class AttachmentGetRequest(val messageId: Long, val attachmentId: Long, val attachmentName: String)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.MainActivity
|
|||||||
import pl.szczodrzynski.edziennik.Notifier.ID_NOTIFICATIONS
|
import pl.szczodrzynski.edziennik.Notifier.ID_NOTIFICATIONS
|
||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.notification.getNotificationTitle
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Notification
|
import pl.szczodrzynski.edziennik.utils.models.Notification
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
@ -33,9 +34,9 @@ class NotifyTask : IApiTask(-1) {
|
|||||||
val pendingIntent = PendingIntent.getActivity(app, notification.id, intent, 0)
|
val pendingIntent = PendingIntent.getActivity(app, notification.id, intent, 0)
|
||||||
val notificationBuilder = NotificationCompat.Builder(app, app.notifier.notificationGroup)
|
val notificationBuilder = NotificationCompat.Builder(app, app.notifier.notificationGroup)
|
||||||
// title, text, type, date
|
// title, text, type, date
|
||||||
.setContentTitle(notification.title)
|
.setContentTitle(notification.profileName)
|
||||||
.setContentText(notification.text)
|
.setContentText(notification.text)
|
||||||
.setSubText(Notification.stringType(app, notification.type))
|
.setSubText(app.getNotificationTitle(notification.type))
|
||||||
.setWhen(notification.addedDate)
|
.setWhen(notification.addedDate)
|
||||||
.setTicker(app.getString(R.string.notification_ticker_format, Notification.stringType(app, notification.type)))
|
.setTicker(app.getString(R.string.notification_ticker_format, Notification.stringType(app, notification.type)))
|
||||||
// icon, color, lights, priority
|
// icon, color, lights, priority
|
||||||
|
@ -138,10 +138,12 @@ class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(
|
|||||||
val teacher = teacherList.singleOrNull { it.fullName == "$firstName $lastName" }
|
val teacher = teacherList.singleOrNull { it.fullName == "$firstName $lastName" }
|
||||||
return validateTeacher(teacher, firstName, lastName)
|
return validateTeacher(teacher, firstName, lastName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTeacher(firstNameChar: Char, lastName: String): Teacher {
|
fun getTeacher(firstNameChar: Char, lastName: String): Teacher {
|
||||||
val teacher = teacherList.singleOrNull { it.shortName == "$firstNameChar.$lastName" }
|
val teacher = teacherList.singleOrNull { it.shortName == "$firstNameChar.$lastName" }
|
||||||
return validateTeacher(teacher, firstNameChar.toString(), lastName)
|
return validateTeacher(teacher, firstNameChar.toString(), lastName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTeacherByLastFirst(nameLastFirst: String): Teacher {
|
fun getTeacherByLastFirst(nameLastFirst: String): Teacher {
|
||||||
val nameParts = nameLastFirst.split(" ")
|
val nameParts = nameLastFirst.split(" ")
|
||||||
return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[1], nameParts[0])
|
return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[1], nameParts[0])
|
||||||
|
@ -70,6 +70,10 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
override fun firstLogin() {
|
override fun firstLogin() {
|
||||||
IdziennikFirstLogin(data) {
|
IdziennikFirstLogin(data) {
|
||||||
completed()
|
completed()
|
||||||
|
@ -11,6 +11,7 @@ const val ENDPOINT_IDZIENNIK_WEB_TIMETABLE = 1030
|
|||||||
const val ENDPOINT_IDZIENNIK_WEB_GRADES = 1040
|
const val ENDPOINT_IDZIENNIK_WEB_GRADES = 1040
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES = 1050
|
const val ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES = 1050
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_EXAMS = 1060
|
const val ENDPOINT_IDZIENNIK_WEB_EXAMS = 1060
|
||||||
|
const val ENDPOINT_IDZIENNIK_WEB_HOMEWORK = 1061
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_NOTICES = 1070
|
const val ENDPOINT_IDZIENNIK_WEB_NOTICES = 1070
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS = 1080
|
const val ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS = 1080
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_ATTENDANCE = 1090
|
const val ENDPOINT_IDZIENNIK_WEB_ATTENDANCE = 1090
|
||||||
@ -34,6 +35,10 @@ val IdziennikFeatures = listOf(
|
|||||||
ENDPOINT_IDZIENNIK_WEB_EXAMS to LOGIN_METHOD_IDZIENNIK_WEB
|
ENDPOINT_IDZIENNIK_WEB_EXAMS to LOGIN_METHOD_IDZIENNIK_WEB
|
||||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
||||||
|
|
||||||
|
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_HOMEWORK, listOf(
|
||||||
|
ENDPOINT_IDZIENNIK_WEB_HOMEWORK to LOGIN_METHOD_IDZIENNIK_WEB
|
||||||
|
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
||||||
|
|
||||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_BEHAVIOUR, listOf(
|
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_BEHAVIOUR, listOf(
|
||||||
ENDPOINT_IDZIENNIK_WEB_NOTICES to LOGIN_METHOD_IDZIENNIK_WEB
|
ENDPOINT_IDZIENNIK_WEB_NOTICES to LOGIN_METHOD_IDZIENNIK_WEB
|
||||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
||||||
|
@ -55,6 +55,10 @@ class IdziennikData(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
|||||||
data.startProgress(R.string.edziennik_progress_endpoint_exams)
|
data.startProgress(R.string.edziennik_progress_endpoint_exams)
|
||||||
IdziennikWebExams(data, onSuccess)
|
IdziennikWebExams(data, onSuccess)
|
||||||
}
|
}
|
||||||
|
ENDPOINT_IDZIENNIK_WEB_HOMEWORK -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
||||||
|
IdziennikWebHomework(data, onSuccess)
|
||||||
|
}
|
||||||
ENDPOINT_IDZIENNIK_WEB_NOTICES -> {
|
ENDPOINT_IDZIENNIK_WEB_NOTICES -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
||||||
IdziennikWebNotices(data, onSuccess)
|
IdziennikWebNotices(data, onSuccess)
|
||||||
|
@ -94,6 +94,7 @@ open class IdziennikWeb(open val data: DataIdziennik) {
|
|||||||
is Long -> json.addProperty(name, value)
|
is Long -> json.addProperty(name, value)
|
||||||
is Float -> json.addProperty(name, value)
|
is Float -> json.addProperty(name, value)
|
||||||
is Char -> json.addProperty(name, value)
|
is Char -> json.addProperty(name, value)
|
||||||
|
is Boolean -> json.addProperty(name, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setJsonBody(json)
|
setJsonBody(json)
|
||||||
|
@ -5,21 +5,21 @@
|
|||||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||||
|
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.*
|
||||||
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
||||||
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_EXAMS
|
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_EXAMS
|
||||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_EXAMS
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_EXAMS
|
||||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.Lesson
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
import pl.szczodrzynski.edziennik.getJsonObject
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
class IdziennikWebExams(override val data: DataIdziennik,
|
class IdziennikWebExams(override val data: DataIdziennik,
|
||||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "IdziennikWebExams"
|
private const val TAG = "IdziennikWebExams"
|
||||||
}
|
}
|
||||||
@ -34,14 +34,15 @@ class IdziennikWebExams(override val data: DataIdziennik,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getExams() {
|
private fun getExams() {
|
||||||
val param = JsonObject()
|
val param = JsonObject().apply {
|
||||||
param.addProperty("strona", 1)
|
addProperty("strona", 1)
|
||||||
param.addProperty("iloscNaStrone", "99")
|
addProperty("iloscNaStrone", "99")
|
||||||
param.addProperty("iloscRekordow", -1)
|
addProperty("iloscRekordow", -1)
|
||||||
param.addProperty("kolumnaSort", "ss.Nazwa,sp.Data_sprawdzianu")
|
addProperty("kolumnaSort", "ss.Nazwa,sp.Data_sprawdzianu")
|
||||||
param.addProperty("kierunekSort", 0)
|
addProperty("kierunekSort", 0)
|
||||||
param.addProperty("maxIloscZaznaczonych", 0)
|
addProperty("maxIloscZaznaczonych", 0)
|
||||||
param.addProperty("panelFiltrow", 0)
|
addProperty("panelFiltrow", 0)
|
||||||
|
}
|
||||||
|
|
||||||
webApiGet(TAG, IDZIENNIK_WEB_EXAMS, mapOf(
|
webApiGet(TAG, IDZIENNIK_WEB_EXAMS, mapOf(
|
||||||
"idP" to data.registerId,
|
"idP" to data.registerId,
|
||||||
@ -55,28 +56,33 @@ class IdziennikWebExams(override val data: DataIdziennik,
|
|||||||
return@webApiGet
|
return@webApiGet
|
||||||
}
|
}
|
||||||
|
|
||||||
for (jExamEl in json.getAsJsonArray("ListK")) {
|
json.getJsonArray("ListK")?.asJsonObjectList()?.forEach { exam ->
|
||||||
val jExam = jExamEl.asJsonObject
|
val id = exam.getLong("_recordId") ?: return@forEach
|
||||||
// jExam
|
val examDate = Date.fromY_m_d(exam.getString("data") ?: return@forEach)
|
||||||
val eventId = jExam.get("_recordId").asLong
|
val subjectId = data.getSubject(exam.getString("przedmiot") ?: return@forEach,
|
||||||
val rSubject = data.getSubject(jExam.get("przedmiot").asString, -1, "")
|
-1, "").id
|
||||||
val rTeacher = data.getTeacherByLastFirst(jExam.get("wpisal").asString)
|
val teacherId = data.getTeacherByLastFirst(exam.getString("wpisal")
|
||||||
val examDate = Date.fromY_m_d(jExam.get("data").asString)
|
?: return@forEach).id
|
||||||
val lessonObject = Lesson.getByWeekDayAndSubject(data.lessonList, examDate.weekDay, rSubject.id)
|
val lessonList = data.db.timetableDao().getForDateNow(profileId, examDate)
|
||||||
val examTime = lessonObject?.startTime
|
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime
|
||||||
|
val topic = exam.getString("zakres") ?: ""
|
||||||
|
|
||||||
|
val eventType = when (exam.getString("rodzaj")) {
|
||||||
|
"sprawdzian/praca klasowa" -> Event.TYPE_EXAM
|
||||||
|
else -> Event.TYPE_SHORT_QUIZ
|
||||||
|
}
|
||||||
|
|
||||||
val eventType = if (jExam.get("rodzaj").asString == "sprawdzian/praca klasowa") Event.TYPE_EXAM else Event.TYPE_SHORT_QUIZ
|
|
||||||
val eventObject = Event(
|
val eventObject = Event(
|
||||||
profileId,
|
profileId,
|
||||||
eventId,
|
id,
|
||||||
examDate,
|
examDate,
|
||||||
examTime,
|
startTime,
|
||||||
jExam.get("zakres").asString,
|
topic,
|
||||||
-1,
|
-1,
|
||||||
eventType,
|
eventType,
|
||||||
false,
|
false,
|
||||||
rTeacher.id,
|
teacherId,
|
||||||
rSubject.id,
|
subjectId,
|
||||||
data.teamClass?.id ?: -1
|
data.teamClass?.id ?: -1
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -106,9 +112,11 @@ class IdziennikWebExams(override val data: DataIdziennik,
|
|||||||
examsNextMonthChecked = true
|
examsNextMonthChecked = true
|
||||||
getExams()
|
getExams()
|
||||||
} else {
|
} else {
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_EXAMS, SYNC_ALWAYS)
|
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_EXAMS, SYNC_ALWAYS)
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.*
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_HOMEWORK
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_HOMEWORK
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
|
class IdziennikWebHomework(override val data: DataIdziennik,
|
||||||
|
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "IdziennikWebHomework"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val param = JsonObject().apply {
|
||||||
|
addProperty("strona", 1)
|
||||||
|
addProperty("iloscNaStrone", 997)
|
||||||
|
addProperty("iloscRekordow", -1)
|
||||||
|
addProperty("kolumnaSort", "DataZadania")
|
||||||
|
addProperty("kierunekSort", 0)
|
||||||
|
addProperty("maxIloscZaznaczonych", 0)
|
||||||
|
addProperty("panelFiltrow", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
webApiGet(TAG, IDZIENNIK_WEB_HOMEWORK, mapOf(
|
||||||
|
"idP" to data.registerId,
|
||||||
|
"data" to Date.getToday().stringY_m_d,
|
||||||
|
"wszystkie" to true,
|
||||||
|
"param" to param
|
||||||
|
)) { result ->
|
||||||
|
val json = result.getJsonObject("d") ?: run {
|
||||||
|
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
||||||
|
.withApiResponse(result))
|
||||||
|
return@webApiGet
|
||||||
|
}
|
||||||
|
|
||||||
|
json.getJsonArray("ListK")?.asJsonObjectList()?.forEach { homework ->
|
||||||
|
val id = homework.getLong("_recordId") ?: return@forEach
|
||||||
|
val eventDate = Date.fromY_m_d(homework.getString("dataO") ?: return@forEach)
|
||||||
|
val subjectId = data.getSubject(homework.getString("przed") ?: return@forEach,
|
||||||
|
-1, "").id
|
||||||
|
val teacherId = data.getTeacherByLastFirst(homework.getString("usr")
|
||||||
|
?: return@forEach).id
|
||||||
|
val lessonList = data.db.timetableDao().getForDateNow(profileId, eventDate)
|
||||||
|
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.displayStartTime
|
||||||
|
val topic = homework.getString("tytul") ?: ""
|
||||||
|
|
||||||
|
val seen = when (profile?.empty) {
|
||||||
|
true -> true
|
||||||
|
else -> eventDate < Date.getToday()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val eventObject = Event(
|
||||||
|
profileId,
|
||||||
|
id,
|
||||||
|
eventDate,
|
||||||
|
startTime,
|
||||||
|
topic,
|
||||||
|
-1,
|
||||||
|
Event.TYPE_HOMEWORK,
|
||||||
|
false,
|
||||||
|
teacherId,
|
||||||
|
subjectId,
|
||||||
|
data.teamClass?.id ?: -1
|
||||||
|
)
|
||||||
|
|
||||||
|
data.eventList.add(eventObject)
|
||||||
|
data.metadataList.add(Metadata(
|
||||||
|
profileId,
|
||||||
|
Metadata.TYPE_HOMEWORK,
|
||||||
|
eventObject.id,
|
||||||
|
seen,
|
||||||
|
seen,
|
||||||
|
System.currentTimeMillis()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||||
|
|
||||||
|
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_HOMEWORK, SYNC_ALWAYS)
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-27.
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-22
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||||
@ -12,33 +12,38 @@ import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_TIMETABLE
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_TIMETABLE
|
||||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.Lesson
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange.TYPE_CANCELLED
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange.TYPE_CHANGE
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonRange
|
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonRange
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||||
|
|
||||||
class IdziennikWebTimetable(override val data: DataIdziennik,
|
class IdziennikWebTimetable(override val data: DataIdziennik,
|
||||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "IdziennikWebTimetable"
|
private const val TAG = "IdziennikWebTimetable"
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init { data.profile?.also { profile ->
|
||||||
val weekStart = Week.getWeekStart()
|
val currentWeekStart = Week.getWeekStart()
|
||||||
|
|
||||||
if (Date.getToday().weekDay > 4) {
|
if (Date.getToday().weekDay > 4) {
|
||||||
weekStart.stepForward(0, 0, 7)
|
currentWeekStart.stepForward(0, 0, 7)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
||||||
|
|
||||||
|
val weekStart = Date.fromY_m_d(getDate)
|
||||||
|
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||||
|
|
||||||
webApiGet(TAG, IDZIENNIK_WEB_TIMETABLE, mapOf(
|
webApiGet(TAG, IDZIENNIK_WEB_TIMETABLE, mapOf(
|
||||||
"idPozDziennika" to data.registerId,
|
"idPozDziennika" to data.registerId,
|
||||||
"pidRokSzkolny" to data.schoolYearId,
|
"pidRokSzkolny" to data.schoolYearId,
|
||||||
"data" to weekStart.stringY_m_d+"T10:00:00.000Z"
|
"data" to "${weekStart.stringY_m_d}T10:00:00.000Z"
|
||||||
)) { result ->
|
)) { result ->
|
||||||
val json = result.getJsonObject("d") ?: run {
|
val json = result.getJsonObject("d") ?: run {
|
||||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
||||||
@ -56,73 +61,132 @@ class IdziennikWebTimetable(override val data: DataIdziennik,
|
|||||||
data.lessonRanges[lessonRange.lessonNumber] = lessonRange
|
data.lessonRanges[lessonRange.lessonNumber] = lessonRange
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val dates = mutableSetOf<Int>()
|
||||||
|
val lessons = mutableListOf<Lesson>()
|
||||||
|
|
||||||
json.getJsonArray("Przedmioty")?.asJsonObjectList()?.forEach { lesson ->
|
json.getJsonArray("Przedmioty")?.asJsonObjectList()?.forEach { lesson ->
|
||||||
val subject = data.getSubject(
|
val subject = data.getSubject(
|
||||||
lesson.getString("Nazwa") ?: return@forEach,
|
lesson.getString("Nazwa") ?: return@forEach,
|
||||||
lesson.getLong("Id"),
|
lesson.getLong("Id"),
|
||||||
lesson.getString("Skrot") ?: ""
|
lesson.getString("Skrot") ?: ""
|
||||||
)
|
)
|
||||||
val teacher = data.getTeacherByFDotLast(lesson.getString("Nauczyciel") ?: return@forEach)
|
val teacher = data.getTeacherByFDotLast(lesson.getString("Nauczyciel")
|
||||||
val weekDay = lesson.getInt("DzienTygodnia")?.minus(1) ?: return@forEach
|
?: return@forEach)
|
||||||
val lessonRange = data.lessonRanges[lesson.getInt("Godzina")?.plus(1) ?: return@forEach]
|
|
||||||
|
|
||||||
val lessonObject = Lesson(
|
val newSubjectName = lesson.getString("PrzedmiotZastepujacy")
|
||||||
profileId,
|
val newSubject = when (newSubjectName.isNullOrBlank()) {
|
||||||
weekDay,
|
true -> null
|
||||||
lessonRange.startTime,
|
else -> data.getSubject(newSubjectName, null, newSubjectName)
|
||||||
lessonRange.endTime
|
|
||||||
).apply {
|
|
||||||
subjectId = subject.id
|
|
||||||
teacherId = teacher.id
|
|
||||||
teamId = data.teamClass?.id ?: -1
|
|
||||||
classroomName = lesson.getString("NazwaSali") ?: ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data.lessonList.add(lessonObject)
|
val newTeacherName = lesson.getString("NauZastepujacy")
|
||||||
|
val newTeacher = when (newTeacherName.isNullOrBlank()) {
|
||||||
|
true -> null
|
||||||
|
else -> data.getTeacherByFDotLast(newTeacherName)
|
||||||
|
}
|
||||||
|
|
||||||
|
val weekDay = lesson.getInt("DzienTygodnia")?.minus(1) ?: return@forEach
|
||||||
|
val lessonRange = data.lessonRanges[lesson.getInt("Godzina")?.plus(1)
|
||||||
|
?: return@forEach]
|
||||||
|
val lessonDate = weekStart.clone().stepForward(0, 0, weekDay)
|
||||||
|
val classroom = lesson.getString("NazwaSali")
|
||||||
|
|
||||||
val type = lesson.getInt("TypZastepstwa") ?: -1
|
val type = lesson.getInt("TypZastepstwa") ?: -1
|
||||||
if (type != -1) {
|
|
||||||
// we have a lesson change to process
|
|
||||||
val lessonChangeObject = LessonChange(
|
|
||||||
profileId,
|
|
||||||
weekStart.clone().stepForward(0, 0, weekDay),
|
|
||||||
lessonObject.startTime,
|
|
||||||
lessonObject.endTime
|
|
||||||
)
|
|
||||||
|
|
||||||
lessonChangeObject.teamId = lessonObject.teamId
|
val lessonObject = Lesson(profileId, -1)
|
||||||
lessonChangeObject.teacherId = lessonObject.teacherId
|
|
||||||
lessonChangeObject.subjectId = lessonObject.subjectId
|
when (type) {
|
||||||
lessonChangeObject.classroomName = lessonObject.classroomName
|
1, 2, 3, 4, 5 -> {
|
||||||
when (type) {
|
lessonObject.apply {
|
||||||
0 -> lessonChangeObject.type = TYPE_CANCELLED
|
this.type = Lesson.TYPE_CHANGE
|
||||||
1, 2, 3, 4, 5 -> {
|
|
||||||
lessonChangeObject.type = TYPE_CHANGE
|
this.date = lessonDate
|
||||||
val newTeacher = lesson.getString("NauZastepujacy")
|
this.lessonNumber = lessonRange.lessonNumber
|
||||||
val newSubject = lesson.getString("PrzedmiotZastepujacy")
|
this.startTime = lessonRange.startTime
|
||||||
if (newTeacher != null) {
|
this.endTime = lessonRange.endTime
|
||||||
lessonChangeObject.teacherId = data.getTeacherByFDotLast(newTeacher).id
|
this.subjectId = newSubject?.id
|
||||||
}
|
this.teacherId = newTeacher?.id
|
||||||
if (newSubject != null) {
|
this.teamId = data.teamClass?.id
|
||||||
lessonChangeObject.subjectId = data.getSubject(newSubject, null, "").id
|
this.classroom = classroom
|
||||||
}
|
|
||||||
|
this.oldDate = lessonDate
|
||||||
|
this.oldLessonNumber = lessonRange.lessonNumber
|
||||||
|
this.oldStartTime = lessonRange.startTime
|
||||||
|
this.oldEndTime = lessonRange.endTime
|
||||||
|
this.oldSubjectId = subject.id
|
||||||
|
this.oldTeacherId = teacher.id
|
||||||
|
this.oldTeamId = data.teamClass?.id
|
||||||
|
this.oldClassroom = classroom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
0 -> {
|
||||||
|
lessonObject.apply {
|
||||||
|
this.type = Lesson.TYPE_CANCELLED
|
||||||
|
|
||||||
data.lessonChangeList.add(lessonChangeObject)
|
this.oldDate = lessonDate
|
||||||
|
this.oldLessonNumber = lessonRange.lessonNumber
|
||||||
|
this.oldStartTime = lessonRange.startTime
|
||||||
|
this.oldEndTime = lessonRange.endTime
|
||||||
|
this.oldSubjectId = subject.id
|
||||||
|
this.oldTeacherId = teacher.id
|
||||||
|
this.oldTeamId = data.teamClass?.id
|
||||||
|
this.oldClassroom = classroom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
lessonObject.apply {
|
||||||
|
this.type = Lesson.TYPE_NORMAL
|
||||||
|
|
||||||
|
this.date = lessonDate
|
||||||
|
this.lessonNumber = lessonRange.lessonNumber
|
||||||
|
this.startTime = lessonRange.startTime
|
||||||
|
this.endTime = lessonRange.endTime
|
||||||
|
this.subjectId = subject.id
|
||||||
|
this.teacherId = teacher.id
|
||||||
|
this.teamId = data.teamClass?.id
|
||||||
|
this.classroom = classroom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lessonObject.id = lessonObject.buildId()
|
||||||
|
|
||||||
|
dates.add(lessonDate.value)
|
||||||
|
lessons.add(lessonObject)
|
||||||
|
|
||||||
|
val seen = profile.empty || lessonDate < Date.getToday()
|
||||||
|
|
||||||
|
if (lessonObject.type != Lesson.TYPE_NORMAL && lessonDate >= Date.getToday()) {
|
||||||
data.metadataList.add(Metadata(
|
data.metadataList.add(Metadata(
|
||||||
profileId,
|
profileId,
|
||||||
Metadata.TYPE_LESSON_CHANGE,
|
Metadata.TYPE_LESSON_CHANGE,
|
||||||
lessonChangeObject.id,
|
lessonObject.id,
|
||||||
profile?.empty ?: false,
|
seen,
|
||||||
profile?.empty ?: false,
|
seen,
|
||||||
System.currentTimeMillis()
|
System.currentTimeMillis()
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val date: Date = weekStart.clone()
|
||||||
|
while (date <= weekEnd) {
|
||||||
|
if (!dates.contains(date.value)) {
|
||||||
|
lessons.add(Lesson(profileId, date.value.toLong()).apply {
|
||||||
|
this.type = Lesson.TYPE_NO_LESSONS
|
||||||
|
this.date = date.clone()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
date.stepForward(0, 0, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
||||||
|
|
||||||
|
data.lessonNewList.addAll(lessons)
|
||||||
|
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
|
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ interface EdziennikInterface {
|
|||||||
fun sync(featureIds: List<Int>, viewId: Int? = null, arguments: JsonObject? = null)
|
fun sync(featureIds: List<Int>, viewId: Int? = null, arguments: JsonObject? = null)
|
||||||
fun getMessage(message: MessageFull)
|
fun getMessage(message: MessageFull)
|
||||||
fun markAllAnnouncementsAsRead()
|
fun markAllAnnouncementsAsRead()
|
||||||
|
fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String)
|
||||||
fun firstLogin()
|
fun firstLogin()
|
||||||
fun cancel()
|
fun cancel()
|
||||||
}
|
}
|
||||||
|
@ -10,13 +10,11 @@ import pl.szczodrzynski.edziennik.api.v2.*
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusData
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusData
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.messages.LibrusMessagesGetAttachment
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.messages.LibrusMessagesGetMessage
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.messages.LibrusMessagesGetMessage
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.synergia.LibrusSynergiaMarkAllAnnouncementsAsRead
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.synergia.LibrusSynergiaMarkAllAnnouncementsAsRead
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.firstlogin.LibrusFirstLogin
|
import pl.szczodrzynski.edziennik.api.v2.librus.firstlogin.LibrusFirstLogin
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLogin
|
import pl.szczodrzynski.edziennik.api.v2.librus.login.*
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginApi
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginMessages
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginSynergia
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||||
@ -82,11 +80,13 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getMessage(message: MessageFull) {
|
override fun getMessage(message: MessageFull) {
|
||||||
LibrusLoginApi(data) {
|
LibrusLoginPortal(data) {
|
||||||
LibrusLoginSynergia(data) {
|
LibrusLoginApi(data) {
|
||||||
LibrusLoginMessages(data) {
|
LibrusLoginSynergia(data) {
|
||||||
LibrusMessagesGetMessage(data, message) {
|
LibrusLoginMessages(data) {
|
||||||
completed()
|
LibrusMessagesGetMessage(data, message) {
|
||||||
|
completed()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,10 +94,26 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun markAllAnnouncementsAsRead() {
|
override fun markAllAnnouncementsAsRead() {
|
||||||
LibrusLoginApi(data) {
|
LibrusLoginPortal(data) {
|
||||||
LibrusLoginSynergia(data) {
|
LibrusLoginApi(data) {
|
||||||
LibrusSynergiaMarkAllAnnouncementsAsRead(data) {
|
LibrusLoginSynergia(data) {
|
||||||
completed()
|
LibrusSynergiaMarkAllAnnouncementsAsRead(data) {
|
||||||
|
completed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String) {
|
||||||
|
LibrusLoginPortal(data) {
|
||||||
|
LibrusLoginApi(data) {
|
||||||
|
LibrusLoginSynergia(data) {
|
||||||
|
LibrusLoginMessages(data) {
|
||||||
|
LibrusMessagesGetAttachment(data, messageId, attachmentId, attachmentName) {
|
||||||
|
completed()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_GC = 1023
|
|||||||
const val ENDPOINT_LIBRUS_API_TEXT_GC = 1024
|
const val ENDPOINT_LIBRUS_API_TEXT_GC = 1024
|
||||||
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GC = 1025
|
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GC = 1025
|
||||||
const val ENDPOINT_LIBRUS_API_BEHAVIOUR_GC = 1026
|
const val ENDPOINT_LIBRUS_API_BEHAVIOUR_GC = 1026
|
||||||
|
const val ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS = 1030
|
||||||
const val ENDPOINT_LIBRUS_API_NORMAL_GRADES = 1031
|
const val ENDPOINT_LIBRUS_API_NORMAL_GRADES = 1031
|
||||||
const val ENDPOINT_LIBRUS_API_POINT_GRADES = 1032
|
const val ENDPOINT_LIBRUS_API_POINT_GRADES = 1032
|
||||||
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES = 1033
|
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES = 1033
|
||||||
@ -97,6 +98,7 @@ val LibrusFeatures = listOf(
|
|||||||
ENDPOINT_LIBRUS_API_TEXT_GC to LOGIN_METHOD_LIBRUS_API,
|
ENDPOINT_LIBRUS_API_TEXT_GC to LOGIN_METHOD_LIBRUS_API,
|
||||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GC to LOGIN_METHOD_LIBRUS_API,
|
ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GC to LOGIN_METHOD_LIBRUS_API,
|
||||||
ENDPOINT_LIBRUS_API_BEHAVIOUR_GC to LOGIN_METHOD_LIBRUS_API,
|
ENDPOINT_LIBRUS_API_BEHAVIOUR_GC to LOGIN_METHOD_LIBRUS_API,
|
||||||
|
ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS to LOGIN_METHOD_LIBRUS_API,
|
||||||
ENDPOINT_LIBRUS_API_NORMAL_GRADES to LOGIN_METHOD_LIBRUS_API,
|
ENDPOINT_LIBRUS_API_NORMAL_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||||
ENDPOINT_LIBRUS_API_POINT_GRADES to LOGIN_METHOD_LIBRUS_API,
|
ENDPOINT_LIBRUS_API_POINT_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES to LOGIN_METHOD_LIBRUS_API,
|
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||||
|
@ -32,6 +32,13 @@ open class LibrusApi(open val data: DataLibrus) {
|
|||||||
|
|
||||||
val callback = object : JsonCallbackHandler() {
|
val callback = object : JsonCallbackHandler() {
|
||||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||||
|
if (response?.code() == HTTP_UNAVAILABLE) {
|
||||||
|
data.error(ApiError(tag, ERROR_LIBRUS_API_MAINTENANCE)
|
||||||
|
.withApiResponse(json)
|
||||||
|
.withResponse(response))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (json == null && response?.parserErrorBody == null) {
|
if (json == null && response?.parserErrorBody == null) {
|
||||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||||
.withResponse(response))
|
.withResponse(response))
|
||||||
@ -104,6 +111,7 @@ open class LibrusApi(open val data: DataLibrus) {
|
|||||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||||
.allowErrorCode(HTTP_FORBIDDEN)
|
.allowErrorCode(HTTP_FORBIDDEN)
|
||||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||||
|
.allowErrorCode(HTTP_UNAVAILABLE)
|
||||||
.callback(callback)
|
.callback(callback)
|
||||||
.build()
|
.build()
|
||||||
.enqueue()
|
.enqueue()
|
||||||
|
@ -85,6 +85,10 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
||||||
LibrusApiGrades(data, onSuccess)
|
LibrusApiGrades(data, onSuccess)
|
||||||
}
|
}
|
||||||
|
ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_grade_comments)
|
||||||
|
LibrusApiGradeComments(data, onSuccess)
|
||||||
|
}
|
||||||
ENDPOINT_LIBRUS_API_NORMAL_GC -> {
|
ENDPOINT_LIBRUS_API_NORMAL_GC -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_grade_categories)
|
data.startProgress(R.string.edziennik_progress_endpoint_grade_categories)
|
||||||
LibrusApiGradeCategories(data, onSuccess)
|
LibrusApiGradeCategories(data, onSuccess)
|
||||||
|
@ -4,9 +4,12 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.librus.data
|
package pl.szczodrzynski.edziennik.api.v2.librus.data
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
import im.wangchao.mhttp.Request
|
import im.wangchao.mhttp.Request
|
||||||
import im.wangchao.mhttp.Response
|
import im.wangchao.mhttp.Response
|
||||||
import im.wangchao.mhttp.body.MediaTypeUtils
|
import im.wangchao.mhttp.body.MediaTypeUtils
|
||||||
|
import im.wangchao.mhttp.callback.FileCallbackHandler
|
||||||
|
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||||
import okhttp3.Cookie
|
import okhttp3.Cookie
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
@ -15,8 +18,8 @@ import org.jsoup.parser.Parser
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.*
|
import pl.szczodrzynski.edziennik.api.v2.*
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
import pl.szczodrzynski.edziennik.get
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
import java.io.File
|
||||||
import java.io.StringWriter
|
import java.io.StringWriter
|
||||||
import javax.xml.parsers.DocumentBuilderFactory
|
import javax.xml.parsers.DocumentBuilderFactory
|
||||||
import javax.xml.transform.OutputKeys
|
import javax.xml.transform.OutputKeys
|
||||||
@ -43,19 +46,19 @@ open class LibrusMessages(open val data: DataLibrus) {
|
|||||||
val callback = object : TextCallbackHandler() {
|
val callback = object : TextCallbackHandler() {
|
||||||
override fun onSuccess(text: String?, response: Response?) {
|
override fun onSuccess(text: String?, response: Response?) {
|
||||||
if (text.isNullOrEmpty()) {
|
if (text.isNullOrEmpty()) {
|
||||||
data.error(ApiError(LibrusSynergia.TAG, ERROR_RESPONSE_EMPTY)
|
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||||
.withResponse(response))
|
.withResponse(response))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Finish error handling
|
when {
|
||||||
|
text.contains("<message>Niepoprawny login i/lub hasło.</message>") -> data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN, response, text)
|
||||||
if ("error" in text) {
|
text.contains("stop.png") -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
|
||||||
when ("<type>(.*)</type>".toRegex().find(text)?.get(1)) {
|
text.contains("eAccessDeny") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||||
"eAccessDeny" -> data.error(ApiError(tag, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED)
|
text.contains("OffLine") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_MAINTENANCE, response, text)
|
||||||
.withResponse(response)
|
text.contains("<status>error</status>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ERROR, response, text)
|
||||||
.withApiResponse(text))
|
text.contains("<type>eVarWhitThisNameNotExists</type>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||||
}
|
text.contains("<error>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -132,4 +135,95 @@ open class LibrusMessages(open val data: DataLibrus) {
|
|||||||
.build()
|
.build()
|
||||||
.enqueue()
|
.enqueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun sandboxGet(tag: String, action: String, parameters: Map<String, Any>? = null,
|
||||||
|
onSuccess: (json: JsonObject) -> Unit) {
|
||||||
|
|
||||||
|
d(tag, "Request: Librus/Messages - $LIBRUS_SANDBOX_URL$action")
|
||||||
|
|
||||||
|
val callback = object : JsonCallbackHandler() {
|
||||||
|
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||||
|
if (json == null) {
|
||||||
|
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||||
|
.withResponse(response))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
onSuccess(json)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(e)
|
||||||
|
.withApiResponse(json))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||||
|
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(throwable))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Request.builder()
|
||||||
|
.url("$LIBRUS_SANDBOX_URL$action")
|
||||||
|
.userAgent(SYNERGIA_USER_AGENT)
|
||||||
|
.apply {
|
||||||
|
parameters?.forEach { (k, v) ->
|
||||||
|
addParameter(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.post()
|
||||||
|
.callback(callback)
|
||||||
|
.build()
|
||||||
|
.enqueue()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sandboxGetFile(tag: String, action: String, targetFile: File, onSuccess: (file: File) -> Unit,
|
||||||
|
onProgress: (written: Long, total: Long) -> Unit) {
|
||||||
|
|
||||||
|
d(tag, "Request: Librus/Messages - $LIBRUS_SANDBOX_URL$action")
|
||||||
|
|
||||||
|
val callback = object : FileCallbackHandler(targetFile) {
|
||||||
|
override fun onSuccess(file: File?, response: Response?) {
|
||||||
|
if (file == null) {
|
||||||
|
data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
|
||||||
|
.withResponse(response))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
onSuccess(file)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onProgress(bytesWritten: Long, bytesTotal: Long) {
|
||||||
|
try {
|
||||||
|
onProgress(bytesWritten, bytesTotal)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
|
||||||
|
.withThrowable(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||||
|
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(throwable))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Request.builder()
|
||||||
|
.url("$LIBRUS_SANDBOX_URL$action")
|
||||||
|
.userAgent(SYNERGIA_USER_AGENT)
|
||||||
|
.post()
|
||||||
|
.callback(callback)
|
||||||
|
.build()
|
||||||
|
.enqueue()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ import pl.szczodrzynski.edziennik.utils.Utils.d
|
|||||||
|
|
||||||
open class LibrusSynergia(open val data: DataLibrus) {
|
open class LibrusSynergia(open val data: DataLibrus) {
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "LibrusSynergia"
|
private const val TAG = "LibrusSynergia"
|
||||||
}
|
}
|
||||||
|
|
||||||
val profileId
|
val profileId
|
||||||
|
@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.*
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_EVENTS
|
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_EVENTS
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
@ -69,6 +70,8 @@ class LibrusApiEvents(override val data: DataLibrus,
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_LIBRUS_API_EVENTS, SYNC_ALWAYS)
|
data.setSyncNext(ENDPOINT_LIBRUS_API_EVENTS, SYNC_ALWAYS)
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-20
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||||
|
import pl.szczodrzynski.edziennik.asJsonObjectList
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
|
||||||
|
import pl.szczodrzynski.edziennik.getJsonArray
|
||||||
|
import pl.szczodrzynski.edziennik.getLong
|
||||||
|
import pl.szczodrzynski.edziennik.getString
|
||||||
|
|
||||||
|
class LibrusApiGradeComments(override val data: DataLibrus,
|
||||||
|
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "LibrusApiGradeComments"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
apiGet(TAG, "Grades/Comments") { json ->
|
||||||
|
|
||||||
|
json.getJsonArray("Comments")?.asJsonObjectList()?.forEach { comment ->
|
||||||
|
val id = comment.getLong("Id") ?: return@forEach
|
||||||
|
val text = comment.getString("Text")
|
||||||
|
|
||||||
|
val gradeCategoryObject = GradeCategory(
|
||||||
|
profileId,
|
||||||
|
id,
|
||||||
|
-1f,
|
||||||
|
-1,
|
||||||
|
text
|
||||||
|
).apply {
|
||||||
|
type = GradeCategory.TYPE_COMMENT
|
||||||
|
}
|
||||||
|
|
||||||
|
data.gradeCategories.put(id, gradeCategoryObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
data.setSyncNext(ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS, SYNC_ALWAYS)
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADE
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
@ -42,12 +43,21 @@ class LibrusApiGrades(override val data: DataLibrus,
|
|||||||
weight = 0f
|
weight = 0f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val description = grade.getJsonArray("Comments")?.asJsonObjectList()?.let { comments ->
|
||||||
|
if (comments.isNotEmpty()) {
|
||||||
|
data.gradeCategories.singleOrNull {
|
||||||
|
it.type == GradeCategory.TYPE_COMMENT
|
||||||
|
&& it.categoryId == comments[0].asJsonObject.getLong("Id")
|
||||||
|
}?.text
|
||||||
|
} else null
|
||||||
|
} ?: ""
|
||||||
|
|
||||||
val gradeObject = Grade(
|
val gradeObject = Grade(
|
||||||
profileId,
|
profileId,
|
||||||
id,
|
id,
|
||||||
categoryName,
|
categoryName,
|
||||||
color,
|
color,
|
||||||
"",
|
description,
|
||||||
name,
|
name,
|
||||||
value,
|
value,
|
||||||
weight,
|
weight,
|
||||||
|
@ -8,6 +8,7 @@ import pl.szczodrzynski.edziennik.*
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_HOMEWORK
|
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_HOMEWORK
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
@ -55,6 +56,8 @@ class LibrusApiHomework(override val data: DataLibrus,
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_LIBRUS_API_HOMEWORK, SYNC_ALWAYS)
|
data.setSyncNext(ENDPOINT_LIBRUS_API_HOMEWORK, SYNC_ALWAYS)
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
|||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||||
|
|
||||||
class LibrusApiTimetables(override val data: DataLibrus,
|
class LibrusApiTimetables(override val data: DataLibrus,
|
||||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||||
@ -29,9 +30,18 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
|||||||
data.db.classroomDao().getAllNow(profileId).toSparseArray(data.classrooms) { it.id }
|
data.db.classroomDao().getAllNow(profileId).toSparseArray(data.classrooms) { it.id }
|
||||||
}
|
}
|
||||||
|
|
||||||
val currentWeekStart = Date.getToday().let { it.stepForward(0, 0, -it.weekDay) }
|
val currentWeekStart = Week.getWeekStart()
|
||||||
|
|
||||||
|
if (Date.getToday().weekDay > 4) {
|
||||||
|
currentWeekStart.stepForward(0, 0, 7)
|
||||||
|
}
|
||||||
|
|
||||||
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
||||||
apiGet(TAG, "Timetables?weekStart=$getDate") { json ->
|
|
||||||
|
val weekStart = Date.fromY_m_d(getDate)
|
||||||
|
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||||
|
|
||||||
|
apiGet(TAG, "Timetables?weekStart=${weekStart.stringY_m_d}") { json ->
|
||||||
val days = json.getJsonObject("Timetable")
|
val days = json.getJsonObject("Timetable")
|
||||||
|
|
||||||
days?.entrySet()?.forEach { (dateString, dayEl) ->
|
days?.entrySet()?.forEach { (dateString, dayEl) ->
|
||||||
@ -44,21 +54,19 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
|||||||
val lessonRange = lessonRangeEl?.asJsonArray?.asJsonObjectList()
|
val lessonRange = lessonRangeEl?.asJsonArray?.asJsonObjectList()
|
||||||
if (lessonRange?.isNullOrEmpty() == false)
|
if (lessonRange?.isNullOrEmpty() == false)
|
||||||
lessonsFound = true
|
lessonsFound = true
|
||||||
lessonRange?.forEachIndexed { index, lesson ->
|
lessonRange?.forEach { lesson ->
|
||||||
parseLesson(lessonDate, lesson)
|
parseLesson(lessonDate, lesson)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (day.isNullOrEmpty() || !lessonsFound) {
|
if (day.isNullOrEmpty() || !lessonsFound) {
|
||||||
data.lessonNewList += Lesson(profileId, lessonDate.value.toLong()).apply {
|
data.lessonNewList.add(Lesson(profileId, lessonDate.value.toLong()).apply {
|
||||||
type = Lesson.TYPE_NO_LESSONS
|
type = Lesson.TYPE_NO_LESSONS
|
||||||
date = lessonDate
|
date = lessonDate
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val weekStart = Date.fromY_m_d(getDate)
|
|
||||||
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
|
||||||
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
||||||
|
|
||||||
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||||
@ -67,7 +75,7 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseLesson(lessonDate: Date, lesson: JsonObject) {
|
private fun parseLesson(lessonDate: Date, lesson: JsonObject) { data.profile?.also { profile ->
|
||||||
val isSubstitution = lesson.getBoolean("IsSubstitutionClass") ?: false
|
val isSubstitution = lesson.getBoolean("IsSubstitutionClass") ?: false
|
||||||
val isCancelled = lesson.getBoolean("IsCanceled") ?: false
|
val isCancelled = lesson.getBoolean("IsCanceled") ?: false
|
||||||
|
|
||||||
@ -80,8 +88,7 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
|||||||
val virtualClassId = lesson.getJsonObject("VirtualClass")?.getLong("Id")
|
val virtualClassId = lesson.getJsonObject("VirtualClass")?.getLong("Id")
|
||||||
val teamId = lesson.getJsonObject("Class")?.getLong("Id") ?: virtualClassId
|
val teamId = lesson.getJsonObject("Class")?.getLong("Id") ?: virtualClassId
|
||||||
|
|
||||||
val id = lessonDate.combineWith(startTime) / 6L * 10L + (lesson.hashCode() and 0xFFFF)
|
val lessonObject = Lesson(profileId, -1)
|
||||||
val lessonObject = Lesson(profileId, id)
|
|
||||||
|
|
||||||
if (isSubstitution && isCancelled) {
|
if (isSubstitution && isCancelled) {
|
||||||
// shifted lesson - source
|
// shifted lesson - source
|
||||||
@ -176,17 +183,21 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lessonObject.id = lessonObject.buildId()
|
||||||
|
|
||||||
|
val seen = profile.empty || lessonDate < Date.getToday()
|
||||||
|
|
||||||
if (lessonObject.type != Lesson.TYPE_NORMAL) {
|
if (lessonObject.type != Lesson.TYPE_NORMAL) {
|
||||||
data.metadataList.add(
|
data.metadataList.add(
|
||||||
Metadata(
|
Metadata(
|
||||||
data.profileId,
|
profileId,
|
||||||
Metadata.TYPE_LESSON_CHANGE,
|
Metadata.TYPE_LESSON_CHANGE,
|
||||||
lessonObject.id,
|
lessonObject.id,
|
||||||
data.profile?.empty ?: false,
|
seen,
|
||||||
data.profile?.empty ?: false,
|
seen,
|
||||||
System.currentTimeMillis()
|
System.currentTimeMillis()
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
data.lessonNewList.add(lessonObject)
|
data.lessonNewList.add(lessonObject)
|
||||||
}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.librus.data.messages
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.ERROR_FILE_DOWNLOAD
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.EXCEPTION_LIBRUS_MESSAGES_REQUEST
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.Regexes
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.events.AttachmentGetEvent
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.events.AttachmentGetEvent.Companion.TYPE_FINISHED
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.events.AttachmentGetEvent.Companion.TYPE_PROGRESS
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusMessages
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.get
|
||||||
|
import pl.szczodrzynski.edziennik.getString
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
|
||||||
|
class LibrusMessagesGetAttachment(override val data: DataLibrus, val messageId: Long, val attachmentId: Long,
|
||||||
|
val attachmentName: String, val onSuccess: () -> Unit) : LibrusMessages(data), CoroutineScope {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "LibrusMessagesGetAttachment"
|
||||||
|
}
|
||||||
|
|
||||||
|
private var job = Job()
|
||||||
|
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = job + Dispatchers.Default
|
||||||
|
|
||||||
|
private var getAttachmentCheckKeyTries = 0
|
||||||
|
|
||||||
|
init {
|
||||||
|
messagesGet(TAG, "GetFileDownloadLink", parameters = mapOf(
|
||||||
|
"fileId" to attachmentId,
|
||||||
|
"msgId" to messageId,
|
||||||
|
"archive" to 0
|
||||||
|
)) { doc ->
|
||||||
|
val downloadLink = doc.select("response GetFileDownloadLink downloadLink").text()
|
||||||
|
val keyMatcher = Regexes.LIBRUS_ATTACHMENT_KEY.find(downloadLink)
|
||||||
|
|
||||||
|
if (keyMatcher != null) {
|
||||||
|
getAttachmentCheckKeyTries = 0
|
||||||
|
|
||||||
|
val attachmentKey = keyMatcher[1]
|
||||||
|
getAttachmentCheckKey(attachmentKey) {
|
||||||
|
downloadAttachment(attachmentKey)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
|
||||||
|
.withApiResponse(doc.toString()))
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAttachmentCheckKey(attachmentKey: String, callback: () -> Unit) {
|
||||||
|
sandboxGet(TAG, "CSCheckKey",
|
||||||
|
parameters = mapOf("singleUseKey" to attachmentKey)) { json ->
|
||||||
|
|
||||||
|
when (json.getString("status")) {
|
||||||
|
"not_downloaded_yet" -> {
|
||||||
|
if (getAttachmentCheckKeyTries++ > 5) {
|
||||||
|
data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
|
||||||
|
.withApiResponse(json))
|
||||||
|
return@sandboxGet
|
||||||
|
}
|
||||||
|
launch {
|
||||||
|
delay(2000)
|
||||||
|
getAttachmentCheckKey(attachmentKey, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"ready" -> {
|
||||||
|
launch { callback() }
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
data.error(ApiError(TAG, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
|
||||||
|
.withApiResponse(json))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun downloadAttachment(attachmentKey: String) {
|
||||||
|
val targetFile = File(Utils.getStorageDir(), attachmentName)
|
||||||
|
|
||||||
|
sandboxGetFile(TAG, "CSDownload&singleUseKey=$attachmentKey",
|
||||||
|
targetFile, { file ->
|
||||||
|
|
||||||
|
val event = AttachmentGetEvent(
|
||||||
|
profileId,
|
||||||
|
messageId,
|
||||||
|
attachmentId,
|
||||||
|
TYPE_FINISHED,
|
||||||
|
file.absolutePath
|
||||||
|
)
|
||||||
|
|
||||||
|
val attachmentDataFile = File(Utils.getStorageDir(), ".${profileId}_${event.messageId}_${event.attachmentId}")
|
||||||
|
Utils.writeStringToFile(attachmentDataFile, event.fileName)
|
||||||
|
|
||||||
|
EventBus.getDefault().post(event)
|
||||||
|
|
||||||
|
}) { written, _ ->
|
||||||
|
val event = AttachmentGetEvent(
|
||||||
|
profileId,
|
||||||
|
messageId,
|
||||||
|
attachmentId,
|
||||||
|
TYPE_PROGRESS,
|
||||||
|
bytesWritten = written
|
||||||
|
)
|
||||||
|
|
||||||
|
EventBus.getDefault().post(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,7 @@ import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_MESSAGES_SENT
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusMessages
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusMessages
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||||
@ -20,7 +21,7 @@ import pl.szczodrzynski.edziennik.singleOrNull
|
|||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int = Message.TYPE_RECEIVED,
|
class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int = TYPE_RECEIVED,
|
||||||
archived: Boolean = false, val onSuccess: () -> Unit) : LibrusMessages(data) {
|
archived: Boolean = false, val onSuccess: () -> Unit) : LibrusMessages(data) {
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "LibrusMessagesGetList"
|
const val TAG = "LibrusMessagesGetList"
|
||||||
@ -28,7 +29,7 @@ class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
val endpoint = when (type) {
|
val endpoint = when (type) {
|
||||||
Message.TYPE_RECEIVED -> "Inbox/action/GetList"
|
TYPE_RECEIVED -> "Inbox/action/GetList"
|
||||||
Message.TYPE_SENT -> "Outbox/action/GetList"
|
Message.TYPE_SENT -> "Outbox/action/GetList"
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
@ -46,34 +47,38 @@ class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int
|
|||||||
else -> 0
|
else -> 0
|
||||||
}
|
}
|
||||||
val sentDate = Date.fromIso(element.select("sendDate").text().trim())
|
val sentDate = Date.fromIso(element.select("sendDate").text().trim())
|
||||||
var senderId: Long = -1
|
|
||||||
var receiverId: Long = -1
|
|
||||||
|
|
||||||
when (type) {
|
val recipientFirstName = element.select(when (type) {
|
||||||
Message.TYPE_RECEIVED -> {
|
TYPE_RECEIVED -> "senderFirstName"
|
||||||
val senderFirstName = element.select("senderFirstName").text().trim()
|
else -> "receiverFirstName"
|
||||||
val senderLastName = element.select("senderLastName").text().trim()
|
}).text().trim()
|
||||||
senderId = data.teacherList.singleOrNull {
|
|
||||||
it.name == senderFirstName && it.surname == senderLastName
|
|
||||||
}?.id ?: -1
|
|
||||||
}
|
|
||||||
|
|
||||||
Message.TYPE_SENT -> {
|
val recipientLastName = element.select(when (type) {
|
||||||
val receiverFirstName = element.select("receiverFirstName").text().trim()
|
TYPE_RECEIVED -> "senderLastName"
|
||||||
val receiverLastName = element.select("receiverLastName").text().trim()
|
else -> "receiverLastName"
|
||||||
receiverId = data.teacherList.singleOrNull {
|
}).text().trim()
|
||||||
it.name == receiverFirstName && it.surname == receiverLastName
|
|
||||||
}?.id ?: {
|
val recipientId = data.teacherList.singleOrNull {
|
||||||
val teacherObject = Teacher(
|
it.name == recipientFirstName && it.surname == recipientLastName
|
||||||
profileId,
|
}?.id ?: {
|
||||||
-1 * Utils.crc16("$receiverFirstName $receiverLastName".toByteArray()).toLong(),
|
val teacherObject = Teacher(
|
||||||
receiverFirstName,
|
profileId,
|
||||||
receiverLastName
|
-1 * Utils.crc16("$recipientFirstName $recipientLastName".toByteArray()).toLong(),
|
||||||
)
|
recipientFirstName,
|
||||||
data.teacherList.put(teacherObject.id, teacherObject)
|
recipientLastName
|
||||||
teacherObject.id
|
)
|
||||||
}.invoke()
|
data.teacherList.put(teacherObject.id, teacherObject)
|
||||||
}
|
teacherObject.id
|
||||||
|
}.invoke()
|
||||||
|
|
||||||
|
val senderId = when (type) {
|
||||||
|
TYPE_RECEIVED -> recipientId
|
||||||
|
else -> -1
|
||||||
|
}
|
||||||
|
|
||||||
|
val receiverId = when (type) {
|
||||||
|
TYPE_RECEIVED -> -1
|
||||||
|
else -> recipientId
|
||||||
}
|
}
|
||||||
|
|
||||||
val notified = when (type) {
|
val notified = when (type) {
|
||||||
@ -112,7 +117,7 @@ class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int
|
|||||||
}
|
}
|
||||||
|
|
||||||
when (type) {
|
when (type) {
|
||||||
Message.TYPE_RECEIVED -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_RECEIVED, SYNC_ALWAYS)
|
TYPE_RECEIVED -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_RECEIVED, SYNC_ALWAYS)
|
||||||
Message.TYPE_SENT -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_SENT, DAY, DRAWER_ITEM_MESSAGES)
|
Message.TYPE_SENT -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_SENT, DAY, DRAWER_ITEM_MESSAGES)
|
||||||
}
|
}
|
||||||
onSuccess()
|
onSuccess()
|
||||||
|
@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.api.v2.POST
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK
|
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusSynergia
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusSynergia
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
import pl.szczodrzynski.edziennik.get
|
import pl.szczodrzynski.edziennik.get
|
||||||
@ -55,19 +56,18 @@ class LibrusSynergiaHomework(override val data: DataLibrus, val onSuccess: () ->
|
|||||||
val id = "/podglad/([0-9]+)'".toRegex().find(
|
val id = "/podglad/([0-9]+)'".toRegex().find(
|
||||||
elements[9].select("input").attr("onclick")
|
elements[9].select("input").attr("onclick")
|
||||||
)?.get(1)?.toLong() ?: return@forEachIndexed
|
)?.get(1)?.toLong() ?: return@forEachIndexed
|
||||||
val startTime = data.lessonList.singleOrNull {
|
|
||||||
it.weekDay == eventDate.weekDay && it.subjectId == subjectId
|
val lessons = data.db.timetableDao().getForDateNow(profileId, eventDate)
|
||||||
}?.startTime
|
val startTime = lessons.firstOrNull { it.subjectId == subjectId }?.startTime
|
||||||
|
|
||||||
val moreInfo = graphElements[2 * i + 1].select("td[title]")
|
val moreInfo = graphElements[2 * i + 1].select("td[title]")
|
||||||
.attr("title").trim()
|
.attr("title").trim()
|
||||||
val description = "Treść: (.*)".toRegex(RegexOption.DOT_MATCHES_ALL).find(moreInfo)
|
val description = "Treść: (.*)".toRegex(RegexOption.DOT_MATCHES_ALL).find(moreInfo)
|
||||||
?.get(1)?.replace("<br.*/>".toRegex(), "\n")?.trim()
|
?.get(1)?.replace("<br.*/>".toRegex(), "\n")?.trim()
|
||||||
|
|
||||||
val notified = when (profile?.empty) {
|
val seen = when (profile?.empty) {
|
||||||
true -> true
|
true -> true
|
||||||
false -> Date.getToday() < eventDate
|
else -> eventDate < Date.getToday()
|
||||||
else -> false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val eventObject = Event(
|
val eventObject = Event(
|
||||||
@ -89,13 +89,15 @@ class LibrusSynergiaHomework(override val data: DataLibrus, val onSuccess: () ->
|
|||||||
profileId,
|
profileId,
|
||||||
Metadata.TYPE_HOMEWORK,
|
Metadata.TYPE_HOMEWORK,
|
||||||
id,
|
id,
|
||||||
notified,
|
seen,
|
||||||
notified,
|
seen,
|
||||||
addedDate
|
addedDate
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||||
|
|
||||||
// because this requires a synergia login (2 more requests) sync this every two hours or if explicit :D
|
// because this requires a synergia login (2 more requests) sync this every two hours or if explicit :D
|
||||||
data.setSyncNext(ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK, 2 * HOUR, DRAWER_ITEM_HOMEWORK)
|
data.setSyncNext(ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK, 2 * HOUR, DRAWER_ITEM_HOMEWORK)
|
||||||
onSuccess()
|
onSuccess()
|
||||||
|
@ -16,8 +16,7 @@ import pl.szczodrzynski.edziennik.getInt
|
|||||||
import pl.szczodrzynski.edziennik.getString
|
import pl.szczodrzynski.edziennik.getString
|
||||||
import pl.szczodrzynski.edziennik.getUnixDate
|
import pl.szczodrzynski.edziennik.getUnixDate
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import java.net.HttpURLConnection.HTTP_BAD_REQUEST
|
import java.net.HttpURLConnection.*
|
||||||
import java.net.HttpURLConnection.HTTP_UNAUTHORIZED
|
|
||||||
|
|
||||||
class LibrusLoginApi {
|
class LibrusLoginApi {
|
||||||
companion object {
|
companion object {
|
||||||
@ -117,6 +116,13 @@ class LibrusLoginApi {
|
|||||||
|
|
||||||
private val tokenCallback = object : JsonCallbackHandler() {
|
private val tokenCallback = object : JsonCallbackHandler() {
|
||||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||||
|
if (response?.code() == HTTP_UNAVAILABLE) {
|
||||||
|
data.error(ApiError(TAG, ERROR_LIBRUS_API_MAINTENANCE)
|
||||||
|
.withApiResponse(json)
|
||||||
|
.withResponse(response))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (json == null) {
|
if (json == null) {
|
||||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||||
.withResponse(response))
|
.withResponse(response))
|
||||||
@ -176,6 +182,7 @@ class LibrusLoginApi {
|
|||||||
.post()
|
.post()
|
||||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||||
|
.allowErrorCode(HTTP_UNAVAILABLE)
|
||||||
.callback(tokenCallback)
|
.callback(tokenCallback)
|
||||||
.build()
|
.build()
|
||||||
.enqueue()
|
.enqueue()
|
||||||
|
@ -6,20 +6,57 @@ package pl.szczodrzynski.edziennik.api.v2.librus.login
|
|||||||
|
|
||||||
import im.wangchao.mhttp.Request
|
import im.wangchao.mhttp.Request
|
||||||
import im.wangchao.mhttp.Response
|
import im.wangchao.mhttp.Response
|
||||||
|
import im.wangchao.mhttp.body.MediaTypeUtils
|
||||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||||
import okhttp3.Cookie
|
import okhttp3.Cookie
|
||||||
import pl.szczodrzynski.edziennik.api.v2.*
|
import pl.szczodrzynski.edziennik.api.v2.*
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
import pl.szczodrzynski.edziennik.getUnixDate
|
import pl.szczodrzynski.edziennik.getUnixDate
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
import java.io.StringWriter
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory
|
||||||
|
import javax.xml.transform.OutputKeys
|
||||||
|
import javax.xml.transform.TransformerFactory
|
||||||
|
import javax.xml.transform.dom.DOMSource
|
||||||
|
import javax.xml.transform.stream.StreamResult
|
||||||
|
|
||||||
class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "LoginLibrusMessages"
|
private const val TAG = "LoginLibrusMessages"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val callback by lazy { object : TextCallbackHandler() {
|
||||||
|
override fun onSuccess(text: String?, response: Response?) {
|
||||||
|
val location = response?.headers()?.get("Location")
|
||||||
|
when {
|
||||||
|
location?.contains("MultiDomainLogon") == true -> loginWithSynergia(location)
|
||||||
|
location?.contains("AutoLogon") == true -> {
|
||||||
|
saveSessionId(response, text)
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
text?.contains("<status>ok</status>") == true -> {
|
||||||
|
saveSessionId(response, text)
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
text?.contains("<message>Niepoprawny login i/lub hasło.</message>") == true -> data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN, response, text)
|
||||||
|
text?.contains("stop.png") == true -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
|
||||||
|
text?.contains("eAccessDeny") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||||
|
text?.contains("OffLine") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_MAINTENANCE, response, text)
|
||||||
|
text?.contains("<status>error</status>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ERROR, response, text)
|
||||||
|
text?.contains("<type>eVarWhitThisNameNotExists</type>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||||
|
text?.contains("<error>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||||
|
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(throwable))
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
init { run {
|
init { run {
|
||||||
if (data.profile == null) {
|
if (data.profile == null) {
|
||||||
data.error(ApiError(TAG, ERROR_PROFILE_MISSING))
|
data.error(ApiError(TAG, ERROR_PROFILE_MISSING))
|
||||||
@ -41,7 +78,7 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
if (data.loginMethods.contains(LOGIN_METHOD_LIBRUS_SYNERGIA)) {
|
if (data.loginMethods.contains(LOGIN_METHOD_LIBRUS_SYNERGIA)) {
|
||||||
loginWithSynergia()
|
loginWithSynergia()
|
||||||
}
|
}
|
||||||
else if (data.apiLogin != null && data.apiPassword != null && false) {
|
else if (data.apiLogin != null && data.apiPassword != null) {
|
||||||
loginWithCredentials()
|
loginWithCredentials()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -54,7 +91,44 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
* XML (Flash messages website) login method. Uses a Synergia login and password.
|
* XML (Flash messages website) login method. Uses a Synergia login and password.
|
||||||
*/
|
*/
|
||||||
private fun loginWithCredentials() {
|
private fun loginWithCredentials() {
|
||||||
|
d(TAG, "Request: Librus/Login/Messages - $LIBRUS_MESSAGES_URL/Login")
|
||||||
|
|
||||||
|
val docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||||
|
val doc = docBuilder.newDocument()
|
||||||
|
val serviceElement = doc.createElement("service")
|
||||||
|
val headerElement = doc.createElement("header")
|
||||||
|
val dataElement = doc.createElement("data")
|
||||||
|
val loginElement = doc.createElement("login")
|
||||||
|
loginElement.appendChild(doc.createTextNode(data.apiLogin))
|
||||||
|
dataElement.appendChild(loginElement)
|
||||||
|
val passwordElement = doc.createElement("password")
|
||||||
|
passwordElement.appendChild(doc.createTextNode(data.apiPassword))
|
||||||
|
dataElement.appendChild(passwordElement)
|
||||||
|
val keyStrokeElement = doc.createElement("KeyStroke")
|
||||||
|
val keysElement = doc.createElement("Keys")
|
||||||
|
val upElement = doc.createElement("Up")
|
||||||
|
keysElement.appendChild(upElement)
|
||||||
|
val downElement = doc.createElement("Down")
|
||||||
|
keysElement.appendChild(downElement)
|
||||||
|
keyStrokeElement.appendChild(keysElement)
|
||||||
|
dataElement.appendChild(keyStrokeElement)
|
||||||
|
serviceElement.appendChild(headerElement)
|
||||||
|
serviceElement.appendChild(dataElement)
|
||||||
|
doc.appendChild(serviceElement)
|
||||||
|
val transformer = TransformerFactory.newInstance().newTransformer()
|
||||||
|
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes")
|
||||||
|
val stringWriter = StringWriter()
|
||||||
|
transformer.transform(DOMSource(doc), StreamResult(stringWriter))
|
||||||
|
val requestXml = stringWriter.toString()
|
||||||
|
|
||||||
|
Request.builder()
|
||||||
|
.url("$LIBRUS_MESSAGES_URL/Login")
|
||||||
|
.userAgent(SYNERGIA_USER_AGENT)
|
||||||
|
.setTextBody(requestXml, MediaTypeUtils.APPLICATION_XML)
|
||||||
|
.post()
|
||||||
|
.callback(callback)
|
||||||
|
.build()
|
||||||
|
.enqueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,37 +137,6 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
private fun loginWithSynergia(url: String = "https://synergia.librus.pl/wiadomosci2") {
|
private fun loginWithSynergia(url: String = "https://synergia.librus.pl/wiadomosci2") {
|
||||||
d(TAG, "Request: Librus/Login/Messages - $url")
|
d(TAG, "Request: Librus/Login/Messages - $url")
|
||||||
|
|
||||||
val callback = object : TextCallbackHandler() {
|
|
||||||
override fun onSuccess(text: String?, response: Response?) {
|
|
||||||
val location = response?.headers()?.get("Location")
|
|
||||||
when {
|
|
||||||
location?.contains("MultiDomainLogon") == true -> loginWithSynergia(location)
|
|
||||||
location?.contains("AutoLogon") == true -> {
|
|
||||||
var sessionId = data.app.cookieJar.getCookie("wiadomosci.librus.pl", "DZIENNIKSID")
|
|
||||||
sessionId = sessionId?.replace("-MAINT", "")
|
|
||||||
if (sessionId == null) {
|
|
||||||
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_NO_SESSION_ID)
|
|
||||||
.withResponse(response)
|
|
||||||
.withApiResponse(text))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data.messagesSessionId = sessionId
|
|
||||||
data.messagesSessionIdExpiryTime = response.getUnixDate() + 45 * 60 /* 45min */
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
text?.contains("eAccessDeny") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
|
||||||
text?.contains("stop.png") == true -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
|
||||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
|
||||||
.withResponse(response)
|
|
||||||
.withThrowable(throwable))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Request.builder()
|
Request.builder()
|
||||||
.url(url)
|
.url(url)
|
||||||
.userAgent(SYNERGIA_USER_AGENT)
|
.userAgent(SYNERGIA_USER_AGENT)
|
||||||
@ -103,4 +146,18 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
.build()
|
.build()
|
||||||
.enqueue()
|
.enqueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun saveSessionId(response: Response?, text: String?) {
|
||||||
|
var sessionId = data.app.cookieJar.getCookie("wiadomosci.librus.pl", "DZIENNIKSID")
|
||||||
|
sessionId = sessionId?.replace("-MAINT", "") // dunno what's this
|
||||||
|
sessionId = sessionId?.replace("MAINT", "") // dunno what's this
|
||||||
|
if (sessionId == null) {
|
||||||
|
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_NO_SESSION_ID)
|
||||||
|
.withResponse(response)
|
||||||
|
.withApiResponse(text))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data.messagesSessionId = sessionId
|
||||||
|
data.messagesSessionIdExpiryTime = response.getUnixDate() + 45 * 60 /* 45min */
|
||||||
|
}
|
||||||
}
|
}
|
@ -99,6 +99,14 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
.post()
|
.post()
|
||||||
.callback(object : JsonCallbackHandler() {
|
.callback(object : JsonCallbackHandler() {
|
||||||
override fun onSuccess(json: JsonObject?, response: Response) {
|
override fun onSuccess(json: JsonObject?, response: Response) {
|
||||||
|
val location = response.headers()?.get("Location")
|
||||||
|
if (location == "http://localhost/bar?command=close") {
|
||||||
|
data.error(ApiError(TAG, ERROR_LIBRUS_PORTAL_MAINTENANCE)
|
||||||
|
.withApiResponse(json)
|
||||||
|
.withResponse(response))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (json == null) {
|
if (json == null) {
|
||||||
if (response.parserErrorBody?.contains("wciąż nieaktywne") == true) {
|
if (response.parserErrorBody?.contains("wciąż nieaktywne") == true) {
|
||||||
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED)
|
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED)
|
||||||
@ -120,7 +128,7 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
|
|
||||||
override fun onFailure(response: Response, throwable: Throwable) {
|
override fun onFailure(response: Response, throwable: Throwable) {
|
||||||
if (response.code() == 403 || response.code() == 401) {
|
if (response.code() == 403 || response.code() == 401) {
|
||||||
data.error(ApiError(TAG, ERROR_LOGIN_DATA_INVALID)
|
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN)
|
||||||
.withResponse(response)
|
.withResponse(response)
|
||||||
.withThrowable(throwable))
|
.withThrowable(throwable))
|
||||||
return
|
return
|
||||||
|
@ -7,7 +7,6 @@ package pl.szczodrzynski.edziennik.api.v2.librus.login
|
|||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import im.wangchao.mhttp.Request
|
import im.wangchao.mhttp.Request
|
||||||
import im.wangchao.mhttp.Response
|
import im.wangchao.mhttp.Response
|
||||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
|
||||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||||
import okhttp3.Cookie
|
import okhttp3.Cookie
|
||||||
import pl.szczodrzynski.edziennik.api.v2.*
|
import pl.szczodrzynski.edziennik.api.v2.*
|
||||||
@ -16,7 +15,6 @@ import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
import pl.szczodrzynski.edziennik.getString
|
import pl.szczodrzynski.edziennik.getString
|
||||||
import pl.szczodrzynski.edziennik.getUnixDate
|
import pl.szczodrzynski.edziennik.getUnixDate
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
|
|
||||||
@ -86,6 +84,13 @@ class LibrusLoginSynergia(override val data: DataLibrus, val onSuccess: () -> Un
|
|||||||
val callback = object : TextCallbackHandler() {
|
val callback = object : TextCallbackHandler() {
|
||||||
override fun onSuccess(json: String?, response: Response?) {
|
override fun onSuccess(json: String?, response: Response?) {
|
||||||
val location = response?.headers()?.get("Location")
|
val location = response?.headers()?.get("Location")
|
||||||
|
if (location?.endsWith("przerwa_techniczna") == true) {
|
||||||
|
data.error(ApiError(TAG, ERROR_LIBRUS_SYNERGIA_MAINTENANCE)
|
||||||
|
.withApiResponse(json)
|
||||||
|
.withResponse(response))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (location?.endsWith("centrum_powiadomien") == true) {
|
if (location?.endsWith("centrum_powiadomien") == true) {
|
||||||
val sessionId = data.app.cookieJar.getCookie("synergia.librus.pl", "DZIENNIKSID")
|
val sessionId = data.app.cookieJar.getCookie("synergia.librus.pl", "DZIENNIKSID")
|
||||||
if (sessionId == null) {
|
if (sessionId == null) {
|
||||||
|
@ -10,8 +10,10 @@ import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.MobidziennikData
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.MobidziennikData
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.web.MobidziennikWebGetMessage
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.firstlogin.MobidziennikFirstLogin
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.firstlogin.MobidziennikFirstLogin
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.login.MobidziennikLogin
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.login.MobidziennikLogin
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.login.MobidziennikLoginWeb
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennikLoginMethods
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennikLoginMethods
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
import pl.szczodrzynski.edziennik.api.v2.prepare
|
import pl.szczodrzynski.edziennik.api.v2.prepare
|
||||||
@ -63,13 +65,21 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getMessage(message: MessageFull) {
|
override fun getMessage(message: MessageFull) {
|
||||||
|
MobidziennikLoginWeb(data) {
|
||||||
|
MobidziennikWebGetMessage(data, message) {
|
||||||
|
completed()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun markAllAnnouncementsAsRead() {
|
override fun markAllAnnouncementsAsRead() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
override fun firstLogin() {
|
override fun firstLogin() {
|
||||||
MobidziennikFirstLogin(data) {
|
MobidziennikFirstLogin(data) {
|
||||||
completed()
|
completed()
|
||||||
|
@ -7,6 +7,7 @@ package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.api
|
|||||||
import androidx.core.util.contains
|
import androidx.core.util.contains
|
||||||
import pl.szczodrzynski.edziennik.api.v2.Regexes
|
import pl.szczodrzynski.edziennik.api.v2.Regexes
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
@ -74,5 +75,7 @@ class MobidziennikApiEvents(val data: DataMobidziennik, rows: List<String>) {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.api
|
|||||||
|
|
||||||
import androidx.core.util.contains
|
import androidx.core.util.contains
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
@ -53,5 +54,7 @@ class MobidziennikApiHomework(val data: DataMobidziennik, rows: List<String>) {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.api
|
package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.api
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.App.profileId
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||||
import pl.szczodrzynski.edziennik.getById
|
import pl.szczodrzynski.edziennik.getById
|
||||||
@ -25,7 +24,7 @@ class MobidziennikApiTeams(val data: DataMobidziennik, tableTeams: List<String>?
|
|||||||
val teacherId = cols[4].toLongOrNull() ?: -1
|
val teacherId = cols[4].toLongOrNull() ?: -1
|
||||||
|
|
||||||
val teamObject = Team(
|
val teamObject = Team(
|
||||||
profileId,
|
data.profileId,
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.api
|
package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.api
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.App.profileId
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
@ -15,7 +14,7 @@ import pl.szczodrzynski.edziennik.utils.models.Date
|
|||||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
|
|
||||||
class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
||||||
init {
|
init { data.profile?.also { profile ->
|
||||||
val lessons = rows.filterNot { it.isEmpty() }.map { it.split("|") }
|
val lessons = rows.filterNot { it.isEmpty() }.map { it.split("|") }
|
||||||
|
|
||||||
val dataStart = Date.getToday()
|
val dataStart = Date.getToday()
|
||||||
@ -33,7 +32,6 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
|||||||
val date = Date.fromYmd(lesson[2])
|
val date = Date.fromYmd(lesson[2])
|
||||||
val startTime = Time.fromYmdHm(lesson[3])
|
val startTime = Time.fromYmdHm(lesson[3])
|
||||||
val endTime = Time.fromYmdHm(lesson[4])
|
val endTime = Time.fromYmdHm(lesson[4])
|
||||||
val id = date.combineWith(startTime) / 6L * 10L + (lesson.joinToString("|").hashCode() and 0xFFFF)
|
|
||||||
|
|
||||||
dataDays.remove(date.value)
|
dataDays.remove(date.value)
|
||||||
|
|
||||||
@ -42,7 +40,7 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
|||||||
val teamId = data.teamList.singleOrNull { it.name == lesson[8]+lesson[9] }?.id ?: -1
|
val teamId = data.teamList.singleOrNull { it.name == lesson[8]+lesson[9] }?.id ?: -1
|
||||||
val classroom = lesson[11]
|
val classroom = lesson[11]
|
||||||
|
|
||||||
Lesson(data.profileId, id).also {
|
Lesson(data.profileId, -1).also {
|
||||||
when (lesson[1]) {
|
when (lesson[1]) {
|
||||||
"plan_lekcji", "lekcja" -> {
|
"plan_lekcji", "lekcja" -> {
|
||||||
it.type = Lesson.TYPE_NORMAL
|
it.type = Lesson.TYPE_NORMAL
|
||||||
@ -76,14 +74,18 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it.id = it.buildId()
|
||||||
|
|
||||||
|
val seen = profile.empty || date < Date.getToday()
|
||||||
|
|
||||||
if (it.type != Lesson.TYPE_NORMAL) {
|
if (it.type != Lesson.TYPE_NORMAL) {
|
||||||
data.metadataList.add(
|
data.metadataList.add(
|
||||||
Metadata(
|
Metadata(
|
||||||
data.profileId,
|
data.profileId,
|
||||||
Metadata.TYPE_LESSON_CHANGE,
|
Metadata.TYPE_LESSON_CHANGE,
|
||||||
it.id,
|
it.id,
|
||||||
data.profile?.empty ?: false,
|
seen,
|
||||||
data.profile?.empty ?: false,
|
seen,
|
||||||
System.currentTimeMillis()
|
System.currentTimeMillis()
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -93,7 +95,7 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
|||||||
|
|
||||||
for (day in dataDays) {
|
for (day in dataDays) {
|
||||||
val lessonDate = Date.fromValue(day)
|
val lessonDate = Date.fromValue(day)
|
||||||
data.lessonNewList += Lesson(profileId, lessonDate.value.toLong()).apply {
|
data.lessonNewList += Lesson(data.profileId, lessonDate.value.toLong()).apply {
|
||||||
type = Lesson.TYPE_NO_LESSONS
|
type = Lesson.TYPE_NO_LESSONS
|
||||||
date = lessonDate
|
date = lessonDate
|
||||||
}
|
}
|
||||||
@ -195,5 +197,5 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2019-11-18.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.web
|
||||||
|
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.Regexes
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.events.MessageGetEvent
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.MobidziennikWeb
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipientFull
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.get
|
||||||
|
import pl.szczodrzynski.edziennik.singleOrNull
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.monthFromName
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
|
|
||||||
|
class MobidziennikWebGetMessage(
|
||||||
|
override val data: DataMobidziennik,
|
||||||
|
private val message: MessageFull,
|
||||||
|
val onSuccess: () -> Unit) : MobidziennikWeb(data) {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "MobidziennikWebGetMessage"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val typeUrl = if (message.type == Message.TYPE_SENT)
|
||||||
|
"wiadwyslana"
|
||||||
|
else
|
||||||
|
"wiadodebrana"
|
||||||
|
webGet(TAG, "/dziennik/$typeUrl/?id=${message.id}") { text ->
|
||||||
|
MobidziennikLuckyNumberExtractor(data, text)
|
||||||
|
|
||||||
|
val messageRecipientList = mutableListOf<MessageRecipientFull>()
|
||||||
|
|
||||||
|
val doc = Jsoup.parse(text)
|
||||||
|
|
||||||
|
val content = doc.select("#content").first()
|
||||||
|
|
||||||
|
val body = content.select(".wiadomosc_tresc").first()
|
||||||
|
|
||||||
|
if (message.type == TYPE_RECEIVED) {
|
||||||
|
var readDate = System.currentTimeMillis()
|
||||||
|
Regexes.MOBIDZIENNIK_MESSAGE_READ_DATE.find(body.html())?.let {
|
||||||
|
val date = Date(
|
||||||
|
it[3].toIntOrNull() ?: 2019,
|
||||||
|
monthFromName(it[2]),
|
||||||
|
it[1].toIntOrNull() ?: 1
|
||||||
|
)
|
||||||
|
val time = Time.fromH_m_s(
|
||||||
|
it[4] // TODO blank string safety
|
||||||
|
)
|
||||||
|
readDate = date.combineWith(time)
|
||||||
|
}
|
||||||
|
|
||||||
|
val recipient = MessageRecipientFull(
|
||||||
|
profileId,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
readDate,
|
||||||
|
message.id
|
||||||
|
)
|
||||||
|
|
||||||
|
recipient.fullName = profile?.accountNameLong ?: profile?.studentNameLong
|
||||||
|
|
||||||
|
messageRecipientList.add(recipient)
|
||||||
|
} else {
|
||||||
|
message.senderId = -1
|
||||||
|
message.senderReplyId = -1
|
||||||
|
|
||||||
|
content.select("table.spis tr:has(td)")?.forEach { recipientEl ->
|
||||||
|
val senderEl = recipientEl.select("td:eq(0)").first()
|
||||||
|
val senderName = senderEl.text()
|
||||||
|
|
||||||
|
val teacher = data.teacherList.singleOrNull { it.fullNameLastFirst == senderName }
|
||||||
|
val receiverId = teacher?.id ?: -1
|
||||||
|
|
||||||
|
var readDate = 0L
|
||||||
|
val isReadEl = recipientEl.select("td:eq(2)").first()
|
||||||
|
if (isReadEl.ownText() != "NIE") {
|
||||||
|
val readDateEl = recipientEl.select("td:eq(3) small").first()
|
||||||
|
Regexes.MOBIDZIENNIK_MESSAGE_SENT_READ_DATE.find(readDateEl.ownText())?.let {
|
||||||
|
val date = Date(
|
||||||
|
it[3].toIntOrNull() ?: 2019,
|
||||||
|
monthFromName(it[2]),
|
||||||
|
it[1].toIntOrNull() ?: 1
|
||||||
|
)
|
||||||
|
val time = Time.fromH_m_s(
|
||||||
|
it[4] // TODO blank string safety
|
||||||
|
)
|
||||||
|
readDate = date.combineWith(time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val recipient = MessageRecipientFull(
|
||||||
|
profileId,
|
||||||
|
receiverId,
|
||||||
|
-1,
|
||||||
|
readDate,
|
||||||
|
message.id
|
||||||
|
)
|
||||||
|
|
||||||
|
recipient.fullName = teacher?.fullName ?: "?"
|
||||||
|
|
||||||
|
messageRecipientList.add(recipient)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this line removes the sender and read date details
|
||||||
|
body.select("div").remove()
|
||||||
|
|
||||||
|
// this needs to be at the end
|
||||||
|
message.apply {
|
||||||
|
this.body = body.html()
|
||||||
|
|
||||||
|
clearAttachments()
|
||||||
|
content.select("ul li").map { it.select("a").first() }.forEach {
|
||||||
|
val attachmentName = it.ownText()
|
||||||
|
Regexes.MOBIDZIENNIK_MESSAGE_ATTACHMENT.find(it.outerHtml())?.let { match ->
|
||||||
|
val attachmentId = match[1].toLong()
|
||||||
|
var size = match[2].toFloatOrNull() ?: 0f
|
||||||
|
when (match[3]) {
|
||||||
|
"K" -> size *= 1024f
|
||||||
|
"M" -> size *= 1024f * 1024f
|
||||||
|
"G" -> size *= 1024f * 1024f * 1024f
|
||||||
|
}
|
||||||
|
message.addAttachment(attachmentId, attachmentName, size.toLong())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!message.seen) { // TODO discover why this monstrosity instead of MetadataDao.setSeen
|
||||||
|
data.messageMetadataList.add(Metadata(
|
||||||
|
message.profileId,
|
||||||
|
Metadata.TYPE_MESSAGE,
|
||||||
|
message.id,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
message.addedDate
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
message.recipients = messageRecipientList
|
||||||
|
data.messageRecipientList.addAll(messageRecipientList)
|
||||||
|
data.messageList.add(message)
|
||||||
|
|
||||||
|
EventBus.getDefault().postSticky(MessageGetEvent(message))
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.models
|
package pl.szczodrzynski.edziennik.api.v2.models
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import im.wangchao.mhttp.Request
|
import im.wangchao.mhttp.Request
|
||||||
import im.wangchao.mhttp.Response
|
import im.wangchao.mhttp.Response
|
||||||
@ -52,6 +53,15 @@ class ApiError(val tag: String, val errorCode: Int) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getStringReason(context: Context): String {
|
||||||
|
return context.resources.getIdentifier("error_${errorCode}_reason", "string", context.packageName).let {
|
||||||
|
if (it != 0)
|
||||||
|
context.getString(it)
|
||||||
|
else
|
||||||
|
"?"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "ApiError(tag='$tag', errorCode=$errorCode, profileId=$profileId, throwable=$throwable, apiResponse=$apiResponse, request=$request, response=$response, isCritical=$isCritical)"
|
return "ApiError(tag='$tag', errorCode=$errorCode, profileId=$profileId, throwable=$throwable, apiResponse=$apiResponse, request=$request, response=$response, isCritical=$isCritical)"
|
||||||
}
|
}
|
||||||
|
@ -283,6 +283,7 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
|||||||
when (model) {
|
when (model) {
|
||||||
is DataRemoveModel.Timetable -> model.commit(profileId, db.timetableDao())
|
is DataRemoveModel.Timetable -> model.commit(profileId, db.timetableDao())
|
||||||
is DataRemoveModel.Grades -> model.commit(profileId, db.gradeDao())
|
is DataRemoveModel.Grades -> model.commit(profileId, db.gradeDao())
|
||||||
|
is DataRemoveModel.Events -> model.commit(profileId, db.eventDao())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,7 +306,6 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
|||||||
db.gradeDao().addAll(gradeList)
|
db.gradeDao().addAll(gradeList)
|
||||||
}
|
}
|
||||||
if (eventList.isNotEmpty()) {
|
if (eventList.isNotEmpty()) {
|
||||||
db.eventDao().removeFuture(profile.id, Date.getToday())
|
|
||||||
db.eventDao().addAll(eventList)
|
db.eventDao().addAll(eventList)
|
||||||
}
|
}
|
||||||
if (noticeList.isNotEmpty()) {
|
if (noticeList.isNotEmpty()) {
|
||||||
@ -375,7 +375,7 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun shouldSyncLuckyNumber(): Boolean {
|
fun shouldSyncLuckyNumber(): Boolean {
|
||||||
return (db.luckyNumberDao().getNearestFutureNow(profileId, Date.getToday()) ?: -1) == -1
|
return (db.luckyNumberDao().getNearestFutureNow(profileId, Date.getToday().value) ?: -1) == -1
|
||||||
}
|
}
|
||||||
|
|
||||||
fun error(tag: String, errorCode: Int, response: Response? = null, throwable: Throwable? = null, apiResponse: JsonObject? = null) {
|
fun error(tag: String, errorCode: Int, response: Response? = null, throwable: Throwable? = null, apiResponse: JsonObject? = null) {
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.api.v2.models
|
package pl.szczodrzynski.edziennik.api.v2.models
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.events.EventDao
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeDao
|
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeDao
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.TimetableDao
|
import pl.szczodrzynski.edziennik.data.db.modules.timetable.TimetableDao
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
@ -15,21 +16,23 @@ open class DataRemoveModel {
|
|||||||
fun to(dateTo: Date) = Timetable(null, dateTo)
|
fun to(dateTo: Date) = Timetable(null, dateTo)
|
||||||
fun between(dateFrom: Date, dateTo: Date) = Timetable(dateFrom, dateTo)
|
fun between(dateFrom: Date, dateTo: Date) = Timetable(dateFrom, dateTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
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.clearBetweenDates(profileId, dateFrom, dateTo)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
dateFrom?.let { dateFrom -> dao.clearFromDate(profileId, dateFrom) }
|
dateFrom?.let { dateFrom -> dao.clearFromDate(profileId, dateFrom) }
|
||||||
dateTo?.let { dateTo -> dao.clearToDate(profileId, dateTo) }
|
dateTo?.let { dateTo -> dao.clearToDate(profileId, dateTo) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class Grades(val all: Boolean, val semester: Int?) : DataRemoveModel() {
|
|
||||||
|
class Grades(private val all: Boolean, private val semester: Int?) : DataRemoveModel() {
|
||||||
companion object {
|
companion object {
|
||||||
fun all() = Grades(true, null)
|
fun all() = Grades(true, null)
|
||||||
fun semester(semester: Int) = Grades(false, semester)
|
fun semester(semester: Int) = Grades(false, semester)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun commit(profileId: Int, dao: GradeDao) {
|
fun commit(profileId: Int, dao: GradeDao) {
|
||||||
if (all) {
|
if (all) {
|
||||||
dao.clear(profileId)
|
dao.clear(profileId)
|
||||||
@ -37,4 +40,16 @@ open class DataRemoveModel {
|
|||||||
semester?.let { dao.clearForSemester(profileId, it) }
|
semester?.let { dao.clearForSemester(profileId, it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
class Events(private val type: Int?, private val exceptType: Int?) : DataRemoveModel() {
|
||||||
|
companion object {
|
||||||
|
fun futureExceptType(exceptType: Int) = Events(null, exceptType)
|
||||||
|
fun futureWithType(type: Int) = Events(type, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun commit(profileId: Int, dao: EventDao) {
|
||||||
|
type?.let { dao.removeFutureWithType(profileId, Date.getToday(), it) }
|
||||||
|
exceptType?.let { dao.removeFutureExceptType(profileId, Date.getToday(), it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -70,6 +70,10 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
override fun firstLogin() {
|
override fun firstLogin() {
|
||||||
TemplateFirstLogin(data) {
|
TemplateFirstLogin(data) {
|
||||||
completed()
|
completed()
|
||||||
|
@ -7,15 +7,14 @@ package pl.szczodrzynski.edziennik.api.v2.vulcan
|
|||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_VULCAN_API
|
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_VULCAN_API
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||||
import pl.szczodrzynski.edziennik.currentTimeUnix
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||||
|
|
||||||
class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
||||||
|
|
||||||
fun isApiLoginValid() = apiCertificateExpiryTime-30 > currentTimeUnix()
|
fun isApiLoginValid() = /*apiCertificateExpiryTime-30 > currentTimeUnix()
|
||||||
&& apiCertificateKey.isNotNullNorEmpty()
|
&&*/ apiCertificateKey.isNotNullNorEmpty()
|
||||||
&& apiCertificatePrivate.isNotNullNorEmpty()
|
&& apiCertificatePrivate.isNotNullNorEmpty()
|
||||||
&& symbol.isNotNullNorEmpty()
|
&& symbol.isNotNullNorEmpty()
|
||||||
|
|
||||||
@ -165,6 +164,8 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
|||||||
"GD1" -> "https://uonetplus-komunikacja.edu.gdansk.pl"
|
"GD1" -> "https://uonetplus-komunikacja.edu.gdansk.pl"
|
||||||
"KA1" -> "https://uonetplus-komunikacja.mcuw.katowice.eu"
|
"KA1" -> "https://uonetplus-komunikacja.mcuw.katowice.eu"
|
||||||
"KA2" -> "https://uonetplus-komunikacja-test.mcuw.katowice.eu"
|
"KA2" -> "https://uonetplus-komunikacja-test.mcuw.katowice.eu"
|
||||||
|
"LU1" -> "https://uonetplus-komunikacja.edu.lublin.eu"
|
||||||
|
"LU2" -> "https://test-uonetplus-komunikacja.edu.lublin.eu"
|
||||||
"P03" -> "https://efeb-komunikacja-pro-efebmobile.pro.vulcan.pl"
|
"P03" -> "https://efeb-komunikacja-pro-efebmobile.pro.vulcan.pl"
|
||||||
"P01" -> "http://efeb-komunikacja.pro-hudson.win.vulcan.pl"
|
"P01" -> "http://efeb-komunikacja.pro-hudson.win.vulcan.pl"
|
||||||
"P02" -> "http://efeb-komunikacja.pro-hudsonrc.win.vulcan.pl"
|
"P02" -> "http://efeb-komunikacja.pro-hudsonrc.win.vulcan.pl"
|
||||||
@ -173,7 +174,7 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
|||||||
"SZ9" -> "http://vulcan.szkolny.eu"
|
"SZ9" -> "http://vulcan.szkolny.eu"
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
return if (url != null) "$url/$symbol" else null
|
return if (url != null) "$url/$symbol" else loginStore.getLoginData("apiUrl", null)
|
||||||
}
|
}
|
||||||
|
|
||||||
val fullApiUrl: String?
|
val fullApiUrl: String?
|
||||||
|
@ -12,8 +12,10 @@ import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
|||||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
import pl.szczodrzynski.edziennik.api.v2.prepare
|
import pl.szczodrzynski.edziennik.api.v2.prepare
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanData
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanData
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.api.VulcanApiMessagesChangeStatus
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.firstlogin.VulcanFirstLogin
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.firstlogin.VulcanFirstLogin
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.login.VulcanLogin
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.login.VulcanLogin
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.login.VulcanLoginApi
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcanLoginMethods
|
import pl.szczodrzynski.edziennik.api.v2.vulcanLoginMethods
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||||
@ -63,13 +65,21 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getMessage(message: MessageFull) {
|
override fun getMessage(message: MessageFull) {
|
||||||
|
VulcanLoginApi(data) {
|
||||||
|
VulcanApiMessagesChangeStatus(data, message) {
|
||||||
|
completed()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun markAllAnnouncementsAsRead() {
|
override fun markAllAnnouncementsAsRead() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
override fun firstLogin() {
|
override fun firstLogin() {
|
||||||
VulcanFirstLogin(data) {
|
VulcanFirstLogin(data) {
|
||||||
completed()
|
completed()
|
||||||
|
@ -64,6 +64,10 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
|
|||||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
||||||
VulcanApiAttendance(data, onSuccess)
|
VulcanApiAttendance(data, onSuccess)
|
||||||
}
|
}
|
||||||
|
ENDPOINT_VULCAN_API_TIMETABLE -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
||||||
|
VulcanApiTimetable(data, onSuccess)
|
||||||
|
}
|
||||||
ENDPOINT_VULCAN_API_MESSAGES_INBOX -> {
|
ENDPOINT_VULCAN_API_MESSAGES_INBOX -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
||||||
VulcanApiMessagesInbox(data, onSuccess)
|
VulcanApiMessagesInbox(data, onSuccess)
|
||||||
|
@ -55,7 +55,7 @@ class VulcanApiAttendance(override val data: DataVulcan, val onSuccess: () -> Un
|
|||||||
lessonSemester,
|
lessonSemester,
|
||||||
attendance.getString("PrzedmiotNazwa") + attendanceCategory.name.let { " - $it" },
|
attendance.getString("PrzedmiotNazwa") + attendanceCategory.name.let { " - $it" },
|
||||||
lessonDate,
|
lessonDate,
|
||||||
data.lessonRanges.get(attendance.getInt("IdPoraLekcji") ?: 0)?.startTime,
|
data.lessonRanges.get(attendance.getInt("Numer") ?: 0)?.startTime,
|
||||||
type)
|
type)
|
||||||
|
|
||||||
data.attendanceList.add(attendanceObject)
|
data.attendanceList.add(attendanceObject)
|
||||||
|
@ -35,7 +35,7 @@ class VulcanApiDictionaries(override val data: DataVulcan, val onSuccess: () ->
|
|||||||
elements?.getJsonArray("KategorieUwag")?.forEach { saveNoticeType(it.asJsonObject) }
|
elements?.getJsonArray("KategorieUwag")?.forEach { saveNoticeType(it.asJsonObject) }
|
||||||
elements?.getJsonArray("KategorieFrekwencji")?.forEach { saveAttendanceType(it.asJsonObject) }
|
elements?.getJsonArray("KategorieFrekwencji")?.forEach { saveAttendanceType(it.asJsonObject) }
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_VULCAN_API_DICTIONARIES, 4*DAY)
|
data.setSyncNext(ENDPOINT_VULCAN_API_DICTIONARIES, 4 * DAY)
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ class VulcanApiDictionaries(override val data: DataVulcan, val onSuccess: () ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun saveLessonRange(lessonRange: JsonObject) {
|
private fun saveLessonRange(lessonRange: JsonObject) {
|
||||||
val lessonNumber = lessonRange.getInt("Id") ?: return
|
val lessonNumber = lessonRange.getInt("Numer") ?: return
|
||||||
val startTime = lessonRange.getString("PoczatekTekst")?.let { Time.fromH_m(it) } ?: return
|
val startTime = lessonRange.getString("PoczatekTekst")?.let { Time.fromH_m(it) } ?: return
|
||||||
val endTime = lessonRange.getString("KoniecTekst")?.let { Time.fromH_m(it) } ?: return
|
val endTime = lessonRange.getString("KoniecTekst")?.let { Time.fromH_m(it) } ?: return
|
||||||
|
|
||||||
@ -126,8 +126,7 @@ class VulcanApiDictionaries(override val data: DataVulcan, val onSuccess: () ->
|
|||||||
Attendance.TYPE_ABSENT_EXCUSED
|
Attendance.TYPE_ABSENT_EXCUSED
|
||||||
else
|
else
|
||||||
Attendance.TYPE_ABSENT
|
Attendance.TYPE_ABSENT
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val belated = attendanceType.getBoolean("Spoznienie") ?: false
|
val belated = attendanceType.getBoolean("Spoznienie") ?: false
|
||||||
val released = attendanceType.getBoolean("Zwolnienie") ?: false
|
val released = attendanceType.getBoolean("Zwolnienie") ?: false
|
||||||
val present = attendanceType.getBoolean("Obecnosc") ?: true
|
val present = attendanceType.getBoolean("Obecnosc") ?: true
|
||||||
|
@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api
|
|||||||
|
|
||||||
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_EVENTS
|
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_EVENTS
|
||||||
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_HOMEWORK
|
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_HOMEWORK
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_EVENTS
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_EVENTS
|
||||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_HOMEWORK
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_HOMEWORK
|
||||||
@ -91,8 +92,14 @@ class VulcanApiEvents(override val data: DataVulcan, private val isHomework: Boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
when (isHomework) {
|
when (isHomework) {
|
||||||
true -> data.setSyncNext(ENDPOINT_VULCAN_API_HOMEWORK, SYNC_ALWAYS)
|
true -> {
|
||||||
false -> data.setSyncNext(ENDPOINT_VULCAN_API_EVENTS, SYNC_ALWAYS)
|
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||||
|
data.setSyncNext(ENDPOINT_VULCAN_API_HOMEWORK, SYNC_ALWAYS)
|
||||||
|
}
|
||||||
|
false -> {
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
|
||||||
|
data.setSyncNext(ENDPOINT_VULCAN_API_EVENTS, SYNC_ALWAYS)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-12
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_MESSAGES_CHANGE_STATUS
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
|
||||||
|
class VulcanApiMessagesChangeStatus(
|
||||||
|
override val data: DataVulcan,
|
||||||
|
private val messageObject: MessageFull,
|
||||||
|
val onSuccess: () -> Unit
|
||||||
|
) : VulcanApi(data) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "VulcanApiMessagesChangeStatus"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
data.profile?.also { profile ->
|
||||||
|
apiGet(TAG, VULCAN_API_ENDPOINT_MESSAGES_CHANGE_STATUS, parameters = mapOf(
|
||||||
|
"WiadomoscId" to messageObject.id,
|
||||||
|
"FolderWiadomosci" to "Odebrane",
|
||||||
|
"Status" to "Widoczna",
|
||||||
|
"LoginId" to data.studentLoginId,
|
||||||
|
"IdUczen" to data.studentId
|
||||||
|
)) { _, _ ->
|
||||||
|
|
||||||
|
if (!messageObject.seen) {
|
||||||
|
data.messageMetadataList.add(Metadata(
|
||||||
|
profileId,
|
||||||
|
Metadata.TYPE_MESSAGE,
|
||||||
|
messageObject.id,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
messageObject.addedDate
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageObject.type != TYPE_SENT) {
|
||||||
|
val messageRecipientObject = MessageRecipient(
|
||||||
|
profileId,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
messageObject.id
|
||||||
|
)
|
||||||
|
|
||||||
|
data.messageRecipientList.add(messageRecipientObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,8 @@ import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
|||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
class VulcanApiMessagesInbox(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
class VulcanApiMessagesInbox(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
||||||
@ -43,7 +45,22 @@ class VulcanApiMessagesInbox(override val data: DataVulcan, val onSuccess: () ->
|
|||||||
|
|
||||||
val senderLoginId = message.getString("NadawcaId") ?: return@forEach
|
val senderLoginId = message.getString("NadawcaId") ?: return@forEach
|
||||||
val senderId = data.teacherList
|
val senderId = data.teacherList
|
||||||
.singleOrNull { it.loginId == senderLoginId }?.id ?: return@forEach
|
.singleOrNull { it.loginId == senderLoginId }?.id ?: {
|
||||||
|
|
||||||
|
val senderName = message.getString("Nadawca") ?: ""
|
||||||
|
|
||||||
|
senderName.getLastFirstName()?.let { (senderLastName, senderFirstName) ->
|
||||||
|
val teacherObject = Teacher(
|
||||||
|
profileId,
|
||||||
|
-1 * Utils.crc16(senderName.toByteArray()).toLong(),
|
||||||
|
senderFirstName,
|
||||||
|
senderLastName,
|
||||||
|
senderLoginId
|
||||||
|
)
|
||||||
|
data.teacherList.put(teacherObject.id, teacherObject)
|
||||||
|
teacherObject.id
|
||||||
|
}
|
||||||
|
}.invoke() ?: -1
|
||||||
|
|
||||||
val sentDate = message.getLong("DataWyslaniaUnixEpoch")?.let { it * 1000 }
|
val sentDate = message.getLong("DataWyslaniaUnixEpoch")?.let { it * 1000 }
|
||||||
?: -1
|
?: -1
|
||||||
|
@ -14,6 +14,8 @@ import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
|||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
class VulcanApiMessagesSent(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
class VulcanApiMessagesSent(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
||||||
@ -23,11 +25,11 @@ class VulcanApiMessagesSent(override val data: DataVulcan, val onSuccess: () ->
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
data.profile?.also { profile ->
|
data.profile?.also { profile ->
|
||||||
val startDate: String = when (profile.empty) {
|
val startDate: Long = when (profile.empty) {
|
||||||
true -> profile.getSemesterStart(profile.currentSemester).stringY_m_d
|
true -> profile.getSemesterStart(profile.currentSemester).inUnix
|
||||||
else -> Date.getToday().stepForward(0, -1, 0).stringY_m_d
|
else -> Date.getToday().stepForward(0, -1, 0).inUnix
|
||||||
}
|
}
|
||||||
val endDate: String = profile.getSemesterEnd(profile.currentSemester).stringY_m_d
|
val endDate: Long = profile.getSemesterEnd(profile.currentSemester).inUnix
|
||||||
|
|
||||||
apiGet(TAG, VULCAN_API_ENDPOINT_MESSAGES_SENT, parameters = mapOf(
|
apiGet(TAG, VULCAN_API_ENDPOINT_MESSAGES_SENT, parameters = mapOf(
|
||||||
"DataPoczatkowa" to startDate,
|
"DataPoczatkowa" to startDate,
|
||||||
@ -43,23 +45,27 @@ class VulcanApiMessagesSent(override val data: DataVulcan, val onSuccess: () ->
|
|||||||
val unreadBy = message.getInt("Nieprzeczytane") ?: 0
|
val unreadBy = message.getInt("Nieprzeczytane") ?: 0
|
||||||
val sentDate = message.getLong("DataWyslaniaUnixEpoch")?.let { it * 1000 } ?: -1
|
val sentDate = message.getLong("DataWyslaniaUnixEpoch")?.let { it * 1000 } ?: -1
|
||||||
|
|
||||||
val messageObject = Message(
|
|
||||||
profileId,
|
|
||||||
id,
|
|
||||||
subject,
|
|
||||||
body,
|
|
||||||
TYPE_SENT,
|
|
||||||
-1,
|
|
||||||
-1
|
|
||||||
)
|
|
||||||
|
|
||||||
message.getJsonArray("Adresaci")?.asJsonObjectList()
|
message.getJsonArray("Adresaci")?.asJsonObjectList()
|
||||||
?.forEachIndexed { _, recipient ->
|
?.onEach { receiver ->
|
||||||
|
|
||||||
val recipientLoginId = recipient.getString("LoginId")
|
val receiverLoginId = receiver.getString("LoginId")
|
||||||
?: return@forEachIndexed
|
?: return@onEach
|
||||||
val recipientId = data.teacherList.singleOrNull { it.loginId == recipientLoginId }?.id
|
val receiverId = data.teacherList.singleOrNull { it.loginId == receiverLoginId }?.id
|
||||||
?: return@forEachIndexed
|
?: {
|
||||||
|
val receiverName = receiver.getString("Nazwa") ?: ""
|
||||||
|
|
||||||
|
receiverName.getLastFirstName()?.let { (receiverLastName, receiverFirstName) ->
|
||||||
|
val teacherObject = Teacher(
|
||||||
|
profileId,
|
||||||
|
-1 * Utils.crc16(receiverName.toByteArray()).toLong(),
|
||||||
|
receiverFirstName,
|
||||||
|
receiverLastName,
|
||||||
|
receiverLoginId
|
||||||
|
)
|
||||||
|
data.teacherList.put(teacherObject.id, teacherObject)
|
||||||
|
teacherObject.id
|
||||||
|
}
|
||||||
|
}.invoke() ?: -1
|
||||||
|
|
||||||
val readDate: Long = when (readBy) {
|
val readDate: Long = when (readBy) {
|
||||||
0 -> 0
|
0 -> 0
|
||||||
@ -71,7 +77,7 @@ class VulcanApiMessagesSent(override val data: DataVulcan, val onSuccess: () ->
|
|||||||
|
|
||||||
val messageRecipientObject = MessageRecipient(
|
val messageRecipientObject = MessageRecipient(
|
||||||
profileId,
|
profileId,
|
||||||
recipientId,
|
receiverId,
|
||||||
-1,
|
-1,
|
||||||
readDate,
|
readDate,
|
||||||
id
|
id
|
||||||
@ -80,6 +86,16 @@ class VulcanApiMessagesSent(override val data: DataVulcan, val onSuccess: () ->
|
|||||||
data.messageRecipientList.add(messageRecipientObject)
|
data.messageRecipientList.add(messageRecipientObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val messageObject = Message(
|
||||||
|
profileId,
|
||||||
|
id,
|
||||||
|
subject,
|
||||||
|
body,
|
||||||
|
TYPE_SENT,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
)
|
||||||
|
|
||||||
data.messageIgnoreList.add(messageObject)
|
data.messageIgnoreList.add(messageObject)
|
||||||
data.metadataList.add(Metadata(
|
data.metadataList.add(Metadata(
|
||||||
profileId,
|
profileId,
|
||||||
|
@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2019-11-13
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api
|
||||||
|
|
||||||
|
import androidx.core.util.set
|
||||||
|
import pl.szczodrzynski.edziennik.*
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.Regexes
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_TIMETABLE
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_TIMETABLE
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.crc16
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||||
|
|
||||||
|
class VulcanApiTimetable(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "VulcanApiTimetable"
|
||||||
|
}
|
||||||
|
|
||||||
|
init { data.profile?.also { profile ->
|
||||||
|
val currentWeekStart = Week.getWeekStart()
|
||||||
|
|
||||||
|
if (Date.getToday().weekDay > 4) {
|
||||||
|
currentWeekStart.stepForward(0, 0, 7)
|
||||||
|
}
|
||||||
|
|
||||||
|
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
||||||
|
|
||||||
|
val weekStart = Date.fromY_m_d(getDate)
|
||||||
|
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||||
|
|
||||||
|
apiGet(TAG, VULCAN_API_ENDPOINT_TIMETABLE, parameters = mapOf(
|
||||||
|
"DataPoczatkowa" to weekStart.stringY_m_d,
|
||||||
|
"DataKoncowa" to weekEnd.stringY_m_d,
|
||||||
|
"IdUczen" to data.studentId,
|
||||||
|
"IdOddzial" to data.studentClassId,
|
||||||
|
"IdOkresKlasyfikacyjny" to data.studentSemesterId
|
||||||
|
)) { json, _ ->
|
||||||
|
val dates = mutableSetOf<Int>()
|
||||||
|
val lessons = mutableListOf<Lesson>()
|
||||||
|
|
||||||
|
json.getJsonArray("Data")?.asJsonObjectList()?.forEach { lesson ->
|
||||||
|
if (lesson.getBoolean("PlanUcznia") != true)
|
||||||
|
return@forEach
|
||||||
|
val lessonDate = Date.fromY_m_d(lesson.getString("DzienTekst"))
|
||||||
|
val lessonNumber = lesson.getInt("NumerLekcji")
|
||||||
|
val lessonRange = data.lessonRanges.singleOrNull { it.lessonNumber == lessonNumber }
|
||||||
|
val startTime = lessonRange?.startTime
|
||||||
|
val endTime = lessonRange?.endTime
|
||||||
|
val teacherId = lesson.getLong("IdPracownik")
|
||||||
|
val classroom = lesson.getString("Sala")
|
||||||
|
|
||||||
|
val oldTeacherId = lesson.getLong("IdPracownikOld")
|
||||||
|
|
||||||
|
val changeAnnotation = lesson.getString("AdnotacjaOZmianie") ?: ""
|
||||||
|
val type = when {
|
||||||
|
changeAnnotation.startsWith("(przeniesiona z") -> Lesson.TYPE_SHIFTED_TARGET
|
||||||
|
changeAnnotation.startsWith("(przeniesiona na") -> Lesson.TYPE_SHIFTED_SOURCE
|
||||||
|
changeAnnotation.startsWith("(zastępstwo") -> Lesson.TYPE_CHANGE
|
||||||
|
lesson.getBoolean("PrzekreslonaNazwa") == true -> Lesson.TYPE_CANCELLED
|
||||||
|
else -> Lesson.TYPE_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
val teamId = lesson.getString("PodzialSkrot")?.let { teamName ->
|
||||||
|
val name = "${data.teamClass?.name} $teamName"
|
||||||
|
val id = name.crc16().toLong()
|
||||||
|
var team = data.teamList.singleOrNull { it.name == name }
|
||||||
|
if (team == null) {
|
||||||
|
team = Team(
|
||||||
|
profileId,
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
Team.TYPE_VIRTUAL,
|
||||||
|
"${data.schoolName}:$name",
|
||||||
|
teacherId ?: oldTeacherId ?: -1
|
||||||
|
)
|
||||||
|
data.teamList[id] = team
|
||||||
|
}
|
||||||
|
team.id
|
||||||
|
} ?: data.studentClassId.toLong()
|
||||||
|
|
||||||
|
val subjectId = lesson.getLong("IdPrzedmiot")?.let {
|
||||||
|
when (it) {
|
||||||
|
0L -> {
|
||||||
|
val subjectName = lesson.getString("PrzedmiotNazwa") ?: ""
|
||||||
|
|
||||||
|
data.subjectList.singleOrNull { subject -> subject.longName == subjectName }?.id
|
||||||
|
?: {
|
||||||
|
/**
|
||||||
|
* CREATE A NEW SUBJECT IF IT DOESN'T EXIST
|
||||||
|
*/
|
||||||
|
|
||||||
|
val subjectObject = Subject(
|
||||||
|
profileId,
|
||||||
|
-1 * crc16(subjectName.toByteArray()).toLong(),
|
||||||
|
subjectName,
|
||||||
|
subjectName
|
||||||
|
)
|
||||||
|
data.subjectList.put(subjectObject.id, subjectObject)
|
||||||
|
subjectObject.id
|
||||||
|
}.invoke()
|
||||||
|
}
|
||||||
|
else -> it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val lessonObject = Lesson(profileId, -1).apply {
|
||||||
|
this.type = type
|
||||||
|
|
||||||
|
when (type) {
|
||||||
|
Lesson.TYPE_NORMAL, Lesson.TYPE_CHANGE, Lesson.TYPE_SHIFTED_TARGET -> {
|
||||||
|
this.date = lessonDate
|
||||||
|
this.lessonNumber = lessonNumber
|
||||||
|
this.startTime = startTime
|
||||||
|
this.endTime = endTime
|
||||||
|
this.subjectId = subjectId
|
||||||
|
this.teacherId = teacherId
|
||||||
|
this.teamId = teamId
|
||||||
|
this.classroom = classroom
|
||||||
|
|
||||||
|
this.oldTeacherId = oldTeacherId
|
||||||
|
}
|
||||||
|
|
||||||
|
Lesson.TYPE_CANCELLED, Lesson.TYPE_SHIFTED_SOURCE -> {
|
||||||
|
this.oldDate = lessonDate
|
||||||
|
this.oldLessonNumber = lessonNumber
|
||||||
|
this.oldStartTime = startTime
|
||||||
|
this.oldEndTime = endTime
|
||||||
|
this.oldSubjectId = subjectId
|
||||||
|
this.oldTeacherId = teacherId
|
||||||
|
this.oldTeamId = teamId
|
||||||
|
this.oldClassroom = classroom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == Lesson.TYPE_SHIFTED_SOURCE || type == Lesson.TYPE_SHIFTED_TARGET) {
|
||||||
|
val shift = Regexes.VULCAN_SHITFT_ANNOTATION.find(changeAnnotation)
|
||||||
|
val oldLessonNumber = shift?.get(2)?.toInt()
|
||||||
|
val oldLessonDate = shift?.get(3)?.let { Date.fromd_m_Y(it) }
|
||||||
|
|
||||||
|
val oldLessonRange = data.lessonRanges.singleOrNull { it.lessonNumber == oldLessonNumber }
|
||||||
|
val oldStartTime = oldLessonRange?.startTime
|
||||||
|
val oldEndTime = oldLessonRange?.endTime
|
||||||
|
|
||||||
|
when (type) {
|
||||||
|
Lesson.TYPE_SHIFTED_SOURCE -> {
|
||||||
|
this.lessonNumber = oldLessonNumber
|
||||||
|
this.date = oldLessonDate
|
||||||
|
this.startTime = oldStartTime
|
||||||
|
this.endTime = oldEndTime
|
||||||
|
}
|
||||||
|
|
||||||
|
Lesson.TYPE_SHIFTED_TARGET -> {
|
||||||
|
this.oldLessonNumber = oldLessonNumber
|
||||||
|
this.oldDate = oldLessonDate
|
||||||
|
this.oldStartTime = oldStartTime
|
||||||
|
this.oldEndTime = oldEndTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.id = buildId()
|
||||||
|
}
|
||||||
|
|
||||||
|
val seen = profile.empty || lessonDate < Date.getToday()
|
||||||
|
|
||||||
|
if (type != Lesson.TYPE_NORMAL) {
|
||||||
|
data.metadataList.add(Metadata(
|
||||||
|
profileId,
|
||||||
|
Metadata.TYPE_LESSON_CHANGE,
|
||||||
|
lessonObject.id,
|
||||||
|
seen,
|
||||||
|
seen,
|
||||||
|
System.currentTimeMillis()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
dates.add(lessonDate.value)
|
||||||
|
lessons.add(lessonObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
val date: Date = weekStart.clone()
|
||||||
|
while (date <= weekEnd) {
|
||||||
|
if (!dates.contains(date.value)) {
|
||||||
|
lessons.add(Lesson(profileId, date.value.toLong()).apply {
|
||||||
|
this.type = Lesson.TYPE_NO_LESSONS
|
||||||
|
this.date = date.clone()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
date.stepForward(0, 0, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
||||||
|
|
||||||
|
data.lessonNewList.addAll(lessons)
|
||||||
|
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||||
|
|
||||||
|
data.setSyncNext(ENDPOINT_VULCAN_API_TIMETABLE, SYNC_ALWAYS)
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}
|
@ -38,10 +38,12 @@ class VulcanLoginApi(val data: DataVulcan, val onSuccess: () -> Unit) {
|
|||||||
if (data.apiToken?.get(0) == 'F') VULCAN_API_PASSWORD_FAKELOG else VULCAN_API_PASSWORD,
|
if (data.apiToken?.get(0) == 'F') VULCAN_API_PASSWORD_FAKELOG else VULCAN_API_PASSWORD,
|
||||||
data.apiCertificatePfx ?: ""
|
data.apiCertificatePfx ?: ""
|
||||||
)
|
)
|
||||||
onSuccess()
|
data.loginStore.removeLoginData("certificatePfx")
|
||||||
return@run
|
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
} finally {
|
||||||
|
onSuccess()
|
||||||
|
return@run
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (data.symbol.isNotNullNorEmpty() && data.apiToken.isNotNullNorEmpty() && data.apiPin.isNotNullNorEmpty()) {
|
if (data.symbol.isNotNullNorEmpty() && data.apiToken.isNotNullNorEmpty() && data.apiPin.isNotNullNorEmpty()) {
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
|
||||||
|
|
||||||
import im.wangchao.mhttp.Request;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback containing a {@link Request.Builder} which has correct headers and body to download a corresponding message attachment when ran.
|
|
||||||
* {@code onSuccess} has to be ran on the UI thread.
|
|
||||||
*/
|
|
||||||
public interface AttachmentGetCallback {
|
|
||||||
void onSuccess(Request.Builder builder);
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher;
|
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesComposeInfo;
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Endpoint;
|
|
||||||
|
|
||||||
public interface EdziennikInterface {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sync all Edziennik data.
|
|
||||||
* Ran always on worker thread.
|
|
||||||
*
|
|
||||||
* @param activityContext a {@link Context}, used for resource extractions, passed back to {@link SyncCallback}
|
|
||||||
* @param callback ran on worker thread.
|
|
||||||
* @param profileId
|
|
||||||
* @param profile
|
|
||||||
* @param loginStore
|
|
||||||
*/
|
|
||||||
void sync(@NonNull Context activityContext, @NonNull SyncCallback callback, int profileId, @Nullable Profile profile, @NonNull LoginStore loginStore);
|
|
||||||
void syncMessages(@NonNull Context activityContext, @NonNull SyncCallback errorCallback, @NonNull ProfileFull profile);
|
|
||||||
void syncFeature(@NonNull Context activityContext, @NonNull SyncCallback callback, @NonNull ProfileFull profile, int ... featureList);
|
|
||||||
|
|
||||||
int FEATURE_ALL = 0;
|
|
||||||
int FEATURE_TIMETABLE = 1;
|
|
||||||
int FEATURE_AGENDA = 2;
|
|
||||||
int FEATURE_GRADES = 3;
|
|
||||||
int FEATURE_HOMEWORK = 4;
|
|
||||||
int FEATURE_NOTICES = 5;
|
|
||||||
int FEATURE_ATTENDANCE = 6;
|
|
||||||
int FEATURE_MESSAGES_INBOX = 7;
|
|
||||||
int FEATURE_MESSAGES_OUTBOX = 8;
|
|
||||||
int FEATURE_ANNOUNCEMENTS = 9;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Download a single message or get its recipient list if it's already downloaded.
|
|
||||||
*
|
|
||||||
* May be executed on any thread.
|
|
||||||
*
|
|
||||||
* @param activityContext
|
|
||||||
* @param errorCallback used for error reporting. Ran on a background thread.
|
|
||||||
* @param profile
|
|
||||||
* @param message a message of which body and recipient list should be downloaded.
|
|
||||||
* @param messageCallback always executed on UI thread.
|
|
||||||
*/
|
|
||||||
void getMessage(@NonNull Context activityContext, @NonNull SyncCallback errorCallback, @NonNull ProfileFull profile, @NonNull MessageFull message, @NonNull MessageGetCallback messageCallback);
|
|
||||||
void getAttachment(@NonNull Context activityContext, @NonNull SyncCallback errorCallback, @NonNull ProfileFull profile, @NonNull MessageFull message, long attachmentId, @NonNull AttachmentGetCallback attachmentCallback);
|
|
||||||
//void getMessageList(@NonNull Context activityContext, @NonNull SyncCallback errorCallback, @NonNull ProfileFull profile, int type, @NonNull MessageListCallback messageCallback);
|
|
||||||
/**
|
|
||||||
* Download a list of available message recipients.
|
|
||||||
*
|
|
||||||
* Updates a database-saved {@code teacherList} with {@code loginId}s.
|
|
||||||
*
|
|
||||||
* A {@link Teacher} is considered as a recipient when its {@code loginId} is not null.
|
|
||||||
*
|
|
||||||
* May be executed on any thread.
|
|
||||||
*
|
|
||||||
* @param activityContext
|
|
||||||
* @param errorCallback used for error reporting. Ran on a background thread.
|
|
||||||
* @param profile
|
|
||||||
* @param recipientListGetCallback always executed on UI thread.
|
|
||||||
*/
|
|
||||||
void getRecipientList(@NonNull Context activityContext, @NonNull SyncCallback errorCallback, @NonNull ProfileFull profile, @NonNull RecipientListGetCallback recipientListGetCallback);
|
|
||||||
MessagesComposeInfo getComposeInfo(@NonNull ProfileFull profile);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param profile a {@link Profile} containing already changed endpoints
|
|
||||||
* @return a map of configurable {@link Endpoint}s along with their names, {@code null} when unsupported
|
|
||||||
*/
|
|
||||||
Map<String, Endpoint> getConfigurableEndpoints(Profile profile);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the specified endpoint is enabled for the current profile.
|
|
||||||
*
|
|
||||||
* @param profile a {@link Profile} containing already changed endpoints
|
|
||||||
* @param defaultActive if the endpoint is enabled by default.
|
|
||||||
* @param name the endpoint's name
|
|
||||||
* @return {@code true} if the endpoint is enabled, {@code false} when it's not. Return {@code defaultActive} if unsupported.
|
|
||||||
*/
|
|
||||||
boolean isEndpointEnabled(Profile profile, boolean defaultActive, String name);
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.AppError;
|
|
||||||
|
|
||||||
public interface ErrorCallback {
|
|
||||||
void onError(Context activityContext, @NonNull AppError error);
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
|
||||||
|
|
||||||
public interface LoginCallback {
|
|
||||||
void onSuccess();
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback containing a {@link MessageFull} which already has its {@code body} and {@code recipients}.
|
|
||||||
* {@code onSuccess} is always ran on the UI thread.
|
|
||||||
*/
|
|
||||||
public interface MessageGetCallback {
|
|
||||||
void onSuccess(MessageFull message);
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull;
|
|
||||||
|
|
||||||
public interface MessageListCallback {
|
|
||||||
void onSuccess(List<MessageFull> messageList);
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
|
||||||
|
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
|
|
||||||
public interface ProgressCallback extends ErrorCallback {
|
|
||||||
void onProgress(int progressStep);
|
|
||||||
void onActionStarted(@StringRes int stringResId);
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher;
|
|
||||||
|
|
||||||
public interface RecipientListGetCallback {
|
|
||||||
void onSuccess(List<Teacher> teacherList);
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A callback used for error reporting, progress information.
|
|
||||||
* All the methods are always ran on a worker thread.
|
|
||||||
*/
|
|
||||||
public interface SyncCallback extends ProgressCallback {
|
|
||||||
void onLoginFirst(List<Profile> profileList, LoginStore loginStore);
|
|
||||||
void onSuccess(Context activityContext, ProfileFull profileFull);
|
|
||||||
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.v2
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.AppError
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
|
||||||
|
|
||||||
data class ApiLoginResult(val loginStore: LoginStore, val error: AppError?)
|
|
@ -1,6 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.v2
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.AppError
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
|
||||||
|
|
||||||
data class FirstLoginResult(val profileList: ArrayList<Profile>, val error: AppError?)
|
|
@ -1,12 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.v2.librus.firstlogin
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.App
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.ProgressCallback
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
|
||||||
|
|
||||||
class FirstLoginLibrus(val app: App, val loginStore: LoginStore, val progressCallback: ProgressCallback, val onSuccess: (profileList: List<Profile>) -> Unit) {
|
|
||||||
init {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.v2.librus.firstlogin
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.App
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.ProgressCallback
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
|
||||||
|
|
||||||
class FirstLoginSynergia(val app: App, val loginStore: LoginStore, val progressCallback: ProgressCallback, val onSuccess: (profileList: List<Profile>) -> Unit) {
|
|
||||||
init {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +1,17 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.db.modules.events;
|
package pl.szczodrzynski.edziennik.data.db.modules.events;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.sqlite.db.SimpleSQLiteQuery;
|
|
||||||
import androidx.sqlite.db.SupportSQLiteQuery;
|
|
||||||
import androidx.room.Dao;
|
import androidx.room.Dao;
|
||||||
import androidx.room.Insert;
|
import androidx.room.Insert;
|
||||||
import androidx.room.OnConflictStrategy;
|
import androidx.room.OnConflictStrategy;
|
||||||
import androidx.room.Query;
|
import androidx.room.Query;
|
||||||
import androidx.room.RawQuery;
|
import androidx.room.RawQuery;
|
||||||
import androidx.room.Transaction;
|
import androidx.room.Transaction;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.sqlite.db.SimpleSQLiteQuery;
|
||||||
import android.util.Log;
|
import androidx.sqlite.db.SupportSQLiteQuery;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -130,6 +131,12 @@ public abstract class EventDao {
|
|||||||
@Query("DELETE FROM events WHERE profileId = :profileId AND eventAddedManually = 0 AND eventDate >= :todayDate")
|
@Query("DELETE FROM events WHERE profileId = :profileId AND eventAddedManually = 0 AND eventDate >= :todayDate")
|
||||||
public abstract void removeFuture(int profileId, Date todayDate);
|
public abstract void removeFuture(int profileId, Date todayDate);
|
||||||
|
|
||||||
|
@Query("DELETE FROM events WHERE profileId = :profileId AND eventAddedManually = 0 AND eventDate >= :todayDate AND eventType = :type")
|
||||||
|
public abstract void removeFutureWithType(int profileId, Date todayDate, int type);
|
||||||
|
|
||||||
|
@Query("DELETE FROM events WHERE profileId = :profileId AND eventAddedManually = 0 AND eventDate >= :todayDate AND eventType != :exceptType")
|
||||||
|
public abstract void removeFutureExceptType(int profileId, Date todayDate, int exceptType);
|
||||||
|
|
||||||
@Query("UPDATE metadata SET seen = :seen WHERE profileId = :profileId AND (thingType = "+TYPE_EVENT+" OR thingType = "+TYPE_LESSON_CHANGE+" OR thingType = "+TYPE_HOMEWORK+") AND thingId IN (SELECT eventId FROM events WHERE profileId = :profileId AND eventDate = :date)")
|
@Query("UPDATE metadata SET seen = :seen WHERE profileId = :profileId AND (thingType = "+TYPE_EVENT+" OR thingType = "+TYPE_LESSON_CHANGE+" OR thingType = "+TYPE_HOMEWORK+") AND thingId IN (SELECT eventId FROM events WHERE profileId = :profileId AND eventDate = :date)")
|
||||||
public abstract void setSeenByDate(int profileId, Date date, boolean seen);
|
public abstract void setSeenByDate(int profileId, Date date, boolean seen);
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.db.modules.grades;
|
package pl.szczodrzynski.edziennik.data.db.modules.grades;
|
||||||
|
|
||||||
|
import androidx.room.Entity;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import androidx.room.Entity;
|
|
||||||
|
|
||||||
@Entity(tableName = "gradeCategories",
|
@Entity(tableName = "gradeCategories",
|
||||||
primaryKeys = {"profileId", "categoryId"})
|
primaryKeys = {"profileId", "categoryId"})
|
||||||
public class GradeCategory {
|
public class GradeCategory {
|
||||||
@ -25,6 +25,9 @@ public class GradeCategory {
|
|||||||
*/
|
*/
|
||||||
public int type = 0;
|
public int type = 0;
|
||||||
|
|
||||||
|
public static final int TYPE_NORMAL = 0;
|
||||||
|
public static final int TYPE_COMMENT = 1;
|
||||||
|
|
||||||
public GradeCategory(int profileId, long categoryId, float weight, int color, String text) {
|
public GradeCategory(int profileId, long categoryId, float weight, int color, String text) {
|
||||||
this.profileId = profileId;
|
this.profileId = profileId;
|
||||||
this.categoryId = categoryId;
|
this.categoryId = categoryId;
|
||||||
|
@ -37,7 +37,10 @@ public abstract class LuckyNumberDao {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Query("SELECT * FROM luckyNumbers WHERE profileId = :profileId AND luckyNumberDate >= :date ORDER BY luckyNumberDate DESC LIMIT 1")
|
@Query("SELECT * FROM luckyNumbers WHERE profileId = :profileId AND luckyNumberDate >= :date ORDER BY luckyNumberDate DESC LIMIT 1")
|
||||||
public abstract LuckyNumber getNearestFutureNow(int profileId, Date date);
|
public abstract LuckyNumber getNearestFutureNow(int profileId, int date);
|
||||||
|
|
||||||
|
@Query("SELECT * FROM luckyNumbers WHERE profileId = :profileId AND luckyNumberDate >= :date ORDER BY luckyNumberDate DESC LIMIT 1")
|
||||||
|
public abstract LiveData<LuckyNumber> getNearestFuture(int profileId, int date);
|
||||||
|
|
||||||
@RawQuery(observedEntities = {LuckyNumber.class})
|
@RawQuery(observedEntities = {LuckyNumber.class})
|
||||||
abstract LiveData<List<LuckyNumberFull>> getAll(SupportSQLiteQuery query);
|
abstract LiveData<List<LuckyNumberFull>> getAll(SupportSQLiteQuery query);
|
||||||
|
@ -21,7 +21,10 @@ interface NotificationDao {
|
|||||||
@Query("DELETE FROM notifications WHERE profileId = :profileId")
|
@Query("DELETE FROM notifications WHERE profileId = :profileId")
|
||||||
fun clear(profileId: Int)
|
fun clear(profileId: Int)
|
||||||
|
|
||||||
@Query("SELECT * FROM notifications")
|
@Query("DELETE FROM notifications")
|
||||||
|
fun clearAll()
|
||||||
|
|
||||||
|
@Query("SELECT * FROM notifications ORDER BY addedDate DESC")
|
||||||
fun getAll(): LiveData<List<Notification>>
|
fun getAll(): LiveData<List<Notification>>
|
||||||
|
|
||||||
@Query("SELECT * FROM notifications")
|
@Query("SELECT * FROM notifications")
|
||||||
|
@ -6,10 +6,10 @@ import com.google.gson.JsonObject
|
|||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE
|
||||||
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR
|
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.*
|
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.*
|
||||||
@ -74,6 +74,7 @@ class ProfileFull : Profile {
|
|||||||
fragmentIds.add(DRAWER_ITEM_AGENDA)
|
fragmentIds.add(DRAWER_ITEM_AGENDA)
|
||||||
fragmentIds.add(DRAWER_ITEM_GRADES)
|
fragmentIds.add(DRAWER_ITEM_GRADES)
|
||||||
fragmentIds.add(DRAWER_ITEM_MESSAGES)
|
fragmentIds.add(DRAWER_ITEM_MESSAGES)
|
||||||
|
fragmentIds.add(DRAWER_ITEM_HOMEWORK)
|
||||||
fragmentIds.add(DRAWER_ITEM_BEHAVIOUR)
|
fragmentIds.add(DRAWER_ITEM_BEHAVIOUR)
|
||||||
fragmentIds.add(DRAWER_ITEM_ATTENDANCE)
|
fragmentIds.add(DRAWER_ITEM_ATTENDANCE)
|
||||||
fragmentIds.add(DRAWER_ITEM_ANNOUNCEMENTS)
|
fragmentIds.add(DRAWER_ITEM_ANNOUNCEMENTS)
|
||||||
@ -87,9 +88,7 @@ class ProfileFull : Profile {
|
|||||||
return fragmentIds
|
return fragmentIds
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() : super() {
|
constructor() : super()
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(profile: Profile, loginStore: LoginStore) {
|
constructor(profile: Profile, loginStore: LoginStore) {
|
||||||
|
|
||||||
@ -122,7 +121,7 @@ class ProfileFull : Profile {
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(context: Context) : super(context) {}
|
constructor(context: Context) : super(context)
|
||||||
|
|
||||||
fun canChangeLoginPassword(): Boolean {
|
fun canChangeLoginPassword(): Boolean {
|
||||||
return loginStoreType == LOGIN_TYPE_MOBIDZIENNIK || loginStoreType == LOGIN_TYPE_LIBRUS || loginStoreType == LOGIN_TYPE_IUCZNIOWIE
|
return loginStoreType == LOGIN_TYPE_MOBIDZIENNIK || loginStoreType == LOGIN_TYPE_LIBRUS || loginStoreType == LOGIN_TYPE_IUCZNIOWIE
|
||||||
|
@ -15,7 +15,7 @@ import pl.szczodrzynski.edziennik.utils.models.Time
|
|||||||
Index(value = ["profileId", "type", "date"]),
|
Index(value = ["profileId", "type", "date"]),
|
||||||
Index(value = ["profileId", "type", "oldDate"])
|
Index(value = ["profileId", "type", "oldDate"])
|
||||||
])
|
])
|
||||||
open class Lesson(val profileId: Int, @PrimaryKey val id: Long) {
|
open class Lesson(val profileId: Int, @PrimaryKey var id: Long) {
|
||||||
companion object {
|
companion object {
|
||||||
const val TYPE_NO_LESSONS = -1
|
const val TYPE_NO_LESSONS = -1
|
||||||
const val TYPE_NORMAL = 0
|
const val TYPE_NORMAL = 0
|
||||||
@ -45,6 +45,27 @@ open class Lesson(val profileId: Int, @PrimaryKey val id: Long) {
|
|||||||
var oldTeamId: Long? = null
|
var oldTeamId: Long? = null
|
||||||
var oldClassroom: String? = null
|
var oldClassroom: String? = null
|
||||||
|
|
||||||
|
val displayDate: Date?
|
||||||
|
get() {
|
||||||
|
if (type == TYPE_SHIFTED_SOURCE)
|
||||||
|
return oldDate
|
||||||
|
return date ?: oldDate
|
||||||
|
}
|
||||||
|
|
||||||
|
val displayStartTime: Time?
|
||||||
|
get() {
|
||||||
|
if (type == TYPE_SHIFTED_SOURCE)
|
||||||
|
return oldStartTime
|
||||||
|
return startTime ?: oldStartTime
|
||||||
|
}
|
||||||
|
|
||||||
|
val isCancelled
|
||||||
|
get() = type == TYPE_CANCELLED || type == TYPE_SHIFTED_SOURCE
|
||||||
|
val isChange
|
||||||
|
get() = type == TYPE_CHANGE || type == TYPE_SHIFTED_TARGET
|
||||||
|
|
||||||
|
fun buildId(): Long = (displayDate?.combineWith(displayStartTime) ?: 0L) / 6L * 10L + (hashCode() and 0xFFFF)
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "Lesson(profileId=$profileId, " +
|
return "Lesson(profileId=$profileId, " +
|
||||||
"id=$id, " +
|
"id=$id, " +
|
||||||
@ -66,32 +87,53 @@ open class Lesson(val profileId: Int, @PrimaryKey val id: Long) {
|
|||||||
"oldTeamId=$oldTeamId, " +
|
"oldTeamId=$oldTeamId, " +
|
||||||
"oldClassroom=$oldClassroom)"
|
"oldClassroom=$oldClassroom)"
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/*
|
|
||||||
DROP TABLE lessons;
|
|
||||||
DROP TABLE lessonChanges;
|
|
||||||
CREATE TABLE lessons (
|
|
||||||
profileId INTEGER NOT NULL,
|
|
||||||
type INTEGER NOT NULL,
|
|
||||||
|
|
||||||
date TEXT DEFAULT NULL,
|
override fun equals(other: Any?): Boolean {
|
||||||
lessonNumber INTEGER DEFAULT NULL,
|
if (this === other) return true
|
||||||
startTime TEXT DEFAULT NULL,
|
if (other !is Lesson) return false
|
||||||
endTime TEXT DEFAULT NULL,
|
|
||||||
teacherId INTEGER DEFAULT NULL,
|
|
||||||
subjectId INTEGER DEFAULT NULL,
|
|
||||||
teamId INTEGER DEFAULT NULL,
|
|
||||||
classroom TEXT DEFAULT NULL,
|
|
||||||
|
|
||||||
oldDate TEXT DEFAULT NULL,
|
if (profileId != other.profileId) return false
|
||||||
oldLessonNumber INTEGER DEFAULT NULL,
|
if (id != other.id) return false
|
||||||
oldStartTime TEXT DEFAULT NULL,
|
if (type != other.type) return false
|
||||||
oldEndTime TEXT DEFAULT NULL,
|
if (date != other.date) return false
|
||||||
oldTeacherId INTEGER DEFAULT NULL,
|
if (lessonNumber != other.lessonNumber) return false
|
||||||
oldSubjectId INTEGER DEFAULT NULL,
|
if (startTime != other.startTime) return false
|
||||||
oldTeamId INTEGER DEFAULT NULL,
|
if (endTime != other.endTime) return false
|
||||||
oldClassroom TEXT DEFAULT NULL,
|
if (subjectId != other.subjectId) return false
|
||||||
|
if (teacherId != other.teacherId) return false
|
||||||
|
if (teamId != other.teamId) return false
|
||||||
|
if (classroom != other.classroom) return false
|
||||||
|
if (oldDate != other.oldDate) return false
|
||||||
|
if (oldLessonNumber != other.oldLessonNumber) return false
|
||||||
|
if (oldStartTime != other.oldStartTime) return false
|
||||||
|
if (oldEndTime != other.oldEndTime) return false
|
||||||
|
if (oldSubjectId != other.oldSubjectId) return false
|
||||||
|
if (oldTeacherId != other.oldTeacherId) return false
|
||||||
|
if (oldTeamId != other.oldTeamId) return false
|
||||||
|
if (oldClassroom != other.oldClassroom) return false
|
||||||
|
|
||||||
PRIMARY KEY(profileId)
|
return true
|
||||||
);
|
}
|
||||||
*/
|
|
||||||
|
override fun hashCode(): Int { // intentionally ignoring ID and display* here
|
||||||
|
var result = profileId
|
||||||
|
result = 31 * result + type
|
||||||
|
result = 31 * result + (date?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (lessonNumber ?: 0)
|
||||||
|
result = 31 * result + (startTime?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (endTime?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (subjectId?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (teacherId?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (teamId?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (classroom?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (oldDate?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (oldLessonNumber ?: 0)
|
||||||
|
result = 31 * result + (oldStartTime?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (oldEndTime?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (oldSubjectId?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (oldTeacherId?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (oldTeamId?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (oldClassroom?.hashCode() ?: 0)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.db.modules.timetable
|
package pl.szczodrzynski.edziennik.data.db.modules.timetable
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import android.content.Context
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
|
|
||||||
class LessonFull(profileId: Int, id: Long) : Lesson(profileId, id) {
|
class LessonFull(profileId: Int, id: Long) : Lesson(profileId, id) {
|
||||||
@ -11,24 +12,13 @@ class LessonFull(profileId: Int, id: Long) : Lesson(profileId, id) {
|
|||||||
var oldTeacherName: String? = null
|
var oldTeacherName: String? = null
|
||||||
var oldTeamName: String? = null
|
var oldTeamName: String? = null
|
||||||
|
|
||||||
val displayDate: Date?
|
|
||||||
get() {
|
|
||||||
if (type == TYPE_SHIFTED_SOURCE)
|
|
||||||
return oldDate
|
|
||||||
return date ?: oldDate
|
|
||||||
}
|
|
||||||
val displayLessonNumber: Int?
|
val displayLessonNumber: Int?
|
||||||
get() {
|
get() {
|
||||||
if (type == TYPE_SHIFTED_SOURCE)
|
if (type == TYPE_SHIFTED_SOURCE)
|
||||||
return oldLessonNumber
|
return oldLessonNumber
|
||||||
return lessonNumber ?: oldLessonNumber
|
return lessonNumber ?: oldLessonNumber
|
||||||
}
|
}
|
||||||
val displayStartTime: Time?
|
|
||||||
get() {
|
|
||||||
if (type == TYPE_SHIFTED_SOURCE)
|
|
||||||
return oldStartTime
|
|
||||||
return startTime ?: oldStartTime
|
|
||||||
}
|
|
||||||
val displayEndTime: Time?
|
val displayEndTime: Time?
|
||||||
get() {
|
get() {
|
||||||
if (type == TYPE_SHIFTED_SOURCE)
|
if (type == TYPE_SHIFTED_SOURCE)
|
||||||
@ -42,12 +32,14 @@ class LessonFull(profileId: Int, id: Long) : Lesson(profileId, id) {
|
|||||||
return oldSubjectName
|
return oldSubjectName
|
||||||
return subjectName ?: oldSubjectName
|
return subjectName ?: oldSubjectName
|
||||||
}
|
}
|
||||||
|
|
||||||
val displayTeacherName: String?
|
val displayTeacherName: String?
|
||||||
get() {
|
get() {
|
||||||
if (type == TYPE_SHIFTED_SOURCE)
|
if (type == TYPE_SHIFTED_SOURCE)
|
||||||
return oldTeacherName
|
return oldTeacherName
|
||||||
return teacherName ?: oldTeacherName
|
return teacherName ?: oldTeacherName
|
||||||
}
|
}
|
||||||
|
|
||||||
val displayTeamName: String?
|
val displayTeamName: String?
|
||||||
get() {
|
get() {
|
||||||
if (type == TYPE_SHIFTED_SOURCE)
|
if (type == TYPE_SHIFTED_SOURCE)
|
||||||
@ -68,12 +60,14 @@ class LessonFull(profileId: Int, id: Long) : Lesson(profileId, id) {
|
|||||||
return oldTeamId
|
return oldTeamId
|
||||||
return teamId ?: oldTeamId
|
return teamId ?: oldTeamId
|
||||||
}
|
}
|
||||||
|
|
||||||
val displaySubjectId: Long?
|
val displaySubjectId: Long?
|
||||||
get() {
|
get() {
|
||||||
if (type == TYPE_SHIFTED_SOURCE)
|
if (type == TYPE_SHIFTED_SOURCE)
|
||||||
return oldSubjectId
|
return oldSubjectId
|
||||||
return subjectId ?: oldSubjectId
|
return subjectId ?: oldSubjectId
|
||||||
}
|
}
|
||||||
|
|
||||||
val displayTeacherId: Long?
|
val displayTeacherId: Long?
|
||||||
get() {
|
get() {
|
||||||
if (type == TYPE_SHIFTED_SOURCE)
|
if (type == TYPE_SHIFTED_SOURCE)
|
||||||
@ -81,8 +75,35 @@ class LessonFull(profileId: Int, id: Long) : Lesson(profileId, id) {
|
|||||||
return teacherId ?: oldTeacherId
|
return teacherId ?: oldTeacherId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getDisplayChangeType(context: Context): String {
|
||||||
|
return context.getString(when (type) {
|
||||||
|
TYPE_CHANGE -> R.string.lesson_change
|
||||||
|
TYPE_CANCELLED -> R.string.lesson_cancelled
|
||||||
|
TYPE_SHIFTED_TARGET, TYPE_SHIFTED_SOURCE -> R.string.lesson_shifted
|
||||||
|
else -> R.string.lesson_timetable_change
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
val changeSubjectName: String
|
||||||
|
get() {
|
||||||
|
val first = when (type) {
|
||||||
|
TYPE_CHANGE, TYPE_CANCELLED, TYPE_SHIFTED_SOURCE -> oldSubjectName
|
||||||
|
else -> subjectName
|
||||||
|
}
|
||||||
|
|
||||||
|
val second = when (type) {
|
||||||
|
TYPE_CHANGE -> subjectName
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
return when (second) {
|
||||||
|
null -> first ?: ""
|
||||||
|
else -> "$first -> $second"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// metadata
|
// metadata
|
||||||
var seen: Boolean = false
|
var seen: Boolean = false
|
||||||
var notified: Boolean = false
|
var notified: Boolean = false
|
||||||
var addedDate: Long = 0
|
var addedDate: Long = 0
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,27 @@ import pl.szczodrzynski.edziennik.utils.models.Date
|
|||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface TimetableDao {
|
interface TimetableDao {
|
||||||
|
companion object {
|
||||||
|
private const val QUERY = """
|
||||||
|
SELECT
|
||||||
|
timetable.*,
|
||||||
|
subjects.subjectLongName AS subjectName,
|
||||||
|
teachers.teacherName ||" "|| teachers.teacherSurname AS teacherName,
|
||||||
|
teams.teamName AS teamName,
|
||||||
|
oldS.subjectLongName AS oldSubjectName,
|
||||||
|
oldT.teacherName ||" "|| oldT.teacherSurname AS oldTeacherName,
|
||||||
|
oldG.teamName AS oldTeamName,
|
||||||
|
metadata.seen, metadata.notified, metadata.addedDate
|
||||||
|
FROM timetable
|
||||||
|
LEFT JOIN subjects USING(profileId, subjectId)
|
||||||
|
LEFT JOIN teachers USING(profileId, teacherId)
|
||||||
|
LEFT JOIN teams USING(profileId, teamId)
|
||||||
|
LEFT JOIN subjects AS oldS ON timetable.profileId = oldS.profileId AND timetable.oldSubjectId = oldS.subjectId
|
||||||
|
LEFT JOIN teachers AS oldT ON timetable.profileId = oldT.profileId AND timetable.oldTeacherId = oldT.teacherId
|
||||||
|
LEFT JOIN teams AS oldG ON timetable.profileId = oldG.profileId AND timetable.oldTeamId = oldG.teamId
|
||||||
|
LEFT JOIN metadata ON id = thingId AND thingType = ${Metadata.TYPE_LESSON_CHANGE} AND metadata.profileId = timetable.profileId
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
operator fun plusAssign(lessonList: List<Lesson>)
|
operator fun plusAssign(lessonList: List<Lesson>)
|
||||||
@ -17,57 +38,67 @@ interface TimetableDao {
|
|||||||
@Query("DELETE FROM timetable WHERE profileId = :profileId")
|
@Query("DELETE FROM timetable WHERE profileId = :profileId")
|
||||||
fun clear(profileId: Int)
|
fun clear(profileId: Int)
|
||||||
|
|
||||||
@Query("DELETE FROM timetable WHERE profileId = :profileId AND (type != 3 AND date >= :dateFrom) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom)")
|
@Query("DELETE FROM timetable WHERE profileId = :profileId AND ((type != 3 AND date >= :dateFrom) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom))")
|
||||||
fun clearFromDate(profileId: Int, dateFrom: Date)
|
fun clearFromDate(profileId: Int, dateFrom: Date)
|
||||||
@Query("DELETE FROM timetable WHERE profileId = :profileId AND (type != 3 AND date <= :dateTo) OR ((type = 3 OR type = 1) AND oldDate <= :dateTo)")
|
@Query("DELETE FROM timetable WHERE profileId = :profileId AND ((type != 3 AND date <= :dateTo) OR ((type = 3 OR type = 1) AND oldDate <= :dateTo))")
|
||||||
fun clearToDate(profileId: Int, dateTo: Date)
|
fun clearToDate(profileId: Int, dateTo: Date)
|
||||||
@Query("DELETE FROM timetable WHERE profileId = :profileId AND (type != 3 AND date >= :dateFrom AND date <= :dateTo) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom AND oldDate <= :dateTo)")
|
@Query("DELETE FROM timetable WHERE profileId = :profileId AND ((type != 3 AND date >= :dateFrom AND date <= :dateTo) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom AND oldDate <= :dateTo))")
|
||||||
fun clearBetweenDates(profileId: Int, dateFrom: Date, dateTo: Date)
|
fun clearBetweenDates(profileId: Int, dateFrom: Date, dateTo: Date)
|
||||||
|
|
||||||
@Query("""
|
@Query("""
|
||||||
SELECT
|
$QUERY
|
||||||
timetable.*,
|
WHERE timetable.profileId = :profileId AND ((type != 3 AND date = :date) OR ((type = 3 OR type = 1) AND oldDate = :date))
|
||||||
subjects.subjectLongName AS subjectName,
|
|
||||||
teachers.teacherName ||" "|| teachers.teacherSurname AS teacherName,
|
|
||||||
teams.teamName AS teamName,
|
|
||||||
oldS.subjectLongName AS oldSubjectName,
|
|
||||||
oldT.teacherName ||" "|| oldT.teacherSurname AS oldTeacherName,
|
|
||||||
oldG.teamName AS oldTeamName,
|
|
||||||
metadata.seen, metadata.notified, metadata.addedDate
|
|
||||||
FROM timetable
|
|
||||||
LEFT JOIN subjects USING(profileId, subjectId)
|
|
||||||
LEFT JOIN teachers USING(profileId, teacherId)
|
|
||||||
LEFT JOIN teams USING(profileId, teamId)
|
|
||||||
LEFT JOIN subjects AS oldS ON timetable.profileId = oldS.profileId AND timetable.oldSubjectId = oldS.subjectId
|
|
||||||
LEFT JOIN teachers AS oldT ON timetable.profileId = oldT.profileId AND timetable.oldTeacherId = oldT.teacherId
|
|
||||||
LEFT JOIN teams AS oldG ON timetable.profileId = oldG.profileId AND timetable.oldTeamId = oldG.teamId
|
|
||||||
LEFT JOIN metadata ON id = thingId AND thingType = ${Metadata.TYPE_LESSON_CHANGE} AND metadata.profileId = timetable.profileId
|
|
||||||
WHERE timetable.profileId = :profileId AND (type != 3 AND date = :date) OR ((type = 3 OR type = 1) AND oldDate = :date)
|
|
||||||
ORDER BY id, type
|
ORDER BY id, type
|
||||||
""")
|
""")
|
||||||
fun getForDate(profileId: Int, date: Date) : LiveData<List<LessonFull>>
|
fun getForDate(profileId: Int, date: Date) : LiveData<List<LessonFull>>
|
||||||
|
|
||||||
@Query("""
|
@Query("""
|
||||||
SELECT
|
$QUERY
|
||||||
timetable.*,
|
WHERE timetable.profileId = :profileId AND ((type != 3 AND date = :date) OR ((type = 3 OR type = 1) AND oldDate = :date))
|
||||||
subjects.subjectLongName AS subjectName,
|
ORDER BY id, type
|
||||||
teachers.teacherName ||" "|| teachers.teacherSurname AS teacherName,
|
""")
|
||||||
teams.teamName AS teamName,
|
fun getForDateNow(profileId: Int, date: Date) : List<LessonFull>
|
||||||
oldS.subjectLongName AS oldSubjectName,
|
|
||||||
oldT.teacherName ||" "|| oldT.teacherSurname AS oldTeacherName,
|
@Query("""
|
||||||
oldG.teamName AS oldTeamName,
|
$QUERY
|
||||||
metadata.seen, metadata.notified, metadata.addedDate
|
|
||||||
FROM timetable
|
|
||||||
LEFT JOIN subjects USING(profileId, subjectId)
|
|
||||||
LEFT JOIN teachers USING(profileId, teacherId)
|
|
||||||
LEFT JOIN teams USING(profileId, teamId)
|
|
||||||
LEFT JOIN subjects AS oldS ON timetable.profileId = oldS.profileId AND timetable.oldSubjectId = oldS.subjectId
|
|
||||||
LEFT JOIN teachers AS oldT ON timetable.profileId = oldT.profileId AND timetable.oldTeacherId = oldT.teacherId
|
|
||||||
LEFT JOIN teams AS oldG ON timetable.profileId = oldG.profileId AND timetable.oldTeamId = oldG.teamId
|
|
||||||
LEFT JOIN metadata ON id = thingId AND thingType = ${Metadata.TYPE_LESSON_CHANGE} AND metadata.profileId = timetable.profileId
|
|
||||||
WHERE timetable.profileId = :profileId AND ((type != 3 AND date > :today) OR ((type = 3 OR type = 1) AND oldDate > :today)) AND timetable.subjectId = :subjectId
|
WHERE timetable.profileId = :profileId AND ((type != 3 AND date > :today) OR ((type = 3 OR type = 1) AND oldDate > :today)) AND timetable.subjectId = :subjectId
|
||||||
ORDER BY id, type
|
ORDER BY id, type
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
""")
|
""")
|
||||||
fun getNextWithSubject(profileId: Int, today: Date, subjectId: Long) : LiveData<LessonFull>
|
fun getNextWithSubject(profileId: Int, today: Date, subjectId: Long) : LiveData<LessonFull?>
|
||||||
|
|
||||||
|
@Query("""
|
||||||
|
$QUERY
|
||||||
|
WHERE timetable.profileId = :profileId AND ((type != 3 AND date > :today) OR ((type = 3 OR type = 1) AND oldDate > :today)) AND timetable.subjectId = :subjectId AND timetable.teamId = :teamId
|
||||||
|
ORDER BY id, type
|
||||||
|
LIMIT 1
|
||||||
|
""")
|
||||||
|
fun getNextWithSubjectAndTeam(profileId: Int, today: Date, subjectId: Long, teamId: Long): LiveData<LessonFull?>
|
||||||
|
|
||||||
|
@Query("""
|
||||||
|
$QUERY
|
||||||
|
WHERE (type != 3 AND date >= :dateFrom AND date <= :dateTo) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom AND oldDate <= :dateTo)
|
||||||
|
ORDER BY profileId, id, type
|
||||||
|
""")
|
||||||
|
fun getBetweenDatesNow(dateFrom: Date, dateTo: Date) : List<LessonFull>
|
||||||
|
|
||||||
|
@Query("""
|
||||||
|
$QUERY
|
||||||
|
WHERE (type != 3 AND date >= :dateFrom AND date <= :dateTo) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom AND oldDate <= :dateTo)
|
||||||
|
ORDER BY profileId, id, type
|
||||||
|
""")
|
||||||
|
fun getBetweenDates(dateFrom: Date, dateTo: Date) : LiveData<List<LessonFull>>
|
||||||
|
|
||||||
|
@Query("""
|
||||||
|
$QUERY
|
||||||
|
WHERE timetable.profileId = :profileId AND timetable.id = :lessonId
|
||||||
|
ORDER BY id, type
|
||||||
|
""")
|
||||||
|
fun getByIdNow(profileId: Int, lessonId: Long) : LessonFull?
|
||||||
|
|
||||||
|
@Query("""
|
||||||
|
$QUERY
|
||||||
|
WHERE timetable.profileId = :profileId AND timetable.type NOT IN (${Lesson.TYPE_NORMAL}, ${Lesson.TYPE_NO_LESSONS}, ${Lesson.TYPE_SHIFTED_SOURCE}) AND metadata.notified = 0
|
||||||
|
""")
|
||||||
|
fun getNotNotifiedNow(profileId: Int): List<LessonFull>
|
||||||
}
|
}
|
||||||
|
@ -125,19 +125,22 @@ public class BootReceiver extends BroadcastReceiver {
|
|||||||
String updateUrl = result.get("update_url").getAsString();
|
String updateUrl = result.get("update_url").getAsString();
|
||||||
String updateFilename = result.get("update_filename").getAsString();
|
String updateFilename = result.get("update_filename").getAsString();
|
||||||
boolean updateMandatory = result.get("update_mandatory").getAsBoolean();
|
boolean updateMandatory = result.get("update_mandatory").getAsBoolean();
|
||||||
|
boolean updateDirect = result.get("update_direct").getAsBoolean();
|
||||||
|
|
||||||
if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals(updateVersion)) {
|
if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals(updateVersion)) {
|
||||||
app.appConfig.updateVersion = updateVersion;
|
app.appConfig.updateVersion = updateVersion;
|
||||||
app.appConfig.updateUrl = updateUrl;
|
app.appConfig.updateUrl = updateUrl;
|
||||||
app.appConfig.updateFilename = updateFilename;
|
app.appConfig.updateFilename = updateFilename;
|
||||||
app.appConfig.updateMandatory = updateMandatory;
|
app.appConfig.updateMandatory = updateMandatory;
|
||||||
|
app.appConfig.updateDirect = updateDirect;
|
||||||
app.saveConfig();
|
app.saveConfig();
|
||||||
}
|
}
|
||||||
if (!UPDATES_ON_PLAY_STORE || intent.getBooleanExtra("UserChecked", false)) {
|
if (!UPDATES_ON_PLAY_STORE || intent.getBooleanExtra("UserChecked", false)) {
|
||||||
app.notifier.notificationUpdatesShow(
|
app.notifier.notificationUpdatesShow(
|
||||||
updateVersion,
|
updateVersion,
|
||||||
updateUrl,
|
updateUrl,
|
||||||
updateFilename);
|
updateFilename,
|
||||||
|
updateDirect);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals("")) {
|
if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals("")) {
|
||||||
@ -259,7 +262,7 @@ public class BootReceiver extends BroadcastReceiver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onHandleIntent(Intent intent) {
|
protected void onHandleIntent(Intent intent) {
|
||||||
if (UPDATES_ON_PLAY_STORE) {
|
if (UPDATES_ON_PLAY_STORE && !intent.getBooleanExtra("update_direct", false)) {
|
||||||
Utils.openGooglePlay(this, "pl.szczodrzynski.edziennik");
|
Utils.openGooglePlay(this, "pl.szczodrzynski.edziennik");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -270,7 +273,8 @@ public class BootReceiver extends BroadcastReceiver {
|
|||||||
app.notifier.notificationUpdatesShow(
|
app.notifier.notificationUpdatesShow(
|
||||||
intent.getStringExtra("update_version"),
|
intent.getStringExtra("update_version"),
|
||||||
intent.getStringExtra("update_url"),
|
intent.getStringExtra("update_url"),
|
||||||
intent.getStringExtra("update_filename"));
|
intent.getStringExtra("update_filename"),
|
||||||
|
intent.getBooleanExtra("update_direct", false));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,19 +154,22 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService {
|
|||||||
String updateUrl = remoteMessage.getData().get("update_url");
|
String updateUrl = remoteMessage.getData().get("update_url");
|
||||||
String updateFilename = remoteMessage.getData().get("update_filename");
|
String updateFilename = remoteMessage.getData().get("update_filename");
|
||||||
boolean updateMandatory = Boolean.parseBoolean(remoteMessage.getData().get("update_mandatory"));
|
boolean updateMandatory = Boolean.parseBoolean(remoteMessage.getData().get("update_mandatory"));
|
||||||
|
boolean updateDirect = Boolean.parseBoolean(remoteMessage.getData().get("update_direct"));
|
||||||
|
|
||||||
if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals(updateVersion)) {
|
if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals(updateVersion)) {
|
||||||
app.appConfig.updateVersion = updateVersion;
|
app.appConfig.updateVersion = updateVersion;
|
||||||
app.appConfig.updateUrl = updateUrl;
|
app.appConfig.updateUrl = updateUrl;
|
||||||
app.appConfig.updateFilename = updateFilename;
|
app.appConfig.updateFilename = updateFilename;
|
||||||
app.appConfig.updateMandatory = updateMandatory;
|
app.appConfig.updateMandatory = updateMandatory;
|
||||||
|
app.appConfig.updateDirect = updateDirect;
|
||||||
app.saveConfig("updateVersion", "updateUrl", "updateFilename", "updateMandatory");
|
app.saveConfig("updateVersion", "updateUrl", "updateFilename", "updateMandatory");
|
||||||
}
|
}
|
||||||
if (!remoteMessage.getData().containsKey("update_silent")) {
|
if (!remoteMessage.getData().containsKey("update_silent")) {
|
||||||
app.notifier.notificationUpdatesShow(
|
app.notifier.notificationUpdatesShow(
|
||||||
updateVersion,
|
updateVersion,
|
||||||
updateUrl,
|
updateUrl,
|
||||||
updateFilename);
|
updateFilename,
|
||||||
|
updateDirect);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals("")) {
|
if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals("")) {
|
||||||
|
@ -36,7 +36,6 @@ import java.util.List;
|
|||||||
import pl.szczodrzynski.edziennik.App;
|
import pl.szczodrzynski.edziennik.App;
|
||||||
import pl.szczodrzynski.edziennik.MainActivity;
|
import pl.szczodrzynski.edziennik.MainActivity;
|
||||||
import pl.szczodrzynski.edziennik.R;
|
import pl.szczodrzynski.edziennik.R;
|
||||||
import pl.szczodrzynski.edziennik.data.api.AppError;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event;
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event;
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull;
|
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull;
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventType;
|
import pl.szczodrzynski.edziennik.data.db.modules.events.EventType;
|
||||||
@ -54,7 +53,6 @@ import pl.szczodrzynski.edziennik.utils.models.Time;
|
|||||||
import pl.szczodrzynski.edziennik.utils.models.Week;
|
import pl.szczodrzynski.edziennik.utils.models.Week;
|
||||||
|
|
||||||
import static pl.szczodrzynski.edziennik.App.APP_URL;
|
import static pl.szczodrzynski.edziennik.App.APP_URL;
|
||||||
import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_OTHER;
|
|
||||||
import static pl.szczodrzynski.edziennik.data.db.modules.events.Event.COLOR_DEFAULT;
|
import static pl.szczodrzynski.edziennik.data.db.modules.events.Event.COLOR_DEFAULT;
|
||||||
import static pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_HOMEWORK;
|
import static pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_HOMEWORK;
|
||||||
import static pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_UNDEFINED;
|
import static pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_UNDEFINED;
|
||||||
@ -374,7 +372,8 @@ public class EventManualDialog {
|
|||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
activity.runOnUiThread(() -> {
|
activity.runOnUiThread(() -> {
|
||||||
app.apiEdziennik.guiShowErrorDialog(activity, new AppError(TAG, 379, CODE_OTHER, null, e), R.string.error_occured);
|
// TODO show error in EventManualDialog
|
||||||
|
//app.apiEdziennik.guiShowErrorDialog(activity, new AppError(TAG, 379, CODE_OTHER, null, e), R.string.error_occured);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -518,7 +517,7 @@ public class EventManualDialog {
|
|||||||
|
|
||||||
registerEventManualDateLayout = dialogView.findViewById(R.id.registerEventManualDateLayout);
|
registerEventManualDateLayout = dialogView.findViewById(R.id.registerEventManualDateLayout);
|
||||||
registerEventManualDate = dialogView.findViewById(R.id.registerEventManualDate);
|
registerEventManualDate = dialogView.findViewById(R.id.registerEventManualDate);
|
||||||
registerEventManualDate.setCompoundDrawablesWithIntrinsicBounds(null, null, new IconicsDrawable(context, CommunityMaterial.Icon.cmd_calendar).size(IconicsSize.dp(16)).color(IconicsColor.colorInt(primaryTextColor)), null);
|
registerEventManualDate.setCompoundDrawablesWithIntrinsicBounds(null, null, new IconicsDrawable(context, CommunityMaterial.Icon.cmd_calendar_outline).size(IconicsSize.dp(16)).color(IconicsColor.colorInt(primaryTextColor)), null);
|
||||||
//registerEventManualDate.setCompoundDrawablePadding(Utils.dpToPx(6));
|
//registerEventManualDate.setCompoundDrawablePadding(Utils.dpToPx(6));
|
||||||
registerEventManualLessonLayout = dialogView.findViewById(R.id.registerEventManualLessonLayout);
|
registerEventManualLessonLayout = dialogView.findViewById(R.id.registerEventManualLessonLayout);
|
||||||
registerEventManualLesson = dialogView.findViewById(R.id.registerEventManualLesson);
|
registerEventManualLesson = dialogView.findViewById(R.id.registerEventManualLesson);
|
||||||
|
@ -4,19 +4,26 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.ui.dialogs.event
|
package pl.szczodrzynski.edziennik.ui.dialogs.event
|
||||||
|
|
||||||
|
import android.graphics.PorterDuff
|
||||||
|
import android.graphics.PorterDuffColorFilter
|
||||||
|
import android.view.View
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import com.google.android.material.datepicker.MaterialDatePicker
|
import com.google.android.material.datepicker.MaterialDatePicker
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.jaredrummler.android.colorpicker.ColorPickerDialog
|
||||||
|
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import pl.szczodrzynski.edziennik.*
|
import pl.szczodrzynski.edziennik.*
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.events.EventType
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject
|
import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.LessonFull
|
import pl.szczodrzynski.edziennik.data.db.modules.timetable.LessonFull
|
||||||
import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding
|
import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Anim
|
||||||
import pl.szczodrzynski.edziennik.utils.TextInputDropDown
|
import pl.szczodrzynski.edziennik.utils.TextInputDropDown
|
||||||
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
|
||||||
@ -30,7 +37,9 @@ class EventManualV2Dialog(
|
|||||||
val defaultDate: Date? = null,
|
val defaultDate: Date? = null,
|
||||||
val defaultTime: Time? = null,
|
val defaultTime: Time? = null,
|
||||||
val defaultType: Int? = null,
|
val defaultType: Int? = null,
|
||||||
val editingEvent: Event? = null
|
val editingEvent: Event? = null,
|
||||||
|
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||||
|
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||||
) : CoroutineScope {
|
) : CoroutineScope {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -44,18 +53,25 @@ class EventManualV2Dialog(
|
|||||||
private val app by lazy { activity.application as App }
|
private val app by lazy { activity.application as App }
|
||||||
private lateinit var b: DialogEventManualV2Binding
|
private lateinit var b: DialogEventManualV2Binding
|
||||||
private lateinit var dialog: AlertDialog
|
private lateinit var dialog: AlertDialog
|
||||||
private lateinit var event: Event
|
|
||||||
private var defaultLoaded = false
|
private var defaultLoaded = false
|
||||||
|
|
||||||
init { run {
|
private lateinit var event: Event
|
||||||
job = Job()
|
private var customColor: Int? = null
|
||||||
|
|
||||||
|
init { run {
|
||||||
|
if (activity.isFinishing)
|
||||||
|
return@run
|
||||||
|
job = Job()
|
||||||
|
onShowListener?.invoke(TAG)
|
||||||
b = DialogEventManualV2Binding.inflate(activity.layoutInflater)
|
b = DialogEventManualV2Binding.inflate(activity.layoutInflater)
|
||||||
dialog = MaterialAlertDialogBuilder(activity)
|
dialog = MaterialAlertDialogBuilder(activity)
|
||||||
.setTitle(R.string.dialog_event_manual_title)
|
.setTitle(R.string.dialog_event_manual_title)
|
||||||
.setView(b.root)
|
.setView(b.root)
|
||||||
.setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
|
.setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
|
||||||
.setPositiveButton(R.string.save) { _, _ -> saveEvent() }
|
.setPositiveButton(R.string.save) { _, _ -> saveEvent() }
|
||||||
|
.setOnDismissListener {
|
||||||
|
onDismissListener?.invoke(TAG)
|
||||||
|
}
|
||||||
.show()
|
.show()
|
||||||
|
|
||||||
event = editingEvent?.clone() ?: Event().also { event ->
|
event = editingEvent?.clone() ?: Event().also { event ->
|
||||||
@ -71,11 +87,46 @@ class EventManualV2Dialog(
|
|||||||
defaultType?.let {
|
defaultType?.let {
|
||||||
event.type = it
|
event.type = it
|
||||||
}*/
|
}*/
|
||||||
|
b.shareSwitch.isChecked = event.sharedBy != null
|
||||||
|
}
|
||||||
|
|
||||||
|
b.showMore.onClick { // TODO iconics is broken
|
||||||
|
it.apply {
|
||||||
|
refreshDrawableState()
|
||||||
|
|
||||||
|
if (isChecked)
|
||||||
|
Anim.expand(b.moreLayout, 200, null)
|
||||||
|
else
|
||||||
|
Anim.collapse(b.moreLayout, 200, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateShareText()
|
||||||
|
b.shareSwitch.onChange { _, isChecked ->
|
||||||
|
updateShareText(isChecked)
|
||||||
}
|
}
|
||||||
|
|
||||||
loadLists()
|
loadLists()
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
private fun updateShareText(checked: Boolean = b.shareSwitch.isChecked) {
|
||||||
|
val editingShared = editingEvent?.sharedBy != null
|
||||||
|
val editingOwn = editingEvent?.sharedBy == "self"
|
||||||
|
|
||||||
|
b.shareDetails.visibility = if (checked || editingShared)
|
||||||
|
View.VISIBLE
|
||||||
|
else View.GONE
|
||||||
|
|
||||||
|
val text = when {
|
||||||
|
checked && editingShared && editingOwn -> R.string.dialog_event_manual_share_will_change
|
||||||
|
checked && editingShared -> R.string.dialog_event_manual_share_will_request
|
||||||
|
!checked && editingShared -> R.string.dialog_event_manual_share_will_remove
|
||||||
|
else -> R.string.dialog_event_manual_share_first_notice
|
||||||
|
}
|
||||||
|
|
||||||
|
b.shareDetails.setText(text)
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadLists() { launch {
|
private fun loadLists() { launch {
|
||||||
val deferred = async(Dispatchers.Default) {
|
val deferred = async(Dispatchers.Default) {
|
||||||
// get the team list
|
// get the team list
|
||||||
@ -107,18 +158,33 @@ class EventManualV2Dialog(
|
|||||||
""
|
""
|
||||||
)
|
)
|
||||||
b.teacherDropdown += teachers.map { TextInputDropDown.Item(it.id, it.fullName, tag = it) }
|
b.teacherDropdown += teachers.map { TextInputDropDown.Item(it.id, it.fullName, tag = it) }
|
||||||
|
|
||||||
|
// get the event type list
|
||||||
|
val eventTypes = app.db.eventTypeDao().getAllNow(profileId)
|
||||||
|
b.typeDropdown.clear()
|
||||||
|
b.typeDropdown += eventTypes.map { TextInputDropDown.Item(it.id, it.name, tag = it) }
|
||||||
}
|
}
|
||||||
deferred.await()
|
deferred.await()
|
||||||
|
|
||||||
b.teamDropdown.isEnabled = true
|
b.teamDropdown.isEnabled = true
|
||||||
b.subjectDropdown.isEnabled = true
|
b.subjectDropdown.isEnabled = true
|
||||||
b.teacherDropdown.isEnabled = true
|
b.teacherDropdown.isEnabled = true
|
||||||
|
b.typeDropdown.isEnabled = true
|
||||||
|
|
||||||
|
b.typeDropdown.selected?.let { item ->
|
||||||
|
customColor = (item.tag as EventType).color
|
||||||
|
}
|
||||||
|
|
||||||
// copy IDs from event being edited
|
// copy IDs from event being edited
|
||||||
editingEvent?.let {
|
editingEvent?.let {
|
||||||
b.teamDropdown.select(it.teamId)
|
b.teamDropdown.select(it.teamId)
|
||||||
b.subjectDropdown.select(it.subjectId)
|
b.subjectDropdown.select(it.subjectId)
|
||||||
b.teacherDropdown.select(it.teacherId)
|
b.teacherDropdown.select(it.teacherId)
|
||||||
|
b.typeDropdown.select(it.type)?.let { item ->
|
||||||
|
customColor = (item.tag as EventType).color
|
||||||
|
}
|
||||||
|
if (it.color != -1)
|
||||||
|
customColor = it.color
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy IDs from the LessonFull
|
// copy IDs from the LessonFull
|
||||||
@ -128,6 +194,30 @@ class EventManualV2Dialog(
|
|||||||
b.teacherDropdown.select(it.displayTeacherId)
|
b.teacherDropdown.select(it.displayTeacherId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.typeDropdown.setOnChangeListener {
|
||||||
|
b.typeColor.background.colorFilter = PorterDuffColorFilter((it.tag as EventType).color, PorterDuff.Mode.SRC_ATOP)
|
||||||
|
customColor = null
|
||||||
|
return@setOnChangeListener true
|
||||||
|
}
|
||||||
|
(customColor ?: Event.COLOR_DEFAULT).let {
|
||||||
|
b.typeColor.background.colorFilter = PorterDuffColorFilter(it, PorterDuff.Mode.SRC_ATOP)
|
||||||
|
}
|
||||||
|
b.typeColor.onClick {
|
||||||
|
val currentColor = (b.typeDropdown?.selected?.tag as EventType?)?.color ?: Event.COLOR_DEFAULT
|
||||||
|
val colorPickerDialog = ColorPickerDialog.newBuilder()
|
||||||
|
.setColor(currentColor)
|
||||||
|
.create()
|
||||||
|
colorPickerDialog.setColorPickerDialogListener(
|
||||||
|
object : ColorPickerDialogListener {
|
||||||
|
override fun onDialogDismissed(dialogId: Int) {}
|
||||||
|
override fun onColorSelected(dialogId: Int, color: Int) {
|
||||||
|
b.typeColor.background.colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)
|
||||||
|
customColor = color
|
||||||
|
}
|
||||||
|
})
|
||||||
|
colorPickerDialog.show(activity.fragmentManager, "color-picker-dialog")
|
||||||
|
}
|
||||||
|
|
||||||
loadDates()
|
loadDates()
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@ -198,12 +288,20 @@ class EventManualV2Dialog(
|
|||||||
val dates = deferred.await()
|
val dates = deferred.await()
|
||||||
b.dateDropdown.clear().append(dates)
|
b.dateDropdown.clear().append(dates)
|
||||||
|
|
||||||
editingEvent?.let {
|
editingEvent?.eventDate?.let {
|
||||||
b.dateDropdown.select(it.eventDate.value.toLong())
|
b.dateDropdown.select(TextInputDropDown.Item(
|
||||||
|
it.value.toLong(),
|
||||||
|
it.formattedString,
|
||||||
|
tag = it
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultLesson?.let {
|
defaultLesson?.displayDate?.let {
|
||||||
b.dateDropdown.select(it.displayDate?.value?.toLong())
|
b.dateDropdown.select(TextInputDropDown.Item(
|
||||||
|
it.value.toLong(),
|
||||||
|
it.formattedString,
|
||||||
|
tag = it
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (b.dateDropdown.selected == null) {
|
if (b.dateDropdown.selected == null) {
|
||||||
@ -216,22 +314,24 @@ class EventManualV2Dialog(
|
|||||||
when {
|
when {
|
||||||
// next lesson with specified subject
|
// next lesson with specified subject
|
||||||
item.id < -1 -> {
|
item.id < -1 -> {
|
||||||
app.db.timetableDao().getNextWithSubject(profileId, Date.getToday(), -item.id).observeOnce(activity, Observer {
|
val teamId = defaultLesson?.teamId ?: -1
|
||||||
|
val selectedLessonDate = defaultLesson?.date ?: Date.getToday()
|
||||||
|
|
||||||
|
when (teamId) {
|
||||||
|
-1L -> app.db.timetableDao().getNextWithSubject(profileId, selectedLessonDate, -item.id)
|
||||||
|
else -> app.db.timetableDao().getNextWithSubjectAndTeam(profileId, selectedLessonDate, -item.id, teamId)
|
||||||
|
}.observeOnce(activity, Observer {
|
||||||
val lessonDate = it?.displayDate ?: return@Observer
|
val lessonDate = it?.displayDate ?: return@Observer
|
||||||
b.dateDropdown.selected = TextInputDropDown.Item(
|
b.dateDropdown.select(TextInputDropDown.Item(
|
||||||
lessonDate.value.toLong(),
|
lessonDate.value.toLong(),
|
||||||
lessonDate.formattedString,
|
lessonDate.formattedString,
|
||||||
tag = lessonDate
|
tag = lessonDate
|
||||||
)
|
))
|
||||||
// TODO load correct hour when selecting next lesson
|
b.teamDropdown.select(it.displayTeamId)
|
||||||
b.dateDropdown.updateText()
|
b.subjectDropdown.select(it.displaySubjectId)
|
||||||
it.let {
|
b.teacherDropdown.select(it.displayTeacherId)
|
||||||
b.teamDropdown.select(it.displayTeamId)
|
|
||||||
b.subjectDropdown.select(it.displaySubjectId)
|
|
||||||
b.teacherDropdown.select(it.displayTeacherId)
|
|
||||||
}
|
|
||||||
defaultLoaded = false
|
defaultLoaded = false
|
||||||
loadHours()
|
loadHours(it.displayStartTime)
|
||||||
})
|
})
|
||||||
return@setOnChangeListener false
|
return@setOnChangeListener false
|
||||||
}
|
}
|
||||||
@ -239,17 +339,17 @@ class EventManualV2Dialog(
|
|||||||
item.id == -1L -> {
|
item.id == -1L -> {
|
||||||
MaterialDatePicker.Builder
|
MaterialDatePicker.Builder
|
||||||
.datePicker()
|
.datePicker()
|
||||||
.setSelection((b.dateDropdown.selectedId?.let { Date.fromValue(it.toInt()) } ?: Date.getToday()).inMillis)
|
.setSelection((b.dateDropdown.selectedId?.let { Date.fromValue(it.toInt()) }
|
||||||
|
?: Date.getToday()).inMillis)
|
||||||
.build()
|
.build()
|
||||||
.apply {
|
.apply {
|
||||||
addOnPositiveButtonClickListener {
|
addOnPositiveButtonClickListener {
|
||||||
val dateSelected = Date.fromMillis(it)
|
val dateSelected = Date.fromMillis(it)
|
||||||
b.dateDropdown.selected = TextInputDropDown.Item(
|
b.dateDropdown.select(TextInputDropDown.Item(
|
||||||
dateSelected.value.toLong(),
|
dateSelected.value.toLong(),
|
||||||
dateSelected.formattedString,
|
dateSelected.formattedString,
|
||||||
tag = dateSelected
|
tag = dateSelected
|
||||||
)
|
))
|
||||||
b.dateDropdown.updateText()
|
|
||||||
loadHours()
|
loadHours()
|
||||||
}
|
}
|
||||||
show(this@EventManualV2Dialog.activity.supportFragmentManager, "MaterialDatePicker")
|
show(this@EventManualV2Dialog.activity.supportFragmentManager, "MaterialDatePicker")
|
||||||
@ -269,7 +369,7 @@ class EventManualV2Dialog(
|
|||||||
loadHours()
|
loadHours()
|
||||||
}}
|
}}
|
||||||
|
|
||||||
private fun loadHours() {
|
private fun loadHours(defaultHour: Time? = null) {
|
||||||
b.timeDropdown.isEnabled = false
|
b.timeDropdown.isEnabled = false
|
||||||
// get the selected date
|
// get the selected date
|
||||||
val date = b.dateDropdown.selectedId?.let { Date.fromValue(it.toInt()) } ?: return
|
val date = b.dateDropdown.selectedId?.let { Date.fromValue(it.toInt()) } ?: return
|
||||||
@ -295,7 +395,8 @@ class EventManualV2Dialog(
|
|||||||
lesson.displayStartTime?.stringHM ?: "",
|
lesson.displayStartTime?.stringHM ?: "",
|
||||||
lesson.displaySubjectName?.let {
|
lesson.displaySubjectName?.let {
|
||||||
when {
|
when {
|
||||||
lesson.type == Lesson.TYPE_CANCELLED -> it.asStrikethroughSpannable()
|
lesson.type == Lesson.TYPE_CANCELLED
|
||||||
|
|| lesson.type == Lesson.TYPE_SHIFTED_SOURCE -> it.asStrikethroughSpannable()
|
||||||
lesson.type != Lesson.TYPE_NORMAL -> it.asItalicSpannable()
|
lesson.type != Lesson.TYPE_NORMAL -> it.asItalicSpannable()
|
||||||
else -> it
|
else -> it
|
||||||
}
|
}
|
||||||
@ -331,6 +432,10 @@ class EventManualV2Dialog(
|
|||||||
defaultLesson?.let {
|
defaultLesson?.let {
|
||||||
b.timeDropdown.select(it.displayStartTime?.value?.toLong())
|
b.timeDropdown.select(it.displayStartTime?.value?.toLong())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defaultHour?.let {
|
||||||
|
b.timeDropdown.select(it.value.toLong())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
defaultLoaded = true
|
defaultLoaded = true
|
||||||
b.timeDropdown.isEnabled = true
|
b.timeDropdown.isEnabled = true
|
||||||
@ -338,16 +443,16 @@ class EventManualV2Dialog(
|
|||||||
// attach a listener to time dropdown
|
// attach a listener to time dropdown
|
||||||
b.timeDropdown.setOnChangeListener { item ->
|
b.timeDropdown.setOnChangeListener { item ->
|
||||||
when {
|
when {
|
||||||
// custom start hour
|
|
||||||
item.id == -1L -> {
|
|
||||||
|
|
||||||
return@setOnChangeListener false
|
|
||||||
}
|
|
||||||
// no lessons this day
|
// no lessons this day
|
||||||
item.id == -2L -> {
|
item.id == -2L -> {
|
||||||
b.timeDropdown.deselect()
|
b.timeDropdown.deselect()
|
||||||
return@setOnChangeListener false
|
return@setOnChangeListener false
|
||||||
}
|
}
|
||||||
|
// custom start hour
|
||||||
|
item.id == -1L -> {
|
||||||
|
|
||||||
|
return@setOnChangeListener false
|
||||||
|
}
|
||||||
// selected a specific lesson
|
// selected a specific lesson
|
||||||
else -> {
|
else -> {
|
||||||
if (item.tag is LessonFull) {
|
if (item.tag is LessonFull) {
|
||||||
@ -376,4 +481,4 @@ class EventManualV2Dialog(
|
|||||||
private fun saveEvent() {
|
private fun saveEvent() {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2019-11-24.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.dialogs.home
|
||||||
|
|
||||||
|
import android.text.InputType
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||||
|
|
||||||
|
class StudentNumberDialog(
|
||||||
|
val activity: AppCompatActivity,
|
||||||
|
val profile: Profile,
|
||||||
|
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||||
|
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "StudentNumberDialog"
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var dialog: AlertDialog
|
||||||
|
|
||||||
|
init { run {
|
||||||
|
if (activity.isFinishing)
|
||||||
|
return@run
|
||||||
|
onShowListener?.invoke(TAG)
|
||||||
|
MaterialDialog.Builder(activity)
|
||||||
|
.title(R.string.card_lucky_number_set_title)
|
||||||
|
.content(R.string.card_lucky_number_set_text)
|
||||||
|
.inputType(InputType.TYPE_CLASS_NUMBER)
|
||||||
|
.input(null, if (profile.studentNumber == -1) "" else profile.studentNumber.toString()) { _: MaterialDialog?, input: CharSequence ->
|
||||||
|
try {
|
||||||
|
profile.studentNumber = input.toString().toInt()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Toast.makeText(activity, R.string.incorrect_format, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dismissListener {
|
||||||
|
onDismissListener?.invoke(TAG)
|
||||||
|
}.show()
|
||||||
|
}}
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2019-11-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.dialogs.settings
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import pl.szczodrzynski.edziennik.App
|
||||||
|
import pl.szczodrzynski.edziennik.MainActivity
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.databinding.DialogLessonDetailsBinding
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Notification
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
class ProfileRemoveDialog(
|
||||||
|
val activity: MainActivity,
|
||||||
|
val profileId: Int,
|
||||||
|
val profileName: String
|
||||||
|
) : CoroutineScope {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "ProfileRemoveDialog"
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var job: Job
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = job + Dispatchers.Main
|
||||||
|
|
||||||
|
private val app by lazy { activity.application as App }
|
||||||
|
private lateinit var b: DialogLessonDetailsBinding
|
||||||
|
private lateinit var dialog: AlertDialog
|
||||||
|
|
||||||
|
init { run {
|
||||||
|
job = Job()
|
||||||
|
|
||||||
|
dialog = MaterialAlertDialogBuilder(activity)
|
||||||
|
.setTitle(R.string.profile_menu_remove_confirm)
|
||||||
|
.setMessage(activity.getString(R.string.profile_menu_remove_confirm_text_format, profileName, profileName))
|
||||||
|
.setPositiveButton(R.string.remove) { _, _ ->
|
||||||
|
removeProfile()
|
||||||
|
}
|
||||||
|
.setNeutralButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
|
||||||
|
.setCancelable(false)
|
||||||
|
.show()
|
||||||
|
}}
|
||||||
|
|
||||||
|
private fun removeProfile() { launch {
|
||||||
|
val deferred = async(Dispatchers.Default) {
|
||||||
|
val profileObject = app.db.profileDao().getByIdNow(profileId) ?: return@async
|
||||||
|
app.db.announcementDao().clear(profileId)
|
||||||
|
app.db.attendanceDao().clear(profileId)
|
||||||
|
app.db.eventDao().clear(profileId)
|
||||||
|
app.db.eventTypeDao().clear(profileId)
|
||||||
|
app.db.gradeDao().clear(profileId)
|
||||||
|
app.db.gradeCategoryDao().clear(profileId)
|
||||||
|
app.db.lessonDao().clear(profileId)
|
||||||
|
app.db.lessonChangeDao().clear(profileId)
|
||||||
|
app.db.luckyNumberDao().clear(profileId)
|
||||||
|
app.db.noticeDao().clear(profileId)
|
||||||
|
app.db.subjectDao().clear(profileId)
|
||||||
|
app.db.teacherDao().clear(profileId)
|
||||||
|
app.db.teamDao().clear(profileId)
|
||||||
|
app.db.messageRecipientDao().clear(profileId)
|
||||||
|
app.db.messageDao().clear(profileId)
|
||||||
|
app.db.endpointTimerDao().clear(profileId)
|
||||||
|
app.db.attendanceTypeDao().clear(profileId)
|
||||||
|
app.db.classroomDao().clear(profileId)
|
||||||
|
app.db.lessonRangeDao().clear(profileId)
|
||||||
|
app.db.noticeTypeDao().clear(profileId)
|
||||||
|
app.db.teacherAbsenceDao().clear(profileId)
|
||||||
|
app.db.teacherAbsenceTypeDao().clear(profileId)
|
||||||
|
app.db.timetableDao().clear(profileId)
|
||||||
|
|
||||||
|
val loginStoreId = profileObject.loginStoreId
|
||||||
|
val profilesUsingLoginStore = app.db.profileDao().getIdsByLoginStoreIdNow(loginStoreId)
|
||||||
|
if (profilesUsingLoginStore.size == 1) {
|
||||||
|
app.db.loginStoreDao().remove(loginStoreId)
|
||||||
|
}
|
||||||
|
app.db.profileDao().remove(profileId)
|
||||||
|
app.db.metadataDao().deleteAll(profileId)
|
||||||
|
|
||||||
|
val toRemove = ArrayList<Notification>()
|
||||||
|
for (notification in app.appConfig.notifications) {
|
||||||
|
if (notification.profileId == profileId) {
|
||||||
|
toRemove.add(notification)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
app.appConfig.notifications.removeAll(toRemove)
|
||||||
|
|
||||||
|
app.profile = null
|
||||||
|
App.profileId = -1
|
||||||
|
|
||||||
|
app.profileLoadById(app.profileLastId())
|
||||||
|
}
|
||||||
|
deferred.await()
|
||||||
|
dialog.dismiss()
|
||||||
|
activity.reloadTarget()
|
||||||
|
Toast.makeText(activity, R.string.dialog_profile_remove_success, Toast.LENGTH_LONG).show()
|
||||||
|
}}
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2019-11-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.dialogs.sync
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import pl.szczodrzynski.edziennik.App
|
||||||
|
import pl.szczodrzynski.edziennik.MainActivity
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask
|
||||||
|
import pl.szczodrzynski.edziennik.databinding.DialogLessonDetailsBinding
|
||||||
|
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
class SyncViewListDialog(
|
||||||
|
val activity: MainActivity,
|
||||||
|
val currentViewId: Int? = null
|
||||||
|
) : CoroutineScope {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "SyncViewListDialog"
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var job: Job
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = job + Dispatchers.Main
|
||||||
|
|
||||||
|
private val app by lazy { activity.application as App }
|
||||||
|
private lateinit var b: DialogLessonDetailsBinding
|
||||||
|
private lateinit var dialog: AlertDialog
|
||||||
|
|
||||||
|
init { run {
|
||||||
|
job = Job()
|
||||||
|
|
||||||
|
val viewIds = arrayOf(
|
||||||
|
MainActivity.DRAWER_ITEM_TIMETABLE,
|
||||||
|
MainActivity.DRAWER_ITEM_AGENDA,
|
||||||
|
MainActivity.DRAWER_ITEM_GRADES,
|
||||||
|
MainActivity.DRAWER_ITEM_HOMEWORK,
|
||||||
|
MainActivity.DRAWER_ITEM_BEHAVIOUR,
|
||||||
|
MainActivity.DRAWER_ITEM_ATTENDANCE,
|
||||||
|
MainActivity.DRAWER_ITEM_MESSAGES,
|
||||||
|
MainActivity.DRAWER_ITEM_MESSAGES,
|
||||||
|
MainActivity.DRAWER_ITEM_ANNOUNCEMENTS
|
||||||
|
)
|
||||||
|
|
||||||
|
val items = arrayOf<String>(
|
||||||
|
app.getString(R.string.menu_timetable),
|
||||||
|
app.getString(R.string.menu_agenda),
|
||||||
|
app.getString(R.string.menu_grades),
|
||||||
|
app.getString(R.string.menu_homework),
|
||||||
|
app.getString(R.string.menu_notices),
|
||||||
|
app.getString(R.string.menu_attendance),
|
||||||
|
app.getString(R.string.title_messages_inbox_single),
|
||||||
|
app.getString(R.string.title_messages_sent_single),
|
||||||
|
app.getString(R.string.menu_announcements)
|
||||||
|
)
|
||||||
|
|
||||||
|
val everything = currentViewId == MainActivity.DRAWER_ITEM_HOME
|
||||||
|
val checkedItems = booleanArrayOf(
|
||||||
|
everything || currentViewId == MainActivity.DRAWER_ITEM_TIMETABLE,
|
||||||
|
everything || currentViewId == MainActivity.DRAWER_ITEM_AGENDA,
|
||||||
|
everything || currentViewId == MainActivity.DRAWER_ITEM_GRADES,
|
||||||
|
everything || currentViewId == MainActivity.DRAWER_ITEM_HOMEWORK,
|
||||||
|
everything || currentViewId == MainActivity.DRAWER_ITEM_BEHAVIOUR,
|
||||||
|
everything || currentViewId == MainActivity.DRAWER_ITEM_ATTENDANCE,
|
||||||
|
everything || currentViewId == MainActivity.DRAWER_ITEM_MESSAGES && MessagesFragment.pageSelection != 1,
|
||||||
|
everything || currentViewId == MainActivity.DRAWER_ITEM_MESSAGES && MessagesFragment.pageSelection == 1,
|
||||||
|
everything || currentViewId == MainActivity.DRAWER_ITEM_ANNOUNCEMENTS
|
||||||
|
)
|
||||||
|
val userChooses = checkedItems.toMutableList()
|
||||||
|
|
||||||
|
dialog = MaterialAlertDialogBuilder(activity)
|
||||||
|
.setTitle(R.string.dialog_sync_view_list_title)
|
||||||
|
.setMultiChoiceItems(items, checkedItems) { _, which, isChecked ->
|
||||||
|
userChooses[which] = isChecked
|
||||||
|
}
|
||||||
|
.setPositiveButton(R.string.ok) { _, _ ->
|
||||||
|
dialog.dismiss()
|
||||||
|
|
||||||
|
val selectedViewIds = userChooses.mapIndexed { index, it ->
|
||||||
|
if (it)
|
||||||
|
viewIds[index] to when (index) {
|
||||||
|
7 -> 1
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
else
|
||||||
|
null
|
||||||
|
}.let {
|
||||||
|
listOfNotNull(*it.toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedViewIds.isNotEmpty()) {
|
||||||
|
activity.swipeRefreshLayout.isRefreshing = true
|
||||||
|
EdziennikTask.syncProfile(
|
||||||
|
App.profileId,
|
||||||
|
selectedViewIds
|
||||||
|
).enqueue(activity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.setNeutralButton(R.string.sync_feature_all) { _, _ ->
|
||||||
|
dialog.dismiss()
|
||||||
|
|
||||||
|
activity.swipeRefreshLayout.isRefreshing = true
|
||||||
|
EdziennikTask.syncProfile(App.profileId).enqueue(activity)
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.cancel) { _, _ ->
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
}}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user