From a1e3477bb477b1a7c5f3e6e201de56aeb30b7003 Mon Sep 17 00:00:00 2001 From: Henning Hall Date: Wed, 29 Aug 2018 23:21:44 +0200 Subject: [PATCH] Date mode WIP: Year fixes. Date mode. --- .../date_picker/DatePickerManager.java | 5 +- .../henninghall/date_picker/PickerView.java | 59 ++++-- .../com/henninghall/date_picker/Utils.java | 17 ++ .../date_picker/WheelOrderUpdater.java | 66 +++++++ .../date_picker/wheelFunctions/Refresh.java | 12 +- .../date_picker/wheels/AmPmWheel.java | 4 +- .../date_picker/wheels/DateWheel.java | 39 ++++ .../date_picker/wheels/DayWheel.java | 4 +- .../date_picker/wheels/HourWheel.java | 4 +- .../date_picker/wheels/MinutesWheel.java | 4 +- .../date_picker/wheels/MonthWheel.java | 39 ++++ .../henninghall/date_picker/wheels/Wheel.java | 10 +- .../date_picker/wheels/YearWheel.java | 63 ++++++ .../src/main/res/layout/datepicker_view.xml | 42 ++++ example/android/build.gradle | 3 +- .../gradle/wrapper/gradle-wrapper.properties | 4 +- example/src/exampleKeys.js | 1 + example/src/examples.js | 5 + example/src/examples/Advanced.js | 2 +- example/src/examples/DateMode.js | 17 ++ temp/DatePickerManager.java | 82 ++++++++ temp/DateWheel.java | 38 ++++ temp/Mode.java | 9 + temp/MonthWheel.java | 38 ++++ temp/PickerView.java | 184 ++++++++++++++++++ temp/Wheel.java | 100 ++++++++++ temp/WheelOrderUpdater.java | 56 ++++++ temp/YearWheel.java | 58 ++++++ 28 files changed, 927 insertions(+), 38 deletions(-) create mode 100644 android/src/main/java/com/henninghall/date_picker/WheelOrderUpdater.java create mode 100644 android/src/main/java/com/henninghall/date_picker/wheels/DateWheel.java create mode 100644 android/src/main/java/com/henninghall/date_picker/wheels/MonthWheel.java create mode 100644 android/src/main/java/com/henninghall/date_picker/wheels/YearWheel.java create mode 100644 example/src/examples/DateMode.js create mode 100644 temp/DatePickerManager.java create mode 100644 temp/DateWheel.java create mode 100644 temp/Mode.java create mode 100644 temp/MonthWheel.java create mode 100644 temp/PickerView.java create mode 100644 temp/Wheel.java create mode 100644 temp/WheelOrderUpdater.java create mode 100644 temp/YearWheel.java diff --git a/android/src/main/java/com/henninghall/date_picker/DatePickerManager.java b/android/src/main/java/com/henninghall/date_picker/DatePickerManager.java index 748daaf..d095863 100644 --- a/android/src/main/java/com/henninghall/date_picker/DatePickerManager.java +++ b/android/src/main/java/com/henninghall/date_picker/DatePickerManager.java @@ -33,12 +33,13 @@ public class DatePickerManager extends SimpleViewManager { @ReactProp(name = "mode") public void setMode(PickerView view, @Nullable String mode) { + Mode m; try { - view.setMode(Mode.valueOf(mode)); + m = Mode.valueOf(mode); } catch (Exception e) { throw new IllegalArgumentException("Invalid mode. Valid modes: 'datetime', 'date', 'time'"); } - + view.setMode(m); } @ReactProp(name = "date") diff --git a/android/src/main/java/com/henninghall/date_picker/PickerView.java b/android/src/main/java/com/henninghall/date_picker/PickerView.java index 5ae203f..156946b 100644 --- a/android/src/main/java/com/henninghall/date_picker/PickerView.java +++ b/android/src/main/java/com/henninghall/date_picker/PickerView.java @@ -11,10 +11,13 @@ import com.henninghall.date_picker.wheelFunctions.Refresh; import com.henninghall.date_picker.wheelFunctions.SetDate; import com.henninghall.date_picker.wheelFunctions.WheelFunction; import com.henninghall.date_picker.wheels.AmPmWheel; +import com.henninghall.date_picker.wheels.DateWheel; import com.henninghall.date_picker.wheels.DayWheel; import com.henninghall.date_picker.wheels.HourWheel; import com.henninghall.date_picker.wheels.MinutesWheel; +import com.henninghall.date_picker.wheels.MonthWheel; import com.henninghall.date_picker.wheels.Wheel; +import com.henninghall.date_picker.wheels.YearWheel; import org.apache.commons.lang3.time.DateUtils; @@ -33,41 +36,41 @@ import cn.carbswang.android.numberpickerview.library.NumberPickerView; public class PickerView extends RelativeLayout { - private final NumberPickerView hourPicker; - private final NumberPickerView ampmPicker; private SimpleDateFormat dateFormat; private HourWheel hourWheel; private DayWheel dayWheel; public MinutesWheel minutesWheel; private AmPmWheel ampmWheel; - private Date minDate; - private Date maxDate; public int minuteInterval = 1; public Locale locale; public Mode mode; public Style style; + public DateWheel dateWheel; + public MonthWheel monthWheel; + public YearWheel yearWheel; + public Date maxDate; + public Date minDate; + private WheelOrderUpdater wheelOrderUpdater; public PickerView() { super(DatePickerManager.context); View rootView = inflate(getContext(), R.layout.datepicker_view, this); this.style = new Style(this); + this.wheelOrderUpdater = new WheelOrderUpdater(this); RelativeLayout wheelsWrapper = (RelativeLayout) rootView.findViewById(R.id.wheelsWrapper); wheelsWrapper.setWillNotDraw(false); locale = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP ? Locale.forLanguageTag("en") : Locale.getDefault(); - NumberPickerView dayPicker = (NumberPickerView) rootView.findViewById(R.id.day); - dayWheel = new DayWheel(dayPicker, this); + yearWheel = new YearWheel( this, R.id.year); + monthWheel = new MonthWheel( this, R.id.month); + dateWheel = new DateWheel( this, R.id.date); - NumberPickerView minutePicker = (NumberPickerView) rootView.findViewById(R.id.minutes); - minutesWheel = new MinutesWheel(minutePicker, this); - - ampmPicker = (NumberPickerView) rootView.findViewById(R.id.ampm); - ampmWheel = new AmPmWheel(ampmPicker, this); - - hourPicker = (NumberPickerView) rootView.findViewById(R.id.hour); - hourWheel = new HourWheel(hourPicker,this); + dayWheel = new DayWheel( this, R.id.day); + minutesWheel = new MinutesWheel( this, R.id.minutes); + ampmWheel = new AmPmWheel(this, R.id.ampm); + hourWheel = new HourWheel(this, R.id.hour); dateFormat = new SimpleDateFormat(getDateFormatTemplate(), Locale.US); changeAmPmWhenPassingMidnightOrNoon(); @@ -78,6 +81,9 @@ public class PickerView extends RelativeLayout { public void onChange(Wheel wheel) { WritableMap event = Arguments.createMap(); try { + String pattern = dateFormat.toPattern(); + String dateString = getDateString(); + Date date = dateFormat.parse(getDateString()); if (minDate != null && date.before(minDate)) applyOnVisibleWheels(new AnimateToDate(minDate)); else if (maxDate != null && date.after(maxDate)) applyOnVisibleWheels(new AnimateToDate(maxDate)); @@ -102,14 +108,14 @@ public class PickerView extends RelativeLayout { }; private void changeAmPmWhenPassingMidnightOrNoon(){ - hourPicker.setOnValueChangeListenerInScrolling(new NumberPickerView.OnValueChangeListenerInScrolling() { + hourWheel.picker.setOnValueChangeListenerInScrolling(new NumberPickerView.OnValueChangeListenerInScrolling() { @Override public void onValueChangeInScrolling(NumberPickerView picker, int oldVal, int newVal) { if(Utils.usesAmPm(locale)){ String oldValue = hourWheel.getValueAtIndex(oldVal); String newValue = hourWheel.getValueAtIndex(newVal); boolean passingNoonOrMidnight = (oldValue.equals("12") && newValue.equals("11")) || oldValue.equals("11") && newValue.equals("12"); - if (passingNoonOrMidnight) ampmPicker.smoothScrollToValue((ampmPicker.getValue() + 1) % 2,false); + if (passingNoonOrMidnight) ampmWheel.picker.smoothScrollToValue((ampmWheel.picker.getValue() + 1) % 2,false); } } }); @@ -130,6 +136,7 @@ public class PickerView extends RelativeLayout { public void setLocale(Locale locale) { this.locale = locale; dateFormat = new SimpleDateFormat(getDateFormatTemplate(), Locale.US); + wheelOrderUpdater.update(locale, mode); applyOnAllWheels(new Refresh()); } @@ -153,14 +160,24 @@ public class PickerView extends RelativeLayout { } private String getDateFormatTemplate() { - return dayWheel.getFormatTemplate() + " " + String dateTemplate = (mode == Mode.date) + ? (yearWheel.getFormatTemplate() + " " + + monthWheel.getFormatTemplate() + " " + + dateWheel.getFormatTemplate()) + : dayWheel.getFormatTemplate(); + return dateTemplate + " " + hourWheel.getFormatTemplate() + " " + minutesWheel.getFormatTemplate() + ampmWheel.getFormatTemplate(); } private String getDateString() { - return dayWheel.getValue() + String dateString= (mode == Mode.date) + ? (yearWheel.getValue() + " " + + monthWheel.getValue() + " " + + dateWheel.getValue()) + : dayWheel.getValue(); + return dateString + " " + hourWheel.getValue() + " " + minutesWheel.getValue() + ampmWheel.getValue(); @@ -168,7 +185,9 @@ public class PickerView extends RelativeLayout { public void setMode(Mode mode) { this.mode = mode; - applyOnAllWheels(new Refresh()); + dateFormat = new SimpleDateFormat(getDateFormatTemplate(), Locale.US); + applyOnAllWheels(new Refresh(false)); + wheelOrderUpdater.update(locale, mode); } public Collection getVisibleWheels() { @@ -178,7 +197,7 @@ public class PickerView extends RelativeLayout { } public List getAllWheels(){ - return new ArrayList<>(Arrays.asList(dayWheel, hourWheel, minutesWheel, ampmWheel)); + return new ArrayList<>(Arrays.asList(yearWheel, monthWheel, dateWheel, dayWheel, hourWheel, minutesWheel, ampmWheel)); } public void applyOnAllWheels(WheelFunction function) { diff --git a/android/src/main/java/com/henninghall/date_picker/Utils.java b/android/src/main/java/com/henninghall/date_picker/Utils.java index 9868eca..a38b082 100644 --- a/android/src/main/java/com/henninghall/date_picker/Utils.java +++ b/android/src/main/java/com/henninghall/date_picker/Utils.java @@ -1,6 +1,9 @@ package com.henninghall.date_picker; +import android.util.TypedValue; +import android.view.View; + import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; @@ -21,4 +24,18 @@ public class Utils { return new Date((long)date); } + public static int getWheelHeight(View pickerView) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 160, pickerView.getResources().getDisplayMetrics()); + } + + public static String localeToYmdPattern(Locale locale) { + DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT, locale); + String pattern = ((SimpleDateFormat)formatter).toLocalizedPattern(); + pattern = pattern.replaceAll("\\[", ""); + pattern = pattern.replaceAll("]", ""); + pattern = pattern.replaceAll(" ", ""); + pattern = pattern.replaceAll("[.]", "/"); + pattern = pattern.replaceAll("-", "/"); + return pattern; +} } diff --git a/android/src/main/java/com/henninghall/date_picker/WheelOrderUpdater.java b/android/src/main/java/com/henninghall/date_picker/WheelOrderUpdater.java new file mode 100644 index 0000000..13bae90 --- /dev/null +++ b/android/src/main/java/com/henninghall/date_picker/WheelOrderUpdater.java @@ -0,0 +1,66 @@ +package com.henninghall.date_picker; + +import android.os.Build; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RelativeLayout; + +import com.henninghall.date_picker.wheels.Wheel; + +import java.util.ArrayList; +import java.util.Locale; + +public class WheelOrderUpdater +{ + private final PickerView pickerView; + private String ymdPattern = ""; + + WheelOrderUpdater(final PickerView v) { + this.pickerView = v; + } + + public void update(final Locale locale, final Mode mode) { + + if (mode != Mode.date) { + return; + } + String lastYmdPattern = ymdPattern; + ymdPattern = Utils.localeToYmdPattern(locale); + if(lastYmdPattern.equals(ymdPattern)) return; + final ArrayList wheelOrder = this.ymdPatternToWheelOrder(ymdPattern); + this.placeWheelRightOf(wheelOrder.get(0), wheelOrder.get(1)); + this.placeWheelRightOf(wheelOrder.get(1), wheelOrder.get(2)); + } + + private void placeWheelRightOf(final Wheel leftWheel, final Wheel rightWheel) { + final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(-2, Utils.getWheelHeight((View)this.pickerView)); + params.addRule(1, leftWheel.id); + if (Build.VERSION.SDK_INT >= 17) { + params.addRule(17, leftWheel.id); + } + rightWheel.picker.setLayoutParams((ViewGroup.LayoutParams)params); + } + + private ArrayList ymdPatternToWheelOrder(final String ymdPattern) { + final String[] parts = ymdPattern.split("/"); + final ArrayList wheelList = new ArrayList(); + for (final String s : parts) { + switch (s.charAt(0)) { + case 'y': { + wheelList.add(this.pickerView.yearWheel); + break; + } + case 'M': { + wheelList.add(this.pickerView.monthWheel); + break; + } + case 'd': { + wheelList.add(this.pickerView.dateWheel); + break; + } + } + } + return wheelList; + } +} + diff --git a/android/src/main/java/com/henninghall/date_picker/wheelFunctions/Refresh.java b/android/src/main/java/com/henninghall/date_picker/wheelFunctions/Refresh.java index 69eae35..1c8fb25 100644 --- a/android/src/main/java/com/henninghall/date_picker/wheelFunctions/Refresh.java +++ b/android/src/main/java/com/henninghall/date_picker/wheelFunctions/Refresh.java @@ -4,9 +4,19 @@ import com.henninghall.date_picker.wheels.Wheel; public class Refresh implements WheelFunction { + private final boolean keepOldValue; + + public Refresh() { + this.keepOldValue = true; + } + + public Refresh(boolean keepOldValue){ + this.keepOldValue = keepOldValue; + } + @Override public void apply(Wheel wheel) { - wheel.refresh(true); + wheel.refresh(keepOldValue); } } diff --git a/android/src/main/java/com/henninghall/date_picker/wheels/AmPmWheel.java b/android/src/main/java/com/henninghall/date_picker/wheels/AmPmWheel.java index 443703e..8c6677b 100644 --- a/android/src/main/java/com/henninghall/date_picker/wheels/AmPmWheel.java +++ b/android/src/main/java/com/henninghall/date_picker/wheels/AmPmWheel.java @@ -9,8 +9,8 @@ import cn.carbswang.android.numberpickerview.library.NumberPickerView; public class AmPmWheel extends Wheel { - public AmPmWheel(NumberPickerView ampmPicker, PickerView pickerView) { - super(ampmPicker, pickerView); + public AmPmWheel(PickerView pickerView, int id) { + super(pickerView, id); } @Override diff --git a/android/src/main/java/com/henninghall/date_picker/wheels/DateWheel.java b/android/src/main/java/com/henninghall/date_picker/wheels/DateWheel.java new file mode 100644 index 0000000..d327178 --- /dev/null +++ b/android/src/main/java/com/henninghall/date_picker/wheels/DateWheel.java @@ -0,0 +1,39 @@ +package com.henninghall.date_picker.wheels; + +import java.util.*; +import com.henninghall.date_picker.*; + +public class DateWheel extends Wheel +{ + public DateWheel(final PickerView pickerView, final int id) { + super(pickerView, id); + } + + @Override + void init() { + final int maxDate = 31; + final int minDate = 1; + final Calendar cal = this.pickerView.getInitialDate(); + final String initialDate = this.format.format(cal.getTime()); + for (int i = minDate; i <= maxDate; ++i) { + final int currentDate = (Integer.valueOf(initialDate) + i) % maxDate + 1; + final String currentDateString = String.valueOf(currentDate); + this.values.add(currentDateString); + this.displayValues.add(currentDateString); + } + this.picker.setDisplayedValues((String[])this.displayValues.toArray(new String[0])); + this.picker.setMinValue(0); + this.picker.setMaxValue(maxDate - minDate); + } + + @Override + public boolean visible() { + return this.pickerView.mode == Mode.date; + } + + @Override + public String getFormatTemplate() { + return "d"; + } + +} diff --git a/android/src/main/java/com/henninghall/date_picker/wheels/DayWheel.java b/android/src/main/java/com/henninghall/date_picker/wheels/DayWheel.java index 0ab7b4b..106987b 100644 --- a/android/src/main/java/com/henninghall/date_picker/wheels/DayWheel.java +++ b/android/src/main/java/com/henninghall/date_picker/wheels/DayWheel.java @@ -13,8 +13,8 @@ import cn.carbswang.android.numberpickerview.library.NumberPickerView; public class DayWheel extends Wheel { - public DayWheel(NumberPickerView dayPicker, PickerView pickerView) { - super(dayPicker, pickerView); + public DayWheel(PickerView pickerView, int id) { + super(pickerView, id); } @Override diff --git a/android/src/main/java/com/henninghall/date_picker/wheels/HourWheel.java b/android/src/main/java/com/henninghall/date_picker/wheels/HourWheel.java index 620fd42..27504d3 100644 --- a/android/src/main/java/com/henninghall/date_picker/wheels/HourWheel.java +++ b/android/src/main/java/com/henninghall/date_picker/wheels/HourWheel.java @@ -10,8 +10,8 @@ import cn.carbswang.android.numberpickerview.library.NumberPickerView; public class HourWheel extends Wheel { - public HourWheel(NumberPickerView hourPicker, PickerView pickerView) { - super(hourPicker, pickerView); + public HourWheel(PickerView pickerView, int id) { + super(pickerView, id); } @Override diff --git a/android/src/main/java/com/henninghall/date_picker/wheels/MinutesWheel.java b/android/src/main/java/com/henninghall/date_picker/wheels/MinutesWheel.java index 134948a..bc8b7fa 100644 --- a/android/src/main/java/com/henninghall/date_picker/wheels/MinutesWheel.java +++ b/android/src/main/java/com/henninghall/date_picker/wheels/MinutesWheel.java @@ -10,8 +10,8 @@ import cn.carbswang.android.numberpickerview.library.NumberPickerView; public class MinutesWheel extends Wheel { - public MinutesWheel(NumberPickerView minutePicker, PickerView pickerView) { - super(minutePicker, pickerView); + public MinutesWheel(PickerView pickerView, int id) { + super(pickerView, id); } @Override diff --git a/android/src/main/java/com/henninghall/date_picker/wheels/MonthWheel.java b/android/src/main/java/com/henninghall/date_picker/wheels/MonthWheel.java new file mode 100644 index 0000000..3289d92 --- /dev/null +++ b/android/src/main/java/com/henninghall/date_picker/wheels/MonthWheel.java @@ -0,0 +1,39 @@ +package com.henninghall.date_picker.wheels; + +import java.text.*; +import java.util.*; +import com.henninghall.date_picker.*; + +public class MonthWheel extends Wheel +{ + public MonthWheel(final PickerView pickerView, final int id) { + super(pickerView, id); + } + + @Override + void init() { + final int min = 0; + final int max = 12; + final Calendar cal = this.pickerView.getInitialDate(); + final SimpleDateFormat format = new SimpleDateFormat(this.getFormatTemplate(), this.pickerView.locale); + for (int i = min; i <= max; ++i) { + this.values.add(format.format(cal.getTime())); + this.displayValues.add(format.format(cal.getTime())); + cal.add(2, 1); + } + this.picker.setDisplayedValues((String[])this.displayValues.toArray(new String[0])); + this.picker.setMinValue(0); + this.picker.setMaxValue(max); + } + + @Override + public boolean visible() { + return this.pickerView.mode == Mode.date; + } + + @Override + public String getFormatTemplate() { + return "LLLL"; + } +} + diff --git a/android/src/main/java/com/henninghall/date_picker/wheels/Wheel.java b/android/src/main/java/com/henninghall/date_picker/wheels/Wheel.java index 43533c0..c15d4df 100644 --- a/android/src/main/java/com/henninghall/date_picker/wheels/Wheel.java +++ b/android/src/main/java/com/henninghall/date_picker/wheels/Wheel.java @@ -2,6 +2,8 @@ package com.henninghall.date_picker.wheels; import android.view.View; import com.henninghall.date_picker.PickerView; +import com.henninghall.date_picker.R; + import org.apache.commons.lang3.LocaleUtils; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -12,12 +14,13 @@ import cn.carbswang.android.numberpickerview.library.NumberPickerView; public abstract class Wheel { private final Wheel self; + public final int id; public PickerView pickerView; private String userSetValue; abstract void init(); public abstract boolean visible(); - abstract String getFormatTemplate(); + public abstract String getFormatTemplate(); ArrayList values; ArrayList displayValues; @@ -25,10 +28,11 @@ public abstract class Wheel { public SimpleDateFormat format; SimpleDateFormat displayFormat; - public Wheel(NumberPickerView picker, final PickerView pickerView) { + public Wheel(final PickerView pickerView, final int id) { + this.id = id; this.self = this; this.pickerView = pickerView; - this.picker = picker; + this.picker = (NumberPickerView) pickerView.findViewById(id); refresh(false); picker.setOnValueChangedListener(new NumberPickerView.OnValueChangeListener() { @Override diff --git a/android/src/main/java/com/henninghall/date_picker/wheels/YearWheel.java b/android/src/main/java/com/henninghall/date_picker/wheels/YearWheel.java new file mode 100644 index 0000000..bf3e3fd --- /dev/null +++ b/android/src/main/java/com/henninghall/date_picker/wheels/YearWheel.java @@ -0,0 +1,63 @@ +package com.henninghall.date_picker.wheels; + +import com.henninghall.date_picker.Mode; +import com.henninghall.date_picker.PickerView; + +import java.util.Calendar; + +public class YearWheel extends Wheel +{ + private int defaultStartYear; + private int defaultEndYear; + + public YearWheel(final PickerView pickerView, final int id) { + super(pickerView, id); + this.defaultStartYear = 0; + this.defaultEndYear = 2100; + } + + @Override + void init() { + final int startYear = getStartYear(); + final int endYear = getEndYear() ; + int max = endYear - startYear; + + for (int i = 0; i <= max; ++i) { + values.add(String.valueOf(startYear + i)); + displayValues.add(String.valueOf(startYear + i)); + } + + picker.setDisplayedValues(displayValues.toArray(new String[0])); + picker.setMinValue(0); + picker.setMaxValue(max); + } + + private int getEndYear() { + if (this.pickerView.maxDate == null) { + return this.defaultEndYear; + } + final Calendar cal = Calendar.getInstance(); + cal.setTime(this.pickerView.maxDate); + return cal.get(Calendar.YEAR); + } + + private int getStartYear() { + if (this.pickerView.minDate != null) { + final Calendar cal = Calendar.getInstance(); + cal.setTime(this.pickerView.minDate); + return cal.get(Calendar.YEAR); + } + return this.defaultStartYear; + } + + @Override + public boolean visible() { + return this.pickerView.mode == Mode.date; + } + + @Override + public String getFormatTemplate() { + return "y"; + } +} + diff --git a/android/src/main/res/layout/datepicker_view.xml b/android/src/main/res/layout/datepicker_view.xml index 718a2c2..591980c 100644 --- a/android/src/main/res/layout/datepicker_view.xml +++ b/android/src/main/res/layout/datepicker_view.xml @@ -16,6 +16,48 @@ android:layout_centerHorizontal="true" android:foregroundGravity="center" > + + + + this.setState({ date })} + mode={'date'} + style={{borderWidth: 1}} + locale={'sv-SE'} + /> + +} diff --git a/temp/DatePickerManager.java b/temp/DatePickerManager.java new file mode 100644 index 0000000..70bd82a --- /dev/null +++ b/temp/DatePickerManager.java @@ -0,0 +1,82 @@ +package com.henninghall.date_picker; + +import android.view.*; +import com.facebook.react.uimanager.*; +import net.time4j.android.*; +import android.content.*; +import android.support.annotation.*; +import com.facebook.react.uimanager.annotations.*; +import org.apache.commons.lang3.*; +import java.util.*; +import com.facebook.react.common.*; + +public class DatePickerManager extends SimpleViewManager +{ + public static final String REACT_CLASS = "DatePickerManager"; + public static ThemedReactContext context; + + public String getName() { + return "DatePickerManager"; + } + + public PickerView createViewInstance(final ThemedReactContext reactContext) { + ApplicationStarter.initialize((Context)(DatePickerManager.context = reactContext), true); + return new PickerView(); + } + + @ReactProp(name = "mode") + public void setMode(final PickerView view, @Nullable final String mode) { + try { + view.setMode(Mode.valueOf(mode)); + } + catch (Exception e) { + throw new IllegalArgumentException("Invalid mode. Valid modes: 'datetime', 'date', 'time'"); + } + } + + @ReactProp(name = "date") + public void setDate(final PickerView view, @Nullable final double date) { + view.setDate(Utils.unixToDate(date)); + } + + @ReactProp(name = "locale") + public void setLocale(final PickerView view, @Nullable final String locale) { + view.setLocale(LocaleUtils.toLocale(locale.replace('-', '_'))); + view.requestLayout(); + } + + @ReactProp(name = "minimumDate") + public void setMinimumDate(final PickerView view, @Nullable final double date) { + view.setMinimumDate(Utils.unixToDate(date)); + } + + @ReactProp(name = "maximumDate") + public void setMaximumDate(final PickerView view, @Nullable final double date) { + view.setMaximumDate(Utils.unixToDate(date)); + } + + @ReactProp(name = "fadeToColor") + public void setFadeToColor(final PickerView view, @Nullable final String color) { + view.style.setFadeToColor(color); + } + + @ReactProp(name = "textColor") + public void setTextColor(final PickerView view, @Nullable final String color) { + view.style.setTextColor(color); + } + + @ReactProp(name = "minuteInterval") + public void setMinuteInterval(final PickerView view, @Nullable final int interval) throws Exception { + if (interval < 0 || interval > 59) { + throw new Exception("Minute interval out of bounds"); + } + if (interval > 1) { + view.setMinuteInterval(interval); + } + } + + public Map getExportedCustomBubblingEventTypeConstants() { + return MapBuilder.builder().put((Object)"dateChange", (Object)MapBuilder.of((Object)"phasedRegistrationNames", (Object)MapBuilder.of((Object)"bubbled", (Object)"onChange"))).build(); + } +} + diff --git a/temp/DateWheel.java b/temp/DateWheel.java new file mode 100644 index 0000000..328537e --- /dev/null +++ b/temp/DateWheel.java @@ -0,0 +1,38 @@ + + -ckage com.henninghall.date_picker.wheels; + +import java.util.*; +import com.henninghall.date_picker.*; + +public class DateWheel extends Wheel +{ + public DateWheel(final PickerView pickerView, final int id) { + super(pickerView, id); + } + + @Override + void init() { + final int maxDate = 31; + final int minDate = 1; + final Calendar cal = this.pickerView.getInitialDate(); + final String initialDate = this.format.format(cal.getTime()); + for (int i = minDate; i <= maxDate; ++i) { + final int currentDate = (Integer.valueOf(initialDate) + i) % maxDate + 1; + final String currentDateString = String.valueOf(currentDate); + this.values.add(currentDateString); + this.displayValues.add(currentDateString); + } + this.picker.setDisplayedValues((String[])this.displayValues.toArray(new String[0])); + this.picker.setMinValue(0); + this.picker.setMaxValue(maxDate - minDate); + } + + @Override + public boolean visible() { + return this.pickerView.mode == Mode.date; + } + + public String getFormatTemplate() { + return "d"; + } +} diff --git a/temp/Mode.java b/temp/Mode.java new file mode 100644 index 0000000..4b2e152 --- /dev/null +++ b/temp/Mode.java @@ -0,0 +1,9 @@ +package com.henninghall.date_picker; + +public enum Mode +{ + date, + time, + datetime; +} + diff --git a/temp/MonthWheel.java b/temp/MonthWheel.java new file mode 100644 index 0000000..a78b491 --- /dev/null +++ b/temp/MonthWheel.java @@ -0,0 +1,38 @@ +package com.henninghall.date_picker.wheels; + +import java.text.*; +import java.util.*; +import com.henninghall.date_picker.*; + +public class MonthWheel extends Wheel +{ + public MonthWheel(final PickerView pickerView, final int id) { + super(pickerView, id); + } + + @Override + void init() { + final int min = 0; + final int max = 12; + final Calendar cal = this.pickerView.getInitialDate(); + final SimpleDateFormat format = new SimpleDateFormat(this.getFormatTemplate(), this.pickerView.locale); + for (int i = min; i <= max; ++i) { + this.values.add(format.format(cal.getTime())); + this.displayValues.add(format.format(cal.getTime())); + cal.add(2, 1); + } + this.picker.setDisplayedValues((String[])this.displayValues.toArray(new String[0])); + this.picker.setMinValue(0); + this.picker.setMaxValue(max); + } + + @Override + public boolean visible() { + return this.pickerView.mode == Mode.date; + } + + public String getFormatTemplate() { + return "LLLL"; + } +} + diff --git a/temp/PickerView.java b/temp/PickerView.java new file mode 100644 index 0000000..ea48334 --- /dev/null +++ b/temp/PickerView.java @@ -0,0 +1,184 @@ +package com.henninghall.date_picker; + +import android.widget.*; +import cn.carbswang.android.numberpickerview.library.*; +import android.content.*; +import com.henninghall.date_picker.wheels.*; +import com.facebook.react.uimanager.events.*; +import java.text.*; +import com.facebook.react.bridge.*; +import android.view.*; +import android.os.*; +import org.apache.commons.lang3.time.*; +import com.henninghall.date_picker.wheelFunctions.*; +import java.util.*; + +public class PickerView extends RelativeLayout +{ + private final NumberPickerView hourPicker; + private final NumberPickerView ampmPicker; + private SimpleDateFormat dateFormat; + private HourWheel hourWheel; + private DayWheel dayWheel; + public MinutesWheel minutesWheel; + private AmPmWheel ampmWheel; + private Date minDate; + private Date maxDate; + public int minuteInterval; + public Locale locale; + public Mode mode; + public Style style; + WheelChangeListener onWheelChangeListener; + private final Runnable measureAndLayout; + + public PickerView() { + super((Context)DatePickerManager.context); + this.minuteInterval = 1; + this.onWheelChangeListener = new WheelChangeListener() { + @Override + public void onChange(final Wheel wheel) { + final WritableMap event = Arguments.createMap(); + try { + final Date date = PickerView.this.dateFormat.parse(PickerView.this.getDateString()); + if (PickerView.this.minDate != null && date.before(PickerView.this.minDate)) { + PickerView.this.applyOnVisibleWheels(new AnimateToDate(PickerView.this.minDate)); + } + else if (PickerView.this.maxDate != null && date.after(PickerView.this.maxDate)) { + PickerView.this.applyOnVisibleWheels(new AnimateToDate(PickerView.this.maxDate)); + } + else { + event.putDouble("date", (double)date.getTime()); + ((RCTEventEmitter)DatePickerManager.context.getJSModule((Class)RCTEventEmitter.class)).receiveEvent(PickerView.this.getId(), "dateChange", event); + } + } + catch (ParseException e) { + e.printStackTrace(); + } + } + }; + this.measureAndLayout = new Runnable() { + @Override + public void run() { + PickerView.this.measure(View.MeasureSpec.makeMeasureSpec(PickerView.this.getWidth(), 1073741824), View.MeasureSpec.makeMeasureSpec(PickerView.this.getHeight(), 1073741824)); + PickerView.this.layout(PickerView.this.getLeft(), PickerView.this.getTop(), PickerView.this.getRight(), PickerView.this.getBottom()); + } + }; + final View rootView = inflate(this.getContext(), R.layout.datepicker_view, (ViewGroup)this); + this.style = new Style(this); + final RelativeLayout wheelsWrapper = (RelativeLayout)rootView.findViewById(R.id.wheelsWrapper); + wheelsWrapper.setWillNotDraw(false); + this.locale = ((Build.VERSION.SDK_INT >= 21) ? Locale.forLanguageTag("en") : Locale.getDefault()); + final NumberPickerView dayPicker = (NumberPickerView)rootView.findViewById(R.id.day); + this.dayWheel = new DayWheel(dayPicker, this); + final NumberPickerView minutePicker = (NumberPickerView)rootView.findViewById(R.id.minutes); + this.minutesWheel = new MinutesWheel(minutePicker, this); + this.ampmPicker = (NumberPickerView)rootView.findViewById(R.id.ampm); + this.ampmWheel = new AmPmWheel(this.ampmPicker, this); + this.hourPicker = (NumberPickerView)rootView.findViewById(R.id.hour); + this.hourWheel = new HourWheel(this.hourPicker, this); + this.dateFormat = new SimpleDateFormat(this.getDateFormatTemplate(), Locale.US); + this.changeAmPmWhenPassingMidnightOrNoon(); + } + + private void changeAmPmWhenPassingMidnightOrNoon() { + this.hourPicker.setOnValueChangeListenerInScrolling((NumberPickerView.OnValueChangeListenerInScrolling)new NumberPickerView.OnValueChangeListenerInScrolling() { + public void onValueChangeInScrolling(final NumberPickerView picker, final int oldVal, final int newVal) { + if (Utils.usesAmPm(PickerView.this.locale)) { + final String oldValue = PickerView.this.hourWheel.getValueAtIndex(oldVal); + final String newValue = PickerView.this.hourWheel.getValueAtIndex(newVal); + final boolean passingNoonOrMidnight = (oldValue.equals("12") && newValue.equals("11")) || (oldValue.equals("11") && newValue.equals("12")); + if (passingNoonOrMidnight) { + PickerView.this.ampmPicker.smoothScrollToValue((PickerView.this.ampmPicker.getValue() + 1) % 2, false); + } + } + } + }); + } + + public void setMinimumDate(final Date date) { + this.minDate = DateUtils.truncate(date, 12); + } + + public void setMaximumDate(final Date date) { + this.maxDate = DateUtils.truncate(date, 12); + } + + public void setDate(final Date date) { + this.applyOnAllWheels(new SetDate(date)); + } + + public void setLocale(final Locale locale) { + this.locale = locale; + this.dateFormat = new SimpleDateFormat(this.getDateFormatTemplate(), Locale.US); + this.applyOnAllWheels(new Refresh()); + } + + public void setMinuteInterval(final int interval) { + this.minuteInterval = interval; + this.applyOnVisibleWheels(new Refresh()); + } + + public Calendar getInitialDate() { + final Calendar cal = Calendar.getInstance(); + if (this.minuteInterval <= 1) { + return cal; + } + final int exactMinute = Integer.valueOf(this.minutesWheel.format.format(cal.getTime())); + final int diffSinceLastInterval = exactMinute % this.minuteInterval; + final int diffAhead = this.minuteInterval - diffSinceLastInterval; + final int diffBehind = -diffSinceLastInterval; + final boolean closerToPrevious = this.minuteInterval / 2 > diffSinceLastInterval; + final int diffToExactValue = closerToPrevious ? diffBehind : diffAhead; + cal.add(12, diffToExactValue); + return (Calendar)cal.clone(); + } + + private String getDateFormatTemplate() { + return this.dayWheel.getFormatTemplate() + " " + this.hourWheel.getFormatTemplate() + " " + this.minutesWheel.getFormatTemplate() + this.ampmWheel.getFormatTemplate(); + } + + private String getDateString() { + return this.dayWheel.getValue() + " " + this.hourWheel.getValue() + " " + this.minutesWheel.getValue() + this.ampmWheel.getValue(); + } + + public void setMode(final Mode mode) { + this.mode = mode; + this.applyOnAllWheels(new Refresh()); + } + + public Collection getVisibleWheels() { + final Collection visibleWheels = new ArrayList(); + for (final Wheel wheel : this.getAllWheels()) { + if (wheel.visible()) { + visibleWheels.add(wheel); + } + } + return visibleWheels; + } + + public List getAllWheels() { + return new ArrayList(Arrays.asList(this.dayWheel, this.hourWheel, this.minutesWheel, this.ampmWheel)); + } + + public void applyOnAllWheels(final WheelFunction function) { + for (final Wheel wheel : this.getAllWheels()) { + function.apply(wheel); + } + } + + public void applyOnVisibleWheels(final WheelFunction function) { + for (final Wheel wheel : this.getVisibleWheels()) { + function.apply(wheel); + } + } + + public void requestLayout() { + super.requestLayout(); + this.post(this.measureAndLayout); + } + + public WheelChangeListener getListener() { + return this.onWheelChangeListener; + } +} + diff --git a/temp/Wheel.java b/temp/Wheel.java new file mode 100644 index 0000000..76d51c5 --- /dev/null +++ b/temp/Wheel.java @@ -0,0 +1,100 @@ +package com.henninghall.date_picker.wheels; + +import com.henninghall.date_picker.*; +import cn.carbswang.android.numberpickerview.library.*; +import java.text.*; +import java.util.*; +import org.apache.commons.lang3.*; + +public abstract class Wheel +{ + private final Wheel self; + public PickerView pickerView; + private String userSetValue; + ArrayList values; + ArrayList displayValues; + public NumberPickerView picker; + public SimpleDateFormat format; + SimpleDateFormat displayFormat; + + abstract void init(); + + public abstract boolean visible(); + + abstract String getFormatTemplate(); + + public Wheel(final NumberPickerView picker, final PickerView pickerView) { + this.self = this; + this.pickerView = pickerView; + this.picker = picker; + this.refresh(false); + picker.setOnValueChangedListener((NumberPickerView.OnValueChangeListener)new NumberPickerView.OnValueChangeListener() { + public void onValueChange(final NumberPickerView picker, final int oldVal, final int newVal) { + pickerView.getListener().onChange(Wheel.this.self); + } + }); + } + + public int getIndexOfDate(final Date date) { + return this.values.indexOf(this.format.format(date)); + } + + public void animateToDate(final Date date) { + this.picker.smoothScrollToValue(this.getIndexOfDate(date)); + } + + public String getValue() { + if (!this.visible()) { + return this.userSetValue; + } + return this.getValueAtIndex(this.getIndex()); + } + + public int getIndex() { + return this.picker.getValue(); + } + + public String getValueAtIndex(final int index) { + return this.values.get(index); + } + + public void setValue(final Date date) { + this.userSetValue = this.format.format(date); + final int index = this.getIndexOfDate(date); + if (index > -1) { + if (this.picker.getValue() == 0) { + this.picker.setValue(index); + } + else { + this.picker.smoothScrollToValue(index); + } + } + } + + public void refresh(final boolean keepOldValue) { + this.displayFormat = new SimpleDateFormat(this.getFormatTemplate(), this.pickerView.locale); + this.format = new SimpleDateFormat(this.getFormatTemplate(), LocaleUtils.toLocale("en_US")); + this.values = new ArrayList(); + this.displayValues = new ArrayList(); + final int oldValue = this.picker.getValue(); + if (this.visible()) { + this.add(); + this.init(); + if (keepOldValue) { + this.picker.setValue(oldValue); + } + } + else { + this.remove(); + } + } + + private void remove() { + this.picker.setVisibility(8); + } + + private void add() { + this.picker.setVisibility(0); + } +} + diff --git a/temp/WheelOrderUpdater.java b/temp/WheelOrderUpdater.java new file mode 100644 index 0000000..0817d3c --- /dev/null +++ b/temp/WheelOrderUpdater.java @@ -0,0 +1,56 @@ +package com.henninghall.date_picker; + +import com.henninghall.date_picker.wheels.*; +import java.util.*; +import android.widget.*; +import android.os.*; +import android.view.*; + +public class WheelOrderUpdater +{ + private final PickerView pickerView; + + WheelOrderUpdater(final PickerView v) { + this.pickerView = v; + } + + public void update(final Locale locale, final Mode mode) { + if (mode != Mode.date) { + return; + } + final String ymdPattern = Utils.localeToYmdPattern(locale); + final ArrayList wheelOrder = this.ymdPatternToWheelOrder(ymdPattern); + this.placeWheelRightOf(wheelOrder.get(0), wheelOrder.get(1)); + this.placeWheelRightOf(wheelOrder.get(1), wheelOrder.get(2)); + } + + private void placeWheelRightOf(final Wheel leftWheel, final Wheel rightWheel) { + final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(-2, Utils.getWheelHeight((View)this.pickerView)); + params.addRule(1, leftWheel.id); + if (Build.VERSION.SDK_INT >= 17) { + params.addRule(17, leftWheel.id); + } + rightWheel.picker.setLayoutParams((ViewGroup.LayoutParams)params); + } + + private ArrayList ymdPatternToWheelOrder(final String ymdPattern) { + final String[] parts = ymdPattern.split("/"); + final ArrayList wheelList = new ArrayList(); + for (final String s : parts) { + switch (s.charAt(0)) { + case 'y': { + wheelList.add(this.pickerView.yearWheel); + } + case 'M': { + wheelList.add(this.pickerView.monthWheel); + } + case 'd': { + wheelList.add(this.pickerView.dateWheel); + break; + } + } + } + return wheelList; + } +} + diff --git a/temp/YearWheel.java b/temp/YearWheel.java new file mode 100644 index 0000000..6dea00e --- /dev/null +++ b/temp/YearWheel.java @@ -0,0 +1,58 @@ +package com.henninghall.date_picker.wheels; + +import java.util.*; +import com.henninghall.date_picker.*; + +public class YearWheel extends Wheel +{ + private int defaultStartYear; + private int defaultEndYear; + + public YearWheel(final PickerView pickerView, final int id) { + super(pickerView, id); + this.defaultStartYear = 0; + this.defaultEndYear = 2100; + } + + @Override + void init() { + final int startYear = this.getStartYear(); + final int endYear = this.getEndYear(); + for (int i = startYear; i <= endYear; ++i) { + this.values.add(String.valueOf(i)); + this.displayValues.add(String.valueOf(i)); + } + this.picker.setDisplayedValues((String[])this.displayValues.toArray(new String[0])); + final int year = Calendar.getInstance().get(1); + this.picker.setMinValue(startYear); + this.picker.setMaxValue(endYear); + } + + private int getEndYear() { + if (this.pickerView.maxDate == null) { + return this.defaultEndYear; + } + final Calendar cal = Calendar.getInstance(); + cal.setTime(this.pickerView.maxDate); + return cal.get(1); + } + + private int getStartYear() { + if (this.pickerView.minDate != null) { + final Calendar cal = Calendar.getInstance(); + cal.setTime(this.pickerView.minDate); + return cal.get(1); + } + return this.defaultStartYear; + } + + @Override + public boolean visible() { + return this.pickerView.mode == Mode.date; + } + + public String getFormatTemplate() { + return "y"; + } +} +