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

Added ability to set date range for datetimepicker and minimum minute interval for time picker #30

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
2 changes: 2 additions & 0 deletions datetimepicker-library/res/values/colors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
<color name="blue">#ff33b5e5</color>
<color name="darker_blue">#ff0099cc</color>
<color name="date_picker_text_normal">#ff999999</color>
<color name="date_picker_text_disabled">#ffcccccc</color>
<color name="calendar_header">#ff999999</color>
<color name="date_picker_view_animator">#fff2f2f2</color>

<color name="ampm_text_color">#8c8c8c</color>
<color name="numbers_text_color">#8c8c8c</color>
<color name="numbers_disable_text_color">#e3e3e3</color>

<color name="transparent_black">#7F000000</color>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ abstract interface DatePickerController {
public abstract int getMaxYear();

public abstract int getMinYear();

public abstract int getStartMonth();

public abstract int getEndMonth();

public abstract int getStartDay();

public abstract int getEndDay();

public abstract SimpleMonthAdapter.CalendarDay getSelectedDay();

public abstract void onDayOfMonthSelected(int year, int month, int day);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ public class DatePickerDialog extends DialogFragment implements View.OnClickList
private HashSet<OnDateChangedListener> mListeners = new HashSet<OnDateChangedListener>();
private int mMaxYear = MAX_YEAR;
private int mMinYear = MIN_YEAR;
private int mStartMonth = 0;
private int mStartDay = 1;
private int mEndMonth = 11;
private int mEndDay = 31;
private LinearLayout mMonthAndDayView;
private String mSelectDay;
private String mSelectYear;
Expand All @@ -67,6 +71,31 @@ private void adjustDayInMonthIfNeeded(int month, int year) {
if (currentDay > day)
this.mCalendar.set(Calendar.DAY_OF_MONTH, day);
}

private void adjustDayAndMonthIfNeeded(int month, int year) {

if (year == this.mMinYear) {
if (month < mStartMonth) {
this.mCalendar.set(Calendar.MONTH, this.mStartMonth);
this.mCalendar.set(Calendar.DAY_OF_MONTH, this.mStartDay);
}
if (month == mStartMonth && this.mCalendar.get(Calendar.DAY_OF_MONTH) < this.mStartDay) {
this.mCalendar.set(Calendar.DAY_OF_MONTH, this.mStartDay);
}
}

if (year == this.mMaxYear) {
if (month > mEndMonth) {
this.mCalendar.set(Calendar.MONTH, this.mEndMonth);
this.mCalendar.set(Calendar.DAY_OF_MONTH, this.mEndDay);
}
if (month == mEndMonth && this.mCalendar.get(Calendar.DAY_OF_MONTH) > this.mEndDay) {
this.mCalendar.set(Calendar.DAY_OF_MONTH, this.mEndDay);
}
}
adjustDayInMonthIfNeeded(month, year);

}

