items, @LayoutRes int footerResource, TwinTextItem footer) {
91 | super(context, itemResource, items);
92 | this.itemResource = itemResource;
93 | this.dropDownResource = dropDownResource;
94 | this.footerResource = footerResource;
95 | this.footer = footer;
96 | this.inflater = LayoutInflater.from(context);
97 | }
98 |
99 | /**
100 | * {@inheritDoc}
101 | */
102 | @Override
103 | public View getView(int position, View convertView, ViewGroup parent) {
104 | View view;
105 | if (convertView == null) {
106 | view = inflater.inflate(itemResource, parent, false);
107 | } else {
108 | view = convertView;
109 | }
110 | if(temporarySelection != null && position == getCount()) {
111 | // our inflated view acts as temporaryView:
112 | return setTextsAndCheck(view, temporarySelection, showSecodaryTextInView);
113 | } else {
114 | // we have a normal item, set the texts:
115 | return setTextsAndCheck(view, getItem(position), showSecodaryTextInView);
116 | }
117 | }
118 |
119 | /**
120 | * {@inheritDoc}
121 | */
122 | @Override
123 | public View getDropDownView(int position, View convertView, ViewGroup parent) {
124 | // depending on the position, use super method or create our own
125 | // we don't need to inflate a footer view if it uses the default resource, the superclass will do it:
126 | if(footer == null || footerResource == 0 || position != getCount()-1) {
127 | // we have a normal item or a footer with same resource
128 | return setTextsAndCheck(inflater.inflate(dropDownResource, parent, false), getItem(position), true);
129 | } else {
130 | // if we want the footer, create it:
131 | return setTextsAndCheck(inflater.inflate(footerResource, parent, false), footer, true);
132 | }
133 | }
134 |
135 | private View setTextsAndCheck(View view, TwinTextItem item, boolean showSecondaryText) {
136 | if (view == null) throw new IllegalArgumentException(
137 | "The resource passed to constructor or setItemResource()/setFooterResource() is invalid");
138 | final TextView primaryText = (TextView) view.findViewById(PRIMARY_TEXT_ID);
139 | if (primaryText == null) throw new IllegalArgumentException(
140 | "The resource passed to constructor or setItemResource()/setFooterResource() does not " +
141 | "contain a textview with id set to android.R.id.text1"
142 | );
143 | primaryText.setText(item.getPrimaryText());
144 | // show a disabled state if the item is disabled
145 | primaryText.setEnabled(item.isEnabled());
146 |
147 | final TextView secondaryText = (TextView) view.findViewById(SECONDARY_TEXT_ID);
148 | if (secondaryText != null) {
149 | if (showSecondaryText)
150 | // Note that we're including the secondary view in the measure even if no secondary text is there.
151 | // The reason is that the spinner should never change its size when an item is selected,
152 | // which would otherwise be possible when a temporary selection (but no other item) has a secondary text.
153 | secondaryText.setText(item.getSecondaryText());
154 | else
155 | secondaryText.setVisibility(View.GONE);
156 | }
157 | return view;
158 | }
159 |
160 | /**
161 | * Push an item to be selected, but not shown in the dropdown menu. This is similar to calling
162 | * setText(item.toString()) if a Spinner had such a method.
163 | * @param item The item to select, or null to remove any temporary selection.
164 | */
165 | public void selectTemporary(TwinTextItem item) {
166 | this.temporarySelection = item;
167 | }
168 |
169 |
170 | /**
171 | * {@inheritDoc}
172 | */
173 | @Override
174 | public TwinTextItem getItem(int position) {
175 | if(temporarySelection != null && position == getCount())
176 | return temporarySelection;
177 | else if(footer != null && position == getCount()-1)
178 | return footer;
179 | else
180 | return super.getItem(position);
181 | }
182 |
183 | /**
184 | * Finds a spinner item by its id value (excluding any temporary selection).
185 | * @param id The id of the item to search.
186 | * @return The specified TwinTextItem, or null if no item with the given id was found.
187 | */
188 | public @Nullable TwinTextItem getItemById(int id) {
189 | for(int index = getCount()-1; index >= 0; index--) {
190 | TwinTextItem item = getItem(index);
191 | if(item.getId() == id)
192 | return item;
193 | }
194 | return null;
195 | }
196 |
197 | /**
198 | * Finds a spinner item's position in the data set by its id value (excluding any temporary selection).
199 | * @param id The id of the item to search.
200 | * @return The position of the specified TwinTextItem, or -1 if no item with the given id was found.
201 | */
202 | public int getItemPosition(int id) {
203 | for(int index = getCount()-1; index >= 0; index--) {
204 | TwinTextItem item = getItem(index);
205 | if(item.getId() == id)
206 | return index;
207 | }
208 | return -1;
209 | }
210 |
211 | /**
212 | * {@inheritDoc}
213 | */
214 | @Override
215 | public int getCount() {
216 | // we need one extra item which is not in the array.
217 | return super.getCount() + (footer==null? 0 : 1);
218 | }
219 |
220 | /**
221 | * {@inheritDoc}
222 | */
223 | @Override
224 | public boolean areAllItemsEnabled() {
225 | return false;
226 | }
227 |
228 | /**
229 | * {@inheritDoc}
230 | */
231 | @Override
232 | public boolean isEnabled(int position) {
233 | return getItem(position).isEnabled();
234 | }
235 |
236 | /**
237 | * Checks if the Spinner will show a footer, previously set using setFooter().
238 | * @return True if there is a footer, false otherwise.
239 | */
240 | public boolean hasFooter() {
241 | return this.footer != null;
242 | }
243 |
244 | /**
245 | * Sets the text to be shown in the footer.
246 | * @param footer An Object whose toString() will be the footer text, or null to disable the footer.
247 | */
248 | public void setFooter(TwinTextItem footer) {
249 | this.footer = footer;
250 | }
251 |
252 | /**
253 | * Sets the layout resource to be inflated as footer. It should contain a TextView with id set
254 | * to android.R.id.text1, where the text will be added.
255 | * @param footerResource A valid xml layout resource, or 0 to use dropDownResource instead.
256 | */
257 | public void setFooterResource(@LayoutRes int footerResource) {
258 | this.footerResource = footerResource;
259 | }
260 |
261 | /**
262 | * Sets the layout resource to create the view.
263 | *
264 | * @param resource the layout resource defining the view, which should contain two text views.
265 | * @see #getDropDownView(int, android.view.View, android.view.ViewGroup)
266 | */
267 | public void setItemResource(@LayoutRes int resource) {
268 | this.itemResource = resource;
269 | }
270 |
271 | /**
272 | * Sets the layout resource to create the drop down views.
273 | *
274 | * @param resource the layout resource defining the drop down views, which should contain two text views.
275 | * @see #getDropDownView(int, android.view.View, android.view.ViewGroup)
276 | */
277 | public void setDropDownViewResource(@LayoutRes int resource) {
278 | this.dropDownResource = resource;
279 | }
280 |
281 | /**
282 | * Enables showing the secondary text in the view. The dropdown view will always include the secondary text.
283 | * @param enable True to enable showing it, false to disable.
284 | */
285 | public void setShowSecondaryTextInView(boolean enable) {
286 | if (showSecodaryTextInView != enable) {
287 | showSecodaryTextInView = enable;
288 | notifyDataSetChanged();
289 | }
290 | }
291 |
292 | /**
293 | * Checks whether showing secondary text in view is enabled for this spinner (defaults to false).
294 | * @return True if this PickerSpinner shows the item's secondary text in the view as well as in
295 | * dropdown, false if only in dropdown.
296 | */
297 | public boolean isShowingSecondaryTextInView() {
298 | return this.showSecodaryTextInView;
299 | }
300 |
301 | private boolean isActivityUsingDarkTheme() {
302 | TypedArray themeArray = getContext().getTheme().obtainStyledAttributes(
303 | new int[] {android.R.attr.textColorPrimary});
304 | int textColor = themeArray.getColor(0, 0);
305 | return brightness(textColor) > 0.5f;
306 | }
307 |
308 | /**
309 | * Returns the brightness component of a color int. Taken from android.graphics.Color.
310 | *
311 | * @return A value between 0.0f and 1.0f
312 | */
313 | private float brightness(int color) {
314 | int r = (color >> 16) & 0xFF;
315 | int g = (color >> 8) & 0xFF;
316 | int b = color & 0xFF;
317 |
318 | int V = Math.max(b, Math.max(r, g));
319 | return (V / 255.f);
320 | }
321 | }
322 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/simplicityapks/reminderdatepicker/lib/ReminderDatePicker.java:
--------------------------------------------------------------------------------
1 | package com.simplicityapks.reminderdatepicker.lib;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.os.Build;
7 | import android.os.Parcelable;
8 | import android.support.annotation.Nullable;
9 | import android.util.AttributeSet;
10 | import android.view.Gravity;
11 | import android.view.LayoutInflater;
12 | import android.view.View;
13 | import android.widget.AdapterView;
14 | import android.widget.ImageButton;
15 | import android.widget.LinearLayout;
16 |
17 | import com.fourmob.datetimepicker.date.DatePickerDialog;
18 | import com.sleepbot.datetimepicker.time.TimePickerDialog;
19 |
20 | import java.util.Calendar;
21 | import java.util.GregorianCalendar;
22 |
23 | /**
24 | * A Google Keep like date and time picker for reminders, to be inflated via xml or constructor.
25 | * Holds both DateSpinner and TimeSpinner and takes care of handling selection layout changes.
26 | *
27 | * Refer to the project's github page for official documentation.
28 | */
29 | public class ReminderDatePicker extends LinearLayout implements AdapterView.OnItemSelectedListener{
30 |
31 | /**
32 | * Mode for {@link #setFlags(int)}. Base mode, same items as in the Google Keep app.
33 | */
34 | public static final int MODE_GOOGLE = 0; // 000000
35 |
36 | /**
37 | * Mode for {@link #setFlags(int)}. Include all possible items and show numbers in the time spinner.
38 | */
39 | public static final int MODE_EVERYTHING = 31; // 011111
40 |
41 | /**
42 | * Flag for {@link #setFlags(int)}. Include a yesterday and last weekday item.
43 | */
44 | public static final int FLAG_PAST = 1; // 000001
45 |
46 | /**
47 | * Flag for {@link #setFlags(int)}. Include a month item exactly one month from today.
48 | */
49 | public static final int FLAG_MONTH = 2; // 000010
50 |
51 | /**
52 | * Flag for {@link #setFlags(int)}. Include a noon and late night item in the time spinner.
53 | */
54 | public static final int FLAG_MORE_TIME = 4; // 000100
55 |
56 | /**
57 | * Flag for {@link #setFlags(int)}. Show numeric time in the time spinner view and in the date
58 | * spinner view when a day within the next week is shown with FLAG_WEEKDAY_NAMES. Note that time
59 | * will always be shown in dropdown.
60 | */
61 | public static final int FLAG_NUMBERS = 8; // 001000
62 |
63 | /**
64 | * Flag for {@link #setFlags(int)}. Show the weekday name when a date within the next week is
65 | * selected instead of the standard date format.
66 | */
67 | public static final int FLAG_WEEKDAY_NAMES = 16; // 010000
68 |
69 | /**
70 | * Flag for {@link #setFlags(int)}. Hide the time picker and show a button to show it.
71 | */
72 | public static final int FLAG_HIDE_TIME = 32; // 100000
73 |
74 | // has FLAG_HIDE_TIME been set?
75 | private boolean shouldHideTime = false;
76 |
77 | private DateSpinner dateSpinner;
78 | private TimeSpinner timeSpinner;
79 |
80 | // This listener doesn't have to be implemented, if it is null just ignore it
81 | private OnDateSelectedListener listener = null;
82 |
83 | // To catch twice selecting the same date:
84 | private Calendar lastSelectedDate = null;
85 |
86 | // To keep track whether we need to selectDefaultDate in onAttachToWindow():
87 | private boolean shouldSelectDefault = true;
88 |
89 | /**
90 | * Construct a new ReminderDatePicker with the given context's theme but without any flags.
91 | * @param context The Context the view is running in, through which it can access the current theme, resources, etc.
92 | */
93 | public ReminderDatePicker(Context context) {
94 | this(context, null);
95 | }
96 |
97 | /**
98 | * Construct a new ReminderDatePicker with the given context's theme and the supplied attribute set.
99 | * @param context The Context the view is running in, through which it can access the current theme, resources, etc.
100 | * @param attrs The attributes of the XML tag that is inflating the view. May contain a flags attribute.
101 | */
102 | public ReminderDatePicker(Context context, AttributeSet attrs) {
103 | super(context, attrs);
104 | init(context, attrs);
105 | }
106 |
107 | /**
108 | * Construct a new ReminderDatePicker with the given context's theme and the supplied attribute set.
109 | * @param context The Context the view is running in, through which it can access the current theme, resources, etc.
110 | * @param attrs The attributes of the XML tag that is inflating the view. May contain a flags attribute.
111 | * @param defStyle The default style to apply to this view. If 0, no style will be applied (beyond
112 | * what is included in the theme). This may either be an attribute resource, whose
113 | * value will be retrieved from the current theme, or an explicit style resource.
114 | */
115 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
116 | public ReminderDatePicker(Context context, AttributeSet attrs, int defStyle) {
117 | super(context, attrs, defStyle);
118 | init(context, attrs);
119 | // Additional styling work is done here
120 | }
121 |
122 | private void init(Context context, AttributeSet attrs) {
123 | View.inflate(context, R.layout.reminder_date_picker, this);
124 | dateSpinner = (DateSpinner) findViewById(R.id.date_spinner);
125 | dateSpinner.setOnItemSelectedListener(this);
126 |
127 | timeSpinner = (TimeSpinner) findViewById(R.id.time_spinner);
128 | timeSpinner.setOnItemSelectedListener(this);
129 | // check if the parent activity has our dateSelectedListener, automatically enable it:
130 | if(context instanceof OnDateSelectedListener)
131 | setOnDateSelectedListener((OnDateSelectedListener) context);
132 |
133 | // set gravity, for the timeButton when th eTimeSpinner is hidden:
134 | setGravity(Gravity.CENTER_VERTICAL);
135 |
136 | if(attrs != null) {
137 | // get our flags from xml, if set:
138 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ReminderDatePicker);
139 | int flags = a.getInt(R.styleable.ReminderDatePicker_flags, MODE_GOOGLE);
140 | setFlags(flags);
141 | a.recycle();
142 | }
143 | }
144 |
145 | @Override
146 | protected void onRestoreInstanceState(Parcelable state) {
147 | super.onRestoreInstanceState(state);
148 | if(state != null)
149 | shouldSelectDefault = false;
150 | }
151 |
152 | @Override
153 | protected void onAttachedToWindow() {
154 | super.onAttachedToWindow();
155 | // we may need to initialize the selected date
156 | if(shouldSelectDefault)
157 | selectDefaultDate();
158 | }
159 |
160 | /**
161 | * Selects the next best date (and time) after today.
162 | * Requires that the items are in ascending order (and that there is at least one item to select).
163 | */
164 | private void selectDefaultDate() {
165 | Calendar today = Calendar.getInstance();
166 | int hour = -1, minute = -1;
167 |
168 | // get the next possible selection
169 | Calendar date = getNextItemDate(today);
170 | // if it is the today item, we need to take a look the time
171 | if(date != null && DateSpinner.compareCalendarDates(date, today) == 0) {
172 | // same as getNextTimeDate for TimeSpinner
173 | final int last = timeSpinner.getLastItemPosition();
174 | final int searchHour = today.get(Calendar.HOUR_OF_DAY),
175 | searchMinute = today.get(Calendar.MINUTE);
176 | for (int i=0; i<=last; i++) {
177 | final TimeItem time = ((TimeItem) timeSpinner.getItemAtPosition(i));
178 | if(time.getHour() > searchHour || (time.getHour() == searchHour && time.getMinute() >= searchMinute)) {
179 | hour = time.getHour();
180 | minute = time.getMinute();
181 | break;
182 | }
183 | }
184 |
185 | // it may be too late in the evening to select the today item
186 | // or if FLAG_HIDE_TIME has been set, set it to tomorrow morning:
187 | if((hour == -1 && minute == -1) || shouldHideTime) {
188 | Calendar tomorrow = (Calendar) today.clone();
189 | tomorrow.add(Calendar.DAY_OF_YEAR, 1);
190 | date = getNextItemDate(tomorrow); // if this returns null it'll be set to today below
191 | }
192 | }
193 | if(date == null) {
194 | // it seems this spinner only contains past items, use the last one
195 | date = ((DateItem) dateSpinner.getItemAtPosition(dateSpinner.getLastItemPosition())).getDate();
196 | }
197 |
198 | if(hour == -1 && minute == -1) {
199 | // the date is not today, just select the earliest possible time
200 | final TimeItem time = ((TimeItem) timeSpinner.getItemAtPosition(0));
201 | hour = time.getHour();
202 | minute = time.getMinute();
203 | }
204 |
205 | // finally, select what we found
206 | date.set(Calendar.HOUR_OF_DAY, hour);
207 | date.set(Calendar.MINUTE, minute);
208 | setSelectedDate(date);
209 | }
210 |
211 | /**
212 | * Gets the next date item's date equal to or later than the given date in the DateSpinner.
213 | * Requires that the items are in ascending order.
214 | * @return A date from the next item in the DateSpinner, or no such date was found.
215 | */
216 | private @Nullable Calendar getNextItemDate(Calendar searchDate) {
217 | final int last = dateSpinner.getLastItemPosition();
218 | for (int i=0; i<=last; i++) {
219 | final Calendar date = ((DateItem) dateSpinner.getItemAtPosition(i)).getDate();
220 | // use the DateSpinner's compare method so hours and minutes are not considered
221 | if(DateSpinner.compareCalendarDates(date, searchDate) >= 0)
222 | return date;
223 | }
224 | // not found
225 | return null;
226 | }
227 |
228 | /**
229 | * Gets the currently selected date (that the Spinners are showing)
230 | * @return The selected date as Calendar, or null if there is none.
231 | */
232 | public Calendar getSelectedDate() {
233 | Calendar result = dateSpinner.getSelectedDate();
234 | Calendar time = timeSpinner.getSelectedTime();
235 | if(result!=null && time!=null) {
236 | result.set(Calendar.HOUR_OF_DAY, time.get(Calendar.HOUR_OF_DAY));
237 | result.set(Calendar.MINUTE, time.get(Calendar.MINUTE));
238 | return result;
239 | }
240 | else return null;
241 | }
242 |
243 | /**
244 | * Sets the Spinners' selection as date considering both time and day.
245 | * @param date The date to be selected.
246 | */
247 | public void setSelectedDate(Calendar date) {
248 | if(date!=null) {
249 | dateSpinner.setSelectedDate(date);
250 | timeSpinner.setSelectedTime(date.get(Calendar.HOUR_OF_DAY), date.get(Calendar.MINUTE));
251 | // a custom selection has been set, don't select the default date:
252 | shouldSelectDefault = false;
253 | }
254 | }
255 |
256 | /**
257 | * Sets the Spinners' date selection as integers considering only day.
258 | */
259 | public void setSelectedDate(int year, int month, int day) {
260 | dateSpinner.setSelectedDate(new GregorianCalendar(year, month, day));
261 | // a custom selection has been set, don't select the default date:
262 | shouldSelectDefault = false;
263 | }
264 |
265 | /**
266 | * Sets the Spinners' time selection as integers considering only time.
267 | */
268 | public void setSelectedTime(int hour, int minute) {
269 | timeSpinner.setSelectedTime(hour, minute);
270 | // a custom selection has been set, don't select the default date:
271 | shouldSelectDefault = false;
272 | }
273 |
274 | /**
275 | * Implement this interface if you want to be notified whenever the selected date changes.
276 | */
277 | public void setOnDateSelectedListener(OnDateSelectedListener listener) {
278 | this.listener = listener;
279 | }
280 |
281 | /**
282 | * Gets the default {@link DatePickerDialog} that is shown when the footer in the DateSpinner is clicked.
283 | * @return The dialog, or null if a custom date picker has been set and the default one is thus unused.
284 | */
285 | public @Nullable DatePickerDialog getDatePickerDialog() {
286 | return dateSpinner.getDatePickerDialog();
287 | }
288 |
289 | /**
290 | * Gets the default {@link TimePickerDialog} that is shown when the footer in the TimeSpinner is clicked.
291 | * @return The dialog, or null if a custom time picker has been set and the default one is thus unused.
292 | */
293 | public @Nullable TimePickerDialog getTimePickerDialog() {
294 | return timeSpinner.getTimePickerDialog();
295 | }
296 |
297 | /**
298 | * Sets a custom listener whose onClick method will be called to create and handle the custom date picker.
299 | * You should call {@link #setSelectedDate(int, int, int)} when the custom picker is finished.
300 | * @param launchPicker An {@link android.view.View.OnClickListener} whose onClick method will be
301 | * called to show the custom date picker, or null to use the default picker.
302 | */
303 | public void setCustomDatePicker(@Nullable OnClickListener launchPicker) {
304 | dateSpinner.setCustomDatePicker(launchPicker);
305 | }
306 |
307 | /**
308 | * Sets a custom listener whose onClick method will be called to create and handle the custom time picker.
309 | * You should call {@link #setSelectedTime} when the custom picker is finished.
310 | * @param launchPicker An {@link android.view.View.OnClickListener} whose onClick method will be
311 | * called to show the custom time picker, or null to use the default picker.
312 | */
313 | public void setCustomTimePicker(@Nullable OnClickListener launchPicker) {
314 | timeSpinner.setCustomTimePicker(launchPicker);
315 | }
316 |
317 | /**
318 | * Checks if the time spinner is currently invisible (with {@link #FLAG_HIDE_TIME}), so the user didn't choose a time.
319 | * @return True if the time is not visible, false otherwise.
320 | */
321 | public boolean isTimeHidden() {
322 | return timeSpinner.getVisibility() == GONE;
323 | }
324 |
325 | /**
326 | * Toggles hiding the Time Spinner and replaces it with a Button.
327 | * @param enable True to hide the Spinner, false to show it.
328 | * @param useDarkTheme True if a white icon shall be used, false for a dark one.
329 | */
330 | public void setHideTime(boolean enable, final boolean useDarkTheme) {
331 | if(enable && !shouldHideTime) {
332 | // hide the time spinner and show a button to show it instead
333 | timeSpinner.setVisibility(GONE);
334 | ImageButton timeButton = (ImageButton) LayoutInflater.from(getContext()).inflate(R.layout.time_button, null);
335 | timeButton.setImageResource(useDarkTheme ? R.drawable.ic_action_time_dark : R.drawable.ic_action_time_light);
336 | timeButton.setOnClickListener(new OnClickListener() {
337 | @Override
338 | public void onClick(View v) {
339 | setHideTime(false, useDarkTheme);
340 | }
341 | });
342 | this.addView(timeButton);
343 | } else if(!enable && shouldHideTime) {
344 | timeSpinner.setVisibility(VISIBLE);
345 | this.removeViewAt(2);
346 | }
347 | shouldHideTime = enable;
348 | }
349 |
350 | private boolean isActivityUsingDarkTheme() {
351 | TypedArray themeArray = getContext().getTheme().obtainStyledAttributes(
352 | new int[] {android.R.attr.textColorPrimary});
353 | int textColor = themeArray.getColor(0, 0);
354 | return brightness(textColor) > 0.5f;
355 | }
356 |
357 | /**
358 | * Returns the brightness component of a color int. Taken from android.graphics.Color.
359 | *
360 | * @return A value between 0.0f and 1.0f
361 | */
362 | private float brightness(int color) {
363 | int r = (color >> 16) & 0xFF;
364 | int g = (color >> 8) & 0xFF;
365 | int b = color & 0xFF;
366 |
367 | int V = Math.max(b, Math.max(r, g));
368 | return (V / 255.f);
369 | }
370 |
371 | /**
372 | * Gets the custom DateFormat currently used in the DateSpinner to format Calendar strings.
373 | * If {@link #setDateFormat(java.text.DateFormat)} has not been called yet, it will return null.
374 | * @return The time format, or null if the Spinner is using the default date format.
375 | */
376 | public java.text.DateFormat getCustomDateFormat() {
377 | return dateSpinner.getCustomDateFormat();
378 | }
379 |
380 | /**
381 | * Sets the custom date format to use for formatting Calendar objects to displayable strings in the DateSpinner.
382 | * @param dateFormat The new DateFormat, or null to use the default format.
383 | */
384 | public void setDateFormat(java.text.DateFormat dateFormat) {
385 | dateSpinner.setDateFormat(dateFormat);
386 | }
387 |
388 | /**
389 | * Gets the time format (as java.text.DateFormat) currently used in the TimeSpinner to format Calendar strings.
390 | * Defaults to the short time instance for your locale.
391 | * @return The time format, which will never be null.
392 | */
393 | public java.text.DateFormat getTimeFormat() {
394 | return timeSpinner.getTimeFormat();
395 | }
396 |
397 | /**
398 | * Sets the time format to use for formatting Calendar objects to displayable strings in the TimeSpinner.
399 | * @param timeFormat The new time format (as java.text.DateFormat), or null to use the default format.
400 | */
401 | public void setTimeFormat(java.text.DateFormat timeFormat) {
402 | timeSpinner.setTimeFormat(timeFormat);
403 | }
404 |
405 |
406 | /**
407 | * Sets the minimum allowed date for the DateSpinner.
408 | * Spinner items and dates in the date picker before the given date will get disabled.
409 | * Does not affect the TimeSpinner.
410 | * @param minDate The minimum date, or null to clear the previous min date.
411 | */
412 | public void setMinDate(@Nullable Calendar minDate) {
413 | dateSpinner.setMinDate(minDate);
414 | }
415 |
416 | /**
417 | * Gets the current minimum allowed date for the DateSpinner.
418 | * @return The minimum date, or null if there is none.
419 | */
420 | public @Nullable Calendar getMinDate() {
421 | return dateSpinner.getMinDate();
422 | }
423 |
424 | /**
425 | * Sets the maximum allowed date for the DateSpinner.
426 | * Spinner items and dates in the date picker before the given date will get disabled.
427 | * Does not affect the TimeSpinner.
428 | * @param maxDate The maximum date, or null to clear the previous max date.
429 | */
430 | public void setMaxDate(@Nullable Calendar maxDate) {
431 | dateSpinner.setMaxDate(maxDate);
432 | }
433 |
434 | /**
435 | * Gets the current maximum allowed date for the DateSpinner.
436 | * @return The maximum date, or null if there is none.
437 | */
438 | public @Nullable Calendar getMaxDate() {
439 | return dateSpinner.getMaxDate();
440 | }
441 |
442 |
443 | /**
444 | * Set the flags to use for the picker.
445 | * @param modeOrFlags A mode of ReminderDatePicker.MODE_... or multiple ReminderDatePicker.FLAG_...
446 | * combined with the | operator.
447 | */
448 | public void setFlags(int modeOrFlags) {
449 | // check each flag and pass it on if needed:
450 | setHideTime((modeOrFlags & FLAG_HIDE_TIME) != 0, isActivityUsingDarkTheme());
451 | dateSpinner.setFlags(modeOrFlags);
452 | timeSpinner.setFlags(modeOrFlags);
453 | }
454 |
455 | @Override
456 | public void onItemSelected(AdapterView> parent, View view, int position, long id) {
457 | // An item has been selected in one of our child spinners, so get the selected Date and call the listeners
458 | if(listener != null) {
459 | // catch selecting same date twice
460 | Calendar date = getSelectedDate();
461 | if(date != null && !date.equals(lastSelectedDate)) {
462 | listener.onDateSelected(date);
463 | lastSelectedDate = date;
464 | }
465 | }
466 | }
467 |
468 | // unused
469 | @Override
470 | public void onNothingSelected(AdapterView> parent) {
471 | }
472 | }
473 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/simplicityapks/reminderdatepicker/lib/TimeItem.java:
--------------------------------------------------------------------------------
1 | package com.simplicityapks.reminderdatepicker.lib;
2 |
3 | import java.util.Calendar;
4 |
5 | /**
6 | * Object to be inserted into the ArrayAdapter of the TimeSpinner. The time is saved as well as a label.
7 | */
8 | public class TimeItem implements TwinTextItem {
9 |
10 | private final String label, digitalTime;
11 | private final int hour, minute, id;
12 | private boolean enabled = true;
13 |
14 | /**
15 | * Constructs a new TimeItem holding the specified time and a label to show primarily.
16 | * @param label The String to return when getPrimaryText() is called, but the first text in brackets is set as secondary text.
17 | * @param time The time to be returned by getTime(), as Calendar.
18 | * @param id The identifier to find this item with.
19 | */
20 | public TimeItem(String label, Calendar time, int id) {
21 | this(label, time.get(Calendar.HOUR_OF_DAY), time.get(Calendar.MINUTE), id);
22 | }
23 |
24 | /**
25 | * Constructs a new TimeItem holding the specified time and a label to to show primarily.
26 | * @param label The String to return when getPrimaryText() is called, but the first text in brackets is set as secondary text.
27 | * @param hour The hour of the day.
28 | * @param minute The minute of the hour.
29 | * @param id The identifier to find this item with.
30 | */
31 | public TimeItem(String label, int hour, int minute, int id) {
32 | this.hour = hour;
33 | this.minute = minute;
34 | this.id = id;
35 |
36 | // parse the digital time from the label and set both label and digitalTime:
37 | int timeStart = label.indexOf('(');
38 | int timeEnd = label.indexOf(')');
39 | if(timeStart>0 || timeEnd>0) {
40 | digitalTime = label.substring(timeStart+1, timeEnd);
41 | this.label = label.substring(0, timeStart) + label.substring(timeEnd+1);
42 | } else {
43 | // something went wrong, assume that label is only the primary text:
44 | digitalTime = null;
45 | this.label = label;
46 | }
47 | }
48 |
49 | /**
50 | * Constructs a new TimeItem holding the specified time and a label to to show primarily.
51 | * @param label The String to return when getPrimaryText() is called.
52 | * @param timeString The String to return when getSecondaryText() is called.
53 | * @param hour The hour of the day.
54 | * @param minute The minute of the hour.
55 | * @param id The identifier to find this item with.
56 | */
57 | public TimeItem(String label, String timeString, int hour, int minute, int id) {
58 | this.label = label;
59 | this.digitalTime = timeString;
60 | this.hour = hour;
61 | this.minute = minute;
62 | this.id = id;
63 | }
64 |
65 | /**
66 | * Gets the current time set in this TimeItem.
67 | * @return A new Calendar containing the time.
68 | */
69 | public Calendar getTime() {
70 | Calendar result = Calendar.getInstance();
71 | result.set(Calendar.HOUR_OF_DAY, hour);
72 | result.set(Calendar.MINUTE, minute);
73 | return result;
74 | }
75 |
76 | /**
77 | * Gets the hour set for this TimeItem.
78 | * @return The hour, as int.
79 | */
80 | public int getHour() {
81 | return this.hour;
82 | }
83 |
84 | /**
85 | * Gets the minute set for this TimeItem.
86 | * @return The minute, as int.
87 | */
88 | public int getMinute() {
89 | return this.minute;
90 | }
91 |
92 | /**
93 | * Deeply compares this TimeItem to the specified Object. Returns true if obj is a TimeItem and
94 | * contains the same date (ignoring the label) or is a Calendar and contains the same hour and minute.
95 | * @param obj The Object to compare this to.
96 | * @return true if equal, false otherwise.
97 | */
98 | @Override
99 | public boolean equals(Object obj) {
100 | int objHour, objMinute;
101 | if(obj instanceof TimeItem) {
102 | TimeItem item = (TimeItem) obj;
103 | objHour = item.getHour();
104 | objMinute = item.getMinute();
105 | }
106 | else if(obj instanceof Calendar) {
107 | Calendar cal = (Calendar) obj;
108 | objHour = cal.get(Calendar.HOUR_OF_DAY);
109 | objMinute = cal.get(Calendar.MINUTE);
110 | }
111 | else return false;
112 | return objHour==this.hour && objMinute==this.minute;
113 | }
114 |
115 | @Override
116 | public CharSequence getPrimaryText() {
117 | return label;
118 | }
119 |
120 | @Override
121 | public CharSequence getSecondaryText() {
122 | return digitalTime;
123 | }
124 |
125 | @Override
126 | public int getId() {
127 | return id;
128 | }
129 |
130 | @Override
131 | public boolean isEnabled() {
132 | return enabled;
133 | }
134 |
135 | /**
136 | * Enable or disable this spinner item.
137 | * @param enable true to enable, false to disable this item.
138 | */
139 | public void setEnabled(boolean enable) {
140 | this.enabled = enable;
141 | }
142 |
143 | /**
144 | * The returned String may be passed to {@link #fromString(String)} to save and recreate this object easily.
145 | * @return The elements of this object separated by \n
146 | */
147 | @Override
148 | public String toString() {
149 | String sep = "\n";
150 | return nullToEmpty(label) +sep+ nullToEmpty(digitalTime) +sep+ hour +sep+ minute +sep+ id;
151 | }
152 |
153 | /**
154 | * Constructs a new TimeItem from a String previously gotten from the {@link #toString()} method.
155 | * @param code The string to parse from.
156 | * @return A new TimeItem, or null if there was an error.
157 | */
158 | public static TimeItem fromString(String code) {
159 | String[] items = code.split("\n");
160 | if(items.length != 5) return null;
161 | int hour, minute, id;
162 | try {
163 | hour = Integer.parseInt(items[2]);
164 | minute = Integer.parseInt(items[3]);
165 | id = Integer.parseInt(items[4]);
166 | }
167 | catch (NumberFormatException e) {
168 | e.printStackTrace();
169 | return null;
170 | }
171 | return new TimeItem(emptyToNull(items[0]), emptyToNull(items[1]), hour, minute, id);
172 | }
173 |
174 | /**
175 | * Makes sure s is not null, but the empty string instead. Otherwise just return s.
176 | */
177 | private static String nullToEmpty(String s) {
178 | return s==null? "" : s;
179 | }
180 |
181 | /**
182 | * Makes sure s is not an empty string, but null instead. Otherwise just return s.
183 | */
184 | private static String emptyToNull(String s) {
185 | return "".equals(s)? null : s;
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/simplicityapks/reminderdatepicker/lib/TimeSpinner.java:
--------------------------------------------------------------------------------
1 | package com.simplicityapks.reminderdatepicker.lib;
2 |
3 | import android.content.Context;
4 | import android.content.pm.PackageManager;
5 | import android.content.res.Resources;
6 | import android.content.res.TypedArray;
7 | import android.content.res.XmlResourceParser;
8 | import android.support.annotation.NonNull;
9 | import android.support.annotation.Nullable;
10 | import android.support.annotation.StringRes;
11 | import android.support.v4.app.FragmentActivity;
12 | import android.support.v4.app.FragmentManager;
13 | import android.text.format.DateFormat;
14 | import android.util.AttributeSet;
15 | import android.util.Log;
16 | import android.view.View;
17 | import android.widget.AdapterView;
18 |
19 | import com.sleepbot.datetimepicker.time.RadialPickerLayout;
20 | import com.sleepbot.datetimepicker.time.TimePickerDialog;
21 |
22 | import java.text.SimpleDateFormat;
23 | import java.util.Calendar;
24 | import java.util.GregorianCalendar;
25 | import java.util.List;
26 |
27 | /**
28 | * The right PickerSpinner of the Google Keep app, to select a time within one day.
29 | */
30 | public class TimeSpinner extends PickerSpinner implements AdapterView.OnItemSelectedListener {
31 |
32 | public static final String XML_TAG_TIMEITEM = "TimeItem";
33 |
34 | public static final String XML_ATTR_ABSHOUR = "absHour";
35 | public static final String XML_ATTR_ABSMINUTE= "absMinute";
36 |
37 | public static final String XML_ATTR_RELHOUR = "relHour";
38 | public static final String XML_ATTR_RELMINUTE = "relMinute";
39 |
40 | /**
41 | * Implement this interface if you want to be notified whenever the selected time changes.
42 | */
43 | public interface OnTimeSelectedListener {
44 | void onTimeSelected(int hour, int minute);
45 | }
46 |
47 | // These listeners don't have to be implemented, if null just ignore
48 | private OnTimeSelectedListener timeListener = null;
49 | private OnClickListener customTimePicker = null;
50 |
51 | // The default time picker dialog to show when the custom one is null:
52 | private TimePickerDialog timePickerDialog;
53 | private FragmentManager fragmentManager;
54 |
55 | private boolean showMoreTimeItems = false;
56 |
57 | // The time format used to convert Calendars into displayable Strings:
58 | private java.text.DateFormat timeFormat = null;
59 |
60 | private int lastSelectedHour = -1;
61 | private int lastSelectedMinute = -1;
62 |
63 | /**
64 | * Construct a new TimeSpinner with the given context's theme.
65 | * @param context The Context the view is running in, through which it can access the current theme, resources, etc.
66 | */
67 | public TimeSpinner(Context context){
68 | this(context, null, 0);
69 | }
70 |
71 | /**
72 | * Construct a new TimeSpinner with the given context's theme and the supplied attribute set.
73 | * @param context The Context the view is running in, through which it can access the current theme, resources, etc.
74 | * @param attrs The attributes of the XML tag that is inflating the view. May contain a flags attribute.
75 | */
76 | public TimeSpinner(Context context, AttributeSet attrs){
77 | this(context, attrs, 0);
78 | }
79 |
80 | /**
81 | * Construct a new TimeSpinner with the given context's theme, the supplied attribute set, and default style.
82 | * @param context The Context the view is running in, through which it can access the current theme, resources, etc.
83 | * @param attrs The attributes of the XML tag that is inflating the view. May contain a flags attribute.
84 | * @param defStyle The default style to apply to this view. If 0, no style will be applied (beyond
85 | * what is included in the theme). This may either be an attribute resource, whose
86 | * value will be retrieved from the current theme, or an explicit style resource.
87 | */
88 | public TimeSpinner(Context context, AttributeSet attrs, int defStyle) {
89 | super(context, attrs, defStyle);
90 | // check if the parent activity has our timeSelectedListener, automatically enable it:
91 | if(context instanceof OnTimeSelectedListener)
92 | setOnTimeSelectedListener((OnTimeSelectedListener) context);
93 | setOnItemSelectedListener(this);
94 |
95 | initTimePickerDialog(context);
96 |
97 | // get the FragmentManager:
98 | try{
99 | fragmentManager = ((FragmentActivity) context).getSupportFragmentManager();
100 | } catch (ClassCastException e) {
101 | Log.d(getClass().getSimpleName(), "Can't get fragment manager from context");
102 | }
103 |
104 | if(attrs != null) {
105 | // get our flags from xml, if set:
106 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ReminderDatePicker);
107 | int flags = a.getInt(R.styleable.ReminderDatePicker_flags, ReminderDatePicker.MODE_GOOGLE);
108 | setFlags(flags);
109 | a.recycle();
110 | }
111 | }
112 |
113 | private void initTimePickerDialog(Context context) {
114 | final Calendar calendar = Calendar.getInstance();
115 | // create the dialog to show later:
116 | timePickerDialog = TimePickerDialog.newInstance(
117 | new TimePickerDialog.OnTimeSetListener() {
118 | @Override
119 | public void onTimeSet(RadialPickerLayout radialPickerLayout, int hour, int minute) {
120 | setSelectedTime(hour, minute);
121 | }
122 | },
123 | calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE),
124 | is24HourFormat(getTimeFormat()), hasVibratePermission(context));
125 | }
126 |
127 | private boolean is24HourFormat(java.text.DateFormat timeFormat) {
128 | String pattern;
129 | try {
130 | pattern = ((SimpleDateFormat) timeFormat).toLocalizedPattern();
131 | } catch (ClassCastException e) {
132 | // we cannot get the pattern, use the default setting for out context:
133 | return DateFormat.is24HourFormat(getContext());
134 | }
135 | // if pattern does not contain the 12 hour formats, we return true (regardless of any 'a' (am/pm) modifier)
136 | return !(pattern.contains("h") || pattern.contains("K"));
137 | }
138 |
139 | private boolean hasVibratePermission(Context context) {
140 | final String permission = "android.permission.VIBRATE";
141 | final int res = context.checkCallingOrSelfPermission(permission);
142 | return (res == PackageManager.PERMISSION_GRANTED);
143 | }
144 |
145 | @Override
146 | public List getSpinnerItems() {
147 | try {
148 | return getItemsFromXml(R.xml.time_items);
149 | } catch (Exception e) {
150 | Log.d("TimeSpinner", "Error parsing time items from xml");
151 | e.printStackTrace();
152 | }
153 | return null;
154 | }
155 |
156 | @Override
157 | protected @Nullable TwinTextItem parseItemFromXmlTag(@NonNull XmlResourceParser parser) {
158 | if(!parser.getName().equals(XML_TAG_TIMEITEM)) {
159 | Log.d("TimeSpinner", "Unknown xml tag name: " + parser.getName());
160 | return null;
161 | }
162 |
163 | // parse the TimeItem, possible values are
164 | String text = null;
165 | @StringRes int textResource = NO_ID, id = NO_ID;
166 | int hour = 0, minute = 0;
167 | for(int i=parser.getAttributeCount()-1; i>=0; i--) {
168 | String attrName = parser.getAttributeName(i);
169 | switch (attrName) {
170 | case XML_ATTR_ID:
171 | id = parser.getIdAttributeResourceValue(NO_ID);
172 | break;
173 | case XML_ATTR_TEXT:
174 | text = parser.getAttributeValue(i);
175 | // try to get a resource value, the string is retrieved below
176 | if(text != null && text.startsWith("@"))
177 | textResource = parser.getAttributeResourceValue(i, NO_ID);
178 | break;
179 |
180 | case XML_ATTR_ABSHOUR:
181 | hour = parser.getAttributeIntValue(i, -1);
182 | break;
183 | case XML_ATTR_ABSMINUTE:
184 | minute = parser.getAttributeIntValue(i, -1);
185 | break;
186 |
187 | case XML_ATTR_RELHOUR:
188 | hour += parser.getAttributeIntValue(i, 0);
189 | break;
190 | case XML_ATTR_RELMINUTE:
191 | minute += parser.getAttributeIntValue(i, 0);
192 | break;
193 | default:
194 | Log.d("TimeSpinner", "Skipping unknown attribute tag parsing xml resource: "
195 | + attrName + ", maybe a typo?");
196 | }
197 | }// end for attr
198 |
199 | // now construct the time item from the attributes
200 | if(textResource != NO_ID)
201 | text = getResources().getString(textResource);
202 |
203 | // when no text is given, format the date to have at least something to show
204 | if(text == null || text.equals(""))
205 | text = formatTime(hour, minute);
206 |
207 | return new TimeItem(text, formatTime(hour, minute), hour, minute, id);
208 | }
209 |
210 | /**
211 | * Gets the currently selected time (that the Spinner is showing)
212 | * @return The selected time as Calendar, or null if there is none.
213 | */
214 | public Calendar getSelectedTime() {
215 | final Object selectedItem = getSelectedItem();
216 | if(!(selectedItem instanceof TimeItem))
217 | return null;
218 | return ((TimeItem) selectedItem).getTime();
219 | }
220 |
221 | /**
222 | * Sets the Spinner's selection as time in hour and minute. If the time was not in the possible
223 | * selections, a temporary item is created and passed to selectTemporary().
224 | * @param hour The hour to be selected.
225 | * @param minute The minute in the hour.
226 | */
227 | public void setSelectedTime(int hour, int minute) {
228 | final int count = getAdapter().getCount() - 1;
229 | int itemPosition = -1;
230 | for(int i=0; i= 0)
238 | setSelection(itemPosition);
239 | else {
240 | // create a temporary TimeItem to select:
241 | selectTemporary(new TimeItem(formatTime(hour, minute), hour, minute, NO_ID));
242 | }
243 | }
244 |
245 | private String formatTime(int hour, int minute) {
246 | return getTimeFormat().format(new GregorianCalendar(0,0,0,hour,minute).getTime());
247 | }
248 |
249 | /**
250 | * Gets the time format (as java.text.DateFormat) currently used to format Calendar strings.
251 | * Defaults to the short time instance for your locale.
252 | * @return The time format, which will never be null.
253 | */
254 | public java.text.DateFormat getTimeFormat() {
255 | if(timeFormat == null)
256 | timeFormat = java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT);
257 | return timeFormat;
258 | }
259 |
260 | /**
261 | * Sets the time format to use for formatting Calendar objects to displayable strings.
262 | * @param timeFormat The new time format (as java.text.DateFormat), or null to use the default format.
263 | */
264 | public void setTimeFormat(java.text.DateFormat timeFormat) {
265 | this.timeFormat = timeFormat;
266 | // update our pre-built timePickerDialog with the new timeFormat:
267 | initTimePickerDialog(getContext());
268 |
269 | // save the flags and selection first:
270 | final PickerSpinnerAdapter adapter = ((PickerSpinnerAdapter)getAdapter());
271 | final boolean moreTimeItems = isShowingMoreTimeItems();
272 | final boolean numbersInView = adapter.isShowingSecondaryTextInView();
273 | final Calendar selection = getSelectedTime();
274 | // we need to restore differently if we have a temporary selection:
275 | final boolean temporarySelected = getSelectedItemPosition() == adapter.getCount();
276 |
277 | // to rebuild the spinner items, we need to recreate our adapter:
278 | initAdapter(getContext());
279 |
280 | // force restore flags and selection to the new Adapter:
281 | setShowNumbersInView(numbersInView);
282 | this.showMoreTimeItems = false;
283 | if(temporarySelected) {
284 | // for some reason these calls have to be exactly in this order!
285 | setSelectedTime(selection.get(Calendar.HOUR_OF_DAY), selection.get(Calendar.MINUTE));
286 | setShowMoreTimeItems(moreTimeItems);
287 | } else {
288 | // this way it works when a date from the array is selected (like the default)
289 | setShowMoreTimeItems(moreTimeItems);
290 | setSelectedTime(selection.get(Calendar.HOUR_OF_DAY), selection.get(Calendar.MINUTE));
291 | }
292 | }
293 |
294 | /**
295 | * Implement this interface if you want to be notified whenever the selected time changes.
296 | */
297 | public void setOnTimeSelectedListener(OnTimeSelectedListener listener) {
298 | this.timeListener = listener;
299 | }
300 |
301 | /**
302 | * Gets the default {@link TimePickerDialog} that is shown when the footer is clicked.
303 | * @return The dialog, or null if a custom time picker has been set and the default one is thus unused.
304 | */
305 | public @Nullable TimePickerDialog getTimePickerDialog() {
306 | if(customTimePicker != null)
307 | return null;
308 | return timePickerDialog;
309 | }
310 |
311 | /**
312 | * Sets a custom listener whose onClick method will be called to create and handle the custom time picker.
313 | * You should call {@link #setSelectedTime} when the custom picker is finished.
314 | * @param launchPicker An {@link android.view.View.OnClickListener} whose onClick method will be
315 | * called to show the custom time picker, or null to use the default picker.
316 | */
317 | public void setCustomTimePicker(@Nullable OnClickListener launchPicker) {
318 | this.customTimePicker = launchPicker;
319 | }
320 |
321 | /**
322 | * Checks whether the spinner is showing all time items, including noon and late night.
323 | * @return True if FLAG_MORE_TIME has been set or {@link #setShowMoreTimeItems(boolean)} was called, false otherwise.
324 | */
325 | public boolean isShowingMoreTimeItems() {
326 | return this.showMoreTimeItems;
327 | }
328 |
329 | /**
330 | * Toggles showing more time items. If enabled, a noon and a late night time item are shown.
331 | * @param enable True to enable, false to disable more time items.
332 | */
333 | public void setShowMoreTimeItems(boolean enable) {
334 | if(enable && !showMoreTimeItems) {
335 | // create the noon and late night item:
336 | final Resources res = getResources();
337 | // switch the afternoon item to 2pm:
338 | insertAdapterItem(new TimeItem(res.getString(R.string.time_afternoon_2), formatTime(14, 0), 14, 0, R.id.time_afternoon_2), 2);
339 | removeAdapterItemById(R.id.time_afternoon);
340 | // noon item:
341 | insertAdapterItem(new TimeItem(res.getString(R.string.time_noon), formatTime(12, 0), 12, 0, R.id.time_noon), 1);
342 | // late night item:
343 | addAdapterItem(new TimeItem(res.getString(R.string.time_late_night), formatTime(23, 0), 23, 0, R.id.time_late_night));
344 | }
345 | else if(!enable && showMoreTimeItems) {
346 | // switch back the afternoon item:
347 | insertAdapterItem(new TimeItem(getResources().getString(R.string.time_afternoon), formatTime(13, 0), 13, 0, R.id.time_afternoon), 3);
348 | removeAdapterItemById(R.id.time_afternoon_2);
349 | removeAdapterItemById(R.id.time_noon);
350 | removeAdapterItemById(R.id.time_late_night);
351 | }
352 | showMoreTimeItems = enable;
353 | }
354 |
355 | /**
356 | * Toggles showing numeric time in the view. Note that time will always be shown in dropdown.
357 | * @param enable True to enable, false to disable numeric mode.
358 | */
359 | public void setShowNumbersInView(boolean enable) {
360 | PickerSpinnerAdapter adapter = (PickerSpinnerAdapter) getAdapter();
361 | // workaround for now.
362 | if(enable != adapter.isShowingSecondaryTextInView() && adapter.getCount() == getSelectedItemPosition())
363 | setSelection(0);
364 | adapter.setShowSecondaryTextInView(enable);
365 | }
366 |
367 | /**
368 | * Set the flags to use for this time spinner.
369 | * @param modeOrFlags A mode of ReminderDatePicker.MODE_... or multiple ReminderDatePicker.FLAG_...
370 | * combined with the | operator.
371 | */
372 | public void setFlags(int modeOrFlags) {
373 | setShowMoreTimeItems((modeOrFlags & ReminderDatePicker.FLAG_MORE_TIME) != 0);
374 | setShowNumbersInView((modeOrFlags & ReminderDatePicker.FLAG_NUMBERS) != 0);
375 | }
376 |
377 | /**
378 | * {@inheritDoc}
379 | */
380 | @Override
381 | public void removeAdapterItemAt(int index) {
382 | if(index == getSelectedItemPosition()) {
383 | Calendar time = getSelectedTime();
384 | selectTemporary(new TimeItem(formatTime(time.get(Calendar.HOUR_OF_DAY), time.get(Calendar.MINUTE)), time, NO_ID));
385 | }
386 | super.removeAdapterItemAt(index);
387 | }
388 |
389 | @Override
390 | public CharSequence getFooter() {
391 | return getResources().getString(R.string.spinner_time_footer);
392 | }
393 |
394 | @Override
395 | public void onFooterClick() {
396 | if (customTimePicker == null) {
397 | // update the selected time in the dialog
398 | final Calendar time = getSelectedTime();
399 | timePickerDialog.setStartTime(time.get(Calendar.HOUR_OF_DAY), time.get(Calendar.MINUTE));
400 | timePickerDialog.show(fragmentManager, "TimePickerDialog");
401 | } else {
402 | customTimePicker.onClick(this);
403 | }
404 | }
405 |
406 | @Override
407 | protected void restoreTemporarySelection(String codeString) {
408 | selectTemporary(TimeItem.fromString(codeString));
409 | }
410 |
411 | @Override
412 | public void onItemSelected(AdapterView> parent, View view, int position, long id) {
413 | if(timeListener != null) {
414 | Object selectedObj = getSelectedItem();
415 | if(selectedObj instanceof TimeItem) {
416 | TimeItem selected = (TimeItem) selectedObj;
417 | int hour = selected.getHour();
418 | int minute = selected.getMinute();
419 | if(hour != lastSelectedHour || minute != lastSelectedMinute) {
420 | timeListener.onTimeSelected(hour, minute);
421 | lastSelectedHour = hour;
422 | lastSelectedMinute = minute;
423 | }
424 | }
425 | }
426 | }
427 |
428 | // unused
429 | @Override
430 | public void onNothingSelected(AdapterView> parent) {
431 | }
432 | }
433 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/simplicityapks/reminderdatepicker/lib/TwinTextItem.java:
--------------------------------------------------------------------------------
1 | package com.simplicityapks.reminderdatepicker.lib;
2 |
3 | /**
4 | * Base interface for list items used by a PickerSpinnerAdapter. Enables having both primary and secondary text.
5 | */
6 | public interface TwinTextItem {
7 |
8 | /**
9 | * Base class for fast creating of TwinTextItems.
10 | */
11 | class Simple implements TwinTextItem{
12 | private final CharSequence primary, secondary;
13 | private final int id;
14 |
15 | /**
16 | * Constructs a new simple TwinTextItem.
17 | * @param primaryText The text to be shown primarily.
18 | * @param secondaryText The text to be shown secondarily.
19 | */
20 | public Simple(CharSequence primaryText, CharSequence secondaryText) {
21 | this(primaryText, secondaryText, 0);
22 | }
23 |
24 | /**
25 | * Constructs a new simple TwinTextItem.
26 | * @param primaryText The text to be shown primarily.
27 | * @param secondaryText The text to be shown secondarily.
28 | * @param itemId The id value to find this item with.
29 | */
30 | public Simple(CharSequence primaryText, CharSequence secondaryText, int itemId) {
31 | primary = primaryText;
32 | secondary = secondaryText;
33 | id = itemId;
34 | }
35 |
36 | /**
37 | * {@inheritDoc}
38 | */
39 | @Override
40 | public CharSequence getPrimaryText() {
41 | return primary;
42 | }
43 |
44 | /**
45 | * {@inheritDoc}
46 | */
47 | @Override
48 | public CharSequence getSecondaryText() {
49 | return secondary;
50 | }
51 |
52 | /**
53 | * {@inheritDoc}
54 | */
55 | @Override
56 | public int getId() {
57 | return id;
58 | }
59 |
60 | /**
61 | * {@inheritDoc}
62 | */
63 | @Override
64 | public boolean isEnabled() {
65 | return true;
66 | }
67 | }
68 |
69 | /**
70 | * Returns the identifier with which the item can be found and removed from the adapter.
71 | * Does not have to be unique for each item if you don't use runtime item modifications.
72 | */
73 | int getId();
74 |
75 | /**
76 | * Gets the text to be shown primarily.
77 | * @return The text (probably as String).
78 | */
79 | CharSequence getPrimaryText();
80 |
81 | /**
82 | * Gets the text to be shown secondarily.
83 | * @return The text (probably as String).
84 | */
85 | CharSequence getSecondaryText();
86 |
87 | /**
88 | * Whether this item is enabled. Return false to show this spinner item in a disabled state with grey text.
89 | * @return true to enable, false to disable this item.
90 | */
91 | boolean isEnabled();
92 | }
93 |
--------------------------------------------------------------------------------
/lib/src/main/project.properties:
--------------------------------------------------------------------------------
1 | android.library=true
2 |
3 | # Make sure you have both android.support.v7.appcompat and com.fourmob.datetimepicker setup correctly
4 | # and referenced as android.library.reference.x=../path/to/lib here!
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-hdpi/ic_action_time_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SimplicityApks/ReminderDatePicker/7596fbac77a5d26f687fec11758935a2b7db156f/lib/src/main/res/drawable-hdpi/ic_action_time_dark.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-hdpi/ic_action_time_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SimplicityApks/ReminderDatePicker/7596fbac77a5d26f687fec11758935a2b7db156f/lib/src/main/res/drawable-hdpi/ic_action_time_light.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-mdpi/ic_action_time_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SimplicityApks/ReminderDatePicker/7596fbac77a5d26f687fec11758935a2b7db156f/lib/src/main/res/drawable-mdpi/ic_action_time_dark.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-mdpi/ic_action_time_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SimplicityApks/ReminderDatePicker/7596fbac77a5d26f687fec11758935a2b7db156f/lib/src/main/res/drawable-mdpi/ic_action_time_light.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-xhdpi/ic_action_time_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SimplicityApks/ReminderDatePicker/7596fbac77a5d26f687fec11758935a2b7db156f/lib/src/main/res/drawable-xhdpi/ic_action_time_dark.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-xhdpi/ic_action_time_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SimplicityApks/ReminderDatePicker/7596fbac77a5d26f687fec11758935a2b7db156f/lib/src/main/res/drawable-xhdpi/ic_action_time_light.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-xxhdpi/ic_action_time_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SimplicityApks/ReminderDatePicker/7596fbac77a5d26f687fec11758935a2b7db156f/lib/src/main/res/drawable-xxhdpi/ic_action_time_dark.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-xxhdpi/ic_action_time_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SimplicityApks/ReminderDatePicker/7596fbac77a5d26f687fec11758935a2b7db156f/lib/src/main/res/drawable-xxhdpi/ic_action_time_light.png
--------------------------------------------------------------------------------
/lib/src/main/res/layout/reminder_date_picker.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
10 |
--------------------------------------------------------------------------------
/lib/src/main/res/layout/time_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/lib/src/main/res/layout/twin_text_dropdown_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
25 |
26 |
38 |
--------------------------------------------------------------------------------
/lib/src/main/res/layout/twin_text_dropdown_item_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
25 |
27 |
39 |
--------------------------------------------------------------------------------
/lib/src/main/res/layout/twin_text_footer.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
25 |
26 |
38 |
--------------------------------------------------------------------------------
/lib/src/main/res/layout/twin_text_footer_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
25 |
26 |
38 |
--------------------------------------------------------------------------------
/lib/src/main/res/layout/twin_text_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
16 |
17 |
18 |
28 |
--------------------------------------------------------------------------------
/lib/src/main/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Datum auswählen…
3 | Uhrzeit auswählen…
4 | Zeit wählen
5 |
6 |
7 | Letzten %1$s
8 | Letzten %1$s
9 | Gestern
10 | Heute
11 | Morgen
12 | Nächsten %1$s
13 | Nächsten %1$s
14 |
15 |
16 | Morgens
17 | Mittags
18 | Nachmittags
19 | Nachmittags
20 | Spätnachmittags
21 | Abends
22 | Nachts
23 |
24 |
--------------------------------------------------------------------------------
/lib/src/main/res/values-el/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Διαλέξτε κάποια ημερομηνία…
3 | Διαλέξτε κάποια ώρα…
4 | Επιλογή ώρας
5 |
6 |
7 | Τελευταία %1$s
8 | Τελευταία %1$s
9 | Χθες
10 | Σήμερα
11 | Αύριο
12 | Επόμενη %1$s
13 | Επόμενη %1$s
14 |
15 |
16 | Πρωί
17 | Μεσημέρι
18 | Απόγευμα
19 | Απόγευμα
20 | Βράδυ
21 | Νύχτα (20:00)
22 | Αργά τη νύχτα
23 |
--------------------------------------------------------------------------------
/lib/src/main/res/values-es/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Elegir una fecha…
3 | Elegir un horario…
4 | Elegir horario
5 |
6 |
7 | %1$s anterior
8 | %1$s anterior
9 | Ayer
10 | Hoy
11 | Mañana
12 | Siguiente %1$s
13 | Siguiente %1$s
14 |
15 |
16 | Por la mañana
17 | Al mediodía
18 | Por la tarde
19 | Por la tarde
20 | Al anochecer
21 | Por la noche
22 | Por la noche
23 |
24 |
--------------------------------------------------------------------------------
/lib/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Sélectionner une date…
3 | Choisir l\'heure…
4 | Sélectionner l\'heure
5 |
6 |
7 | %1$s dernier
8 | %1$s dernier
9 | Hier
10 | Aujourd\'hui
11 | Demain
12 | %1$s prochain
13 | %1$s prochain
14 |
15 |
16 | Matin
17 | Midi
18 | Après-midi
19 | Après-midi
20 | Début de soirée
21 | Soir
22 | Fin de soirée
23 |
24 |
--------------------------------------------------------------------------------
/lib/src/main/res/values-it/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Seleziona una data…
3 | Seleziona l\'ora…
4 | Seleziona l\'ora
5 |
6 |
7 | Ultimo %1$s
8 | Ultimo %1$s
9 | Ieri
10 | Oggi
11 | Domani
12 | Prossimo %1$s
13 | Prossimo %1$s
14 |
15 |
16 | Mattina
17 | Mezzogiorno
18 | Pomeriggio
19 | Pomeriggio
20 | Sera
21 | Notte
22 | Tarda notte
23 |
24 |
--------------------------------------------------------------------------------
/lib/src/main/res/values-pt-rBR/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Escolha uma data…
3 | Escolha um horário…
4 | Escolha um horário
5 |
6 |
7 | Última %1$s
8 | Último %1$s
9 | Ontem
10 | Hoje
11 | Amanhã
12 | Próxima %1$s
13 | Próximo %1$s
14 |
15 |
16 | Manhã
17 | Meio-dia
18 | Tarde
19 | Tarde
20 | Anoitecer
21 | Noite
22 | Noite
23 |
24 |
--------------------------------------------------------------------------------
/lib/src/main/res/values-tr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Bir tarih seçin…
3 | Bir saat seçin…
4 | Saat seç
5 |
6 |
7 | Son %1$s
8 | Son %1$s
9 | Dün
10 | Bugün
11 | Yarın
12 | Sonraki %1$s
13 | Sonraki %1$s
14 |
15 |
16 | Sabah
17 | Öğlen
18 | Öğleden sonra
19 | Öğleden sonra
20 | Akşam
21 | Gece
22 | Gece yarısı
23 |
--------------------------------------------------------------------------------
/lib/src/main/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
--------------------------------------------------------------------------------
/lib/src/main/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
--------------------------------------------------------------------------------
/lib/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/lib/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ffb2b2b2
4 | #48b7b7b7
5 |
6 |
--------------------------------------------------------------------------------
/lib/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/lib/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Pick a date…
3 | Pick a time…
4 | Select time
5 |
6 |
7 | Last %1$s
8 | Last %1$s
9 | Yesterday
10 | Today
11 | Tomorrow
12 | Next %1$s
13 | Next %1$s
14 | %1$s
15 |
16 |
17 | Morning
18 | Noon
19 | Afternoon
20 | Afternoon
21 | Evening
22 | Night
23 | Late night
24 |
25 |
--------------------------------------------------------------------------------
/lib/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
14 |
15 |
17 |
18 |
23 |
24 |
27 |
--------------------------------------------------------------------------------
/lib/src/main/res/xml/date_items.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
11 |
--------------------------------------------------------------------------------
/lib/src/main/res/xml/time_items.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
15 |
19 |
--------------------------------------------------------------------------------
/maven_push.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven'
2 | apply plugin: 'signing'
3 |
4 | def sonatypeRepositoryUrl
5 | if (isReleaseBuild()) {
6 | println 'RELEASE BUILD'
7 | sonatypeRepositoryUrl = hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
8 | : "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
9 | } else {
10 | println 'DEBUG BUILD'
11 | sonatypeRepositoryUrl = hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
12 | : "https://oss.sonatype.org/content/repositories/snapshots/"
13 | }
14 |
15 | def getRepositoryUsername() {
16 | return hasProperty('nexusUsername') ? nexusUsername : ""
17 | }
18 |
19 | def getRepositoryPassword() {
20 | return hasProperty('nexusPassword') ? nexusPassword : ""
21 | }
22 |
23 | afterEvaluate { project ->
24 | uploadArchives {
25 | repositories {
26 | mavenDeployer {
27 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
28 |
29 | pom.artifactId = POM_ARTIFACT_ID
30 |
31 | repository(url: sonatypeRepositoryUrl) {
32 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
33 | }
34 |
35 | pom.project {
36 | name POM_NAME
37 | packaging POM_PACKAGING
38 | description POM_DESCRIPTION
39 | url POM_URL
40 |
41 | scm {
42 | url POM_SCM_URL
43 | connection POM_SCM_CONNECTION
44 | developerConnection POM_SCM_DEV_CONNECTION
45 | }
46 |
47 | licenses {
48 | license {
49 | name POM_LICENCE_NAME
50 | url POM_LICENCE_URL
51 | distribution POM_LICENCE_DIST
52 | }
53 | }
54 |
55 | developers {
56 | developer {
57 | id POM_DEVELOPER_ID
58 | name POM_DEVELOPER_NAME
59 | }
60 | }
61 | }
62 | }
63 | }
64 | }
65 |
66 | signing {
67 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
68 | sign configurations.archives
69 | }
70 |
71 | task androidJavadocs(type: Javadoc) {
72 | source = android.sourceSets.main.java.sourceFiles
73 | }
74 |
75 | task androidJavadocsJar(type: Jar) {
76 | classifier = 'javadoc'
77 | //basename = artifact_id
78 | from androidJavadocs.destinationDir
79 | }
80 |
81 | task androidSourcesJar(type: Jar) {
82 | classifier = 'sources'
83 | //basename = artifact_id
84 | from android.sourceSets.main.java.sourceFiles
85 | }
86 |
87 | artifacts {
88 | //archives packageReleaseJar
89 | archives androidSourcesJar
90 | archives androidJavadocsJar
91 | }
92 | }
--------------------------------------------------------------------------------
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 26
5 | buildToolsVersion '27.0.0'
6 |
7 | defaultConfig {
8 | applicationId 'com.simplicityapks.reminderdatepicker.sample'
9 | minSdkVersion 14
10 | targetSdkVersion 26
11 | versionCode 3
12 | versionName '1.2.0'
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled true
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | productFlavors {
21 | }
22 | }
23 |
24 | dependencies {
25 | compile fileTree(dir: 'libs', include: ['*.jar'])
26 | compile 'com.android.support:appcompat-v7:26.+'
27 | compile project(':lib')
28 | }
29 |
--------------------------------------------------------------------------------
/sample/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/patrick/Dokumente/AndroidStudioDevelopment/android-studio/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/simplicityapks/reminderdatepicker/sample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.simplicityapks.reminderdatepicker.sample;
2 |
3 | import android.content.Intent;
4 | import android.net.Uri;
5 | import android.os.Bundle;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.view.Menu;
8 | import android.view.MenuItem;
9 | import android.widget.CheckBox;
10 | import android.widget.CompoundButton;
11 | import android.widget.Toast;
12 |
13 | import com.simplicityapks.reminderdatepicker.lib.OnDateSelectedListener;
14 | import com.simplicityapks.reminderdatepicker.lib.ReminderDatePicker;
15 |
16 | import java.text.DateFormat;
17 | import java.util.Calendar;
18 |
19 | public class MainActivity extends AppCompatActivity implements CompoundButton.OnCheckedChangeListener{
20 |
21 | private String FLAG_DARK_THEME = "flag_dark_theme";
22 | private boolean useDarkTheme = false;
23 |
24 | private ReminderDatePicker datePicker;
25 |
26 | private CheckBox cbPast, cbMonth, cbMoreTime, cbNumbers, cbWeekdayNames, cbHideTime;
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | // do we want to change the theme to dark?
31 | useDarkTheme = getIntent().getBooleanExtra(FLAG_DARK_THEME, false);
32 | if(useDarkTheme) setTheme(R.style.Theme_AppCompat);
33 |
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.activity_main);
36 | datePicker = (ReminderDatePicker) findViewById(R.id.date_picker);
37 |
38 | // setup listener for a date change:
39 | datePicker.setOnDateSelectedListener(new OnDateSelectedListener() {
40 | @Override
41 | public void onDateSelected(Calendar date) {
42 | Toast.makeText(MainActivity.this, "Selected date: "+ getDateFormat().format(date.getTime()), Toast.LENGTH_SHORT).show();
43 | }
44 | });
45 |
46 | cbPast = (CheckBox) findViewById(R.id.cb_past);
47 | cbMonth = (CheckBox) findViewById(R.id.cb_month);
48 | cbMoreTime = (CheckBox) findViewById(R.id.cb_more_time);
49 | cbNumbers = (CheckBox) findViewById(R.id.cb_numbers);
50 | cbWeekdayNames = (CheckBox) findViewById(R.id.cb_weekday_names);
51 | cbHideTime = (CheckBox) findViewById(R.id.cb_hide_time);
52 |
53 | // setup flag change listeners:
54 | cbPast.setOnCheckedChangeListener(this);
55 | cbMonth.setOnCheckedChangeListener(this);
56 | cbMoreTime.setOnCheckedChangeListener(this);
57 | cbNumbers.setOnCheckedChangeListener(this);
58 | cbWeekdayNames.setOnCheckedChangeListener(this);
59 | cbHideTime.setOnCheckedChangeListener(this);
60 | }
61 |
62 | private java.text.DateFormat savedFormat;
63 | public java.text.DateFormat getDateFormat() {
64 | if(savedFormat == null)
65 | savedFormat = DateFormat.getDateTimeInstance();
66 | return savedFormat;
67 | }
68 |
69 | @Override
70 | public boolean onCreateOptionsMenu(Menu menu) {
71 | // Inflate the menu; this adds items to the action bar if it is present.
72 | getMenuInflater().inflate(R.menu.main, menu);
73 | return true;
74 | }
75 |
76 | @Override
77 | public boolean onOptionsItemSelected(MenuItem item) {
78 | // Handle action bar item clicks here. The action bar will
79 | // automatically handle clicks on the Home/Up button, so long
80 | // as you specify a parent activity in AndroidManifest.xml.
81 | switch (item.getItemId()) {
82 | case R.id.action_switch_theme:
83 | Intent restart = new Intent(this, MainActivity.class);
84 | // add boolean extra to switch theme:
85 | restart.putExtra(FLAG_DARK_THEME, !useDarkTheme);
86 | // kill current activity and start again
87 | overridePendingTransition(0, 0);
88 | restart.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
89 | finish();
90 | overridePendingTransition(0, 0);
91 | startActivity(restart);
92 | break;
93 | case R.id.action_view_source:
94 | Intent viewSource = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.uri_github_source)));
95 | startActivity(viewSource);
96 | break;
97 | }
98 | return super.onOptionsItemSelected(item);
99 | }
100 |
101 | private int getCheckedFlags() {
102 | return (cbPast.isChecked()? ReminderDatePicker.FLAG_PAST : 0) |
103 | (cbMonth.isChecked()? ReminderDatePicker.FLAG_MONTH : 0) |
104 | (cbMoreTime.isChecked()? ReminderDatePicker.FLAG_MORE_TIME : 0) |
105 | (cbNumbers.isChecked()? ReminderDatePicker.FLAG_NUMBERS : 0) |
106 | (cbWeekdayNames.isChecked()? ReminderDatePicker.FLAG_WEEKDAY_NAMES : 0) |
107 | (cbHideTime.isChecked()? ReminderDatePicker.FLAG_HIDE_TIME : 0);
108 | }
109 |
110 | @Override
111 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
112 | datePicker.setFlags(getCheckedFlags());
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SimplicityApks/ReminderDatePicker/7596fbac77a5d26f687fec11758935a2b7db156f/sample/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SimplicityApks/ReminderDatePicker/7596fbac77a5d26f687fec11758935a2b7db156f/sample/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SimplicityApks/ReminderDatePicker/7596fbac77a5d26f687fec11758935a2b7db156f/sample/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SimplicityApks/ReminderDatePicker/7596fbac77a5d26f687fec11758935a2b7db156f/sample/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SimplicityApks/ReminderDatePicker/7596fbac77a5d26f687fec11758935a2b7db156f/sample/src/main/res/drawable-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
17 |
18 |
19 |
20 |
26 |
27 |
35 |
36 |
42 |
43 |
49 |
50 |
56 |
57 |
63 |
64 |
70 |
71 |
77 |
78 |
--------------------------------------------------------------------------------
/sample/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/sample/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ReminderDatePicker Sample
5 | Switch theme
6 | Get source code
7 | https://github.com/SimplicityApks/ReminderDatePicker
8 |
9 | Select Flags
10 |
11 |
12 | FLAG_PAST
13 | FLAG_MONTH
14 | FLAG_MORE_TIME
15 | FLAG_NUMBERS
16 | FLAG_WEEKDAY_NAMES
17 | FLAG_HIDE_TIME
18 |
19 |
20 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
15 |
16 |
25 |
26 |
29 |
30 |
36 |
37 |
41 |
42 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':lib', ':sample'
2 |
--------------------------------------------------------------------------------