Skip to content

Commit 5640dba

Browse files
authored
Merge pull request #1 from henninghall/feature/minute-interval
Minute interval support.
2 parents f4c926e + 74d7db4 commit 5640dba

File tree

13 files changed

+221
-130
lines changed

13 files changed

+221
-130
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ The goal is to make a cross platform variant of [DatePickerIOS](https://facebook
6161
- [x] Animate to date when state change occur.
6262
- [x] Switch between AM/PM when scrolling between forenoon and afternoon.
6363
- [x] Support maximumDate/minimumDate.
64-
- [ ] Minute interval prop.
64+
- [x] Minute interval prop.
6565
- [ ] Colored background support.
6666
- [ ] Align text to right.
6767
- [ ] Mode: date

android/src/main/java/com/henninghall/date_picker/DatePickerManager.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,13 @@
22

33
import android.support.annotation.Nullable;
44
import android.view.View;
5-
65
import com.facebook.react.common.MapBuilder;
76
import com.facebook.react.uimanager.SimpleViewManager;
87
import com.facebook.react.uimanager.ThemedReactContext;
98
import com.facebook.react.uimanager.annotations.ReactProp;
10-
119
import net.time4j.android.ApplicationStarter;
12-
1310
import org.apache.commons.lang3.LocaleUtils;
1411

15-
import java.util.Date;
1612
import java.util.Map;
1713

1814
public class DatePickerManager extends SimpleViewManager<View> {
@@ -53,6 +49,12 @@ public void setMaximumDate(PickerView view, @Nullable double date) {
5349
view.setMaximumDate(Utils.unixToDate(date));
5450
}
5551

52+
@ReactProp(name = "minuteInterval")
53+
public void setMinuteInterval(PickerView view, @Nullable int interval) throws Exception {
54+
if (interval < 0 || interval > 59) throw new Exception("Minute interval out of bounds");
55+
if (interval > 1) view.setMinuteInterval(interval);
56+
}
57+
5658
public Map getExportedCustomBubblingEventTypeConstants() {
5759
return MapBuilder.builder()
5860
.put("dateChange", MapBuilder.of("phasedRegistrationNames",
Lines changed: 98 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
package com.henninghall.date_picker;
22

3+
import android.annotation.SuppressLint;
34
import android.view.View;
45
import android.widget.RelativeLayout;
56

67
import com.facebook.react.bridge.Arguments;
78
import com.facebook.react.bridge.WritableMap;
89
import com.facebook.react.uimanager.events.RCTEventEmitter;
10+
import com.henninghall.date_picker.wheelFunctions.AnimateToDate;
11+
import com.henninghall.date_picker.wheelFunctions.Refresh;
12+
import com.henninghall.date_picker.wheelFunctions.SetDate;
13+
import com.henninghall.date_picker.wheelFunctions.WheelFunction;
914
import com.henninghall.date_picker.wheels.AmPmWheel;
1015
import com.henninghall.date_picker.wheels.DayWheel;
1116
import com.henninghall.date_picker.wheels.HourWheel;
@@ -16,50 +21,54 @@
1621

1722
import java.text.ParseException;
1823
import java.text.SimpleDateFormat;
24+
import java.util.ArrayList;
25+
import java.util.Arrays;
1926
import java.util.Calendar;
27+
import java.util.Collection;
2028
import java.util.Date;
29+
import java.util.List;
2130
import java.util.Locale;
2231

2332
import cn.carbswang.android.numberpickerview.library.NumberPickerView;
2433

2534

2635
public class PickerView extends RelativeLayout {
2736

28-
private final RelativeLayout wheelsWrapper;
2937
private final NumberPickerView hourPicker;
3038
private final NumberPickerView ampmPicker;
3139
private SimpleDateFormat dateFormat;
3240
private HourWheel hourWheel;
3341
private DayWheel dayWheel;
34-
private MinutesWheel minutesWheel;
42+
public MinutesWheel minutesWheel;
3543
private AmPmWheel ampmWheel;
3644
private Date minDate;
3745
private Date maxDate;
46+
public int minuteInterval = 1;
47+
public Locale locale;
3848

3949
public PickerView() {
4050
super(DatePickerManager.context);
4151
View rootView = inflate(getContext(), R.layout.datepicker_view, this);
4252

43-
wheelsWrapper = (RelativeLayout) rootView.findViewById(R.id.wheelsWrapper);
53+
RelativeLayout wheelsWrapper = (RelativeLayout) rootView.findViewById(R.id.wheelsWrapper);
4454
wheelsWrapper.setWillNotDraw(false);
4555

46-
Locale locale = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP ? Locale.forLanguageTag("en") : Locale.getDefault();
56+
locale = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP ? Locale.forLanguageTag("en") : Locale.getDefault();
4757

4858
NumberPickerView dayPicker = (NumberPickerView) rootView.findViewById(R.id.day);
49-
dayWheel = new DayWheel(dayPicker, onWheelChangeListener, locale);
59+
dayWheel = new DayWheel(dayPicker, this);
5060

5161
NumberPickerView minutePicker = (NumberPickerView) rootView.findViewById(R.id.minutes);
52-
minutesWheel = new MinutesWheel(minutePicker, onWheelChangeListener, locale);
62+
minutesWheel = new MinutesWheel(minutePicker, this);
5363

5464
ampmPicker = (NumberPickerView) rootView.findViewById(R.id.ampm);
55-
ampmWheel = new AmPmWheel(ampmPicker, onWheelChangeListener, locale);
65+
ampmWheel = new AmPmWheel(ampmPicker, this);
5666

5767
hourPicker = (NumberPickerView) rootView.findViewById(R.id.hour);
58-
hourWheel = new HourWheel(hourPicker, onWheelChangeListener, locale);
68+
hourWheel = new HourWheel(hourPicker,this);
5969

6070
dateFormat = new SimpleDateFormat(getDateFormatTemplate(), Locale.US);
6171
changeAmPmWhenPassingMidnightOrNoon();
62-
6372
}
6473

6574
WheelChangeListener onWheelChangeListener = new WheelChangeListener(){
@@ -68,8 +77,8 @@ public void onChange(Wheel wheel) {
6877
WritableMap event = Arguments.createMap();
6978
try {
7079
Date date = dateFormat.parse(getDateString());
71-
if (date.before(minDate)) wheel.animateToDate(minDate);
72-
if (date.after(maxDate)) wheel.animateToDate(maxDate);
80+
if (date.before(minDate)) applyOnVisibleWheels(new AnimateToDate(minDate));
81+
if (date.after(maxDate)) applyOnVisibleWheels(new AnimateToDate(maxDate));
7382
else {
7483
event.putDouble("date", date.getTime());
7584
DatePickerManager.context.getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "dateChange", event);
@@ -80,12 +89,72 @@ public void onChange(Wheel wheel) {
8089
}
8190
};
8291

92+
private final Runnable measureAndLayout = new Runnable() {
93+
@Override
94+
public void run() {
95+
measure(
96+
MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
97+
MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));
98+
layout(getLeft(), getTop(), getRight(), getBottom());
99+
}
100+
};
101+
102+
private void changeAmPmWhenPassingMidnightOrNoon(){
103+
hourPicker.setOnValueChangeListenerInScrolling(new NumberPickerView.OnValueChangeListenerInScrolling() {
104+
@Override
105+
public void onValueChangeInScrolling(NumberPickerView picker, int oldVal, int newVal) {
106+
if(Utils.usesAmPm(locale)){
107+
String oldValue = hourWheel.getValueAtIndex(oldVal);
108+
String newValue = hourWheel.getValueAtIndex(newVal);
109+
boolean passingNoonOrMidnight = (oldValue.equals("12") && newValue.equals("11")) || oldValue.equals("11") && newValue.equals("12");
110+
if (passingNoonOrMidnight) ampmPicker.smoothScrollToValue((ampmPicker.getValue() + 1) % 2,false);
111+
}
112+
}
113+
});
114+
}
115+
116+
public void setMinimumDate(Date date) {
117+
minDate = DateUtils.truncate(date, Calendar.MINUTE);
118+
}
119+
120+
public void setMaximumDate(Date date) {
121+
maxDate = DateUtils.truncate(date, Calendar.MINUTE);
122+
}
123+
124+
public void setDate(Date date) {
125+
applyOnVisibleWheels(new SetDate(date));
126+
}
127+
128+
public void setLocale(Locale locale) {
129+
this.locale = locale;
130+
dateFormat = new SimpleDateFormat(getDateFormatTemplate(), Locale.US);
131+
applyOnAllWheels(new Refresh());
132+
}
133+
134+
public void setMinuteInterval(int interval) {
135+
this.minuteInterval = interval;
136+
applyOnVisibleWheels(new Refresh());
137+
}
138+
139+
// Rounding cal to closest minute interval
140+
public Calendar getInitialDate() {
141+
Calendar cal = Calendar.getInstance();
142+
if(minuteInterval <= 1) return cal;
143+
int exactMinute = Integer.valueOf(minutesWheel.format.format(cal.getTime()));
144+
int diffSinceLastInterval = exactMinute % minuteInterval;
145+
int diffAhead = minuteInterval - diffSinceLastInterval;
146+
int diffBehind= -diffSinceLastInterval;
147+
boolean closerToPrevious = minuteInterval / 2 > diffSinceLastInterval;
148+
int diffToExactValue = closerToPrevious ? diffBehind : diffAhead;
149+
cal.add(Calendar.MINUTE, diffToExactValue);
150+
return (Calendar) cal.clone();
151+
}
83152

84153
private String getDateFormatTemplate() {
85154
return dayWheel.getFormatTemplate() + " "
86155
+ hourWheel.getFormatTemplate() + " "
87156
+ minutesWheel.getFormatTemplate()
88-
+ ampmWheel.getFormatTemplate();
157+
+ ampmWheel.getFormatTemplate();
89158
}
90159

91160
private String getDateString() {
@@ -95,58 +164,36 @@ private String getDateString() {
95164
+ ampmWheel.getValue();
96165
}
97166

98-
public void setMinimumDate(Date date) {
99-
minDate = DateUtils.truncate(date, Calendar.MINUTE);
167+
public Collection<Wheel> getVisibleWheels() {
168+
Collection<Wheel> visibleWheels = new ArrayList<>();
169+
for (Wheel wheel: getAllWheels()) {
170+
if (wheel.visible()) {
171+
visibleWheels.add(wheel);
172+
}
173+
}
174+
return visibleWheels;
100175
}
101176

102-
public void setMaximumDate(Date date) {
103-
maxDate = DateUtils.truncate(date, Calendar.MINUTE);
177+
public List<Wheel> getAllWheels(){
178+
return new ArrayList<>(Arrays.asList(dayWheel, hourWheel, minutesWheel, ampmWheel));
104179
}
105180

106-
public void setDate(Date date) {
107-
dayWheel.setValue(date);
108-
hourWheel.setValue(date);
109-
minutesWheel.setValue(date);
110-
ampmWheel.setValue(date);
181+
public void applyOnAllWheels(WheelFunction function) {
182+
for (Wheel wheel: getAllWheels()) function.apply(wheel);
111183
}
112184

113-
public void setLocale(Locale locale) {
114-
dayWheel.setLocale(locale);
115-
hourWheel.setLocale(locale);
116-
minutesWheel.setLocale(locale);
117-
ampmWheel.setLocale(locale);
118-
119-
dateFormat = new SimpleDateFormat(getDateFormatTemplate(), Locale.US);
185+
public void applyOnVisibleWheels(WheelFunction function) {
186+
for (Wheel wheel: getVisibleWheels()) function.apply(wheel);
120187
}
121188

122-
private final Runnable measureAndLayout = new Runnable() {
123-
@Override
124-
public void run() {
125-
measure(
126-
MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
127-
MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));
128-
layout(getLeft(), getTop(), getRight(), getBottom());
129-
}
130-
};
131-
132189
@Override
133190
public void requestLayout() {
134191
super.requestLayout();
135192
post(measureAndLayout);
136193
}
137194

138-
private void changeAmPmWhenPassingMidnightOrNoon(){
139-
hourPicker.setOnValueChangeListenerInScrolling(new NumberPickerView.OnValueChangeListenerInScrolling() {
140-
@Override
141-
public void onValueChangeInScrolling(NumberPickerView picker, int oldVal, int newVal) {
142-
if(Utils.usesAmPm(hourWheel.getLocale())){
143-
String oldValue = hourWheel.getValueAtIndex(oldVal);
144-
String newValue = hourWheel.getValueAtIndex(newVal);
145-
boolean passingNoonOrMidnight = (oldValue.equals("12") && newValue.equals("11")) || oldValue.equals("11") && newValue.equals("12");
146-
if (passingNoonOrMidnight) ampmPicker.smoothScrollToValue((ampmPicker.getValue() + 1) % 2);
147-
}
148-
}
149-
});
150-
195+
public WheelChangeListener getListener() {
196+
return onWheelChangeListener;
151197
}
198+
152199
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.henninghall.date_picker.wheelFunctions;
2+
3+
import com.henninghall.date_picker.wheels.Wheel;
4+
5+
import java.util.Date;
6+
7+
public class AnimateToDate implements WheelFunction {
8+
9+
private Date date;
10+
11+
public AnimateToDate(Date date) {
12+
this.date = date;
13+
}
14+
15+
@Override
16+
public void apply(Wheel wheel) {
17+
wheel.animateToDate(date);
18+
}
19+
}
20+
21+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.henninghall.date_picker.wheelFunctions;
2+
3+
import com.henninghall.date_picker.wheels.Wheel;
4+
5+
public class Refresh implements WheelFunction {
6+
7+
@Override
8+
public void apply(Wheel wheel) {
9+
wheel.refresh(true);
10+
}
11+
}
12+
13+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.henninghall.date_picker.wheelFunctions;
2+
3+
import com.henninghall.date_picker.wheels.Wheel;
4+
5+
import java.util.Date;
6+
7+
public class SetDate implements WheelFunction {
8+
9+
private Date date;
10+
11+
public SetDate(Date date) {
12+
this.date = date;
13+
}
14+
15+
@Override
16+
public void apply(Wheel wheel) {
17+
wheel.setValue(date);
18+
}
19+
}
20+
21+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.henninghall.date_picker.wheelFunctions;
2+
3+
import com.henninghall.date_picker.wheels.Wheel;
4+
5+
public interface WheelFunction {
6+
7+
void apply(Wheel wheel);
8+
}
9+
10+

0 commit comments

Comments
 (0)