From f26dcc954f2aa82d94cc30f7532c8fe8809a67d0 Mon Sep 17 00:00:00 2001 From: Tomasz Sapeta Date: Mon, 25 May 2020 23:49:39 +0200 Subject: [PATCH 1/3] [android][ios] Update @react-native-community/datetimepicker to 2.4.0 --- .../RNDatePickerDialogFragment.java | 9 ++- .../RNDismissableDatePickerDialog.java | 80 ++++++++----------- .../RNDismissableTimePickerDialog.java | 62 +++++++------- .../RNTimePickerDialogFragment.java | 6 +- apps/native-component-list/package.json | 2 +- ios/Exponent.xcodeproj/project.pbxproj | 1 - .../DateTimePicker/RNDateTimePickerManager.m | 17 ++++ packages/expo/bundledNativeModules.json | 2 +- yarn.lock | 8 +- 9 files changed, 96 insertions(+), 91 deletions(-) diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDatePickerDialogFragment.java b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDatePickerDialogFragment.java index c6ab8507a0f29..f08081b58885e 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDatePickerDialogFragment.java +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDatePickerDialogFragment.java @@ -82,18 +82,21 @@ DatePickerDialog getDialog( onDateSetListener, year, month, - day); + day, + display + ); default: return new RNDismissableDatePickerDialog( activityContext, onDateSetListener, year, month, - day + day, + display ); } } else { - DatePickerDialog dialog = new RNDismissableDatePickerDialog(activityContext, onDateSetListener, year, month, day); + DatePickerDialog dialog = new RNDismissableDatePickerDialog(activityContext, onDateSetListener, year, month, day, display); switch (display) { case CALENDAR: dialog.getDatePicker().setCalendarViewShown(true); diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDismissableDatePickerDialog.java b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDismissableDatePickerDialog.java index b1b861def9ab9..4e21a2ead5f23 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDismissableDatePickerDialog.java +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDismissableDatePickerDialog.java @@ -37,9 +37,10 @@ public RNDismissableDatePickerDialog( @Nullable DatePickerDialog.OnDateSetListener callback, int year, int monthOfYear, - int dayOfMonth) { + int dayOfMonth, + RNDatePickerDisplay display) { super(context, callback, year, monthOfYear, dayOfMonth); - fixSpinner(context, year, monthOfYear, dayOfMonth); + fixSpinner(context, year, monthOfYear, dayOfMonth, display); } public RNDismissableDatePickerDialog( @@ -48,9 +49,10 @@ public RNDismissableDatePickerDialog( @Nullable DatePickerDialog.OnDateSetListener callback, int year, int monthOfYear, - int dayOfMonth) { + int dayOfMonth, + RNDatePickerDisplay display) { super(context, theme, callback, year, monthOfYear, dayOfMonth); - fixSpinner(context, year, monthOfYear, dayOfMonth); + fixSpinner(context, year, monthOfYear, dayOfMonth, display); } @Override @@ -62,57 +64,43 @@ protected void onStop() { } } - private void fixSpinner(Context context, int year, int month, int dayOfMonth) { - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N) { + private void fixSpinner(Context context, int year, int month, int dayOfMonth, RNDatePickerDisplay display) { + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N && display == RNDatePickerDisplay.SPINNER) { try { // Get the theme's android:datePickerMode - final int MODE_SPINNER = 2; Class styleableClass = Class.forName("com.android.internal.R$styleable"); Field datePickerStyleableField = styleableClass.getField("DatePicker"); int[] datePickerStyleable = (int[]) datePickerStyleableField.get(null); - - final TypedArray a = - context.obtainStyledAttributes( - null, datePickerStyleable, android.R.attr.datePickerStyle, 0); - Field datePickerModeStyleableField = styleableClass.getField("DatePicker_datePickerMode"); - int datePickerModeStyleable = datePickerModeStyleableField.getInt(null); - final int mode = a.getInt(datePickerModeStyleable, MODE_SPINNER); + final TypedArray a = context.obtainStyledAttributes(null, datePickerStyleable, android.R.attr.datePickerStyle, 0); a.recycle(); - if (mode == MODE_SPINNER) { - DatePicker datePicker = - (DatePicker) - findField(DatePickerDialog.class, DatePicker.class, "mDatePicker").get(this); - Class delegateClass = Class.forName("android.widget.DatePickerSpinnerDelegate"); - Field delegateField = findField(DatePicker.class, delegateClass, "mDelegate"); - Object delegate = delegateField.get(datePicker); - Class spinnerDelegateClass; - spinnerDelegateClass = Class.forName("android.widget.DatePickerSpinnerDelegate"); + DatePicker datePicker = (DatePicker)findField(DatePickerDialog.class, DatePicker.class, "mDatePicker").get(this); + Class delegateClass = Class.forName("android.widget.DatePickerSpinnerDelegate"); + Field delegateField = findField(DatePicker.class, delegateClass, "mDelegate"); + Object delegate = delegateField.get(datePicker); + Class spinnerDelegateClass; + spinnerDelegateClass = Class.forName("android.widget.DatePickerSpinnerDelegate"); - // In 7.0 Nougat for some reason the datePickerMode is ignored and the delegate is - // DatePickerClockDelegate - if (delegate.getClass() != spinnerDelegateClass) { - delegateField.set(datePicker, null); // throw out the DatePickerClockDelegate! - datePicker.removeAllViews(); // remove the DatePickerClockDelegate views - Method createSpinnerUIDelegate = - DatePicker.class.getDeclaredMethod( - "createSpinnerUIDelegate", - Context.class, - AttributeSet.class, - int.class, - int.class); - createSpinnerUIDelegate.setAccessible(true); + // In 7.0 Nougat for some reason the datePickerMode is ignored and the delegate is + // DatePickerClockDelegate + if (delegate.getClass() != spinnerDelegateClass) { + delegateField.set(datePicker, null); // throw out the DatePickerClockDelegate! + datePicker.removeAllViews(); // remove the DatePickerClockDelegate views + Method createSpinnerUIDelegate = + DatePicker.class.getDeclaredMethod( + "createSpinnerUIDelegate", + Context.class, + AttributeSet.class, + int.class, + int.class); + createSpinnerUIDelegate.setAccessible(true); - // Instantiate a DatePickerSpinnerDelegate throughout createSpinnerUIDelegate method - delegate = - createSpinnerUIDelegate.invoke( - datePicker, context, null, android.R.attr.datePickerStyle, 0); - delegateField.set( - datePicker, delegate); // set the DatePicker.mDelegate to the spinner delegate - datePicker.setCalendarViewShown(false); - // Initialize the date for the DatePicker delegate again - datePicker.init(year, month, dayOfMonth, this); - } + // Instantiate a DatePickerSpinnerDelegate throughout createSpinnerUIDelegate method + delegate = createSpinnerUIDelegate.invoke(datePicker, context, null, android.R.attr.datePickerStyle, 0); + delegateField.set(datePicker, delegate); // set the DatePicker.mDelegate to the spinner delegate + datePicker.setCalendarViewShown(false); + // Initialize the date for the DatePicker delegate again + datePicker.init(year, month, dayOfMonth, this); } } catch (Exception e) { throw new RuntimeException(e); diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDismissableTimePickerDialog.java b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDismissableTimePickerDialog.java index 7c5c7ef55a93a..90192bc4125f6 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDismissableTimePickerDialog.java +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDismissableTimePickerDialog.java @@ -38,9 +38,10 @@ public RNDismissableTimePickerDialog( @Nullable TimePickerDialog.OnTimeSetListener callback, int hourOfDay, int minute, - boolean is24HourView) { + boolean is24HourView, + RNTimePickerDisplay display) { super(context, callback, hourOfDay, minute, is24HourView); - fixSpinner(context, hourOfDay, minute, is24HourView); + fixSpinner(context, hourOfDay, minute, is24HourView, display); } public RNDismissableTimePickerDialog( @@ -49,9 +50,10 @@ public RNDismissableTimePickerDialog( @Nullable TimePickerDialog.OnTimeSetListener callback, int hourOfDay, int minute, - boolean is24HourView) { + boolean is24HourView, + RNTimePickerDisplay display) { super(context, theme, callback, hourOfDay, minute, is24HourView); - fixSpinner(context, hourOfDay, minute, is24HourView); + fixSpinner(context, hourOfDay, minute, is24HourView, display); } @Override @@ -61,41 +63,35 @@ protected void onStop() { } } - private void fixSpinner(Context context, int hourOfDay, int minute, boolean is24HourView) { - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N) { + private void fixSpinner(Context context, int hourOfDay, int minute, boolean is24HourView, RNTimePickerDisplay display) { + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N && display == RNTimePickerDisplay.SPINNER) { try { - // Get the theme's android:timePickerMode - final int MODE_SPINNER = 1; Class styleableClass = Class.forName("com.android.internal.R$styleable"); Field timePickerStyleableField = styleableClass.getField("TimePicker"); int[] timePickerStyleable = (int[]) timePickerStyleableField.get(null); final TypedArray a = context.obtainStyledAttributes(null, timePickerStyleable, android.R.attr.timePickerStyle, 0); - Field timePickerModeStyleableField = styleableClass.getField("TimePicker_timePickerMode"); - int timePickerModeStyleable = timePickerModeStyleableField.getInt(null); - final int mode = a.getInt(timePickerModeStyleable, MODE_SPINNER); a.recycle(); - if (mode == MODE_SPINNER) { - TimePicker timePicker = (TimePicker) findField(TimePickerDialog.class, TimePicker.class, "mTimePicker").get(this); - Class delegateClass = Class.forName("android.widget.TimePicker$TimePickerDelegate"); - Field delegateField = findField(TimePicker.class, delegateClass, "mDelegate"); - Object delegate = delegateField.get(timePicker); - Class spinnerDelegateClass; - spinnerDelegateClass = Class.forName("android.widget.TimePickerSpinnerDelegate"); - // In 7.0 Nougat for some reason the timePickerMode is ignored and the delegate is TimePickerClockDelegate - if (delegate.getClass() != spinnerDelegateClass) { - delegateField.set(timePicker, null); // throw out the TimePickerClockDelegate! - timePicker.removeAllViews(); // remove the TimePickerClockDelegate views - Constructor spinnerDelegateConstructor = spinnerDelegateClass.getConstructor(TimePicker.class, Context.class, AttributeSet.class, int.class, int.class); - spinnerDelegateConstructor.setAccessible(true); - // Instantiate a TimePickerSpinnerDelegate - delegate = spinnerDelegateConstructor.newInstance(timePicker, context, null, android.R.attr.timePickerStyle, 0); - delegateField.set(timePicker, delegate); // set the TimePicker.mDelegate to the spinner delegate - // Set up the TimePicker again, with the TimePickerSpinnerDelegate - timePicker.setIs24HourView(is24HourView); - timePicker.setCurrentHour(hourOfDay); - timePicker.setCurrentMinute(minute); - timePicker.setOnTimeChangedListener(this); - } + + TimePicker timePicker = (TimePicker) findField(TimePickerDialog.class, TimePicker.class, "mTimePicker").get(this); + Class delegateClass = Class.forName("android.widget.TimePicker$TimePickerDelegate"); + Field delegateField = findField(TimePicker.class, delegateClass, "mDelegate"); + Object delegate = delegateField.get(timePicker); + Class spinnerDelegateClass; + spinnerDelegateClass = Class.forName("android.widget.TimePickerSpinnerDelegate"); + // In 7.0 Nougat for some reason the timePickerMode is ignored and the delegate is TimePickerClockDelegate + if (delegate.getClass() != spinnerDelegateClass) { + delegateField.set(timePicker, null); // throw out the TimePickerClockDelegate! + timePicker.removeAllViews(); // remove the TimePickerClockDelegate views + Constructor spinnerDelegateConstructor = spinnerDelegateClass.getConstructor(TimePicker.class, Context.class, AttributeSet.class, int.class, int.class); + spinnerDelegateConstructor.setAccessible(true); + // Instantiate a TimePickerSpinnerDelegate + delegate = spinnerDelegateConstructor.newInstance(timePicker, context, null, android.R.attr.timePickerStyle, 0); + delegateField.set(timePicker, delegate); // set the TimePicker.mDelegate to the spinner delegate + // Set up the TimePicker again, with the TimePickerSpinnerDelegate + timePicker.setIs24HourView(is24HourView); + timePicker.setCurrentHour(hourOfDay); + timePicker.setCurrentMinute(minute); + timePicker.setOnTimeChangedListener(this); } } catch (Exception e) { throw new RuntimeException(e); diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNTimePickerDialogFragment.java b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNTimePickerDialogFragment.java index e7dd8f9e65ad8..32e9fa22c747f 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNTimePickerDialogFragment.java +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNTimePickerDialogFragment.java @@ -81,7 +81,8 @@ static TimePickerDialog getDialog( onTimeSetListener, hour, minute, - is24hour + is24hour, + display ); } } @@ -90,7 +91,8 @@ static TimePickerDialog getDialog( onTimeSetListener, hour, minute, - is24hour + is24hour, + display ); } diff --git a/apps/native-component-list/package.json b/apps/native-component-list/package.json index d609d56d7e9b2..cbb22b101782f 100644 --- a/apps/native-component-list/package.json +++ b/apps/native-component-list/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@expo/react-native-action-sheet": "^2.0.1", - "@react-native-community/datetimepicker": "2.2.2", + "@react-native-community/datetimepicker": "2.4.0", "@react-native-community/masked-view": "0.1.6", "@react-native-community/netinfo": "5.9.0", "@react-native-community/segmented-control": "1.6.1", diff --git a/ios/Exponent.xcodeproj/project.pbxproj b/ios/Exponent.xcodeproj/project.pbxproj index 99bdb18090f63..393863b237afb 100644 --- a/ios/Exponent.xcodeproj/project.pbxproj +++ b/ios/Exponent.xcodeproj/project.pbxproj @@ -5,7 +5,6 @@ }; objectVersion = 46; objects = { - /* Begin PBXBuildFile section */ 0726F0592007E438004992E7 /* EXKernelAppRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 0726F0582007E438004992E7 /* EXKernelAppRecord.m */; }; 0726F05C2007E446004992E7 /* EXKernelAppRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = 0726F05B2007E446004992E7 /* EXKernelAppRegistry.m */; }; diff --git a/ios/Exponent/Versioned/Core/Api/Components/DateTimePicker/RNDateTimePickerManager.m b/ios/Exponent/Versioned/Core/Api/Components/DateTimePicker/RNDateTimePickerManager.m index 661e1f1781174..731ceeb17b992 100644 --- a/ios/Exponent/Versioned/Core/Api/Components/DateTimePicker/RNDateTimePickerManager.m +++ b/ios/Exponent/Versioned/Core/Api/Components/DateTimePicker/RNDateTimePickerManager.m @@ -40,4 +40,21 @@ - (UIView *)view RCT_REMAP_VIEW_PROPERTY(mode, datePickerMode, UIDatePickerMode) RCT_REMAP_VIEW_PROPERTY(timeZoneOffsetInMinutes, timeZone, NSTimeZone) +RCT_CUSTOM_VIEW_PROPERTY(textColor, UIColor, RNDateTimePicker) +{ + if (json) { + [view setValue:[RCTConvert UIColor:json] forKey:@"textColor"]; + [view setValue:@(NO) forKey:@"highlightsToday"]; + } else { + UIColor* defaultColor; + if (@available(iOS 13.0, *)) { + defaultColor = [UIColor labelColor]; + } else { + defaultColor = [UIColor blackColor]; + } + [view setValue:defaultColor forKey:@"textColor"]; + [view setValue:@(YES) forKey:@"highlightsToday"]; + } +} + @end diff --git a/packages/expo/bundledNativeModules.json b/packages/expo/bundledNativeModules.json index f24ede4b5fd61..2366d45ee9572 100644 --- a/packages/expo/bundledNativeModules.json +++ b/packages/expo/bundledNativeModules.json @@ -87,7 +87,7 @@ "expo-network": "~2.1.1", "expo-store-review": "~2.1.0", "expo-updates": "~0.2.5", - "@react-native-community/datetimepicker": "2.2.2", + "@react-native-community/datetimepicker": "2.4.0", "@react-native-community/masked-view": "0.1.6", "@react-native-community/viewpager": "3.3.0", "@react-native-community/segmented-control": "1.6.1", diff --git a/yarn.lock b/yarn.lock index 41d86b5a28df3..cc09aea4438ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2409,10 +2409,10 @@ wcwidth "^1.0.1" ws "^1.1.0" -"@react-native-community/datetimepicker@2.2.2": - version "2.2.2" - resolved "https://registry.yarnpkg.com/@react-native-community/datetimepicker/-/datetimepicker-2.2.2.tgz#4c6388631179098cc5b289146e879764f79af4c1" - integrity sha512-J4Z1tuZQszLR+BNu+UusZlK6/S+CpI6AHzolqTdPS2tRlyVbVim3KyjXrn8trtKxQncR5LEqF9OHw9zsRfEdXA== +"@react-native-community/datetimepicker@2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@react-native-community/datetimepicker/-/datetimepicker-2.4.0.tgz#6b3cf050f507f9b70d31d5a572e1153bb5bd50c9" + integrity sha512-ZXPwNAQt4T66PTL20l2nSEbtsn6vtsvFqdYWBfx8aaNKBoCPDygR6SsYzWcIoexKH5wmX0zctSzIsryl+Gtngg== dependencies: invariant "^2.2.4" From 5ae5333ff854ba449183b80c0b03b0af8e5ee7ab Mon Sep 17 00:00:00 2001 From: Tomasz Sapeta Date: Mon, 25 May 2020 23:50:11 +0200 Subject: [PATCH 2/3] [ncl] Update DateTimePicker example --- .../src/screens/DateTimePickerScreen.tsx | 162 ++++++++++-------- 1 file changed, 93 insertions(+), 69 deletions(-) diff --git a/apps/native-component-list/src/screens/DateTimePickerScreen.tsx b/apps/native-component-list/src/screens/DateTimePickerScreen.tsx index d3a6abaa12044..a706cf423c9a3 100644 --- a/apps/native-component-list/src/screens/DateTimePickerScreen.tsx +++ b/apps/native-component-list/src/screens/DateTimePickerScreen.tsx @@ -1,24 +1,16 @@ -import { - SafeAreaView, - ScrollView, - StyleSheet, - View, - Text, - StatusBar, - Button, - Platform, -} from 'react-native'; +import { ScrollView, StyleSheet, View, Text, Button, Platform, TextInput } from 'react-native'; import DateTimePicker from '@react-native-community/datetimepicker'; import React, { useState } from 'react'; import moment from 'moment'; -// This example is a copy from https://github.com/react-native-community/react-native-datetimepicker/tree/master/example +// This example is a refactored copy from https://github.com/react-native-community/react-native-datetimepicker/tree/master/example // Please try to keep it up to date when updating @react-native-community/datetimepicker package :) const DateTimePickerScreen = () => { const [date, setDate] = useState(new Date(1598051730000)); const [mode, setMode] = useState('date'); const [show, setShow] = useState(false); + const [color, setColor] = useState(); const [display, setDisplay] = useState('default'); const onChange = (event, selectedDate) => { @@ -45,66 +37,86 @@ const DateTimePickerScreen = () => { const showTimepicker = () => { showMode('time'); + setDisplay('default'); + }; + + const showTimepickerSpinner = () => { + showMode('time'); + setDisplay('spinner'); }; return ( - <> - - - - {global.HermesInternal == null ? null : ( - - Engine: Hermes - - )} - - - - Example DateTime Picker - - -