mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-05-03 15:24:58 +08:00
Open source Android date and time pickers
Reviewed By: bestander Differential Revision: D2856486 fb-gh-sync-id: 0bb81136289e2f121387649765ba682103e4701b
This commit is contained in:
committed by
facebook-github-bot-8
parent
5f0ef12cb5
commit
9a0539d2c4
@@ -0,0 +1,20 @@
|
||||
include_defs('//ReactAndroid/DEFS')
|
||||
|
||||
android_library(
|
||||
name = 'timepicker',
|
||||
srcs = glob(['**/*.java']),
|
||||
deps = [
|
||||
react_native_target('java/com/facebook/react/bridge:bridge'),
|
||||
react_native_target('java/com/facebook/react/common:common'),
|
||||
react_native_dep('third-party/android/support/v4:lib-support-v4'),
|
||||
react_native_dep('third-party/java/infer-annotations:infer-annotations'),
|
||||
react_native_dep('third-party/java/jsr-305:jsr-305'),
|
||||
],
|
||||
visibility = [
|
||||
'PUBLIC',
|
||||
],
|
||||
)
|
||||
|
||||
project_config(
|
||||
src_target = ':timepicker',
|
||||
)
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.modules.timepicker;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import android.app.TimePickerDialog;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Certain versions of Android (Jellybean-KitKat) have a bug where when dismissed, the
|
||||
* {@link TimePickerDialog} still calls the OnTimeSetListener. This class works around that issue
|
||||
* by *not* calling super.onStop on KitKat on lower, as that would erroneously call the
|
||||
* OnTimeSetListener when the dialog is dismissed, or call it twice when "OK" is pressed.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* See: <a href="https://code.google.com/p/android/issues/detail?id=34833">Issue 34833</a>
|
||||
* </p>
|
||||
*/
|
||||
public class DismissableTimePickerDialog extends TimePickerDialog {
|
||||
|
||||
public DismissableTimePickerDialog(
|
||||
Context context,
|
||||
@Nullable OnTimeSetListener callback,
|
||||
int hourOfDay,
|
||||
int minute,
|
||||
boolean is24HourView) {
|
||||
super(context, callback, hourOfDay, minute, is24HourView);
|
||||
}
|
||||
|
||||
public DismissableTimePickerDialog(
|
||||
Context context,
|
||||
int theme,
|
||||
@Nullable OnTimeSetListener callback,
|
||||
int hourOfDay,
|
||||
int minute,
|
||||
boolean is24HourView) {
|
||||
super(context, theme, callback, hourOfDay, minute, is24HourView);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
|
||||
super.onStop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.modules.timepicker;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.TimePickerDialog.OnTimeSetListener;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnDismissListener;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
|
||||
@SuppressWarnings("ValidFragment")
|
||||
public class SupportTimePickerDialogFragment extends DialogFragment {
|
||||
|
||||
@Nullable
|
||||
private OnTimeSetListener mOnTimeSetListener;
|
||||
@Nullable
|
||||
private OnDismissListener mOnDismissListener;
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final Bundle args = getArguments();
|
||||
return TimePickerDialogFragment.createDialog(args, getActivity(), mOnTimeSetListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
super.onDismiss(dialog);
|
||||
if (mOnDismissListener != null) {
|
||||
mOnDismissListener.onDismiss(dialog);
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnDismissListener(@Nullable OnDismissListener onDismissListener) {
|
||||
mOnDismissListener = onDismissListener;
|
||||
}
|
||||
|
||||
public void setOnTimeSetListener(@Nullable OnTimeSetListener onTimeSetListener) {
|
||||
mOnTimeSetListener = onTimeSetListener;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.modules.timepicker;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.DialogFragment;
|
||||
import android.app.TimePickerDialog.OnTimeSetListener;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnDismissListener;
|
||||
import android.os.Bundle;
|
||||
import android.text.format.DateFormat;
|
||||
|
||||
@SuppressWarnings("ValidFragment")
|
||||
public class TimePickerDialogFragment extends DialogFragment {
|
||||
|
||||
@Nullable
|
||||
private OnTimeSetListener mOnTimeSetListener;
|
||||
@Nullable
|
||||
private OnDismissListener mOnDismissListener;
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final Bundle args = getArguments();
|
||||
return createDialog(args, getActivity(), mOnTimeSetListener);
|
||||
}
|
||||
|
||||
/*package*/ static Dialog createDialog(
|
||||
Bundle args, Context activityContext, @Nullable OnTimeSetListener onTimeSetListener
|
||||
) {
|
||||
final Calendar now = Calendar.getInstance();
|
||||
int hour = now.get(Calendar.HOUR_OF_DAY);
|
||||
int minute = now.get(Calendar.MINUTE);
|
||||
boolean is24hour = DateFormat.is24HourFormat(activityContext);
|
||||
|
||||
if (args != null) {
|
||||
hour = args.getInt(TimePickerDialogModule.ARG_HOUR, now.get(Calendar.HOUR_OF_DAY));
|
||||
minute = args.getInt(TimePickerDialogModule.ARG_MINUTE, now.get(Calendar.MINUTE));
|
||||
is24hour = args.getBoolean(
|
||||
TimePickerDialogModule.ARG_IS24HOUR,
|
||||
DateFormat.is24HourFormat(activityContext));
|
||||
}
|
||||
|
||||
return new DismissableTimePickerDialog(
|
||||
activityContext,
|
||||
onTimeSetListener,
|
||||
hour,
|
||||
minute,
|
||||
is24hour);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
super.onDismiss(dialog);
|
||||
if (mOnDismissListener != null) {
|
||||
mOnDismissListener.onDismiss(dialog);
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnDismissListener(@Nullable OnDismissListener onDismissListener) {
|
||||
mOnDismissListener = onDismissListener;
|
||||
}
|
||||
|
||||
public void setOnTimeSetListener(@Nullable OnTimeSetListener onTimeSetListener) {
|
||||
mOnTimeSetListener = onTimeSetListener;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.modules.timepicker;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.DialogFragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.TimePickerDialog.OnTimeSetListener;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnDismissListener;
|
||||
import android.os.Bundle;
|
||||
import android.widget.TimePicker;
|
||||
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.bridge.WritableNativeMap;
|
||||
import com.facebook.react.common.annotations.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* {@link NativeModule} that allows JS to show a native time picker dialog and get called back when
|
||||
* the user selects a time.
|
||||
*/
|
||||
public class TimePickerDialogModule extends ReactContextBaseJavaModule {
|
||||
|
||||
@VisibleForTesting
|
||||
public static final String FRAGMENT_TAG = "TimePickerAndroid";
|
||||
|
||||
private static final String ERROR_NO_ACTIVITY = "E_NO_ACTIVITY";
|
||||
|
||||
/* package */ static final String ARG_HOUR = "hour";
|
||||
/* package */ static final String ARG_MINUTE = "minute";
|
||||
/* package */ static final String ARG_IS24HOUR = "is24Hour";
|
||||
/* package */ static final String ACTION_TIME_SET = "timeSetAction";
|
||||
/* package */ static final String ACTION_DISMISSED = "dismissedAction";
|
||||
|
||||
public TimePickerDialogModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "TimePickerAndroid";
|
||||
}
|
||||
|
||||
private class TimePickerDialogListener implements OnTimeSetListener, OnDismissListener {
|
||||
|
||||
private final Promise mPromise;
|
||||
private boolean mPromiseResolved = false;
|
||||
|
||||
public TimePickerDialogListener(Promise promise) {
|
||||
mPromise = promise;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeSet(TimePicker view, int hour, int minute) {
|
||||
if (!mPromiseResolved && getReactApplicationContext().hasActiveCatalystInstance()) {
|
||||
WritableMap result = new WritableNativeMap();
|
||||
result.putString("action", ACTION_TIME_SET);
|
||||
result.putInt("hour", hour);
|
||||
result.putInt("minute", minute);
|
||||
mPromise.resolve(result);
|
||||
mPromiseResolved = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
if (!mPromiseResolved && getReactApplicationContext().hasActiveCatalystInstance()) {
|
||||
WritableMap result = new WritableNativeMap();
|
||||
result.putString("action", ACTION_DISMISSED);
|
||||
mPromise.resolve(result);
|
||||
mPromiseResolved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void open(@Nullable final ReadableMap options, Promise promise) {
|
||||
|
||||
Activity activity = getCurrentActivity();
|
||||
if (activity == null) {
|
||||
promise.reject(
|
||||
ERROR_NO_ACTIVITY,
|
||||
"Tried to open a TimePicker dialog while not attached to an Activity");
|
||||
return;
|
||||
}
|
||||
// We want to support both android.app.Activity and the pre-Honeycomb FragmentActivity
|
||||
// (for apps that use it for legacy reasons). This unfortunately leads to some code duplication.
|
||||
if (activity instanceof android.support.v4.app.FragmentActivity) {
|
||||
android.support.v4.app.FragmentManager fragmentManager =
|
||||
((android.support.v4.app.FragmentActivity) activity).getSupportFragmentManager();
|
||||
android.support.v4.app.DialogFragment oldFragment =
|
||||
(android.support.v4.app.DialogFragment)fragmentManager.findFragmentByTag(FRAGMENT_TAG);
|
||||
if (oldFragment != null) {
|
||||
oldFragment.dismiss();
|
||||
}
|
||||
SupportTimePickerDialogFragment fragment = new SupportTimePickerDialogFragment();
|
||||
if (options != null) {
|
||||
Bundle args = createFragmentArguments(options);
|
||||
fragment.setArguments(args);
|
||||
}
|
||||
TimePickerDialogListener listener = new TimePickerDialogListener(promise);
|
||||
fragment.setOnDismissListener(listener);
|
||||
fragment.setOnTimeSetListener(listener);
|
||||
fragment.show(fragmentManager, FRAGMENT_TAG);
|
||||
} else {
|
||||
FragmentManager fragmentManager = activity.getFragmentManager();
|
||||
DialogFragment oldFragment = (DialogFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
|
||||
if (oldFragment != null) {
|
||||
oldFragment.dismiss();
|
||||
}
|
||||
TimePickerDialogFragment fragment = new TimePickerDialogFragment();
|
||||
if (options != null) {
|
||||
final Bundle args = createFragmentArguments(options);
|
||||
fragment.setArguments(args);
|
||||
}
|
||||
TimePickerDialogListener listener = new TimePickerDialogListener(promise);
|
||||
fragment.setOnDismissListener(listener);
|
||||
fragment.setOnTimeSetListener(listener);
|
||||
fragment.show(fragmentManager, FRAGMENT_TAG);
|
||||
}
|
||||
}
|
||||
|
||||
private Bundle createFragmentArguments(ReadableMap options) {
|
||||
final Bundle args = new Bundle();
|
||||
if (options.hasKey(ARG_HOUR) && !options.isNull(ARG_HOUR)) {
|
||||
args.putInt(ARG_HOUR, options.getInt(ARG_HOUR));
|
||||
}
|
||||
if (options.hasKey(ARG_MINUTE) && !options.isNull(ARG_MINUTE)) {
|
||||
args.putInt(ARG_MINUTE, options.getInt(ARG_MINUTE));
|
||||
}
|
||||
if (options.hasKey(ARG_IS24HOUR) && !options.isNull(ARG_IS24HOUR)) {
|
||||
args.putBoolean(ARG_IS24HOUR, options.getBoolean(ARG_IS24HOUR));
|
||||
}
|
||||
return args;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user