Migrate material date picker (#1277)

This commit is contained in:
Mateusz Idziejczak 2021-04-12 21:43:52 +02:00 committed by GitHub
parent 95ffb0a687
commit 13ccfda009
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 180 additions and 129 deletions

View File

@ -1,5 +1,6 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'
apply plugin: 'com.google.firebase.crashlytics'
@ -209,7 +210,6 @@ dependencies {
implementation "at.favre.lib:slf4j-timber:1.0.1"
implementation "fr.bipi.treessence:treessence:0.3.2"
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
implementation "io.coil-kt:coil:1.1.1"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.3.1'

View File

@ -13,7 +13,8 @@ import android.view.View.VISIBLE
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.view.ActionMode
import androidx.recyclerview.widget.LinearLayoutManager
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog
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
@ -24,9 +25,12 @@ import io.github.wulkanowy.ui.modules.attendance.summary.AttendanceSummaryFragme
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.SchooldaysRangeLimiter
import io.github.wulkanowy.utils.SchoolDaysValidator
import io.github.wulkanowy.utils.dpToPx
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
import javax.inject.Inject
@ -216,19 +220,27 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag
}
override fun showDatePickerDialog(currentDate: LocalDate) {
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
presenter.onDateSet(year, month + 1, dayOfMonth)
}
val datePickerDialog = DatePickerDialog.newInstance(dateSetListener,
currentDate.year, currentDate.monthValue - 1, currentDate.dayOfMonth)
val now = LocalDate.now()
val startOfSchoolYear = now.schoolYearStart.toTimestamp()
val endWeek = now.plusWeeks(1).toTimestamp()
with(datePickerDialog) {
setDateRangeLimiter(SchooldaysRangeLimiter())
version = DatePickerDialog.Version.VERSION_2
scrollOrientation = DatePickerDialog.ScrollOrientation.VERTICAL
vibrate(false)
show(this@AttendanceFragment.parentFragmentManager, null)
val constraintsBuilder = CalendarConstraints.Builder().apply {
setValidator(SchoolDaysValidator(startOfSchoolYear, endWeek))
setStart(startOfSchoolYear)
setEnd(endWeek)
}
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)
}
datePicker.show(this@AttendanceFragment.parentFragmentManager, null)
}
override fun showExcuseDialog() {

View File

@ -5,7 +5,8 @@ import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import androidx.recyclerview.widget.LinearLayoutManager
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog
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
@ -13,14 +14,18 @@ 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.SchooldaysRangeLimiter
import io.github.wulkanowy.utils.SchoolDaysValidator
import io.github.wulkanowy.utils.dpToPx
import io.github.wulkanowy.utils.schoolYearStart
import io.github.wulkanowy.utils.toLocalDateTime
import io.github.wulkanowy.utils.toTimestamp
import java.time.LocalDate
import javax.inject.Inject
@AndroidEntryPoint
class LuckyNumberHistoryFragment :
BaseFragment<FragmentLuckyNumberHistoryBinding>(R.layout.fragment_lucky_number_history), LuckyNumberHistoryView,
BaseFragment<FragmentLuckyNumberHistoryBinding>(R.layout.fragment_lucky_number_history),
LuckyNumberHistoryView,
MainView.TitledView {
@Inject
@ -107,19 +112,26 @@ class LuckyNumberHistoryFragment :
}
override fun showDatePickerDialog(currentDate: LocalDate) {
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
presenter.onDateSet(year, month + 1, dayOfMonth)
}
val datePickerDialog = DatePickerDialog.newInstance(dateSetListener,
currentDate.year, currentDate.monthValue - 1, currentDate.dayOfMonth)
val now = LocalDate.now()
val startOfSchoolYear = now.schoolYearStart.toTimestamp()
with(datePickerDialog) {
setDateRangeLimiter(SchooldaysRangeLimiter())
version = DatePickerDialog.Version.VERSION_2
scrollOrientation = DatePickerDialog.ScrollOrientation.VERTICAL
vibrate(false)
show(this@LuckyNumberHistoryFragment.parentFragmentManager, null)
val constraintsBuilder = CalendarConstraints.Builder().apply {
setValidator(SchoolDaysValidator(startOfSchoolYear, now.toTimestamp()))
setStart(startOfSchoolYear)
setEnd(now.toTimestamp())
}
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)
}
datePicker.show(this@LuckyNumberHistoryFragment.parentFragmentManager, null)
}
override fun showContent(show: Boolean) {

View File

@ -9,7 +9,8 @@ import android.view.View.GONE
import android.view.View.VISIBLE
import androidx.core.text.HtmlCompat
import androidx.recyclerview.widget.LinearLayoutManager
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog
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
@ -20,9 +21,13 @@ 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.SchooldaysRangeLimiter
import io.github.wulkanowy.utils.SchoolDaysValidator
import io.github.wulkanowy.utils.dpToPx
import io.github.wulkanowy.utils.getThemeAttrColor
import io.github.wulkanowy.utils.schoolYearEnd
import io.github.wulkanowy.utils.schoolYearStart
import io.github.wulkanowy.utils.toLocalDateTime
import io.github.wulkanowy.utils.toTimestamp
import java.time.LocalDate
import javax.inject.Inject
@ -184,21 +189,27 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
}
override fun showDatePickerDialog(currentDate: LocalDate) {
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
presenter.onDateSet(year, month + 1, dayOfMonth)
}
val datePickerDialog = DatePickerDialog.newInstance(
dateSetListener,
currentDate.year, currentDate.monthValue - 1, currentDate.dayOfMonth
)
val now = LocalDate.now()
val startOfSchoolYear = now.schoolYearStart.toTimestamp()
val endOfSchoolYear = now.schoolYearEnd.toTimestamp()
with(datePickerDialog) {
setDateRangeLimiter(SchooldaysRangeLimiter())
version = DatePickerDialog.Version.VERSION_2
scrollOrientation = DatePickerDialog.ScrollOrientation.VERTICAL
vibrate(false)
show(this@TimetableFragment.parentFragmentManager, null)
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)
}
datePicker.show(this@TimetableFragment.parentFragmentManager, null)
}
override fun openAdditionalLessonsView() {

View File

@ -3,7 +3,8 @@ package io.github.wulkanowy.ui.modules.timetable.additional
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog
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
@ -11,9 +12,13 @@ import io.github.wulkanowy.databinding.FragmentTimetableAdditionalBinding
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.SchooldaysRangeLimiter
import io.github.wulkanowy.utils.SchoolDaysValidator
import io.github.wulkanowy.utils.dpToPx
import io.github.wulkanowy.utils.getThemeAttrColor
import io.github.wulkanowy.utils.schoolYearEnd
import io.github.wulkanowy.utils.schoolYearStart
import io.github.wulkanowy.utils.toLocalDateTime
import io.github.wulkanowy.utils.toTimestamp
import java.time.LocalDate
import javax.inject.Inject
@ -55,7 +60,11 @@ class AdditionalLessonsFragment :
with(binding) {
additionalLessonsSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
additionalLessonsSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
additionalLessonsSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh))
additionalLessonsSwipe.setProgressBackgroundColorSchemeColor(
requireContext().getThemeAttrColor(
R.attr.colorSwipeRefresh
)
)
additionalLessonsErrorRetry.setOnClickListener { presenter.onRetry() }
additionalLessonsErrorDetails.setOnClickListener { presenter.onDetailsClick() }
@ -114,7 +123,8 @@ class AdditionalLessonsFragment :
}
override fun showPreButton(show: Boolean) {
binding.additionalLessonsPreviousButton.visibility = if (show) View.VISIBLE else View.INVISIBLE
binding.additionalLessonsPreviousButton.visibility =
if (show) View.VISIBLE else View.INVISIBLE
}
override fun showNextButton(show: Boolean) {
@ -122,19 +132,27 @@ class AdditionalLessonsFragment :
}
override fun showDatePickerDialog(currentDate: LocalDate) {
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
presenter.onDateSet(year, month + 1, dayOfMonth)
}
val datePickerDialog = DatePickerDialog.newInstance(dateSetListener,
currentDate.year, currentDate.monthValue - 1, currentDate.dayOfMonth)
val now = LocalDate.now()
val startOfSchoolYear = now.schoolYearStart.toTimestamp()
val endOfSchoolYear = now.schoolYearEnd.toTimestamp()
with(datePickerDialog) {
setDateRangeLimiter(SchooldaysRangeLimiter())
version = DatePickerDialog.Version.VERSION_2
scrollOrientation = DatePickerDialog.ScrollOrientation.VERTICAL
vibrate(false)
show(this@AdditionalLessonsFragment.parentFragmentManager, null)
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)
}
datePicker.show(this@AdditionalLessonsFragment.parentFragmentManager, null)
}
override fun onSaveInstanceState(outState: Bundle) {

View File

@ -6,7 +6,8 @@ import android.view.View.GONE
import android.view.View.INVISIBLE
import android.view.View.VISIBLE
import androidx.recyclerview.widget.LinearLayoutManager
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog
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
@ -15,10 +16,14 @@ 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.SchooldaysRangeLimiter
import io.github.wulkanowy.utils.SchoolDaysValidator
import io.github.wulkanowy.utils.dpToPx
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.toLocalDateTime
import io.github.wulkanowy.utils.toTimestamp
import java.time.LocalDate
import javax.inject.Inject
@ -62,7 +67,11 @@ class CompletedLessonsFragment :
with(binding) {
completedLessonsSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
completedLessonsSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
completedLessonsSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh))
completedLessonsSwipe.setProgressBackgroundColorSchemeColor(
requireContext().getThemeAttrColor(
R.attr.colorSwipeRefresh
)
)
completedLessonErrorRetry.setOnClickListener { presenter.onRetry() }
completedLessonErrorDetails.setOnClickListener { presenter.onDetailsClick() }
@ -136,23 +145,35 @@ class CompletedLessonsFragment :
}
override fun showCompletedLessonDialog(completedLesson: CompletedLesson) {
(activity as? MainActivity)?.showDialogFragment(CompletedLessonDialog.newInstance(completedLesson))
(activity as? MainActivity)?.showDialogFragment(
CompletedLessonDialog.newInstance(
completedLesson
)
)
}
override fun showDatePickerDialog(currentDate: LocalDate) {
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
presenter.onDateSet(year, month + 1, dayOfMonth)
}
val datePickerDialog = DatePickerDialog.newInstance(dateSetListener,
currentDate.year, currentDate.monthValue - 1, currentDate.dayOfMonth)
val now = LocalDate.now()
val startOfSchoolYear = now.schoolYearStart.toTimestamp()
val endOfSchoolYear = now.schoolYearEnd.toTimestamp()
with(datePickerDialog) {
setDateRangeLimiter(SchooldaysRangeLimiter())
version = DatePickerDialog.Version.VERSION_2
scrollOrientation = DatePickerDialog.ScrollOrientation.VERTICAL
vibrate(false)
show(this@CompletedLessonsFragment.parentFragmentManager, null)
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)
}
datePicker.show(this@CompletedLessonsFragment.parentFragmentManager, null)
}
override fun onSaveInstanceState(outState: Bundle) {

View File

@ -1,51 +0,0 @@
package io.github.wulkanowy.utils
import android.os.Parcel
import android.os.Parcelable
import com.wdullaer.materialdatetimepicker.date.DateRangeLimiter
import java.time.DayOfWeek
import java.time.LocalDate
import java.util.Calendar
@Suppress("UNUSED_PARAMETER")
class SchooldaysRangeLimiter : DateRangeLimiter {
private val now = LocalDate.now()
override fun setToNearestDate(day: Calendar): Calendar = day
override fun isOutOfRange(year: Int, month: Int, day: Int): Boolean {
val date = LocalDate.of(year, month + 1, day)
val dayOfWeek = date.dayOfWeek
return dayOfWeek == DayOfWeek.SUNDAY || date.isHolidays
}
override fun getStartDate(): Calendar {
val startYear = if (now.monthValue <= 6) now.year - 1 else now.year
val startOfSchoolYear = now.withYear(startYear).firstSchoolDay
val calendar = Calendar.getInstance()
calendar.set(startOfSchoolYear.year, startOfSchoolYear.monthValue - 1, startOfSchoolYear.dayOfMonth)
return calendar
}
override fun getEndDate(): Calendar {
val endYear = if (now.monthValue > 6) now.year + 1 else now.year
val endOfSchoolYear = now.withYear(endYear).lastSchoolDay
val calendar = Calendar.getInstance()
calendar.set(endOfSchoolYear.year, endOfSchoolYear.monthValue - 1, endOfSchoolYear.dayOfMonth)
return calendar
}
override fun writeToParcel(parcel: Parcel, flags: Int) {}
override fun describeContents() = 0
companion object CREATOR : Parcelable.Creator<SchooldaysRangeLimiter> {
override fun createFromParcel(parcel: Parcel): SchooldaysRangeLimiter = SchooldaysRangeLimiter()
override fun newArray(size: Int): Array<SchooldaysRangeLimiter?> = arrayOfNulls(size)
}
}

View File

@ -0,0 +1,18 @@
package io.github.wulkanowy.utils
import com.google.android.material.datepicker.CalendarConstraints
import kotlinx.parcelize.Parcelize
import java.time.DayOfWeek
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 &&
date.dayOfWeek != DayOfWeek.SUNDAY
}
}

