From 6520f8a0d7a83f908c39480f24b4cfa32e52d235 Mon Sep 17 00:00:00 2001 From: Michael <5672750+mibac138@users.noreply.github.com> Date: Mon, 27 Dec 2021 08:10:30 +0100 Subject: [PATCH] Fix that an incorrect day would be selected in MaterialDatePicker (#1723) --- .../modules/attendance/AttendanceFragment.kt | 38 ++++---------- .../ui/modules/attendance/AttendanceView.kt | 2 +- .../modules/homework/add/HomeworkAddDialog.kt | 38 +++++--------- .../modules/homework/add/HomeworkAddView.kt | 2 +- .../history/LuckyNumberHistoryFragment.kt | 38 ++++---------- .../history/LuckyNumberHistoryView.kt | 2 +- .../ui/modules/timetable/TimetableFragment.kt | 38 ++++---------- .../ui/modules/timetable/TimetableView.kt | 2 +- .../additional/AdditionalLessonsFragment.kt | 36 ++++--------- .../additional/AdditionalLessonsView.kt | 2 +- .../add/AdditionalLessonAddDialog.kt | 36 ++++--------- .../completed/CompletedLessonsFragment.kt | 36 ++++--------- .../completed/CompletedLessonsView.kt | 2 +- .../utils/MaterialDatePickerUtils.kt | 51 +++++++++++++++++++ .../wulkanowy/utils/SchooldaysValidator.kt | 16 ------ .../github/wulkanowy/utils/TimeExtension.kt | 11 ++-- .../wulkanowy/utils/TimeExtensionTest.kt | 20 +++++++- 17 files changed, 153 insertions(+), 217 deletions(-) create mode 100644 app/src/main/java/io/github/wulkanowy/utils/MaterialDatePickerUtils.kt delete mode 100644 app/src/main/java/io/github/wulkanowy/utils/SchooldaysValidator.kt diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt index 9b5a3fa3..84af1ca3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt @@ -14,8 +14,6 @@ import androidx.appcompat.app.AlertDialog import androidx.appcompat.view.ActionMode import androidx.core.view.isVisible import androidx.recyclerview.widget.LinearLayoutManager -import com.google.android.material.datepicker.CalendarConstraints -import com.google.android.material.datepicker.MaterialDatePicker import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Attendance @@ -27,12 +25,10 @@ import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView 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.toLocalDateTime -import io.github.wulkanowy.utils.toTimestamp +import io.github.wulkanowy.utils.openMaterialDatePicker import java.time.LocalDate import javax.inject.Inject @@ -224,29 +220,15 @@ class AttendanceFragment : BaseFragment(R.layout.frag (activity as? MainActivity)?.showDialogFragment(AttendanceDialog.newInstance(lesson)) } - override fun showDatePickerDialog(currentDate: LocalDate) { - val baseDate = currentDate.firstSchoolDayInSchoolYear - val rangeStart = baseDate.toTimestamp() - val rangeEnd = LocalDate.now().plusWeeks(1).toTimestamp() - - val constraintsBuilder = CalendarConstraints.Builder().apply { - setValidator(SchoolDaysValidator(rangeStart, rangeEnd)) - setStart(rangeStart) - setEnd(rangeEnd) - } - val datePicker = MaterialDatePicker.Builder.datePicker() - .setCalendarConstraints(constraintsBuilder.build()) - .setSelection(currentDate.toTimestamp()) - .build() - - datePicker.addOnPositiveButtonClickListener { - val date = it.toLocalDateTime() - presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth) - } - - if (!parentFragmentManager.isStateSaved) { - datePicker.show(parentFragmentManager, null) - } + override fun showDatePickerDialog(selectedDate: LocalDate) { + openMaterialDatePicker( + selected = selectedDate, + rangeStart = selectedDate.firstSchoolDayInSchoolYear, + rangeEnd = LocalDate.now().plusWeeks(1), + onDateSelected = { + presenter.onDateSet(it.year, it.monthValue, it.dayOfMonth) + } + ) } override fun showExcuseDialog() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceView.kt index 7ddd75f4..b0123065 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceView.kt @@ -48,7 +48,7 @@ interface AttendanceView : BaseView { fun showAttendanceDialog(lesson: Attendance) - fun showDatePickerDialog(currentDate: LocalDate) + fun showDatePickerDialog(selectedDate: LocalDate) fun showExcuseDialog() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/add/HomeworkAddDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/add/HomeworkAddDialog.kt index 0f285b13..c2aff2b1 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/add/HomeworkAddDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/add/HomeworkAddDialog.kt @@ -5,17 +5,13 @@ 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 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.openMaterialDatePicker import io.github.wulkanowy.utils.toFormattedString -import io.github.wulkanowy.utils.toLocalDateTime -import io.github.wulkanowy.utils.toTimestamp import java.time.LocalDate import javax.inject.Inject @@ -25,6 +21,7 @@ class HomeworkAddDialog : BaseDialogFragment(), Homewo @Inject lateinit var presenter: HomeworkAddPresenter + // todo: move it to presenter private var date: LocalDate? = null override fun onCreate(savedInstanceState: Bundle?) { @@ -99,27 +96,16 @@ class HomeworkAddDialog : BaseDialogFragment(), Homewo dismiss() } - override fun showDatePickerDialog(currentDate: 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(currentDate.toTimestamp()) - .build() - - datePicker.addOnPositiveButtonClickListener { - date = it.toLocalDateTime().toLocalDate() - binding.homeworkDialogDate.editText?.setText(date!!.toFormattedString()) - } - - if (!parentFragmentManager.isStateSaved) { - datePicker.show(this.parentFragmentManager, null) - } + override fun showDatePickerDialog(selectedDate: LocalDate) { + openMaterialDatePicker( + selected = selectedDate, + rangeStart = LocalDate.now(), + rangeEnd = LocalDate.now().lastSchoolDayInSchoolYear, + onDateSelected = { + date = it + binding.homeworkDialogDate.editText?.setText(date!!.toFormattedString()) + } + ) } override fun onDestroyView() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/add/HomeworkAddView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/add/HomeworkAddView.kt index 3bb304d9..91414ae2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/add/HomeworkAddView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/add/HomeworkAddView.kt @@ -17,5 +17,5 @@ interface HomeworkAddView : BaseView { fun closeDialog() - fun showDatePickerDialog(currentDate: LocalDate) + fun showDatePickerDialog(selectedDate: LocalDate) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/history/LuckyNumberHistoryFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/history/LuckyNumberHistoryFragment.kt index 3bbed18b..53f06cac 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/history/LuckyNumberHistoryFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/history/LuckyNumberHistoryFragment.kt @@ -5,8 +5,6 @@ import android.view.View import android.view.View.GONE import android.view.View.VISIBLE import androidx.recyclerview.widget.LinearLayoutManager -import com.google.android.material.datepicker.CalendarConstraints -import com.google.android.material.datepicker.MaterialDatePicker import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.LuckyNumber @@ -14,11 +12,9 @@ import io.github.wulkanowy.databinding.FragmentLuckyNumberHistoryBinding import io.github.wulkanowy.ui.base.BaseFragment 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.toLocalDateTime -import io.github.wulkanowy.utils.toTimestamp +import io.github.wulkanowy.utils.openMaterialDatePicker import java.time.LocalDate import javax.inject.Inject @@ -111,29 +107,15 @@ class LuckyNumberHistoryFragment : binding.luckyNumberHistoryNextButton.visibility = if (show) VISIBLE else View.INVISIBLE } - override fun showDatePickerDialog(currentDate: LocalDate) { - val baseDate = currentDate.firstSchoolDayInSchoolYear - val rangeStart = baseDate.toTimestamp() - val rangeEnd = LocalDate.now().plusWeeks(1).toTimestamp() - - val constraintsBuilder = CalendarConstraints.Builder().apply { - setValidator(SchoolDaysValidator(rangeStart, rangeEnd)) - setStart(rangeStart) - setEnd(rangeEnd) - } - val datePicker = MaterialDatePicker.Builder.datePicker() - .setCalendarConstraints(constraintsBuilder.build()) - .setSelection(currentDate.toTimestamp()) - .build() - - datePicker.addOnPositiveButtonClickListener { - val date = it.toLocalDateTime() - presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth) - } - - if (!parentFragmentManager.isStateSaved) { - datePicker.show(parentFragmentManager, null) - } + override fun showDatePickerDialog(selectedDate: LocalDate) { + openMaterialDatePicker( + selected = selectedDate, + rangeStart = selectedDate.firstSchoolDayInSchoolYear, + rangeEnd = LocalDate.now().plusWeeks(1), + onDateSelected = { + presenter.onDateSet(it.year, it.monthValue, it.dayOfMonth) + } + ) } override fun showContent(show: Boolean) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/history/LuckyNumberHistoryView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/history/LuckyNumberHistoryView.kt index 331e4ff8..7b9b0294 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/history/LuckyNumberHistoryView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/history/LuckyNumberHistoryView.kt @@ -28,7 +28,7 @@ interface LuckyNumberHistoryView : BaseView { fun showNextButton(show: Boolean) - fun showDatePickerDialog(currentDate: LocalDate) + fun showDatePickerDialog(selectedDate: LocalDate) fun showContent(show: Boolean) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt index dd113639..f59c6432 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt @@ -9,8 +9,6 @@ import android.view.View.GONE import android.view.View.VISIBLE import androidx.core.text.parseAsHtml import androidx.recyclerview.widget.LinearLayoutManager -import com.google.android.material.datepicker.CalendarConstraints -import com.google.android.material.datepicker.MaterialDatePicker import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Timetable @@ -22,13 +20,11 @@ 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.SchoolDaysValidator 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.toLocalDateTime -import io.github.wulkanowy.utils.toTimestamp +import io.github.wulkanowy.utils.openMaterialDatePicker import java.time.LocalDate import javax.inject.Inject @@ -193,29 +189,15 @@ class TimetableFragment : BaseFragment(R.layout.fragme (activity as? MainActivity)?.showDialogFragment(TimetableDialog.newInstance(lesson)) } - override fun showDatePickerDialog(currentDate: LocalDate) { - val baseDate = currentDate.firstSchoolDayInSchoolYear - val rangeStart = baseDate.toTimestamp() - val rangeEnd = LocalDate.now().lastSchoolDayInSchoolYear.toTimestamp() - - val constraintsBuilder = CalendarConstraints.Builder().apply { - setValidator(SchoolDaysValidator(rangeStart, rangeEnd)) - setStart(rangeStart) - setEnd(rangeEnd) - } - val datePicker = MaterialDatePicker.Builder.datePicker() - .setCalendarConstraints(constraintsBuilder.build()) - .setSelection(currentDate.toTimestamp()) - .build() - - datePicker.addOnPositiveButtonClickListener { - val date = it.toLocalDateTime() - presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth) - } - - if (!parentFragmentManager.isStateSaved) { - datePicker.show(parentFragmentManager, null) - } + override fun showDatePickerDialog(selectedDate: LocalDate) { + openMaterialDatePicker( + selected = selectedDate, + rangeStart = selectedDate.firstSchoolDayInSchoolYear, + rangeEnd = LocalDate.now().lastSchoolDayInSchoolYear, + onDateSelected = { + presenter.onDateSet(it.year, it.monthValue, it.dayOfMonth) + } + ) } override fun openAdditionalLessonsView() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableView.kt index eaf75cb0..4f6af4b9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableView.kt @@ -48,7 +48,7 @@ interface TimetableView : BaseView { fun showTimetableDialog(lesson: Timetable) - fun showDatePickerDialog(currentDate: LocalDate) + fun showDatePickerDialog(selectedDate: LocalDate) fun popView() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsFragment.kt index b2a4a9a3..043fa1f7 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsFragment.kt @@ -4,8 +4,6 @@ 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 import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.TimetableAdditional @@ -15,13 +13,11 @@ 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.lastSchoolDayInSchoolYear -import io.github.wulkanowy.utils.toLocalDateTime -import io.github.wulkanowy.utils.toTimestamp +import io.github.wulkanowy.utils.openMaterialDatePicker import java.time.LocalDate import javax.inject.Inject @@ -144,29 +140,17 @@ class AdditionalLessonsFragment : (activity as? MainActivity)?.showDialogFragment(AdditionalLessonAddDialog.newInstance()) } - override fun showDatePickerDialog(currentDate: LocalDate) { + override fun showDatePickerDialog(selectedDate: LocalDate) { val now = LocalDate.now() - 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() - - datePicker.addOnPositiveButtonClickListener { - val date = it.toLocalDateTime() - presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth) - } - - if (!parentFragmentManager.isStateSaved) { - datePicker.show(parentFragmentManager, null) - } + openMaterialDatePicker( + selected = selectedDate, + rangeStart = now.firstSchoolDayInSchoolYear, + rangeEnd = now.lastSchoolDayInSchoolYear, + onDateSelected = { + presenter.onDateSet(it.year, it.monthValue, it.dayOfMonth) + } + ) } override fun showDeleteLessonDialog(timetableAdditional: TimetableAdditional) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsView.kt index 03466d69..76d37b75 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/AdditionalLessonsView.kt @@ -34,7 +34,7 @@ interface AdditionalLessonsView : BaseView { fun showNextButton(show: Boolean) - fun showDatePickerDialog(currentDate: LocalDate) + fun showDatePickerDialog(selectedDate: LocalDate) fun showAddAdditionalLessonDialog() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/add/AdditionalLessonAddDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/add/AdditionalLessonAddDialog.kt index f57841c9..f82d6483 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/add/AdditionalLessonAddDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/additional/add/AdditionalLessonAddDialog.kt @@ -5,19 +5,15 @@ 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.openMaterialDatePicker 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 @@ -128,27 +124,15 @@ class AdditionalLessonAddDialog : BaseDialogFragment } 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) - } + openMaterialDatePicker( + selected = selectedDate, + rangeStart = LocalDate.now(), + rangeEnd = LocalDate.now().lastSchoolDayInSchoolYear, + onDateSelected = { + presenter.onDateSelected(it) + binding.additionalLessonDialogDateEdit.setText(it.toFormattedString()) + } + ) } override fun showStartTimePickerDialog(selectedTime: LocalTime) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt index 4d5e3e1a..34a69e6a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsFragment.kt @@ -6,8 +6,6 @@ import android.view.View.GONE import android.view.View.INVISIBLE import android.view.View.VISIBLE import androidx.recyclerview.widget.LinearLayoutManager -import com.google.android.material.datepicker.CalendarConstraints -import com.google.android.material.datepicker.MaterialDatePicker import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.CompletedLesson @@ -16,14 +14,12 @@ 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.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.lastSchoolDayInSchoolYear -import io.github.wulkanowy.utils.toLocalDateTime -import io.github.wulkanowy.utils.toTimestamp +import io.github.wulkanowy.utils.openMaterialDatePicker import java.time.LocalDate import javax.inject.Inject @@ -150,29 +146,17 @@ class CompletedLessonsFragment : ) } - override fun showDatePickerDialog(currentDate: LocalDate) { + override fun showDatePickerDialog(selectedDate: LocalDate) { val now = LocalDate.now() - 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() - - datePicker.addOnPositiveButtonClickListener { - val date = it.toLocalDateTime() - presenter.onDateSet(date.year, date.monthValue, date.dayOfMonth) - } - - if (!parentFragmentManager.isStateSaved) { - datePicker.show(parentFragmentManager, null) - } + openMaterialDatePicker( + selected = selectedDate, + rangeStart = now.firstSchoolDayInSchoolYear, + rangeEnd = now.lastSchoolDayInSchoolYear, + onDateSelected = { + presenter.onDateSet(it.year, it.monthValue, it.dayOfMonth) + } + ) } override fun onSaveInstanceState(outState: Bundle) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsView.kt index 7a98874e..715ce01f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsView.kt @@ -38,5 +38,5 @@ interface CompletedLessonsView : BaseView { fun showCompletedLessonDialog(completedLesson: CompletedLesson) - fun showDatePickerDialog(currentDate: LocalDate) + fun showDatePickerDialog(selectedDate: LocalDate) } diff --git a/app/src/main/java/io/github/wulkanowy/utils/MaterialDatePickerUtils.kt b/app/src/main/java/io/github/wulkanowy/utils/MaterialDatePickerUtils.kt new file mode 100644 index 00000000..14b5989b --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/utils/MaterialDatePickerUtils.kt @@ -0,0 +1,51 @@ +package io.github.wulkanowy.utils + +import androidx.fragment.app.Fragment +import com.google.android.material.datepicker.CalendarConstraints +import com.google.android.material.datepicker.MaterialDatePicker +import kotlinx.parcelize.Parcelize +import java.time.LocalDate +import java.time.ZoneOffset +import java.time.temporal.ChronoUnit + +fun Fragment.openMaterialDatePicker( + selected: LocalDate, + rangeStart: LocalDate, + rangeEnd: LocalDate, + onDateSelected: (LocalDate) -> Unit, +) { + val constraintsBuilder = CalendarConstraints.Builder().apply { + setValidator(CalendarDayRangeValidator(rangeStart, rangeEnd)) + setStart(rangeStart.toTimestamp(ZoneOffset.UTC)) + setEnd(rangeEnd.toTimestamp(ZoneOffset.UTC)) + } + + val datePicker = MaterialDatePicker.Builder.datePicker() + .setCalendarConstraints(constraintsBuilder.build()) + .setSelection(selected.toTimestamp(ZoneOffset.UTC)) + .build() + + datePicker.addOnPositiveButtonClickListener { + val date = it.toLocalDateTime(ZoneOffset.UTC).toLocalDate() + onDateSelected(date) + } + + if (!parentFragmentManager.isStateSaved) { + datePicker.show(parentFragmentManager, null) + } +} + +@Parcelize +private class CalendarDayRangeValidator( + val start: LocalDate, + val end: LocalDate, +) : CalendarConstraints.DateValidator { + + override fun isValid(dateLong: Long): Boolean { + val date = dateLong.toLocalDateTime().toLocalDate() + val daysUntilEnd = date.until(end, ChronoUnit.DAYS) + val daysUntilStart = date.until(start, ChronoUnit.DAYS) + + return daysUntilStart <= 0 && daysUntilEnd >= 0 + } +} diff --git a/app/src/main/java/io/github/wulkanowy/utils/SchooldaysValidator.kt b/app/src/main/java/io/github/wulkanowy/utils/SchooldaysValidator.kt deleted file mode 100644 index b6dd528f..00000000 --- a/app/src/main/java/io/github/wulkanowy/utils/SchooldaysValidator.kt +++ /dev/null @@ -1,16 +0,0 @@ -package io.github.wulkanowy.utils - -import com.google.android.material.datepicker.CalendarConstraints -import kotlinx.parcelize.Parcelize -import java.time.temporal.ChronoUnit - -@Parcelize -class SchoolDaysValidator(val start: Long, val end: Long) : CalendarConstraints.DateValidator { - - override fun isValid(dateLong: Long): Boolean { - val date = dateLong.toLocalDateTime() - - return date.until(end.toLocalDateTime(), ChronoUnit.DAYS) >= 0 && - date.until(start.toLocalDateTime(), ChronoUnit.DAYS) <= 0 - } -} diff --git a/app/src/main/java/io/github/wulkanowy/utils/TimeExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/TimeExtension.kt index bebb6c54..355f3ab4 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/TimeExtension.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/TimeExtension.kt @@ -8,7 +8,6 @@ import java.time.DayOfWeek.SUNDAY import java.time.Instant import java.time.LocalDate import java.time.LocalDateTime -import java.time.LocalTime import java.time.Month import java.time.ZoneId import java.time.ZoneOffset @@ -23,13 +22,13 @@ private const val DEFAULT_DATE_PATTERN = "dd.MM.yyyy" fun String.toLocalDate(format: String = DEFAULT_DATE_PATTERN): LocalDate = LocalDate.parse(this, DateTimeFormatter.ofPattern(format)) -fun LocalDateTime.toTimestamp() = - atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC).toInstant().toEpochMilli() +fun LocalDateTime.toTimestamp(tz: ZoneId = ZoneId.systemDefault()) = + atZone(tz).withZoneSameInstant(ZoneOffset.UTC).toInstant().toEpochMilli() -fun Long.toLocalDateTime(): LocalDateTime = - LocalDateTime.ofInstant(Instant.ofEpochMilli(this), ZoneId.systemDefault()) +fun Long.toLocalDateTime(tz: ZoneId = ZoneId.systemDefault()): LocalDateTime = + LocalDateTime.ofInstant(Instant.ofEpochMilli(this), tz) -fun LocalDate.toTimestamp() = atTime(LocalTime.now()).toTimestamp() +fun LocalDate.toTimestamp(tz: ZoneId = ZoneId.systemDefault()) = atStartOfDay().toTimestamp(tz) fun LocalDate.toFormattedString(pattern: String = DEFAULT_DATE_PATTERN): String = format(DateTimeFormatter.ofPattern(pattern)) diff --git a/app/src/test/java/io/github/wulkanowy/utils/TimeExtensionTest.kt b/app/src/test/java/io/github/wulkanowy/utils/TimeExtensionTest.kt index 0ffbf78e..9a3bf9fe 100644 --- a/app/src/test/java/io/github/wulkanowy/utils/TimeExtensionTest.kt +++ b/app/src/test/java/io/github/wulkanowy/utils/TimeExtensionTest.kt @@ -7,6 +7,7 @@ import org.junit.Test import java.time.LocalDate.of import java.time.LocalDateTime import java.time.Month.JANUARY +import java.time.ZoneOffset import java.util.Locale class TimeExtensionTest { @@ -25,7 +26,10 @@ class TimeExtensionTest { @Test fun toFormattedStringLocalDateTimeTest() { assertEquals("01.10.2018", LocalDateTime.of(2018, 10, 1, 10, 0, 0).toFormattedString()) - assertEquals("2018-10-01 10:00:00", LocalDateTime.of(2018, 10, 1, 10, 0, 0).toFormattedString("uuuu-MM-dd HH:mm:ss")) + assertEquals( + "2018-10-01 10:00:00", + LocalDateTime.of(2018, 10, 1, 10, 0, 0).toFormattedString("uuuu-MM-dd HH:mm:ss") + ) } @Test @@ -222,4 +226,18 @@ class TimeExtensionTest { assertEquals(of(2020, 10, 18), endExamsDay) } } + + @Test + fun getLocalDateToTimestampUTC() { + assertEquals(0L, of(1970, 1, 1).toTimestamp(ZoneOffset.UTC)) + assertEquals(946684800000L, of(2000, 1, 1).toTimestamp(ZoneOffset.UTC)) + assertEquals(1640131200000L, of(2021, 12, 22).toTimestamp(ZoneOffset.UTC)) + } + + @Test + fun getLocalDateTimeToUtcTimestamp() { + assertEquals(0L, LocalDateTime.of(1970, 1, 1, 0, 0, 0).toTimestamp(ZoneOffset.UTC)) + assertEquals(946684800000L, LocalDateTime.of(2000, 1, 1, 0, 0, 0).toTimestamp(ZoneOffset.UTC)) + assertEquals(1640131200000L, LocalDateTime.of(2021, 12, 22, 0, 0, 0).toTimestamp(ZoneOffset.UTC)) + } }