Improved architecturemaster
@ -1,42 +0,0 @@ | |||||
package com.henninghall.date_picker; | |||||
import java.util.HashMap; | |||||
import cn.carbswang.android.numberpickerview.library.NumberPickerView; | |||||
public class EmptyWheelUpdater { | |||||
private final PickerView pickerView; | |||||
private final HashMap<Integer, NumberPickerView> views; | |||||
EmptyWheelUpdater(PickerView pickerView) { | |||||
this.pickerView = pickerView; | |||||
this.views = getViews(); | |||||
} | |||||
private HashMap<Integer, NumberPickerView> getViews() { | |||||
HashMap<Integer, NumberPickerView> views = new HashMap<>(); | |||||
for (int id: Utils.emptyWheelIds) { | |||||
NumberPickerView view = (NumberPickerView) pickerView.findViewById(id); | |||||
views.put(id, view); | |||||
} | |||||
return views; | |||||
} | |||||
void update() { | |||||
hideAll(); | |||||
int numberOfVisibleWheels = pickerView.getVisibleWheels().size(); | |||||
int emptyViewsToAdd = numberOfVisibleWheels + 1; | |||||
for (int i = 0; i < emptyViewsToAdd; i++) { | |||||
int index = i * 2; | |||||
pickerView.wheelsWrapper.addView(views.get(Utils.emptyWheelIds[i]), index); | |||||
} | |||||
} | |||||
private void hideAll() { | |||||
for (NumberPickerView view: views.values()) { | |||||
pickerView.wheelsWrapper.removeView(view); | |||||
} | |||||
} | |||||
} |
@ -1,12 +0,0 @@ | |||||
package com.henninghall.date_picker; | |||||
import android.text.format.DateFormat; | |||||
public class Settings { | |||||
public static boolean usesAmPm (){ | |||||
return !DateFormat.is24HourFormat(DatePickerManager.context); | |||||
} | |||||
} |
@ -0,0 +1,206 @@ | |||||
package com.henninghall.date_picker; | |||||
import android.util.Log; | |||||
import com.facebook.react.bridge.Dynamic; | |||||
import com.henninghall.date_picker.models.Mode; | |||||
import com.henninghall.date_picker.models.WheelType; | |||||
import com.henninghall.date_picker.props.DateProp; | |||||
import com.henninghall.date_picker.props.FadeToColorProp; | |||||
import com.henninghall.date_picker.props.HeightProp; | |||||
import com.henninghall.date_picker.props.LocaleProp; | |||||
import com.henninghall.date_picker.props.MaximumDateProp; | |||||
import com.henninghall.date_picker.props.MinimumDateProp; | |||||
import com.henninghall.date_picker.props.MinuteIntervalProp; | |||||
import com.henninghall.date_picker.props.ModeProp; | |||||
import com.henninghall.date_picker.props.Prop; | |||||
import com.henninghall.date_picker.props.TextColorProp; | |||||
import com.henninghall.date_picker.props.UtcProp; | |||||
import java.text.SimpleDateFormat; | |||||
import java.util.ArrayList; | |||||
import java.util.Arrays; | |||||
import java.util.Calendar; | |||||
import java.util.HashMap; | |||||
import java.util.Locale; | |||||
import java.util.TimeZone; | |||||
public class State { | |||||
private final Prop dateProp = new DateProp(); | |||||
private final Prop modeProp = new ModeProp(); | |||||
private final Prop localeProp = new LocaleProp(); | |||||
private final Prop fadeToColorProp = new FadeToColorProp(); | |||||
private final Prop textColorProp = new TextColorProp(); | |||||
private final Prop minuteIntervalProp = new MinuteIntervalProp(); | |||||
private final Prop minimumDateProp = new MinimumDateProp(); | |||||
private final Prop maximumDateProp = new MaximumDateProp(); | |||||
private final Prop utcProp = new UtcProp(); | |||||
private final Prop heightProp = new HeightProp(); | |||||
private final HashMap props = new HashMap<String, Prop>() {{ | |||||
put(DateProp.name, dateProp); | |||||
put(ModeProp.name, modeProp); | |||||
put(LocaleProp.name, localeProp); | |||||
put(FadeToColorProp.name, fadeToColorProp); | |||||
put(TextColorProp.name, textColorProp); | |||||
put(MinuteIntervalProp.name, minuteIntervalProp); | |||||
put(MinimumDateProp.name, minimumDateProp); | |||||
put(MaximumDateProp.name, maximumDateProp); | |||||
put(UtcProp.name, utcProp); | |||||
}}; | |||||
private Prop getProp(String name){ | |||||
return (Prop) props.get(name); | |||||
} | |||||
void setProp(String propName, Dynamic value){ | |||||
getProp(propName).setValue(value); | |||||
} | |||||
public Mode getMode() { | |||||
return (Mode) modeProp.getValue(); | |||||
} | |||||
public String getFadeToColor() { | |||||
return (String) fadeToColorProp.getValue(); | |||||
} | |||||
public String getTextColor() { | |||||
return (String) textColorProp.getValue(); | |||||
} | |||||
public int getMinuteInterval() { | |||||
return (int) minuteIntervalProp.getValue(); | |||||
} | |||||
public Locale getLocale() { | |||||
return (Locale) localeProp.getValue(); | |||||
} | |||||
public Calendar getMinimumDate(){ | |||||
DateBoundary db = new DateBoundary(getTimeZone(), (String) minimumDateProp.getValue()); | |||||
return db.get(); | |||||
} | |||||
public Calendar getMaximumDate(){ | |||||
DateBoundary db = new DateBoundary(getTimeZone(), (String) maximumDateProp.getValue()); | |||||
return db.get(); | |||||
} | |||||
public TimeZone getTimeZone(){ | |||||
boolean utc = (boolean) utcProp.getValue(); | |||||
return utc ? TimeZone.getTimeZone("UTC") : TimeZone.getDefault(); | |||||
} | |||||
public Calendar getDate() { | |||||
String date = (String) dateProp.getValue(); | |||||
return Utils.isoToCalendar(date, getTimeZone()); | |||||
} | |||||
public Integer getHeight() { | |||||
return (Integer) heightProp.getValue(); | |||||
} | |||||
public int getShownCount() { | |||||
int DP_PER_SHOW_SHOW_COUNT = 35; | |||||
int showCount = getHeight() / DP_PER_SHOW_SHOW_COUNT; | |||||
int oddShowCount = showCount % 2 == 0 ? showCount + 1 : showCount; | |||||
return oddShowCount; | |||||
} | |||||
public ArrayList<WheelType> getOrderedWheels() { | |||||
String dateTimePattern = LocaleUtils.getDateTimePattern(getLocale()); | |||||
ArrayList<WheelType> unorderedTypes = new ArrayList(Arrays.asList(WheelType.values())); | |||||
ArrayList<WheelType> orderedWheels = new ArrayList<>(); | |||||
// Always put day wheel first | |||||
unorderedTypes.remove(WheelType.DAY); | |||||
orderedWheels.add(WheelType.DAY); | |||||
for (char ch : dateTimePattern.toCharArray()){ | |||||
try { | |||||
WheelType wheelType = Utils.patternCharToWheelType(ch); | |||||
if (unorderedTypes.contains(wheelType)) { | |||||
unorderedTypes.remove(wheelType); | |||||
orderedWheels.add(wheelType); | |||||
} | |||||
} catch (Exception e) { | |||||
// ignore unknown pattern chars that not correspond to any wheel type | |||||
} | |||||
} | |||||
// If AM/PM wheel remains it means that the locale does not have AM/PM by default and it | |||||
// should be put last. | |||||
if(unorderedTypes.contains(WheelType.AM_PM)){ | |||||
unorderedTypes.remove(WheelType.AM_PM); | |||||
orderedWheels.add(WheelType.AM_PM); | |||||
} | |||||
if(!unorderedTypes.isEmpty()) { | |||||
Log.e( | |||||
"RNDatePicker", | |||||
unorderedTypes.size() + " wheel types cannot be ordered. Wheel type 0: " + unorderedTypes.get(0)); | |||||
} | |||||
return orderedWheels; | |||||
} | |||||
public ArrayList<WheelType> getVisibleWheels() { | |||||
ArrayList<WheelType> visibleWheels = new ArrayList<>(); | |||||
Mode mode = getMode(); | |||||
switch (mode){ | |||||
case datetime: { | |||||
visibleWheels.add(WheelType.DAY); | |||||
visibleWheels.add(WheelType.HOUR); | |||||
visibleWheels.add(WheelType.MINUTE); | |||||
break; | |||||
} | |||||
case time: { | |||||
visibleWheels.add(WheelType.HOUR); | |||||
visibleWheels.add(WheelType.MINUTE); | |||||
break; | |||||
} | |||||
case date: { | |||||
visibleWheels.add(WheelType.YEAR); | |||||
visibleWheels.add(WheelType.MONTH); | |||||
visibleWheels.add(WheelType.DATE); | |||||
break; | |||||
} | |||||
} | |||||
if((mode == Mode.time || mode == Mode.datetime) && Utils.usesAmPm()){ | |||||
visibleWheels.add(WheelType.AM_PM); | |||||
} | |||||
return visibleWheels; | |||||
} | |||||
public ArrayList<WheelType> getOrderedVisibleWheels() { | |||||
ArrayList<WheelType> orderedWheels = getOrderedWheels(); | |||||
ArrayList<WheelType> visibleWheels = getVisibleWheels(); | |||||
ArrayList<WheelType> visibleOrderedWheels = new ArrayList<>(); | |||||
for (WheelType wheel : orderedWheels){ | |||||
if(visibleWheels.contains(wheel)) visibleOrderedWheels.add(wheel); | |||||
} | |||||
return visibleOrderedWheels; | |||||
} | |||||
// Rounding cal to closest minute interval | |||||
public Calendar getInitialDate() { | |||||
Calendar cal = Calendar.getInstance(); | |||||
int minuteInterval = getMinuteInterval(); | |||||
if(minuteInterval <= 1) return cal; | |||||
SimpleDateFormat minuteFormat = new SimpleDateFormat("mm", getLocale()); | |||||
int exactMinute = Integer.valueOf(minuteFormat.format(cal.getTime())); | |||||
int diffSinceLastInterval = exactMinute % minuteInterval; | |||||
int diffAhead = minuteInterval - diffSinceLastInterval; | |||||
int diffBehind= -diffSinceLastInterval; | |||||
boolean closerToPrevious = minuteInterval / 2 > diffSinceLastInterval; | |||||
int diffToExactValue = closerToPrevious ? diffBehind : diffAhead; | |||||
cal.add(Calendar.MINUTE, diffToExactValue); | |||||
return (Calendar) cal.clone(); | |||||
} | |||||
public WheelType getVisibleWheel(int index) { | |||||
return getOrderedVisibleWheels().get(index); | |||||
} | |||||
} |
@ -1,61 +0,0 @@ | |||||
package com.henninghall.date_picker; | |||||
import android.graphics.Color; | |||||
import android.graphics.drawable.GradientDrawable; | |||||
import android.widget.ImageView; | |||||
import com.henninghall.date_picker.wheelFunctions.SetShowCount; | |||||
import com.henninghall.date_picker.wheelFunctions.TextColor; | |||||
import cn.carbswang.android.numberpickerview.library.NumberPickerView; | |||||
class Style { | |||||
private static int DP_PER_SHOW_SHOW_COUNT = 35; | |||||
private final GradientDrawable gradientBottom; | |||||
private final GradientDrawable gradientTop; | |||||
private final PickerView pickerView; | |||||
public Style(PickerView pickerView) { | |||||
this.pickerView = pickerView; | |||||
ImageView overlayTop = (ImageView) pickerView.findViewById(R.id.overlay_top); | |||||
ImageView overlayBottom = (ImageView) pickerView.findViewById(R.id.overlay_bottom); | |||||
this.gradientTop = (GradientDrawable) overlayTop.getDrawable(); | |||||
this.gradientBottom = (GradientDrawable) overlayBottom.getDrawable(); | |||||
} | |||||
public void setFadeToColor(String color) { | |||||
int alpha = validColor(color) ? 255 : 0; | |||||
gradientTop.setAlpha(alpha); | |||||
gradientBottom.setAlpha(alpha); | |||||
if(validColor(color)) { | |||||
int startColor = Color.parseColor("#FF"+ color.substring(1)); | |||||
int endColor = Color.parseColor("#00" + color.substring(1)); | |||||
gradientTop.setColors(new int[] {startColor, endColor}); | |||||
gradientBottom.setColors(new int[] {startColor, endColor}); | |||||
} | |||||
} | |||||
public void setTextColor(String color) { | |||||
this.pickerView.applyOnAllWheels(new TextColor(color)); | |||||
} | |||||
public void setHeight(int height) { | |||||
int showCount = height / DP_PER_SHOW_SHOW_COUNT; | |||||
int oddShowCount = showCount % 2 == 0 ? showCount + 1 : showCount; | |||||
pickerView.applyOnAllWheels(new SetShowCount(oddShowCount)); | |||||
setShownCountOnEmptyWheels(oddShowCount); | |||||
} | |||||
private void setShownCountOnEmptyWheels(int shownCount) { | |||||
for (int id : Utils.emptyWheelIds) { | |||||
NumberPickerView view = (NumberPickerView) pickerView.findViewById(id); | |||||
if(view != null) view.setShownCount(shownCount); | |||||
} | |||||
} | |||||
private boolean validColor(String color){ | |||||
return color != null && color.length() == 7; | |||||
} | |||||
} |
@ -1,56 +0,0 @@ | |||||
package com.henninghall.date_picker; | |||||
import com.facebook.react.bridge.Arguments; | |||||
import com.facebook.react.bridge.WritableMap; | |||||
import com.facebook.react.uimanager.events.RCTEventEmitter; | |||||
import com.henninghall.date_picker.wheelFunctions.AnimateToDate; | |||||
import com.henninghall.date_picker.wheels.Wheel; | |||||
import java.text.DateFormat; | |||||
import java.text.FieldPosition; | |||||
import java.text.ParseException; | |||||
import java.text.SimpleDateFormat; | |||||
import java.util.Calendar; | |||||
import java.util.Date; | |||||
import java.util.Locale; | |||||
import java.util.TimeZone; | |||||
public class WheelChangeListenerImpl implements WheelChangeListener { | |||||
private final PickerView pickerView; | |||||
public WheelChangeListenerImpl(PickerView pickerView) { | |||||
this.pickerView = pickerView; | |||||
} | |||||
@Override | |||||
public void onChange(Wheel picker) { | |||||
WritableMap event = Arguments.createMap(); | |||||
TimeZone timeZone = pickerView.timeZone; | |||||
SimpleDateFormat dateFormat = pickerView.getDateFormat(); | |||||
Calendar minDate = pickerView.getMinimumDate(); | |||||
Calendar maxDate = pickerView.getMaximumDate(); | |||||
try { | |||||
dateFormat.setTimeZone(timeZone); | |||||
Calendar date = Calendar.getInstance(timeZone); | |||||
String toParse = this.pickerView.getDateString(); | |||||
Date newDate = dateFormat.parse(toParse); | |||||
date.setTime(newDate); | |||||
if (minDate != null && date.before(minDate)) pickerView.applyOnVisibleWheels( | |||||
new AnimateToDate(minDate) | |||||
); | |||||
else if (maxDate != null && date.after(maxDate)) pickerView.applyOnVisibleWheels( | |||||
new AnimateToDate(maxDate) | |||||
); | |||||
else { | |||||
event.putString("date", Utils.dateToIso(date)); | |||||
DatePickerManager.context.getJSModule(RCTEventEmitter.class).receiveEvent(pickerView.getId(), "dateChange", event); | |||||
} | |||||
} catch (ParseException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
} |
@ -1,109 +0,0 @@ | |||||
package com.henninghall.date_picker; | |||||
import com.henninghall.date_picker.wheels.Wheel; | |||||
import java.util.ArrayList; | |||||
import java.util.Arrays; | |||||
import java.util.HashMap; | |||||
import java.util.Locale; | |||||
public class WheelOrder | |||||
{ | |||||
private final HashMap<WheelType, Wheel> wheelPerWheelType; | |||||
private PickerView pickerView; | |||||
private ArrayList<WheelType> orderedWheels; | |||||
WheelOrder(final PickerView view) { | |||||
this.pickerView = view; | |||||
this.wheelPerWheelType = new HashMap<WheelType, Wheel>() {{ | |||||
put(WheelType.DAY, pickerView.dayWheel); | |||||
put(WheelType.YEAR, pickerView.yearWheel); | |||||
put(WheelType.MONTH, pickerView.monthWheel); | |||||
put(WheelType.DATE, pickerView.dateWheel); | |||||
put(WheelType.HOUR, pickerView.hourWheel); | |||||
put(WheelType.MINUTE, pickerView.minutesWheel); | |||||
put(WheelType.AM_PM, pickerView.ampmWheel); | |||||
}}; | |||||
} | |||||
private void updateAllWheels(final Locale locale) { | |||||
try { | |||||
this.orderedWheels = getOrderedWheels(locale); | |||||
pickerView.wheelsWrapper.removeAllViews(); | |||||
for (int i = 0; i < wheelPerWheelType.size(); i++) { | |||||
Wheel w = getWheels(i); | |||||
if(w.visible()) { | |||||
pickerView.wheelsWrapper.addView(w.picker); | |||||
} | |||||
} | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
void update(final Locale locale) { | |||||
updateAllWheels(locale); | |||||
pickerView.emptyWheelUpdater.update(); | |||||
} | |||||
private Wheel getWheels(int index){ | |||||
return wheelPerWheelType.get(orderedWheels.get(index)); | |||||
} | |||||
Wheel getVisibleWheel(int index){ | |||||
return getVisibleWheels().get(index); | |||||
} | |||||
private ArrayList<Wheel> getVisibleWheels() { | |||||
ArrayList<Wheel> visibleOrderedWheels = new ArrayList<>(); | |||||
for (WheelType wheelType : orderedWheels){ | |||||
Wheel wheel = wheelPerWheelType.get(wheelType); | |||||
if(wheel.visible()) { | |||||
visibleOrderedWheels.add(wheel); | |||||
} | |||||
} | |||||
return visibleOrderedWheels; | |||||
} | |||||
private ArrayList<WheelType> getOrderedWheels(Locale locale) throws Exception { | |||||
String dateTimePattern = LocaleUtils.getDateTimePattern(locale); | |||||
ArrayList<WheelType> unorderedTypes = new ArrayList(Arrays.asList(WheelType.values())); | |||||
ArrayList<WheelType> orderedWheels = new ArrayList<>(); | |||||
// Always put day wheel first | |||||
unorderedTypes.remove(WheelType.DAY); | |||||
orderedWheels.add(WheelType.DAY); | |||||
for (char ch : dateTimePattern.toCharArray()){ | |||||
try { | |||||
WheelType wheelType = Utils.patternCharToWheelType(ch); | |||||
if (unorderedTypes.contains(wheelType)) { | |||||
unorderedTypes.remove(wheelType); | |||||
orderedWheels.add(wheelType); | |||||
} | |||||
} catch (Exception e) { | |||||
// ignore unknown pattern chars that not correspond to any wheel type | |||||
} | |||||
} | |||||
// If AM/PM wheel remains it means that the locale does not have AM/PM by default and it | |||||
// should be put last. | |||||
if(unorderedTypes.contains(WheelType.AM_PM)){ | |||||
unorderedTypes.remove(WheelType.AM_PM); | |||||
orderedWheels.add(WheelType.AM_PM); | |||||
} | |||||
if(!unorderedTypes.isEmpty()) { | |||||
throw new Exception(unorderedTypes.size() + " wheel types cannot be ordered. Wheel type 0: " + unorderedTypes.get(0)); | |||||
} | |||||
return orderedWheels; | |||||
} | |||||
} | |||||
@ -1,5 +0,0 @@ | |||||
package com.henninghall.date_picker; | |||||
public enum WheelPosition { | |||||
LEFT, RIGHT, MIDDLE | |||||
} |
@ -1,4 +1,4 @@ | |||||
package com.henninghall.date_picker; | |||||
package com.henninghall.date_picker.models; | |||||
public enum Mode { | public enum Mode { | ||||
date, time, datetime | date, time, datetime |
@ -1,4 +1,4 @@ | |||||
package com.henninghall.date_picker; | |||||
package com.henninghall.date_picker.models; | |||||
public enum WheelType { | public enum WheelType { | ||||
DAY, DATE, MONTH, YEAR, HOUR, MINUTE, AM_PM | DAY, DATE, MONTH, YEAR, HOUR, MINUTE, AM_PM |
@ -0,0 +1,13 @@ | |||||
package com.henninghall.date_picker.props; | |||||
import com.facebook.react.bridge.Dynamic; | |||||
public class DateProp extends Prop<String> { | |||||
public static final String name = "date"; | |||||
@Override | |||||
public String toValue(Dynamic value){ | |||||
return value.asString(); | |||||
} | |||||
} |
@ -0,0 +1,13 @@ | |||||
package com.henninghall.date_picker.props; | |||||
import com.facebook.react.bridge.Dynamic; | |||||
public class FadeToColorProp extends Prop<String> { | |||||
public static final String name = "fadeToColor"; | |||||
@Override | |||||
public String toValue(Dynamic value){ | |||||
return value.asString(); | |||||
} | |||||
} |
@ -0,0 +1,13 @@ | |||||
package com.henninghall.date_picker.props; | |||||
import com.facebook.react.bridge.Dynamic; | |||||
import com.henninghall.date_picker.models.Mode; | |||||
public class HeightProp extends Prop<Integer> { | |||||
public static final String name = "height"; | |||||
@Override | |||||
public Integer toValue(Dynamic value){ | |||||
return value.asInt(); | |||||
} | |||||
} |
@ -0,0 +1,28 @@ | |||||
package com.henninghall.date_picker.props; | |||||
import android.os.Build; | |||||
import com.facebook.react.bridge.Dynamic; | |||||
import org.apache.commons.lang3.LocaleUtils; | |||||
import java.util.Locale; | |||||
public class LocaleProp extends Prop<Locale> { | |||||
public static final String name = "locale"; | |||||
public LocaleProp(){ | |||||
super( | |||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP | |||||
? Locale.forLanguageTag("en") | |||||
: Locale.getDefault() | |||||
); | |||||
} | |||||
@Override | |||||
public Locale toValue(Dynamic value){ | |||||
return LocaleUtils.toLocale(value.asString().replace('-','_')); | |||||
} | |||||
} | |||||
@ -0,0 +1,13 @@ | |||||
package com.henninghall.date_picker.props; | |||||
import com.facebook.react.bridge.Dynamic; | |||||
public class MaximumDateProp extends Prop<String> { | |||||
public static final String name = "maximumDate"; | |||||
@Override | |||||
public String toValue(Dynamic value){ | |||||
return value.asString(); | |||||
} | |||||
} |
@ -0,0 +1,13 @@ | |||||
package com.henninghall.date_picker.props; | |||||
import com.facebook.react.bridge.Dynamic; | |||||
public class MinimumDateProp extends Prop<String> { | |||||
public static final String name = "minimumDate"; | |||||
@Override | |||||
public String toValue(Dynamic value){ | |||||
return value.asString(); | |||||
} | |||||
} |
@ -0,0 +1,17 @@ | |||||
package com.henninghall.date_picker.props; | |||||
import com.facebook.react.bridge.Dynamic; | |||||
import com.henninghall.date_picker.models.Mode; | |||||
public class MinuteIntervalProp extends Prop<Integer> { | |||||
public static final String name = "minuteInterval"; | |||||
public MinuteIntervalProp(){ | |||||
super(1); | |||||
} | |||||
public Integer toValue(Dynamic value){ | |||||
return value.asInt(); | |||||
} | |||||
} |
@ -0,0 +1,13 @@ | |||||
package com.henninghall.date_picker.props; | |||||
import com.facebook.react.bridge.Dynamic; | |||||
import com.henninghall.date_picker.models.Mode; | |||||
public class ModeProp extends Prop<Mode> { | |||||
public static final String name = "mode"; | |||||
@Override | |||||
public Mode toValue(Dynamic value){ | |||||
return Mode.valueOf(value.asString()); | |||||
} | |||||
} |
@ -0,0 +1,28 @@ | |||||
package com.henninghall.date_picker.props; | |||||
import com.facebook.react.bridge.Dynamic; | |||||
public abstract class Prop<T> { | |||||
private T value; | |||||
public Prop() { } | |||||
public Prop(T defaultValue) { | |||||
value = defaultValue; | |||||
} | |||||
abstract T toValue(Dynamic value); | |||||
public void setValue(Dynamic value){ | |||||
this.value = toValue(value); | |||||
} | |||||
public void setValue(T value){ | |||||
this.value = value; | |||||
} | |||||
public T getValue(){ | |||||
return value; | |||||
} | |||||
} |
@ -0,0 +1,13 @@ | |||||
package com.henninghall.date_picker.props; | |||||
import com.facebook.react.bridge.Dynamic; | |||||
public class TextColorProp extends Prop<String> { | |||||
public static final String name = "textColor"; | |||||
@Override | |||||
public String toValue(Dynamic value){ | |||||
return value.asString(); | |||||
} | |||||
} |
@ -0,0 +1,12 @@ | |||||
package com.henninghall.date_picker.props; | |||||
import com.facebook.react.bridge.Dynamic; | |||||
public class UtcProp extends Prop<Boolean> { | |||||
public static final String name = "utc"; | |||||
@Override | |||||
Boolean toValue(Dynamic value) { | |||||
return value.asBoolean(); | |||||
} | |||||
} |
@ -0,0 +1,45 @@ | |||||
package com.henninghall.date_picker.ui; | |||||
import android.view.View; | |||||
import com.henninghall.date_picker.PickerView; | |||||
import com.henninghall.date_picker.State; | |||||
import com.henninghall.date_picker.Utils; | |||||
import java.util.HashMap; | |||||
import cn.carbswang.android.numberpickerview.library.NumberPickerView; | |||||
public class EmptyWheels { | |||||
private final HashMap<Integer, NumberPickerView> views; | |||||
private final Wheels wheels; | |||||
private View rootView; | |||||
private State state; | |||||
EmptyWheels(View rootView, Wheels wheels, State state) { | |||||
this.wheels = wheels; | |||||
this.rootView = rootView; | |||||
this.state = state; | |||||
this.views = getViews(); | |||||
} | |||||
private HashMap<Integer, NumberPickerView> getViews() { | |||||
HashMap<Integer, NumberPickerView> views = new HashMap<>(); | |||||
for (int id: Utils.emptyWheelIds) { | |||||
NumberPickerView view = (NumberPickerView) rootView.findViewById(id); | |||||
views.put(id, view); | |||||
} | |||||
return views; | |||||
} | |||||
void add() { | |||||
int numberOfVisibleWheels = state.getVisibleWheels().size(); | |||||
int emptyViewsToAdd = numberOfVisibleWheels + 1; | |||||
for (int i = 0; i < emptyViewsToAdd; i++) { | |||||
int index = i * 2; | |||||
wheels.addWheel(views.get(Utils.emptyWheelIds[i]), index); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,42 @@ | |||||
package com.henninghall.date_picker.ui; | |||||
import android.graphics.Color; | |||||
import android.graphics.drawable.GradientDrawable; | |||||
import android.view.View; | |||||
import android.widget.ImageView; | |||||
import com.henninghall.date_picker.R; | |||||
import com.henninghall.date_picker.State; | |||||
public class FadingOverlay { | |||||
private final GradientDrawable gradientTop; | |||||
private final GradientDrawable gradientBottom; | |||||
private final State state; | |||||
public FadingOverlay(State state, View rootView) { | |||||
this.state = state; | |||||
ImageView overlayTop = (ImageView) rootView.findViewById(R.id.overlay_top); | |||||
ImageView overlayBottom = (ImageView) rootView.findViewById(R.id.overlay_bottom); | |||||
gradientTop = (GradientDrawable) overlayTop.getDrawable(); | |||||
gradientBottom = (GradientDrawable) overlayBottom.getDrawable(); | |||||
} | |||||
public void updateColor(){ | |||||
String color = state.getFadeToColor(); | |||||
int alpha = validColor(color) ? 255 : 0; | |||||
gradientTop.setAlpha(alpha); | |||||
gradientBottom.setAlpha(alpha); | |||||
if(validColor(color)) { | |||||
int startColor = Color.parseColor("#FF"+ color.substring(1)); | |||||
int endColor = Color.parseColor("#00" + color.substring(1)); | |||||
gradientTop.setColors(new int[] {startColor, endColor}); | |||||
gradientBottom.setColors(new int[] {startColor, endColor}); | |||||
} | |||||
} | |||||
private boolean validColor(String color){ | |||||
return color != null && color.length() == 7; | |||||
} | |||||
} |
@ -0,0 +1,87 @@ | |||||
package com.henninghall.date_picker.ui; | |||||
import android.view.View; | |||||
import com.henninghall.date_picker.State; | |||||
import com.henninghall.date_picker.Utils; | |||||
import com.henninghall.date_picker.wheelFunctions.AnimateToDate; | |||||
import com.henninghall.date_picker.wheelFunctions.Refresh; | |||||
import com.henninghall.date_picker.wheelFunctions.SetDate; | |||||
import com.henninghall.date_picker.wheelFunctions.SetShowCount; | |||||
import com.henninghall.date_picker.wheelFunctions.TextColor; | |||||
import com.henninghall.date_picker.wheelFunctions.UpdateVisibility; | |||||
import com.henninghall.date_picker.wheels.Wheel; | |||||
import java.text.SimpleDateFormat; | |||||
import java.util.Calendar; | |||||
import cn.carbswang.android.numberpickerview.library.NumberPickerView; | |||||
public class UIManager { | |||||
private final State state; | |||||
private final View rootView; | |||||
private Wheels wheels; | |||||
private FadingOverlay fadingOverlay; | |||||
private WheelScroller wheelScroller = new WheelScroller(); | |||||
public UIManager(State state, View rootView){ | |||||
this.rootView = rootView; | |||||
this.state = state; | |||||
wheels = new Wheels(state, rootView, this); | |||||
fadingOverlay = new FadingOverlay(state, rootView); | |||||
} | |||||
public void updateWheelVisibility(){ | |||||
wheels.applyOnAll(new UpdateVisibility()); | |||||
} | |||||
public void updateTextColor(){ | |||||
wheels.applyOnAll(new TextColor(state.getTextColor())); | |||||
} | |||||
public void updateFadeToColor(){ | |||||
fadingOverlay.updateColor(); | |||||
} | |||||
public void updateHeight(){ | |||||
int shownCount = state.getShownCount(); | |||||
wheels.applyOnAll(new SetShowCount(shownCount)); | |||||
setShownCountOnEmptyWheels(shownCount); | |||||
} | |||||
public void updateWheelOrder() { | |||||
wheels.removeAll(); | |||||
wheels.addInOrder(); | |||||
wheels.addEmpty(); | |||||
} | |||||
public void updateDisplayValues(){ | |||||
wheels.applyOnAll(new Refresh()); | |||||
} | |||||
public void setWheelsToDate(){ | |||||
wheels.applyOnAll(new SetDate(state.getDate())); | |||||
} | |||||
public void scroll(int wheelIndex, int scrollTimes) { | |||||
Wheel wheel = wheels.getWheel(state.getOrderedVisibleWheels().get(wheelIndex)); | |||||
wheelScroller.scroll(wheel,scrollTimes); | |||||
} | |||||
SimpleDateFormat getDateFormat() { | |||||
return new SimpleDateFormat(wheels.getFormatPattern(), state.getLocale()); | |||||
} | |||||
void animateToDate(Calendar date) { | |||||
wheels.applyOnVisible(new AnimateToDate(date)); | |||||
} | |||||
private void setShownCountOnEmptyWheels(int shownCount) { | |||||
for (int id : Utils.emptyWheelIds) { | |||||
NumberPickerView view = (NumberPickerView) rootView.findViewById(id); | |||||
if(view != null) view.setShownCount(shownCount); | |||||
} | |||||
} | |||||
} |
@ -1,4 +1,4 @@ | |||||
package com.henninghall.date_picker; | |||||
package com.henninghall.date_picker.ui; | |||||
import com.henninghall.date_picker.wheels.Wheel; | import com.henninghall.date_picker.wheels.Wheel; | ||||
@ -0,0 +1,60 @@ | |||||
package com.henninghall.date_picker.ui; | |||||
import android.view.View; | |||||
import com.facebook.react.bridge.Arguments; | |||||
import com.facebook.react.bridge.WritableMap; | |||||
import com.facebook.react.uimanager.events.RCTEventEmitter; | |||||
import com.henninghall.date_picker.DatePickerManager; | |||||
import com.henninghall.date_picker.PickerView; | |||||
import com.henninghall.date_picker.State; | |||||
import com.henninghall.date_picker.Utils; | |||||
import com.henninghall.date_picker.wheels.Wheel; | |||||
import java.text.ParseException; | |||||
import java.text.SimpleDateFormat; | |||||
import java.util.Calendar; | |||||
import java.util.Date; | |||||
import java.util.TimeZone; | |||||
public class WheelChangeListenerImpl implements WheelChangeListener { | |||||
private final Wheels wheels; | |||||
private final State state; | |||||
private final UIManager uiManager; | |||||
private final View rootView; | |||||
public WheelChangeListenerImpl(Wheels wheels, State state, UIManager uiManager, View rootView) { | |||||
this.wheels = wheels; | |||||
this.uiManager = uiManager; | |||||
this.state = state; | |||||
this.rootView = rootView; | |||||
} | |||||
@Override | |||||
public void onChange(Wheel picker) { | |||||
WritableMap event = Arguments.createMap(); | |||||
TimeZone timeZone = state.getTimeZone(); | |||||
SimpleDateFormat dateFormat = uiManager.getDateFormat(); | |||||
Calendar minDate = state.getMinimumDate(); | |||||
Calendar maxDate = state.getMaximumDate(); | |||||
try { | |||||
dateFormat.setTimeZone(timeZone); | |||||
Calendar date = Calendar.getInstance(timeZone); | |||||
String toParse = wheels.getDateString(); | |||||
Date newDate = dateFormat.parse(toParse); | |||||
date.setTime(newDate); | |||||
if (minDate != null && date.before(minDate)) uiManager.animateToDate(minDate); | |||||
else if (maxDate != null && date.after(maxDate)) uiManager.animateToDate(maxDate); | |||||
else { | |||||
event.putString("date", Utils.dateToIso(date)); | |||||
DatePickerManager.context.getJSModule(RCTEventEmitter.class) | |||||
.receiveEvent(rootView.getId(), "dateChange", event); | |||||
} | |||||
} catch (ParseException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,19 @@ | |||||
package com.henninghall.date_picker.ui; | |||||
import com.henninghall.date_picker.wheels.Wheel; | |||||
import cn.carbswang.android.numberpickerview.library.NumberPickerView; | |||||
public class WheelScroller { | |||||
public void scroll(Wheel wheel, int scrollTimes) { | |||||
NumberPickerView picker = wheel.picker; | |||||
int currentIndex = picker.getValue(); | |||||
int maxValue = picker.getMaxValue(); | |||||
boolean isWrapping = picker.getWrapSelectorWheel(); | |||||
int nextValue = currentIndex + scrollTimes; | |||||
if(nextValue <= maxValue || isWrapping) { | |||||
picker.smoothScrollToValue(nextValue % (maxValue + 1)); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,186 @@ | |||||
package com.henninghall.date_picker.ui; | |||||
import android.view.View; | |||||
import android.widget.LinearLayout; | |||||
import com.henninghall.date_picker.R; | |||||
import com.henninghall.date_picker.State; | |||||
import com.henninghall.date_picker.Utils; | |||||
import com.henninghall.date_picker.models.WheelType; | |||||
import com.henninghall.date_picker.models.Mode; | |||||
import com.henninghall.date_picker.wheelFunctions.AddOnChangeListener; | |||||
import com.henninghall.date_picker.wheelFunctions.WheelFunction; | |||||
import com.henninghall.date_picker.wheels.AmPmWheel; | |||||
import com.henninghall.date_picker.wheels.DateWheel; | |||||
import com.henninghall.date_picker.wheels.DayWheel; | |||||
import com.henninghall.date_picker.wheels.HourWheel; | |||||
import com.henninghall.date_picker.wheels.MinutesWheel; | |||||
import com.henninghall.date_picker.wheels.MonthWheel; | |||||
import com.henninghall.date_picker.wheels.Wheel; | |||||
import com.henninghall.date_picker.wheels.YearWheel; | |||||
import java.util.ArrayList; | |||||
import java.util.Arrays; | |||||
import java.util.Collection; | |||||
import java.util.HashMap; | |||||
import java.util.List; | |||||
import cn.carbswang.android.numberpickerview.library.NumberPickerView; | |||||
public class Wheels { | |||||
private final State state; | |||||
private HourWheel hourWheel; | |||||
private DayWheel dayWheel; | |||||
private MinutesWheel minutesWheel; | |||||
private AmPmWheel ampmWheel; | |||||
private DateWheel dateWheel; | |||||
private MonthWheel monthWheel; | |||||
private YearWheel yearWheel; | |||||
private View rootView; | |||||
private final LinearLayout wheelsWrapper; | |||||
private final EmptyWheels emptyWheels; | |||||
private HashMap<WheelType, Wheel> wheelPerWheelType; | |||||
private UIManager uiManager; | |||||
Wheels(State state, View rootView, UIManager uiManager){ | |||||
this.state = state; | |||||
this.rootView = rootView; | |||||
this.uiManager = uiManager; | |||||
wheelsWrapper = (LinearLayout) rootView.findViewById(R.id.wheelsWrapper); | |||||
wheelsWrapper.setWillNotDraw(false); | |||||
yearWheel = new YearWheel(getPickerWithId(R.id.year), state); | |||||
monthWheel = new MonthWheel(getPickerWithId(R.id.month), state); | |||||
dateWheel = new DateWheel(getPickerWithId(R.id.date), state); | |||||
dayWheel = new DayWheel(getPickerWithId(R.id.day), state); | |||||
minutesWheel = new MinutesWheel(getPickerWithId(R.id.minutes), state); | |||||
ampmWheel = new AmPmWheel(getPickerWithId(R.id.ampm), state); | |||||
hourWheel = new HourWheel(getPickerWithId(R.id.hour), state); | |||||
wheelPerWheelType = getWheelPerType(); | |||||
changeAmPmWhenPassingMidnightOrNoon(); | |||||
addOnChangeListener(); | |||||
emptyWheels = new EmptyWheels(rootView,this,state); | |||||
} | |||||
private void addOnChangeListener(){ | |||||
WheelChangeListener onWheelChangeListener = new WheelChangeListenerImpl(this, state, uiManager, rootView); | |||||
applyOnAll(new AddOnChangeListener(onWheelChangeListener)); | |||||
} | |||||
private NumberPickerView getPickerWithId(int id){ | |||||
return (NumberPickerView) rootView.findViewById(id); | |||||
} | |||||
private Collection<Wheel> getVisible() { | |||||
ArrayList<WheelType> wheelTypes = state.getVisibleWheels(); | |||||
Collection<Wheel> wheels = new ArrayList<>(); | |||||
for (WheelType type: wheelTypes){ | |||||
wheels.add(getWheel(type)); | |||||
} | |||||
return wheels; | |||||
} | |||||
void applyOnAll(WheelFunction function) { | |||||
for (Wheel wheel: getAll()) function.apply(wheel); | |||||
} | |||||
void applyOnVisible(WheelFunction function) { | |||||
for (Wheel wheel: getVisible()) function.apply(wheel); | |||||
} | |||||
Wheel getWheel(WheelType type){ | |||||
return wheelPerWheelType.get(type); | |||||
} | |||||
void addInOrder(){ | |||||
ArrayList<WheelType> wheels = state.getOrderedVisibleWheels(); | |||||
for (WheelType wheelType : wheels) { | |||||
Wheel wheel = getWheel(wheelType); | |||||
addWheel(wheel.picker); | |||||
} | |||||
} | |||||
private ArrayList<Wheel> getOrderedWheels(){ | |||||
ArrayList<Wheel> list = new ArrayList<>(); | |||||
for (WheelType type : state.getOrderedVisibleWheels()) { | |||||
list.add(getWheel(type)); | |||||
} | |||||
return list; | |||||
} | |||||
void addWheel(View wheel) { wheelsWrapper.addView(wheel); } | |||||
void addWheel(View wheel, int index) { wheelsWrapper.addView(wheel,index); } | |||||
void removeAll() { | |||||
wheelsWrapper.removeAllViews(); | |||||
} | |||||
private void changeAmPmWhenPassingMidnightOrNoon() { | |||||
hourWheel.picker.setOnValueChangeListenerInScrolling(new NumberPickerView.OnValueChangeListenerInScrolling() { | |||||
@Override | |||||
public void onValueChangeInScrolling(NumberPickerView picker, int oldVal, int newVal) { | |||||
if(Utils.usesAmPm()){ | |||||
String oldValue = hourWheel.getValueAtIndex(oldVal); | |||||
String newValue = hourWheel.getValueAtIndex(newVal); | |||||
boolean passingNoonOrMidnight = (oldValue.equals("12") && newValue.equals("11")) || oldValue.equals("11") && newValue.equals("12"); | |||||
if (passingNoonOrMidnight) ampmWheel.picker.smoothScrollToValue((ampmWheel.picker.getValue() + 1) % 2,false); | |||||
} | |||||
} | |||||
}); | |||||
} | |||||
private List<Wheel> getAll(){ | |||||
return new ArrayList<>(Arrays.asList(yearWheel, monthWheel, dateWheel, dayWheel, hourWheel, minutesWheel, ampmWheel)); | |||||
} | |||||
private String getDateFormatPattern(){ | |||||
ArrayList<Wheel> wheels = getOrderedWheels(); | |||||
if(state.getMode() == Mode.date){ | |||||
return wheels.get(0).getFormatPattern() + " " | |||||
+ wheels.get(1).getFormatPattern() + " " | |||||
+ wheels.get(2).getFormatPattern(); | |||||
} | |||||
return dayWheel.getFormatPattern(); | |||||
} | |||||
public String getFormatPattern() { | |||||
return this.getDateFormatPattern() + " " | |||||
+ hourWheel.getFormatPattern() + " " | |||||
+ minutesWheel.getFormatPattern() | |||||
+ ampmWheel.getFormatPattern(); | |||||
} | |||||
String getDateString() { | |||||
ArrayList<Wheel> wheels = getOrderedWheels(); | |||||
String dateString = (state.getMode() == Mode.date) | |||||
? wheels.get(0).getValue() + " " | |||||
+ wheels.get(1).getValue() + " " | |||||
+ wheels.get(2).getValue() | |||||
: dayWheel.getValue(); | |||||
return dateString | |||||
+ " " + hourWheel.getValue() | |||||
+ " " + minutesWheel.getValue() | |||||
+ ampmWheel.getValue(); | |||||
} | |||||
private HashMap<WheelType, Wheel> getWheelPerType(){ | |||||
return new HashMap<WheelType, Wheel>() {{ | |||||
put(WheelType.DAY, dayWheel); | |||||
put(WheelType.YEAR, yearWheel); | |||||
put(WheelType.MONTH,monthWheel); | |||||
put(WheelType.DATE, dateWheel); | |||||
put(WheelType.HOUR, hourWheel); | |||||
put(WheelType.MINUTE, minutesWheel); | |||||
put(WheelType.AM_PM, ampmWheel); | |||||
}}; | |||||
} | |||||
void addEmpty() { | |||||
emptyWheels.add(); | |||||
} | |||||
} |
@ -0,0 +1,27 @@ | |||||
package com.henninghall.date_picker.wheelFunctions; | |||||
import com.henninghall.date_picker.ui.WheelChangeListener; | |||||
import com.henninghall.date_picker.wheels.Wheel; | |||||
import cn.carbswang.android.numberpickerview.library.NumberPickerView; | |||||
public class AddOnChangeListener implements WheelFunction { | |||||
private final WheelChangeListener onChangeListener; | |||||
public AddOnChangeListener(WheelChangeListener onChangeListener){ | |||||
this.onChangeListener = onChangeListener; | |||||
} | |||||
@Override | |||||
public void apply(final Wheel wheel) { | |||||
wheel.picker.setOnValueChangedListener(new NumberPickerView.OnValueChangeListener() { | |||||
@Override | |||||
public void onValueChange(NumberPickerView picker, int oldVal, int newVal) { | |||||
onChangeListener.onChange(wheel); | |||||
} | |||||
}); | |||||
} | |||||
} | |||||