forked from github/wulkanowy-mirror
Add additional lessons feature (#1550)
This commit is contained in:

committed by
GitHub

parent
cc22985dc5
commit
094df212b4
@ -29,8 +29,8 @@ import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
|
||||
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||
import io.github.wulkanowy.utils.SchoolDaysValidator
|
||||
import io.github.wulkanowy.utils.dpToPx
|
||||
import io.github.wulkanowy.utils.firstSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.schoolYearStart
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import java.time.LocalDate
|
||||
@ -225,7 +225,7 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag
|
||||
}
|
||||
|
||||
override fun showDatePickerDialog(currentDate: LocalDate) {
|
||||
val baseDate = currentDate.schoolYearStart
|
||||
val baseDate = currentDate.firstSchoolDayInSchoolYear
|
||||
val rangeStart = baseDate.toTimestamp()
|
||||
val rangeEnd = LocalDate.now().plusWeeks(1).toTimestamp()
|
||||
|
||||
|
@ -11,6 +11,8 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.databinding.DialogHomeworkAddBinding
|
||||
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
||||
import io.github.wulkanowy.utils.SchoolDaysValidator
|
||||
import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
@ -98,14 +100,17 @@ class HomeworkAddDialog : BaseDialogFragment<DialogHomeworkAddBinding>(), Homewo
|
||||
}
|
||||
|
||||
override fun showDatePickerDialog(currentDate: LocalDate) {
|
||||
val rangeStart = LocalDate.now().toTimestamp()
|
||||
val rangeEnd = LocalDate.now().lastSchoolDayInSchoolYear.toTimestamp()
|
||||
val constraintsBuilder = CalendarConstraints.Builder().apply {
|
||||
setStart(LocalDate.now().toEpochDay())
|
||||
setStart(rangeStart)
|
||||
setEnd(rangeEnd)
|
||||
setValidator(SchoolDaysValidator(rangeStart, rangeEnd))
|
||||
}
|
||||
val datePicker =
|
||||
MaterialDatePicker.Builder.datePicker()
|
||||
.setCalendarConstraints(constraintsBuilder.build())
|
||||
.setSelection(currentDate.toTimestamp())
|
||||
.build()
|
||||
val datePicker = MaterialDatePicker.Builder.datePicker()
|
||||
.setCalendarConstraints(constraintsBuilder.build())
|
||||
.setSelection(currentDate.toTimestamp())
|
||||
.build()
|
||||
|
||||
datePicker.addOnPositiveButtonClickListener {
|
||||
date = it.toLocalDateTime().toLocalDate()
|
||||
|
@ -16,7 +16,7 @@ import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||
import io.github.wulkanowy.utils.SchoolDaysValidator
|
||||
import io.github.wulkanowy.utils.dpToPx
|
||||
import io.github.wulkanowy.utils.schoolYearStart
|
||||
import io.github.wulkanowy.utils.firstSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import java.time.LocalDate
|
||||
@ -112,7 +112,7 @@ class LuckyNumberHistoryFragment :
|
||||
}
|
||||
|
||||
override fun showDatePickerDialog(currentDate: LocalDate) {
|
||||
val baseDate = currentDate.schoolYearStart
|
||||
val baseDate = currentDate.firstSchoolDayInSchoolYear
|
||||
val rangeStart = baseDate.toTimestamp()
|
||||
val rangeEnd = LocalDate.now().plusWeeks(1).toTimestamp()
|
||||
|
||||
|
@ -24,9 +24,9 @@ import io.github.wulkanowy.ui.modules.timetable.completed.CompletedLessonsFragme
|
||||
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||
import io.github.wulkanowy.utils.SchoolDaysValidator
|
||||
import io.github.wulkanowy.utils.dpToPx
|
||||
import io.github.wulkanowy.utils.firstSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.schoolYearEnd
|
||||
import io.github.wulkanowy.utils.schoolYearStart
|
||||
import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import java.time.LocalDate
|
||||
@ -194,9 +194,9 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
|
||||
}
|
||||
|
||||
override fun showDatePickerDialog(currentDate: LocalDate) {
|
||||
val baseDate = currentDate.schoolYearStart
|
||||
val baseDate = currentDate.firstSchoolDayInSchoolYear
|
||||
val rangeStart = baseDate.toTimestamp()
|
||||
val rangeEnd = LocalDate.now().schoolYearEnd.toTimestamp()
|
||||
val rangeEnd = LocalDate.now().lastSchoolDayInSchoolYear.toTimestamp()
|
||||
|
||||
val constraintsBuilder = CalendarConstraints.Builder().apply {
|
||||
setValidator(SchoolDaysValidator(rangeStart, rangeEnd))
|
||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.timetable.additional
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||
import io.github.wulkanowy.databinding.ItemTimetableAdditionalBinding
|
||||
@ -14,6 +15,8 @@ class AdditionalLessonsAdapter @Inject constructor() :
|
||||
|
||||
var items = emptyList<TimetableAdditional>()
|
||||
|
||||
var onDeleteClickListener: (timetableAdditional: TimetableAdditional) -> Unit = {}
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
|
||||
@ -25,8 +28,12 @@ class AdditionalLessonsAdapter @Inject constructor() :
|
||||
val item = items[position]
|
||||
|
||||
with(holder.binding) {
|
||||
additionalLessonItemTime.text = "${item.start.toFormattedString("HH:mm")} - ${item.end.toFormattedString("HH:mm")}"
|
||||
additionalLessonItemTime.text =
|
||||
"${item.start.toFormattedString("HH:mm")} - ${item.end.toFormattedString("HH:mm")}"
|
||||
additionalLessonItemSubject.text = item.subject
|
||||
|
||||
additionalLessonItemDelete.isVisible = item.isAddedByUser
|
||||
additionalLessonItemDelete.setOnClickListener { onDeleteClickListener(item) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.timetable.additional
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.datepicker.CalendarConstraints
|
||||
import com.google.android.material.datepicker.MaterialDatePicker
|
||||
@ -10,13 +11,15 @@ import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||
import io.github.wulkanowy.databinding.FragmentTimetableAdditionalBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.ui.modules.timetable.additional.add.AdditionalLessonAddDialog
|
||||
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||
import io.github.wulkanowy.utils.SchoolDaysValidator
|
||||
import io.github.wulkanowy.utils.dpToPx
|
||||
import io.github.wulkanowy.utils.firstSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.schoolYearEnd
|
||||
import io.github.wulkanowy.utils.schoolYearStart
|
||||
import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import java.time.LocalDate
|
||||
@ -53,7 +56,9 @@ class AdditionalLessonsFragment :
|
||||
override fun initView() {
|
||||
with(binding.additionalLessonsRecycler) {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
adapter = additionalLessonsAdapter
|
||||
adapter = additionalLessonsAdapter.apply {
|
||||
onDeleteClickListener = { presenter.onDeleteLessonsSelected(it) }
|
||||
}
|
||||
addItemDecoration(DividerItemDecoration(context))
|
||||
}
|
||||
|
||||
@ -61,9 +66,7 @@ class AdditionalLessonsFragment :
|
||||
additionalLessonsSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
|
||||
additionalLessonsSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
|
||||
additionalLessonsSwipe.setProgressBackgroundColorSchemeColor(
|
||||
requireContext().getThemeAttrColor(
|
||||
R.attr.colorSwipeRefresh
|
||||
)
|
||||
requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)
|
||||
)
|
||||
additionalLessonsErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||
additionalLessonsErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||
@ -72,6 +75,8 @@ class AdditionalLessonsFragment :
|
||||
additionalLessonsNavDate.setOnClickListener { presenter.onPickDate() }
|
||||
additionalLessonsNextButton.setOnClickListener { presenter.onNextDay() }
|
||||
|
||||
openAddAdditionalLessonButton.setOnClickListener { presenter.onAdditionalLessonAddButtonClicked() }
|
||||
|
||||
additionalLessonsNavContainer.elevation = requireContext().dpToPx(8f)
|
||||
}
|
||||
}
|
||||
@ -90,6 +95,10 @@ class AdditionalLessonsFragment :
|
||||
}
|
||||
}
|
||||
|
||||
override fun showSuccessMessage() {
|
||||
getString(R.string.additional_lessons_delete_success)
|
||||
}
|
||||
|
||||
override fun updateNavigationDay(date: String) {
|
||||
binding.additionalLessonsNavDate.text = date
|
||||
}
|
||||
@ -131,21 +140,24 @@ class AdditionalLessonsFragment :
|
||||
binding.additionalLessonsNextButton.visibility = if (show) View.VISIBLE else View.INVISIBLE
|
||||
}
|
||||
|
||||
override fun showAddAdditionalLessonDialog() {
|
||||
(activity as? MainActivity)?.showDialogFragment(AdditionalLessonAddDialog.newInstance())
|
||||
}
|
||||
|
||||
override fun showDatePickerDialog(currentDate: LocalDate) {
|
||||
val now = LocalDate.now()
|
||||
val startOfSchoolYear = now.schoolYearStart.toTimestamp()
|
||||
val endOfSchoolYear = now.schoolYearEnd.toTimestamp()
|
||||
val startOfSchoolYear = now.firstSchoolDayInSchoolYear.toTimestamp()
|
||||
val endOfSchoolYear = now.lastSchoolDayInSchoolYear.toTimestamp()
|
||||
|
||||
val constraintsBuilder = CalendarConstraints.Builder().apply {
|
||||
setValidator(SchoolDaysValidator(startOfSchoolYear, endOfSchoolYear))
|
||||
setStart(startOfSchoolYear)
|
||||
setEnd(endOfSchoolYear)
|
||||
}
|
||||
val datePicker =
|
||||
MaterialDatePicker.Builder.datePicker()
|
||||
.setCalendarConstraints(constraintsBuilder.build())
|
||||
.setSelection(currentDate.toTimestamp())
|
||||
.build()
|
||||
val datePicker = MaterialDatePicker.Builder.datePicker()
|
||||
.setCalendarConstraints(constraintsBuilder.build())
|
||||
.setSelection(currentDate.toTimestamp())
|
||||
.build()
|
||||
|
||||
datePicker.addOnPositiveButtonClickListener {
|
||||
val date = it.toLocalDateTime()
|
||||
@ -157,6 +169,18 @@ class AdditionalLessonsFragment :
|
||||
}
|
||||
}
|
||||
|
||||
override fun showDeleteLessonDialog(timetableAdditional: TimetableAdditional) {
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setTitle(getString(R.string.additional_lessons_delete_title))
|
||||
.setItems(
|
||||
arrayOf(
|
||||
getString(R.string.additional_lessons_delete_one),
|
||||
getString(R.string.additional_lessons_delete_series)
|
||||
)
|
||||
) { _, position -> presenter.onDeleteDialogSelectItem(position, timetableAdditional) }
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
||||
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.timetable.additional
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
@ -20,6 +21,7 @@ import io.github.wulkanowy.utils.toFormattedString
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.time.LocalDate
|
||||
import javax.inject.Inject
|
||||
@ -63,6 +65,10 @@ class AdditionalLessonsPresenter @Inject constructor(
|
||||
view?.showDatePickerDialog(currentDate)
|
||||
}
|
||||
|
||||
fun onAdditionalLessonAddButtonClicked() {
|
||||
view?.showAddAdditionalLessonDialog()
|
||||
}
|
||||
|
||||
fun onDateSet(year: Int, month: Int, day: Int) {
|
||||
loadData(LocalDate.of(year, month, day))
|
||||
reloadView()
|
||||
@ -98,6 +104,36 @@ class AdditionalLessonsPresenter @Inject constructor(
|
||||
}.launch("holidays")
|
||||
}
|
||||
|
||||
fun onDeleteLessonsSelected(timetableAdditional: TimetableAdditional) {
|
||||
if (timetableAdditional.repeatId == null) {
|
||||
deleteAdditionalLessons(timetableAdditional, false)
|
||||
} else {
|
||||
view?.showDeleteLessonDialog(timetableAdditional)
|
||||
}
|
||||
}
|
||||
|
||||
fun onDeleteDialogSelectItem(position: Int, timetableAdditional: TimetableAdditional) {
|
||||
deleteAdditionalLessons(timetableAdditional, position == 1)
|
||||
}
|
||||
|
||||
private fun deleteAdditionalLessons(
|
||||
timetableAdditional: TimetableAdditional,
|
||||
deleteSeries: Boolean
|
||||
) {
|
||||
presenterScope.launch {
|
||||
Timber.i("Additional Lesson delete start")
|
||||
runCatching { timetableRepository.deleteAdditional(timetableAdditional, deleteSeries) }
|
||||
.onSuccess {
|
||||
Timber.i("Additional Lesson delete: Success")
|
||||
view?.showSuccessMessage()
|
||||
}
|
||||
.onFailure {
|
||||
Timber.i("Additional Lesson delete result: An exception occurred")
|
||||
errorHandler.dispatch(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) {
|
||||
currentDate = date
|
||||
|
||||
@ -111,7 +147,7 @@ class AdditionalLessonsPresenter @Inject constructor(
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading additional lessons lessons result: Success")
|
||||
view?.apply {
|
||||
updateData(it.data!!.additional.sortedBy { item -> item.date })
|
||||
updateData(it.data!!.additional.sortedBy { item -> item.start })
|
||||
showEmpty(it.data.additional.isEmpty())
|
||||
showErrorView(false)
|
||||
showContent(it.data.additional.isNotEmpty())
|
||||
|
@ -35,4 +35,10 @@ interface AdditionalLessonsView : BaseView {
|
||||
fun showNextButton(show: Boolean)
|
||||
|
||||
fun showDatePickerDialog(currentDate: LocalDate)
|
||||
|
||||
fun showAddAdditionalLessonDialog()
|
||||
|
||||
fun showSuccessMessage()
|
||||
|
||||
fun showDeleteLessonDialog(timetableAdditional: TimetableAdditional)
|
||||
}
|
||||
|
@ -0,0 +1,188 @@
|
||||
package io.github.wulkanowy.ui.modules.timetable.additional.add
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import com.google.android.material.datepicker.CalendarConstraints
|
||||
import com.google.android.material.datepicker.MaterialDatePicker
|
||||
import com.google.android.material.timepicker.MaterialTimePicker
|
||||
import com.google.android.material.timepicker.TimeFormat
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.databinding.DialogAdditionalAddBinding
|
||||
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
||||
import io.github.wulkanowy.utils.SchoolDaysValidator
|
||||
import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalTime
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AdditionalLessonAddDialog : BaseDialogFragment<DialogAdditionalAddBinding>(),
|
||||
AdditionalLessonAddView {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: AdditionalLessonAddPresenter
|
||||
|
||||
companion object {
|
||||
fun newInstance() = AdditionalLessonAddDialog()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setStyle(STYLE_NO_TITLE, 0)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
) = DialogAdditionalAddBinding.inflate(inflater).apply { binding = this }.root
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
presenter.onAttachView(this)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
with(binding) {
|
||||
additionalLessonDialogStartEdit.doOnTextChanged { _, _, _, _ ->
|
||||
additionalLessonDialogStart.isErrorEnabled = false
|
||||
additionalLessonDialogStart.error = null
|
||||
}
|
||||
additionalLessonDialogEndEdit.doOnTextChanged { _, _, _, _ ->
|
||||
additionalLessonDialogEnd.isErrorEnabled = false
|
||||
additionalLessonDialogEnd.error = null
|
||||
}
|
||||
additionalLessonDialogDateEdit.doOnTextChanged { _, _, _, _ ->
|
||||
additionalLessonDialogDate.isErrorEnabled = false
|
||||
additionalLessonDialogDate.error = null
|
||||
}
|
||||
additionalLessonDialogContentEdit.doOnTextChanged { _, _, _, _ ->
|
||||
additionalLessonDialogContent.isErrorEnabled = false
|
||||
additionalLessonDialogContent.error = null
|
||||
}
|
||||
|
||||
additionalLessonDialogAdd.setOnClickListener {
|
||||
presenter.onAddAdditionalClicked(
|
||||
start = additionalLessonDialogStartEdit.text?.toString(),
|
||||
end = additionalLessonDialogEndEdit.text?.toString(),
|
||||
date = additionalLessonDialogDateEdit.text?.toString(),
|
||||
content = additionalLessonDialogContentEdit.text?.toString(),
|
||||
isRepeat = additionalLessonDialogRepeat.isChecked
|
||||
)
|
||||
}
|
||||
additionalLessonDialogClose.setOnClickListener { dismiss() }
|
||||
additionalLessonDialogDateEdit.setOnClickListener { presenter.showDatePicker() }
|
||||
additionalLessonDialogStartEdit.setOnClickListener { presenter.showStartTimePicker() }
|
||||
additionalLessonDialogEndEdit.setOnClickListener { presenter.showEndTimePicker() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun showSuccessMessage() {
|
||||
showMessage(getString(R.string.additional_lessons_add_success))
|
||||
}
|
||||
|
||||
override fun setErrorDateRequired() {
|
||||
with(binding.additionalLessonDialogDate) {
|
||||
isErrorEnabled = true
|
||||
error = getString(R.string.error_field_required)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setErrorStartRequired() {
|
||||
with(binding.additionalLessonDialogStart) {
|
||||
isErrorEnabled = true
|
||||
error = getString(R.string.error_field_required)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setErrorEndRequired() {
|
||||
with(binding.additionalLessonDialogEnd) {
|
||||
isErrorEnabled = true
|
||||
error = getString(R.string.error_field_required)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setErrorContentRequired() {
|
||||
with(binding.additionalLessonDialogContent) {
|
||||
isErrorEnabled = true
|
||||
error = getString(R.string.error_field_required)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setErrorIncorrectEndTime() {
|
||||
with(binding.additionalLessonDialogEnd) {
|
||||
isErrorEnabled = true
|
||||
error = getString(R.string.additional_lessons_end_time_error)
|
||||
}
|
||||
}
|
||||
|
||||
override fun closeDialog() {
|
||||
dismiss()
|
||||
}
|
||||
|
||||
override fun showDatePickerDialog(selectedDate: LocalDate) {
|
||||
val rangeStart = LocalDate.now().toTimestamp()
|
||||
val rangeEnd = LocalDate.now().lastSchoolDayInSchoolYear.toTimestamp()
|
||||
val constraintsBuilder = CalendarConstraints.Builder().apply {
|
||||
setStart(rangeStart)
|
||||
setEnd(rangeEnd)
|
||||
setValidator(SchoolDaysValidator(rangeStart, rangeEnd))
|
||||
}
|
||||
val datePicker = MaterialDatePicker.Builder.datePicker()
|
||||
.setCalendarConstraints(constraintsBuilder.build())
|
||||
.setSelection(selectedDate.toTimestamp())
|
||||
.build()
|
||||
|
||||
datePicker.addOnPositiveButtonClickListener {
|
||||
val date = it.toLocalDateTime().toLocalDate()
|
||||
presenter.onDateSelected(date)
|
||||
binding.additionalLessonDialogDateEdit.setText(date.toFormattedString())
|
||||
}
|
||||
|
||||
if (!parentFragmentManager.isStateSaved) {
|
||||
datePicker.show(parentFragmentManager, null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun showStartTimePickerDialog(selectedTime: LocalTime) {
|
||||
showTimePickerDialog(selectedTime) {
|
||||
presenter.onStartTimeSelected(it)
|
||||
binding.additionalLessonDialogStartEdit.setText(it.toString())
|
||||
}
|
||||
}
|
||||
|
||||
override fun showEndTimePickerDialog(selectedTime: LocalTime) {
|
||||
showTimePickerDialog(selectedTime) {
|
||||
presenter.onEndTimeSelected(it)
|
||||
binding.additionalLessonDialogEndEdit.setText(it.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun showTimePickerDialog(defaultTime: LocalTime, onTimeSelected: (LocalTime) -> Unit) {
|
||||
val timePicker = MaterialTimePicker.Builder()
|
||||
.setTimeFormat(TimeFormat.CLOCK_24H)
|
||||
.setHour(defaultTime.hour)
|
||||
.setMinute(defaultTime.minute)
|
||||
.build()
|
||||
|
||||
timePicker.addOnPositiveButtonClickListener {
|
||||
onTimeSelected(LocalTime.of(timePicker.hour, timePicker.minute))
|
||||
}
|
||||
|
||||
if (!parentFragmentManager.isStateSaved) {
|
||||
timePicker.show(parentFragmentManager, null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
presenter.onDetachView()
|
||||
super.onDestroyView()
|
||||
}
|
||||
}
|
@ -0,0 +1,166 @@
|
||||
package io.github.wulkanowy.ui.modules.timetable.additional.add
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||
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.lastSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.toLocalDate
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.time.LocalTime
|
||||
import java.time.temporal.ChronoUnit
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
|
||||
class AdditionalLessonAddPresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val timetableRepository: TimetableRepository,
|
||||
private val semesterRepository: SemesterRepository
|
||||
) : BasePresenter<AdditionalLessonAddView>(errorHandler, studentRepository) {
|
||||
|
||||
private var selectedStartTime = LocalTime.of(15, 0)
|
||||
|
||||
private var selectedEndTime = LocalTime.of(15, 45)
|
||||
|
||||
private var selectedDate = LocalDate.now()
|
||||
|
||||
override fun onAttachView(view: AdditionalLessonAddView) {
|
||||
super.onAttachView(view)
|
||||
view.initView()
|
||||
Timber.i("AdditionalLesson details view was initialized")
|
||||
}
|
||||
|
||||
fun showDatePicker() {
|
||||
view?.showDatePickerDialog(selectedDate)
|
||||
}
|
||||
|
||||
fun showStartTimePicker() {
|
||||
view?.showStartTimePickerDialog(selectedStartTime)
|
||||
}
|
||||
|
||||
fun showEndTimePicker() {
|
||||
view?.showEndTimePickerDialog(selectedEndTime)
|
||||
}
|
||||
|
||||
fun onStartTimeSelected(time: LocalTime) {
|
||||
selectedStartTime = time
|
||||
}
|
||||
|
||||
fun onEndTimeSelected(time: LocalTime) {
|
||||
selectedEndTime = time
|
||||
}
|
||||
|
||||
fun onDateSelected(date: LocalDate) {
|
||||
selectedDate = date
|
||||
}
|
||||
|
||||
fun onAddAdditionalClicked(
|
||||
start: String?,
|
||||
end: String?,
|
||||
date: String?,
|
||||
content: String?,
|
||||
isRepeat: Boolean
|
||||
) {
|
||||
if (isUserInputValid(start, end, date, content)) {
|
||||
addAdditionalLesson(
|
||||
start = LocalTime.parse(start!!),
|
||||
end = LocalTime.parse(end),
|
||||
date = date!!.toLocalDate(),
|
||||
subject = content!!,
|
||||
isRepeat = isRepeat
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isUserInputValid(
|
||||
start: String?,
|
||||
end: String?,
|
||||
date: String?,
|
||||
content: String?
|
||||
): Boolean {
|
||||
var isValid = true
|
||||
|
||||
if (start.isNullOrBlank()) {
|
||||
view?.setErrorStartRequired()
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if (end.isNullOrBlank()) {
|
||||
view?.setErrorEndRequired()
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if (date.isNullOrBlank()) {
|
||||
view?.setErrorDateRequired()
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if (content.isNullOrBlank()) {
|
||||
view?.setErrorContentRequired()
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if (selectedStartTime >= selectedEndTime) {
|
||||
view?.setErrorIncorrectEndTime()
|
||||
isValid = false
|
||||
}
|
||||
|
||||
return isValid
|
||||
}
|
||||
|
||||
private fun addAdditionalLesson(
|
||||
start: LocalTime,
|
||||
end: LocalTime,
|
||||
date: LocalDate,
|
||||
subject: String,
|
||||
isRepeat: Boolean
|
||||
) {
|
||||
presenterScope.launch {
|
||||
val semester = runCatching {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
semesterRepository.getCurrentSemester(student)
|
||||
}
|
||||
.onFailure(errorHandler::dispatch)
|
||||
.getOrNull() ?: return@launch
|
||||
|
||||
val weeks = if (isRepeat) {
|
||||
ChronoUnit.WEEKS.between(date, date.lastSchoolDayInSchoolYear)
|
||||
} else 0
|
||||
val uniqueRepeatId = UUID.randomUUID().takeIf { isRepeat }
|
||||
|
||||
val lessonsToAdd = (0..weeks).map {
|
||||
TimetableAdditional(
|
||||
studentId = semester.studentId,
|
||||
diaryId = semester.diaryId,
|
||||
start = LocalDateTime.of(date, start),
|
||||
end = LocalDateTime.of(date, end),
|
||||
date = date.plusWeeks(it),
|
||||
subject = subject
|
||||
).apply {
|
||||
isAddedByUser = true
|
||||
repeatId = uniqueRepeatId
|
||||
}
|
||||
}
|
||||
|
||||
Timber.i("AdditionalLesson insert start")
|
||||
runCatching { timetableRepository.saveAdditionalList(lessonsToAdd) }
|
||||
.onSuccess {
|
||||
Timber.i("AdditionalLesson insert: Success")
|
||||
view?.run {
|
||||
showSuccessMessage()
|
||||
closeDialog()
|
||||
}
|
||||
}
|
||||
.onFailure {
|
||||
Timber.i("AdditionalLesson insert result: An exception occurred")
|
||||
errorHandler.dispatch(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package io.github.wulkanowy.ui.modules.timetable.additional.add
|
||||
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalTime
|
||||
|
||||
interface AdditionalLessonAddView : BaseView {
|
||||
|
||||
fun initView()
|
||||
|
||||
fun closeDialog()
|
||||
|
||||
fun showDatePickerDialog(selectedDate: LocalDate)
|
||||
|
||||
fun showStartTimePickerDialog(selectedTime: LocalTime)
|
||||
|
||||
fun showEndTimePickerDialog(selectedTime: LocalTime)
|
||||
|
||||
fun showSuccessMessage()
|
||||
|
||||
fun setErrorDateRequired()
|
||||
|
||||
fun setErrorStartRequired()
|
||||
|
||||
fun setErrorEndRequired()
|
||||
|
||||
fun setErrorContentRequired()
|
||||
|
||||
fun setErrorIncorrectEndTime()
|
||||
}
|
@ -18,10 +18,10 @@ import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||
import io.github.wulkanowy.utils.SchoolDaysValidator
|
||||
import io.github.wulkanowy.utils.dpToPx
|
||||
import io.github.wulkanowy.utils.firstSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.getCompatDrawable
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.schoolYearEnd
|
||||
import io.github.wulkanowy.utils.schoolYearStart
|
||||
import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import java.time.LocalDate
|
||||
@ -68,9 +68,7 @@ class CompletedLessonsFragment :
|
||||
completedLessonsSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
|
||||
completedLessonsSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
|
||||
completedLessonsSwipe.setProgressBackgroundColorSchemeColor(
|
||||
requireContext().getThemeAttrColor(
|
||||
R.attr.colorSwipeRefresh
|
||||
)
|
||||
requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)
|
||||
)
|
||||
completedLessonErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||
completedLessonErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||
@ -154,19 +152,18 @@ class CompletedLessonsFragment :
|
||||
|
||||
override fun showDatePickerDialog(currentDate: LocalDate) {
|
||||
val now = LocalDate.now()
|
||||
val startOfSchoolYear = now.schoolYearStart.toTimestamp()
|
||||
val endOfSchoolYear = now.schoolYearEnd.toTimestamp()
|
||||
val startOfSchoolYear = now.firstSchoolDayInSchoolYear.toTimestamp()
|
||||
val endOfSchoolYear = now.lastSchoolDayInSchoolYear.toTimestamp()
|
||||
|
||||
val constraintsBuilder = CalendarConstraints.Builder().apply {
|
||||
setValidator(SchoolDaysValidator(startOfSchoolYear, endOfSchoolYear))
|
||||
setStart(startOfSchoolYear)
|
||||
setEnd(endOfSchoolYear)
|
||||
}
|
||||
val datePicker =
|
||||
MaterialDatePicker.Builder.datePicker()
|
||||
.setCalendarConstraints(constraintsBuilder.build())
|
||||
.setSelection(currentDate.toTimestamp())
|
||||
.build()
|
||||
val datePicker = MaterialDatePicker.Builder.datePicker()
|
||||
.setCalendarConstraints(constraintsBuilder.build())
|
||||
.setSelection(currentDate.toTimestamp())
|
||||
.build()
|
||||
|
||||
datePicker.addOnPositiveButtonClickListener {
|
||||
val date = it.toLocalDateTime()
|
||||
|
Reference in New Issue
Block a user