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 { | |||
date, time, datetime |
@ -1,4 +1,4 @@ | |||
package com.henninghall.date_picker; | |||
package com.henninghall.date_picker.models; | |||
public enum WheelType { | |||
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; | |||
@ -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); | |||
} | |||
}); | |||
} | |||
} | |||