Add option to excuse a whole day

This commit is contained in:
Mikołaj Pich 2024-02-25 18:14:39 +01:00
parent d5c17285c1
commit 7effb7aca2
6 changed files with 104 additions and 19 deletions

View File

@ -88,9 +88,12 @@ class AttendanceRepository @Inject constructor(
return attendanceDb.updateAll(timetable) return attendanceDb.updateAll(timetable)
} }
@JvmName("excuseForAbsenceLessons")
suspend fun excuseForAbsence( suspend fun excuseForAbsence(
student: Student, semester: Semester, student: Student,
absenceList: List<Attendance>, reason: String? = null semester: Semester,
absenceList: List<Attendance>,
reason: String? = null
) { ) {
val items = absenceList.map { attendance -> val items = absenceList.map { attendance ->
Absent( Absent(
@ -102,4 +105,22 @@ class AttendanceRepository @Inject constructor(
.switchSemester(semester) .switchSemester(semester)
.excuseForAbsence(items, reason) .excuseForAbsence(items, reason)
} }
@JvmName("excuseForAbsenceDays")
suspend fun excuseForAbsence(
student: Student,
semester: Semester,
days: List<LocalDate>,
reason: String? = null
) {
val items = days.map { day ->
Absent(
date = LocalDateTime.of(day, LocalTime.of(0, 0)),
timeId = null,
)
}
sdk.init(student)
.switchSemester(semester)
.excuseForAbsence(items, reason)
}
} }

View File

@ -2,8 +2,14 @@ package io.github.wulkanowy.ui.modules.attendance
import android.content.DialogInterface.BUTTON_POSITIVE import android.content.DialogInterface.BUTTON_POSITIVE
import android.os.Bundle import android.os.Bundle
import android.view.* import android.view.LayoutInflater
import android.view.View.* import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.View.GONE
import android.view.View.INVISIBLE
import android.view.View.VISIBLE
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@ -123,6 +129,7 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag
attendanceNextButton.setOnClickListener { presenter.onNextDay() } attendanceNextButton.setOnClickListener { presenter.onNextDay() }
attendanceExcuseButton.setOnClickListener { presenter.onExcuseButtonClick() } attendanceExcuseButton.setOnClickListener { presenter.onExcuseButtonClick() }
attendanceExcuseDayButton.setOnClickListener { presenter.onExcuseDayButtonClick() }
attendanceNavContainer.elevation = requireContext().dpToPx(3f) attendanceNavContainer.elevation = requireContext().dpToPx(3f)
} }
@ -215,6 +222,10 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag
binding.attendanceExcuseButton.isVisible = show binding.attendanceExcuseButton.isVisible = show
} }
override fun showExcuseDayButton(show: Boolean) {
binding.attendanceExcuseDayButton.isVisible = show
}
override fun showAttendanceDialog(lesson: Attendance) { override fun showAttendanceDialog(lesson: Attendance) {
(activity as? MainActivity)?.showDialogFragment(AttendanceDialog.newInstance(lesson)) (activity as? MainActivity)?.showDialogFragment(AttendanceDialog.newInstance(lesson))
} }
@ -257,11 +268,18 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag
actionMode = (activity as MainActivity?)?.startSupportActionMode(actionModeCallback) actionMode = (activity as MainActivity?)?.startSupportActionMode(actionModeCallback)
} }
override fun startSendMessageIntent(date: LocalDate, numbers: String, reason: String) { override fun startSendMessageIntent(date: LocalDate, lessons: String, reason: String) {
val reasonFullText = getString( val reasonFullText = if (lessons.isEmpty()) {
R.string.attendance_excuse_formula, getString(
R.string.attendance_excuse_day_formula,
date,
if (reason.isNotBlank()) " ${getString(R.string.attendance_excuse_reason)} " else "",
reason.ifBlank { "" }
)
} else getString(
R.string.attendance_excuse_lessons_formula,
date, date,
numbers, lessons,
if (reason.isNotBlank()) " ${getString(R.string.attendance_excuse_reason)} " else "", if (reason.isNotBlank()) " ${getString(R.string.attendance_excuse_reason)} " else "",
reason.ifBlank { "" } reason.ifBlank { "" }
) )

View File

@ -38,6 +38,7 @@ class AttendancePresenter @Inject constructor(
private lateinit var lastError: Throwable private lateinit var lastError: Throwable
private val attendanceToExcuseList = mutableListOf<Attendance>() private val attendanceToExcuseList = mutableListOf<Attendance>()
private var isWholeDayExcusable = false
private var isVulcanExcusedFunctionEnabled = false private var isVulcanExcusedFunctionEnabled = false
@ -129,6 +130,14 @@ class AttendancePresenter @Inject constructor(
fun onExcuseButtonClick() { fun onExcuseButtonClick() {
view?.startActionMode() view?.startActionMode()
if (isWholeDayExcusable) {
view?.showExcuseDayButton(true)
}
}
fun onExcuseDayButtonClick() {
view?.showExcuseDialog()
} }
fun onExcuseCheckboxSelect(attendanceItem: Attendance, checked: Boolean) { fun onExcuseCheckboxSelect(attendanceItem: Attendance, checked: Boolean) {
@ -152,7 +161,7 @@ class AttendancePresenter @Inject constructor(
fun onExcuseDialogSubmit(reason: String) { fun onExcuseDialogSubmit(reason: String) {
view?.finishActionMode() view?.finishActionMode()
if (attendanceToExcuseList.isEmpty()) return if (attendanceToExcuseList.isEmpty() && !isWholeDayExcusable) return
if (isVulcanExcusedFunctionEnabled) { if (isVulcanExcusedFunctionEnabled) {
excuseAbsence( excuseAbsence(
@ -163,8 +172,8 @@ class AttendancePresenter @Inject constructor(
val attendanceToExcuseNumbers = attendanceToExcuseList.map { it.number } val attendanceToExcuseNumbers = attendanceToExcuseList.map { it.number }
view?.startSendMessageIntent( view?.startSendMessageIntent(
date = attendanceToExcuseList[0].date, date = currentDate ?: attendanceToExcuseList[0].date,
numbers = attendanceToExcuseNumbers.joinToString(", "), lessons = attendanceToExcuseNumbers.joinToString(", "),
reason = reason reason = reason
) )
} }
@ -174,6 +183,7 @@ class AttendancePresenter @Inject constructor(
view?.apply { view?.apply {
showExcuseCheckboxes(true) showExcuseCheckboxes(true)
showExcuseButton(false) showExcuseButton(false)
showExcuseDayButton(false)
enableSwipe(false) enableSwipe(false)
showDayNavigation(false) showDayNavigation(false)
} }
@ -185,6 +195,7 @@ class AttendancePresenter @Inject constructor(
view?.apply { view?.apply {
showExcuseCheckboxes(false) showExcuseCheckboxes(false)
showExcuseButton(true) showExcuseButton(true)
showExcuseDayButton(false)
enableSwipe(true) enableSwipe(true)
showDayNavigation(true) showDayNavigation(true)
} }
@ -217,7 +228,10 @@ class AttendancePresenter @Inject constructor(
} }
.logResourceStatus("load attendance") .logResourceStatus("load attendance")
.onResourceLoading { .onResourceLoading {
view?.showExcuseButton(false) view?.apply {
showExcuseButton(false)
showExcuseDayButton(false)
}
} }
.mapResourceData { .mapResourceData {
if (prefRepository.isShowPresent) { if (prefRepository.isShowPresent) {
@ -240,15 +254,16 @@ class AttendancePresenter @Inject constructor(
} }
} }
.onResourceIntermediate { view?.showRefresh(true) } .onResourceIntermediate { view?.showRefresh(true) }
.onResourceSuccess { .onResourceSuccess { items ->
isVulcanExcusedFunctionEnabled = it.any { item -> item.excusable } isVulcanExcusedFunctionEnabled = items.any { item -> item.excusable }
val anyExcusables = it.any { it.isExcusableOrNotExcused } isWholeDayExcusable = items.all { it.isExcusableOrNotExcused }
val anyExcusables = items.any { it.isExcusableOrNotExcused }
view?.showExcuseButton(anyExcusables && (isParent || isVulcanExcusedFunctionEnabled)) view?.showExcuseButton(anyExcusables && (isParent || isVulcanExcusedFunctionEnabled))
analytics.logEvent( analytics.logEvent(
"load_data", "load_data",
"type" to "attendance", "type" to "attendance",
"items" to it.size "items" to items.size
) )
} }
.onResourceNotLoading { .onResourceNotLoading {
@ -301,7 +316,19 @@ class AttendancePresenter @Inject constructor(
resourceFlow { resourceFlow {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
val semester = semesterRepository.getCurrentSemester(student) val semester = semesterRepository.getCurrentSemester(student)
attendanceRepository.excuseForAbsence(student, semester, toExcuseList, reason) if (toExcuseList.isEmpty()) {
attendanceRepository.excuseForAbsence(
student = student,
semester = semester,
days = listOfNotNull(currentDate),
reason = reason
)
} else attendanceRepository.excuseForAbsence(
student = student,
semester = semester,
absenceList = toExcuseList,
reason = reason
)
}.onEach { }.onEach {
when (it) { when (it) {
is Resource.Loading -> view?.run { is Resource.Loading -> view?.run {
@ -309,6 +336,7 @@ class AttendancePresenter @Inject constructor(
showProgress(true) showProgress(true)
showContent(false) showContent(false)
showExcuseButton(false) showExcuseButton(false)
showExcuseDayButton(false)
} }
is Resource.Success -> { is Resource.Success -> {
@ -317,6 +345,7 @@ class AttendancePresenter @Inject constructor(
attendanceToExcuseList.clear() attendanceToExcuseList.clear()
view?.run { view?.run {
showExcuseButton(false) showExcuseButton(false)
showExcuseDayButton(false)
showMessage(excuseSuccessString) showMessage(excuseSuccessString)
showContent(true) showContent(true)
showProgress(false) showProgress(false)

View File

@ -48,6 +48,8 @@ interface AttendanceView : BaseView {
fun showExcuseButton(show: Boolean) fun showExcuseButton(show: Boolean)
fun showExcuseDayButton(show: Boolean)
fun showAttendanceDialog(lesson: Attendance) fun showAttendanceDialog(lesson: Attendance)
fun showDatePickerDialog(selectedDate: LocalDate) fun showDatePickerDialog(selectedDate: LocalDate)
@ -56,7 +58,7 @@ interface AttendanceView : BaseView {
fun openSummaryView() fun openSummaryView()
fun startSendMessageIntent(date: LocalDate, numbers: String, reason: String) fun startSendMessageIntent(date: LocalDate, lessons: String, reason: String)
fun startActionMode() fun startActionMode()

View File

@ -69,6 +69,19 @@
app:icon="@drawable/ic_all_done_all" app:icon="@drawable/ic_all_done_all"
tools:visibility="visible" /> tools:visibility="visible" />
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/attendanceExcuseDayButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:clickable="true"
android:focusable="true"
android:text="@string/attendance_excuse_day_title"
android:visibility="gone"
app:icon="@drawable/ic_all_done_all"
tools:visibility="visible" />
<LinearLayout <LinearLayout
android:id="@+id/attendanceError" android:id="@+id/attendanceError"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -274,8 +274,10 @@
<string name="attendance_excuse_success">Absence excuse request sent successfully!</string> <string name="attendance_excuse_success">Absence excuse request sent successfully!</string>
<string name="attendance_excuse_no_selection">You must select at least one absence!</string> <string name="attendance_excuse_no_selection">You must select at least one absence!</string>
<string name="attendance_excuse_title">Excuse</string> <string name="attendance_excuse_title">Excuse</string>
<string name="attendance_excuse_day_title">Excuse entire day</string>
<string name="attendance_excuse_reason" translatable="false">z powodu</string> <string name="attendance_excuse_reason" translatable="false">z powodu</string>
<string name="attendance_excuse_formula" translatable="false">Dzień dobry,\nProszę o usprawiedliwienie mojego dziecka w dniu %s z lekcji %s%s%s.\n\nPozdrawiam.</string> <string name="attendance_excuse_lessons_formula" translatable="false">Dzień dobry,\nProszę o usprawiedliwienie mojego dziecka w dniu %s z lekcji %s%s%s.\n\nPozdrawiam.</string>
<string name="attendance_excuse_day_formula" translatable="false">Dzień dobry,\nProszę o usprawiedliwienie mojego dziecka w dniu %s%s%s.\n\nPozdrawiam.</string>
<plurals name="attendance_notify_new_items_title"> <plurals name="attendance_notify_new_items_title">
<item quantity="one">New attendance</item> <item quantity="one">New attendance</item>
<item quantity="other">New attendance</item> <item quantity="other">New attendance</item>