Timetable timer refactor (#1785)
This commit is contained in:
parent
c3abe50ed4
commit
57ea6379ab
6 changed files with 190 additions and 206 deletions
12
.editorconfig
Normal file
12
.editorconfig
Normal file
|
@ -0,0 +1,12 @@
|
|||
[*]
|
||||
charset=utf-8
|
||||
end_of_line=lf
|
||||
insert_final_newline=true
|
||||
indent_style=space
|
||||
indent_size=4
|
||||
|
||||
[*.json]
|
||||
indent_size=2
|
||||
|
||||
[*.{kt,kts}]
|
||||
disabled_rules=import-ordering,no-wildcard-imports
|
|
@ -1,116 +1,69 @@
|
|||
package io.github.wulkanowy.ui.modules.timetable
|
||||
|
||||
import android.graphics.Paint
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.enums.TimetableMode
|
||||
import io.github.wulkanowy.databinding.ItemTimetableBinding
|
||||
import io.github.wulkanowy.databinding.ItemTimetableSmallBinding
|
||||
import io.github.wulkanowy.utils.*
|
||||
import timber.log.Timber
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import javax.inject.Inject
|
||||
import kotlin.concurrent.timer
|
||||
|
||||
class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
class TimetableAdapter @Inject constructor() :
|
||||
ListAdapter<TimetableItem, RecyclerView.ViewHolder>(differ) {
|
||||
|
||||
private enum class ViewType {
|
||||
ITEM_NORMAL,
|
||||
ITEM_SMALL
|
||||
}
|
||||
|
||||
var onClickListener: (Timetable) -> Unit = {}
|
||||
|
||||
private var showWholeClassPlan = TimetableMode.ONLY_CURRENT_GROUP
|
||||
|
||||
private var showGroupsInPlan: Boolean = false
|
||||
|
||||
private var showTimers: Boolean = false
|
||||
|
||||
private val timers = mutableMapOf<Int, Timer?>()
|
||||
|
||||
private val items = mutableListOf<Timetable>()
|
||||
|
||||
fun submitList(
|
||||
newTimetable: List<Timetable>,
|
||||
showWholeClassPlan: TimetableMode = this.showWholeClassPlan,
|
||||
showGroupsInPlan: Boolean = this.showGroupsInPlan,
|
||||
showTimers: Boolean = this.showTimers
|
||||
) {
|
||||
val isFlagsDifferent = this.showWholeClassPlan != showWholeClassPlan
|
||||
|| this.showGroupsInPlan != showGroupsInPlan
|
||||
|| this.showTimers != showTimers
|
||||
|
||||
val diffResult = DiffUtil.calculateDiff(
|
||||
TimetableAdapterDiffCallback(
|
||||
oldList = items.toMutableList(),
|
||||
newList = newTimetable,
|
||||
isFlagsDifferent = isFlagsDifferent
|
||||
)
|
||||
)
|
||||
|
||||
this.showGroupsInPlan = showGroupsInPlan
|
||||
this.showTimers = showTimers
|
||||
this.showWholeClassPlan = showWholeClassPlan
|
||||
|
||||
items.clear()
|
||||
items.addAll(newTimetable)
|
||||
|
||||
diffResult.dispatchUpdatesTo(this)
|
||||
}
|
||||
|
||||
fun clearTimers() {
|
||||
Timber.d("Timetable timers (${timers.size}) cleared")
|
||||
with(timers) {
|
||||
forEach { (_, timer) ->
|
||||
timer?.cancel()
|
||||
timer?.purge()
|
||||
}
|
||||
clear()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
override fun getItemViewType(position: Int) = when {
|
||||
!items[position].isStudentPlan && showWholeClassPlan == TimetableMode.SMALL_OTHER_GROUP -> ViewType.ITEM_SMALL.ordinal
|
||||
else -> ViewType.ITEM_NORMAL.ordinal
|
||||
}
|
||||
override fun getItemViewType(position: Int): Int = getItem(position).type.ordinal
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
|
||||
return when (viewType) {
|
||||
ViewType.ITEM_NORMAL.ordinal -> ItemViewHolder(
|
||||
ItemTimetableBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
ViewType.ITEM_SMALL.ordinal -> SmallItemViewHolder(
|
||||
return when (TimetableItemType.values()[viewType]) {
|
||||
TimetableItemType.SMALL -> SmallViewHolder(
|
||||
ItemTimetableSmallBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
else -> throw IllegalStateException()
|
||||
TimetableItemType.NORMAL -> NormalViewHolder(
|
||||
ItemTimetableBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(
|
||||
holder: RecyclerView.ViewHolder,
|
||||
position: Int,
|
||||
payloads: MutableList<Any>
|
||||
) {
|
||||
if (payloads.isEmpty()) return super.onBindViewHolder(holder, position, payloads)
|
||||
|
||||
if (holder is NormalViewHolder) updateTimeLeft(
|
||||
binding = holder.binding,
|
||||
timeLeft = (getItem(position) as TimetableItem.Normal).timeLeft,
|
||||
)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val lesson = items[position]
|
||||
|
||||
when (holder) {
|
||||
is ItemViewHolder -> bindNormalView(holder.binding, lesson, position)
|
||||
is SmallItemViewHolder -> bindSmallView(holder.binding, lesson)
|
||||
is SmallViewHolder -> bindSmallView(
|
||||
binding = holder.binding,
|
||||
item = getItem(position) as TimetableItem.Small,
|
||||
)
|
||||
is NormalViewHolder -> bindNormalView(
|
||||
binding = holder.binding,
|
||||
item = getItem(position) as TimetableItem.Normal,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindSmallView(binding: ItemTimetableSmallBinding, lesson: Timetable) {
|
||||
private fun bindSmallView(binding: ItemTimetableSmallBinding, item: TimetableItem.Small) {
|
||||
val lesson = item.lesson
|
||||
|
||||
with(binding) {
|
||||
timetableSmallItemNumber.text = lesson.number.toString()
|
||||
timetableSmallItemSubject.text = lesson.subject
|
||||
|
@ -122,11 +75,13 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||
bindSmallDescription(binding, lesson)
|
||||
bindSmallColors(binding, lesson)
|
||||
|
||||
root.setOnClickListener { onClickListener(lesson) }
|
||||
root.setOnClickListener { item.onClick(lesson) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindNormalView(binding: ItemTimetableBinding, lesson: Timetable, position: Int) {
|
||||
private fun bindNormalView(binding: ItemTimetableBinding, item: TimetableItem.Normal) {
|
||||
val lesson = item.lesson
|
||||
|
||||
with(binding) {
|
||||
timetableItemNumber.text = lesson.number.toString()
|
||||
timetableItemSubject.text = lesson.subject
|
||||
|
@ -137,51 +92,19 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||
timetableItemTimeFinish.text = lesson.end.toFormattedString("HH:mm")
|
||||
|
||||
bindSubjectStyle(timetableItemSubject, lesson)
|
||||
bindNormalDescription(binding, lesson)
|
||||
bindNormalDescription(binding, item)
|
||||
bindNormalColors(binding, lesson)
|
||||
updateTimeLeft(binding, item.timeLeft)
|
||||
|
||||
timers[position]?.let {
|
||||
it.cancel()
|
||||
it.purge()
|
||||
}
|
||||
timers[position] = null
|
||||
|
||||
if (lesson.isStudentPlan && showTimers) {
|
||||
timers[position] = timer(period = 1000) {
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
updateTimeLeft(binding, lesson, position)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// reset item on set changed
|
||||
timetableItemTimeUntil.visibility = GONE
|
||||
timetableItemTimeLeft.visibility = GONE
|
||||
}
|
||||
|
||||
root.setOnClickListener { onClickListener(lesson) }
|
||||
root.setOnClickListener { item.onClick(lesson) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPreviousLesson(position: Int): Instant? {
|
||||
return items.filter { it.isStudentPlan }
|
||||
.getOrNull(position - 1 - items.filterIndexed { i, item -> i < position && !item.isStudentPlan }.size)
|
||||
?.let {
|
||||
if (!it.canceled && it.isStudentPlan) it.end
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTimeLeft(binding: ItemTimetableBinding, lesson: Timetable, position: Int) {
|
||||
val isShowTimeUntil = lesson.isShowTimeUntil(getPreviousLesson(position))
|
||||
val until = lesson.until.plusMinutes(1)
|
||||
val left = lesson.left?.plusMinutes(1)
|
||||
val isJustFinished = lesson.isJustFinished
|
||||
|
||||
private fun updateTimeLeft(binding: ItemTimetableBinding, timeLeft: TimeLeft?) {
|
||||
with(binding) {
|
||||
when {
|
||||
// before lesson
|
||||
isShowTimeUntil -> {
|
||||
Timber.d("Show time until lesson: $position")
|
||||
timeLeft?.until != null -> {
|
||||
timetableItemTimeLeft.visibility = GONE
|
||||
with(timetableItemTimeUntil) {
|
||||
visibility = VISIBLE
|
||||
|
@ -189,14 +112,13 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||
R.string.timetable_time_until,
|
||||
context.getString(
|
||||
R.string.timetable_minutes,
|
||||
until.toMinutes().toString(10)
|
||||
timeLeft.until.toMinutes().toString(10)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
// after lesson start
|
||||
left != null -> {
|
||||
Timber.d("Show time left lesson: $position")
|
||||
timeLeft?.left != null -> {
|
||||
timetableItemTimeUntil.visibility = GONE
|
||||
with(timetableItemTimeLeft) {
|
||||
visibility = VISIBLE
|
||||
|
@ -204,14 +126,13 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||
R.string.timetable_time_left,
|
||||
context.getString(
|
||||
R.string.timetable_minutes,
|
||||
left.toMinutes().toString()
|
||||
timeLeft.left.toMinutes().toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
// right after lesson finish
|
||||
isJustFinished -> {
|
||||
Timber.d("Show just finished lesson: $position")
|
||||
timeLeft?.isJustFinished == true -> {
|
||||
timetableItemTimeUntil.visibility = GONE
|
||||
timetableItemTimeLeft.visibility = VISIBLE
|
||||
timetableItemTimeLeft.text = root.context.getString(R.string.timetable_finished)
|
||||
|
@ -225,9 +146,7 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||
}
|
||||
|
||||
private fun bindSubjectStyle(subjectView: TextView, lesson: Timetable) {
|
||||
subjectView.paintFlags =
|
||||
if (lesson.canceled) subjectView.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
|
||||
else subjectView.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
|
||||
subjectView.paint.isStrikeThruText = lesson.canceled
|
||||
}
|
||||
|
||||
private fun bindSmallDescription(binding: ItemTimetableSmallBinding, lesson: Timetable) {
|
||||
|
@ -253,7 +172,8 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||
}
|
||||
}
|
||||
|
||||
private fun bindNormalDescription(binding: ItemTimetableBinding, lesson: Timetable) {
|
||||
private fun bindNormalDescription(binding: ItemTimetableBinding, item: TimetableItem.Normal) {
|
||||
val lesson = item.lesson
|
||||
with(binding) {
|
||||
if (lesson.info.isNotBlank() && !lesson.changes) {
|
||||
timetableItemDescription.visibility = VISIBLE
|
||||
|
@ -272,8 +192,7 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||
} else {
|
||||
timetableItemDescription.visibility = GONE
|
||||
timetableItemRoom.visibility = VISIBLE
|
||||
timetableItemGroup.visibility =
|
||||
if (showGroupsInPlan && lesson.group.isNotBlank()) VISIBLE else GONE
|
||||
timetableItemGroup.isVisible = item.showGroupsInPlan && lesson.group.isNotBlank()
|
||||
timetableItemTeacher.visibility = VISIBLE
|
||||
}
|
||||
}
|
||||
|
@ -349,26 +268,35 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||
)
|
||||
}
|
||||
|
||||
private class ItemViewHolder(val binding: ItemTimetableBinding) :
|
||||
private class NormalViewHolder(val binding: ItemTimetableBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
private class SmallItemViewHolder(val binding: ItemTimetableSmallBinding) :
|
||||
private class SmallViewHolder(val binding: ItemTimetableSmallBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
class TimetableAdapterDiffCallback(
|
||||
private val oldList: List<Timetable>,
|
||||
private val newList: List<Timetable>,
|
||||
private val isFlagsDifferent: Boolean
|
||||
) : DiffUtil.Callback() {
|
||||
companion object {
|
||||
private val differ = object : DiffUtil.ItemCallback<TimetableItem>() {
|
||||
override fun areItemsTheSame(oldItem: TimetableItem, newItem: TimetableItem): Boolean =
|
||||
when {
|
||||
oldItem is TimetableItem.Small && newItem is TimetableItem.Small -> {
|
||||
oldItem.lesson.start == newItem.lesson.start
|
||||
}
|
||||
oldItem is TimetableItem.Normal && newItem is TimetableItem.Normal -> {
|
||||
oldItem.lesson.start == newItem.lesson.start
|
||||
}
|
||||
else -> oldItem == newItem
|
||||
}
|
||||
|
||||
override fun getOldListSize() = oldList.size
|
||||
override fun areContentsTheSame(oldItem: TimetableItem, newItem: TimetableItem) =
|
||||
oldItem == newItem
|
||||
|
||||
override fun getNewListSize() = newList.size
|
||||
|
||||
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
|
||||
oldList[oldItemPosition].id == newList[newItemPosition].id
|
||||
|
||||
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
|
||||
oldList[oldItemPosition] == newList[newItemPosition] && !isFlagsDifferent
|
||||
override fun getChangePayload(oldItem: TimetableItem, newItem: TimetableItem): Any? {
|
||||
return if (oldItem is TimetableItem.Normal && newItem is TimetableItem.Normal) {
|
||||
if (oldItem.lesson == newItem.lesson && oldItem.timeLeft != newItem.timeLeft) {
|
||||
"time_left"
|
||||
} else super.getChangePayload(oldItem, newItem)
|
||||
} else super.getChangePayload(oldItem, newItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.enums.TimetableMode
|
||||
import io.github.wulkanowy.databinding.FragmentTimetableBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
|
@ -20,11 +19,7 @@ import io.github.wulkanowy.ui.modules.main.MainView
|
|||
import io.github.wulkanowy.ui.modules.timetable.additional.AdditionalLessonsFragment
|
||||
import io.github.wulkanowy.ui.modules.timetable.completed.CompletedLessonsFragment
|
||||
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||
import io.github.wulkanowy.utils.dpToPx
|
||||
import io.github.wulkanowy.utils.firstSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.openMaterialDatePicker
|
||||
import io.github.wulkanowy.utils.*
|
||||
import java.time.LocalDate
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -73,8 +68,6 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
|
|||
}
|
||||
|
||||
override fun initView() {
|
||||
timetableAdapter.onClickListener = presenter::onTimetableItemSelected
|
||||
|
||||
with(binding.timetableRecycler) {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
adapter = timetableAdapter
|
||||
|
@ -110,18 +103,8 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
|
|||
}
|
||||
}
|
||||
|
||||
override fun updateData(
|
||||
data: List<Timetable>,
|
||||
showWholeClassPlanType: TimetableMode,
|
||||
showGroupsInPlanType: Boolean,
|
||||
showTimetableTimers: Boolean
|
||||
) {
|
||||
timetableAdapter.submitList(
|
||||
newTimetable = data.toMutableList(),
|
||||
showGroupsInPlan = showGroupsInPlanType,
|
||||
showTimers = showTimetableTimers,
|
||||
showWholeClassPlan = showWholeClassPlanType
|
||||
)
|
||||
override fun updateData(data: List<TimetableItem>) {
|
||||
timetableAdapter.submitList(data)
|
||||
}
|
||||
|
||||
override fun clearData() {
|
||||
|
@ -214,7 +197,6 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
|
|||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
timetableAdapter.clearTimers()
|
||||
presenter.onDetachView()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package io.github.wulkanowy.ui.modules.timetable
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import java.time.Duration
|
||||
|
||||
sealed class TimetableItem(val type: TimetableItemType) {
|
||||
|
||||
data class Small(
|
||||
val lesson: Timetable,
|
||||
val onClick: (Timetable) -> Unit,
|
||||
) : TimetableItem(TimetableItemType.SMALL)
|
||||
|
||||
data class Normal(
|
||||
val lesson: Timetable,
|
||||
val showGroupsInPlan: Boolean,
|
||||
val timeLeft: TimeLeft?,
|
||||
val onClick: (Timetable) -> Unit,
|
||||
) : TimetableItem(TimetableItemType.NORMAL)
|
||||
}
|
||||
|
||||
data class TimeLeft(
|
||||
val until: Duration?,
|
||||
val left: Duration?,
|
||||
val isJustFinished: Boolean,
|
||||
)
|
||||
|
||||
enum class TimetableItemType {
|
||||
SMALL,
|
||||
NORMAL,
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package io.github.wulkanowy.ui.modules.timetable
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.enums.TimetableMode
|
||||
|
@ -10,25 +9,17 @@ import io.github.wulkanowy.data.repositories.StudentRepository
|
|||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.capitalise
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import io.github.wulkanowy.utils.getLastSchoolDayIfHoliday
|
||||
import io.github.wulkanowy.utils.isHolidays
|
||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||
import io.github.wulkanowy.utils.nextSchoolDay
|
||||
import io.github.wulkanowy.utils.previousSchoolDay
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.*
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDate.now
|
||||
import java.time.LocalDate.of
|
||||
import java.time.LocalDate.ofEpochDay
|
||||
import java.time.LocalDate.*
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.concurrent.timer
|
||||
|
||||
class TimetablePresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
|
@ -46,6 +37,8 @@ class TimetablePresenter @Inject constructor(
|
|||
|
||||
private lateinit var lastError: Throwable
|
||||
|
||||
private var tickTimer: Timer? = null
|
||||
|
||||
fun onAttachView(view: TimetableView, date: Long?) {
|
||||
super.onAttachView(view)
|
||||
view.initView()
|
||||
|
@ -106,11 +99,6 @@ class TimetablePresenter @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun onTimetableItemSelected(lesson: Timetable) {
|
||||
Timber.i("Select timetable item ${lesson.id}")
|
||||
view?.showTimetableDialog(lesson)
|
||||
}
|
||||
|
||||
fun onAdditionalLessonsSwitchSelected(): Boolean {
|
||||
view?.openAdditionalLessonsView()
|
||||
return true
|
||||
|
@ -148,12 +136,12 @@ class TimetablePresenter @Inject constructor(
|
|||
Status.LOADING -> {
|
||||
if (!it.data?.lessons.isNullOrEmpty()) {
|
||||
view?.run {
|
||||
updateData(it.data!!.lessons)
|
||||
enableSwipe(true)
|
||||
showRefresh(true)
|
||||
showErrorView(false)
|
||||
showProgress(false)
|
||||
showContent(true)
|
||||
updateData(it.data!!.lessons)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -189,17 +177,62 @@ class TimetablePresenter @Inject constructor(
|
|||
}
|
||||
|
||||
private fun updateData(lessons: List<Timetable>) {
|
||||
view?.updateData(
|
||||
showWholeClassPlanType = prefRepository.showWholeClassPlan,
|
||||
showGroupsInPlanType = prefRepository.showGroupsInPlan,
|
||||
showTimetableTimers = prefRepository.showTimetableTimers,
|
||||
data = createItems(lessons)
|
||||
tickTimer?.cancel()
|
||||
|
||||
if (!prefRepository.showTimetableTimers) {
|
||||
view?.updateData(createItems(lessons))
|
||||
} else {
|
||||
tickTimer = timer(period = 2_000) {
|
||||
view?.updateData(createItems(lessons))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createItems(items: List<Timetable>): List<TimetableItem> {
|
||||
val filteredItems = items
|
||||
.filter {
|
||||
if (prefRepository.showWholeClassPlan == TimetableMode.ONLY_CURRENT_GROUP) {
|
||||
it.isStudentPlan
|
||||
} else true
|
||||
}.sortedWith(
|
||||
compareBy({ item -> item.number }, { item -> !item.isStudentPlan })
|
||||
)
|
||||
|
||||
return filteredItems.mapIndexed { i, it ->
|
||||
if (it.isStudentPlan) TimetableItem.Normal(
|
||||
lesson = it,
|
||||
showGroupsInPlan = prefRepository.showGroupsInPlan,
|
||||
timeLeft = filteredItems.getTimeLeftForLesson(it, i),
|
||||
onClick = ::onTimetableItemSelected
|
||||
) else TimetableItem.Small(
|
||||
lesson = it,
|
||||
onClick = ::onTimetableItemSelected
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<Timetable>.getTimeLeftForLesson(lesson: Timetable, index: Int): TimeLeft {
|
||||
val isShowTimeUntil = lesson.isShowTimeUntil(getPreviousLesson(index))
|
||||
return TimeLeft(
|
||||
until = lesson.until.plusMinutes(1).takeIf { isShowTimeUntil },
|
||||
left = lesson.left?.plusMinutes(1),
|
||||
isJustFinished = lesson.isJustFinished,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createItems(items: List<Timetable>) = items.filter { item ->
|
||||
if (prefRepository.showWholeClassPlan == TimetableMode.ONLY_CURRENT_GROUP) item.isStudentPlan else true
|
||||
}.sortedWith(compareBy({ item -> item.number }, { item -> !item.isStudentPlan }))
|
||||
private fun List<Timetable>.getPreviousLesson(position: Int): Instant? {
|
||||
return filter { it.isStudentPlan }
|
||||
.getOrNull(position - 1 - filterIndexed { i, item -> i < position && !item.isStudentPlan }.size)
|
||||
?.let {
|
||||
if (!it.canceled && it.isStudentPlan) it.end
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
private fun onTimetableItemSelected(lesson: Timetable) {
|
||||
Timber.i("Select timetable item ${lesson.id}")
|
||||
view?.showTimetableDialog(lesson)
|
||||
}
|
||||
|
||||
private fun showErrorViewOnError(message: String, error: Throwable) {
|
||||
view?.run {
|
||||
|
@ -227,7 +260,6 @@ class TimetablePresenter @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private fun reloadNavigation() {
|
||||
view?.apply {
|
||||
showPreButton(!currentDate.minusDays(1).isHolidays)
|
||||
|
@ -235,4 +267,10 @@ class TimetablePresenter @Inject constructor(
|
|||
updateNavigationDay(currentDate.toFormattedString("EEEE, dd.MM").capitalise())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDetachView() {
|
||||
tickTimer?.cancel()
|
||||
tickTimer = null
|
||||
super.onDetachView()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.github.wulkanowy.ui.modules.timetable
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.enums.TimetableMode
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
import java.time.LocalDate
|
||||
|
||||
|
@ -13,12 +12,7 @@ interface TimetableView : BaseView {
|
|||
|
||||
fun initView()
|
||||
|
||||
fun updateData(
|
||||
data: List<Timetable>,
|
||||
showWholeClassPlanType: TimetableMode,
|
||||
showGroupsInPlanType: Boolean,
|
||||
showTimetableTimers: Boolean
|
||||
)
|
||||
fun updateData(data: List<TimetableItem>)
|
||||
|
||||
fun updateNavigationDay(date: String)
|
||||
|
||||
|
|
Loading…
Reference in a new issue