Remove DatePickerAndroid from react-native-github

Summary:
Changelog:
[JavaScript][Removed] - Remove DatePickerAndroid from React Native

Reviewed By: lunaleaps, yungsters

Differential Revision: D30281952

fbshipit-source-id: 5cd0ad2ad741afeef3e6f8a39635c6baf4b79b38
This commit is contained in:
Andres Riveros Moya
2021-08-25 13:38:25 -07:00
committed by Facebook GitHub Bot
parent 25c5d194ad
commit 7a770526c6
15 changed files with 15 additions and 837 deletions
@@ -1,27 +0,0 @@
load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "react_native_root_target", "react_native_target", "rn_android_library")
rn_android_library(
name = "datepicker",
srcs = glob(["**/*.java"]),
autoglob = False,
is_androidx = True,
labels = ["supermodule:xplat/default/public.react_native.infra"],
provided_deps = [
react_native_dep("third-party/android/androidx:annotation"),
react_native_dep("third-party/android/androidx:core"),
react_native_dep("third-party/android/androidx:fragment"),
react_native_dep("third-party/android/androidx:legacy-support-core-ui"),
react_native_dep("third-party/android/androidx:legacy-support-core-utils"),
],
visibility = [
"PUBLIC",
],
deps = [
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
react_native_dep("third-party/java/jsr-305:jsr-305"),
react_native_target("java/com/facebook/react/bridge:bridge"),
react_native_target("java/com/facebook/react/common:common"),
react_native_target("java/com/facebook/react/module/annotations:annotations"),
],
exported_deps = [react_native_root_target(":FBReactNativeSpec")],
)
@@ -1,137 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.modules.datepicker;
import android.annotation.SuppressLint;
import android.app.DatePickerDialog;
import android.app.DatePickerDialog.OnDateSetListener;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.widget.DatePicker;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import java.util.Calendar;
import java.util.Locale;
@SuppressLint("ValidFragment")
public class DatePickerDialogFragment extends DialogFragment {
/** Minimum date supported by {@link DatePicker}, 01 Jan 1900 */
private static final long DEFAULT_MIN_DATE = -2208988800001l;
@Nullable private OnDateSetListener mOnDateSetListener;
@Nullable private OnDismissListener mOnDismissListener;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Bundle args = getArguments();
return createDialog(args, getActivity(), mOnDateSetListener);
}
/*package*/ static Dialog createDialog(
Bundle args, Context activityContext, @Nullable OnDateSetListener onDateSetListener) {
final Calendar c = Calendar.getInstance();
if (args != null && args.containsKey(DatePickerDialogModule.ARG_DATE)) {
c.setTimeInMillis(args.getLong(DatePickerDialogModule.ARG_DATE));
}
final int year = c.get(Calendar.YEAR);
final int month = c.get(Calendar.MONTH);
final int day = c.get(Calendar.DAY_OF_MONTH);
DatePickerMode mode = DatePickerMode.DEFAULT;
if (args != null && args.getString(DatePickerDialogModule.ARG_MODE, null) != null) {
mode =
DatePickerMode.valueOf(
args.getString(DatePickerDialogModule.ARG_MODE).toUpperCase(Locale.US));
}
DatePickerDialog dialog = null;
switch (mode) {
case CALENDAR:
dialog =
new DismissableDatePickerDialog(
activityContext,
activityContext
.getResources()
.getIdentifier(
"CalendarDatePickerDialog", "style", activityContext.getPackageName()),
onDateSetListener,
year,
month,
day);
break;
case SPINNER:
dialog =
new DismissableDatePickerDialog(
activityContext,
android.R.style.Theme_Holo_Light_Dialog,
onDateSetListener,
year,
month,
day);
dialog
.getWindow()
.setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
break;
case DEFAULT:
dialog =
new DismissableDatePickerDialog(activityContext, onDateSetListener, year, month, day);
break;
}
final DatePicker datePicker = dialog.getDatePicker();
if (args != null && args.containsKey(DatePickerDialogModule.ARG_MINDATE)) {
// Set minDate to the beginning of the day. We need this because of clowniness in datepicker
// that causes it to throw an exception if minDate is greater than the internal timestamp
// that it generates from the y/m/d passed in the constructor.
c.setTimeInMillis(args.getLong(DatePickerDialogModule.ARG_MINDATE));
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
datePicker.setMinDate(c.getTimeInMillis());
} else {
// This is to work around a bug in DatePickerDialog where it doesn't display a title showing
// the date under certain conditions.
datePicker.setMinDate(DEFAULT_MIN_DATE);
}
if (args != null && args.containsKey(DatePickerDialogModule.ARG_MAXDATE)) {
// Set maxDate to the end of the day, same reason as for minDate.
c.setTimeInMillis(args.getLong(DatePickerDialogModule.ARG_MAXDATE));
c.set(Calendar.HOUR_OF_DAY, 23);
c.set(Calendar.MINUTE, 59);
c.set(Calendar.SECOND, 59);
c.set(Calendar.MILLISECOND, 999);
datePicker.setMaxDate(c.getTimeInMillis());
}
return dialog;
}
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
if (mOnDismissListener != null) {
mOnDismissListener.onDismiss(dialog);
}
}
/*package*/ void setOnDateSetListener(@Nullable OnDateSetListener onDateSetListener) {
mOnDateSetListener = onDateSetListener;
}
/*package*/ void setOnDismissListener(@Nullable OnDismissListener onDismissListener) {
mOnDismissListener = onDismissListener;
}
}
@@ -1,153 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.modules.datepicker;
import android.app.Activity;
import android.app.DatePickerDialog.OnDateSetListener;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.os.Bundle;
import android.widget.DatePicker;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import com.facebook.fbreact.specs.NativeDatePickerAndroidSpec;
import com.facebook.react.bridge.*;
import com.facebook.react.common.annotations.VisibleForTesting;
import com.facebook.react.module.annotations.ReactModule;
/**
* {@link NativeModule} that allows JS to show a native date picker dialog and get called back when
* the user selects a date.
*/
@ReactModule(name = DatePickerDialogModule.FRAGMENT_TAG)
public class DatePickerDialogModule extends NativeDatePickerAndroidSpec {
@VisibleForTesting public static final String FRAGMENT_TAG = "DatePickerAndroid";
private static final String ERROR_NO_ACTIVITY = "E_NO_ACTIVITY";
/* package */ static final String ARG_DATE = "date";
/* package */ static final String ARG_MINDATE = "minDate";
/* package */ static final String ARG_MAXDATE = "maxDate";
/* package */ static final String ARG_MODE = "mode";
/* package */ static final String ACTION_DATE_SET = "dateSetAction";
/* package */ static final String ACTION_DISMISSED = "dismissedAction";
public DatePickerDialogModule(ReactApplicationContext reactContext) {
super(reactContext);
}
public @NonNull String getName() {
return DatePickerDialogModule.FRAGMENT_TAG;
}
private class DatePickerDialogListener implements OnDateSetListener, OnDismissListener {
private final Promise mPromise;
private boolean mPromiseResolved = false;
public DatePickerDialogListener(final Promise promise) {
mPromise = promise;
}
@Override
public void onDateSet(DatePicker view, int year, int month, int day) {
if (!mPromiseResolved && getReactApplicationContext().hasActiveReactInstance()) {
WritableMap result = new WritableNativeMap();
result.putString("action", ACTION_DATE_SET);
result.putInt("year", year);
result.putInt("month", month);
result.putInt("day", day);
mPromise.resolve(result);
mPromiseResolved = true;
}
}
@Override
public void onDismiss(DialogInterface dialog) {
if (!mPromiseResolved && getReactApplicationContext().hasActiveReactInstance()) {
WritableMap result = new WritableNativeMap();
result.putString("action", ACTION_DISMISSED);
mPromise.resolve(result);
mPromiseResolved = true;
}
}
}
/**
* Show a date picker dialog.
*
* @param options a map containing options. Available keys are:
* <ul>
* <li>{@code date} (timestamp in milliseconds) the date to show by default
* <li>{@code minDate} (timestamp in milliseconds) the minimum date the user should be
* allowed to select
* <li>{@code maxDate} (timestamp in milliseconds) the maximum date the user should be
* allowed to select
* <li>{@code mode} To set the date picker mode to 'calendar/spinner/default'
* </ul>
*
* @param promise This will be invoked with parameters action, year, month (0-11), day, where
* action is {@code dateSetAction} or {@code dismissedAction}, depending on what the user did.
* If the action is dismiss, year, month and date are undefined.
*/
@Override
public void open(@Nullable final ReadableMap options, final Promise promise) {
Activity raw_activity = getCurrentActivity();
if (raw_activity == null || !(raw_activity instanceof FragmentActivity)) {
promise.reject(
ERROR_NO_ACTIVITY,
"Tried to open a DatePicker dialog while not attached to a FragmentActivity");
return;
}
FragmentActivity activity = (FragmentActivity) raw_activity;
final FragmentManager fragmentManager = activity.getSupportFragmentManager();
DialogFragment oldFragment = (DialogFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
if (oldFragment != null) {
oldFragment.dismiss();
}
activity.runOnUiThread(
new Runnable() {
@Override
public void run() {
DatePickerDialogFragment fragment = new DatePickerDialogFragment();
if (options != null) {
final Bundle args = createFragmentArguments(options);
fragment.setArguments(args);
}
final DatePickerDialogListener listener = new DatePickerDialogListener(promise);
fragment.setOnDismissListener(listener);
fragment.setOnDateSetListener(listener);
fragment.show(fragmentManager, FRAGMENT_TAG);
}
});
}
private Bundle createFragmentArguments(ReadableMap options) {
final Bundle args = new Bundle();
if (options.hasKey(ARG_DATE) && !options.isNull(ARG_DATE)) {
args.putLong(ARG_DATE, (long) options.getDouble(ARG_DATE));
}
if (options.hasKey(ARG_MINDATE) && !options.isNull(ARG_MINDATE)) {
args.putLong(ARG_MINDATE, (long) options.getDouble(ARG_MINDATE));
}
if (options.hasKey(ARG_MAXDATE) && !options.isNull(ARG_MAXDATE)) {
args.putLong(ARG_MAXDATE, (long) options.getDouble(ARG_MAXDATE));
}
if (options.hasKey(ARG_MODE) && !options.isNull(ARG_MODE)) {
args.putString(ARG_MODE, options.getString(ARG_MODE));
}
return args;
}
}
@@ -1,15 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.modules.datepicker;
/** Date picker modes */
public enum DatePickerMode {
CALENDAR,
SPINNER,
DEFAULT
}
@@ -1,117 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.modules.datepicker;
import android.app.DatePickerDialog;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.DatePicker;
import androidx.annotation.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class DismissableDatePickerDialog extends DatePickerDialog {
public DismissableDatePickerDialog(
Context context,
@Nullable DatePickerDialog.OnDateSetListener callback,
int year,
int monthOfYear,
int dayOfMonth) {
super(context, callback, year, monthOfYear, dayOfMonth);
fixSpinner(context, year, monthOfYear, dayOfMonth);
}
public DismissableDatePickerDialog(
Context context,
int theme,
@Nullable DatePickerDialog.OnDateSetListener callback,
int year,
int monthOfYear,
int dayOfMonth) {
super(context, theme, callback, year, monthOfYear, dayOfMonth);
fixSpinner(context, year, monthOfYear, dayOfMonth);
}
private void fixSpinner(Context context, int year, int month, int dayOfMonth) {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N) {
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);
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");
// 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);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private static Field findField(Class objectClass, Class fieldClass, String expectedName) {
try {
Field field = objectClass.getDeclaredField(expectedName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
} // ignore
// search for it if it wasn't found under the expected ivar name
for (Field searchField : objectClass.getDeclaredFields()) {
if (searchField.getType() == fieldClass) {
searchField.setAccessible(true);
return searchField;
}
}
return null;
}
}
@@ -34,7 +34,6 @@ rn_android_library(
react_native_target("java/com/facebook/react/modules/camera:camera"),
react_native_target("java/com/facebook/react/modules/clipboard:clipboard"),
react_native_target("java/com/facebook/react/modules/core:core"),
react_native_target("java/com/facebook/react/modules/datepicker:datepicker"),
react_native_target("java/com/facebook/react/modules/debug:debug"),
react_native_target("java/com/facebook/react/modules/dialog:dialog"),
react_native_target("java/com/facebook/react/modules/fresco:fresco"),
@@ -23,7 +23,6 @@ import com.facebook.react.modules.blob.BlobModule;
import com.facebook.react.modules.blob.FileReaderModule;
import com.facebook.react.modules.camera.ImageStoreManager;
import com.facebook.react.modules.clipboard.ClipboardModule;
import com.facebook.react.modules.datepicker.DatePickerDialogModule;
import com.facebook.react.modules.dialog.DialogModule;
import com.facebook.react.modules.fresco.FrescoModule;
import com.facebook.react.modules.i18nmanager.I18nManagerModule;
@@ -72,7 +71,6 @@ import java.util.Map;
FileReaderModule.class,
AsyncStorageModule.class,
ClipboardModule.class,
DatePickerDialogModule.class,
DialogModule.class,
FrescoModule.class,
I18nManagerModule.class,
@@ -117,8 +115,6 @@ public class MainReactPackage extends TurboReactPackage {
return new AsyncStorageModule(context);
case ClipboardModule.NAME:
return new ClipboardModule(context);
case DatePickerDialogModule.FRAGMENT_TAG:
return new DatePickerDialogModule(context);
case DialogModule.NAME:
return new DialogModule(context);
case FrescoModule.NAME:
@@ -199,7 +195,6 @@ public class MainReactPackage extends TurboReactPackage {
FileReaderModule.class,
AsyncStorageModule.class,
ClipboardModule.class,
DatePickerDialogModule.class,
DialogModule.class,
FrescoModule.class,
I18nManagerModule.class,