mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-06-22 18:13:04 +02:00
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
da48c059ec | |||
ee5566d1ef | |||
b794b30346 | |||
0db6393bb0 | |||
fcc3c55110 | |||
328c07eaf4 | |||
b004ec048e | |||
b9f83875a0 | |||
8c869d082b | |||
043f8210ba | |||
41a79caf83 | |||
0427fa6087 | |||
2f3c912dbe | |||
219a7443c0 | |||
6deb408d80 | |||
c6e1ff2164 | |||
bc0918a115 | |||
55ff9173be | |||
d4d548846f | |||
ef4527f140 | |||
0b1e7242bb | |||
30b6ac2a06 | |||
a7fa7cb5e4 | |||
f3e87f9016 |
1
annotation/.gitignore
vendored
Normal file
1
annotation/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
29
annotation/build.gradle
Normal file
29
annotation/build.gradle
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-28.
|
||||
*/
|
||||
|
||||
apply plugin: 'java-library'
|
||||
apply plugin: 'kotlin'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
}
|
||||
|
||||
sourceCompatibility = "7"
|
||||
targetCompatibility = "7"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
compileKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
compileTestKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.annotation
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
@MustBeDocumented
|
||||
annotation class SelectiveDao(
|
||||
val db: KClass<*>
|
||||
)
|
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.annotation
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
@MustBeDocumented
|
||||
annotation class UpdateSelective(
|
||||
val primaryKeys: Array<String>,
|
||||
val skippedColumns: Array<String> = []
|
||||
)
|
@ -193,6 +193,9 @@ dependencies {
|
||||
implementation "io.coil-kt:coil:0.9.2"
|
||||
|
||||
implementation 'com.github.kuba2k2:NumberSlidingPicker:2921225f76'
|
||||
|
||||
implementation project(":annotation")
|
||||
kapt project(":codegen")
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
@ -1,4 +1,10 @@
|
||||
<h3>Wersja 4.0-rc.1, 2020-03-26</h3>
|
||||
<h3>Wersja 4.0-rc.4, 2020-03-30</h3>
|
||||
<ul>
|
||||
<li>Poprawione pobieranie załączników w Librusie.</li>
|
||||
<li>Nowy widok zadań domowych</li>
|
||||
<li>Możliwość oznaczania zadań domowych i wydarzeń jako wykonane.</li>
|
||||
</ul>
|
||||
<!--<h3>Wersja 4.0-rc.3, 2020-03-29</h3>
|
||||
<ul>
|
||||
<li><b><u>Wysyłanie wiadomości</u></b> - funkcja, na którą czekał każdy. Od teraz w Szkolnym można wysyłać oraz odpowiadać na wiadomości do nauczycieli 👏</li>
|
||||
<li><b>Przebudowaliśmy cały moduł synchronizacji</b>, co oznacza większą stabilność aplikacji, szybkość oraz poprawność pobieranych danych</li>
|
||||
@ -22,7 +28,7 @@
|
||||
<li>Poprawiliśmy synchronizację w tle na niektórych telefonach</li>
|
||||
<li>Usunąłem denerwujący brak zaznaczenia w lewym menu</li>
|
||||
<li>Znaczna ilość błędów z poprzednich wersji już nie występuje</li>
|
||||
</ul>
|
||||
</ul>-->
|
||||
<br>
|
||||
<br>
|
||||
Dzięki za korzystanie ze Szkolnego!<br>
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
/*secret password - removed for source code publication*/
|
||||
static toys AES_IV[16] = {
|
||||
0x53, 0xfb, 0x18, 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
0x1c, 0x15, 0x0f, 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);
|
||||
|
||||
|
@ -40,6 +40,9 @@ import androidx.core.util.forEach
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import com.google.android.gms.security.ProviderInstaller
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
@ -141,6 +144,10 @@ fun CharSequence?.isNotNullNorEmpty(): Boolean {
|
||||
return this != null && this.isNotEmpty()
|
||||
}
|
||||
|
||||
fun <T> Collection<T>?.isNotNullNorEmpty(): Boolean {
|
||||
return this != null && this.isNotEmpty()
|
||||
}
|
||||
|
||||
fun CharSequence?.isNotNullNorBlank(): Boolean {
|
||||
return this != null && this.isNotBlank()
|
||||
}
|
||||
@ -722,6 +729,13 @@ inline fun <T : View> T.onClick(crossinline onClickListener: (v: T) -> Unit) {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <T : View> T.onLongClick(crossinline onLongClickListener: (v: T) -> Boolean) {
|
||||
setOnLongClickListener { v: View ->
|
||||
onLongClickListener(v as T)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <T : CompoundButton> T.onChange(crossinline onChangeListener: (v: T, isChecked: Boolean) -> Unit) {
|
||||
setOnCheckedChangeListener { buttonView, isChecked ->
|
||||
@ -1008,6 +1022,7 @@ fun Context.getNotificationTitle(type: Int): String {
|
||||
Notification.TYPE_FEEDBACK_MESSAGE -> R.string.notification_type_feedback_message
|
||||
Notification.TYPE_NEW_ANNOUNCEMENT -> R.string.notification_type_new_announcement
|
||||
Notification.TYPE_AUTO_ARCHIVING -> R.string.notification_type_auto_archiving
|
||||
Notification.TYPE_TEACHER_ABSENCE -> R.string.notification_type_new_teacher_absence
|
||||
Notification.TYPE_GENERAL -> R.string.notification_type_general
|
||||
else -> R.string.notification_type_general
|
||||
})
|
||||
@ -1166,3 +1181,19 @@ fun TextView.getTextPosition(range: IntRange): Rect {
|
||||
|
||||
return parentTextViewRect
|
||||
}
|
||||
|
||||
inline fun ViewPager.addOnPageSelectedListener(crossinline block: (position: Int) -> Unit) = addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
|
||||
override fun onPageScrollStateChanged(state: Int) {}
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
|
||||
override fun onPageSelected(position: Int) { block(position) }
|
||||
})
|
||||
|
||||
val SwipeRefreshLayout.onScrollListener: RecyclerView.OnScrollListener
|
||||
get() = object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
if (recyclerView.canScrollVertically(-1))
|
||||
this@onScrollListener.isEnabled = false
|
||||
if (!recyclerView.canScrollVertically(-1) && newState == RecyclerView.SCROLL_STATE_IDLE)
|
||||
this@onScrollListener.isEnabled = true
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ 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.HelpFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesListFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.editor.GradesEditorFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment
|
||||
@ -70,9 +70,10 @@ import pl.szczodrzynski.edziennik.ui.modules.messages.MessageFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesComposeFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesListFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsListFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsNewFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.template.TemplateFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.timetable.TimetableFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.webpush.WebPushFragment
|
||||
import pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoTouch
|
||||
@ -129,6 +130,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
const val TARGET_MESSAGES_DETAILS = 503
|
||||
const val TARGET_MESSAGES_COMPOSE = 504
|
||||
const val TARGET_WEB_PUSH = 140
|
||||
const val TARGET_TEMPLATE = 1000
|
||||
|
||||
const val HOME_ID = DRAWER_ITEM_HOME
|
||||
|
||||
@ -153,7 +155,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
.withBadgeTypeId(TYPE_EVENT)
|
||||
.isInDrawer(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesFragment::class)
|
||||
list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesListFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_numeric_5_box_outline)
|
||||
.withBadgeTypeId(TYPE_GRADE)
|
||||
.isInDrawer(true)
|
||||
@ -185,7 +187,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
|
||||
|
||||
// static drawer items
|
||||
list += NavTarget(DRAWER_ITEM_NOTIFICATIONS, R.string.menu_notifications, NotificationsFragment::class)
|
||||
list += NavTarget(DRAWER_ITEM_NOTIFICATIONS, R.string.menu_notifications, NotificationsListFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_bell_ring_outline)
|
||||
.isInDrawer(true)
|
||||
.isStatic(true)
|
||||
@ -227,6 +229,13 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
list += NavTarget(TARGET_MESSAGES_COMPOSE, R.string.menu_message_compose, MessagesComposeFragment::class)
|
||||
list += NavTarget(TARGET_WEB_PUSH, R.string.menu_web_push, WebPushFragment::class)
|
||||
list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class)
|
||||
if (App.devMode) {
|
||||
list += NavTarget(TARGET_TEMPLATE, R.string.menu_template, TemplateFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_test_tube_empty)
|
||||
.isInDrawer(true)
|
||||
.isBelowSeparator(true)
|
||||
.isStatic(true)
|
||||
}
|
||||
|
||||
list
|
||||
}
|
||||
@ -1068,6 +1077,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
.also { if (target.icon != null) it.withIcon(target.icon!!) }
|
||||
.also { if (target.title != null) it.withAppTitle(getString(target.title!!)) }
|
||||
.also { if (target.badgeTypeId != null) it.withBadgeStyle(drawer.badgeStyle)}
|
||||
.withSelectedBackgroundAnimated(false)
|
||||
|
||||
if (target.badgeTypeId != null)
|
||||
drawer.addUnreadCounterType(target.badgeTypeId!!, target.id)
|
||||
|
@ -22,7 +22,7 @@ import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
|
||||
companion object {
|
||||
const val DATA_VERSION = 11
|
||||
const val DATA_VERSION = 12
|
||||
}
|
||||
|
||||
private val job = Job()
|
||||
|
@ -18,7 +18,7 @@ import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class ProfileConfig(val db: AppDb, val profileId: Int, rawEntries: List<ConfigEntry>) : CoroutineScope, AbstractConfig {
|
||||
companion object {
|
||||
const val DATA_VERSION = 1
|
||||
const val DATA_VERSION = 2
|
||||
}
|
||||
|
||||
private val job = Job()
|
||||
|
@ -64,11 +64,25 @@ class ConfigMigration(app: App, config: Config) {
|
||||
dataVersion = 2
|
||||
}
|
||||
|
||||
if (dataVersion < 3) {
|
||||
update = null
|
||||
privacyPolicyAccepted = false
|
||||
debugMode = false
|
||||
devModePassword = null
|
||||
appInstalledTime = 0L
|
||||
appRateSnackbarTime = 0L
|
||||
|
||||
dataVersion = 3
|
||||
}
|
||||
|
||||
if (dataVersion < 10) {
|
||||
ui.openDrawerOnBackPressed = false
|
||||
ui.snowfall = false
|
||||
ui.bottomSheetOpened = false
|
||||
sync.dontShowAppManagerDialog = false
|
||||
sync.webPushEnabled = true
|
||||
sync.lastAppSync = 0L
|
||||
|
||||
|
||||
dataVersion = 10
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.ProfileConfig
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.AGENDA_DEFAULT
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.COLOR_MODE_WEIGHTED
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_ALL_GRADES
|
||||
@ -14,11 +15,23 @@ class ProfileConfigMigration(config: ProfileConfig) {
|
||||
|
||||
if (dataVersion < 1) {
|
||||
grades.colorMode = COLOR_MODE_WEIGHTED
|
||||
grades.dontCountEnabled = false
|
||||
grades.yearAverageMode = YEAR_ALL_GRADES
|
||||
grades.hideImproved = false
|
||||
grades.averageWithoutWeight = true
|
||||
grades.plusValue = null
|
||||
grades.minusValue = null
|
||||
grades.dontCountEnabled = false
|
||||
grades.dontCountGrades = listOf()
|
||||
ui.agendaViewType = AGENDA_DEFAULT
|
||||
// no migration for ui.homeCards
|
||||
|
||||
dataVersion = 1
|
||||
}
|
||||
|
||||
if (dataVersion < 2) {
|
||||
sync.notificationFilter = sync.notificationFilter + Notification.TYPE_TEACHER_ABSENCE
|
||||
|
||||
dataVersion = 2
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
@ -70,13 +70,13 @@ val librusLoginMethods = listOf(
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_SYNERGIA, LibrusLoginSynergia::class.java)
|
||||
.withIsPossible { _, loginStore -> !loginStore.hasLoginData("fakeLogin") }
|
||||
.withRequiredLoginMethod { profile, _ ->
|
||||
if (profile?.hasStudentData("accountPassword") == false) LOGIN_METHOD_LIBRUS_API else LOGIN_METHOD_NOT_NEEDED
|
||||
if (profile?.hasStudentData("accountPassword") == false || true) LOGIN_METHOD_LIBRUS_API else LOGIN_METHOD_NOT_NEEDED
|
||||
},
|
||||
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_MESSAGES, LibrusLoginMessages::class.java)
|
||||
.withIsPossible { _, loginStore -> !loginStore.hasLoginData("fakeLogin") }
|
||||
.withRequiredLoginMethod { profile, _ ->
|
||||
if (profile?.hasStudentData("accountPassword") == false) LOGIN_METHOD_LIBRUS_SYNERGIA else LOGIN_METHOD_NOT_NEEDED
|
||||
if (profile?.hasStudentData("accountPassword") == false || true) LOGIN_METHOD_LIBRUS_SYNERGIA else LOGIN_METHOD_NOT_NEEDED
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -39,17 +39,16 @@ class EdudziennikWebEvents(override val data: DataEdudziennik,
|
||||
?: return@forEach
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
date,
|
||||
null,
|
||||
title,
|
||||
-1,
|
||||
Event.TYPE_CLASS_EVENT,
|
||||
false,
|
||||
-1,
|
||||
-1,
|
||||
data.teamClass?.id ?: -1
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
date = date,
|
||||
time = null,
|
||||
topic = title,
|
||||
color = null,
|
||||
type = Event.TYPE_CLASS_EVENT,
|
||||
teacherId = -1,
|
||||
subjectId = -1,
|
||||
teamId = data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
|
@ -56,17 +56,16 @@ class EdudziennikWebExams(override val data: DataEdudziennik,
|
||||
val eventType = data.getEventType(eventTypeId, eventTypeName)
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
date,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
eventType.id,
|
||||
false,
|
||||
-1,
|
||||
subject.id,
|
||||
data.teamClass?.id ?: -1
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
date = date,
|
||||
time = startTime,
|
||||
topic = topic,
|
||||
color = null,
|
||||
type = eventType.id,
|
||||
teacherId = -1,
|
||||
subjectId = subject.id,
|
||||
teamId = data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
|
@ -52,17 +52,16 @@ class EdudziennikWebHomework(override val data: DataEdudziennik,
|
||||
val topic = homeworkElement.child(4).text()
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
date,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
Event.TYPE_HOMEWORK,
|
||||
false,
|
||||
teacher.id,
|
||||
subject.id,
|
||||
data.teamClass?.id ?: -1
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
date = date,
|
||||
time = startTime,
|
||||
topic = topic,
|
||||
color = null,
|
||||
type = Event.TYPE_HOMEWORK,
|
||||
teacherId = teacher.id,
|
||||
subjectId = subject.id,
|
||||
teamId = data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
|
@ -80,17 +80,16 @@ class IdziennikWebExams(override val data: DataIdziennik,
|
||||
}
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
examDate,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
eventType,
|
||||
false,
|
||||
teacherId,
|
||||
subjectId,
|
||||
data.teamClass?.id ?: -1
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
date = examDate,
|
||||
time = startTime,
|
||||
topic = topic,
|
||||
color = null,
|
||||
type = eventType,
|
||||
teacherId = teacherId,
|
||||
subjectId = subjectId,
|
||||
teamId = data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
|
@ -67,17 +67,16 @@ class IdziennikWebHomework(override val data: DataIdziennik,
|
||||
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
eventDate,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
Event.TYPE_HOMEWORK,
|
||||
false,
|
||||
teacherId,
|
||||
subjectId,
|
||||
data.teamClass?.id ?: -1
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
date = eventDate,
|
||||
time = startTime,
|
||||
topic = topic,
|
||||
color = null,
|
||||
type = Event.TYPE_HOMEWORK,
|
||||
teacherId = teacherId,
|
||||
subjectId = subjectId,
|
||||
teamId = data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
|
@ -252,10 +252,11 @@ open class LibrusMessages(open val data: DataLibrus, open val lastSync: Long?) {
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
fun sandboxGetFile(tag: String, action: String, targetFile: File, onSuccess: (file: File) -> Unit,
|
||||
fun sandboxGetFile(tag: String, url: String, targetFile: File, onSuccess: (file: File) -> Unit,
|
||||
method: Int = GET,
|
||||
onProgress: (written: Long, total: Long) -> Unit) {
|
||||
|
||||
d(tag, "Request: Librus/Messages - $LIBRUS_SANDBOX_URL$action")
|
||||
d(tag, "Request: Librus/Messages - $url")
|
||||
|
||||
val callback = object : FileCallbackHandler(targetFile) {
|
||||
override fun onSuccess(file: File?, response: Response?) {
|
||||
@ -291,9 +292,14 @@ open class LibrusMessages(open val data: DataLibrus, open val lastSync: Long?) {
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url("$LIBRUS_SANDBOX_URL$action")
|
||||
.url(url)
|
||||
.userAgent(SYNERGIA_USER_AGENT)
|
||||
.post()
|
||||
.also {
|
||||
when (method) {
|
||||
POST -> it.post()
|
||||
else -> it.get()
|
||||
}
|
||||
}
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
|
@ -47,17 +47,16 @@ class LibrusApiEvents(override val data: DataLibrus,
|
||||
val addedDate = Date.fromIso(event.getString("AddDate"))
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
eventDate,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
type,
|
||||
false,
|
||||
teacherId,
|
||||
subjectId,
|
||||
teamId
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
date = eventDate,
|
||||
time = startTime,
|
||||
topic = topic,
|
||||
color = null,
|
||||
type = type,
|
||||
teacherId = teacherId,
|
||||
subjectId = subjectId,
|
||||
teamId = teamId
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
|
@ -34,17 +34,16 @@ class LibrusApiHomework(override val data: DataLibrus,
|
||||
val addedDate = Date.fromY_m_d(homework.getString("Date"))
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
eventDate,
|
||||
null,
|
||||
topic,
|
||||
-1,
|
||||
-1,
|
||||
false,
|
||||
teacherId,
|
||||
-1,
|
||||
-1
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
date = eventDate,
|
||||
time = null,
|
||||
topic = topic,
|
||||
color = null,
|
||||
type = -1,
|
||||
teacherId = teacherId,
|
||||
subjectId = -1,
|
||||
teamId = -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
|
@ -39,17 +39,16 @@ class LibrusApiPtMeetings(override val data: DataLibrus,
|
||||
}
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
eventDate,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
Event.TYPE_PT_MEETING,
|
||||
false,
|
||||
teacherId,
|
||||
-1,
|
||||
data.teamClass?.id ?: -1
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
date = eventDate,
|
||||
time = startTime,
|
||||
topic = topic,
|
||||
color = null,
|
||||
type = Event.TYPE_PT_MEETING,
|
||||
teacherId = teacherId,
|
||||
subjectId = -1,
|
||||
teamId = data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
|
@ -59,7 +59,7 @@ class LibrusApiTeacherFreeDays(override val data: DataLibrus,
|
||||
profileId,
|
||||
Metadata.TYPE_TEACHER_ABSENCE,
|
||||
id,
|
||||
profile?.empty ?: false,
|
||||
true,
|
||||
profile?.empty ?: false,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
|
@ -6,9 +6,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_FILE_DOWNLOAD
|
||||
import pl.szczodrzynski.edziennik.data.api.EXCEPTION_LIBRUS_MESSAGES_REQUEST
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusMessages
|
||||
import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
|
||||
@ -53,11 +51,10 @@ class LibrusMessagesGetAttachment(override val data: DataLibrus,
|
||||
|
||||
val attachmentKey = keyMatcher[1]
|
||||
getAttachmentCheckKey(attachmentKey) {
|
||||
downloadAttachment(attachmentKey)
|
||||
downloadAttachment("${LIBRUS_SANDBOX_URL}CSDownload&singleUseKey=$attachmentKey", method = POST)
|
||||
}
|
||||
} else {
|
||||
data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
|
||||
.withApiResponse(doc.toString()))
|
||||
downloadAttachment("$downloadLink/get", method = GET)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -91,10 +88,10 @@ class LibrusMessagesGetAttachment(override val data: DataLibrus,
|
||||
}
|
||||
}
|
||||
|
||||
private fun downloadAttachment(attachmentKey: String) {
|
||||
private fun downloadAttachment(url: String, method: Int = GET) {
|
||||
val targetFile = File(Utils.getStorageDir(), attachmentName)
|
||||
|
||||
sandboxGetFile(TAG, "CSDownload&singleUseKey=$attachmentKey", targetFile, { file ->
|
||||
sandboxGetFile(TAG, url, targetFile, { file ->
|
||||
|
||||
val event = AttachmentGetEvent(
|
||||
profileId,
|
||||
|
@ -109,6 +109,11 @@ class LibrusMessagesGetList(override val data: DataLibrus,
|
||||
id
|
||||
)
|
||||
|
||||
element.select("isAnyFileAttached")?.text()?.let {
|
||||
if (it == "1")
|
||||
messageObject.overrideHasAttachments = true
|
||||
}
|
||||
|
||||
data.messageIgnoreList.add(messageObject)
|
||||
data.messageRecipientList.add(messageRecipientObject)
|
||||
data.setSeenMetadataList.add(Metadata(
|
||||
|
@ -89,17 +89,16 @@ class LibrusSynergiaHomework(override val data: DataLibrus,
|
||||
}
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
eventDate,
|
||||
startTime,
|
||||
"$topic\n$description",
|
||||
-1,
|
||||
Event.TYPE_HOMEWORK,
|
||||
false,
|
||||
teacherId,
|
||||
subjectId,
|
||||
data.teamClass?.id ?: -1
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
date = eventDate,
|
||||
time = startTime,
|
||||
topic = "$topic\n$description",
|
||||
color = null,
|
||||
type = Event.TYPE_HOMEWORK,
|
||||
teacherId = teacherId,
|
||||
subjectId = subjectId,
|
||||
teamId = data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
|
@ -51,17 +51,16 @@ class MobidziennikApiEvents(val data: DataMobidziennik, rows: List<String>) {
|
||||
|
||||
|
||||
val eventObject = Event(
|
||||
data.profileId,
|
||||
id,
|
||||
eventDate,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
type,
|
||||
false,
|
||||
teacherId,
|
||||
subjectId,
|
||||
teamId)
|
||||
profileId = data.profileId,
|
||||
id = id,
|
||||
date = eventDate,
|
||||
time = startTime,
|
||||
topic = topic,
|
||||
color = null,
|
||||
type = type,
|
||||
teacherId = teacherId,
|
||||
subjectId = subjectId,
|
||||
teamId = teamId)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
data.metadataList.add(
|
||||
@ -76,6 +75,8 @@ class MobidziennikApiEvents(val data: DataMobidziennik, rows: List<String>) {
|
||||
}
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
|
||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_DEFAULT))
|
||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_EXAM))
|
||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_SHORT_QUIZ))
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.api
|
||||
|
||||
import android.text.Html
|
||||
import androidx.core.util.contains
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
@ -25,22 +26,21 @@ class MobidziennikApiHomework(val data: DataMobidziennik, rows: List<String>) {
|
||||
val id = cols[0].toLong()
|
||||
val teacherId = cols[7].toLong()
|
||||
val subjectId = cols[6].toLong()
|
||||
val topic = cols[1]
|
||||
val topic = Html.fromHtml(cols[1])?.toString() ?: ""
|
||||
val eventDate = Date.fromYmd(cols[2])
|
||||
val startTime = Time.fromYmdHm(cols[3])
|
||||
|
||||
val eventObject = Event(
|
||||
data.profileId,
|
||||
id,
|
||||
eventDate,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
Event.TYPE_HOMEWORK,
|
||||
false,
|
||||
teacherId,
|
||||
subjectId,
|
||||
teamId)
|
||||
profileId = data.profileId,
|
||||
id = id,
|
||||
date = eventDate,
|
||||
time = startTime,
|
||||
topic = topic,
|
||||
color = null,
|
||||
type = Event.TYPE_HOMEWORK,
|
||||
teacherId = teacherId,
|
||||
subjectId = subjectId,
|
||||
teamId = teamId)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
data.metadataList.add(
|
||||
|
@ -44,7 +44,7 @@ class MobidziennikApiTeams(val data: DataMobidziennik, tableTeams: List<String>?
|
||||
|
||||
val studentId = cols[1].toInt()
|
||||
val teamId = cols[2].toLong()
|
||||
val studentNumber = cols[4].toInt()
|
||||
val studentNumber = cols[4].toIntOrNull() ?: -1
|
||||
|
||||
if (studentId != data.studentId)
|
||||
continue
|
||||
|
@ -61,26 +61,25 @@ class MobidziennikWebCalendar(override val data: DataMobidziennik,
|
||||
val title = event.getString("title")
|
||||
val comment = event.getString("comment")
|
||||
|
||||
var topic = title
|
||||
var topic = title ?: ""
|
||||
if (title != comment) {
|
||||
topic += "\n" + comment
|
||||
}
|
||||
|
||||
if (id == -1L) {
|
||||
id = crc16(topic?.toByteArray()).toLong()
|
||||
id = crc16(topic.toByteArray()).toLong()
|
||||
}
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
eventDate, null,
|
||||
topic,
|
||||
-1,
|
||||
eventType,
|
||||
false,
|
||||
-1,
|
||||
-1,
|
||||
data.teamClass?.id ?: -1
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
date = eventDate, time = null,
|
||||
topic = topic,
|
||||
color = null,
|
||||
type = eventType,
|
||||
teacherId = -1,
|
||||
subjectId = -1,
|
||||
teamId = data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
|
@ -72,17 +72,16 @@ class VulcanApiEvents(override val data: DataVulcan,
|
||||
val teamId = event.getLong("IdOddzial") ?: data.teamClass?.id ?: -1
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
eventDate,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
type,
|
||||
false,
|
||||
teacherId,
|
||||
subjectId,
|
||||
teamId
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
date = eventDate,
|
||||
time = startTime,
|
||||
topic = topic,
|
||||
color = null,
|
||||
type = type,
|
||||
teacherId = teacherId,
|
||||
subjectId = subjectId,
|
||||
teamId = teamId
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
|
@ -284,7 +284,7 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
|
||||
db.gradeDao().addAll(gradeList)
|
||||
}
|
||||
if (eventList.isNotEmpty()) {
|
||||
db.eventDao().addAll(eventList)
|
||||
db.eventDao().upsertAll(eventList, removeNotKept = true)
|
||||
}
|
||||
if (noticeList.isNotEmpty()) {
|
||||
db.noticeDao().clear(profile.id)
|
||||
|
@ -56,9 +56,9 @@ open class DataRemoveModel {
|
||||
}
|
||||
|
||||
fun commit(profileId: Int, dao: EventDao) {
|
||||
type?.let { dao.removeFutureWithType(profileId, Date.getToday(), it) }
|
||||
exceptType?.let { dao.removeFutureExceptType(profileId, Date.getToday(), it) }
|
||||
exceptTypes?.let { dao.removeFutureExceptTypes(profileId, Date.getToday(), it) }
|
||||
type?.let { dao.dontKeepFutureWithType(profileId, Date.getToday(), it) }
|
||||
exceptType?.let { dao.dontKeepFutureExceptType(profileId, Date.getToday(), it) }
|
||||
exceptTypes?.let { dao.dontKeepFutureExceptTypes(profileId, Date.getToday(), it) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,6 +196,11 @@ class SzkolnyApi(val app: App) : CoroutineScope {
|
||||
// skip blacklisted events
|
||||
if (event.id in blacklistedIds)
|
||||
return@forEach
|
||||
|
||||
// force nullable non-negative colors
|
||||
if (event.color == -1)
|
||||
event.color = null
|
||||
|
||||
// create the event for every matching team and profile
|
||||
teams.filter { it.code == event.teamCode }.onEach { team ->
|
||||
val profile = profiles.firstOrNull { it.id == team.profileId } ?: return@onEach
|
||||
|
@ -46,6 +46,6 @@ object Signing {
|
||||
|
||||
/*fun provideKey(param1: String, param2: Long): ByteArray {*/
|
||||
fun pleaseStopRightNow(param1: String, param2: Long): ByteArray {
|
||||
return "$param1.MTIzNDU2Nzg5MD86J6EdtN===.$param2".sha256()
|
||||
return "$param1.MTIzNDU2Nzg5MDj3yyZoD8===.$param2".sha256()
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,8 @@ data class EventShareRequest (
|
||||
|
||||
val action: String = "event",
|
||||
|
||||
val sharedByName: String,
|
||||
/* If null, the server shows an error */
|
||||
val sharedByName: String?,
|
||||
val shareTeamCode: String? = null,
|
||||
val unshareTeamCode: String? = null,
|
||||
val requesterName: String? = null,
|
||||
|
@ -34,7 +34,7 @@ class AppSync(val app: App, val notifications: MutableList<Notification>, val pr
|
||||
if (events.isNotEmpty()) {
|
||||
val today = Date.getToday()
|
||||
app.db.metadataDao().addAllIgnore(events.map { event ->
|
||||
val isPast = event.eventDate < today
|
||||
val isPast = event.date < today
|
||||
Metadata(
|
||||
event.profileId,
|
||||
Metadata.TYPE_EVENT,
|
||||
@ -44,7 +44,7 @@ class AppSync(val app: App, val notifications: MutableList<Notification>, val pr
|
||||
event.addedDate
|
||||
)
|
||||
})
|
||||
return app.db.eventDao().addAll(events).size
|
||||
return app.db.eventDao().upsertAll(events).size
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
|
||||
announcementNotifications()
|
||||
messageNotifications()
|
||||
luckyNumberNotifications()
|
||||
teacherAbsenceNotifications()
|
||||
}
|
||||
|
||||
private fun timetableNotifications() {
|
||||
@ -58,7 +59,7 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
|
||||
}
|
||||
|
||||
private fun eventNotifications() {
|
||||
for (event in app.db.eventDao().notNotifiedNow.filter { it.eventDate >= today }) {
|
||||
for (event in app.db.eventDao().getNotNotifiedNow().filter { it.date >= today }) {
|
||||
val text = if (event.type == Event.TYPE_HOMEWORK)
|
||||
app.getString(
|
||||
if (event.subjectLongName.isNullOrEmpty())
|
||||
@ -66,7 +67,7 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
|
||||
else
|
||||
R.string.notification_homework_format,
|
||||
event.subjectLongName,
|
||||
event.eventDate.formattedString
|
||||
event.date.formattedString
|
||||
)
|
||||
else
|
||||
app.getString(
|
||||
@ -74,8 +75,8 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
|
||||
R.string.notification_event_no_subject_format
|
||||
else
|
||||
R.string.notification_event_format,
|
||||
event.typeName,
|
||||
event.eventDate.formattedString,
|
||||
event.typeName ?: "wydarzenie",
|
||||
event.date.formattedString,
|
||||
event.subjectLongName
|
||||
)
|
||||
val type = if (event.type == Event.TYPE_HOMEWORK) Notification.TYPE_NEW_HOMEWORK else Notification.TYPE_NEW_EVENT
|
||||
@ -88,17 +89,17 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
|
||||
profileName = profiles.singleOrNull { it.id == event.profileId }?.name,
|
||||
viewId = if (event.type == Event.TYPE_HOMEWORK) MainActivity.DRAWER_ITEM_HOMEWORK else MainActivity.DRAWER_ITEM_AGENDA,
|
||||
addedDate = event.addedDate
|
||||
).addExtra("eventId", event.id).addExtra("eventDate", event.eventDate.value.toLong())
|
||||
).addExtra("eventId", event.id).addExtra("eventDate", event.date.value.toLong())
|
||||
}
|
||||
}
|
||||
|
||||
fun sharedEventNotifications() {
|
||||
for (event in app.db.eventDao().notNotifiedNow.filter { it.eventDate >= today && it.sharedBy != null }) {
|
||||
for (event in app.db.eventDao().getNotNotifiedNow().filter { it.date >= today && it.sharedBy != null }) {
|
||||
val text = app.getString(
|
||||
R.string.notification_shared_event_format,
|
||||
event.sharedByName,
|
||||
event.typeName ?: "wydarzenie",
|
||||
event.eventDate.formattedString,
|
||||
event.date.formattedString,
|
||||
event.topic
|
||||
)
|
||||
val type = if (event.type == Event.TYPE_HOMEWORK) Notification.TYPE_NEW_HOMEWORK else Notification.TYPE_NEW_EVENT
|
||||
@ -111,7 +112,7 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
|
||||
profileName = profiles.singleOrNull { it.id == event.profileId }?.name,
|
||||
viewId = if (event.type == Event.TYPE_HOMEWORK) MainActivity.DRAWER_ITEM_HOMEWORK else MainActivity.DRAWER_ITEM_AGENDA,
|
||||
addedDate = event.addedDate
|
||||
).addExtra("eventId", event.id).addExtra("eventDate", event.eventDate.value.toLong())
|
||||
).addExtra("eventId", event.id).addExtra("eventDate", event.date.value.toLong())
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,4 +275,23 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun teacherAbsenceNotifications() {
|
||||
for (teacherAbsence in app.db.teacherAbsenceDao().getNotNotifiedNow()) {
|
||||
val message = app.getString(
|
||||
R.string.notification_teacher_absence_new_format,
|
||||
teacherAbsence.teacherFullName
|
||||
)
|
||||
notifications += Notification(
|
||||
id = Notification.buildId(teacherAbsence.profileId, Notification.TYPE_TEACHER_ABSENCE, teacherAbsence.id),
|
||||
title = app.getNotificationTitle(Notification.TYPE_TEACHER_ABSENCE),
|
||||
text = message,
|
||||
type = Notification.TYPE_TEACHER_ABSENCE,
|
||||
profileId = teacherAbsence.profileId,
|
||||
profileName = profiles.singleOrNull { it.id == teacherAbsence.profileId }?.name,
|
||||
viewId = MainActivity.DRAWER_ITEM_AGENDA,
|
||||
addedDate = teacherAbsence.addedDate
|
||||
).addExtra("eventDate", teacherAbsence.dateFrom.value.toLong())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ import pl.szczodrzynski.edziennik.data.db.migration.*
|
||||
LibrusLesson::class,
|
||||
TimetableManual::class,
|
||||
Metadata::class
|
||||
], version = 79)
|
||||
], version = 83)
|
||||
@TypeConverters(
|
||||
ConverterTime::class,
|
||||
ConverterDate::class,
|
||||
@ -164,7 +164,11 @@ abstract class AppDb : RoomDatabase() {
|
||||
Migration76(),
|
||||
Migration77(),
|
||||
Migration78(),
|
||||
Migration79()
|
||||
Migration79(),
|
||||
Migration80(),
|
||||
Migration81(),
|
||||
Migration82(),
|
||||
Migration83()
|
||||
).allowMainThreadQueries().build()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.db.dao
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.*
|
||||
import androidx.sqlite.db.SimpleSQLiteQuery
|
||||
import androidx.sqlite.db.SupportSQLiteQuery
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Keepable
|
||||
|
||||
@Dao
|
||||
interface BaseDao<T : Keepable, F : T> {
|
||||
@RawQuery
|
||||
fun getRaw(query: SupportSQLiteQuery): LiveData<List<F>>
|
||||
fun getRaw(query: String) = getRaw(SimpleSQLiteQuery(query))
|
||||
@RawQuery
|
||||
fun getRawNow(query: SupportSQLiteQuery): List<F>
|
||||
fun getRawNow(query: String) = getRawNow(SimpleSQLiteQuery(query))
|
||||
@RawQuery
|
||||
fun getOneNow(query: SupportSQLiteQuery): F?
|
||||
fun getOneNow(query: String) = getOneNow(SimpleSQLiteQuery(query))
|
||||
|
||||
@Query("DELETE FROM events WHERE keep = 0")
|
||||
fun removeNotKept()
|
||||
|
||||
/**
|
||||
* INSERT an [item] into the database,
|
||||
* ignoring any conflicts.
|
||||
*/
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
fun add(item: T): Long
|
||||
/**
|
||||
* INSERT [items] into the database,
|
||||
* ignoring any conflicts.
|
||||
*/
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
fun addAll(items: List<T>): LongArray
|
||||
|
||||
/**
|
||||
* REPLACE an [item] in the database,
|
||||
* removing any conflicting rows.
|
||||
*/
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun replace(item: T)
|
||||
/**
|
||||
* REPLACE [items] in the database,
|
||||
* removing any conflicting rows.
|
||||
*/
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun replaceAll(items: List<T>)
|
||||
|
||||
/**
|
||||
* Selective UPDATE an [item] in the database.
|
||||
* Do nothing if a matching item does not exist.
|
||||
*/
|
||||
fun update(item: T): Long
|
||||
/**
|
||||
* Selective UPDATE [items] in the database.
|
||||
* Do nothing for those items which do not exist.
|
||||
*/
|
||||
fun updateAll(items: List<T>): LongArray
|
||||
|
||||
/**
|
||||
* Remove all items from the database,
|
||||
* that match the given [profileId].
|
||||
*/
|
||||
fun clear(profileId: Int)
|
||||
|
||||
/**
|
||||
* INSERT an [item] into the database,
|
||||
* doing a selective [update] on conflicts.
|
||||
* @return the newly inserted item's ID or -1L if the item was updated instead
|
||||
*/
|
||||
@Transaction
|
||||
fun upsert(item: T): Long {
|
||||
val id = add(item)
|
||||
if (id == -1L) update(item)
|
||||
return id
|
||||
}
|
||||
/**
|
||||
* INSERT [items] into the database,
|
||||
* doing a selective [update] on conflicts.
|
||||
* @return a [LongArray] of IDs of newly inserted items or -1L if the item existed before
|
||||
*/
|
||||
@Transaction
|
||||
fun upsertAll(items: List<T>, removeNotKept: Boolean = false): LongArray {
|
||||
val insertResult = addAll(items)
|
||||
val updateList = mutableListOf<T>()
|
||||
|
||||
insertResult.forEachIndexed { index, result ->
|
||||
if (result == -1L) updateList.add(items[index])
|
||||
}
|
||||
|
||||
if (updateList.isNotEmpty()) updateAll(items)
|
||||
if (removeNotKept) removeNotKept()
|
||||
return insertResult
|
||||
}
|
||||
}
|
@ -1,186 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2020-1-6
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.db.dao;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.RawQuery;
|
||||
import androidx.room.Transaction;
|
||||
import androidx.sqlite.db.SimpleSQLiteQuery;
|
||||
import androidx.sqlite.db.SupportSQLiteQuery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_EVENT;
|
||||
import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_HOMEWORK;
|
||||
import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_LESSON_CHANGE;
|
||||
|
||||
@Dao
|
||||
public abstract class EventDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
public abstract long add(Event event);
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
public abstract long[] addAll(List<Event> eventList);
|
||||
|
||||
@Query("DELETE FROM events WHERE profileId = :profileId")
|
||||
public abstract void clear(int profileId);
|
||||
|
||||
@Query("DELETE FROM events WHERE profileId = :profileId AND eventId = :id")
|
||||
public abstract void remove(int profileId, long id);
|
||||
@Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = :thingType AND thingId = :thingId")
|
||||
public abstract void removeMetadata(int profileId, int thingType, long thingId);
|
||||
@Transaction
|
||||
public void remove(int profileId, long type, long id) {
|
||||
remove(profileId, id);
|
||||
removeMetadata(profileId, type == Event.TYPE_HOMEWORK ? TYPE_HOMEWORK : TYPE_EVENT, id);
|
||||
}
|
||||
@Transaction
|
||||
public void remove(Event event) {
|
||||
remove(event.profileId, event.type, event.id);
|
||||
}
|
||||
@Transaction
|
||||
public void remove(int profileId, Event event) {
|
||||
remove(profileId, event.type, event.id);
|
||||
}
|
||||
@Query("DELETE FROM events WHERE teamId = :teamId AND eventId = :id")
|
||||
public abstract void removeByTeamId(long teamId, long id);
|
||||
|
||||
@RawQuery(observedEntities = {Event.class})
|
||||
abstract LiveData<List<EventFull>> getAll(SupportSQLiteQuery query);
|
||||
public LiveData<List<EventFull>> getAll(int profileId, String filter, String limit) {
|
||||
String query = "SELECT \n" +
|
||||
"*, \n" +
|
||||
"teachers.teacherName || ' ' || teachers.teacherSurname AS teacherFullName,\n" +
|
||||
"eventTypes.eventTypeName AS typeName,\n" +
|
||||
"eventTypes.eventTypeColor AS typeColor\n" +
|
||||
"FROM events\n" +
|
||||
"LEFT JOIN subjects USING(profileId, subjectId)\n" +
|
||||
"LEFT JOIN teachers USING(profileId, teacherId)\n" +
|
||||
"LEFT JOIN teams USING(profileId, teamId)\n" +
|
||||
"LEFT JOIN eventTypes USING(profileId, eventType)\n" +
|
||||
"LEFT JOIN metadata ON eventId = thingId AND (thingType = " + TYPE_EVENT + " OR thingType = " + TYPE_HOMEWORK + ") AND metadata.profileId = "+profileId+"\n" +
|
||||
"WHERE events.profileId = "+profileId+" AND events.eventBlacklisted = 0 AND "+filter+"\n" +
|
||||
"GROUP BY eventId\n" +
|
||||
"ORDER BY eventDate, eventStartTime ASC "+limit;
|
||||
Log.d("DB", query);
|
||||
return getAll(new SimpleSQLiteQuery(query));
|
||||
}
|
||||
public LiveData<List<EventFull>> getAll(int profileId) {
|
||||
return getAll(profileId, "1", "");
|
||||
}
|
||||
public List<EventFull> getAllNow(int profileId) {
|
||||
return getAllNow(profileId, "1");
|
||||
}
|
||||
public LiveData<List<EventFull>> getAllWhere(int profileId, String filter) {
|
||||
return getAll(profileId, filter, "");
|
||||
}
|
||||
public LiveData<List<EventFull>> getAllByType(int profileId, long type, String filter) {
|
||||
return getAll(profileId, "eventType = "+type+" AND "+filter, "");
|
||||
}
|
||||
public LiveData<List<EventFull>> getAllByDate(int profileId, @NonNull Date date) {
|
||||
return getAll(profileId, "eventDate = '"+date.getStringY_m_d()+"'", "");
|
||||
}
|
||||
public List<EventFull> getAllByDateNow(int profileId, @NonNull Date date) {
|
||||
return getAllNow(profileId, "eventDate = '"+date.getStringY_m_d()+"'");
|
||||
}
|
||||
public LiveData<List<EventFull>> getAllByDateTime(int profileId, @NonNull Date date, Time time) {
|
||||
if (time == null)
|
||||
return getAllByDate(profileId, date);
|
||||
return getAll(profileId, "eventDate = '"+date.getStringY_m_d()+"' AND eventStartTime = '"+time.getStringValue()+"'", "");
|
||||
}
|
||||
public LiveData<List<EventFull>> getAllNearest(int profileId, @NonNull Date today, int limit) {
|
||||
return getAll(profileId, "eventDate >= '"+today.getStringY_m_d()+"'", "LIMIT "+limit);
|
||||
}
|
||||
|
||||
@RawQuery
|
||||
abstract List<EventFull> getAllNow(SupportSQLiteQuery query);
|
||||
public List<EventFull> getAllNow(int profileId, String filter) {
|
||||
return getAllNow(new SimpleSQLiteQuery("SELECT \n" +
|
||||
"*, \n" +
|
||||
"teachers.teacherName || ' ' || teachers.teacherSurname AS teacherFullName,\n" +
|
||||
"eventTypes.eventTypeName AS typeName,\n" +
|
||||
"eventTypes.eventTypeColor AS typeColor\n" +
|
||||
"FROM events \n" +
|
||||
"LEFT JOIN subjects USING(profileId, subjectId)\n" +
|
||||
"LEFT JOIN teachers USING(profileId, teacherId)\n" +
|
||||
"LEFT JOIN teams USING(profileId, teamId)\n" +
|
||||
"LEFT JOIN eventTypes USING(profileId, eventType)\n" +
|
||||
"LEFT JOIN metadata ON eventId = thingId AND (thingType = " + TYPE_EVENT + " OR thingType = " + TYPE_HOMEWORK + ") AND metadata.profileId = "+profileId+"\n" +
|
||||
"WHERE events.profileId = "+profileId+" AND events.eventBlacklisted = 0 AND "+filter+"\n" +
|
||||
"GROUP BY eventId\n" +
|
||||
"ORDER BY eventStartTime, addedDate ASC"));
|
||||
}
|
||||
public List<EventFull> getNotNotifiedNow(int profileId) {
|
||||
return getAllNow(profileId, "notified = 0");
|
||||
}
|
||||
|
||||
@Query("SELECT eventId FROM events WHERE profileId = :profileId AND eventBlacklisted = 1")
|
||||
public abstract List<Long> getBlacklistedIds(int profileId);
|
||||
@Query("SELECT eventId FROM events WHERE eventBlacklisted = 1")
|
||||
public abstract List<Long> getBlacklistedIds();
|
||||
|
||||
@Query("SELECT " +
|
||||
"*, " +
|
||||
"eventTypes.eventTypeName AS typeName, " +
|
||||
"eventTypes.eventTypeColor AS typeColor " +
|
||||
"FROM events " +
|
||||
"LEFT JOIN subjects USING(profileId, subjectId) " +
|
||||
"LEFT JOIN eventTypes USING(profileId, eventType) " +
|
||||
"LEFT JOIN metadata ON eventId = thingId AND (thingType = " + TYPE_EVENT + " OR thingType = " + TYPE_HOMEWORK + ") AND metadata.profileId = events.profileId " +
|
||||
"WHERE events.eventBlacklisted = 0 AND notified = 0 " +
|
||||
"GROUP BY eventId " +
|
||||
"ORDER BY addedDate ASC")
|
||||
public abstract List<EventFull> getNotNotifiedNow();
|
||||
|
||||
public EventFull getByIdNow(int profileId, long eventId) {
|
||||
List<EventFull> eventList = getAllNow(profileId, "eventId = "+eventId);
|
||||
return eventList.size() == 0 ? null : eventList.get(0);
|
||||
}
|
||||
|
||||
@Query("UPDATE events SET eventAddedManually = 1 WHERE profileId = :profileId AND eventDate < :date")
|
||||
public abstract void convertOlderToManual(int profileId, Date date);
|
||||
|
||||
@Query("DELETE FROM events WHERE profileId = :profileId AND eventAddedManually = 0")
|
||||
public abstract void removeNotManual(int profileId);
|
||||
|
||||
@RawQuery
|
||||
abstract long removeFuture(SupportSQLiteQuery query);
|
||||
@Transaction
|
||||
public void removeFuture(int profileId, Date todayDate, String filter) {
|
||||
removeFuture(new SimpleSQLiteQuery("DELETE FROM events WHERE profileId = " + profileId
|
||||
+ " AND eventAddedManually = 0 AND eventDate >= '" + todayDate.getStringY_m_d() + "'" +
|
||||
" AND " + filter));
|
||||
}
|
||||
|
||||
@Query("DELETE FROM events WHERE profileId = :profileId AND eventAddedManually = 0 AND eventDate >= :todayDate AND eventType = :type")
|
||||
public abstract void removeFutureWithType(int profileId, Date todayDate, long type);
|
||||
|
||||
@Query("DELETE FROM events WHERE profileId = :profileId AND eventAddedManually = 0 AND eventDate >= :todayDate AND eventType != :exceptType")
|
||||
public abstract void removeFutureExceptType(int profileId, Date todayDate, long exceptType);
|
||||
|
||||
@Transaction
|
||||
public void removeFutureExceptTypes(int profileId, Date todayDate, List<Long> exceptTypes) {
|
||||
removeFuture(profileId, todayDate, "eventType NOT IN " + exceptTypes.toString().replace('[', '(').replace(']', ')'));
|
||||
}
|
||||
|
||||
@Query("UPDATE metadata SET seen = :seen WHERE profileId = :profileId AND (thingType = "+TYPE_EVENT+" OR thingType = "+TYPE_LESSON_CHANGE+" OR thingType = "+TYPE_HOMEWORK+") AND thingId IN (SELECT eventId FROM events WHERE profileId = :profileId AND eventDate = :date)")
|
||||
public abstract void setSeenByDate(int profileId, Date date, boolean seen);
|
||||
|
||||
@Query("UPDATE events SET eventBlacklisted = :blacklisted WHERE profileId = :profileId AND eventId = :eventId")
|
||||
public abstract void setBlacklisted(int profileId, long eventId, boolean blacklisted);
|
||||
}
|
||||
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2020-1-6
|
||||
*/
|
||||
package pl.szczodrzynski.edziennik.data.db.dao
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import androidx.room.RawQuery
|
||||
import androidx.room.Transaction
|
||||
import androidx.sqlite.db.SimpleSQLiteQuery
|
||||
import androidx.sqlite.db.SupportSQLiteQuery
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.annotation.SelectiveDao
|
||||
import pl.szczodrzynski.edziennik.annotation.UpdateSelective
|
||||
import pl.szczodrzynski.edziennik.data.db.AppDb
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
@Dao
|
||||
@SelectiveDao(db = AppDb::class)
|
||||
abstract class EventDao : BaseDao<Event, EventFull> {
|
||||
companion object {
|
||||
private const val QUERY = """
|
||||
SELECT
|
||||
*,
|
||||
teachers.teacherName ||" "|| teachers.teacherSurname AS teacherName,
|
||||
eventTypes.eventTypeName AS typeName,
|
||||
eventTypes.eventTypeColor AS typeColor
|
||||
FROM events
|
||||
LEFT JOIN subjects USING(profileId, subjectId)
|
||||
LEFT JOIN teachers USING(profileId, teacherId)
|
||||
LEFT JOIN teams USING(profileId, teamId)
|
||||
LEFT JOIN eventTypes USING(profileId, eventType)
|
||||
LEFT JOIN metadata ON eventId = thingId AND (thingType = ${Metadata.TYPE_EVENT} OR thingType = ${Metadata.TYPE_HOMEWORK}) AND metadata.profileId = events.profileId
|
||||
"""
|
||||
|
||||
private const val ORDER_BY = """GROUP BY eventId ORDER BY eventDate, eventTime, addedDate ASC"""
|
||||
private const val NOT_BLACKLISTED = """events.eventBlacklisted = 0"""
|
||||
private const val NOT_DONE = """events.eventIsDone = 0"""
|
||||
}
|
||||
|
||||
private val selective by lazy { EventDaoSelective(App.db) }
|
||||
|
||||
@RawQuery(observedEntities = [Event::class])
|
||||
abstract override fun getRaw(query: SupportSQLiteQuery): LiveData<List<EventFull>>
|
||||
|
||||
// SELECTIVE UPDATE
|
||||
@UpdateSelective(primaryKeys = ["profileId", "eventId"], skippedColumns = ["eventIsDone", "eventBlacklisted", "homeworkBody", "attachmentIds", "attachmentNames"])
|
||||
override fun update(item: Event) = selective.update(item)
|
||||
override fun updateAll(items: List<Event>) = selective.updateAll(items)
|
||||
|
||||
// CLEAR
|
||||
@Query("DELETE FROM events WHERE profileId = :profileId")
|
||||
abstract override fun clear(profileId: Int)
|
||||
|
||||
// GET ALL - LIVE DATA
|
||||
fun getAll(profileId: Int) =
|
||||
getRaw("$QUERY WHERE $NOT_BLACKLISTED AND events.profileId = $profileId $ORDER_BY")
|
||||
fun getAllByType(profileId: Int, type: Long, filter: String = "1") =
|
||||
getRaw("$QUERY WHERE $NOT_BLACKLISTED AND events.profileId = $profileId AND eventType = $type AND $filter $ORDER_BY")
|
||||
fun getAllByDate(profileId: Int, date: Date) =
|
||||
getRaw("$QUERY WHERE $NOT_BLACKLISTED AND events.profileId = $profileId AND eventDate = '${date.stringY_m_d}' $ORDER_BY")
|
||||
fun getAllByDateTime(profileId: Int, date: Date, time: Time) =
|
||||
getRaw("$QUERY WHERE $NOT_BLACKLISTED AND events.profileId = $profileId AND eventDate = '${date.stringY_m_d}' AND eventTime = '${time.stringValue}'")
|
||||
fun getNearestNotDone(profileId: Int, today: Date, limit: Int) =
|
||||
getRaw("$QUERY WHERE $NOT_BLACKLISTED AND $NOT_DONE AND events.profileId = $profileId AND eventDate >= '${today.stringY_m_d}' $ORDER_BY LIMIT $limit")
|
||||
|
||||
// GET ALL - NOW
|
||||
fun getAllNow(profileId: Int) =
|
||||
getRawNow("$QUERY WHERE $NOT_BLACKLISTED AND events.profileId = $profileId $ORDER_BY")
|
||||
fun getNotNotifiedNow() =
|
||||
getRawNow("$QUERY WHERE $NOT_BLACKLISTED AND notified = 0 $ORDER_BY")
|
||||
fun getNotNotifiedNow(profileId: Int) =
|
||||
getRawNow("$QUERY WHERE $NOT_BLACKLISTED AND events.profileId = $profileId AND notified = 0 $ORDER_BY")
|
||||
fun getAllByDateNow(profileId: Int, date: Date) =
|
||||
getRawNow("$QUERY WHERE $NOT_BLACKLISTED AND events.profileId = $profileId AND eventDate = '${date.stringY_m_d}' $ORDER_BY")
|
||||
|
||||
// GET ONE - NOW
|
||||
fun getByIdNow(profileId: Int, id: Long) =
|
||||
getOneNow("$QUERY WHERE events.profileId = $profileId AND eventId = $id")
|
||||
|
||||
|
||||
@Query("SELECT eventId FROM events WHERE profileId = :profileId AND eventBlacklisted = 1")
|
||||
abstract fun getBlacklistedIds(profileId: Int): List<Long>
|
||||
|
||||
@get:Query("SELECT eventId FROM events WHERE eventBlacklisted = 1")
|
||||
abstract val blacklistedIds: List<Long>
|
||||
|
||||
/*@Query("UPDATE events SET eventAddedManually = 1 WHERE profileId = :profileId AND eventDate < :date")
|
||||
abstract fun convertOlderToManual(profileId: Int, date: Date?)
|
||||
|
||||
@Query("DELETE FROM events WHERE teamId = :teamId AND eventId = :id")
|
||||
abstract fun removeByTeamId(teamId: Long, id: Long)
|
||||
|
||||
@Query("DELETE FROM events WHERE profileId = :profileId AND eventAddedManually = 0")
|
||||
abstract fun removeNotManual(profileId: Int)*/
|
||||
|
||||
@RawQuery
|
||||
abstract fun dontKeepFuture(query: SupportSQLiteQuery?): Long
|
||||
|
||||
@Transaction
|
||||
open fun dontKeepFuture(profileId: Int, todayDate: Date, filter: String) {
|
||||
dontKeepFuture(SimpleSQLiteQuery("UPDATE events SET keep = 0 WHERE profileId = " + profileId
|
||||
+ " AND eventAddedManually = 0 AND eventDate >= '" + todayDate.stringY_m_d + "'" +
|
||||
" AND " + filter))
|
||||
}
|
||||
|
||||
@Query("UPDATE events SET keep = 0 WHERE profileId = :profileId AND eventAddedManually = 0 AND eventDate >= :todayDate AND eventType = :type")
|
||||
abstract fun dontKeepFutureWithType(profileId: Int, todayDate: Date, type: Long)
|
||||
|
||||
@Query("UPDATE events SET keep = 0 WHERE profileId = :profileId AND eventAddedManually = 0 AND eventDate >= :todayDate AND eventType != :exceptType")
|
||||
abstract fun dontKeepFutureExceptType(profileId: Int, todayDate: Date, exceptType: Long)
|
||||
|
||||
@Transaction
|
||||
open fun dontKeepFutureExceptTypes(profileId: Int, todayDate: Date, exceptTypes: List<Long>) {
|
||||
dontKeepFuture(profileId, todayDate, "eventType NOT IN " + exceptTypes.toString().replace('[', '(').replace(']', ')'))
|
||||
}
|
||||
|
||||
@Query("UPDATE metadata SET seen = :seen WHERE profileId = :profileId AND (thingType = " + Metadata.TYPE_EVENT + " OR thingType = " + Metadata.TYPE_LESSON_CHANGE + " OR thingType = " + Metadata.TYPE_HOMEWORK + ") AND thingId IN (SELECT eventId FROM events WHERE profileId = :profileId AND eventDate = :date)")
|
||||
abstract fun setSeenByDate(profileId: Int, date: Date, seen: Boolean)
|
||||
|
||||
@Query("UPDATE events SET eventBlacklisted = :blacklisted WHERE profileId = :profileId AND eventId = :eventId")
|
||||
abstract fun setBlacklisted(profileId: Int, eventId: Long, blacklisted: Boolean)
|
||||
|
||||
@Query("DELETE FROM events WHERE profileId = :profileId AND eventId = :id")
|
||||
abstract fun remove(profileId: Int, id: Long)
|
||||
|
||||
@Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = :thingType AND thingId = :thingId")
|
||||
abstract fun removeMetadata(profileId: Int, thingType: Int, thingId: Long)
|
||||
|
||||
@Transaction
|
||||
open fun remove(profileId: Int, type: Long, id: Long) {
|
||||
remove(profileId, id)
|
||||
removeMetadata(profileId, if (type == Event.TYPE_HOMEWORK) Metadata.TYPE_HOMEWORK else Metadata.TYPE_EVENT, id)
|
||||
}
|
||||
|
||||
@Transaction
|
||||
open fun remove(event: Event) {
|
||||
remove(event.profileId, event.type, event.id)
|
||||
}
|
||||
|
||||
@Transaction
|
||||
open fun remove(profileId: Int, event: Event) {
|
||||
remove(profileId, event.type, event.id)
|
||||
}
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2020-1-6
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.db.dao;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.EventType;
|
||||
|
||||
@Dao
|
||||
public interface EventTypeDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
void add(EventType gradeCategory);
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
void addAll(List<EventType> gradeCategoryList);
|
||||
|
||||
@Query("DELETE FROM eventTypes WHERE profileId = :profileId")
|
||||
void clear(int profileId);
|
||||
|
||||
@Query("SELECT * FROM eventTypes WHERE profileId = :profileId AND eventType = :typeId")
|
||||
EventType getByIdNow(int profileId, long typeId);
|
||||
|
||||
@Query("SELECT * FROM eventTypes WHERE profileId = :profileId")
|
||||
LiveData<List<EventType>> getAll(int profileId);
|
||||
|
||||
@Query("SELECT * FROM eventTypes WHERE profileId = :profileId")
|
||||
List<EventType> getAllNow(int profileId);
|
||||
|
||||
@Query("SELECT * FROM eventTypes")
|
||||
List<EventType> getAllNow();
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2020-1-6
|
||||
*/
|
||||
package pl.szczodrzynski.edziennik.data.db.dao
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_CLASS_EVENT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_DEFAULT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_ESSAY
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_EXAM
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_EXCURSION
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_INFORMATION
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_PROJECT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_PT_MEETING
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_READING
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_SHORT_QUIZ
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_CLASS_EVENT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_DEFAULT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_ESSAY
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_EXAM
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_EXCURSION
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_INFORMATION
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_PROJECT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_PT_MEETING
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_READING
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_SHORT_QUIZ
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.EventType
|
||||
|
||||
@Dao
|
||||
abstract class EventTypeDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract fun add(eventType: EventType)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract fun addAll(eventTypeList: List<EventType>)
|
||||
|
||||
@Query("DELETE FROM eventTypes WHERE profileId = :profileId")
|
||||
abstract fun clear(profileId: Int)
|
||||
|
||||
@Query("SELECT * FROM eventTypes WHERE profileId = :profileId AND eventType = :typeId")
|
||||
abstract fun getByIdNow(profileId: Int, typeId: Long): EventType?
|
||||
|
||||
@Query("SELECT * FROM eventTypes WHERE profileId = :profileId")
|
||||
abstract fun getAll(profileId: Int): LiveData<List<EventType>>
|
||||
|
||||
@Query("SELECT * FROM eventTypes WHERE profileId = :profileId")
|
||||
abstract fun getAllNow(profileId: Int): List<EventType>
|
||||
|
||||
@get:Query("SELECT * FROM eventTypes")
|
||||
abstract val allNow: List<EventType>
|
||||
|
||||
fun addDefaultTypes(context: Context, profileId: Int): List<EventType> {
|
||||
val typeList = listOf(
|
||||
EventType(profileId, TYPE_HOMEWORK, context.getString(R.string.event_type_homework), COLOR_HOMEWORK),
|
||||
EventType(profileId, TYPE_DEFAULT, context.getString(R.string.event_other), COLOR_DEFAULT),
|
||||
EventType(profileId, TYPE_EXAM, context.getString(R.string.event_exam), COLOR_EXAM),
|
||||
EventType(profileId, TYPE_SHORT_QUIZ, context.getString(R.string.event_short_quiz), COLOR_SHORT_QUIZ),
|
||||
EventType(profileId, TYPE_ESSAY, context.getString(R.string.event_essay), COLOR_ESSAY),
|
||||
EventType(profileId, TYPE_PROJECT, context.getString(R.string.event_project), COLOR_PROJECT),
|
||||
EventType(profileId, TYPE_PT_MEETING, context.getString(R.string.event_pt_meeting), COLOR_PT_MEETING),
|
||||
EventType(profileId, TYPE_EXCURSION, context.getString(R.string.event_excursion), COLOR_EXCURSION),
|
||||
EventType(profileId, TYPE_READING, context.getString(R.string.event_reading), COLOR_READING),
|
||||
EventType(profileId, TYPE_CLASS_EVENT, context.getString(R.string.event_class_event), COLOR_CLASS_EVENT),
|
||||
EventType(profileId, TYPE_INFORMATION, context.getString(R.string.event_information), COLOR_INFORMATION)
|
||||
)
|
||||
addAll(typeList)
|
||||
return typeList
|
||||
}
|
||||
}
|
@ -78,8 +78,8 @@ public abstract class MetadataDao {
|
||||
}
|
||||
}
|
||||
if (o instanceof Event) {
|
||||
if (add(new Metadata(profileId, ((Event) o).type == Event.TYPE_HOMEWORK ? TYPE_HOMEWORK : TYPE_EVENT, ((Event) o).id, seen, false, 0)) == -1) {
|
||||
updateSeen(profileId, ((Event) o).type == Event.TYPE_HOMEWORK ? TYPE_HOMEWORK : TYPE_EVENT, ((Event) o).id, seen);
|
||||
if (add(new Metadata(profileId, ((Event) o).getType() == Event.TYPE_HOMEWORK ? TYPE_HOMEWORK : TYPE_EVENT, ((Event) o).getId(), seen, false, 0)) == -1) {
|
||||
updateSeen(profileId, ((Event) o).getType() == Event.TYPE_HOMEWORK ? TYPE_HOMEWORK : TYPE_EVENT, ((Event) o).getId(), seen);
|
||||
}
|
||||
}
|
||||
if (o instanceof LessonFull) {
|
||||
@ -117,8 +117,8 @@ public abstract class MetadataDao {
|
||||
}
|
||||
}
|
||||
if (o instanceof Event) {
|
||||
if (add(new Metadata(profileId, ((Event) o).type == Event.TYPE_HOMEWORK ? TYPE_HOMEWORK : TYPE_EVENT, ((Event) o).id, false, notified, 0)) == -1) {
|
||||
updateNotified(profileId, ((Event) o).type == Event.TYPE_HOMEWORK ? TYPE_HOMEWORK : TYPE_EVENT, ((Event) o).id, notified);
|
||||
if (add(new Metadata(profileId, ((Event) o).getType() == Event.TYPE_HOMEWORK ? TYPE_HOMEWORK : TYPE_EVENT, ((Event) o).getId(), false, notified, 0)) == -1) {
|
||||
updateNotified(profileId, ((Event) o).getType() == Event.TYPE_HOMEWORK ? TYPE_HOMEWORK : TYPE_EVENT, ((Event) o).getId(), notified);
|
||||
}
|
||||
}
|
||||
if (o instanceof LessonFull) {
|
||||
@ -141,9 +141,9 @@ public abstract class MetadataDao {
|
||||
@Transaction
|
||||
public void setBoth(int profileId, Event o, boolean seen, boolean notified, long addedDate) {
|
||||
if (o != null) {
|
||||
if (add(new Metadata(profileId, o.type == Event.TYPE_HOMEWORK ? TYPE_HOMEWORK : TYPE_EVENT, o.id, seen, notified, addedDate)) == -1) {
|
||||
updateSeen(profileId, o.type == Event.TYPE_HOMEWORK ? TYPE_HOMEWORK : TYPE_EVENT, o.id, seen);
|
||||
updateNotified(profileId, o.type == Event.TYPE_HOMEWORK ? TYPE_HOMEWORK : TYPE_EVENT, o.id, notified);
|
||||
if (add(new Metadata(profileId, o.getType() == Event.TYPE_HOMEWORK ? TYPE_HOMEWORK : TYPE_EVENT, o.getId(), seen, notified, addedDate)) == -1) {
|
||||
updateSeen(profileId, o.getType() == Event.TYPE_HOMEWORK ? TYPE_HOMEWORK : TYPE_EVENT, o.getId(), seen);
|
||||
updateNotified(profileId, o.getType() == Event.TYPE_HOMEWORK ? TYPE_HOMEWORK : TYPE_EVENT, o.getId(), notified);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +49,17 @@ interface TeacherAbsenceDao {
|
||||
"AND :date BETWEEN teacherAbsenceDateFrom AND teacherAbsenceDateTo")
|
||||
fun getAllByDateNow(profileId: Int, date: Date): List<TeacherAbsenceFull>
|
||||
|
||||
@Query("""
|
||||
SELECT *,
|
||||
teachers.teacherName || ' ' || teachers.teacherSurname as teacherFullName
|
||||
FROM teacherAbsence
|
||||
LEFT JOIN teachers USING (profileId, teacherId)
|
||||
LEFT JOIN metadata ON teacherAbsenceId = thingId AND metadata.thingType = ${Metadata.TYPE_TEACHER_ABSENCE}
|
||||
AND teachers.profileId = metadata.profileId WHERE metadata.notified = 0
|
||||
ORDER BY addedDate DESC
|
||||
""")
|
||||
fun getNotNotifiedNow(): List<TeacherAbsenceFull>
|
||||
|
||||
@Query("DELETE FROM teacherAbsence WHERE profileId = :profileId")
|
||||
fun clear(profileId: Int)
|
||||
}
|
||||
|
@ -1,161 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2020-1-6
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.db.entity;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.Ignore;
|
||||
import androidx.room.Index;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
|
||||
@Entity(tableName = "events",
|
||||
primaryKeys = {"profileId", "eventId"},
|
||||
indices = {@Index(value = {"profileId", "eventDate", "eventStartTime"}), @Index(value = {"profileId", "eventType"})})
|
||||
public class Event {
|
||||
public int profileId;
|
||||
|
||||
@ColumnInfo(name = "eventId")
|
||||
public long id;
|
||||
|
||||
@ColumnInfo(name = "eventDate")
|
||||
public Date eventDate;
|
||||
@ColumnInfo(name = "eventStartTime")
|
||||
@Nullable
|
||||
public Time startTime; // null for allDay
|
||||
@ColumnInfo(name = "eventTopic")
|
||||
public String topic;
|
||||
@ColumnInfo(name = "eventColor")
|
||||
public int color = -1;
|
||||
public static final long TYPE_UNDEFINED = -2;
|
||||
public static final long TYPE_HOMEWORK = -1;
|
||||
public static final long TYPE_DEFAULT = 0;
|
||||
public static final long TYPE_EXAM = 1;
|
||||
public static final long TYPE_SHORT_QUIZ = 2;
|
||||
public static final long TYPE_ESSAY = 3;
|
||||
public static final long TYPE_PROJECT = 4;
|
||||
public static final long TYPE_PT_MEETING = 5;
|
||||
public static final long TYPE_EXCURSION = 6;
|
||||
public static final long TYPE_READING = 7;
|
||||
public static final long TYPE_CLASS_EVENT = 8;
|
||||
public static final long TYPE_INFORMATION = 9;
|
||||
public static final long TYPE_TEACHER_ABSENCE = 10;
|
||||
public static final int COLOR_HOMEWORK = 0xff795548;
|
||||
public static final int COLOR_DEFAULT = 0xffffc107;
|
||||
public static final int COLOR_EXAM = 0xfff44336;
|
||||
public static final int COLOR_SHORT_QUIZ = 0xff76ff03;
|
||||
public static final int COLOR_ESSAY = 0xFF4050B5;
|
||||
public static final int COLOR_PROJECT = 0xFF673AB7;
|
||||
public static final int COLOR_PT_MEETING = 0xff90caf9;
|
||||
public static final int COLOR_EXCURSION = 0xFF4CAF50;
|
||||
public static final int COLOR_READING = 0xFFFFEB3B;
|
||||
public static final int COLOR_CLASS_EVENT = 0xff388e3c;
|
||||
public static final int COLOR_INFORMATION = 0xff039be5;
|
||||
public static final int COLOR_TEACHER_ABSENCE = 0xff039be5;
|
||||
@ColumnInfo(name = "eventType")
|
||||
public long type = TYPE_DEFAULT;
|
||||
@ColumnInfo(name = "eventAddedManually")
|
||||
public boolean addedManually;
|
||||
@ColumnInfo(name = "eventSharedBy")
|
||||
public String sharedBy = null;
|
||||
@ColumnInfo(name = "eventSharedByName")
|
||||
public String sharedByName = null;
|
||||
@ColumnInfo(name = "eventBlacklisted")
|
||||
public boolean blacklisted = false;
|
||||
|
||||
|
||||
public long teacherId;
|
||||
public long subjectId;
|
||||
public long teamId;
|
||||
|
||||
@Ignore
|
||||
public Event() {}
|
||||
|
||||
public Event(int profileId, long id, Date eventDate, @Nullable Time startTime, String topic, int color, long type, boolean addedManually, long teacherId, long subjectId, long teamId)
|
||||
{
|
||||
this.profileId = profileId;
|
||||
this.id = id;
|
||||
this.eventDate = eventDate;
|
||||
this.startTime = startTime;
|
||||
this.topic = topic;
|
||||
this.color = color;
|
||||
this.type = type;
|
||||
this.addedManually = addedManually;
|
||||
this.teacherId = teacherId;
|
||||
this.subjectId = subjectId;
|
||||
this.teamId = teamId;
|
||||
}
|
||||
|
||||
@Ignore
|
||||
public EventFull withMetadata(Metadata metadata) {
|
||||
return new EventFull(this, metadata);
|
||||
}
|
||||
|
||||
@Ignore
|
||||
public Calendar getStartTimeCalendar() {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.set(
|
||||
eventDate.year,
|
||||
eventDate.month - 1,
|
||||
eventDate.day,
|
||||
(startTime == null) ? 0 : startTime.hour,
|
||||
(startTime == null) ? 0 : startTime.minute,
|
||||
(startTime == null) ? 0 : startTime.second
|
||||
);
|
||||
return c;
|
||||
}
|
||||
|
||||
@Ignore
|
||||
public Calendar getEndTimeCalendar() {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.setTimeInMillis(getStartTimeCalendar().getTimeInMillis() + (45 * 60 * 1000));
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event clone() {
|
||||
Event event = new Event(
|
||||
profileId,
|
||||
id,
|
||||
eventDate.clone(),
|
||||
startTime == null ? null : startTime.clone(),
|
||||
topic,
|
||||
color,
|
||||
type,
|
||||
addedManually,
|
||||
subjectId,
|
||||
teacherId,
|
||||
teamId
|
||||
);
|
||||
event.sharedBy = sharedBy;
|
||||
event.sharedByName = sharedByName;
|
||||
event.blacklisted = blacklisted;
|
||||
return event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Event{" +
|
||||
"profileId=" + profileId +
|
||||
", id=" + id +
|
||||
", eventDate=" + eventDate +
|
||||
", startTime=" + startTime +
|
||||
", topic='" + topic + '\'' +
|
||||
", color=" + color +
|
||||
", type=" + type +
|
||||
", addedManually=" + addedManually +
|
||||
", sharedBy='" + sharedBy + '\'' +
|
||||
", sharedByName='" + sharedByName + '\'' +
|
||||
", teacherId=" + teacherId +
|
||||
", subjectId=" + subjectId +
|
||||
", teamId=" + teamId +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2020-1-6
|
||||
*/
|
||||
package pl.szczodrzynski.edziennik.data.db.entity
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.Index
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import pl.szczodrzynski.edziennik.MINUTE
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import java.util.*
|
||||
|
||||
@Entity(tableName = "events",
|
||||
primaryKeys = ["profileId", "eventId"],
|
||||
indices = [
|
||||
Index(value = ["profileId", "eventDate", "eventTime"]),
|
||||
Index(value = ["profileId", "eventType"])
|
||||
])
|
||||
open class Event(
|
||||
/* This needs to be mutable: see SzkolnyApi.getEvents() */
|
||||
var profileId: Int,
|
||||
@ColumnInfo(name = "eventId")
|
||||
var id: Long,
|
||||
@ColumnInfo(name = "eventDate")
|
||||
@SerializedName("eventDate")
|
||||
var date: Date,
|
||||
@ColumnInfo(name = "eventTime")
|
||||
@SerializedName("startTime")
|
||||
var time: Time?,
|
||||
|
||||
@ColumnInfo(name = "eventTopic")
|
||||
var topic: String,
|
||||
@ColumnInfo(name = "eventColor")
|
||||
var color: Int?,
|
||||
@ColumnInfo(name = "eventType")
|
||||
var type: Long,
|
||||
|
||||
var teacherId: Long,
|
||||
var subjectId: Long,
|
||||
var teamId: Long
|
||||
) : Keepable() {
|
||||
companion object {
|
||||
const val TYPE_UNDEFINED = -2L
|
||||
const val TYPE_HOMEWORK = -1L
|
||||
const val TYPE_DEFAULT = 0L
|
||||
const val TYPE_EXAM = 1L
|
||||
const val TYPE_SHORT_QUIZ = 2L
|
||||
const val TYPE_ESSAY = 3L
|
||||
const val TYPE_PROJECT = 4L
|
||||
const val TYPE_PT_MEETING = 5L
|
||||
const val TYPE_EXCURSION = 6L
|
||||
const val TYPE_READING = 7L
|
||||
const val TYPE_CLASS_EVENT = 8L
|
||||
const val TYPE_INFORMATION = 9L
|
||||
const val TYPE_TEACHER_ABSENCE = 10L
|
||||
const val COLOR_HOMEWORK = 0xff795548.toInt()
|
||||
const val COLOR_DEFAULT = 0xffffc107.toInt()
|
||||
const val COLOR_EXAM = 0xfff44336.toInt()
|
||||
const val COLOR_SHORT_QUIZ = 0xff76ff03.toInt()
|
||||
const val COLOR_ESSAY = 0xFF4050B5.toInt()
|
||||
const val COLOR_PROJECT = 0xFF673AB7.toInt()
|
||||
const val COLOR_PT_MEETING = 0xff90caf9.toInt()
|
||||
const val COLOR_EXCURSION = 0xFF4CAF50.toInt()
|
||||
const val COLOR_READING = 0xFFFFEB3B.toInt()
|
||||
const val COLOR_CLASS_EVENT = 0xff388e3c.toInt()
|
||||
const val COLOR_INFORMATION = 0xff039be5.toInt()
|
||||
const val COLOR_TEACHER_ABSENCE = 0xff039be5.toInt()
|
||||
}
|
||||
|
||||
@ColumnInfo(name = "eventAddedManually")
|
||||
var addedManually: Boolean = false
|
||||
@ColumnInfo(name = "eventSharedBy")
|
||||
var sharedBy: String? = null
|
||||
@ColumnInfo(name = "eventSharedByName")
|
||||
var sharedByName: String? = null
|
||||
@ColumnInfo(name = "eventBlacklisted")
|
||||
var blacklisted: Boolean = false
|
||||
@ColumnInfo(name = "eventIsDone")
|
||||
var isDone: Boolean = false
|
||||
|
||||
var homeworkBody: String? = null
|
||||
var attachmentIds: List<Long>? = null
|
||||
var attachmentNames: List<String>? = null
|
||||
|
||||
@Ignore
|
||||
var showAsUnseen = false
|
||||
|
||||
val startTimeCalendar: Calendar
|
||||
get() = Calendar.getInstance().also { it.set(
|
||||
date.year,
|
||||
date.month - 1,
|
||||
date.day,
|
||||
time?.hour ?: 0,
|
||||
time?.minute ?: 0,
|
||||
time?.second ?: 0
|
||||
) }
|
||||
|
||||
val endTimeCalendar: Calendar
|
||||
get() = startTimeCalendar.also {
|
||||
it.timeInMillis += 45 * MINUTE * 1000
|
||||
}
|
||||
|
||||
@Ignore
|
||||
fun withMetadata(metadata: Metadata) = EventFull(this, metadata)
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-30.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.db.entity
|
||||
|
||||
abstract class Keepable {
|
||||
var keep: Boolean = true
|
||||
}
|
@ -52,6 +52,7 @@ data class Notification(
|
||||
const val TYPE_NEW_ANNOUNCEMENT = 15
|
||||
const val TYPE_FEEDBACK_MESSAGE = 16
|
||||
const val TYPE_AUTO_ARCHIVING = 17
|
||||
const val TYPE_TEACHER_ABSENCE = 19
|
||||
|
||||
fun buildId(profileId: Int, type: Int, itemId: Long): Long {
|
||||
return 1000000000000 + profileId*10000000000 + type*100000000 + itemId;
|
||||
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2020-1-6
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.db.full;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata;
|
||||
|
||||
public class EventFull extends Event {
|
||||
public String typeName = "";
|
||||
public int typeColor = -1;
|
||||
|
||||
public String teacherFullName = "";
|
||||
|
||||
public String subjectLongName = "";
|
||||
public String subjectShortName = "";
|
||||
|
||||
public String teamName = "";
|
||||
public String teamCode = null;
|
||||
|
||||
// metadata
|
||||
public boolean seen;
|
||||
public boolean notified;
|
||||
public long addedDate;
|
||||
|
||||
public EventFull() {}
|
||||
|
||||
public EventFull(Event event) {
|
||||
super(
|
||||
event.profileId,
|
||||
event.id,
|
||||
event.eventDate.clone(),
|
||||
event.startTime == null ? null : event.startTime.clone(),
|
||||
event.topic,
|
||||
event.color,
|
||||
event.type,
|
||||
event.addedManually,
|
||||
event.teacherId,
|
||||
event.subjectId,
|
||||
event.teamId
|
||||
);
|
||||
|
||||
this.sharedBy = event.sharedBy;
|
||||
this.sharedByName = event.sharedByName;
|
||||
this.blacklisted = event.blacklisted;
|
||||
}
|
||||
public EventFull(EventFull event) {
|
||||
super(
|
||||
event.profileId,
|
||||
event.id,
|
||||
event.eventDate.clone(),
|
||||
event.startTime == null ? null : event.startTime.clone(),
|
||||
event.topic,
|
||||
event.color,
|
||||
event.type,
|
||||
event.addedManually,
|
||||
event.teacherId,
|
||||
event.subjectId,
|
||||
event.teamId
|
||||
);
|
||||
|
||||
this.sharedBy = event.sharedBy;
|
||||
this.sharedByName = event.sharedByName;
|
||||
this.blacklisted = event.blacklisted;
|
||||
this.typeName = event.typeName;
|
||||
this.typeColor = event.typeColor;
|
||||
this.teacherFullName = event.teacherFullName;
|
||||
this.subjectLongName = event.subjectLongName;
|
||||
this.subjectShortName = event.subjectShortName;
|
||||
this.teamName = event.teamName;
|
||||
this.teamCode = event.teamCode;
|
||||
this.seen = event.seen;
|
||||
this.notified = event.notified;
|
||||
this.addedDate = event.addedDate;
|
||||
}
|
||||
|
||||
public EventFull(Event event, Metadata metadata) {
|
||||
this(event);
|
||||
|
||||
this.seen = metadata.seen;
|
||||
this.notified = metadata.notified;
|
||||
this.addedDate = metadata.addedDate;
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return color == -1 ? typeColor : color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EventFull{" +
|
||||
"profileId=" + profileId +
|
||||
", id=" + id +
|
||||
", eventDate=" + eventDate +
|
||||
", startTime=" + startTime +
|
||||
", topic='" + topic + '\'' +
|
||||
", color=" + color +
|
||||
", type=" + type +
|
||||
", addedManually=" + addedManually +
|
||||
", sharedBy='" + sharedBy + '\'' +
|
||||
", sharedByName='" + sharedByName + '\'' +
|
||||
", blacklisted=" + blacklisted +
|
||||
", teacherId=" + teacherId +
|
||||
", subjectId=" + subjectId +
|
||||
", teamId=" + teamId +
|
||||
", typeName='" + typeName + '\'' +
|
||||
", teacherFullName='" + teacherFullName + '\'' +
|
||||
", subjectLongName='" + subjectLongName + '\'' +
|
||||
", subjectShortName='" + subjectShortName + '\'' +
|
||||
", teamName='" + teamName + '\'' +
|
||||
", seen=" + seen +
|
||||
", notified=" + notified +
|
||||
", addedDate=" + addedDate +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2020-1-6
|
||||
*/
|
||||
package pl.szczodrzynski.edziennik.data.db.full
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class EventFull(
|
||||
profileId: Int, id: Long, date: Date, time: Time?,
|
||||
topic: String, color: Int?, type: Long,
|
||||
teacherId: Long, subjectId: Long, teamId: Long
|
||||
) : Event(
|
||||
profileId, id, date, time,
|
||||
topic, color, type,
|
||||
teacherId, subjectId, teamId
|
||||
) {
|
||||
constructor(event: Event, metadata: Metadata? = null) : this(
|
||||
event.profileId, event.id, event.date, event.time,
|
||||
event.topic, event.color, event.type,
|
||||
event.teacherId, event.subjectId, event.teamId) {
|
||||
event.let {
|
||||
addedManually = it.addedManually
|
||||
sharedBy = it.sharedBy
|
||||
sharedByName = it.sharedByName
|
||||
blacklisted = it.blacklisted
|
||||
homeworkBody = it.homeworkBody
|
||||
attachmentIds = it.attachmentIds
|
||||
attachmentNames = it.attachmentNames
|
||||
}
|
||||
metadata?.let {
|
||||
seen = it.seen
|
||||
notified = it.notified
|
||||
addedDate = it.addedDate
|
||||
}
|
||||
}
|
||||
|
||||
var typeName: String? = null
|
||||
var typeColor: Int? = null
|
||||
|
||||
var teacherName: String? = null
|
||||
var subjectLongName: String? = null
|
||||
var subjectShortName: String? = null
|
||||
var teamName: String? = null
|
||||
var teamCode: String? = null
|
||||
// metadata
|
||||
var seen = false
|
||||
var notified = false
|
||||
var addedDate: Long = 0
|
||||
|
||||
val eventColor
|
||||
get() = color ?: typeColor ?: 0xff2196f3.toInt()
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-27.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.db.migration
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
class Migration80 : Migration(79, 80) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
// The Homework Update
|
||||
database.execSQL("ALTER TABLE events RENAME TO _events;")
|
||||
database.execSQL("""CREATE TABLE events (
|
||||
profileId INTEGER NOT NULL,
|
||||
eventId INTEGER NOT NULL,
|
||||
eventDate TEXT NOT NULL,
|
||||
eventTime TEXT,
|
||||
eventTopic TEXT NOT NULL,
|
||||
eventColor INTEGER,
|
||||
eventType INTEGER NOT NULL,
|
||||
teacherId INTEGER NOT NULL,
|
||||
subjectId INTEGER NOT NULL,
|
||||
teamId INTEGER NOT NULL,
|
||||
eventAddedManually INTEGER NOT NULL DEFAULT 0,
|
||||
eventSharedBy TEXT DEFAULT NULL,
|
||||
eventSharedByName TEXT DEFAULT NULL,
|
||||
eventBlacklisted INTEGER NOT NULL DEFAULT 0,
|
||||
homeworkBody TEXT DEFAULT NULL,
|
||||
attachmentIds TEXT DEFAULT NULL,
|
||||
attachmentNames TEXT DEFAULT NULL,
|
||||
PRIMARY KEY(profileId, eventId)
|
||||
)""")
|
||||
database.execSQL("DROP INDEX IF EXISTS index_events_profileId_eventDate_eventStartTime")
|
||||
database.execSQL("DROP INDEX IF EXISTS index_events_profileId_eventType")
|
||||
database.execSQL("CREATE INDEX index_events_profileId_eventDate_eventTime ON events (profileId, eventDate, eventTime)")
|
||||
database.execSQL("CREATE INDEX index_events_profileId_eventType ON events (profileId, eventType)")
|
||||
database.execSQL("""
|
||||
INSERT INTO events (profileId, eventId, eventDate, eventTime, eventTopic, eventColor, eventType, teacherId, subjectId, teamId, eventAddedManually, eventSharedBy, eventSharedByName, eventBlacklisted)
|
||||
SELECT profileId, eventId, eventDate, eventStartTime, eventTopic,
|
||||
CASE eventColor WHEN -1 THEN NULL ELSE eventColor END,
|
||||
eventType, teacherId, subjectId, teamId,
|
||||
eventAddedManually, eventSharedBy, eventSharedByName, eventBlacklisted
|
||||
FROM _events
|
||||
""")
|
||||
database.execSQL("DROP TABLE _events")
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package pl.szczodrzynski.edziennik.data.db.migration
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
|
||||
class Migration81 : Migration(80, 81) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("UPDATE metadata SET seen = 1, notified = 1 WHERE thingType = ${Metadata.TYPE_TEACHER_ABSENCE}")
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package pl.szczodrzynski.edziennik.data.db.migration
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
class Migration82 : Migration(81, 82) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE events ADD COLUMN eventIsDone INTEGER DEFAULT 0 NOT NULL")
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-30.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.db.migration
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
class Migration83 : Migration(82, 83) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE events ADD COLUMN keep INTEGER NOT NULL DEFAULT 1")
|
||||
}
|
||||
}
|
@ -105,18 +105,19 @@ class SzkolnyAppFirebase(val app: App, val profiles: List<Profile>, val message:
|
||||
if (profile.registration != Profile.REGISTRATION_ENABLED)
|
||||
return@forEach
|
||||
val event = Event(
|
||||
team.profileId,
|
||||
json.getLong("id") ?: return,
|
||||
json.getInt("eventDate")?.let { Date.fromValue(it) } ?: return,
|
||||
json.getInt("startTime")?.let { Time.fromValue(it) },
|
||||
json.getString("topic") ?: "",
|
||||
json.getInt("color") ?: -1,
|
||||
json.getLong("type") ?: 0,
|
||||
true,
|
||||
json.getLong("teacherId") ?: -1,
|
||||
json.getLong("subjectId") ?: -1,
|
||||
team.id
|
||||
profileId = team.profileId,
|
||||
id = json.getLong("id") ?: return,
|
||||
date = json.getInt("eventDate")?.let { Date.fromValue(it) } ?: return,
|
||||
time = json.getInt("startTime")?.let { Time.fromValue(it) },
|
||||
topic = json.getString("topic") ?: "",
|
||||
color = json.getInt("color"),
|
||||
type = json.getLong("type") ?: 0,
|
||||
teacherId = json.getLong("teacherId") ?: -1,
|
||||
subjectId = json.getLong("subjectId") ?: -1,
|
||||
teamId = team.id
|
||||
)
|
||||
if (event.color == -1)
|
||||
event.color = null
|
||||
|
||||
event.sharedBy = json.getString("sharedBy")
|
||||
event.sharedByName = json.getString("sharedByName")
|
||||
@ -144,14 +145,14 @@ class SzkolnyAppFirebase(val app: App, val profiles: List<Profile>, val message:
|
||||
profileName = profile.name,
|
||||
viewId = if (event.type == Event.TYPE_HOMEWORK) MainActivity.DRAWER_ITEM_HOMEWORK else MainActivity.DRAWER_ITEM_AGENDA,
|
||||
addedDate = metadata.addedDate
|
||||
).addExtra("eventId", event.id).addExtra("eventDate", event.eventDate.value.toLong())
|
||||
).addExtra("eventId", event.id).addExtra("eventDate", event.date.value.toLong())
|
||||
notificationList += notification
|
||||
}
|
||||
|
||||
events += event
|
||||
metadataList += metadata
|
||||
}
|
||||
app.db.eventDao().addAll(events)
|
||||
app.db.eventDao().upsertAll(events)
|
||||
app.db.metadataDao().addAllReplace(metadataList)
|
||||
if (notificationList.isNotEmpty()) {
|
||||
app.db.notificationDao().addAll(notificationList)
|
||||
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-12-19.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.databinding.TemplateListItemBinding
|
||||
import pl.szczodrzynski.edziennik.onClick
|
||||
|
||||
class TemplateAdapter(
|
||||
val context: Context,
|
||||
val onItemClick: ((item: TemplateItem) -> Unit)? = null,
|
||||
val onItemButtonClick: ((item: TemplateItem) -> Unit)? = null
|
||||
) : RecyclerView.Adapter<TemplateAdapter.ViewHolder>() {
|
||||
|
||||
private val app by lazy { context.applicationContext as App }
|
||||
|
||||
var items = listOf<TemplateItem>()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
val view = TemplateListItemBinding.inflate(inflater, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = items[position]
|
||||
val b = holder.b
|
||||
|
||||
onItemClick?.let { listener ->
|
||||
b.root.onClick { listener(item) }
|
||||
}
|
||||
|
||||
/*b.someButton.visibility = if (buttonVisible) View.VISIBLE else View.GONE
|
||||
onItemButtonClick?.let { listener ->
|
||||
b.someButton.onClick { listener(item) }
|
||||
}*/
|
||||
}
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
class ViewHolder(val b: TemplateListItemBinding) : RecyclerView.ViewHolder(b.root)
|
||||
|
||||
data class TemplateItem(val text: String)
|
||||
}
|
@ -146,6 +146,11 @@ class DayDialog(
|
||||
|
||||
adapter = EventListAdapter(
|
||||
activity,
|
||||
showWeekDay = false,
|
||||
showDate = false,
|
||||
showType = true,
|
||||
showTime = true,
|
||||
showSubject = true,
|
||||
onItemClick = {
|
||||
EventDetailsDialog(
|
||||
activity,
|
||||
|
@ -87,11 +87,11 @@ class EventDetailsDialog(
|
||||
val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity)
|
||||
|
||||
try {
|
||||
b.monthName = app.resources.getStringArray(R.array.months_day_of_array)[event.eventDate.month - 1]
|
||||
b.monthName = app.resources.getStringArray(R.array.months_day_of_array)[event.date.month - 1]
|
||||
}
|
||||
catch (_: Exception) {}
|
||||
|
||||
b.typeColor.background?.setTintColor(event.getColor())
|
||||
b.typeColor.background?.setTintColor(event.eventColor)
|
||||
|
||||
b.details = mutableListOf(
|
||||
event.subjectLongName,
|
||||
@ -102,14 +102,14 @@ class EventDetailsDialog(
|
||||
when (event.sharedBy) {
|
||||
null -> when {
|
||||
event.addedManually -> R.string.event_details_added_by_self_format
|
||||
event.teacherFullName == null -> R.string.event_details_added_by_unknown_format
|
||||
event.teacherName == null -> R.string.event_details_added_by_unknown_format
|
||||
else -> R.string.event_details_added_by_format
|
||||
}
|
||||
"self" -> R.string.event_details_shared_by_self_format
|
||||
else -> R.string.event_details_shared_by_format
|
||||
},
|
||||
Date.fromMillis(event.addedDate).formattedString,
|
||||
event.sharedByName ?: event.teacherFullName ?: ""
|
||||
event.sharedByName ?: event.teacherName ?: ""
|
||||
)
|
||||
|
||||
b.editButton.visibility = if (event.addedManually) View.VISIBLE else View.GONE
|
||||
@ -125,7 +125,7 @@ class EventDetailsDialog(
|
||||
|
||||
b.goToTimetableButton.setOnClickListener {
|
||||
dialog.dismiss()
|
||||
val dateStr = event.eventDate?.stringY_m_d ?: return@setOnClickListener
|
||||
val dateStr = event.date.stringY_m_d
|
||||
|
||||
val intent =
|
||||
if (activity is MainActivity && activity.navTargetId == MainActivity.DRAWER_ITEM_TIMETABLE)
|
||||
@ -148,6 +148,10 @@ class EventDetailsDialog(
|
||||
openInCalendar()
|
||||
}
|
||||
|
||||
b.checkDoneButton.setOnLongClickListener {
|
||||
Toast.makeText(activity, R.string.hint_mark_as_done, Toast.LENGTH_SHORT).show()
|
||||
true
|
||||
}
|
||||
b.goToTimetableButton.setOnLongClickListener {
|
||||
Toast.makeText(activity, R.string.hint_go_to_timetable, Toast.LENGTH_SHORT).show()
|
||||
true
|
||||
@ -161,6 +165,14 @@ class EventDetailsDialog(
|
||||
true
|
||||
}
|
||||
|
||||
b.checkDoneButton.isChecked = event.isDone
|
||||
b.checkDoneButton.addOnCheckedChangeListener { _, isChecked ->
|
||||
event.isDone = isChecked
|
||||
launch(Dispatchers.Default) {
|
||||
app.db.eventDao().replace(event)
|
||||
}
|
||||
}
|
||||
|
||||
b.topic.text = event.topic
|
||||
BetterLink.attach(b.topic) {
|
||||
dialog.dismiss()
|
||||
@ -245,7 +257,7 @@ class EventDetailsDialog(
|
||||
}
|
||||
|
||||
private fun openInCalendar() { launch {
|
||||
val title = (event.typeName ?: "") +
|
||||
val title = event.typeName ?: "" +
|
||||
(if (event.typeName.isNotNullNorBlank() && event.subjectLongName.isNotNullNorBlank()) " - " else " ") +
|
||||
(event.subjectLongName ?: "")
|
||||
|
||||
@ -254,12 +266,12 @@ class EventDetailsDialog(
|
||||
putExtra(Events.TITLE, title)
|
||||
putExtra(Events.DESCRIPTION, event.topic)
|
||||
|
||||
if (event.startTime == null) {
|
||||
if (event.time == null) {
|
||||
putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, true)
|
||||
putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, event.eventDate.inMillis)
|
||||
putExtra(CalendarContract.EXTRA_EVENT_END_TIME, event.eventDate.inMillis)
|
||||
putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, event.date.inMillis)
|
||||
putExtra(CalendarContract.EXTRA_EVENT_END_TIME, event.date.inMillis)
|
||||
} else {
|
||||
val startTime = event.eventDate.combineWith(event.startTime)
|
||||
val startTime = event.date.combineWith(event.time)
|
||||
val endTime = startTime + 45 * 60 * 1000 /* 45 min */
|
||||
|
||||
putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, false)
|
||||
|
@ -6,9 +6,9 @@ package pl.szczodrzynski.edziennik.ui.dialogs.event
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||
@ -19,8 +19,11 @@ import pl.szczodrzynski.edziennik.utils.models.Week
|
||||
class EventListAdapter(
|
||||
val context: Context,
|
||||
val simpleMode: Boolean = false,
|
||||
val showDate: Boolean = false,
|
||||
val showWeekDay: Boolean = false,
|
||||
val showDate: Boolean = false,
|
||||
val showType: Boolean = true,
|
||||
val showTime: Boolean = true,
|
||||
val showSubject: Boolean = true,
|
||||
val onItemClick: ((event: EventFull) -> Unit)? = null,
|
||||
val onEventEditClick: ((event: EventFull) -> Unit)? = null
|
||||
) : RecyclerView.Adapter<EventListAdapter.ViewHolder>() {
|
||||
@ -48,37 +51,41 @@ class EventListAdapter(
|
||||
b.simpleMode = simpleMode
|
||||
|
||||
b.topic.text = event.topic
|
||||
b.topic.maxLines = if (simpleMode) 2 else 3
|
||||
|
||||
b.details.text = mutableListOf<CharSequence?>(
|
||||
if (showWeekDay) Week.getFullDayName(event.eventDate.weekDay) else null,
|
||||
if (showDate) event.eventDate.getRelativeString(context, 7) ?: event.eventDate.formattedStringShort else null,
|
||||
event.typeName,
|
||||
if (simpleMode) null else event.startTime?.stringHM ?: app.getString(R.string.event_all_day),
|
||||
if (simpleMode) null else event.subjectLongName
|
||||
if (showWeekDay) Week.getFullDayName(event.date.weekDay) else null,
|
||||
if (showDate) event.date.getRelativeString(context, 7) ?: event.date.formattedStringShort else null,
|
||||
if (showType) event.typeName else null,
|
||||
if (showTime) event.time?.stringHM ?: app.getString(R.string.event_all_day) else null,
|
||||
if (showSubject) event.subjectLongName else null
|
||||
).concat(bullet)
|
||||
|
||||
b.addedBy.setText(
|
||||
when (event.sharedBy) {
|
||||
null -> when {
|
||||
event.addedManually -> R.string.event_list_added_by_self_format
|
||||
event.teacherFullName == null -> R.string.event_list_added_by_unknown_format
|
||||
event.teacherName == null -> R.string.event_list_added_by_unknown_format
|
||||
else -> R.string.event_list_added_by_format
|
||||
}
|
||||
"self" -> R.string.event_list_shared_by_self_format
|
||||
else -> R.string.event_list_shared_by_format
|
||||
},
|
||||
Date.fromMillis(event.addedDate).formattedString,
|
||||
event.sharedByName ?: event.teacherFullName ?: "",
|
||||
event.sharedByName ?: event.teacherName ?: "",
|
||||
event.teamName?.let { bullet+it } ?: ""
|
||||
)
|
||||
|
||||
b.typeColor.background?.setTintColor(event.getColor())
|
||||
b.typeColor.background?.setTintColor(event.eventColor)
|
||||
b.typeColor.isVisible = showType
|
||||
|
||||
b.editButton.visibility = if (event.addedManually && !simpleMode) View.VISIBLE else View.GONE
|
||||
b.editButton.isVisible = !simpleMode && event.addedManually && !event.isDone
|
||||
b.editButton.onClick {
|
||||
onEventEditClick?.invoke(event)
|
||||
}
|
||||
|
||||
b.isDone.isVisible = event.isDone
|
||||
|
||||
b.editButton.setOnLongClickListener {
|
||||
Toast.makeText(context, R.string.hint_edit_event, Toast.LENGTH_SHORT).show()
|
||||
true
|
||||
|
@ -216,7 +216,7 @@ class EventManualDialog(
|
||||
progressDialog?.dismiss()
|
||||
launch {
|
||||
b.timeDropdown.loadItems()
|
||||
b.timeDropdown.selectDefault(editingEvent?.startTime)
|
||||
b.timeDropdown.selectDefault(editingEvent?.time)
|
||||
b.timeDropdown.selectDefault(defaultLesson?.displayStartTime ?: defaultTime)
|
||||
}
|
||||
}
|
||||
@ -251,7 +251,7 @@ class EventManualDialog(
|
||||
nextLessonTeamId = it.displayTeamId
|
||||
}
|
||||
loadItems()
|
||||
selectDefault(editingEvent?.eventDate)
|
||||
selectDefault(editingEvent?.date)
|
||||
selectDefault(defaultLesson?.displayDate ?: defaultDate)
|
||||
onDateSelected = { date, lesson ->
|
||||
b.timeDropdown.deselect()
|
||||
@ -276,8 +276,8 @@ class EventManualDialog(
|
||||
displayMode = DISPLAY_LESSONS
|
||||
if (!loadItems())
|
||||
syncTimetable(lessonsDate ?: Date.getToday())
|
||||
selectDefault(editingEvent?.startTime)
|
||||
if (editingEvent != null && editingEvent.startTime == null)
|
||||
selectDefault(editingEvent?.time)
|
||||
if (editingEvent != null && editingEvent.time == null)
|
||||
select(0L)
|
||||
selectDefault(defaultLesson?.displayStartTime ?: defaultTime)
|
||||
onLessonSelected = { lesson ->
|
||||
@ -319,7 +319,12 @@ class EventManualDialog(
|
||||
|
||||
val deferred = async(Dispatchers.Default) {
|
||||
// get the event type list
|
||||
val eventTypes = app.db.eventTypeDao().getAllNow(profileId)
|
||||
var eventTypes = app.db.eventTypeDao().getAllNow(profileId)
|
||||
|
||||
if (eventTypes.none { it.id in -1L..10L }) {
|
||||
eventTypes = app.db.eventTypeDao().addDefaultTypes(activity, profileId)
|
||||
}
|
||||
|
||||
b.typeDropdown.clear()
|
||||
b.typeDropdown += eventTypes.map { TextInputDropDown.Item(it.id, it.name, tag = it) }
|
||||
}
|
||||
@ -338,10 +343,10 @@ class EventManualDialog(
|
||||
// copy IDs from event being edited
|
||||
editingEvent?.let {
|
||||
b.topic.setText(it.topic)
|
||||
b.typeDropdown.select(it.type.toLong())?.let { item ->
|
||||
b.typeDropdown.select(it.type)?.let { item ->
|
||||
customColor = (item.tag as EventType).color
|
||||
}
|
||||
if (it.color != -1)
|
||||
if (it.color != null && it.color != -1)
|
||||
customColor = it.color
|
||||
}
|
||||
|
||||
@ -464,22 +469,25 @@ class EventManualDialog(
|
||||
(timeSelected as? Pair<*, *>)?.first as? Time
|
||||
|
||||
if (isError) return
|
||||
date ?: return
|
||||
topic ?: return
|
||||
|
||||
val id = System.currentTimeMillis()
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
editingEvent?.id ?: id,
|
||||
date,
|
||||
startTime,
|
||||
topic,
|
||||
customColor ?: -1,
|
||||
type ?: Event.TYPE_DEFAULT,
|
||||
true,
|
||||
teacherId ?: -1,
|
||||
subjectId ?: -1,
|
||||
teamId ?: -1
|
||||
)
|
||||
profileId = profileId,
|
||||
id = editingEvent?.id ?: id,
|
||||
date = date,
|
||||
time = startTime,
|
||||
topic = topic,
|
||||
color = customColor,
|
||||
type = type ?: Event.TYPE_DEFAULT,
|
||||
teacherId = teacherId ?: -1,
|
||||
subjectId = subjectId ?: -1,
|
||||
teamId = teamId ?: -1
|
||||
).also {
|
||||
it.addedManually = true
|
||||
}
|
||||
|
||||
val metadataObject = Metadata(
|
||||
profileId,
|
||||
@ -579,7 +587,7 @@ class EventManualDialog(
|
||||
private fun finishAdding(eventObject: Event, metadataObject: Metadata) {
|
||||
launch {
|
||||
withContext(Dispatchers.Default) {
|
||||
app.db.eventDao().add(eventObject)
|
||||
app.db.eventDao().upsert(eventObject)
|
||||
app.db.metadataDao().add(metadataObject)
|
||||
}
|
||||
}
|
||||
@ -590,6 +598,7 @@ class EventManualDialog(
|
||||
activity.reloadTarget()
|
||||
}
|
||||
private fun finishRemoving() {
|
||||
editingEvent ?: return
|
||||
launch {
|
||||
withContext(Dispatchers.Default) {
|
||||
app.db.eventDao().remove(editingEvent)
|
||||
|
@ -37,7 +37,8 @@ class NotificationFilterDialog(
|
||||
Notification.TYPE_NEW_ANNOUNCEMENT to R.string.notification_type_new_announcement,
|
||||
Notification.TYPE_NEW_SHARED_EVENT to R.string.notification_type_new_shared_event,
|
||||
Notification.TYPE_NEW_SHARED_HOMEWORK to R.string.notification_type_new_shared_homework,
|
||||
Notification.TYPE_REMOVED_SHARED_EVENT to R.string.notification_type_removed_shared_event
|
||||
Notification.TYPE_REMOVED_SHARED_EVENT to R.string.notification_type_removed_shared_event,
|
||||
Notification.TYPE_TEACHER_ABSENCE to R.string.notification_type_new_teacher_absence
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -170,6 +170,11 @@ class LessonDetailsDialog(
|
||||
|
||||
adapter = EventListAdapter(
|
||||
activity,
|
||||
showWeekDay = false,
|
||||
showDate = false,
|
||||
showType = true,
|
||||
showTime = true,
|
||||
showSubject = true,
|
||||
onItemClick = {
|
||||
EventDetailsDialog(
|
||||
activity,
|
||||
|
@ -222,22 +222,22 @@ class AgendaFragment : Fragment(), CoroutineScope {
|
||||
|
||||
events.forEach { event ->
|
||||
eventList.add(BaseCalendarEvent(
|
||||
"${event.typeName} - ${event.topic}",
|
||||
"${event.typeName ?: "wydarzenie"} - ${event.topic}",
|
||||
"",
|
||||
(if (event.startTime == null) getString(R.string.agenda_event_all_day) else event.startTime!!.stringHM) +
|
||||
(if (event.time == null) getString(R.string.agenda_event_all_day) else event.time!!.stringHM) +
|
||||
(event.subjectLongName?.let { ", $it" } ?: "") +
|
||||
(event.teacherFullName?.let { ", $it" } ?: "") +
|
||||
(event.teacherName?.let { ", $it" } ?: "") +
|
||||
(event.teamName?.let { ", $it" } ?: ""),
|
||||
event.getColor(),
|
||||
Colors.legibleTextColor(event.getColor()),
|
||||
event.eventColor,
|
||||
Colors.legibleTextColor(event.eventColor),
|
||||
event.startTimeCalendar,
|
||||
event.endTimeCalendar,
|
||||
event.startTime == null,
|
||||
event.time == null,
|
||||
event.id,
|
||||
!event.seen
|
||||
))
|
||||
|
||||
if (!event.seen) unreadEventDates.add(event.eventDate.value)
|
||||
if (!event.seen) unreadEventDates.add(event.date.value)
|
||||
}
|
||||
|
||||
b.agendaDefaultView.init(eventList, minDate, maxDate, Locale.getDefault(), object : CalendarPickerController {
|
||||
@ -281,11 +281,11 @@ class AgendaFragment : Fragment(), CoroutineScope {
|
||||
val eventIcon = IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon.cmd_checkbox_blank_circle)
|
||||
.size(IconicsSize.dp(10))
|
||||
.color(IconicsColor.colorInt(event.getColor()))
|
||||
.color(IconicsColor.colorInt(event.eventColor))
|
||||
|
||||
dayList.add(EventDay(event.startTimeCalendar, eventIcon))
|
||||
|
||||
if (!event.seen) unreadEventDates.add(event.eventDate.value)
|
||||
if (!event.seen) unreadEventDates.add(event.date.value)
|
||||
}
|
||||
|
||||
b.agendaCalendarView.setEvents(dayList)
|
||||
|
@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-2-22.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.base
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
|
||||
abstract class PagerFragment : Fragment() {
|
||||
private var isPageCreated = false
|
||||
|
||||
/**
|
||||
* Called when the page is first shown, or if previous
|
||||
* [onPageCreated] returned false
|
||||
*
|
||||
* @return true if the view is set up
|
||||
* @return false if the setup failed. The method may be then called
|
||||
* again, when page becomes visible.
|
||||
*/
|
||||
abstract fun onPageCreated(): Boolean
|
||||
|
||||
override fun onResume() {
|
||||
if (!isPageCreated) {
|
||||
isPageCreated = onPageCreated()
|
||||
}
|
||||
super.onResume()
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-30.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.base.lazypager
|
||||
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
|
||||
class FragmentLazyPagerAdapter(
|
||||
fragmentManager: FragmentManager,
|
||||
swipeRefreshLayout: SwipeRefreshLayout,
|
||||
private val fragments: List<Pair<LazyFragment, CharSequence>>
|
||||
) : LazyPagerAdapter(fragmentManager, swipeRefreshLayout) {
|
||||
override fun getPage(position: Int) = fragments[position].first
|
||||
override fun getPageTitle(position: Int) = fragments[position].second
|
||||
override fun getCount() = fragments.size
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-29.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.base.lazypager
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
abstract class LazyFragment : Fragment() {
|
||||
private var isPageCreated = false
|
||||
internal var position = -1
|
||||
internal var swipeRefreshLayoutCallback: ((position: Int, isEnabled: Boolean) -> Unit)? = null
|
||||
|
||||
/**
|
||||
* Called when the page is first shown, or if previous
|
||||
* [onPageCreated] returned false
|
||||
*
|
||||
* @return true if the view is set up
|
||||
* @return false if the setup failed. The method may be then called
|
||||
* again, when page becomes visible.
|
||||
*/
|
||||
abstract fun onPageCreated(): Boolean
|
||||
|
||||
fun enableSwipeToRefresh() = swipeRefreshLayoutCallback?.invoke(position, true)
|
||||
fun disableSwipeToRefresh() = swipeRefreshLayoutCallback?.invoke(position, false)
|
||||
fun setSwipeToRefresh(enabled: Boolean) = swipeRefreshLayoutCallback?.invoke(position, enabled)
|
||||
|
||||
val onScrollListener: RecyclerView.OnScrollListener
|
||||
get() = object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
if (recyclerView.canScrollVertically(-1))
|
||||
disableSwipeToRefresh()
|
||||
if (!recyclerView.canScrollVertically(-1) && newState == RecyclerView.SCROLL_STATE_IDLE)
|
||||
enableSwipeToRefresh()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun createPage() {
|
||||
if (!isPageCreated && isAdded) {
|
||||
isPageCreated = onPageCreated()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
isPageCreated = false
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
createPage()
|
||||
super.onResume()
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-29.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.base.lazypager
|
||||
|
||||
import android.util.SparseBooleanArray
|
||||
import androidx.core.util.set
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
|
||||
abstract class LazyPagerAdapter(fragmentManager: FragmentManager, val swipeRefreshLayout: SwipeRefreshLayout? = null) : FragmentStatePagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
|
||||
internal val enabledList = SparseBooleanArray()
|
||||
private val refreshLayoutCallback: (position: Int, isEnabled: Boolean) -> Unit = { position, isEnabled ->
|
||||
swipeRefreshLayout?.isEnabled = isEnabled
|
||||
if (position > -1)
|
||||
enabledList[position] = isEnabled
|
||||
}
|
||||
final override fun getItem(position: Int): LazyFragment {
|
||||
return getPage(position).also {
|
||||
it.position = position
|
||||
it.swipeRefreshLayoutCallback = refreshLayoutCallback
|
||||
}
|
||||
}
|
||||
abstract fun getPage(position: Int): LazyFragment
|
||||
abstract override fun getPageTitle(position: Int): CharSequence
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-29.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.base.lazypager
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
|
||||
class LazyViewPager @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null
|
||||
) : ViewPager(context, attrs) {
|
||||
|
||||
private var pageSelection = -1
|
||||
private var scrollState = 0
|
||||
|
||||
init {
|
||||
addOnPageChangeListener(object : OnPageChangeListener {
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
scrollState = state
|
||||
(adapter as? LazyPagerAdapter)?.let {
|
||||
it.swipeRefreshLayout?.isEnabled = state == SCROLL_STATE_IDLE && it.enabledList[pageSelection, true]
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun onPageSelected(position: Int) {
|
||||
pageSelection = position
|
||||
(adapter as? LazyPagerAdapter)?.let {
|
||||
it.swipeRefreshLayout?.isEnabled = scrollState == SCROLL_STATE_IDLE && it.enabledList[pageSelection, true]
|
||||
val fragment = adapter?.instantiateItem(this@LazyViewPager, position)
|
||||
val lazyFragment = fragment as? LazyFragment
|
||||
lazyFragment?.createPage()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -10,11 +10,10 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial.Icon2
|
||||
import kotlinx.coroutines.*
|
||||
@ -23,7 +22,7 @@ import pl.szczodrzynski.edziennik.MainActivity.Companion.TARGET_GRADES_EDITOR
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_GRADE
|
||||
import pl.szczodrzynski.edziennik.data.db.full.GradeFull
|
||||
import pl.szczodrzynski.edziennik.databinding.GradesFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.databinding.GradesListFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradeDetailsDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesAverages
|
||||
@ -36,24 +35,20 @@ import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.math.max
|
||||
|
||||
|
||||
class GradesFragment : Fragment(), CoroutineScope {
|
||||
class GradesListFragment : Fragment(), CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "GradesFragment"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: GradesFragmentBinding
|
||||
private lateinit var b: GradesListFragmentBinding
|
||||
|
||||
private val job: Job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
// local/private variables go here
|
||||
private val adapter by lazy {
|
||||
GradesAdapter(activity)
|
||||
}
|
||||
private val manager by lazy { app.gradesManager }
|
||||
private val dontCountEnabled by lazy { manager.dontCountEnabled }
|
||||
private val dontCountGrades by lazy { manager.dontCountGrades }
|
||||
@ -63,51 +58,49 @@ class GradesFragment : Fragment(), CoroutineScope {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
context ?: return null
|
||||
app = activity.application as App
|
||||
b = GradesFragmentBinding.inflate(inflater)
|
||||
b = GradesListFragmentBinding.inflate(inflater)
|
||||
b.refreshLayout.setParent(activity.swipeRefreshLayout)
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
if (!isAdded)
|
||||
return
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { startCoroutineTimer(100L) {
|
||||
if (!isAdded) return@startCoroutineTimer
|
||||
|
||||
expandSubjectId = arguments?.getLong("gradesSubjectId") ?: 0L
|
||||
|
||||
app.db.gradeDao()
|
||||
.getAllOrderBy(App.profileId, app.gradesManager.getOrderByString())
|
||||
.observe(this, Observer { grades ->
|
||||
if (b.gradesRecyclerView.adapter == null) {
|
||||
b.gradesRecyclerView.adapter = adapter
|
||||
b.gradesRecyclerView.apply {
|
||||
setHasFixedSize(true)
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
//addItemDecoration(SimpleDividerItemDecoration(context))
|
||||
addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
if (recyclerView.canScrollVertically(-1)) {
|
||||
b.refreshLayout.isEnabled = false
|
||||
}
|
||||
if (!recyclerView.canScrollVertically(-1) && newState == SCROLL_STATE_IDLE) {
|
||||
b.refreshLayout.isEnabled = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
val adapter = GradesAdapter(activity)
|
||||
var firstRun = true
|
||||
|
||||
launch(Dispatchers.Default) {
|
||||
processGrades(grades)
|
||||
}
|
||||
app.db.gradeDao().getAllOrderBy(App.profileId, app.gradesManager.getOrderByString()).observe(this, Observer { items -> launch {
|
||||
if (!isAdded) return@launch
|
||||
|
||||
if (grades != null && grades.isNotEmpty()) {
|
||||
b.gradesRecyclerView.visibility = View.VISIBLE
|
||||
b.gradesNoData.visibility = View.GONE
|
||||
} else {
|
||||
b.gradesRecyclerView.visibility = View.GONE
|
||||
b.gradesNoData.visibility = View.VISIBLE
|
||||
}
|
||||
})
|
||||
// load & configure the adapter
|
||||
adapter.items = withContext(Dispatchers.Default) { processGrades(items) }
|
||||
if (items.isNotNullNorEmpty() && b.list.adapter == null) {
|
||||
b.list.adapter = adapter
|
||||
b.list.apply {
|
||||
setHasFixedSize(true)
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
addOnScrollListener(b.refreshLayout.onScrollListener)
|
||||
}
|
||||
}
|
||||
adapter.notifyDataSetChanged()
|
||||
|
||||
if (firstRun) {
|
||||
expandSubject(adapter)
|
||||
firstRun = false
|
||||
}
|
||||
|
||||
// show/hide relevant views
|
||||
b.progressBar.isVisible = false
|
||||
if (items.isNullOrEmpty()) {
|
||||
b.list.isVisible = false
|
||||
b.noData.isVisible = true
|
||||
} else {
|
||||
b.list.isVisible = true
|
||||
b.noData.isVisible = false
|
||||
}
|
||||
}})
|
||||
|
||||
adapter.onGradeClick = {
|
||||
GradeDetailsDialog(activity, it)
|
||||
@ -153,10 +146,30 @@ class GradesFragment : Fragment(), CoroutineScope {
|
||||
})
|
||||
)
|
||||
activity.gainAttention()
|
||||
}}
|
||||
|
||||
private fun expandSubject(adapter: GradesAdapter) {
|
||||
var expandSubjectModel: GradesSubject? = null
|
||||
if (expandSubjectId != 0L) {
|
||||
expandSubjectModel = adapter.items.firstOrNull { it is GradesSubject && it.subjectId == expandSubjectId } as? GradesSubject
|
||||
adapter.expandModel(
|
||||
model = expandSubjectModel,
|
||||
view = null,
|
||||
notifyAdapter = false
|
||||
)
|
||||
}
|
||||
|
||||
startCoroutineTimer(500L) {
|
||||
if (expandSubjectModel != null) {
|
||||
b.list.smoothScrollToPosition(
|
||||
adapter.items.indexOf(expandSubjectModel) + expandSubjectModel.semesters.size + (expandSubjectModel.semesters.firstOrNull()?.grades?.size ?: 0)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("SuspendFunctionOnCoroutineScope")
|
||||
private suspend fun processGrades(grades: List<GradeFull>) {
|
||||
private fun processGrades(grades: List<GradeFull>): MutableList<Any> {
|
||||
val items = mutableListOf<GradesSubject>()
|
||||
|
||||
var subjectId = -1L
|
||||
@ -284,30 +297,7 @@ class GradesFragment : Fragment(), CoroutineScope {
|
||||
GradesManager.ORDER_BY_DATE_ASC -> items.sortBy { it.lastAddedDate }
|
||||
}
|
||||
|
||||
adapter.items = items.toMutableList()
|
||||
adapter.items.add(stats)
|
||||
|
||||
var expandSubjectModel: GradesSubject? = null
|
||||
if (expandSubjectId != 0L) {
|
||||
expandSubjectModel = items.firstOrNull { it.subjectId == expandSubjectId }
|
||||
adapter.expandModel(
|
||||
model = expandSubjectModel,
|
||||
view = null,
|
||||
notifyAdapter = false
|
||||
)
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
startCoroutineTimer(500L, 0L) {
|
||||
if (expandSubjectModel != null) {
|
||||
b.gradesRecyclerView.smoothScrollToPosition(
|
||||
items.indexOf(expandSubjectModel) + expandSubjectModel.semesters.size + (expandSubjectModel.semesters.firstOrNull()?.grades?.size ?: 0)
|
||||
)
|
||||
}
|
||||
}
|
||||
return (items + stats).toMutableList()
|
||||
}
|
||||
|
||||
private fun countGrade(grade: Grade, averages: GradesAverages) {
|
@ -60,8 +60,11 @@ class HomeEventsCard(
|
||||
adapter = EventListAdapter(
|
||||
activity,
|
||||
simpleMode = true,
|
||||
showDate = true,
|
||||
showWeekDay = true,
|
||||
showDate = true,
|
||||
showType = true,
|
||||
showTime = false,
|
||||
showSubject = false,
|
||||
onItemClick = {
|
||||
EventDetailsDialog(
|
||||
activity,
|
||||
@ -77,7 +80,7 @@ class HomeEventsCard(
|
||||
}
|
||||
)
|
||||
|
||||
app.db.eventDao().getAllNearest(profile.id, Date.getToday(), 4).observe(activity, Observer { events ->
|
||||
app.db.eventDao().getNearestNotDone(profile.id, Date.getToday(), 4).observe(activity, Observer { events ->
|
||||
adapter.items = events
|
||||
if (b.eventsView.adapter == null) {
|
||||
b.eventsView.adapter = adapter
|
||||
|
@ -50,17 +50,17 @@ public class HomeworkAdapter extends RecyclerView.Adapter<HomeworkAdapter.ViewHo
|
||||
|
||||
EventFull homework = homeworkList.get(position);
|
||||
|
||||
int diffDays = Date.diffDays(homework.eventDate, Date.getToday());
|
||||
int diffDays = Date.diffDays(homework.getDate(), Date.getToday());
|
||||
|
||||
holder.homeworkItemHomeworkDate.setText(app.getString(R.string.date_relative_format, homework.eventDate.getFormattedString(), Date.dayDiffString(context, diffDays)));
|
||||
holder.homeworkItemTopic.setText(homework.topic);
|
||||
holder.homeworkItemSubjectTeacher.setText(context.getString(R.string.homework_subject_teacher_format, bs(homework.subjectLongName), bs(homework.teacherFullName)));
|
||||
holder.homeworkItemTeamDate.setText(context.getString(R.string.homework_team_date_format, bs(homework.teamName), Date.fromMillis(homework.addedDate).getFormattedStringShort()));
|
||||
holder.homeworkItemHomeworkDate.setText(app.getString(R.string.date_relative_format, homework.getDate().getFormattedString(), Date.dayDiffString(context, diffDays)));
|
||||
holder.homeworkItemTopic.setText(homework.getTopic());
|
||||
holder.homeworkItemSubjectTeacher.setText(context.getString(R.string.homework_subject_teacher_format, bs(homework.getSubjectLongName()), bs(homework.getTeacherName())));
|
||||
holder.homeworkItemTeamDate.setText(context.getString(R.string.homework_team_date_format, bs(homework.getTeamName()), Date.fromMillis(homework.getAddedDate()).getFormattedStringShort()));
|
||||
|
||||
if (!homework.seen) {
|
||||
if (!homework.getSeen()) {
|
||||
holder.homeworkItemTopic.setBackground(context.getResources().getDrawable(R.drawable.bg_rounded_8dp));
|
||||
holder.homeworkItemTopic.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY));
|
||||
homework.seen = true;
|
||||
homework.setSeen(true);
|
||||
AsyncTask.execute(() -> {
|
||||
App.db.metadataDao().setSeen(App.Companion.getProfileId(), homework, true);
|
||||
});
|
||||
@ -69,11 +69,11 @@ public class HomeworkAdapter extends RecyclerView.Adapter<HomeworkAdapter.ViewHo
|
||||
holder.homeworkItemTopic.setBackground(null);
|
||||
}
|
||||
|
||||
holder.homeworkItemEdit.setVisibility((homework.addedManually ? View.VISIBLE : View.GONE));
|
||||
holder.homeworkItemEdit.setVisibility((homework.getAddedManually() ? View.VISIBLE : View.GONE));
|
||||
holder.homeworkItemEdit.setOnClickListener(v -> {
|
||||
new EventManualDialog(
|
||||
(MainActivity) context,
|
||||
homework.profileId,
|
||||
homework.getProfileId(),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
@ -83,11 +83,11 @@ public class HomeworkAdapter extends RecyclerView.Adapter<HomeworkAdapter.ViewHo
|
||||
null);
|
||||
});
|
||||
|
||||
if (homework.sharedBy == null) {
|
||||
if (homework.getSharedBy() == null) {
|
||||
holder.homeworkItemSharedBy.setVisibility(View.GONE);
|
||||
}
|
||||
else if (homework.sharedByName != null) {
|
||||
holder.homeworkItemSharedBy.setText(app.getString(R.string.event_shared_by_format, (homework.sharedBy.equals("self") ? app.getString(R.string.event_shared_by_self) : homework.sharedByName)));
|
||||
else if (homework.getSharedByName() != null) {
|
||||
holder.homeworkItemSharedBy.setText(app.getString(R.string.event_shared_by_format, (homework.getSharedBy().equals("self") ? app.getString(R.string.event_shared_by_self) : homework.getSharedByName())));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-30.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.homework
|
||||
|
||||
import android.os.AsyncTask
|
||||
@ -7,46 +11,48 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentHomeworkBinding
|
||||
import pl.szczodrzynski.edziennik.databinding.HomeworkFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.FragmentLazyPagerAdapter
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class HomeworkFragment : Fragment() {
|
||||
class HomeworkFragment : Fragment(), CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "HomeworkFragment"
|
||||
var pageSelection = 0
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: FragmentHomeworkBinding
|
||||
private lateinit var b: HomeworkFragmentBinding
|
||||
|
||||
private val job: Job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
// local/private variables go here
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
if (context == null)
|
||||
return null
|
||||
context ?: return null
|
||||
app = activity.application as App
|
||||
context!!.theme.applyStyle(Themes.appTheme, true)
|
||||
// activity, context and profile is valid
|
||||
b = FragmentHomeworkBinding.inflate(inflater)
|
||||
b = HomeworkFragmentBinding.inflate(inflater)
|
||||
b.refreshLayout.setParent(activity.swipeRefreshLayout)
|
||||
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
|
||||
if (!isAdded) return
|
||||
|
||||
activity.bottomSheet.prependItems(
|
||||
BottomSheetPrimaryItem(true)
|
||||
@ -67,34 +73,29 @@ class HomeworkFragment : Fragment() {
|
||||
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show()
|
||||
}))
|
||||
|
||||
b.viewPager.adapter = MessagesFragment.Adapter(childFragmentManager).also { adapter ->
|
||||
adapter.addFragment(HomeworkListFragment().also { fragment ->
|
||||
fragment.arguments = Bundle().also { args ->
|
||||
args.putInt("homeworkDate", HomeworkDate.CURRENT)
|
||||
}
|
||||
}, getString(R.string.homework_tab_current))
|
||||
val pagerAdapter = FragmentLazyPagerAdapter(
|
||||
fragmentManager ?: return,
|
||||
b.refreshLayout,
|
||||
listOf(
|
||||
HomeworkListFragment().apply {
|
||||
arguments = Bundle("homeworkDate" to HomeworkDate.CURRENT)
|
||||
} to getString(R.string.homework_tab_current),
|
||||
|
||||
adapter.addFragment(HomeworkListFragment().also { fragment ->
|
||||
fragment.arguments = Bundle().also { args ->
|
||||
args.putInt("homeworkDate", HomeworkDate.PAST)
|
||||
}
|
||||
}, getString(R.string.homework_tab_past))
|
||||
HomeworkListFragment().apply {
|
||||
arguments = Bundle("homeworkDate" to HomeworkDate.PAST)
|
||||
} to getString(R.string.homework_tab_past)
|
||||
)
|
||||
)
|
||||
b.viewPager.apply {
|
||||
offscreenPageLimit = 1
|
||||
adapter = pagerAdapter
|
||||
currentItem = pageSelection
|
||||
addOnPageSelectedListener {
|
||||
pageSelection = it
|
||||
}
|
||||
b.tabLayout.setupWithViewPager(this)
|
||||
}
|
||||
|
||||
b.viewPager.currentItem = pageSelection
|
||||
b.viewPager.clearOnPageChangeListeners()
|
||||
b.viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
b.refreshLayout.isEnabled = state == ViewPager.SCROLL_STATE_IDLE
|
||||
}
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
|
||||
override fun onPageSelected(position: Int) {
|
||||
pageSelection = position
|
||||
}
|
||||
})
|
||||
|
||||
b.tabLayout.setupWithViewPager(b.viewPager)
|
||||
|
||||
activity.navView.apply {
|
||||
bottomBar.apply {
|
||||
fabEnable = true
|
||||
|
@ -4,67 +4,106 @@ import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.databinding.HomeworkListBinding
|
||||
import pl.szczodrzynski.edziennik.getInt
|
||||
import pl.szczodrzynski.edziennik.databinding.HomeworkListFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventDetailsDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventListAdapter
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment
|
||||
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class HomeworkListFragment : Fragment() {
|
||||
class HomeworkListFragment : LazyFragment(), CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "HomeworkListFragment"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: HomeworkListBinding
|
||||
private lateinit var b: HomeworkListFragmentBinding
|
||||
|
||||
private var homeworkDate = HomeworkDate.CURRENT
|
||||
private val job: Job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
// local/private variables go here
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
context ?: return null
|
||||
app = activity.application as App
|
||||
b = HomeworkListBinding.inflate(inflater)
|
||||
b = HomeworkListFragmentBinding.inflate(inflater)
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
// TODO check if app, activity, b can be null
|
||||
if (!isAdded)
|
||||
return
|
||||
|
||||
if (arguments != null) {
|
||||
homeworkDate = arguments.getInt("homeworkDate", HomeworkDate.CURRENT)
|
||||
}
|
||||
|
||||
val layoutManager = LinearLayoutManager(context)
|
||||
layoutManager.reverseLayout = homeworkDate == HomeworkDate.PAST
|
||||
layoutManager.stackFromEnd = homeworkDate == HomeworkDate.PAST
|
||||
|
||||
b.homeworkView.setHasFixedSize(true)
|
||||
b.homeworkView.layoutManager = layoutManager
|
||||
override fun onPageCreated(): Boolean { startCoroutineTimer(100L) {
|
||||
val homeworkDate = arguments.getInt("homeworkDate", HomeworkDate.CURRENT)
|
||||
|
||||
val today = Date.getToday()
|
||||
val filter = when(homeworkDate) {
|
||||
HomeworkDate.CURRENT -> "eventDate >= '" + Date.getToday().stringY_m_d + "'"
|
||||
else -> "eventDate < '" + Date.getToday().stringY_m_d + "'"
|
||||
HomeworkDate.CURRENT -> "eventDate >= '${today.stringY_m_d}' AND eventIsDone = 0"
|
||||
else -> "eventDate < '${today.stringY_m_d}' OR eventIsDone = 1"
|
||||
}
|
||||
|
||||
app.db.eventDao()
|
||||
.getAllByType(App.profileId, Event.TYPE_HOMEWORK, filter)
|
||||
.observe(this, Observer { homeworkList ->
|
||||
if (!isAdded) return@Observer
|
||||
val adapter = EventListAdapter(
|
||||
activity,
|
||||
showWeekDay = true,
|
||||
showDate = true,
|
||||
showType = false,
|
||||
showTime = true,
|
||||
showSubject = true,
|
||||
onItemClick = {
|
||||
EventDetailsDialog(
|
||||
activity,
|
||||
it
|
||||
)
|
||||
},
|
||||
onEventEditClick = {
|
||||
EventManualDialog(
|
||||
activity,
|
||||
it.profileId,
|
||||
editingEvent = it
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
if (homeworkList != null && homeworkList.size > 0) {
|
||||
val adapter = HomeworkAdapter(context, homeworkList)
|
||||
b.homeworkView.adapter = adapter
|
||||
b.homeworkView.visibility = View.VISIBLE
|
||||
b.homeworkNoData.visibility = View.GONE
|
||||
} else {
|
||||
b.homeworkView.visibility = View.GONE
|
||||
b.homeworkNoData.visibility = View.VISIBLE
|
||||
app.db.eventDao().getAllByType(App.profileId, Event.TYPE_HOMEWORK, filter).observe(this@HomeworkListFragment, Observer { items ->
|
||||
if (!isAdded) return@Observer
|
||||
|
||||
// load & configure the adapter
|
||||
adapter.items = items
|
||||
if (items.isNotNullNorEmpty() && b.list.adapter == null) {
|
||||
b.list.adapter = adapter
|
||||
b.list.apply {
|
||||
setHasFixedSize(true)
|
||||
layoutManager = LinearLayoutManager(context).apply {
|
||||
reverseLayout = homeworkDate == HomeworkDate.PAST
|
||||
stackFromEnd = homeworkDate == HomeworkDate.PAST
|
||||
}
|
||||
})
|
||||
}
|
||||
addItemDecoration(SimpleDividerItemDecoration(context))
|
||||
addOnScrollListener(onScrollListener)
|
||||
}
|
||||
}
|
||||
adapter.notifyDataSetChanged()
|
||||
setSwipeToRefresh(false) // TODO
|
||||
|
||||
// show/hide relevant views
|
||||
b.progressBar.isVisible = false
|
||||
if (items.isNullOrEmpty()) {
|
||||
b.list.isVisible = false
|
||||
b.noData.isVisible = true
|
||||
} else {
|
||||
b.list.isVisible = true
|
||||
b.noData.isVisible = false
|
||||
}
|
||||
})
|
||||
}; return true }
|
||||
}
|
||||
|
@ -19,8 +19,6 @@ import pl.szczodrzynski.edziennik.data.api.events.ApiTaskAllFinishedEvent
|
||||
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent
|
||||
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskProgressEvent
|
||||
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskStartedEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.EventType
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.REGISTRATION_DISABLED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.REGISTRATION_ENABLED
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginSyncBinding
|
||||
@ -62,20 +60,7 @@ class LoginSyncFragment : Fragment(), CoroutineScope {
|
||||
else
|
||||
REGISTRATION_DISABLED
|
||||
|
||||
val typeList = listOf(
|
||||
EventType(it.id, TYPE_HOMEWORK, getString(R.string.event_type_homework), COLOR_HOMEWORK),
|
||||
EventType(it.id, TYPE_DEFAULT, getString(R.string.event_other), COLOR_DEFAULT),
|
||||
EventType(it.id, TYPE_EXAM, getString(R.string.event_exam), COLOR_EXAM),
|
||||
EventType(it.id, TYPE_SHORT_QUIZ, getString(R.string.event_short_quiz), COLOR_SHORT_QUIZ),
|
||||
EventType(it.id, TYPE_ESSAY, getString(R.string.event_essay), COLOR_SHORT_QUIZ),
|
||||
EventType(it.id, TYPE_PROJECT, getString(R.string.event_project), COLOR_PROJECT),
|
||||
EventType(it.id, TYPE_PT_MEETING, getString(R.string.event_pt_meeting), COLOR_PT_MEETING),
|
||||
EventType(it.id, TYPE_EXCURSION, getString(R.string.event_excursion), COLOR_EXCURSION),
|
||||
EventType(it.id, TYPE_READING, getString(R.string.event_reading), COLOR_READING),
|
||||
EventType(it.id, TYPE_CLASS_EVENT, getString(R.string.event_class_event), COLOR_CLASS_EVENT),
|
||||
EventType(it.id, TYPE_INFORMATION, getString(R.string.event_information), COLOR_INFORMATION)
|
||||
)
|
||||
app.db.eventTypeDao().addAll(typeList)
|
||||
app.db.eventTypeDao().addDefaultTypes(activity, it.id)
|
||||
}
|
||||
|
||||
app.db.profileDao().addAll(profiles)
|
||||
|
@ -15,6 +15,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ProgressBar
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.mikepenz.iconics.IconicsColor
|
||||
@ -62,7 +63,7 @@ class MessageFragment : Fragment(), CoroutineScope {
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: MessageFragmentBinding
|
||||
|
||||
private lateinit var job: Job
|
||||
private val job: Job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
@ -73,16 +74,12 @@ class MessageFragment : Fragment(), CoroutineScope {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
context ?: return null
|
||||
app = activity.application as App
|
||||
context!!.theme.applyStyle(Themes.appTheme, true)
|
||||
b = MessageFragmentBinding.inflate(inflater)
|
||||
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
|
||||
if (!isAdded) return
|
||||
|
||||
b.closeButton.setImageDrawable(
|
||||
IconicsDrawable(activity, CommunityMaterial.Icon2.cmd_window_close)
|
||||
@ -260,16 +257,35 @@ class MessageFragment : Fragment(), CoroutineScope {
|
||||
MessagesFragment.pageSelection = min(message.type, 1)
|
||||
}
|
||||
|
||||
private val attachmentOnClick = { v: View ->
|
||||
if (v.tag is Int) {
|
||||
downloadAttachment(v.tag as Int)
|
||||
}
|
||||
}
|
||||
|
||||
private val attachmentOnLongClick = { v: View ->
|
||||
(v.tag as? Int)?.let { tag ->
|
||||
val popupMenu = PopupMenu(v.context, v)
|
||||
popupMenu.menu.add(0, tag, 0, R.string.messages_attachment_download_again)
|
||||
popupMenu.setOnMenuItemClickListener {
|
||||
downloadAttachment(it.itemId, forceDownload = true)
|
||||
true
|
||||
}
|
||||
popupMenu.show()
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
private fun showAttachments() {
|
||||
if (message.attachmentIds != null) {
|
||||
val insertPoint = b.attachments
|
||||
insertPoint.removeAllViews()
|
||||
|
||||
val chipLayoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
chipLayoutParams.setMargins(0, Utils.dpToPx(8), 0, Utils.dpToPx(8))
|
||||
chipLayoutParams.setMargins(0, 8.dp, 0, 0)
|
||||
|
||||
val progressLayoutParams = FrameLayout.LayoutParams(Utils.dpToPx(18), Utils.dpToPx(18))
|
||||
progressLayoutParams.setMargins(Utils.dpToPx(8), 0, Utils.dpToPx(8), 0)
|
||||
val progressLayoutParams = FrameLayout.LayoutParams(18.dp, 18.dp)
|
||||
progressLayoutParams.setMargins(8.dp, 0, 8.dp, 0)
|
||||
progressLayoutParams.gravity = END or CENTER_VERTICAL
|
||||
|
||||
// CREATE VIEWS AND AN OBJECT FOR EVERY ATTACHMENT
|
||||
@ -280,12 +296,13 @@ class MessageFragment : Fragment(), CoroutineScope {
|
||||
val size = message.attachmentSizes[index]
|
||||
// create the parent
|
||||
val attachmentLayout = FrameLayout(b.root.context)
|
||||
attachmentLayout.setPadding(Utils.dpToPx(16), 0, Utils.dpToPx(16), 0)
|
||||
attachmentLayout.setPadding(16.dp, 0, 16.dp, 0)
|
||||
|
||||
val attachmentChip = Chip(attachmentLayout.context)
|
||||
//attachmentChip.setChipBackgroundColorResource(ThemeUtils.getChipColorRes());
|
||||
attachmentChip.layoutParams = chipLayoutParams
|
||||
attachmentChip.height = Utils.dpToPx(40)
|
||||
attachmentChip.chipMinHeight = 40.dp.toFloat()
|
||||
//attachmentChip.height = Utils.dpToPx(40)
|
||||
|
||||
// show the file size or not
|
||||
if (size == -1L)
|
||||
@ -312,11 +329,8 @@ class MessageFragment : Fragment(), CoroutineScope {
|
||||
attachmentChip.isCloseIconVisible = false
|
||||
// set the object's index in the attachmentList as the tag
|
||||
attachmentChip.tag = index
|
||||
attachmentChip.setOnClickListener { v ->
|
||||
if (v.tag is Int) {
|
||||
downloadAttachment(v.tag as Int)
|
||||
}
|
||||
}
|
||||
attachmentChip.onClick(attachmentOnClick)
|
||||
attachmentChip.onLongClick(attachmentOnLongClick)
|
||||
attachmentLayout.addView(attachmentChip)
|
||||
|
||||
val attachmentProgress = ProgressBar(attachmentLayout.context)
|
||||
@ -338,10 +352,10 @@ class MessageFragment : Fragment(), CoroutineScope {
|
||||
}
|
||||
}
|
||||
|
||||
private fun downloadAttachment(index: Int) {
|
||||
private fun downloadAttachment(index: Int, forceDownload: Boolean = false) {
|
||||
val attachment = attachmentList[index]
|
||||
|
||||
if (attachment.downloaded != null) {
|
||||
if (!forceDownload && attachment.downloaded != null) {
|
||||
Utils.openFile(activity, File(attachment.downloaded))
|
||||
return
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentPagerAdapter
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
@ -14,8 +14,9 @@ import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentMessagesBinding
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyPagerAdapter
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import java.util.*
|
||||
|
||||
class MessagesFragment : Fragment() {
|
||||
companion object {
|
||||
@ -54,7 +55,7 @@ class MessagesFragment : Fragment() {
|
||||
return
|
||||
}
|
||||
|
||||
b.viewPager.adapter = Adapter(childFragmentManager).also { adapter ->
|
||||
b.viewPager.adapter = Adapter(childFragmentManager, b.refreshLayout).also { adapter ->
|
||||
|
||||
adapter.addFragment(MessagesListFragment().also { fragment ->
|
||||
fragment.arguments = Bundle().also { args ->
|
||||
@ -71,13 +72,8 @@ class MessagesFragment : Fragment() {
|
||||
}
|
||||
|
||||
b.viewPager.currentItem = pageSelection
|
||||
b.viewPager.clearOnPageChangeListeners()
|
||||
b.viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
if (b.refreshLayout != null) {
|
||||
b.refreshLayout.isEnabled = state == ViewPager.SCROLL_STATE_IDLE
|
||||
}
|
||||
}
|
||||
override fun onPageScrollStateChanged(state: Int) {}
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
|
||||
override fun onPageSelected(position: Int) {
|
||||
pageSelection = position
|
||||
@ -126,11 +122,11 @@ class MessagesFragment : Fragment() {
|
||||
}*/
|
||||
}
|
||||
|
||||
internal class Adapter(manager: FragmentManager) : FragmentPagerAdapter(manager) {
|
||||
private val mFragmentList = ArrayList<Fragment>()
|
||||
private val mFragmentTitleList = ArrayList<String>()
|
||||
internal class Adapter(manager: FragmentManager, swipeRefreshLayout: SwipeRefreshLayout) : LazyPagerAdapter(manager, swipeRefreshLayout) {
|
||||
private val mFragmentList = mutableListOf<LazyFragment>()
|
||||
private val mFragmentTitleList = mutableListOf<String>()
|
||||
|
||||
override fun getItem(position: Int): Fragment {
|
||||
override fun getPage(position: Int): LazyFragment {
|
||||
return mFragmentList[position]
|
||||
}
|
||||
|
||||
@ -138,12 +134,12 @@ class MessagesFragment : Fragment() {
|
||||
return mFragmentList.size
|
||||
}
|
||||
|
||||
fun addFragment(fragment: Fragment, title: String) {
|
||||
fun addFragment(fragment: LazyFragment, title: String) {
|
||||
mFragmentList.add(fragment)
|
||||
mFragmentTitleList.add(title)
|
||||
}
|
||||
|
||||
override fun getPageTitle(position: Int): CharSequence? {
|
||||
override fun getPageTitle(position: Int): CharSequence {
|
||||
return mFragmentTitleList[position]
|
||||
}
|
||||
}
|
||||
|
@ -10,11 +10,10 @@ import android.view.ViewGroup;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -26,13 +25,15 @@ import pl.szczodrzynski.edziennik.data.db.entity.Message;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageRecipientFull;
|
||||
import pl.szczodrzynski.edziennik.databinding.MessagesListBinding;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment;
|
||||
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
|
||||
import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
|
||||
import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.d;
|
||||
|
||||
public class MessagesListFragment extends Fragment {
|
||||
public class MessagesListFragment extends LazyFragment {
|
||||
|
||||
private App app = null;
|
||||
private MainActivity activity = null;
|
||||
@ -65,9 +66,9 @@ public class MessagesListFragment extends Fragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
public boolean onPageCreated() {
|
||||
if (app == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
return false;
|
||||
|
||||
long messageId = -1;
|
||||
if (getArguments() != null) {
|
||||
@ -78,7 +79,7 @@ public class MessagesListFragment extends Fragment {
|
||||
args.putLong("messageId", messageId);
|
||||
getArguments().remove("messageId");
|
||||
activity.loadTarget(MainActivity.TARGET_MESSAGES_DETAILS, args);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getArguments() != null) {
|
||||
@ -161,11 +162,22 @@ public class MessagesListFragment extends Fragment {
|
||||
// TODO ANIMATION
|
||||
//postponeEnterTransition();
|
||||
|
||||
viewParent = (ViewGroup) view.getParent();
|
||||
viewParent = (ViewGroup) getView().getParent();
|
||||
|
||||
b.emailList.setLayoutManager(new LinearLayoutManager(view.getContext()));
|
||||
b.emailList.addItemDecoration(new SimpleDividerItemDecoration(view.getContext()));
|
||||
b.emailList.setLayoutManager(new LinearLayoutManager(getView().getContext()));
|
||||
b.emailList.addItemDecoration(new SimpleDividerItemDecoration(getView().getContext()));
|
||||
b.emailList.setAdapter(messagesAdapter);
|
||||
b.emailList.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
|
||||
if (b.emailList.canScrollVertically(-1)) {
|
||||
setSwipeToRefresh(false);
|
||||
}
|
||||
if (!b.emailList.canScrollVertically(-1) && newState == SCROLL_STATE_IDLE) {
|
||||
setSwipeToRefresh(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (messageType == Message.TYPE_RECEIVED) {
|
||||
App.db.messageDao().getReceived(App.Companion.getProfileId()).observe(this, messageFulls -> {
|
||||
@ -215,7 +227,7 @@ public class MessagesListFragment extends Fragment {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void createMessageList(List<MessageFull> messageFulls) {
|
||||
|
@ -1,71 +1,62 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.notifications
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.databinding.NotificationsListItemBinding
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class NotificationsAdapter(
|
||||
private val context: Context
|
||||
) : RecyclerView.Adapter<NotificationsAdapter.ViewHolder>() {
|
||||
private val activity: AppCompatActivity,
|
||||
val onItemClick: ((item: Notification) -> Unit)? = null
|
||||
) : RecyclerView.Adapter<NotificationsAdapter.ViewHolder>(), CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "NotificationsAdapter"
|
||||
}
|
||||
|
||||
private val app = activity.applicationContext as App
|
||||
// optional: place the manager here
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
var items = listOf<Notification>()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val view = inflater.inflate(R.layout.row_notifications_item, parent, false)
|
||||
val inflater = LayoutInflater.from(activity)
|
||||
val view = NotificationsListItemBinding.inflate(inflater, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val app = context.applicationContext as App
|
||||
val item = items[position]
|
||||
val b = holder.b
|
||||
|
||||
val notification = items[position]
|
||||
val date = Date.fromMillis(item.addedDate).formattedString
|
||||
val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity)
|
||||
|
||||
val date = Date.fromMillis(notification.addedDate).formattedString
|
||||
val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(context)
|
||||
|
||||
holder.title.text = notification.text
|
||||
holder.profileDate.text = listOf(
|
||||
notification.profileName ?: "",
|
||||
b.title.text = item.text
|
||||
b.profileDate.text = listOf(
|
||||
item.profileName ?: "",
|
||||
" • ",
|
||||
date.asColoredSpannable(colorSecondary)
|
||||
).concat()
|
||||
holder.type.text = context.getNotificationTitle(notification.type)
|
||||
date
|
||||
).concat().asColoredSpannable(colorSecondary)
|
||||
b.type.text = activity.getNotificationTitle(item.type)
|
||||
|
||||
holder.root.onClick {
|
||||
val intent = Intent("android.intent.action.MAIN")
|
||||
notification.fillIntent(intent)
|
||||
|
||||
d(TAG, "notification with item " + notification.viewId + " extras " + if (intent.extras == null) "null" else intent.extras!!.toString())
|
||||
|
||||
//Log.d(TAG, "Got date "+intent.getLongExtra("timetableDate", 0));
|
||||
|
||||
if (notification.profileId != null && notification.profileId != -1 && notification.profileId != app.profile.id && context is Activity) {
|
||||
Toast.makeText(app, app.getString(R.string.toast_changing_profile), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
app.sendBroadcast(intent)
|
||||
onItemClick?.let { listener ->
|
||||
b.root.onClick { listener(item) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
var root = itemView
|
||||
var title: TextView = itemView.findViewById(R.id.title)
|
||||
var profileDate: TextView = itemView.findViewById(R.id.profileDate)
|
||||
var type: TextView = itemView.findViewById(R.id.type)
|
||||
}
|
||||
class ViewHolder(val b: NotificationsListItemBinding) : RecyclerView.ViewHolder(b.root)
|
||||
}
|
||||
|
@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-22.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.notifications
|
||||
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentNotificationsBinding
|
||||
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
||||
|
||||
|
||||
class NotificationsFragment : Fragment() {
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: FragmentNotificationsBinding
|
||||
|
||||
private val adapter by lazy {
|
||||
NotificationsAdapter(activity)
|
||||
}
|
||||
|
||||
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)
|
||||
if (app.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false)
|
||||
// activity, context and profile is valid
|
||||
b = FragmentNotificationsBinding.inflate(inflater)
|
||||
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_remove_notifications)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_delete_sweep_outline)
|
||||
.withOnClickListener(View.OnClickListener {
|
||||
activity.bottomSheet.close()
|
||||
AsyncTask.execute { app.db.notificationDao().clearAll() }
|
||||
Toast.makeText(activity, R.string.menu_remove_notifications_success, Toast.LENGTH_SHORT).show()
|
||||
}))
|
||||
|
||||
app.db.notificationDao()
|
||||
.getAll()
|
||||
.observe(this, Observer { notifications ->
|
||||
if (app.profile == null || !isAdded) return@Observer
|
||||
|
||||
adapter.items = notifications
|
||||
if (b.notificationsView.adapter == null) {
|
||||
b.notificationsView.adapter = adapter
|
||||
b.notificationsView.apply {
|
||||
setHasFixedSize(true)
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
addItemDecoration(SimpleDividerItemDecoration(context))
|
||||
}
|
||||
}
|
||||
adapter.notifyDataSetChanged()
|
||||
|
||||
if (notifications != null && notifications.isNotEmpty()) {
|
||||
b.notificationsView.visibility = View.VISIBLE
|
||||
b.notificationsNoData.visibility = View.GONE
|
||||
} else {
|
||||
b.notificationsView.visibility = View.GONE
|
||||
b.notificationsNoData.visibility = View.VISIBLE
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-22.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.notifications
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.databinding.NotificationsListFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class NotificationsListFragment : Fragment(), CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "NotificationsListFragment"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: NotificationsListFragmentBinding
|
||||
|
||||
private val job: 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
|
||||
b = NotificationsListFragmentBinding.inflate(inflater)
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { startCoroutineTimer(100L) {
|
||||
if (!isAdded) return@startCoroutineTimer
|
||||
|
||||
activity.bottomSheet.prependItems(
|
||||
BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_remove_notifications)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_delete_sweep_outline)
|
||||
.withOnClickListener(View.OnClickListener {
|
||||
activity.bottomSheet.close()
|
||||
AsyncTask.execute { app.db.notificationDao().clearAll() }
|
||||
Toast.makeText(activity, R.string.menu_remove_notifications_success, Toast.LENGTH_SHORT).show()
|
||||
}))
|
||||
|
||||
val adapter = NotificationsAdapter(activity) { notification ->
|
||||
val intent = Intent("android.intent.action.MAIN")
|
||||
notification.fillIntent(intent)
|
||||
|
||||
Utils.d(TAG, "notification with item " + notification.viewId + " extras " + if (intent.extras == null) "null" else intent.extras!!.toString())
|
||||
if (notification.profileId != null && notification.profileId != -1 && notification.profileId != app.profile.id && context is Activity) {
|
||||
Toast.makeText(app, app.getString(R.string.toast_changing_profile), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
app.sendBroadcast(intent)
|
||||
}
|
||||
|
||||
app.db.notificationDao().getAll().observe(this, Observer { items ->
|
||||
if (!isAdded) return@Observer
|
||||
|
||||
// load & configure the adapter
|
||||
adapter.items = items
|
||||
if (items.isNotNullNorEmpty() && b.list.adapter == null) {
|
||||
b.list.adapter = adapter
|
||||
b.list.apply {
|
||||
setHasFixedSize(true)
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
addItemDecoration(SimpleDividerItemDecoration(context))
|
||||
}
|
||||
}
|
||||
adapter.notifyDataSetChanged()
|
||||
|
||||
// show/hide relevant views
|
||||
b.progressBar.isVisible = false
|
||||
if (items.isNullOrEmpty()) {
|
||||
b.list.isVisible = false
|
||||
b.noData.isVisible = true
|
||||
} else {
|
||||
b.list.isVisible = true
|
||||
b.noData.isVisible = false
|
||||
}
|
||||
})
|
||||
}}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-30.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.template
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification
|
||||
import pl.szczodrzynski.edziennik.databinding.TemplateListItemBinding
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class TemplateAdapter(
|
||||
val activity: AppCompatActivity,
|
||||
val onItemClick: ((item: Notification) -> Unit)? = null
|
||||
) : RecyclerView.Adapter<TemplateAdapter.ViewHolder>(), CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "TemplateAdapter"
|
||||
}
|
||||
|
||||
private val app = activity.applicationContext as App
|
||||
// optional: place the manager here
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
var items = listOf<Notification>()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
val view = TemplateListItemBinding.inflate(inflater, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = items[position]
|
||||
val b = holder.b
|
||||
|
||||
val date = Date.fromMillis(item.addedDate).formattedString
|
||||
val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity)
|
||||
|
||||
b.title.text = item.text
|
||||
b.profileDate.text = listOf(
|
||||
item.profileName ?: "",
|
||||
" • ",
|
||||
date
|
||||
).concat().asColoredSpannable(colorSecondary)
|
||||
b.type.text = activity.getNotificationTitle(item.type)
|
||||
|
||||
onItemClick?.let { listener ->
|
||||
b.root.onClick { listener(item) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
class ViewHolder(val b: TemplateListItemBinding) : RecyclerView.ViewHolder(b.root)
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-8.
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-30.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs
|
||||
package pl.szczodrzynski.edziennik.ui.modules.template
|
||||
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-30.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.template
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
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.addOnPageSelectedListener
|
||||
import pl.szczodrzynski.edziennik.databinding.TemplateFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.FragmentLazyPagerAdapter
|
||||
import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class TemplateFragment : Fragment(), CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "TemplateFragment"
|
||||
var pageSelection = 0
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: TemplateFragmentBinding
|
||||
|
||||
private val job: Job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
// local/private variables go here
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
context ?: return null
|
||||
app = activity.application as App
|
||||
b = TemplateFragmentBinding.inflate(inflater)
|
||||
b.refreshLayout.setParent(activity.swipeRefreshLayout)
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
if (!isAdded) return
|
||||
|
||||
val pagerAdapter = FragmentLazyPagerAdapter(
|
||||
fragmentManager ?: return,
|
||||
b.refreshLayout,
|
||||
listOf(
|
||||
TemplatePageFragment() to "Pager 0",
|
||||
TemplatePageFragment() to "Pager 1",
|
||||
TemplatePageFragment() to "Pager 2",
|
||||
TemplatePageFragment() to "Pager 3",
|
||||
TemplateListPageFragment() to "Pager 4",
|
||||
TemplateListPageFragment() to "Pager 5",
|
||||
TemplateListPageFragment() to "Pager 6",
|
||||
TemplateListPageFragment() to "Pager 7"
|
||||
)
|
||||
)
|
||||
b.viewPager.apply {
|
||||
offscreenPageLimit = 1
|
||||
adapter = pagerAdapter
|
||||
currentItem = pageSelection
|
||||
addOnPageSelectedListener {
|
||||
HomeworkFragment.pageSelection = it
|
||||
}
|
||||
b.tabLayout.setupWithViewPager(this)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-30.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.template
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.databinding.TemplateListFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class TemplateListFragment : Fragment(), CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "TemplateListFragment"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: TemplateListFragmentBinding
|
||||
|
||||
private val job: Job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
// local/private variables go here
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
context ?: return null
|
||||
app = activity.application as App
|
||||
b = TemplateListFragmentBinding.inflate(inflater)
|
||||
b.refreshLayout.setParent(activity.swipeRefreshLayout)
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { startCoroutineTimer(100L) {
|
||||
if (!isAdded) return@startCoroutineTimer
|
||||
|
||||
val adapter = TemplateAdapter(activity)
|
||||
|
||||
app.db.notificationDao().getAll().observe(this, Observer { items ->
|
||||
if (!isAdded) return@Observer
|
||||
|
||||
// load & configure the adapter
|
||||
adapter.items = items
|
||||
if (items.isNotNullNorEmpty() && b.list.adapter == null) {
|
||||
b.list.adapter = adapter
|
||||
b.list.apply {
|
||||
setHasFixedSize(true)
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
addItemDecoration(SimpleDividerItemDecoration(context))
|
||||
addOnScrollListener(b.refreshLayout.onScrollListener)
|
||||
}
|
||||
}
|
||||
adapter.notifyDataSetChanged()
|
||||
b.refreshLayout.isEnabled = false // TODO
|
||||
|
||||
// show/hide relevant views
|
||||
b.progressBar.isVisible = false
|
||||
if (items.isNullOrEmpty()) {
|
||||
b.list.isVisible = false
|
||||
b.noData.isVisible = true
|
||||
} else {
|
||||
b.list.isVisible = true
|
||||
b.noData.isVisible = false
|
||||
}
|
||||
})
|
||||
}}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-30.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.template
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
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.databinding.TemplateListPageFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||
import pl.szczodrzynski.edziennik.startCoroutineTimer
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment
|
||||
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class TemplateListPageFragment : LazyFragment(), CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "TemplateListPagerFragment"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: TemplateListPageFragmentBinding
|
||||
|
||||
private val job: Job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
// local/private variables go here
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
context ?: return null
|
||||
app = activity.application as App
|
||||
b = TemplateListPageFragmentBinding.inflate(inflater)
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onPageCreated(): Boolean { startCoroutineTimer(100L) {
|
||||
val adapter = TemplateAdapter(activity)
|
||||
|
||||
app.db.notificationDao().getAll().observe(this, Observer { items ->
|
||||
if (!isAdded) return@Observer
|
||||
|
||||
// load & configure the adapter
|
||||
adapter.items = items
|
||||
if (items.isNotNullNorEmpty() && b.list.adapter == null) {
|
||||
b.list.adapter = adapter
|
||||
b.list.apply {
|
||||
setHasFixedSize(true)
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
addItemDecoration(SimpleDividerItemDecoration(context))
|
||||
addOnScrollListener(onScrollListener)
|
||||
}
|
||||
}
|
||||
adapter.notifyDataSetChanged()
|
||||
setSwipeToRefresh(false) // TODO
|
||||
|
||||
// show/hide relevant views
|
||||
b.progressBar.isVisible = false
|
||||
if (items.isNullOrEmpty()) {
|
||||
b.list.isVisible = false
|
||||
b.noData.isVisible = true
|
||||
} else {
|
||||
b.list.isVisible = true
|
||||
b.noData.isVisible = false
|
||||
}
|
||||
})
|
||||
}; return true }
|
||||
}
|
@ -1,26 +1,30 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.base
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-30.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.template
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
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.databinding.FragmentTemplateBinding
|
||||
import pl.szczodrzynski.edziennik.databinding.TemplatePageFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class TemplateFragment : Fragment(), CoroutineScope {
|
||||
class TemplatePageFragment : LazyFragment(), CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "TemplateFragment"
|
||||
private const val TAG = "TemplatePagerFragment"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: FragmentTemplateBinding
|
||||
private lateinit var b: TemplatePageFragmentBinding
|
||||
|
||||
private val job: Job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
@ -32,15 +36,16 @@ class TemplateFragment : Fragment(), CoroutineScope {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
context ?: return null
|
||||
app = activity.application as App
|
||||
b = FragmentTemplateBinding.inflate(inflater)
|
||||
b.refreshLayout.setParent(activity.swipeRefreshLayout)
|
||||
b = TemplatePageFragmentBinding.inflate(inflater)
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
if (!isAdded)
|
||||
return
|
||||
|
||||
override fun onPageCreated(): Boolean {
|
||||
b.text.text = "Fragment $position"
|
||||
|
||||
b.button.addOnCheckedChangeListener { button, isChecked ->
|
||||
setSwipeToRefresh(isChecked)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-3-30.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.template
|
||||
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyPagerAdapter
|
||||
|
||||
class TemplatePagerAdapter(fragmentManager: FragmentManager, swipeRefreshLayout: SwipeRefreshLayout) : LazyPagerAdapter(fragmentManager, swipeRefreshLayout) {
|
||||
override fun getPage(position: Int) = TemplatePageFragment()
|
||||
override fun getPageTitle(position: Int) = "Page $position"
|
||||
override fun getCount() = 10
|
||||
}
|
@ -27,7 +27,7 @@ import pl.szczodrzynski.edziennik.data.db.full.LessonFull
|
||||
import pl.szczodrzynski.edziennik.databinding.TimetableLessonBinding
|
||||
import pl.szczodrzynski.edziennik.databinding.TimetableNoTimetableBinding
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.timetable.LessonDetailsDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.PagerFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.timetable.TimetableFragment.Companion.DEFAULT_END_HOUR
|
||||
import pl.szczodrzynski.edziennik.ui.modules.timetable.TimetableFragment.Companion.DEFAULT_START_HOUR
|
||||
import pl.szczodrzynski.edziennik.utils.ListenerScrollView
|
||||
@ -36,7 +36,7 @@ import java.util.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.math.min
|
||||
|
||||
class TimetableDayFragment : PagerFragment(), CoroutineScope {
|
||||
class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "TimetableDayFragment"
|
||||
}
|
||||
@ -104,9 +104,6 @@ class TimetableDayFragment : PagerFragment(), CoroutineScope {
|
||||
}
|
||||
|
||||
override fun onPageCreated(): Boolean {
|
||||
if (!isAdded)
|
||||
return false
|
||||
|
||||
// observe lesson database
|
||||
app.db.timetableDao().getForDate(App.profileId, date).observe(this, Observer { lessons ->
|
||||
launch {
|
||||
@ -216,23 +213,23 @@ class TimetableDayFragment : PagerFragment(), CoroutineScope {
|
||||
LessonDetailsDialog(activity, it.tag as LessonFull)
|
||||
}
|
||||
|
||||
val eventList = events.filter { it.startTime != null && it.startTime == lesson.displayStartTime }.take(3)
|
||||
val eventList = events.filter { it.time != null && it.time == lesson.displayStartTime }.take(3)
|
||||
eventList.getOrNull(0).let {
|
||||
lb.event1.visibility = if (it == null) View.GONE else View.VISIBLE
|
||||
lb.event1.background = it?.let {
|
||||
R.drawable.bg_circle.resolveDrawable(activity).setTintColor(it.getColor())
|
||||
R.drawable.bg_circle.resolveDrawable(activity).setTintColor(it.eventColor)
|
||||
}
|
||||
}
|
||||
eventList.getOrNull(1).let {
|
||||
lb.event2.visibility = if (it == null) View.GONE else View.VISIBLE
|
||||
lb.event2.background = it?.let {
|
||||
R.drawable.bg_circle.resolveDrawable(activity).setTintColor(it.getColor())
|
||||
R.drawable.bg_circle.resolveDrawable(activity).setTintColor(it.eventColor)
|
||||
}
|
||||
}
|
||||
eventList.getOrNull(2).let {
|
||||
lb.event3.visibility = if (it == null) View.GONE else View.VISIBLE
|
||||
lb.event3.background = it?.let {
|
||||
R.drawable.bg_circle.resolveDrawable(activity).setTintColor(it.getColor())
|
||||
R.drawable.bg_circle.resolveDrawable(activity).setTintColor(it.eventColor)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,9 +5,9 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.timetable
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyPagerAdapter
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||
|
||||
@ -16,7 +16,7 @@ class TimetablePagerAdapter(
|
||||
private val items: List<Date>,
|
||||
private val startHour: Int,
|
||||
private val endHour: Int
|
||||
) : FragmentStatePagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
|
||||
) : LazyPagerAdapter(fragmentManager, null) {
|
||||
companion object {
|
||||
private const val TAG = "TimetablePagerAdapter"
|
||||
}
|
||||
@ -25,7 +25,7 @@ class TimetablePagerAdapter(
|
||||
private val weekStart by lazy { today.weekStart }
|
||||
private val weekEnd by lazy { weekStart.clone().stepForward(0, 0, 6) }
|
||||
|
||||
override fun getItem(position: Int): Fragment {
|
||||
override fun getPage(position: Int): LazyFragment {
|
||||
return TimetableDayFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putInt("date", items[position].value)
|
||||
@ -39,7 +39,7 @@ class TimetablePagerAdapter(
|
||||
return items.size
|
||||
}
|
||||
|
||||
override fun getPageTitle(position: Int): CharSequence? {
|
||||
override fun getPageTitle(position: Int): CharSequence {
|
||||
val date = items[position]
|
||||
val pageTitle = StringBuilder(Week.getFullDayName(date.weekDay))
|
||||
if (date > weekEnd || date < weekStart) {
|
||||
|
@ -27,7 +27,7 @@ import com.mikepenz.iconics.utils.colorInt
|
||||
import com.mikepenz.iconics.utils.sizeDp
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.TYPE_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Lesson.Companion.TYPE_NO_LESSONS
|
||||
import pl.szczodrzynski.edziennik.ui.widgets.LessonDialogActivity
|
||||
@ -289,7 +289,7 @@ class WidgetTimetableProvider : AppWidgetProvider() {
|
||||
}
|
||||
|
||||
// get all events for the current date
|
||||
val events = app.db.eventDao().getAllByDateNow(profile.id, timetableDate)?.filterNotNull() ?: emptyList()
|
||||
val events = app.db.eventDao().getAllByDateNow(profile.id, timetableDate)
|
||||
|
||||
lessons.forEachIndexed { pos, lesson ->
|
||||
if (lesson.type == TYPE_NO_LESSONS)
|
||||
@ -345,9 +345,9 @@ class WidgetTimetableProvider : AppWidgetProvider() {
|
||||
|
||||
// add every event on this lesson
|
||||
for (event in events) {
|
||||
if (event.startTime == null || event.startTime != lesson.displayStartTime)
|
||||
if (event.time == null || event.time != lesson.displayStartTime)
|
||||
continue
|
||||
model.eventColors.add(if (event.type == TYPE_HOMEWORK) ItemWidgetTimetableModel.EVENT_COLOR_HOMEWORK else event.getColor())
|
||||
model.eventColors.add(if (event.type == TYPE_HOMEWORK) ItemWidgetTimetableModel.EVENT_COLOR_HOMEWORK else event.eventColor)
|
||||
}
|
||||
|
||||
models += model
|
||||
|
@ -137,7 +137,7 @@ public class Date implements Comparable<Date> {
|
||||
}
|
||||
|
||||
public static int diffDays(Date d1, Date d2) {
|
||||
return (int) ((d1.getInMillis() - d2.getInMillis()) / (24 * 60 * 60 * 1000));
|
||||
return Math.round((d1.getInMillis() - d2.getInMillis()) / (24 * 60 * 60 * 1000f));
|
||||
}
|
||||
|
||||
public static boolean isToday(Date date) {
|
||||
@ -254,6 +254,7 @@ public class Date implements Comparable<Date> {
|
||||
/**
|
||||
* @return 2019-06-02
|
||||
*/
|
||||
@NonNull
|
||||
public String getStringY_m_d() {
|
||||
return year + (month < 10 ? "-0" : "-") + month + (day < 10 ? "-0" : "-") + day;
|
||||
}
|
||||
|
34
app/src/main/res/drawable/ic_no_homework.xml
Normal file
34
app/src/main/res/drawable/ic_no_homework.xml
Normal file
@ -0,0 +1,34 @@
|
||||
<!--
|
||||
~ Copyright (c) Kuba Szczodrzyński 2020-3-30.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="128"
|
||||
android:viewportHeight="128">
|
||||
<path
|
||||
android:pathData="m102,24h-74c-4.42,0 -8,3.58 -8,8v72c0,4.42 3.58,8 8,8h74c4.42,0 8,-3.58 8,-8v-72c0,-4.42 -3.58,-8 -8,-8z"
|
||||
android:fillColor="#70d0f3"/>
|
||||
<path
|
||||
android:pathData="m20,32v8h90v-8c0,-4.42 -3.58,-8 -8,-8h-74c-4.42,0 -8,3.58 -8,8z"
|
||||
android:fillColor="#3281e6"/>
|
||||
<path
|
||||
android:pathData="m88,92h-30c-2.21,0 -4,-1.79 -4,-4 0,-2.21 1.79,-4 4,-4h30c2.21,0 4,1.79 4,4 0,2.21 -1.79,4 -4,4zM92,74c0,-2.21 -1.79,-4 -4,-4h-30c-2.21,0 -4,1.79 -4,4 0,2.21 1.79,4 4,4h30c2.21,0 4,-1.79 4,-4zM92,60c0,-2.21 -1.79,-4 -4,-4h-30c-2.21,0 -4,1.79 -4,4 0,2.21 1.79,4 4,4h30c2.21,0 4,-1.79 4,-4zM48,88c0,-2.21 -1.79,-4 -4,-4h-2c-2.21,0 -4,1.79 -4,4 0,2.21 1.79,4 4,4h2c2.21,0 4,-1.79 4,-4zM48,74c0,-2.21 -1.79,-4 -4,-4h-2c-2.21,0 -4,1.79 -4,4 0,2.21 1.79,4 4,4h2c2.21,0 4,-1.79 4,-4zM48,60c0,-2.21 -1.79,-4 -4,-4h-2c-2.21,0 -4,1.79 -4,4 0,2.21 1.79,4 4,4h2c2.21,0 4,-1.79 4,-4z"
|
||||
android:fillColor="#2b83d5"/>
|
||||
<path
|
||||
android:pathData="m127,86.3 l-7.42,-7.42c-1.12,-1.13 -2.96,-1.13 -4.09,0l-3.5,3.49 11.5,11.5 3.49,-3.5c1.13,-1.13 1.13,-2.96 0,-4.09"
|
||||
android:fillColor="#fc657c"/>
|
||||
<path
|
||||
android:pathData="m93.4,124 l-11.5,-11.5 24.5,-24.5 11.5,11.5z"
|
||||
android:fillColor="#ffa859"/>
|
||||
<path
|
||||
android:pathData="m118,99.6 l-11.5,-11.5 5.75,-5.76 11.5,11.5z"
|
||||
android:fillColor="#c8c8c8"/>
|
||||
<path
|
||||
android:pathData="m81.9,113 l-3.88,15.4 15.4,-3.88z"
|
||||
android:fillColor="#ffcd98"/>
|
||||
<path
|
||||
android:pathData="m80,120 l-1.96,7.78 7.78,-1.96z"
|
||||
android:fillColor="#818181"/>
|
||||
</vector>
|
@ -81,14 +81,14 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:text="@{event.startTime == null ? @string/event_all_day : event.startTime.stringHM}"
|
||||
android:text="@{event.time == null ? @string/event_all_day : event.time.stringHM}"
|
||||
tools:text="14:50"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:text="@{Integer.toString(event.eventDate.day)}"
|
||||
android:text="@{Integer.toString(event.date.day)}"
|
||||
android:textSize="36sp"
|
||||
tools:text="14" />
|
||||
|
||||
@ -107,13 +107,13 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:text="@string/dialog_event_details_teacher"
|
||||
android:visibility="@{event.teacherFullName != null ? View.VISIBLE : View.GONE}"/>
|
||||
android:visibility="@{event.teacherName != null ? View.VISIBLE : View.GONE}"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{event.teacherFullName}"
|
||||
android:text="@{event.teacherName}"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="@{event.teacherFullName != null ? View.VISIBLE : View.GONE}"
|
||||
android:visibility="@{event.teacherName != null ? View.VISIBLE : View.GONE}"
|
||||
tools:text="Janósz Kowalski" />
|
||||
|
||||
<TextView
|
||||
@ -195,6 +195,18 @@
|
||||
android:text="\uFCDA"
|
||||
android:textSize="20sp"
|
||||
android:fontFamily="@font/community_material_font_v3_5_95_1" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/checkDoneButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:minWidth="0dp"
|
||||
android:checkable="true"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:text="\uFCE1"
|
||||
android:textSize="20sp"
|
||||
android:fontFamily="@font/community_material_font_v3_5_95_1" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
@ -4,7 +4,8 @@
|
||||
-->
|
||||
|
||||
<layout xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<data>
|
||||
<import type="android.view.View"/>
|
||||
@ -54,22 +55,35 @@
|
||||
android:id="@+id/topic"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_marginRight="4dp"
|
||||
android:layout_weight="1"
|
||||
android:textAppearance="@style/NavView.TextView.Medium"
|
||||
android:maxLines="@{simpleMode ? 2 : 3}"
|
||||
android:ellipsize="end"
|
||||
tools:maxLines="3"
|
||||
android:maxLines="3"
|
||||
android:textAppearance="@style/NavView.TextView.Medium"
|
||||
tools:text="Rozdział II: Panowanie Piastów i Jagiellonów.Przeniesiony z 11 grudnia. Nie wiem co się dzieje w tym roku nie będzie już religii w szkołach podstawowych w Polsce i Europie zachodniej Afryki" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/editButton"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/community_material_font_v3_5_95_1"
|
||||
android:minWidth="0dp"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:text="\uFC92"
|
||||
android:textSize="20sp"
|
||||
android:fontFamily="@font/community_material_font_v3_5_95_1"/>
|
||||
tools:visibility="gone" />
|
||||
|
||||
<com.mikepenz.iconics.view.IconicsImageView
|
||||
android:id="@+id/isDone"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="top"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginRight="4dp"
|
||||
app:iiv_color="@color/md_green_500"
|
||||
app:iiv_icon="cmd-check"
|
||||
tools:background="@sample/check" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
app:tabSelectedTextColor="?colorPrimary"
|
||||
app:tabTextColor="?android:textColorPrimary"/>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
<pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyViewPager
|
||||
android:id="@+id/viewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@ -29,4 +29,4 @@
|
||||
</LinearLayout>
|
||||
|
||||
</pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoIndicator>
|
||||
</layout>
|
||||
</layout>
|
||||
|
@ -28,7 +28,7 @@
|
||||
android:id="@+id/tabLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:background="@color/colorSurface_6dp"
|
||||
android:background="@color/colorSurface_1dp"
|
||||
app:rtl_tabIndicatorColor="?colorPrimary"
|
||||
app:rtl_tabMaxWidth="300dp"
|
||||
app:rtl_tabMinWidth="90dp"
|
||||
@ -40,7 +40,7 @@
|
||||
app:rtl_tabTextAppearance="@style/rtl_RecyclerTabLayout.Tab" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
<pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyViewPager
|
||||
android:id="@+id/viewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@ -94,4 +94,4 @@
|
||||
|
||||
</FrameLayout>
|
||||
<!--</pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoIndicator>-->
|
||||
</layout>
|
||||
</layout>
|
||||
|
@ -16,8 +16,14 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/gradesNoData"
|
||||
android:id="@+id/noData"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
@ -25,13 +31,17 @@
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:text="@string/grades_no_data"
|
||||
android:textSize="24sp"
|
||||
app:drawableTopCompat="@drawable/ic_no_grades" />
|
||||
android:visibility="gone"
|
||||
app:drawableTopCompat="@drawable/ic_no_grades"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/gradesRecyclerView"
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:listitem="@layout/grades_item_subject" />
|
||||
android:visibility="gone"
|
||||
tools:listitem="@layout/grades_item_subject"
|
||||
tools:visibility="visible" />
|
||||
</FrameLayout>
|
||||
</pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoIndicator>
|
||||
</layout>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user