forked from github/wulkanowy-mirror
Allow direct access to weekend from day navigation when there is any lesson during weekend (#2326)
This commit is contained in:
parent
9d62410530
commit
83527d91f3
@ -148,6 +148,10 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag
|
||||
binding.attendanceNavDate.text = date
|
||||
}
|
||||
|
||||
override fun showNavigation(show: Boolean) {
|
||||
binding.attendanceNavContainer.isVisible = show
|
||||
}
|
||||
|
||||
override fun clearData() {
|
||||
with(attendanceAdapter) {
|
||||
items = emptyList()
|
||||
@ -281,7 +285,9 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
||||
presenter.currentDate?.let {
|
||||
outState.putLong(SAVED_DATE_KEY, it.toEpochDay())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -3,10 +3,14 @@ package io.github.wulkanowy.ui.modules.attendance
|
||||
import android.annotation.SuppressLint
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.repositories.AttendanceRepository
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
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.*
|
||||
@ -14,6 +18,7 @@ import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import java.time.DayOfWeek
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDate.now
|
||||
import java.time.LocalDate.ofEpochDay
|
||||
@ -28,9 +33,10 @@ class AttendancePresenter @Inject constructor(
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<AttendanceView>(errorHandler, studentRepository) {
|
||||
|
||||
private var baseDate: LocalDate = now().previousOrSameSchoolDay
|
||||
private var initialDate: LocalDate? = null
|
||||
private var isWeekendHasLessons: Boolean = false
|
||||
|
||||
lateinit var currentDate: LocalDate
|
||||
var currentDate: LocalDate? = null
|
||||
private set
|
||||
|
||||
private lateinit var lastError: Throwable
|
||||
@ -44,27 +50,34 @@ class AttendancePresenter @Inject constructor(
|
||||
view.initView()
|
||||
Timber.i("Attendance view was initialized")
|
||||
errorHandler.showErrorMessage = ::showErrorViewOnError
|
||||
reloadView(ofEpochDay(date ?: baseDate.toEpochDay()))
|
||||
currentDate = date?.let(::ofEpochDay)
|
||||
loadData()
|
||||
if (currentDate.isHolidays) setBaseDateOnHolidays()
|
||||
}
|
||||
|
||||
fun onPreviousDay() {
|
||||
val date = if (isWeekendHasLessons) {
|
||||
currentDate?.minusDays(1)
|
||||
} else currentDate?.previousSchoolDay
|
||||
|
||||
view?.finishActionMode()
|
||||
attendanceToExcuseList.clear()
|
||||
reloadView(currentDate.previousSchoolDay)
|
||||
reloadView(date ?: return)
|
||||
loadData()
|
||||
}
|
||||
|
||||
fun onNextDay() {
|
||||
val date = if (isWeekendHasLessons) {
|
||||
currentDate?.plusDays(1)
|
||||
} else currentDate?.nextSchoolDay
|
||||
|
||||
view?.finishActionMode()
|
||||
attendanceToExcuseList.clear()
|
||||
reloadView(currentDate.nextSchoolDay)
|
||||
reloadView(date ?: return)
|
||||
loadData()
|
||||
}
|
||||
|
||||
fun onPickDate() {
|
||||
view?.showDatePickerDialog(currentDate)
|
||||
view?.showDatePickerDialog(currentDate ?: return)
|
||||
}
|
||||
|
||||
fun onDateSet(year: Int, month: Int, day: Int) {
|
||||
@ -93,10 +106,8 @@ class AttendancePresenter @Inject constructor(
|
||||
Timber.i("Attendance view is reselected")
|
||||
view?.let { view ->
|
||||
if (view.currentStackSize == 1) {
|
||||
baseDate = now().previousOrSameSchoolDay
|
||||
|
||||
if (currentDate != baseDate) {
|
||||
reloadView(baseDate)
|
||||
if (currentDate != initialDate) {
|
||||
reloadView(initialDate ?: return)
|
||||
loadData()
|
||||
} else if (!view.isViewEmpty) {
|
||||
view.resetView()
|
||||
@ -188,19 +199,6 @@ class AttendancePresenter @Inject constructor(
|
||||
return true
|
||||
}
|
||||
|
||||
private fun setBaseDateOnHolidays() {
|
||||
flow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
emit(semesterRepository.getCurrentSemester(student))
|
||||
}.catch {
|
||||
Timber.i("Loading semester result: An exception occurred")
|
||||
}.onEach {
|
||||
baseDate = baseDate.getLastSchoolDayIfHoliday(it.schoolYear)
|
||||
currentDate = baseDate
|
||||
reloadNavigation()
|
||||
}.launch("holidays")
|
||||
}
|
||||
|
||||
private fun loadData(forceRefresh: Boolean = false) {
|
||||
Timber.i("Loading attendance data started")
|
||||
|
||||
@ -211,11 +209,13 @@ class AttendancePresenter @Inject constructor(
|
||||
isParent = student.isParent
|
||||
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
|
||||
checkInitialAndCurrentDate(student, semester)
|
||||
attendanceRepository.getAttendance(
|
||||
student = student,
|
||||
semester = semester,
|
||||
start = currentDate,
|
||||
end = currentDate,
|
||||
start = currentDate ?: now(),
|
||||
end = currentDate ?: now(),
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}
|
||||
@ -231,6 +231,8 @@ class AttendancePresenter @Inject constructor(
|
||||
}.sortedBy { item -> item.number }
|
||||
}
|
||||
.onResourceData {
|
||||
isWeekendHasLessons = isWeekendHasLessons || isWeekendHasLessons(it)
|
||||
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showProgress(false)
|
||||
@ -238,6 +240,7 @@ class AttendancePresenter @Inject constructor(
|
||||
showEmpty(it.isEmpty())
|
||||
showContent(it.isNotEmpty())
|
||||
updateData(it)
|
||||
reloadNavigation()
|
||||
}
|
||||
}
|
||||
.onResourceIntermediate { view?.showRefresh(true) }
|
||||
@ -263,6 +266,43 @@ class AttendancePresenter @Inject constructor(
|
||||
.launch()
|
||||
}
|
||||
|
||||
private suspend fun checkInitialAndCurrentDate(student: Student, semester: Semester) {
|
||||
if (initialDate == null) {
|
||||
val lessons = attendanceRepository.getAttendance(
|
||||
student = student,
|
||||
semester = semester,
|
||||
start = now().monday,
|
||||
end = now().sunday,
|
||||
forceRefresh = false,
|
||||
).toFirstResult().dataOrNull.orEmpty()
|
||||
isWeekendHasLessons = isWeekendHasLessons(lessons)
|
||||
initialDate = getInitialDate(semester)
|
||||
}
|
||||
|
||||
if (currentDate == null) {
|
||||
currentDate = initialDate
|
||||
}
|
||||
}
|
||||
|
||||
private fun isWeekendHasLessons(
|
||||
lessons: List<Attendance>,
|
||||
): Boolean = lessons.any {
|
||||
it.date.dayOfWeek in listOf(
|
||||
DayOfWeek.SATURDAY,
|
||||
DayOfWeek.SUNDAY,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getInitialDate(semester: Semester): LocalDate {
|
||||
val now = now()
|
||||
|
||||
return when {
|
||||
now.isHolidays -> now.getLastSchoolDayIfHoliday(semester.schoolYear)
|
||||
isWeekendHasLessons -> now
|
||||
else -> now.previousOrSameSchoolDay
|
||||
}
|
||||
}
|
||||
|
||||
private fun excuseAbsence(reason: String?, toExcuseList: List<Attendance>) {
|
||||
resourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
@ -311,7 +351,7 @@ class AttendancePresenter @Inject constructor(
|
||||
private fun reloadView(date: LocalDate) {
|
||||
currentDate = date
|
||||
|
||||
Timber.i("Reload attendance view with the date ${currentDate.toFormattedString()}")
|
||||
Timber.i("Reload attendance view with the date ${currentDate?.toFormattedString()}")
|
||||
view?.apply {
|
||||
showProgress(true)
|
||||
enableSwipe(false)
|
||||
@ -326,10 +366,13 @@ class AttendancePresenter @Inject constructor(
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private fun reloadNavigation() {
|
||||
val currentDate = currentDate ?: return
|
||||
|
||||
view?.apply {
|
||||
showPreButton(!currentDate.minusDays(1).isHolidays)
|
||||
showNextButton(!currentDate.plusDays(1).isHolidays)
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE, dd.MM").capitalise())
|
||||
showNavigation(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,8 @@ interface AttendanceView : BaseView {
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
|
||||
fun showNavigation(show: Boolean)
|
||||
|
||||
fun showPreButton(show: Boolean)
|
||||
|
||||
fun showNextButton(show: Boolean)
|
||||
|
@ -386,7 +386,7 @@ class DashboardPresenter @Inject constructor(
|
||||
private fun loadLessons(student: Student, forceRefresh: Boolean) {
|
||||
flatResourceFlow {
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
val date = LocalDate.now().nextOrSameSchoolDay
|
||||
val date = LocalDate.now()
|
||||
|
||||
timetableRepository.getTimetable(
|
||||
student = student,
|
||||
|
@ -9,6 +9,7 @@ import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.text.parseAsHtml
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
@ -160,6 +161,10 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
|
||||
binding.timetableRecycler.visibility = if (show) VISIBLE else GONE
|
||||
}
|
||||
|
||||
override fun showNavigation(show: Boolean) {
|
||||
binding.timetableNavContainer.isVisible = true
|
||||
}
|
||||
|
||||
override fun showPreButton(show: Boolean) {
|
||||
binding.timetablePreviousButton.visibility = if (show) VISIBLE else View.INVISIBLE
|
||||
}
|
||||
@ -193,7 +198,9 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
||||
presenter.currentDate?.toEpochDay()?.let {
|
||||
outState.putLong(SAVED_DATE_KEY, it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -1,5 +1,8 @@
|
||||
package io.github.wulkanowy.ui.modules.timetable
|
||||
|
||||
import io.github.wulkanowy.data.dataOrNull
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.enums.TimetableGapsMode.BETWEEN_AND_BEFORE_LESSONS
|
||||
import io.github.wulkanowy.data.enums.TimetableGapsMode.NO_GAPS
|
||||
@ -15,6 +18,8 @@ import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
import io.github.wulkanowy.data.toFirstResult
|
||||
import io.github.wulkanowy.data.waitForResult
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
@ -24,15 +29,16 @@ import io.github.wulkanowy.utils.isHolidays
|
||||
import io.github.wulkanowy.utils.isJustFinished
|
||||
import io.github.wulkanowy.utils.isShowTimeUntil
|
||||
import io.github.wulkanowy.utils.left
|
||||
import io.github.wulkanowy.utils.monday
|
||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||
import io.github.wulkanowy.utils.nextSchoolDay
|
||||
import io.github.wulkanowy.utils.previousSchoolDay
|
||||
import io.github.wulkanowy.utils.sunday
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.until
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import timber.log.Timber
|
||||
import java.time.DayOfWeek
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDate.now
|
||||
@ -51,9 +57,10 @@ class TimetablePresenter @Inject constructor(
|
||||
private val analytics: AnalyticsHelper,
|
||||
) : BasePresenter<TimetableView>(errorHandler, studentRepository) {
|
||||
|
||||
private var baseDate: LocalDate = now().nextOrSameSchoolDay
|
||||
private var initialDate: LocalDate? = null
|
||||
private var isWeekendHasLessons: Boolean = false
|
||||
|
||||
lateinit var currentDate: LocalDate
|
||||
var currentDate: LocalDate? = null
|
||||
private set
|
||||
|
||||
private lateinit var lastError: Throwable
|
||||
@ -65,23 +72,30 @@ class TimetablePresenter @Inject constructor(
|
||||
view.initView()
|
||||
Timber.i("Timetable was initialized")
|
||||
errorHandler.showErrorMessage = ::showErrorViewOnError
|
||||
reloadView(ofEpochDay(date ?: baseDate.toEpochDay()))
|
||||
currentDate = date?.let(::ofEpochDay)
|
||||
loadData()
|
||||
if (currentDate.isHolidays) setBaseDateOnHolidays()
|
||||
}
|
||||
|
||||
fun onPreviousDay() {
|
||||
reloadView(currentDate.previousSchoolDay)
|
||||
val date = if (isWeekendHasLessons) {
|
||||
currentDate?.minusDays(1)
|
||||
} else currentDate?.previousSchoolDay
|
||||
|
||||
reloadView(date ?: return)
|
||||
loadData()
|
||||
}
|
||||
|
||||
fun onNextDay() {
|
||||
reloadView(currentDate.nextSchoolDay)
|
||||
val date = if (isWeekendHasLessons) {
|
||||
currentDate?.plusDays(1)
|
||||
} else currentDate?.nextSchoolDay
|
||||
|
||||
reloadView(date ?: return)
|
||||
loadData()
|
||||
}
|
||||
|
||||
fun onPickDate() {
|
||||
view?.showDatePickerDialog(currentDate)
|
||||
view?.showDatePickerDialog(currentDate ?: return)
|
||||
}
|
||||
|
||||
fun onDateSet(year: Int, month: Int, day: Int) {
|
||||
@ -110,10 +124,8 @@ class TimetablePresenter @Inject constructor(
|
||||
Timber.i("Timetable view is reselected")
|
||||
view?.let { view ->
|
||||
if (view.currentStackSize == 1) {
|
||||
baseDate = now().nextOrSameSchoolDay
|
||||
|
||||
if (currentDate != baseDate) {
|
||||
reloadView(baseDate)
|
||||
if (currentDate != initialDate) {
|
||||
reloadView(initialDate ?: return)
|
||||
loadData()
|
||||
} else if (!view.isViewEmpty) {
|
||||
view.resetView()
|
||||
@ -134,34 +146,25 @@ class TimetablePresenter @Inject constructor(
|
||||
return true
|
||||
}
|
||||
|
||||
private fun setBaseDateOnHolidays() {
|
||||
flow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
emit(semesterRepository.getCurrentSemester(student))
|
||||
}.catch {
|
||||
Timber.i("Loading semester result: An exception occurred")
|
||||
}.onEach {
|
||||
baseDate = baseDate.getLastSchoolDayIfHoliday(it.schoolYear)
|
||||
currentDate = baseDate
|
||||
reloadNavigation()
|
||||
}.launch("holidays")
|
||||
}
|
||||
|
||||
private fun loadData(forceRefresh: Boolean = false) {
|
||||
flatResourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
|
||||
checkInitialAndCurrentDate(student, semester)
|
||||
timetableRepository.getTimetable(
|
||||
student = student,
|
||||
semester = semester,
|
||||
start = currentDate,
|
||||
end = currentDate,
|
||||
start = currentDate ?: now(),
|
||||
end = currentDate ?: now(),
|
||||
forceRefresh = forceRefresh,
|
||||
timetableType = TimetableRepository.TimetableType.NORMAL
|
||||
)
|
||||
}
|
||||
.logResourceStatus("load timetable data")
|
||||
.onResourceData {
|
||||
isWeekendHasLessons = isWeekendHasLessons || isWeekendHasLessons(it.lessons)
|
||||
|
||||
view?.run {
|
||||
enableSwipe(true)
|
||||
showProgress(false)
|
||||
@ -169,7 +172,8 @@ class TimetablePresenter @Inject constructor(
|
||||
showContent(it.lessons.isNotEmpty())
|
||||
showEmpty(it.lessons.isEmpty())
|
||||
updateData(it.lessons)
|
||||
setDayHeaderMessage(it.headers.singleOrNull { header -> header.date == currentDate }?.content)
|
||||
setDayHeaderMessage(it.headers.find { header -> header.date == currentDate }?.content)
|
||||
reloadNavigation()
|
||||
}
|
||||
}
|
||||
.onResourceIntermediate { view?.showRefresh(true) }
|
||||
@ -191,6 +195,44 @@ class TimetablePresenter @Inject constructor(
|
||||
.launch()
|
||||
}
|
||||
|
||||
private suspend fun checkInitialAndCurrentDate(student: Student, semester: Semester) {
|
||||
if (initialDate == null) {
|
||||
val lessons = timetableRepository.getTimetable(
|
||||
student = student,
|
||||
semester = semester,
|
||||
start = now().monday,
|
||||
end = now().sunday,
|
||||
forceRefresh = false,
|
||||
timetableType = TimetableRepository.TimetableType.NORMAL
|
||||
).toFirstResult().dataOrNull?.lessons.orEmpty()
|
||||
isWeekendHasLessons = isWeekendHasLessons(lessons)
|
||||
initialDate = getInitialDate(semester)
|
||||
}
|
||||
|
||||
if (currentDate == null) {
|
||||
currentDate = initialDate
|
||||
}
|
||||
}
|
||||
|
||||
private fun isWeekendHasLessons(
|
||||
lessons: List<Timetable>,
|
||||
): Boolean = lessons.any {
|
||||
it.date.dayOfWeek in listOf(
|
||||
DayOfWeek.SATURDAY,
|
||||
DayOfWeek.SUNDAY,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getInitialDate(semester: Semester): LocalDate {
|
||||
val now = now()
|
||||
|
||||
return when {
|
||||
now.isHolidays -> now.getLastSchoolDayIfHoliday(semester.schoolYear)
|
||||
isWeekendHasLessons -> now
|
||||
else -> now.nextOrSameSchoolDay
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateData(lessons: List<Timetable>) {
|
||||
tickTimer?.cancel()
|
||||
|
||||
@ -285,7 +327,7 @@ class TimetablePresenter @Inject constructor(
|
||||
private fun reloadView(date: LocalDate) {
|
||||
currentDate = date
|
||||
|
||||
Timber.i("Reload timetable view with the date ${currentDate.toFormattedString()}")
|
||||
Timber.i("Reload timetable view with the date ${currentDate?.toFormattedString()}")
|
||||
view?.apply {
|
||||
showProgress(true)
|
||||
enableSwipe(false)
|
||||
@ -298,10 +340,13 @@ class TimetablePresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun reloadNavigation() {
|
||||
val currentDate = currentDate ?: return
|
||||
|
||||
view?.apply {
|
||||
showPreButton(!currentDate.minusDays(1).isHolidays)
|
||||
showNextButton(!currentDate.plusDays(1).isHolidays)
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE, dd.MM").capitalise())
|
||||
showNavigation(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,8 @@ interface TimetableView : BaseView {
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
|
||||
fun showNavigation(show: Boolean)
|
||||
|
||||
fun showPreButton(show: Boolean)
|
||||
|
||||
fun showNextButton(show: Boolean)
|
||||
|
@ -128,7 +128,9 @@
|
||||
android:layout_gravity="bottom"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
tools:ignore="UnusedAttribute">
|
||||
android:visibility="gone"
|
||||
tools:ignore="UnusedAttribute"
|
||||
tools:visibility="visible">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/attendancePreviousButton"
|
||||
|
@ -128,7 +128,9 @@
|
||||
android:layout_gravity="bottom"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
tools:ignore="UnusedAttribute">
|
||||
android:visibility="gone"
|
||||
tools:ignore="UnusedAttribute"
|
||||
tools:visibility="visible">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/timetablePreviousButton"
|
||||
|
Loading…
x
Reference in New Issue
Block a user