|
2 | 2 |
|
3 | 3 | import java.util.ArrayList;
|
4 | 4 | import java.util.List;
|
5 |
| -import java.util.Locale; |
6 | 5 |
|
7 | 6 | import android.app.TimePickerDialog;
|
8 | 7 | import android.content.DialogInterface;
|
|
14 | 13 | import android.widget.NumberPicker;
|
15 | 14 |
|
16 | 15 | class CustomTimePickerDialog extends TimePickerDialog {
|
17 |
| - private static final String LOG_TAG = CustomTimePickerDialog.class.getSimpleName(); |
18 |
| - |
19 |
| - private TimePicker mTimePicker; |
20 |
| - private int mTimePickerInterval; |
21 |
| - private RNTimePickerDisplay mDisplay; |
22 |
| - private final OnTimeSetListener mTimeSetListener; |
23 |
| - private Handler handler = new Handler(); |
24 |
| - private Runnable runnable; |
25 |
| - private Context mContext; |
26 |
| - |
27 |
| - public CustomTimePickerDialog( |
28 |
| - Context context, |
29 |
| - OnTimeSetListener listener, |
30 |
| - int hourOfDay, |
31 |
| - int minute, |
32 |
| - int minuteInterval, |
33 |
| - boolean is24HourView, |
34 |
| - RNTimePickerDisplay display |
35 |
| - ) { |
36 |
| - super(context, listener, hourOfDay, minute, is24HourView); |
37 |
| - mTimePickerInterval = minuteInterval; |
38 |
| - mTimeSetListener = listener; |
39 |
| - mDisplay = display; |
40 |
| - mContext = context; |
41 |
| - } |
42 |
| - |
43 |
| - public CustomTimePickerDialog( |
44 |
| - Context context, |
45 |
| - int theme, |
46 |
| - OnTimeSetListener listener, |
47 |
| - int hourOfDay, |
48 |
| - int minute, |
49 |
| - int minuteInterval, |
50 |
| - boolean is24HourView, |
51 |
| - RNTimePickerDisplay display |
52 |
| - ) { |
53 |
| - super(context, theme, listener, hourOfDay, minute, is24HourView); |
54 |
| - mTimePickerInterval = minuteInterval; |
55 |
| - mTimeSetListener = listener; |
56 |
| - mDisplay = display; |
57 |
| - mContext = context; |
58 |
| - } |
59 |
| - |
60 |
| - /** |
61 |
| - * Converts values returned from picker to actual minutes |
62 |
| - * |
63 |
| - * @param minute the internal value of what the user had selected on picker |
64 |
| - * @return returns 'real' minutes (0-59) |
65 |
| - */ |
66 |
| - private int getRealMinutes(int minute) { |
67 |
| - if (mDisplay == RNTimePickerDisplay.SPINNER) { |
68 |
| - return minute * mTimePickerInterval; |
| 16 | + private TimePicker mTimePicker; |
| 17 | + private int mTimePickerInterval; |
| 18 | + private RNTimePickerDisplay mDisplay; |
| 19 | + private final OnTimeSetListener mTimeSetListener; |
| 20 | + private Handler handler = new Handler(); |
| 21 | + private Runnable runnable; |
| 22 | + private Context mContext; |
| 23 | + |
| 24 | + public CustomTimePickerDialog( |
| 25 | + Context context, |
| 26 | + OnTimeSetListener listener, |
| 27 | + int hourOfDay, |
| 28 | + int minute, |
| 29 | + int minuteInterval, |
| 30 | + boolean is24HourView, |
| 31 | + RNTimePickerDisplay display |
| 32 | + ) { |
| 33 | + super(context, listener, hourOfDay, minute, is24HourView); |
| 34 | + mTimePickerInterval = minuteInterval; |
| 35 | + mTimeSetListener = listener; |
| 36 | + mDisplay = display; |
| 37 | + mContext = context; |
69 | 38 | }
|
70 | 39 |
|
71 |
| - return minute; |
72 |
| - } |
| 40 | + public CustomTimePickerDialog( |
| 41 | + Context context, |
| 42 | + int theme, |
| 43 | + OnTimeSetListener listener, |
| 44 | + int hourOfDay, |
| 45 | + int minute, |
| 46 | + int minuteInterval, |
| 47 | + boolean is24HourView, |
| 48 | + RNTimePickerDisplay display |
| 49 | + ) { |
| 50 | + super(context, theme, listener, hourOfDay, minute, is24HourView); |
| 51 | + mTimePickerInterval = minuteInterval; |
| 52 | + mTimeSetListener = listener; |
| 53 | + mDisplay = display; |
| 54 | + mContext = context; |
| 55 | + } |
73 | 56 |
|
74 |
| - /** |
75 |
| - * 'Snaps' real minutes to nearest valid value |
76 |
| - * |
77 |
| - * @param realMinutes 'real' minutes (0-59) |
78 |
| - * @return nearest valid value |
79 |
| - */ |
80 |
| - private int snapMinutesToInterval(int realMinutes) { |
81 |
| - float stepsInMinutes = (float) realMinutes / (float) mTimePickerInterval; |
| 57 | + /** |
| 58 | + * Converts values returned from picker to actual minutes |
| 59 | + * |
| 60 | + * @param minute the internal value of what the user had selected on picker |
| 61 | + * @return returns 'real' minutes (0-59) |
| 62 | + */ |
| 63 | + private int getRealMinutes(int minute) { |
| 64 | + if (mDisplay == RNTimePickerDisplay.SPINNER) { |
| 65 | + return minute * mTimePickerInterval; |
| 66 | + } |
82 | 67 |
|
83 |
| - if (mDisplay == RNTimePickerDisplay.SPINNER) { |
84 |
| - return Math.round(stepsInMinutes); |
| 68 | + return minute; |
85 | 69 | }
|
86 | 70 |
|
87 |
| - return Math.round(stepsInMinutes) * mTimePickerInterval; |
88 |
| - } |
89 |
| - |
90 |
| - /** |
91 |
| - * Determines if real minutes align setted minuteInterval |
92 |
| - * |
93 |
| - * @param realMinutes 'real' minutes (0-59) |
94 |
| - */ |
95 |
| - private boolean minutesAreInvalid(int realMinutes) { |
96 |
| - return realMinutes % mTimePickerInterval != 0; |
97 |
| - } |
98 |
| - |
99 |
| - /** |
100 |
| - * Determines if the picker is in text input mode (keyboard icon in 'clock' mode) |
101 |
| - */ |
102 |
| - private boolean pickerIsInTextInputMode() { |
103 |
| - int textInputPickerId = mContext.getResources().getIdentifier("input_mode", "id", "android"); |
104 |
| - final View textInputPicker = this.findViewById(textInputPickerId); |
105 |
| - |
106 |
| - return textInputPicker != null && textInputPicker.hasFocus(); |
107 |
| - } |
108 |
| - |
109 |
| - /** |
110 |
| - * Corrects minute values if they don't align with minuteInterval |
111 |
| - * |
112 |
| - * If the picker is in text input mode, correction will be postponed slightly to let the user |
113 |
| - * finish the input |
114 |
| - * |
115 |
| - * If the picker is not in text input mode, correction will take place immidiately |
116 |
| - * |
117 |
| - * @param view the picker's view |
118 |
| - * @param hourOfDay the picker's selected hours |
119 |
| - * @param realMinutes 'real' minutes (0-59) |
120 |
| - */ |
121 |
| - private void correctEnteredMinutes(final TimePicker view, final int hourOfDay, final int realMinutes) { |
122 |
| - if (pickerIsInTextInputMode()) { |
123 |
| - final EditText textInput = (EditText) view.findFocus(); |
124 |
| - |
125 |
| - // 'correction' callback |
126 |
| - runnable = new Runnable() { |
127 |
| - @Override |
128 |
| - public void run() { |
129 |
| - // set valid minutes && move caret to the end of input |
130 |
| - view.setCurrentMinute(snapMinutesToInterval(realMinutes)); |
131 |
| - view.setCurrentHour(hourOfDay); |
132 |
| - textInput.setSelection(textInput.getText().length()); |
| 71 | + /** |
| 72 | + * 'Snaps' real minutes to nearest valid value |
| 73 | + * |
| 74 | + * @param realMinutes 'real' minutes (0-59) |
| 75 | + * @return nearest valid value |
| 76 | + */ |
| 77 | + private int snapMinutesToInterval(int realMinutes) { |
| 78 | + float stepsInMinutes = (float) realMinutes / (float) mTimePickerInterval; |
| 79 | + |
| 80 | + if (mDisplay == RNTimePickerDisplay.SPINNER) { |
| 81 | + return Math.round(stepsInMinutes); |
133 | 82 | }
|
134 |
| - }; |
135 | 83 |
|
136 |
| - handler.postDelayed(runnable, 500); |
137 |
| - return; |
| 84 | + return Math.round(stepsInMinutes) * mTimePickerInterval; |
138 | 85 | }
|
139 | 86 |
|
140 |
| - view.setCurrentMinute(snapMinutesToInterval(realMinutes)); |
141 |
| - view.setCurrentHour(hourOfDay); |
142 |
| - } |
| 87 | + /** |
| 88 | + * Determines if real minutes align setted minuteInterval |
| 89 | + * |
| 90 | + * @param realMinutes 'real' minutes (0-59) |
| 91 | + */ |
| 92 | + private boolean minutesAreInvalid(int realMinutes) { |
| 93 | + return realMinutes % mTimePickerInterval != 0; |
| 94 | + } |
143 | 95 |
|
144 |
| - @Override |
145 |
| - public void onTimeChanged(final TimePicker view, final int hourOfDay, final int minute) { |
146 |
| - final int realMinutes = getRealMinutes(minute); |
| 96 | + /** |
| 97 | + * Determines if the picker is in text input mode (keyboard icon in 'clock' mode) |
| 98 | + */ |
| 99 | + private boolean pickerIsInTextInputMode() { |
| 100 | + int textInputPickerId = mContext.getResources().getIdentifier("input_mode", "id", "android"); |
| 101 | + final View textInputPicker = this.findViewById(textInputPickerId); |
147 | 102 |
|
148 |
| - // remove pending 'validation' callbacks if any |
149 |
| - handler.removeCallbacks(runnable); |
| 103 | + return textInputPicker != null && textInputPicker.hasFocus(); |
| 104 | + } |
150 | 105 |
|
151 |
| - if (minutesAreInvalid(realMinutes)) { |
152 |
| - correctEnteredMinutes(view, hourOfDay, realMinutes); |
153 |
| - return; |
| 106 | + /** |
| 107 | + * Corrects minute values if they don't align with minuteInterval |
| 108 | + * <p> |
| 109 | + * If the picker is in text input mode, correction will be postponed slightly to let the user |
| 110 | + * finish the input |
| 111 | + * <p> |
| 112 | + * If the picker is not in text input mode, correction will take place immidiately |
| 113 | + * |
| 114 | + * @param view the picker's view |
| 115 | + * @param hourOfDay the picker's selected hours |
| 116 | + * @param realMinutes 'real' minutes (0-59) |
| 117 | + */ |
| 118 | + private void correctEnteredMinutes(final TimePicker view, final int hourOfDay, final int realMinutes) { |
| 119 | + if (pickerIsInTextInputMode()) { |
| 120 | + final EditText textInput = (EditText) view.findFocus(); |
| 121 | + |
| 122 | + // 'correction' callback |
| 123 | + runnable = new Runnable() { |
| 124 | + @Override |
| 125 | + public void run() { |
| 126 | + // set valid minutes && move caret to the end of input |
| 127 | + view.setCurrentMinute(snapMinutesToInterval(realMinutes)); |
| 128 | + view.setCurrentHour(hourOfDay); |
| 129 | + textInput.setSelection(textInput.getText().length()); |
| 130 | + } |
| 131 | + }; |
| 132 | + |
| 133 | + handler.postDelayed(runnable, 500); |
| 134 | + return; |
| 135 | + } |
| 136 | + |
| 137 | + view.setCurrentMinute(snapMinutesToInterval(realMinutes)); |
| 138 | + view.setCurrentHour(hourOfDay); |
154 | 139 | }
|
155 | 140 |
|
156 |
| - super.onTimeChanged(view, hourOfDay, realMinutes); |
157 |
| - } |
| 141 | + @Override |
| 142 | + public void onTimeChanged(final TimePicker view, final int hourOfDay, final int minute) { |
| 143 | + final int realMinutes = getRealMinutes(minute); |
158 | 144 |
|
159 |
| - @Override |
160 |
| - public void onClick(DialogInterface dialog, int which) { |
161 |
| - switch (which) { |
162 |
| - case BUTTON_POSITIVE: |
163 |
| - final int hours = mTimePicker.getCurrentHour(); |
164 |
| - final int realMinutes = getRealMinutes(mTimePicker.getCurrentMinute()); |
165 |
| - int minutesToCallListenerWith = realMinutes; |
| 145 | + // remove pending 'validation' callbacks if any |
| 146 | + handler.removeCallbacks(runnable); |
166 | 147 |
|
167 |
| - if (pickerIsInTextInputMode() && minutesAreInvalid(realMinutes)) { |
168 |
| - minutesToCallListenerWith = snapMinutesToInterval(realMinutes); |
| 148 | + if (minutesAreInvalid(realMinutes)) { |
| 149 | + correctEnteredMinutes(view, hourOfDay, realMinutes); |
| 150 | + return; |
169 | 151 | }
|
170 | 152 |
|
171 |
| - if (mTimeSetListener != null) { |
172 |
| - mTimeSetListener.onTimeSet(mTimePicker, hours, minutesToCallListenerWith); |
173 |
| - } |
174 |
| - break; |
175 |
| - case BUTTON_NEGATIVE: |
176 |
| - cancel(); |
177 |
| - break; |
| 153 | + super.onTimeChanged(view, hourOfDay, realMinutes); |
178 | 154 | }
|
179 |
| - } |
180 |
| - |
181 |
| - @Override |
182 |
| - public void updateTime(int hourOfDay, int minuteOfHour) { |
183 |
| - mTimePicker.setCurrentHour(hourOfDay); |
184 |
| - mTimePicker.setCurrentMinute(snapMinutesToInterval(minuteOfHour)); |
185 |
| - } |
186 |
| - |
187 |
| - /** |
188 |
| - * Apply visual style in 'spinner' mode |
189 |
| - * Adjust minutes to correspond selected interval |
190 |
| - */ |
191 |
| - @Override |
192 |
| - public void onAttachedToWindow() { |
193 |
| - super.onAttachedToWindow(); |
194 |
| - |
195 |
| - if (mTimePickerInterval > RNConstants.DEFAULT_TIME_PICKER_INTERVAL) { |
196 |
| - int timePickerId = mContext.getResources().getIdentifier("timePicker", "id", "android"); |
197 |
| - |
198 |
| - mTimePicker = this.findViewById(timePickerId); |
199 |
| - int currentMinute = mTimePicker.getCurrentMinute(); |
200 |
| - |
201 |
| - if (mDisplay == RNTimePickerDisplay.SPINNER) { |
202 |
| - int minutePickerId = mContext.getResources().getIdentifier("minute", "id", "android"); |
203 |
| - NumberPicker minutePicker = this.findViewById(minutePickerId); |
204 |
| - |
205 |
| - minutePicker.setMinValue(0); |
206 |
| - minutePicker.setMaxValue((60 / mTimePickerInterval) - 1); |
207 |
| - |
208 |
| - List<String> displayedValues = new ArrayList<>(); |
209 |
| - for (int i = 0; i < 60; i += mTimePickerInterval) { |
210 |
| - displayedValues.add(String.format("%02d", i)); |
| 155 | + |
| 156 | + @Override |
| 157 | + public void onClick(DialogInterface dialog, int which) { |
| 158 | + if (mTimePickerInterval == RNConstants.DEFAULT_TIME_PICKER_INTERVAL) { |
| 159 | + super.onClick(dialog, which); |
| 160 | + } else { |
| 161 | + switch (which) { |
| 162 | + case BUTTON_POSITIVE: |
| 163 | + final int hours = mTimePicker.getCurrentHour(); |
| 164 | + int minutes = mTimePicker.getCurrentMinute(); |
| 165 | + |
| 166 | + if (mTimePickerInterval > RNConstants.DEFAULT_TIME_PICKER_INTERVAL) { |
| 167 | + final int realMinutes = getRealMinutes(minutes); |
| 168 | + minutes = realMinutes; |
| 169 | + |
| 170 | + if (pickerIsInTextInputMode() && minutesAreInvalid(realMinutes)) { |
| 171 | + minutes = snapMinutesToInterval(realMinutes); |
| 172 | + } |
| 173 | + } |
| 174 | + |
| 175 | + if (mTimeSetListener != null) { |
| 176 | + mTimeSetListener.onTimeSet(mTimePicker, hours, minutes); |
| 177 | + } |
| 178 | + break; |
| 179 | + case BUTTON_NEGATIVE: |
| 180 | + cancel(); |
| 181 | + break; |
| 182 | + } |
211 | 183 | }
|
| 184 | + } |
212 | 185 |
|
213 |
| - minutePicker.setDisplayedValues(displayedValues.toArray(new String[0])); |
214 |
| - } |
| 186 | + @Override |
| 187 | + public void updateTime(int hourOfDay, int minuteOfHour) { |
| 188 | + mTimePicker.setCurrentMinute(snapMinutesToInterval(minuteOfHour)); |
| 189 | + } |
| 190 | + |
| 191 | + /** |
| 192 | + * Apply visual style in 'spinner' mode |
| 193 | + * Adjust minutes to correspond selected interval |
| 194 | + */ |
| 195 | + @Override |
| 196 | + public void onAttachedToWindow() { |
| 197 | + super.onAttachedToWindow(); |
| 198 | + |
| 199 | + if (mTimePickerInterval > RNConstants.DEFAULT_TIME_PICKER_INTERVAL) { |
| 200 | + int timePickerId = mContext.getResources().getIdentifier("timePicker", "id", "android"); |
| 201 | + |
| 202 | + mTimePicker = this.findViewById(timePickerId); |
| 203 | + int currentMinute = mTimePicker.getCurrentMinute(); |
| 204 | + |
| 205 | + if (mDisplay == RNTimePickerDisplay.SPINNER) { |
| 206 | + int minutePickerId = mContext.getResources().getIdentifier("minute", "id", "android"); |
| 207 | + NumberPicker minutePicker = this.findViewById(minutePickerId); |
215 | 208 |
|
216 |
| - mTimePicker.setCurrentMinute(snapMinutesToInterval(currentMinute)); |
| 209 | + minutePicker.setMinValue(0); |
| 210 | + minutePicker.setMaxValue((60 / mTimePickerInterval) - 1); |
| 211 | + |
| 212 | + List<String> displayedValues = new ArrayList<>(); |
| 213 | + for (int i = 0; i < 60; i += mTimePickerInterval) { |
| 214 | + displayedValues.add(String.format("%02d", i)); |
| 215 | + } |
| 216 | + |
| 217 | + minutePicker.setDisplayedValues(displayedValues.toArray(new String[0])); |
| 218 | + } |
| 219 | + |
| 220 | + mTimePicker.setCurrentMinute(snapMinutesToInterval(currentMinute)); |
| 221 | + } |
217 | 222 | }
|
218 |
| - } |
219 | 223 | }
|
0 commit comments