Open SapuSeven opened 4 years ago
This is a great idea but I don't have the bandwidth right now to build it. You are more than welcome to add this functionality and submit a pull request.
If you're okay with not having the background between the start and end days you can implement a custom SelectionMode
to achieve the range behaviour. I drafted one below. You can update it to get the user experience you want:
class RangeSelectionMode(
private val materialDayPicker: MaterialDayPicker
) : SelectionMode {
override fun getSelectionStateAfterSelecting(lastSelectionState: SelectionState, dayToSelect: MaterialDayPicker.Weekday): SelectionState {
return createRangedSelectionState(
lastSelectionState = lastSelectionState,
dayPressed = dayToSelect
)
}
override fun getSelectionStateAfterDeselecting(lastSelectionState: SelectionState, dayToDeselect: MaterialDayPicker.Weekday): SelectionState {
return createRangedSelectionState(
lastSelectionState = lastSelectionState,
dayPressed = dayToDeselect
)
}
private fun createRangedSelectionState(lastSelectionState: SelectionState, dayPressed: MaterialDayPicker.Weekday): SelectionState {
val previouslySelectedDays = lastSelectionState.selectedDays
val orderedWeekdays = getWeekdaysOrderedForCurrentLocale()
val ordinalsOfPreviouslySelectedDays = previouslySelectedDays.map { orderedWeekdays.indexOf(it) }
val ordinalOfFirstDayInPreviousRange = ordinalsOfPreviouslySelectedDays.min()
val ordinalOfLastDayInPreviousRange = ordinalsOfPreviouslySelectedDays.max()
val ordinalOfSelectedDay = orderedWeekdays.indexOf(dayPressed)
return when {
ordinalOfFirstDayInPreviousRange == null || ordinalOfLastDayInPreviousRange == null -> {
// We had no previous selection so just return the day pressed as the selection.
SelectionState.withSingleDay(dayPressed)
}
ordinalOfFirstDayInPreviousRange == ordinalOfLastDayInPreviousRange && ordinalOfFirstDayInPreviousRange == ordinalOfSelectedDay -> {
// User pressed the only day in the range selection. Return an empty selection.
SelectionState()
}
ordinalOfSelectedDay == ordinalOfFirstDayInPreviousRange || ordinalOfSelectedDay == ordinalOfLastDayInPreviousRange -> {
// User pressed the first or last item in range. Just deselect that item.
lastSelectionState.withDayDeselected(dayPressed)
}
ordinalOfSelectedDay < ordinalOfFirstDayInPreviousRange -> {
// User pressed a day on the left of the previous date range. Grow the starting point of the range to that.
SelectionState(selectedDays = orderedWeekdays.subList(ordinalOfSelectedDay, ordinalOfLastDayInPreviousRange + 1))
}
else -> {
// User pressed a day on the right of the start of the date range. Update the ending point to that position.
SelectionState(selectedDays = orderedWeekdays.subList(ordinalOfFirstDayInPreviousRange, ordinalOfSelectedDay + 1))
}
}
}
private fun getWeekdaysOrderedForCurrentLocale(): List<MaterialDayPicker.Weekday> {
return MaterialDayPicker.Weekday.getOrderedDaysOfWeek(materialDayPicker.locale)
}
}
You can use it by doing:
materialDayPicker.selectionMode = RangeSelectionMode(materialDayPicker)
Sample usage:
Awesome, thank you very much! I'll use your suggested approach for now, maybe I'll implement the background thing and submit a pull request later.
I want to allow a user to input a day range. Using this library, it is possible to select every day independently, however for my application I only want to allow selection of a range of continuous days.
You can see this on the Material Design Pickers page as Mobile Date Range Picker.
I imagine it looking like this, only for a single week:
Is there any possibility for this to get added?