public DatePickerDialog() {
// Empty constructor required for dialog fragment. DO NOT REMOVE
Expand Down Expand Up @@ -218,6 +247,10 @@ public View onCreateView(LayoutInflater layoutInflater, ViewGroup parent, Bundle
this.mWeekStart = bundle.getInt("week_start");
this.mMinYear = bundle.getInt("year_start");
this.mMaxYear = bundle.getInt("year_end");
this.mStartMonth = bundle.getInt("month_start");
this.mEndMonth = bundle.getInt("month_end");
this.mStartDay = bundle.getInt("day_start");
this.mEndDay = bundle.getInt("day_end");
currentView = bundle.getInt("current_view");
listPosition = bundle.getInt("list_position");
listPositionOffset = bundle.getInt("list_position_offset");
Expand Down Expand Up @@ -279,6 +312,10 @@ public void onSaveInstanceState(Bundle bundle) {
bundle.putInt("week_start", this.mWeekStart);
bundle.putInt("year_start", this.mMinYear);
bundle.putInt("year_end", this.mMaxYear);
bundle.putInt("month_start", this.mStartMonth);
bundle.putInt("month_end", this.mEndMonth);
bundle.putInt("day_start", this.mStartDay);
bundle.putInt("day_end", this.mEndDay);
bundle.putInt("current_view", this.mCurrentView);
int mostVisiblePosition = -1;
if (this.mCurrentView == 0)
Expand All @@ -292,7 +329,7 @@ public void onSaveInstanceState(Bundle bundle) {
}

public void onYearSelected(int year) {
adjustDayInMonthIfNeeded(this.mCalendar.get(Calendar.MONTH), year);
adjustDayAndMonthIfNeeded(this.mCalendar.get(Calendar.MONTH), year);
this.mCalendar.set(Calendar.YEAR, year);
updatePickers();
setCurrentView(0);
Expand All @@ -316,8 +353,6 @@ public void setOnDateSetListener(OnDateSetListener onDateSetListener) {
}

public void setYearRange(int minYear, int maxYear) {
if (maxYear <= minYear)
throw new IllegalArgumentException("Year end must be larger than year start");
if (maxYear > MAX_YEAR)
throw new IllegalArgumentException("max year end must < " + MAX_YEAR);
if (minYear < MIN_YEAR)
Expand All @@ -327,7 +362,72 @@ public void setYearRange(int minYear, int maxYear) {
if (this.mDayPickerView != null)
this.mDayPickerView.onChange();
}


/**
* Sets the start date for the DatePickerDialog.
*
* @param startYear The minimum year.
* @param startMonth The first valid month of the startYear. This must be a valid Calendar.Month. (0-11). Default is 0.
* @param startDay The first valid day of startMont (inclusive). Default is 1.
*/
public void setStartDate(int startYear, int startMonth, int startDay) {
setDateRange(startYear, startMonth, startDay, mMaxYear, mEndMonth, mEndDay);
}

/**
* Sets the end date for the DatePickerDialog.
*
* @param endYear The maximum year.
* @param endMonth The last valid month of the endYear. This must be a valid Calendar.Month. (0-11). Default is 11.
* @param endDay THe last valid day of endMonth (inclusive). Default is 31.
*/
public void setEndDate(int endYear, int endMonth, int endDay) {
setDateRange(mMinYear, mStartMonth, mStartDay, endYear, endMonth, endDay);
}

/**
* Sets the time period for the DatePickerDialog.
*
* @param startYear The minimum year.
* @param startMonth The first valid month of the startYear. This must be a valid Calendar.Month. (0-11). Default is 0.
* @param startDay The first valid day of startMont (inclusive). Default is 1.
* @param endYear The maximum year.
* @param endMonth The last valid month of the endYear. This must be a valid Calendar.Month. (0-11). Default is 11.
* @param endDay THe last valid day of endMonth (inclusive). Default is 31.
*/
public void setDateRange(int startYear, int startMonth, int startDay, int endYear, int endMonth, int endDay) {
setYearRange(startYear, endYear);
if (startMonth >= 12 || startMonth < 0)
throw new IllegalArgumentException("startMonth must be between 0-11");
if (endMonth >= 12 || endMonth < 0)
throw new IllegalArgumentException("endMonth must be between 0-11");
this.mStartMonth = startMonth;
this.mStartDay = startDay;
this.mEndMonth = endMonth;
this.mEndDay = endDay;
}

@Override
public int getStartMonth() {
return this.mStartMonth;
}

@Override
public int getEndMonth() {
return this.mEndMonth;
}

@Override
public int getStartDay() {
return this.mStartDay;
}

@Override
public int getEndDay() {
return this.mEndDay;
}

public void tryVibrate() {
if (this.mVibrator != null && this.mVibrate) {
long timeInMillis = SystemClock.uptimeMillis();
Expand All @@ -345,4 +445,5 @@ static abstract interface OnDateChangedListener {
public static abstract interface OnDateSetListener {
public abstract void onDateSet(DatePickerDialog datePickerDialog, int year, int month, int day);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,13 @@ public int getMostVisiblePosition() {
}

public boolean goTo(SimpleMonthAdapter.CalendarDay calendarDay, boolean scrollToTop, boolean selectDay, boolean displayMonth) {
if (selectDay)
if (selectDay) {
this.mSelectedDay.set(calendarDay);
this.mAdapter.setSelectedDay(this.mSelectedDay);
}

this.mTempDay.set(calendarDay);
int monthIndex = 12 * (calendarDay.year - this.mController.getMinYear()) + calendarDay.month;
int monthIndex = 12 * (calendarDay.year - this.mController.getMinYear()) - this.mController.getStartMonth() + calendarDay.month;
postSetSelection(monthIndex);

// TODO improve
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ private boolean isSelectedDayInMonth(int year, int month) {
}

public int getCount() {
return 12 * (1 + (this.mController.getMaxYear() - this.mController.getMinYear()));
return 12 * (this.mController.getMaxYear() - this.mController.getMinYear())
+ this.mController.getEndMonth() - this.mController.getStartMonth() + 1;
}

public Object getItem(int position) {
Expand All @@ -54,17 +55,25 @@ public View getView(int position, View convertView, ViewGroup parent) {
if (monthParams == null)
monthParams = new HashMap<String, Integer>();
monthParams.clear();
int month = position % 12;
int year = position / 12 + this.mController.getMinYear();
int month = (position + this.mController.getStartMonth()) % 12;
int year = (position + this.mController.getStartMonth()) / 12 + this.mController.getMinYear();
Log.d("SimpleMonthAdapter", "Year: " + year + ", Month: " + month);
int selectedDay = -1;
if (isSelectedDayInMonth(year, month))
selectedDay = this.mSelectedDay.day;
int startDay = -1;
int endDay = 31;
if (this.mController.getStartMonth() == month && this.mController.getMinYear() == year)
startDay = this.mController.getStartDay();
if (this.mController.getEndMonth() == month && this.mController.getMaxYear() == year)
endDay = this.mController.getEndDay();
simpleMonthView.reuse();
monthParams.put("selected_day", Integer.valueOf(selectedDay));
monthParams.put("year", Integer.valueOf(year));
monthParams.put("month", Integer.valueOf(month));
monthParams.put("week_start", Integer.valueOf(this.mController.getFirstDayOfWeek()));
monthParams.put("start_day", Integer.valueOf(startDay));
monthParams.put("end_day", Integer.valueOf(endDay));
simpleMonthView.setMonthParams(monthParams);
simpleMonthView.invalidate();
return simpleMonthView;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ public class SimpleMonthView extends View {
protected int mWeekStart = 1;
protected int mWidth;
protected int mYear;
protected int mDayDisabledTextColor;
protected int mStartDay;
protected int mEndDay;
private DateFormatSymbols mDateFormatSymbols = new DateFormatSymbols();

public SimpleMonthView(Context context) {
Expand All @@ -73,6 +76,7 @@ public SimpleMonthView(Context context) {
this.mDayOfWeekTypeface = resources.getString(R.string.day_of_week_label_typeface);
this.mMonthTitleTypeface = resources.getString(R.string.sans_serif);
this.mDayTextColor = resources.getColor(R.color.date_picker_text_normal);
this.mDayDisabledTextColor = resources.getColor(R.color.date_picker_text_disabled);
this.mTodayNumberColor = resources.getColor(R.color.blue);
this.mMonthTitleColor = resources.getColor(R.color.white);
this.mMonthTitleBGColor = resources.getColor(R.color.circle_background);
Expand Down Expand Up @@ -149,8 +153,11 @@ protected void drawMonthNums(Canvas canvas) {
int x = paddingDay * (1 + dayOffset * 2) + this.mPadding;
if (this.mSelectedDay == day)
canvas.drawCircle(x, y - MINI_DAY_NUMBER_TEXT_SIZE / 3, DAY_SELECTED_CIRCLE_SIZE, this.mSelectedCirclePaint);

if ((this.mHasToday) && (this.mToday == day))
this.mMonthNumPaint.setColor(this.mTodayNumberColor);
else if (day < this.mStartDay || day > this.mEndDay)
this.mMonthNumPaint.setColor(this.mDayDisabledTextColor);
else
this.mMonthNumPaint.setColor(this.mDayTextColor);
canvas.drawText(String.format("%d", day), x, y, this.mMonthNumPaint);
Expand All @@ -171,7 +178,9 @@ public SimpleMonthAdapter.CalendarDay getDayFromLocation(float x, float y) {

int yDay = (int) (y - MONTH_HEADER_SIZE) / this.mRowHeight;
int day = 1 + ((int) ((x - padding) * this.mNumDays / (this.mWidth - padding - this.mPadding)) - findDayOffset()) + yDay * this.mNumDays;

// If day out of range
if (day < this.mStartDay || day > this.mEndDay)
return null;
return new SimpleMonthAdapter.CalendarDay(this.mYear, this.mMonth, day);
}

Expand Down Expand Up @@ -254,6 +263,8 @@ public void setMonthParams(HashMap<String, Integer> monthParams) {
this.mSelectedDay = ((Integer) monthParams.get("selected_day")).intValue();
this.mMonth = ((Integer) monthParams.get("month")).intValue();
this.mYear = ((Integer) monthParams.get("year")).intValue();
this.mStartDay = ((Integer) monthParams.get("start_day")).intValue();
this.mEndDay = ((Integer) monthParams.get("end_day")).intValue();
Time time = new Time(Time.getCurrentTimezone());
time.setToNow();
this.mHasToday = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Service;
import android.content.Context;
import android.content.res.Resources;
Expand Down Expand Up @@ -94,6 +95,8 @@ public class RadialPickerLayout extends FrameLayout implements OnTouchListener {
private AnimatorSet mTransition;
private Handler mHandler = new Handler();

private int mMinutesInterval = 1;

public interface OnValueSelectedListener {
void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance);
}
Expand Down Expand Up @@ -171,7 +174,7 @@ public void setOnValueSelectedListener(OnValueSelectedListener listener) {
* @param is24HourMode
*/
public void initialize(Context context, int initialHoursOfDay, int initialMinutes,
boolean is24HourMode, boolean vibrate) {
boolean is24HourMode, boolean vibrate, int minutesInterval) {
if (mTimeInitialized) {
Log.e(TAG, "Time has already been initialized.");
return;
Expand Down Expand Up @@ -203,10 +206,17 @@ public void initialize(Context context, int initialHoursOfDay, int initialMinute
innerHoursTexts[i] = String.format("%d", hours[i]);
minutesTexts[i] = String.format("%02d", minutes[i]);
}

mMinutesInterval = minutesInterval;
boolean[] minutesEnabled = new boolean[12];
for (int i = 0; i < 12; i++) {
minutesEnabled[i] = (i*5 % minutesInterval == 0);
}

mHourRadialTextsView.initialize(res,
hoursTexts, (is24HourMode ? innerHoursTexts : null), mHideAmPm, true);
hoursTexts, (is24HourMode ? innerHoursTexts : null), null, mHideAmPm, true);
mHourRadialTextsView.invalidate();
mMinuteRadialTextsView.initialize(res, minutesTexts, null, mHideAmPm, false);
mMinuteRadialTextsView.initialize(res, minutesTexts, null, minutesEnabled, mHideAmPm, false);
mMinuteRadialTextsView.invalidate();

// Initialize the currently-selected hour and minute.
Expand Down Expand Up @@ -374,6 +384,20 @@ private void preparePrefer30sMap() {
}
}

/**
* Snaps to the nearest valid minute value.
*/
private int snapValid(int degrees) {
int stepSize = 360 / (60 / mMinutesInterval);
int floor = (degrees/stepSize) * stepSize;
int ceiling = floor + stepSize;
if ((degrees - floor) < (ceiling - degrees)) {
return floor;
} else {
return ceiling;
}
}

/**
* Returns mapping of any input degrees (0 to 360) to one of 60 selectable output degrees,
* where the degrees corresponding to visible numbers (i.e. those divisible by 30) will be
Expand Down Expand Up @@ -442,7 +466,10 @@ private int reselectSelector(int degrees, boolean isInnerCircle,

int stepSize;
boolean allowFineGrained = !forceToVisibleValue && (currentShowing == MINUTE_INDEX);
if (allowFineGrained) {
// Check if we have a minute interval
if (currentShowing == MINUTE_INDEX && mMinutesInterval != 1) {
degrees = snapValid(degrees);
} else if (allowFineGrained) {
degrees = snapPrefer30s(degrees);
} else {
degrees = snapOnly30s(degrees, 0);
Expand Down Expand Up @@ -773,6 +800,7 @@ public boolean trySettingInputEnabled(boolean inputEnabled) {
* Necessary for accessibility, to ensure we support "scrolling" forward and backward
* in the circle.
*/
@TargetApi(14)
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
if (Build.VERSION.SDK_INT >= 14) {
super.onInitializeAccessibilityNodeInfo(info);
Expand Down
Loading