Browse Source

fix(android): min/max dates not always correct when `timezoneOffsetInMinutes` is set (#635)

master
Henning Hall 2 years ago
committed by GitHub
parent
commit
40e74b2706
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 85 additions and 57 deletions
  1. +25
    -2
      .maestro/timezone-offset-in-minutes.yml
  2. +11
    -1
      .maestro/utils/select-region.yml
  3. +0
    -8
      .maestro/utils/set-timezone-us.yml
  4. +2
    -1
      .maestro/utils/set-timezone.yml
  5. +2
    -10
      android/src/main/java/com/henninghall/date_picker/DatePickerManager.java
  6. +2
    -2
      android/src/main/java/com/henninghall/date_picker/PickerView.java
  7. +16
    -9
      android/src/main/java/com/henninghall/date_picker/State.java
  8. +6
    -0
      android/src/main/java/com/henninghall/date_picker/Utils.java
  9. +13
    -0
      android/src/main/java/com/henninghall/date_picker/props/TimezoneOffsetInMinutesProp.java
  10. +0
    -12
      android/src/main/java/com/henninghall/date_picker/props/UtcProp.java
  11. +0
    -4
      android/src/main/java/com/henninghall/date_picker/wheels/DayWheel.java
  12. +8
    -8
      src/DatePickerAndroid.js

+ 25
- 2
.maestro/timezone-offset-in-minutes.yml View File

@ -3,8 +3,9 @@ appId: com.rn069
- runFlow:
file: utils/set-timezone.yml
env:
TIMEZONE: Sweden
REGION: Sweden
GMT: GMT+01:00
STATE: ''
- runFlow: utils/launch.yml
@ -53,8 +54,9 @@ appId: com.rn069
- runFlow:
file: utils/set-timezone.yml
env:
TIMEZONE: Sweden
REGION: Sweden
GMT: GMT+02:00
STATE: ''
- runFlow: utils/launch.yml
@ -118,3 +120,24 @@ appId: com.rn069
- assertVisible: 'Thu Jun 1101 AM '
- runFlow: utils/reset.yml
# test: timezoneOffsetInMinutes combined with maximumDate/minimumDate in another timezone than current device.
# Bug was reported here: https://github.com/henninghall/react-native-date-picker/issues/613
- runFlow:
file: utils/set-timezone.yml
env:
REGION: 'United states'
STATE: Phoenix
GMT: GMT-07:00
- runFlow: utils/launch.yml
- runFlow:
file: utils/change-prop.yml
env:
PROP: timeZoneOffsetInMinutes
VALUE: 180
- repeat:
times: 5
commands:
- runFlow: utils/swipe-wheel-1.yml
- runFlow: utils/swipe-wheel-4.yml
- assertVisible: 'Thu Jan 61000 AM '

+ 11
- 1
.maestro/utils/select-region.yml View File

@ -1,4 +1,14 @@
appId: com.android.settings
---
- tapOn: Region
- inputText: ${TIMEZONE}
- inputText: ${REGION}
- tapOn:
text: ${REGION}
index: 1
- runFlow:
when:
true: ${REGION == 'United states'}
file: tap.yml
env:
TEXT: ${STATE}

+ 0
- 8
.maestro/utils/set-timezone-us.yml View File

@ -1,8 +0,0 @@
appId: com.android.settings
---
- runFlow:
file: set-timezone.yml
env:
TIMEZONE: 'United states'
GMT: ${GMT}
- tapOn: ${STATE}

+ 2
- 1
.maestro/utils/set-timezone.yml View File

@ -29,4 +29,5 @@ appId: com.android.settings
visible: Region
file: select-region.yml
env:
TIMEZONE: ${TIMEZONE}
REGION: ${REGION}
STATE: ${STATE}

+ 2
- 10
android/src/main/java/com/henninghall/date_picker/DatePickerManager.java View File

@ -1,18 +1,10 @@
package com.henninghall.date_picker;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.facebook.react.bridge.Dynamic;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.SimpleViewManager;
@ -29,7 +21,7 @@ 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.TextColorProp;
import com.henninghall.date_picker.props.UtcProp;
import com.henninghall.date_picker.props.TimezoneOffsetInMinutesProp;
import java.lang.reflect.Method;
@ -54,7 +46,7 @@ public class DatePickerManager extends SimpleViewManager {
}
@ReactPropGroup(names = { DateProp.name, ModeProp.name, LocaleProp.name, MaximumDateProp.name,
MinimumDateProp.name, FadeToColorProp.name, TextColorProp.name, UtcProp.name, MinuteIntervalProp.name,
MinimumDateProp.name, FadeToColorProp.name, TextColorProp.name, TimezoneOffsetInMinutesProp.name, MinuteIntervalProp.name,
VariantProp.name, DividerHeightProp.name, Is24hourSourceProp.name
})
public void setProps(PickerView view, int index, Dynamic value) {

+ 2
- 2
android/src/main/java/com/henninghall/date_picker/PickerView.java View File

@ -11,7 +11,7 @@ import com.henninghall.date_picker.props.Is24hourSourceProp;
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.UtcProp;
import com.henninghall.date_picker.props.TimezoneOffsetInMinutesProp;
import com.henninghall.date_picker.props.VariantProp;
import com.henninghall.date_picker.props.DateProp;
import com.henninghall.date_picker.props.FadeToColorProp;
@ -77,7 +77,7 @@ public class PickerView extends RelativeLayout {
if (didUpdate(DateProp.name, HeightProp.name, LocaleProp.name,
MaximumDateProp.name, MinimumDateProp.name, MinuteIntervalProp.name, ModeProp.name,
UtcProp.name, VariantProp.name
TimezoneOffsetInMinutesProp.name, VariantProp.name
)) {
uiManager.updateDisplayValues();
}

+ 16
- 9
android/src/main/java/com/henninghall/date_picker/State.java View File

@ -17,7 +17,9 @@ 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 com.henninghall.date_picker.props.TimezoneOffsetInMinutesProp;
import net.time4j.tz.Timezone;
import java.util.Calendar;
import java.util.HashMap;
@ -35,7 +37,7 @@ public class State {
private final MinuteIntervalProp minuteIntervalProp = new MinuteIntervalProp();
private final MinimumDateProp minimumDateProp = new MinimumDateProp();
private final MaximumDateProp maximumDateProp = new MaximumDateProp();
private final UtcProp utcProp = new UtcProp();
private final TimezoneOffsetInMinutesProp timezoneOffsetInMinutesProp = new TimezoneOffsetInMinutesProp();
private final HeightProp heightProp = new HeightProp();
private final VariantProp variantProp = new VariantProp();
private final DividerHeightProp dividerHeightProp = new DividerHeightProp();
@ -50,7 +52,7 @@ public class State {
put(MinuteIntervalProp.name, minuteIntervalProp);
put(MinimumDateProp.name, minimumDateProp);
put(MaximumDateProp.name, maximumDateProp);
put(UtcProp.name, utcProp);
put(TimezoneOffsetInMinutesProp.name, timezoneOffsetInMinutesProp);
put(HeightProp.name, heightProp);
put(VariantProp.name, variantProp);
put(DividerHeightProp.name, dividerHeightProp);
@ -91,18 +93,23 @@ public class State {
}
public Calendar getMinimumDate() {
DateBoundary db = new DateBoundary(getTimeZone(), (String) minimumDateProp.getValue());
return db.get();
return Utils.isoToCalendar(minimumDateProp.getValue(), getTimeZone());
}
public Calendar getMaximumDate() {
DateBoundary db = new DateBoundary(getTimeZone(), (String) maximumDateProp.getValue());
return db.get();
return Utils.isoToCalendar(maximumDateProp.getValue(), getTimeZone());
}
public TimeZone getTimeZone() {
boolean utc = (boolean) utcProp.getValue();
return utc ? TimeZone.getTimeZone("UTC") : TimeZone.getDefault();
Integer offset = timezoneOffsetInMinutesProp.getValue();
if(offset == null) return TimeZone.getDefault();
int totalOffsetMinutes = Math.abs(offset);
char offsetDirection = offset < 0 ? '-' : '+';
int offsetHours = (int) Math.floor(totalOffsetMinutes / 60f);
int offsetMinutes = totalOffsetMinutes - offsetHours * 60;
String timeZoneId = "GMT" + offsetDirection + offsetHours + ":" + Utils.toPaddedMinutes(offsetMinutes);
TimeZone zone = TimeZone.getTimeZone(timeZoneId);
return zone;
}
public String getIsoDate() {

+ 6
- 0
android/src/main/java/com/henninghall/date_picker/Utils.java View File

@ -9,6 +9,7 @@ import com.henninghall.date_picker.models.WheelType;
import net.time4j.PrettyTime;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@ -110,4 +111,9 @@ public class Utils {
public static int toDp(int pixels){
return (int) (pixels * DatePickerPackage.context.getResources().getDisplayMetrics().density);
}
public static String toPaddedMinutes(int minutes){
DecimalFormat df = new DecimalFormat("00");
return df.format(minutes);
}
}

+ 13
- 0
android/src/main/java/com/henninghall/date_picker/props/TimezoneOffsetInMinutesProp.java View File

@ -0,0 +1,13 @@
package com.henninghall.date_picker.props;
import com.facebook.react.bridge.Dynamic;
public class TimezoneOffsetInMinutesProp extends Prop<Integer> {
public static final String name = "timezoneOffsetInMinutes";
@Override
Integer toValue(Dynamic value) {
if(value.isNull()) return null;
return value.asInt();
}
}

+ 0
- 12
android/src/main/java/com/henninghall/date_picker/props/UtcProp.java View File

@ -1,12 +0,0 @@
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
- 4
android/src/main/java/com/henninghall/date_picker/wheels/DayWheel.java View File

@ -50,10 +50,8 @@ public class DayWheel extends Wheel {
Calendar min = state.getMinimumDate();
if (min != null) {
cal = (Calendar) min.clone();
resetToMidnight(cal);
} else if (max != null) {
cal = (Calendar) max.clone();
resetToMidnight(cal);
cal.add(Calendar.DATE, -cal.getActualMaximum(Calendar.DAY_OF_YEAR) / 2);
} else {
cal = (Calendar) getInitialDate().clone();
@ -68,10 +66,8 @@ public class DayWheel extends Wheel {
Calendar min = state.getMinimumDate();
if (max != null) {
cal = (Calendar) max.clone();
resetToMidnight(cal);
} else if (min != null) {
cal = (Calendar) min.clone();
resetToMidnight(cal);
cal.add(Calendar.DATE, cal.getActualMaximum(Calendar.DAY_OF_YEAR) / 2);
} else {
cal = (Calendar) getInitialDate().clone();

+ 8
- 8
src/DatePickerAndroid.js View File

@ -46,10 +46,15 @@ class DatePickerAndroid extends React.PureComponent {
date: this._date(),
minimumDate: this._minimumDate(),
maximumDate: this._maximumDate(),
utc: this.props.timeZoneOffsetInMinutes !== undefined,
timezoneOffsetInMinutes: this._getTimezoneOffsetInMinutes(),
style: this._getStyle(),
})
_getTimezoneOffsetInMinutes = () => {
if (this.props.timeZoneOffsetInMinutes == undefined) return undefined
return this.props.timeZoneOffsetInMinutes
}
_getStyle = () => {
const width = this.props.mode === 'time' ? timeModeWidth : defaultWidth
return [{ width, height }, this.props.style]
@ -74,16 +79,11 @@ class DatePickerAndroid extends React.PureComponent {
_date = () => this._toIsoWithTimeZoneOffset(this.props.date)
_fromIsoWithTimeZoneOffset = (timestamp) => {
const date = new Date(timestamp)
if (this.props.timeZoneOffsetInMinutes === undefined) return date
return addMinutes(date, -this.props.timeZoneOffsetInMinutes)
return new Date(timestamp)
}
_toIsoWithTimeZoneOffset = (date) => {
if (this.props.timeZoneOffsetInMinutes === undefined)
return date.toISOString()
return addMinutes(date, this.props.timeZoneOffsetInMinutes).toISOString()
return date.toISOString()
}
_onConfirm = (isoDate) => {

Loading…
Cancel
Save