diff --git a/README.md b/README.md
index e26c432..687d7c6 100644
--- a/README.md
+++ b/README.md
@@ -66,7 +66,7 @@ The mode of the date picker.
Type: String
-Values: `date` | `time` | `datetime` (iOS, Windows only)
+Values: `date` | `time` | `datetime` (iOS, Windows only) | `duration` (iOS, Android only)
Default: `date`
@@ -213,6 +213,13 @@ Type: Integer
Default: `1`
+### countDownDuration - iOS
+Represents the displayed duration in seconds.
+
+Type: Integer
+
+Default: `0`
+
### popoverArrowDirection - iOS
Force the UIPopoverArrowDirection enum.
The value `any` will revert to default `UIPopoverArrowDirectionAny` and let the app choose the proper direction itself.
diff --git a/plugin.xml b/plugin.xml
index 3a23c2c..1db8b11 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -28,6 +28,7 @@
+
diff --git a/src/android/CustomTimePickerDialog.java b/src/android/CustomTimePickerDialog.java
new file mode 100644
index 0000000..d9e4804
--- /dev/null
+++ b/src/android/CustomTimePickerDialog.java
@@ -0,0 +1,128 @@
+package com.plugin.datepicker;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.TimePickerDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.widget.NumberPicker;
+import android.widget.TimePicker;
+import android.os.Bundle;
+
+public class CustomTimePickerDialog extends TimePickerDialog {
+
+ final OnTimeSetListener mCallback;
+ TimePicker mTimePicker;
+ final int increment;
+ final int theme;
+ private int minHour = 0;
+ private int maxHour = 24;
+ private int minMinute = 0;
+ private int maxMinute = 60;
+
+ public int getMinHour() {
+ return minHour;
+ }
+
+ public void setMinHour(int minHour) {
+ this.minHour = minHour;
+ }
+
+ public void setMaxHour(int maxHour) {
+ this.maxHour = maxHour;
+ }
+
+ public void setMinMinute(int minMinute) {
+ this.minMinute = minMinute;
+ }
+
+ public void setMaxMinute(int maxMinute) {
+ this.maxMinute = maxMinute;
+ }
+
+ public CustomTimePickerDialog(Context context, int theme, OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView, int increment)
+ {
+ super(context, theme, callBack, hourOfDay, minute/increment, is24HourView);
+ this.mCallback = callBack;
+ this.increment = increment;
+ this.theme = theme;
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (mCallback != null && mTimePicker!=null) {
+ mTimePicker.clearFocus();
+ int minutes = theme != 2 ? mTimePicker.getCurrentMinute(): mTimePicker.getCurrentMinute()*increment;
+ mCallback.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
+ minutes);
+ }
+ }
+
+ @Override
+ public void updateTime(int hourOfDay, int minuteOfHour) {
+ mTimePicker.setCurrentHour(hourOfDay);
+ mTimePicker.setCurrentMinute((minuteOfHour-minMinute)/increment);
+ }
+
+ public void updateTimeClock(int hourOfDay, int minuteOfHour) {
+ if(minuteOfHour == maxMinute){
+ minuteOfHour = 0;
+ }
+ mTimePicker.setCurrentHour(hourOfDay);
+ mTimePicker.setCurrentMinute(minuteOfHour);
+ }
+
+ @Override
+ protected void onStop()
+ {
+ // override and do nothing
+ }
+
+ private void setHourSpinner(TimePicker timePicker, Field hour) throws IllegalAccessException{
+ NumberPicker mHourSpinner = (NumberPicker)timePicker.findViewById(hour.getInt(null));
+ mHourSpinner.setMinValue(minHour);
+ mHourSpinner.setMaxValue(maxHour-1);
+ List displayedHoursValues = new ArrayList();
+ for(int i=minHour;i displayedMinutesValues = new ArrayList();
+ for(int i=newMin;i rClass = Class.forName("com.android.internal.R$id");
+ Field timePicker = rClass.getField("timePicker");
+ this.mTimePicker = (TimePicker)findViewById(timePicker.getInt(null));
+ Field m = rClass.getField("minute");
+ Field h = rClass.getField("hour");
+
+ setHourSpinner(this.mTimePicker, h);
+ setMinuteSpinner(this.mTimePicker, m);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/android/DatePickerPlugin.java b/src/android/DatePickerPlugin.java
index b76edcc..e3e0860 100644
--- a/src/android/DatePickerPlugin.java
+++ b/src/android/DatePickerPlugin.java
@@ -16,7 +16,6 @@
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;
-import java.util.Random;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
@@ -27,7 +26,6 @@
import android.annotation.SuppressLint;
import android.app.DatePickerDialog;
import android.app.DatePickerDialog.OnDateSetListener;
-import android.app.TimePickerDialog;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.content.Context;
import android.content.DialogInterface;
@@ -42,10 +40,11 @@ public class DatePickerPlugin extends CordovaPlugin {
private static final String ACTION_DATE = "date";
private static final String ACTION_TIME = "time";
+ private static final String ACTION_DURATION = "duration";
private static final String RESULT_ERROR = "error";
private static final String RESULT_CANCEL = "cancel";
private final String pluginName = "DatePickerPlugin";
-
+
// On some devices, onDateSet or onTimeSet are being called twice
private boolean called = false;
private boolean canceled = false;
@@ -68,12 +67,13 @@ public synchronized void show(final JSONArray data, final CallbackContext callba
Context currentCtx = cordova.getActivity();
Runnable runnable;
JsonDate jsonDate = new JsonDate().fromJson(data);
-
- // Retrieve Android theme
- JSONObject options = data.optJSONObject(0);
- int theme = options.optInt("androidTheme", 1);
- if (ACTION_TIME.equalsIgnoreCase(jsonDate.action)) {
+ // Retrieve Android theme
+ JSONObject options = data.optJSONObject(0);
+ int theme = options.optInt("androidTheme", 1);
+
+ if (ACTION_TIME.equalsIgnoreCase(jsonDate.action) ||
+ ACTION_DURATION.equalsIgnoreCase(jsonDate.action)) {
runnable = runnableTimeDialog(datePickerPlugin, theme, currentCtx,
callbackContext, jsonDate, Calendar.getInstance(TimeZone.getDefault()));
@@ -83,30 +83,36 @@ public synchronized void show(final JSONArray data, final CallbackContext callba
cordova.getActivity().runOnUiThread(runnable);
}
-
+
private TimePicker timePicker;
private int timePickerHour = 0;
private int timePickerMinute = 0;
-
+
private Runnable runnableTimeDialog(final DatePickerPlugin datePickerPlugin,
- final int theme, final Context currentCtx, final CallbackContext callbackContext,
- final JsonDate jsonDate, final Calendar calendarDate) {
+ final int theme, final Context currentCtx, final CallbackContext callbackContext,
+ final JsonDate jsonDate, final Calendar calendarDate) {
return new Runnable() {
@Override
public void run() {
final TimeSetListener timeSetListener = new TimeSetListener(datePickerPlugin, callbackContext, calendarDate);
- final TimePickerDialog timeDialog = new TimePickerDialog(currentCtx, theme, timeSetListener, jsonDate.hour,
- jsonDate.minutes, jsonDate.is24Hour) {
+ final CustomTimePickerDialog timeDialog = new CustomTimePickerDialog(currentCtx, theme, timeSetListener, jsonDate.hour,
+ jsonDate.minutes, jsonDate.is24Hour, jsonDate.minuteInterval) {
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
timePicker = view;
timePickerHour = hourOfDay;
- timePickerMinute = minute;
+ if(theme != 2){
+ int offset = minute%jsonDate.minuteInterval != 0 ? jsonDate.minuteInterval: 0;
+ timePickerMinute = (minute/jsonDate.minuteInterval)*jsonDate.minuteInterval + offset;
+ updateTimeClock(timePickerHour, timePickerMinute);
+ } else {
+ timePickerMinute = minute;
+ }
}
};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
timeDialog.setCancelable(true);
timeDialog.setCanceledOnTouchOutside(false);
-
+
if (!jsonDate.titleText.isEmpty()){
timeDialog.setTitle(jsonDate.titleText);
}
@@ -120,8 +126,8 @@ public void onClick(DialogInterface dialog, int which) {
}
}
});
- }
- String labelCancel = jsonDate.cancelText.isEmpty() ? currentCtx.getString(android.R.string.cancel) : jsonDate.cancelText;
+ }
+ String labelCancel = jsonDate.cancelText.isEmpty() ? currentCtx.getString(android.R.string.cancel) : jsonDate.cancelText;
timeDialog.setButton(DialogInterface.BUTTON_NEGATIVE, labelCancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
@@ -132,13 +138,30 @@ public void onClick(DialogInterface dialog, int which) {
String labelOk = jsonDate.okText.isEmpty() ? currentCtx.getString(android.R.string.ok) : jsonDate.okText;
timeDialog.setButton(DialogInterface.BUTTON_POSITIVE, labelOk, timeDialog);
}
+
+ Calendar todayDate = calendarDate.getInstance();
+ todayDate.set(Calendar.MINUTE, 0);
+ todayDate.set(Calendar.SECOND, 0);
+ todayDate.set(Calendar.MILLISECOND, 0);
+
+ calendarDate.set(Calendar.MINUTE, 0);
+ calendarDate.set(Calendar.SECOND, 0);
+ calendarDate.set(Calendar.MILLISECOND, 0);
+
+ if (todayDate.getTime().compareTo(calendarDate.getTime()) == 0 &&
+ !ACTION_DURATION.equalsIgnoreCase(jsonDate.action))
+ {
+ timeDialog.setMinHour(calendarDate.get(Calendar.HOUR_OF_DAY));
+ } else {
+ timeDialog.setMinHour(0);
+ }
+
timeDialog.show();
- timeDialog.updateTime(new Random().nextInt(23), new Random().nextInt(59));
timeDialog.updateTime(jsonDate.hour, jsonDate.minutes);
}
};
}
-
+
private Runnable runnableDatePicker(
final DatePickerPlugin datePickerPlugin,
final int theme, final Context currentCtx,
@@ -155,58 +178,72 @@ public void run() {
else {
prepareDialogPreHoneycomb(dateDialog, callbackContext, currentCtx, jsonDate);
}
-
+
dateDialog.show();
}
};
}
-
- private void prepareDialog(final DatePickerDialog dateDialog, final OnDateSetListener dateListener,
- final CallbackContext callbackContext, Context currentCtx, JsonDate jsonDate) {
+
+ private void prepareDialog(final DatePickerDialog dateDialog, final OnDateSetListener dateListener,
+ final CallbackContext callbackContext, Context currentCtx, JsonDate jsonDate) {
dateDialog.setCancelable(true);
dateDialog.setCanceledOnTouchOutside(false);
if (!jsonDate.titleText.isEmpty()){
dateDialog.setTitle(jsonDate.titleText);
}
if (!jsonDate.todayText.isEmpty()){
- dateDialog.setButton(DialogInterface.BUTTON_NEUTRAL, jsonDate.todayText, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- Calendar now = Calendar.getInstance();
- DatePicker datePicker = dateDialog.getDatePicker();
+ dateDialog.setButton(DialogInterface.BUTTON_NEUTRAL, jsonDate.todayText, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Calendar now = Calendar.getInstance();
+ DatePicker datePicker = dateDialog.getDatePicker();
dateListener.onDateSet(datePicker, now.get(Calendar.YEAR), now.get(Calendar.MONTH), now.get(Calendar.DAY_OF_MONTH));
- }
- });
- }
- String labelCancel = jsonDate.cancelText.isEmpty() ? currentCtx.getString(android.R.string.cancel) : jsonDate.cancelText;
+ }
+ });
+ }
+ String labelCancel = jsonDate.cancelText.isEmpty() ? currentCtx.getString(android.R.string.cancel) : jsonDate.cancelText;
dateDialog.setButton(DialogInterface.BUTTON_NEGATIVE, labelCancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
canceled = true;
callbackContext.error(RESULT_CANCEL);
- }
- });
+ }
+ });
String labelOk = jsonDate.okText.isEmpty() ? currentCtx.getString(android.R.string.ok) : jsonDate.okText;
dateDialog.setButton(DialogInterface.BUTTON_POSITIVE, labelOk, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
DatePicker datePicker = dateDialog.getDatePicker();
datePicker.clearFocus();
dateListener.onDateSet(datePicker, datePicker.getYear(), datePicker.getMonth(), datePicker.getDayOfMonth());
- }
- });
-
- DatePicker dp = dateDialog.getDatePicker();
+ }
+ });
+
+ DatePicker dp = dateDialog.getDatePicker();
if(jsonDate.minDate > 0) {
- dp.setMinDate(jsonDate.minDate);
+ final Calendar minDate = Calendar.getInstance();
+ minDate.setTimeInMillis(jsonDate.minDate);
+ minDate.set(Calendar.HOUR_OF_DAY, minDate.getMinimum(Calendar.HOUR_OF_DAY));
+ minDate.set(Calendar.MINUTE, minDate.getMinimum(Calendar.MINUTE));
+ minDate.set(Calendar.SECOND, minDate.getMinimum(Calendar.SECOND));
+ minDate.set(Calendar.MILLISECOND, minDate.getMinimum(Calendar.MILLISECOND));
+
+ dp.setMinDate(minDate.getTimeInMillis());
}
if(jsonDate.maxDate > 0 && jsonDate.maxDate > jsonDate.minDate) {
- dp.setMaxDate(jsonDate.maxDate);
+ final Calendar maxDate = Calendar.getInstance();
+ maxDate.setTimeInMillis(jsonDate.maxDate);
+ maxDate.set(Calendar.HOUR_OF_DAY, maxDate.getMaximum(Calendar.HOUR_OF_DAY));
+ maxDate.set(Calendar.MINUTE, maxDate.getMaximum(Calendar.MINUTE));
+ maxDate.set(Calendar.SECOND, maxDate.getMaximum(Calendar.SECOND));
+ maxDate.set(Calendar.MILLISECOND, maxDate.getMaximum(Calendar.MILLISECOND));
+
+ dp.setMaxDate(maxDate.getTimeInMillis());
}
}
-
+
private void prepareDialogPreHoneycomb(DatePickerDialog dateDialog,
- final CallbackContext callbackContext, Context currentCtx, final JsonDate jsonDate){
+ final CallbackContext callbackContext, Context currentCtx, final JsonDate jsonDate){
java.lang.reflect.Field mDatePickerField = null;
try {
mDatePickerField = dateDialog.getClass().getDeclaredField("mDatePicker");
@@ -229,28 +266,28 @@ private void prepareDialogPreHoneycomb(DatePickerDialog dateDialog,
endDate.setTimeInMillis(jsonDate.maxDate);
final int minYear = startDate.get(Calendar.YEAR);
- final int minMonth = startDate.get(Calendar.MONTH);
- final int minDay = startDate.get(Calendar.DAY_OF_MONTH);
- final int maxYear = endDate.get(Calendar.YEAR);
- final int maxMonth = endDate.get(Calendar.MONTH);
- final int maxDay = endDate.get(Calendar.DAY_OF_MONTH);
+ final int minMonth = startDate.get(Calendar.MONTH);
+ final int minDay = startDate.get(Calendar.DAY_OF_MONTH);
+ final int maxYear = endDate.get(Calendar.YEAR);
+ final int maxMonth = endDate.get(Calendar.MONTH);
+ final int maxDay = endDate.get(Calendar.DAY_OF_MONTH);
if(startDate !=null || endDate != null) {
pickerView.init(jsonDate.year, jsonDate.month, jsonDate.day, new OnDateChangedListener() {
- @Override
+ @Override
public void onDateChanged(DatePicker view, int year, int month, int day) {
- if(jsonDate.maxDate > 0 && jsonDate.maxDate > jsonDate.minDate) {
- if(year > maxYear || month > maxMonth && year == maxYear || day > maxDay && year == maxYear && month == maxMonth){
- view.updateDate(maxYear, maxMonth, maxDay);
- }
- }
- if(jsonDate.minDate > 0) {
- if(year < minYear || month < minMonth && year == minYear || day < minDay && year == minYear && month == minMonth) {
- view.updateDate(minYear, minMonth, minDay);
- }
- }
- }
- });
+ if(jsonDate.maxDate > 0 && jsonDate.maxDate > jsonDate.minDate) {
+ if(year > maxYear || month > maxMonth && year == maxYear || day > maxDay && year == maxYear && month == maxMonth){
+ view.updateDate(maxYear, maxMonth, maxDay);
+ }
+ }
+ if(jsonDate.minDate > 0) {
+ if(year < minYear || month < minMonth && year == minYear || day < minDay && year == minYear && month == minMonth) {
+ view.updateDate(minYear, minMonth, minDay);
+ }
+ }
+ }
+ });
}
}
@@ -264,7 +301,7 @@ private DateSetListener(DatePickerPlugin datePickerPlugin, int theme, CallbackCo
this.datePickerPlugin = datePickerPlugin;
this.callbackContext = callbackContext;
this.jsonDate = jsonDate;
- this.theme = theme;
+ this.theme = theme;
}
/**
@@ -277,24 +314,24 @@ public void onDateSet(final DatePicker view, final int year, final int monthOfYe
}
called = true;
canceled = false;
-
+
Log.d("onDateSet", "called: " + called);
Log.d("onDateSet", "canceled: " + canceled);
Log.d("onDateSet", "mode: " + jsonDate.action);
-
+
if (ACTION_DATE.equalsIgnoreCase(jsonDate.action)) {
String returnDate = year + "/" + (monthOfYear + 1) + "/" + dayOfMonth;
Log.d("onDateSet", "returnDate: " + returnDate);
-
+
callbackContext.success(returnDate);
-
+
} else {
// Open time dialog
Calendar selectedDate = Calendar.getInstance();
selectedDate.set(Calendar.YEAR, year);
selectedDate.set(Calendar.MONTH, monthOfYear);
selectedDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
-
+
cordova.getActivity().runOnUiThread(runnableTimeDialog(datePickerPlugin, theme, cordova.getActivity(),
callbackContext, jsonDate, selectedDate));
}
@@ -319,7 +356,7 @@ public void onTimeSet(final TimePicker view, final int hourOfDay, final int minu
if (canceled) {
return;
}
-
+
calendarDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
calendarDate.set(Calendar.MINUTE, minute);
calendarDate.set(Calendar.SECOND, 0);
@@ -331,9 +368,9 @@ public void onTimeSet(final TimePicker view, final int hourOfDay, final int minu
callbackContext.success(toReturn);
}
}
-
+
private final class JsonDate {
-
+
private String action = ACTION_DATE;
private String titleText = "";
private String okText = "";
@@ -348,6 +385,7 @@ private final class JsonDate {
private int hour = 0;
private int minutes = 0;
private boolean is24Hour = false;
+ private int minuteInterval = 1;
public JsonDate() {
reset(Calendar.getInstance());
@@ -380,6 +418,8 @@ public JsonDate fromJson(JSONArray data) {
: "";
is24Hour = isNotEmpty(obj, "is24Hour") ? obj.getBoolean("is24Hour")
: false;
+ minuteInterval = isNotEmpty(obj, "minuteInterval") ? obj.getInt("minuteInterval")
+ : 1;
String optionDate = obj.getString("date");
@@ -403,7 +443,7 @@ public boolean isNotEmpty(JSONObject object, String key)
&& !object.isNull(key)
&& object.get(key).toString().length() > 0
&& !JSONObject.NULL.toString().equals(
- object.get(key).toString());
+ object.get(key).toString());
}
}
diff --git a/src/ios/DatePicker.h b/src/ios/DatePicker.h
index 24077fa..57387de 100644
--- a/src/ios/DatePicker.h
+++ b/src/ios/DatePicker.h
@@ -18,4 +18,4 @@
- (void)show:(CDVInvokedUrlCommand*)command;
-@end
\ No newline at end of file
+@end
diff --git a/src/ios/DatePicker.m b/src/ios/DatePicker.m
index caae145..4e10f48 100644
--- a/src/ios/DatePicker.m
+++ b/src/ios/DatePicker.m
@@ -216,6 +216,8 @@ - (void)updateDatePicker:(NSMutableDictionary *)options {
NSString *maxDateString = [options objectForKey:@"maxDate"];
NSString *minuteIntervalString = [options objectForKey:@"minuteInterval"];
NSInteger minuteInterval = [minuteIntervalString integerValue];
+ NSString *countDownDurationString = [options objectForKey:@"countDownDuration"];
+ NSInteger countDownDuration = [countDownDurationString integerValue];
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:[options objectForKey:@"locale"]];
@@ -248,6 +250,9 @@ - (void)updateDatePicker:(NSMutableDictionary *)options {
}
else if ([mode isEqualToString:@"time"]) {
self.datePicker.datePickerMode = UIDatePickerModeTime;
+ }
+ else if ([mode isEqualToString:@"duration"]) {
+ self.datePicker.datePickerMode = UIDatePickerModeCountDownTimer;
} else {
self.datePicker.datePickerMode = UIDatePickerModeDateAndTime;
}
@@ -256,6 +261,10 @@ - (void)updateDatePicker:(NSMutableDictionary *)options {
self.datePicker.minuteInterval = minuteInterval;
}
+ if (countDownDuration) {
+ self.datePicker.countDownDuration = countDownDuration;
+ }
+
if (locale) {
[self.datePicker setLocale:locale];
}
diff --git a/www/android/DatePicker.js b/www/android/DatePicker.js
index 3ba4c22..ed71a95 100644
--- a/www/android/DatePicker.js
+++ b/www/android/DatePicker.js
@@ -45,6 +45,7 @@ DatePicker.prototype.show = function(options, cb, errCb) {
todayText: '',
nowText: '',
is24Hour: false,
+ minuteInterval: 1,
androidTheme : window.datePicker.ANDROID_THEMES.THEME_TRADITIONAL, // Default theme
};
diff --git a/www/ios/DatePicker.js b/www/ios/DatePicker.js
index a09a9b2..9a47fb6 100644
--- a/www/ios/DatePicker.js
+++ b/www/ios/DatePicker.js
@@ -92,6 +92,7 @@ DatePicker.prototype.show = function(options, cb) {
x: '0',
y: '0',
minuteInterval: 1,
+ countDownDuration: 0,
popoverArrowDirection: this._popoverArrowDirectionIntegerFromString("any"),
locale: "en_US"
};