Skip to content

Commit a207114

Browse files
Material Design Teamimhappi
authored andcommitted
[DatePicker] Add MonthAdapter helpers for finding enabled days
This change introduces helper methods to `MonthAdapter` to allow callers to identify days that are enabled according to the `CalendarConstraints`. PiperOrigin-RevId: 826466043
1 parent 3b971c9 commit a207114

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed

lib/java/com/google/android/material/datepicker/MonthAdapter.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,4 +343,61 @@ boolean isFirstInRow(int position) {
343343
boolean isLastInRow(int position) {
344344
return (position + 1) % month.daysInWeek == 0;
345345
}
346+
347+
/**
348+
* Returns true if the day at the given adapter position is within the current month, and valid
349+
* according to the {@link CalendarConstraints}.
350+
*/
351+
boolean isDayPositionValid(int position) {
352+
Long day = getItem(position);
353+
return day != null && calendarConstraints.getDateValidator().isValid(day);
354+
}
355+
356+
/**
357+
* Finds the closest valid day to the given position searching forward.
358+
*
359+
* @param position The starting position.
360+
* @return The position of the next valid day, or -1 if none is found before reaching the
361+
* end of the month.
362+
*/
363+
int findNextValidDayPosition(int position) {
364+
for (int i = position + 1; i <= lastPositionInMonth(); i++) {
365+
if (isDayPositionValid(i)) {
366+
return i;
367+
}
368+
}
369+
return -1;
370+
}
371+
372+
/**
373+
* Finds the closest valid day to the given position searching backward.
374+
*
375+
* @param position The starting position.
376+
* @return The position of the previous valid day, or -1 if none is found before reaching the
377+
* start of the month.
378+
*/
379+
int findPreviousValidDayPosition(int position) {
380+
for (int i = position - 1; i >= firstPositionInMonth(); i--) {
381+
if (isDayPositionValid(i)) {
382+
return i;
383+
}
384+
}
385+
return -1;
386+
}
387+
388+
/**
389+
* Returns the adapter position of the first day in the month that is valid, or -1 if no days
390+
* are valid.
391+
*/
392+
int findFirstValidDayPosition() {
393+
return findNextValidDayPosition(firstPositionInMonth() - 1);
394+
}
395+
396+
/**
397+
* Returns the adapter position of the last day in the month that is valid, or -1 if no days are
398+
* valid.
399+
*/
400+
int findLastValidDayPosition() {
401+
return findPreviousValidDayPosition(lastPositionInMonth() + 1);
402+
}
346403
}

lib/javatests/com/google/android/material/datepicker/MonthAdapterTest.java

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,90 @@ public void rangeDateSelector_isNotEndOfRange() {
388388
assertFalse(monthAdapter.isEndOfRange(month.getDay(9)));
389389
}
390390

391+
@Test
392+
public void isDayPositionValid_withValidator() {
393+
Locale.setDefault(Locale.US);
394+
Month month = Month.create(2019, Calendar.FEBRUARY);
395+
long dateValidFrom = month.getDay(15);
396+
CalendarConstraints constraints =
397+
new CalendarConstraints.Builder()
398+
.setValidator(DateValidatorPointForward.from(dateValidFrom))
399+
.build();
400+
MonthAdapter adapter = new MonthAdapter(month, new SingleDateSelector(), constraints, null);
401+
402+
assertThat(adapter.isDayPositionValid(adapter.dayToPosition(14))).isFalse();
403+
assertThat(adapter.isDayPositionValid(adapter.dayToPosition(15))).isTrue();
404+
}
405+
406+
@Test
407+
public void findNextValidDayPosition_withValidator() {
408+
Locale.setDefault(Locale.US);
409+
Month month = Month.create(2019, Calendar.FEBRUARY);
410+
long dateValidFrom = month.getDay(15);
411+
CalendarConstraints constraints =
412+
new CalendarConstraints.Builder()
413+
.setValidator(DateValidatorPointForward.from(dateValidFrom))
414+
.build();
415+
MonthAdapter adapter = new MonthAdapter(month, new SingleDateSelector(), constraints, null);
416+
417+
// Search forward from day 28 (last valid day), expecting no results.
418+
assertThat(adapter.findNextValidDayPosition(adapter.dayToPosition(28))).isEqualTo(-1);
419+
// Search forward from day 14 (valid) to day 15 (valid).
420+
assertThat(adapter.findNextValidDayPosition(adapter.dayToPosition(14)))
421+
.isEqualTo(adapter.dayToPosition(15));
422+
}
423+
424+
@Test
425+
public void findPreviousValidDayPosition_withValidator() {
426+
Locale.setDefault(Locale.US);
427+
Month month = Month.create(2019, Calendar.FEBRUARY);
428+
long dateValidFrom = month.getDay(15);
429+
CalendarConstraints constraints =
430+
new CalendarConstraints.Builder()
431+
.setValidator(DateValidatorPointForward.from(dateValidFrom))
432+
.build();
433+
MonthAdapter adapter = new MonthAdapter(month, new SingleDateSelector(), constraints, null);
434+
435+
// Search backward from day 15 (first valid day), expecting no results.
436+
assertThat(adapter.findPreviousValidDayPosition(adapter.dayToPosition(15))).isEqualTo(-1);
437+
// Search backward from day 16 (valid) to day 15 (valid).
438+
assertThat(adapter.findPreviousValidDayPosition(adapter.dayToPosition(16)))
439+
.isEqualTo(adapter.dayToPosition(15));
440+
}
441+
442+
@Test
443+
public void findFirstValidDayPosition_withValidator() {
444+
Locale.setDefault(Locale.US);
445+
Month month = Month.create(2019, Calendar.FEBRUARY);
446+
long dateValidFrom = month.getDay(15);
447+
CalendarConstraints constraints =
448+
new CalendarConstraints.Builder()
449+
.setValidator(DateValidatorPointForward.from(dateValidFrom))
450+
.build();
451+
MonthAdapter adapter = new MonthAdapter(month, new SingleDateSelector(), constraints, null);
452+
453+
assertThat(adapter.findFirstValidDayPosition()).isEqualTo(adapter.dayToPosition(15));
454+
}
455+
456+
@Test
457+
public void findLastValidDayPosition_withValidator() {
458+
Locale.setDefault(Locale.US);
459+
Month month = Month.create(2019, Calendar.FEBRUARY);
460+
long dateValidFrom = month.getDay(15);
461+
long dateValidTo = month.getDay(18);
462+
CalendarConstraints constraints =
463+
new CalendarConstraints.Builder()
464+
.setValidator(
465+
CompositeDateValidator.allOf(
466+
Arrays.asList(
467+
DateValidatorPointForward.from(dateValidFrom),
468+
DateValidatorPointBackward.before(dateValidTo))))
469+
.build();
470+
MonthAdapter adapter = new MonthAdapter(month, new SingleDateSelector(), constraints, null);
471+
472+
assertThat(adapter.findLastValidDayPosition()).isEqualTo(adapter.dayToPosition(18));
473+
}
474+
391475
private MonthAdapter createRangeMonthAdapter(Month month, Pair<Long, Long> selection) {
392476
DateSelector<Pair<Long, Long>> dateSelector = new RangeDateSelector();
393477
dateSelector.setSelection(selection);

0 commit comments

Comments
 (0)