Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Final - Select range #315

Merged
merged 9 commits into from
May 23, 2016
Merged
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ android:
components:
- tools
- platform-tools
- build-tools-23.0.2
- build-tools-23.0.3
- android-23
- extra-android-m2repository
- extra-google-m2repository
2 changes: 1 addition & 1 deletion library/build.gradle
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ apply plugin: 'signing'

android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
buildToolsVersion "23.0.3"

defaultConfig {
minSdkVersion 14
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.SparseArray;
@@ -41,6 +42,8 @@
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

/**
* <p>
@@ -73,7 +76,7 @@ public class MaterialCalendarView extends ViewGroup {
* @see #getSelectionMode()
*/
@Retention(RetentionPolicy.RUNTIME)
@IntDef({SELECTION_MODE_NONE, SELECTION_MODE_SINGLE, SELECTION_MODE_MULTIPLE})
@IntDef({SELECTION_MODE_NONE, SELECTION_MODE_SINGLE, SELECTION_MODE_MULTIPLE, SELECTION_MODE_RANGE})
public @interface SelectionMode {
}

@@ -95,6 +98,11 @@ public class MaterialCalendarView extends ViewGroup {
*/
public static final int SELECTION_MODE_MULTIPLE = 2;

/**
* Selection mode which allows selection of a range between two dates
*/
public static final int SELECTION_MODE_RANGE = 3;

/**
* {@linkplain IntDef} annotation for showOtherDates.
*
@@ -204,6 +212,8 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse

private OnDateSelectedListener listener;
private OnMonthChangedListener monthListener;
private OnRangeSelectedListener rangeListener;


CharSequence calendarContentDescription;
private int accentColor = 0;
@@ -413,40 +423,39 @@ private void updateUi() {
* Change the selection mode of the calendar. The default mode is {@linkplain #SELECTION_MODE_SINGLE}
*
* @param mode the selection mode to change to. This must be one of
* {@linkplain #SELECTION_MODE_NONE}, {@linkplain #SELECTION_MODE_SINGLE}, or {@linkplain #SELECTION_MODE_MULTIPLE}.
* {@linkplain #SELECTION_MODE_NONE}, {@linkplain #SELECTION_MODE_SINGLE},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SELECTION_MODE_MULTIPLE shouldn't be removed, this is breaking selection mode multiple

* {@linkplain #SELECTION_MODE_RANGE} or {@linkplain #SELECTION_MODE_MULTIPLE}.
* Unknown values will act as {@linkplain #SELECTION_MODE_SINGLE}
* @see #getSelectionMode()
* @see #SELECTION_MODE_NONE
* @see #SELECTION_MODE_SINGLE
* @see #SELECTION_MODE_MULTIPLE
* @see #SELECTION_MODE_RANGE
*/
public void setSelectionMode(final @SelectionMode int mode) {
final @SelectionMode int oldMode = this.selectionMode;
this.selectionMode = mode;
switch (mode) {
case SELECTION_MODE_MULTIPLE: {
this.selectionMode = SELECTION_MODE_MULTIPLE;
}
break;
default:
case SELECTION_MODE_SINGLE: {
this.selectionMode = SELECTION_MODE_SINGLE;
if (oldMode == SELECTION_MODE_MULTIPLE) {
case SELECTION_MODE_RANGE:
clearSelection();
break;
case SELECTION_MODE_SINGLE:
if (oldMode == SELECTION_MODE_MULTIPLE || oldMode == SELECTION_MODE_RANGE) {
//We should only have one selection now, so we should pick one
List<CalendarDay> dates = getSelectedDates();
if (!dates.isEmpty()) {
setSelectedDate(getSelectedDate());
}
}
}
break;
case SELECTION_MODE_NONE: {
break;
default:
case SELECTION_MODE_NONE:
this.selectionMode = SELECTION_MODE_NONE;
if (oldMode != SELECTION_MODE_NONE) {
//No selection! Clear out!
clearSelection();
}
}
break;
break;
}

adapter.setSelectionEnabled(selectionMode != SELECTION_MODE_NONE);
@@ -482,6 +491,7 @@ public void goToNext() {
* @see #SELECTION_MODE_NONE
* @see #SELECTION_MODE_SINGLE
* @see #SELECTION_MODE_MULTIPLE
* @see #SELECTION_MODE_RANGE
*/
@SelectionMode
public int getSelectionMode() {
@@ -1088,6 +1098,7 @@ private void setRangeDates(CalendarDay min, CalendarDay max) {
currentMonth = c;
int position = adapter.getIndexForDay(c);
pager.setCurrentItem(position, false);
updateUi();
}

public static class SavedState extends BaseSavedState {
@@ -1292,6 +1303,15 @@ public void setOnMonthChangedListener(OnMonthChangedListener listener) {
this.monthListener = listener;
}

/**
* Sets the listener to be notified upon a range has been selected.
*
* @param listener thing to be notified
*/
public void setOnRangeSelectedListener(OnRangeSelectedListener listener) {
this.rangeListener = listener;
}

/**
* Dispatch date change events to a listener, if set
*
@@ -1305,6 +1325,41 @@ protected void dispatchOnDateSelected(final CalendarDay day, final boolean selec
}
}

/**
* Dispatch a range of days to a listener, if set
*
* @param firstDay first day enclosing a range
* @param lastDay last day enclosing a range
*/
protected void dispatchOnRangeSelected(final CalendarDay firstDay, final CalendarDay lastDay) {
final OnRangeSelectedListener listener = rangeListener;
final List<CalendarDay> days = new ArrayList<>();

final SortedSet<Date> sortedDays = new TreeSet<>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sort is unnecessary--we only have two dates. If first day is after last day, call the method again with inverted params:

if (firstDay.isAfter(lastDay)) {
  dispatchOnRangeSelected(lastDay, firstDay);
  return;
}

sortedDays.add(firstDay.getDate());
sortedDays.add(lastDay.getDate());

final Date first = sortedDays.first(); // min date
final Date last = sortedDays.last(); // max date

final Calendar counter = Calendar.getInstance();
counter.setTime(first); // start from the first day and increment

final Calendar end = Calendar.getInstance();
end.setTime(last); // for comparison

while (counter.before(end) || counter.equals(end)) {
final CalendarDay current = CalendarDay.from(counter);
adapter.setDateSelected(current, true);
days.add(current);
counter.add(Calendar.DATE, 1);
}

if (listener != null) {
listener.onRangeSelected(MaterialCalendarView.this, days);
}
}

/**
* Dispatch date change events to a listener, if set
*
@@ -1331,6 +1386,21 @@ protected void onDateClicked(@NonNull CalendarDay date, boolean nowSelected) {
dispatchOnDateSelected(date, nowSelected);
}
break;
case SELECTION_MODE_RANGE: {
adapter.setDateSelected(date, nowSelected);
if (adapter.getSelectedDates().size() > 2) {
adapter.clearSelections();
adapter.setDateSelected(date, nowSelected); // re-set because adapter has been cleared
dispatchOnDateSelected(date, nowSelected);
} else if (adapter.getSelectedDates().size() == 2) {
final List<CalendarDay> dates = adapter.getSelectedDates();
dispatchOnRangeSelected(dates.get(0), dates.get(1));
} else {
adapter.setDateSelected(date, nowSelected);
dispatchOnDateSelected(date, nowSelected);
}
}
break;
default:
case SELECTION_MODE_SINGLE: {
adapter.clearSelections();
@@ -1341,6 +1411,17 @@ protected void onDateClicked(@NonNull CalendarDay date, boolean nowSelected) {
}
}

/**
* Select a fresh range of date including first day and last day.
*
* @param firstDay first day of the range to select
* @param lastDay last day of the range to select
*/
public void selectRange(final CalendarDay firstDay, final CalendarDay lastDay) {
clearSelection();
dispatchOnRangeSelected(firstDay, lastDay);
}

/**
* Call by {@link CalendarPagerView} to indicate that a day was clicked and we should handle it
*
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.prolificinteractive.materialcalendarview;

import android.support.annotation.NonNull;

import java.util.List;

/**
* The callback used to indicate a range has been selected
*/
public interface OnRangeSelectedListener {

/**
* Called when a user selects a range of days.
* There is no logic to prevent multiple calls for the same date and state.
*
* @param widget the view associated with this listener
* @param dates the dates in the range, in ascending order
*/
void onRangeSelected(@NonNull MaterialCalendarView widget, @NonNull List<CalendarDay> dates);
}
2 changes: 1 addition & 1 deletion sample/build.gradle
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ apply plugin: 'com.android.application'

android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
buildToolsVersion "23.0.3"

defaultConfig {
applicationId "com.prolificinteractive.materialcalendarview.sample"
Original file line number Diff line number Diff line change
@@ -230,7 +230,8 @@ void onChangeSelectionMode() {
CharSequence[] items = {
"No Selection",
"Single Date",
"Multiple Dates"
"Multiple Dates",
"Range of Dates"
};
new AlertDialog.Builder(this)
.setTitle("Selection Mode")