mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-06-15 07:00:20 +02:00
Compare commits
63 Commits
v3.9.5-dev
...
v3.9.11-de
Author | SHA1 | Date | |
---|---|---|---|
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()
|
||||||
|
@ -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,9 +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.edziennik.utils.models.Time
|
||||||
import pl.szczodrzynski.navlib.R
|
import pl.szczodrzynski.navlib.R
|
||||||
import pl.szczodrzynski.navlib.getColorFromRes
|
import pl.szczodrzynski.navlib.getColorFromRes
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
@ -95,6 +103,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 +170,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 {
|
||||||
@ -404,15 +422,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 +446,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 +460,76 @@ 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)
|
||||||
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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()
|
||||||
|
@ -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("login")
|
||||||
|
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,17 @@ 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
|
||||||
|
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()
|
||||||
|
@ -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)"
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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,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")
|
||||||
|
@ -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,22 @@ 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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,6 +82,55 @@ open class Lesson(val profileId: Int, @PrimaryKey val id: Long) {
|
|||||||
"oldTeamId=$oldTeamId, " +
|
"oldTeamId=$oldTeamId, " +
|
||||||
"oldClassroom=$oldClassroom)"
|
"oldClassroom=$oldClassroom)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (other !is Lesson) return false
|
||||||
|
|
||||||
|
if (profileId != other.profileId) return false
|
||||||
|
if (id != other.id) return false
|
||||||
|
if (type != other.type) return false
|
||||||
|
if (date != other.date) return false
|
||||||
|
if (lessonNumber != other.lessonNumber) return false
|
||||||
|
if (startTime != other.startTime) return false
|
||||||
|
if (endTime != other.endTime) return false
|
||||||
|
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
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
DROP TABLE lessons;
|
DROP TABLE lessons;
|
||||||
@ -94,4 +159,4 @@ CREATE TABLE lessons (
|
|||||||
|
|
||||||
PRIMARY KEY(profileId)
|
PRIMARY KEY(profileId)
|
||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
|
@ -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,60 @@ 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.*,
|
|
||||||
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 > :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()
|
||||||
|
}}
|
||||||
|
}
|
@ -21,7 +21,9 @@ import pl.szczodrzynski.edziennik.utils.models.Week
|
|||||||
|
|
||||||
class LessonDetailsDialog(
|
class LessonDetailsDialog(
|
||||||
val activity: AppCompatActivity,
|
val activity: AppCompatActivity,
|
||||||
val lesson: LessonFull
|
val lesson: LessonFull,
|
||||||
|
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||||
|
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "LessonDetailsDialog"
|
private const val TAG = "LessonDetailsDialog"
|
||||||
@ -31,6 +33,9 @@ class LessonDetailsDialog(
|
|||||||
private lateinit var dialog: AlertDialog
|
private lateinit var dialog: AlertDialog
|
||||||
|
|
||||||
init { run {
|
init { run {
|
||||||
|
if (activity.isFinishing)
|
||||||
|
return@run
|
||||||
|
onShowListener?.invoke(TAG)
|
||||||
b = DialogLessonDetailsBinding.inflate(activity.layoutInflater)
|
b = DialogLessonDetailsBinding.inflate(activity.layoutInflater)
|
||||||
dialog = MaterialAlertDialogBuilder(activity)
|
dialog = MaterialAlertDialogBuilder(activity)
|
||||||
.setView(b.root)
|
.setView(b.root)
|
||||||
@ -38,8 +43,13 @@ class LessonDetailsDialog(
|
|||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}
|
}
|
||||||
.setNeutralButton(R.string.add) { dialog, _ ->
|
.setNeutralButton(R.string.add) { dialog, _ ->
|
||||||
dialog.dismiss()
|
EventManualV2Dialog(
|
||||||
EventManualV2Dialog(activity, lesson.profileId, lesson)
|
activity,
|
||||||
|
lesson.profileId,
|
||||||
|
lesson,
|
||||||
|
onShowListener = onShowListener,
|
||||||
|
onDismissListener = onDismissListener
|
||||||
|
)
|
||||||
/*MaterialAlertDialogBuilder(activity)
|
/*MaterialAlertDialogBuilder(activity)
|
||||||
.setItems(R.array.main_menu_add_options) { dialog2, which ->
|
.setItems(R.array.main_menu_add_options) { dialog2, which ->
|
||||||
dialog2.dismiss()
|
dialog2.dismiss()
|
||||||
@ -59,6 +69,9 @@ class LessonDetailsDialog(
|
|||||||
.setNegativeButton(R.string.cancel) { dialog2, _ -> dialog2.dismiss() }
|
.setNegativeButton(R.string.cancel) { dialog2, _ -> dialog2.dismiss() }
|
||||||
.show()*/
|
.show()*/
|
||||||
}
|
}
|
||||||
|
.setOnDismissListener {
|
||||||
|
onDismissListener?.invoke(TAG)
|
||||||
|
}
|
||||||
.show()
|
.show()
|
||||||
update()
|
update()
|
||||||
}}
|
}}
|
||||||
@ -107,7 +120,7 @@ class LessonDetailsDialog(
|
|||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
val dateStr = otherLessonDate?.stringY_m_d ?: return@setOnClickListener
|
val dateStr = otherLessonDate?.stringY_m_d ?: return@setOnClickListener
|
||||||
val intent = Intent(TimetableFragment.ACTION_SCROLL_TO_DATE).apply {
|
val intent = Intent(TimetableFragment.ACTION_SCROLL_TO_DATE).apply {
|
||||||
putExtra("date", dateStr)
|
putExtra("timetableDate", dateStr)
|
||||||
}
|
}
|
||||||
activity.sendBroadcast(intent)
|
activity.sendBroadcast(intent)
|
||||||
}
|
}
|
||||||
@ -119,29 +132,29 @@ class LessonDetailsDialog(
|
|||||||
if (lesson.type < Lesson.TYPE_SHIFTED_SOURCE && lesson.oldSubjectId != null && lesson.subjectId != lesson.oldSubjectId) {
|
if (lesson.type < Lesson.TYPE_SHIFTED_SOURCE && lesson.oldSubjectId != null && lesson.subjectId != lesson.oldSubjectId) {
|
||||||
b.oldSubjectName = lesson.oldSubjectName
|
b.oldSubjectName = lesson.oldSubjectName
|
||||||
}
|
}
|
||||||
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.subjectId != null) {
|
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.displaySubjectId != null) {
|
||||||
b.subjectName = lesson.subjectName
|
b.subjectName = lesson.subjectName
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lesson.type < Lesson.TYPE_SHIFTED_SOURCE && lesson.oldTeacherId != null && lesson.teacherId != lesson.oldTeacherId) {
|
if (lesson.type < Lesson.TYPE_SHIFTED_SOURCE && lesson.oldTeacherId != null && lesson.teacherId != lesson.oldTeacherId) {
|
||||||
b.oldTeacherName = lesson.oldTeacherName
|
b.oldTeacherName = lesson.oldTeacherName
|
||||||
}
|
}
|
||||||
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.teacherId != null) {
|
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.displayTeacherId != null) {
|
||||||
b.teacherName = lesson.teacherName
|
b.teacherName = lesson.teacherName
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lesson.oldClassroom != null && lesson.classroom != lesson.oldClassroom) {
|
if (lesson.oldClassroom != null && lesson.classroom != lesson.oldClassroom) {
|
||||||
b.oldClassroom = lesson.oldClassroom
|
b.oldClassroom = lesson.oldClassroom
|
||||||
}
|
}
|
||||||
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.classroom != null) {
|
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.displayClassroom != null) {
|
||||||
b.classroom = lesson.classroom
|
b.classroom = lesson.classroom
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lesson.type < Lesson.TYPE_SHIFTED_SOURCE && lesson.oldTeamId != null && lesson.teamId != lesson.oldTeamId) {
|
if (lesson.type < Lesson.TYPE_SHIFTED_SOURCE && lesson.oldTeamId != null && lesson.teamId != lesson.oldTeamId) {
|
||||||
b.oldTeamName = lesson.oldTeamName
|
b.oldTeamName = lesson.oldTeamName
|
||||||
}
|
}
|
||||||
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.teamId != null) {
|
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.displayTeamId != null) {
|
||||||
b.teamName = lesson.teamName
|
b.teamName = lesson.teamName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,15 +6,16 @@ import android.graphics.drawable.Drawable;
|
|||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.databinding.DataBindingUtil;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.databinding.DataBindingUtil;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.afollestad.materialdialogs.MaterialDialog;
|
import com.afollestad.materialdialogs.MaterialDialog;
|
||||||
import com.applandeo.materialcalendarview.CalendarView;
|
import com.applandeo.materialcalendarview.CalendarView;
|
||||||
import com.applandeo.materialcalendarview.EventDay;
|
import com.applandeo.materialcalendarview.EventDay;
|
||||||
@ -27,6 +28,7 @@ import com.mikepenz.iconics.IconicsColor;
|
|||||||
import com.mikepenz.iconics.IconicsDrawable;
|
import com.mikepenz.iconics.IconicsDrawable;
|
||||||
import com.mikepenz.iconics.IconicsSize;
|
import com.mikepenz.iconics.IconicsSize;
|
||||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
||||||
|
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
@ -34,13 +36,13 @@ import java.util.List;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.App;
|
import pl.szczodrzynski.edziennik.App;
|
||||||
import pl.szczodrzynski.edziennik.R;
|
|
||||||
import pl.szczodrzynski.edziennik.MainActivity;
|
import pl.szczodrzynski.edziennik.MainActivity;
|
||||||
|
import pl.szczodrzynski.edziennik.R;
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull;
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.TeacherAbsenceFull;
|
import pl.szczodrzynski.edziennik.data.db.modules.teachers.TeacherAbsenceFull;
|
||||||
import pl.szczodrzynski.edziennik.databinding.FragmentAgendaCalendarBinding;
|
import pl.szczodrzynski.edziennik.databinding.FragmentAgendaCalendarBinding;
|
||||||
import pl.szczodrzynski.edziennik.databinding.FragmentAgendaDefaultBinding;
|
import pl.szczodrzynski.edziennik.databinding.FragmentAgendaDefaultBinding;
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventListDialog;
|
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventListDialog;
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog;
|
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog;
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.lessonchange.LessonChangeDialog;
|
import pl.szczodrzynski.edziennik.ui.dialogs.lessonchange.LessonChangeDialog;
|
||||||
@ -51,11 +53,11 @@ import pl.szczodrzynski.edziennik.ui.modules.agenda.lessonchange.LessonChangeEve
|
|||||||
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceCounter;
|
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceCounter;
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceEvent;
|
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceEvent;
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceEventRenderer;
|
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceEventRenderer;
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Colors;
|
import pl.szczodrzynski.edziennik.utils.Colors;
|
||||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem;
|
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem;
|
||||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem;
|
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem;
|
||||||
|
|
||||||
@ -102,7 +104,7 @@ public class AgendaFragment extends Fragment {
|
|||||||
new BottomSheetPrimaryItem(true)
|
new BottomSheetPrimaryItem(true)
|
||||||
.withTitle(R.string.menu_add_event)
|
.withTitle(R.string.menu_add_event)
|
||||||
.withDescription(R.string.menu_add_event_desc)
|
.withDescription(R.string.menu_add_event_desc)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_calendar_plus)
|
.withIcon(SzkolnyFont.Icon.szf_calendar_plus_outline)
|
||||||
.withOnClickListener(v3 -> {
|
.withOnClickListener(v3 -> {
|
||||||
activity.getBottomSheet().close();
|
activity.getBottomSheet().close();
|
||||||
new MaterialDialog.Builder(activity)
|
new MaterialDialog.Builder(activity)
|
||||||
@ -122,7 +124,7 @@ public class AgendaFragment extends Fragment {
|
|||||||
}),
|
}),
|
||||||
new BottomSheetPrimaryItem(true)
|
new BottomSheetPrimaryItem(true)
|
||||||
.withTitle(R.string.menu_agenda_change_view)
|
.withTitle(R.string.menu_agenda_change_view)
|
||||||
.withIcon(viewType == AGENDA_DEFAULT ? CommunityMaterial.Icon.cmd_calendar : CommunityMaterial.Icon2.cmd_view_list)
|
.withIcon(viewType == AGENDA_DEFAULT ? CommunityMaterial.Icon.cmd_calendar_outline : CommunityMaterial.Icon.cmd_format_list_bulleted_square)
|
||||||
.withOnClickListener(v3 -> {
|
.withOnClickListener(v3 -> {
|
||||||
activity.getBottomSheet().close();
|
activity.getBottomSheet().close();
|
||||||
viewType = viewType == AGENDA_DEFAULT ? AGENDA_CALENDAR : AGENDA_DEFAULT;
|
viewType = viewType == AGENDA_DEFAULT ? AGENDA_CALENDAR : AGENDA_DEFAULT;
|
||||||
@ -133,7 +135,7 @@ public class AgendaFragment extends Fragment {
|
|||||||
new BottomSheetSeparatorItem(true),
|
new BottomSheetSeparatorItem(true),
|
||||||
new BottomSheetPrimaryItem(true)
|
new BottomSheetPrimaryItem(true)
|
||||||
.withTitle(R.string.menu_mark_as_read)
|
.withTitle(R.string.menu_mark_as_read)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||||
.withOnClickListener(v3 -> {
|
.withOnClickListener(v3 -> {
|
||||||
activity.getBottomSheet().close();
|
activity.getBottomSheet().close();
|
||||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_EVENT, true));
|
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_EVENT, true));
|
||||||
|
@ -58,7 +58,7 @@ public class AnnouncementsFragment extends Fragment {
|
|||||||
activity.getBottomSheet().prependItems(
|
activity.getBottomSheet().prependItems(
|
||||||
new BottomSheetPrimaryItem(true)
|
new BottomSheetPrimaryItem(true)
|
||||||
.withTitle(R.string.menu_mark_as_read)
|
.withTitle(R.string.menu_mark_as_read)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||||
.withOnClickListener(v3 -> {
|
.withOnClickListener(v3 -> {
|
||||||
activity.getBottomSheet().close();
|
activity.getBottomSheet().close();
|
||||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_ANNOUNCEMENT, true));
|
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_ANNOUNCEMENT, true));
|
||||||
|
@ -95,7 +95,7 @@ public class AttendanceFragment extends Fragment {
|
|||||||
activity.getBottomSheet().prependItems(
|
activity.getBottomSheet().prependItems(
|
||||||
new BottomSheetPrimaryItem(true)
|
new BottomSheetPrimaryItem(true)
|
||||||
.withTitle(R.string.menu_mark_as_read)
|
.withTitle(R.string.menu_mark_as_read)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||||
.withOnClickListener(v3 -> {
|
.withOnClickListener(v3 -> {
|
||||||
activity.getBottomSheet().close();
|
activity.getBottomSheet().close();
|
||||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_ATTENDANCE, true));
|
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_ATTENDANCE, true));
|
||||||
@ -133,7 +133,7 @@ public class AttendanceFragment extends Fragment {
|
|||||||
CafeBar.builder(activity)
|
CafeBar.builder(activity)
|
||||||
.to(activity.getNavView().getCoordinator())
|
.to(activity.getNavView().getCoordinator())
|
||||||
.content(R.string.sync_old_data_info)
|
.content(R.string.sync_old_data_info)
|
||||||
.icon(new IconicsDrawable(activity).icon(CommunityMaterial.Icon2.cmd_sync).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.INSTANCE.getPrimaryTextColor(activity))))
|
.icon(new IconicsDrawable(activity).icon(CommunityMaterial.Icon.cmd_download_outline).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.INSTANCE.getPrimaryTextColor(activity))))
|
||||||
.positiveText(R.string.refresh)
|
.positiveText(R.string.refresh)
|
||||||
.positiveColor(0xff4caf50)
|
.positiveColor(0xff4caf50)
|
||||||
.negativeText(R.string.ok)
|
.negativeText(R.string.ok)
|
||||||
|
@ -69,7 +69,7 @@ public class BehaviourFragment extends Fragment {
|
|||||||
activity.getBottomSheet().prependItems(
|
activity.getBottomSheet().prependItems(
|
||||||
new BottomSheetPrimaryItem(true)
|
new BottomSheetPrimaryItem(true)
|
||||||
.withTitle(R.string.menu_mark_as_read)
|
.withTitle(R.string.menu_mark_as_read)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||||
.withOnClickListener(v3 -> {
|
.withOnClickListener(v3 -> {
|
||||||
activity.getBottomSheet().close();
|
activity.getBottomSheet().close();
|
||||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_NOTICE, true));
|
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_NOTICE, true));
|
||||||
|
@ -9,21 +9,20 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
|
||||||
import com.mikepenz.iconics.IconicsDrawable
|
|
||||||
import androidx.cardview.widget.CardView
|
import androidx.cardview.widget.CardView
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.mikepenz.iconics.IconicsDrawable
|
||||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||||
|
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
|
||||||
import com.mikepenz.iconics.utils.colorRes
|
import com.mikepenz.iconics.utils.colorRes
|
||||||
import com.mikepenz.iconics.utils.sizeDp
|
import com.mikepenz.iconics.utils.sizeDp
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_MOBIDZIENNIK
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice
|
import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.notices.NoticeFull
|
import pl.szczodrzynski.edziennik.data.db.modules.notices.NoticeFull
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_MOBIDZIENNIK
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.bs
|
import pl.szczodrzynski.edziennik.utils.Utils.bs
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
class NoticesAdapter//getting the context and product list with constructor
|
class NoticesAdapter//getting the context and product list with constructor
|
||||||
(private val context: Context, var noticeList: List<NoticeFull>) : RecyclerView.Adapter<NoticesAdapter.ViewHolder>() {
|
(private val context: Context, var noticeList: List<NoticeFull>) : RecyclerView.Adapter<NoticesAdapter.ViewHolder>() {
|
||||||
@ -50,15 +49,15 @@ class NoticesAdapter//getting the context and product list with constructor
|
|||||||
holder.noticesItemAddedDate.text = Date.fromMillis(notice.addedDate).formattedString
|
holder.noticesItemAddedDate.text = Date.fromMillis(notice.addedDate).formattedString
|
||||||
|
|
||||||
if (notice.type == Notice.TYPE_POSITIVE) {
|
if (notice.type == Notice.TYPE_POSITIVE) {
|
||||||
holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon2.cmd_plus_circle)
|
holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon2.cmd_plus_circle_outline)
|
||||||
.colorRes(R.color.md_green_600)
|
.colorRes(R.color.md_green_600)
|
||||||
.sizeDp(36))
|
.sizeDp(36))
|
||||||
} else if (notice.type == Notice.TYPE_NEGATIVE) {
|
} else if (notice.type == Notice.TYPE_NEGATIVE) {
|
||||||
holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon.cmd_alert_decagram)
|
holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon.cmd_alert_decagram_outline)
|
||||||
.colorRes(R.color.md_red_600)
|
.colorRes(R.color.md_red_600)
|
||||||
.sizeDp(36))
|
.sizeDp(36))
|
||||||
} else {
|
} else {
|
||||||
holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon2.cmd_message_outline)
|
holder.noticesItemType.setImageDrawable(IconicsDrawable(context, SzkolnyFont.Icon.szf_message_processing_outline)
|
||||||
.colorRes(R.color.md_blue_500)
|
.colorRes(R.color.md_blue_500)
|
||||||
.sizeDp(36))
|
.sizeDp(36))
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2019-11-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.modules.error
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
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.R
|
||||||
|
import pl.szczodrzynski.edziennik.databinding.DialogLessonDetailsBinding
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
class ErrorDialog(
|
||||||
|
val activity: AppCompatActivity,
|
||||||
|
val exception: Exception
|
||||||
|
) : CoroutineScope {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "ErrorDialog"
|
||||||
|
}
|
||||||
|
|
||||||
|
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.error_occured)
|
||||||
|
.setMessage(exception.message + "\n" + Log.getStackTraceString(exception))
|
||||||
|
.setPositiveButton(R.string.ok) { _, _ ->
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
}}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2019-11-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.modules.error
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
import androidx.core.graphics.ColorUtils
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||||
|
import pl.szczodrzynski.navlib.getColorFromAttr
|
||||||
|
|
||||||
|
class ErrorSnackbar(val activity: AppCompatActivity) {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "ErrorSnackbar"
|
||||||
|
}
|
||||||
|
|
||||||
|
private var snackbar: Snackbar? = null
|
||||||
|
private lateinit var coordinator: CoordinatorLayout
|
||||||
|
private val errors = mutableListOf<ApiError>()
|
||||||
|
|
||||||
|
fun setCoordinator(coordinatorLayout: CoordinatorLayout, showAbove: View? = null) {
|
||||||
|
this.coordinator = coordinatorLayout
|
||||||
|
snackbar = Snackbar.make(coordinator, R.string.snackbar_error_text, Snackbar.LENGTH_INDEFINITE)
|
||||||
|
snackbar?.setAction(R.string.more) {
|
||||||
|
|
||||||
|
}
|
||||||
|
val bgColor = ColorUtils.compositeColors(
|
||||||
|
getColorFromAttr(activity, R.attr.colorOnSurface) and 0xcfffffff.toInt(),
|
||||||
|
getColorFromAttr(activity, R.attr.colorSurface)
|
||||||
|
)
|
||||||
|
snackbar?.setBackgroundTint(bgColor)
|
||||||
|
showAbove?.let { snackbar?.anchorView = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addError(apiError: ApiError): ErrorSnackbar {
|
||||||
|
errors += apiError
|
||||||
|
snackbar?.setText(apiError.getStringReason(activity))
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun show() = snackbar?.show()
|
||||||
|
fun dismiss() = snackbar?.dismiss()
|
||||||
|
}
|
@ -132,7 +132,7 @@ public class GradesFragment extends Fragment {
|
|||||||
}),
|
}),
|
||||||
new BottomSheetPrimaryItem(true)
|
new BottomSheetPrimaryItem(true)
|
||||||
.withTitle(R.string.menu_grades_color_mode)
|
.withTitle(R.string.menu_grades_color_mode)
|
||||||
.withIcon(CommunityMaterial.Icon2.cmd_palette)
|
.withIcon(CommunityMaterial.Icon2.cmd_palette_outline)
|
||||||
.withOnClickListener(v3 -> {
|
.withOnClickListener(v3 -> {
|
||||||
activity.getBottomSheet().close();
|
activity.getBottomSheet().close();
|
||||||
new MaterialDialog.Builder(activity)
|
new MaterialDialog.Builder(activity)
|
||||||
@ -195,7 +195,7 @@ public class GradesFragment extends Fragment {
|
|||||||
new BottomSheetSeparatorItem(true),
|
new BottomSheetSeparatorItem(true),
|
||||||
new BottomSheetPrimaryItem(true)
|
new BottomSheetPrimaryItem(true)
|
||||||
.withTitle(R.string.menu_mark_as_read)
|
.withTitle(R.string.menu_mark_as_read)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||||
.withOnClickListener(v3 -> {
|
.withOnClickListener(v3 -> {
|
||||||
activity.getBottomSheet().close();
|
activity.getBottomSheet().close();
|
||||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_GRADE, true));
|
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_GRADE, true));
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2019-11-23.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.modules.home
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.google.android.material.card.MaterialCardView
|
||||||
|
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragmentV2.Companion.swapCards
|
||||||
|
import pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoIndicator
|
||||||
|
|
||||||
|
class CardItemTouchHelperCallback(private val cardAdapter: HomeCardAdapter, private val refreshLayout: SwipeRefreshLayoutNoIndicator?) : ItemTouchHelper.Callback() {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "CardItemTouchHelperCallback"
|
||||||
|
private const val DRAG_FLAGS = ItemTouchHelper.UP or ItemTouchHelper.DOWN
|
||||||
|
private const val SWIPE_FLAGS = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
private var dragCardView: MaterialCardView? = null
|
||||||
|
|
||||||
|
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
|
||||||
|
return makeMovementFlags(DRAG_FLAGS, SWIPE_FLAGS)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
|
||||||
|
val fromPosition = viewHolder.adapterPosition
|
||||||
|
val toPosition = target.adapterPosition
|
||||||
|
|
||||||
|
swapCards(fromPosition, toPosition, cardAdapter)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) = Unit
|
||||||
|
|
||||||
|
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
|
||||||
|
super.onSelectedChanged(viewHolder, actionState)
|
||||||
|
|
||||||
|
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG && viewHolder != null) {
|
||||||
|
dragCardView = viewHolder.itemView as MaterialCardView
|
||||||
|
dragCardView?.isDragged = true
|
||||||
|
refreshLayout?.isEnabled = false
|
||||||
|
} else if (actionState == ItemTouchHelper.ACTION_STATE_IDLE && dragCardView != null) {
|
||||||
|
refreshLayout?.isEnabled = true
|
||||||
|
dragCardView?.isDragged = false
|
||||||
|
dragCardView = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,12 @@
|
|||||||
package pl.szczodrzynski.edziennik.ui.modules.home;
|
package pl.szczodrzynski.edziennik.ui.modules.home;
|
||||||
|
|
||||||
import androidx.databinding.DataBindingUtil;
|
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import android.util.Log;
|
import androidx.databinding.DataBindingUtil;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -14,8 +15,8 @@ import java.util.TimerTask;
|
|||||||
|
|
||||||
import pl.szczodrzynski.edziennik.App;
|
import pl.szczodrzynski.edziennik.App;
|
||||||
import pl.szczodrzynski.edziennik.R;
|
import pl.szczodrzynski.edziennik.R;
|
||||||
import pl.szczodrzynski.edziennik.databinding.ActivityCounterBinding;
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
||||||
|
import pl.szczodrzynski.edziennik.databinding.ActivityCounterBinding;
|
||||||
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;
|
||||||
|
|
||||||
@ -88,7 +89,7 @@ public class CounterActivity extends AppCompatActivity {
|
|||||||
private void findLessons(Time syncedNow) {
|
private void findLessons(Time syncedNow) {
|
||||||
AsyncTask.execute(() -> {
|
AsyncTask.execute(() -> {
|
||||||
Date today = Date.getToday();
|
Date today = Date.getToday();
|
||||||
lessons = app.db.lessonDao().getAllNearestNow(App.profileId, today.clone().stepForward(0, 0, -today.getWeekDay()), today, syncedNow);
|
lessons = app.db.lessonDao().getAllNearestNow(App.profileId, today.getWeekStart(), today, syncedNow);
|
||||||
|
|
||||||
if (lessons != null && lessons.size() != 0) {
|
if (lessons != null && lessons.size() != 0) {
|
||||||
Date displayingDate = lessons.get(0).lessonDate;
|
Date displayingDate = lessons.get(0).lessonDate;
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2019-11-23.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.modules.home
|
||||||
|
|
||||||
|
interface HomeCard {
|
||||||
|
fun bind(position: Int, holder: HomeCardAdapter.ViewHolder)
|
||||||
|
fun unbind(position: Int, holder: HomeCardAdapter.ViewHolder)
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2019-11-23.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.modules.home
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.google.android.material.card.MaterialCardView
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
|
||||||
|
class HomeCardAdapter(var items: MutableList<HomeCard>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "HomeCardAdapter"
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemTouchHelper: ItemTouchHelper? = null
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
(holder as ViewHolder).bind(itemTouchHelper)
|
||||||
|
items[position].bind(position, holder)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
|
||||||
|
items.getOrNull(holder.adapterPosition)?.unbind(holder.adapterPosition, holder as ViewHolder)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
|
return ViewHolder(
|
||||||
|
LayoutInflater.from(parent.context).inflate(R.layout.card_home, parent, false) as MaterialCardView
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = items.size
|
||||||
|
|
||||||
|
class ViewHolder(val root: MaterialCardView) : RecyclerView.ViewHolder(root) {
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
fun bind(itemTouchHelper: ItemTouchHelper?) {
|
||||||
|
/*root.setOnTouchListener { _: View?, event: MotionEvent ->
|
||||||
|
if (event.action == MotionEvent.ACTION_DOWN) {
|
||||||
|
itemTouchHelper?.startDrag(this)
|
||||||
|
return@setOnTouchListener true
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2019-11-23.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.modules.home
|
||||||
|
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.core.view.plusAssign
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import pl.szczodrzynski.edziennik.App
|
||||||
|
import pl.szczodrzynski.edziennik.MainActivity
|
||||||
|
import pl.szczodrzynski.edziennik.startCoroutineTimer
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
class HomeDummyCard(val id: Int) : HomeCard, CoroutineScope {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "HomeDummyCard"
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var app: App
|
||||||
|
private lateinit var activity: MainActivity
|
||||||
|
|
||||||
|
private var job: Job = Job()
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = job + Dispatchers.Main
|
||||||
|
|
||||||
|
var timer: Job? = null
|
||||||
|
var time = 0
|
||||||
|
|
||||||
|
override fun bind(position: Int, holder: HomeCardAdapter.ViewHolder) { launch {
|
||||||
|
holder.root.removeAllViews()
|
||||||
|
//holder.setIsRecyclable(false)
|
||||||
|
|
||||||
|
val text = TextView(holder.root.context).apply {
|
||||||
|
text = "This is a card #$id"
|
||||||
|
}
|
||||||
|
holder.root += text
|
||||||
|
|
||||||
|
timer = startCoroutineTimer(repeatMillis = 1000) {
|
||||||
|
time++
|
||||||
|
text.text = "Coroutine timer at #$id! $time seconds"
|
||||||
|
}
|
||||||
|
|
||||||
|
/*val button = MaterialButton(holder.root.context).apply {
|
||||||
|
setText("Cancel")
|
||||||
|
onClick {
|
||||||
|
timer.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
holder.root += button*/
|
||||||
|
}}
|
||||||
|
|
||||||
|
override fun unbind(position: Int, holder: HomeCardAdapter.ViewHolder) {
|
||||||
|
timer?.cancel()
|
||||||
|
timer = null
|
||||||
|
}
|
||||||
|
}
|
@ -37,6 +37,7 @@ import com.mikepenz.iconics.IconicsColor;
|
|||||||
import com.mikepenz.iconics.IconicsDrawable;
|
import com.mikepenz.iconics.IconicsDrawable;
|
||||||
import com.mikepenz.iconics.IconicsSize;
|
import com.mikepenz.iconics.IconicsSize;
|
||||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
||||||
|
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -268,7 +269,7 @@ public class HomeFragment extends Fragment {
|
|||||||
activity.getBottomSheet().prependItems(
|
activity.getBottomSheet().prependItems(
|
||||||
new BottomSheetPrimaryItem(true)
|
new BottomSheetPrimaryItem(true)
|
||||||
.withTitle(R.string.menu_set_student_number)
|
.withTitle(R.string.menu_set_student_number)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_counter)
|
.withIcon(SzkolnyFont.Icon.szf_clipboard_list_outline)
|
||||||
.withOnClickListener(v3 -> {
|
.withOnClickListener(v3 -> {
|
||||||
activity.getBottomSheet().close();
|
activity.getBottomSheet().close();
|
||||||
setNumberDialog();
|
setNumberDialog();
|
||||||
@ -276,7 +277,7 @@ public class HomeFragment extends Fragment {
|
|||||||
new BottomSheetSeparatorItem(true),
|
new BottomSheetSeparatorItem(true),
|
||||||
new BottomSheetPrimaryItem(true)
|
new BottomSheetPrimaryItem(true)
|
||||||
.withTitle(R.string.menu_mark_everything_as_read)
|
.withTitle(R.string.menu_mark_everything_as_read)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||||
.withOnClickListener(v3 -> {
|
.withOnClickListener(v3 -> {
|
||||||
activity.getBottomSheet().close();
|
activity.getBottomSheet().close();
|
||||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, true));
|
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, true));
|
||||||
|
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2019-11-23.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.modules.home
|
||||||
|
|
||||||
|
import android.os.AsyncTask
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.View.OnClickListener
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.core.view.AccessibilityDelegateCompat
|
||||||
|
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
|
||||||
|
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate
|
||||||
|
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial.Icon
|
||||||
|
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
|
||||||
|
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.databinding.FragmentHomeV2Binding
|
||||||
|
import pl.szczodrzynski.edziennik.ui.dialogs.home.StudentNumberDialog
|
||||||
|
import pl.szczodrzynski.edziennik.ui.modules.home.cards.HomeLuckyNumberCard
|
||||||
|
import pl.szczodrzynski.edziennik.ui.modules.home.cards.HomeTimetableCard
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Themes
|
||||||
|
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
||||||
|
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
class HomeFragmentV2 : Fragment(), CoroutineScope {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "HomeFragment"
|
||||||
|
|
||||||
|
fun swapCards(fromPosition: Int, toPosition: Int, cardAdapter: HomeCardAdapter) {
|
||||||
|
val fromCard = cardAdapter.items[fromPosition]
|
||||||
|
cardAdapter.items[fromPosition] = cardAdapter.items[toPosition]
|
||||||
|
cardAdapter.items[toPosition] = fromCard
|
||||||
|
cardAdapter.notifyItemMoved(fromPosition, toPosition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var app: App
|
||||||
|
private lateinit var activity: MainActivity
|
||||||
|
private lateinit var b: FragmentHomeV2Binding
|
||||||
|
|
||||||
|
private lateinit var job: Job
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = job + Dispatchers.Main
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
activity = (getActivity() as MainActivity?) ?: return null
|
||||||
|
context ?: return null
|
||||||
|
app = activity.application as App
|
||||||
|
context!!.theme.applyStyle(Themes.appTheme, true)
|
||||||
|
b = FragmentHomeV2Binding.inflate(inflater)
|
||||||
|
b.refreshLayout.setParent(activity.swipeRefreshLayout)
|
||||||
|
job = Job()
|
||||||
|
return b.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
// TODO check if app, activity, b can be null
|
||||||
|
if (app.profile == null || !isAdded)
|
||||||
|
return
|
||||||
|
|
||||||
|
activity.bottomSheet.prependItems(
|
||||||
|
BottomSheetPrimaryItem(true)
|
||||||
|
.withTitle(R.string.menu_set_student_number)
|
||||||
|
.withIcon(SzkolnyFont.Icon.szf_clipboard_list_outline)
|
||||||
|
.withOnClickListener(OnClickListener {
|
||||||
|
activity.bottomSheet.close()
|
||||||
|
StudentNumberDialog(activity, app.profile) {
|
||||||
|
app.profileSaveAsync()
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
BottomSheetSeparatorItem(true),
|
||||||
|
BottomSheetPrimaryItem(true)
|
||||||
|
.withTitle(R.string.menu_mark_everything_as_read)
|
||||||
|
.withIcon(Icon.cmd_eye_check_outline)
|
||||||
|
.withOnClickListener(OnClickListener {
|
||||||
|
activity.bottomSheet.close()
|
||||||
|
AsyncTask.execute { app.db.metadataDao().setAllSeen(App.profileId, true) }
|
||||||
|
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show()
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
val items = mutableListOf<HomeCard>(
|
||||||
|
HomeLuckyNumberCard(0, app, activity, this, app.profile),
|
||||||
|
HomeTimetableCard(1, app, activity, this, app.profile)
|
||||||
|
)
|
||||||
|
|
||||||
|
val adapter = HomeCardAdapter(items)
|
||||||
|
val itemTouchHelper = ItemTouchHelper(CardItemTouchHelperCallback(adapter, b.refreshLayout))
|
||||||
|
adapter.itemTouchHelper = itemTouchHelper
|
||||||
|
b.list.layoutManager = LinearLayoutManager(activity)
|
||||||
|
b.list.adapter = adapter
|
||||||
|
b.list.setAccessibilityDelegateCompat(object : RecyclerViewAccessibilityDelegate(b.list) {
|
||||||
|
override fun getItemDelegate(): AccessibilityDelegateCompat {
|
||||||
|
return object : ItemDelegate(this) {
|
||||||
|
override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfoCompat) {
|
||||||
|
super.onInitializeAccessibilityNodeInfo(host, info)
|
||||||
|
val position: Int = b.list.getChildLayoutPosition(host)
|
||||||
|
if (position != 0) {
|
||||||
|
info.addAction(AccessibilityActionCompat(
|
||||||
|
R.id.move_card_up_action,
|
||||||
|
host.resources.getString(R.string.card_action_move_up)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
if (position != adapter.itemCount - 1) {
|
||||||
|
info.addAction(AccessibilityActionCompat(
|
||||||
|
R.id.move_card_down_action,
|
||||||
|
host.resources.getString(R.string.card_action_move_down)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun performAccessibilityAction(host: View, action: Int, args: Bundle): Boolean {
|
||||||
|
val fromPosition: Int = b.list.getChildLayoutPosition(host)
|
||||||
|
if (action == R.id.move_card_down_action) {
|
||||||
|
swapCards(fromPosition, fromPosition + 1, adapter)
|
||||||
|
return true
|
||||||
|
} else if (action == R.id.move_card_up_action) {
|
||||||
|
swapCards(fromPosition, fromPosition - 1, adapter)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.performAccessibilityAction(host, action, args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
itemTouchHelper.attachToRecyclerView(b.list)
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user