View File

@ -11,6 +11,7 @@ import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalDateTime.now
import java.time.LocalDateTime.ofInstant
import java.time.LocalTime
import java.time.Month
import java.time.ZoneId
import java.time.ZoneOffset
@ -22,15 +23,20 @@ import java.util.Locale
private const val DATE_PATTERN = "dd.MM.yyyy"
fun String.toLocalDate(format: String = DATE_PATTERN): LocalDate = LocalDate.parse(this, ofPattern(format))
fun String.toLocalDate(format: String = DATE_PATTERN): LocalDate =
LocalDate.parse(this, ofPattern(format))
fun LocalDateTime.toTimestamp() = atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC).toInstant().toEpochMilli()
fun LocalDateTime.toTimestamp() =
atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC).toInstant().toEpochMilli()
fun Long.toLocalDateTime(): LocalDateTime = ofInstant(ofEpochMilli(this), ZoneId.systemDefault())
fun LocalDate.toTimestamp() = atTime(LocalTime.now()).toTimestamp()
fun LocalDate.toFormattedString(format: String = DATE_PATTERN): String = format(ofPattern(format))
fun LocalDateTime.toFormattedString(format: String = DATE_PATTERN): String = format(ofPattern(format))
fun LocalDateTime.toFormattedString(format: String = DATE_PATTERN): String =
format(ofPattern(format))
@SuppressLint("DefaultLocale")
fun Month.getFormattedName(): String {
@ -105,6 +111,12 @@ inline val LocalDate.lastSchoolDay: LocalDate
get() = LocalDate.of(year, 6, 20)
.with(next(FRIDAY))
inline val LocalDate.schoolYearStart: LocalDate
get() = withYear(if (this.monthValue <= 6) this.year - 1 else this.year).firstSchoolDay
inline val LocalDate.schoolYearEnd: LocalDate
get() = withYear(if (this.monthValue > 6) this.year + 1 else this.year).lastSchoolDay
private fun Int.getSchoolYearByMonth(monthValue: Int): Int {
return when (monthValue) {
in 9..12 -> this

View File

@ -14,7 +14,6 @@
<item name="android:statusBarColor">@color/colorStatusBarLight</item>
<item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">false</item>
<item name="android:windowLightStatusBar" tools:targetApi="m">false</item>
<item name="mdtp_theme_dark">true</item>
</style>
<style name="WulkanowyTheme.Black" parent="WulkanowyTheme.NoActionBar">

View File

@ -14,7 +14,6 @@
<item name="android:statusBarColor">@android:color/darker_gray</item>
<item name="android:textColor">?android:textColorPrimary</item>
<item name="android:preferenceStyle">@style/PreferenceThemeOverlay</item>
<item name="mdtp_theme_dark">false</item>
</style>
<style name="WulkanowyTheme.NoActionBar" parent="WulkanowyTheme">