Open source Android date and time pickers

Reviewed By: bestander

Differential Revision: D2856486

fb-gh-sync-id: 0bb81136289e2f121387649765ba682103e4701b
This commit is contained in:
Martin Konicek 2016-01-26 10:29:47 -08:00 committed by facebook-github-bot-8
parent 5f0ef12cb5
commit 9a0539d2c4
29 changed files with 1275 additions and 41 deletions

View File

@ -0,0 +1,117 @@
/**
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
'use strict';
var React = require('react-native');
var {
DatePickerAndroid,
StyleSheet,
Text,
TouchableWithoutFeedback,
} = React;
var UIExplorerBlock = require('./UIExplorerBlock');
var UIExplorerPage = require('./UIExplorerPage');
var DatePickerAndroidExample = React.createClass({
statics: {
title: 'DatePickerAndroid',
description: 'Standard Android date picker dialog',
},
getInitialState() {
return {
presetDate: new Date(2020, 4, 5),
allDate: new Date(2020, 4, 5),
simpleText: 'pick a date',
minText: 'pick a date, no earlier than today',
maxText: 'pick a date, no later than today',
presetText: 'pick a date, preset to 2020/5/5',
allText: 'pick a date between 2020/5/1 and 2020/5/10',
};
},
async showPicker(stateKey, options) {
try {
var newState = {};
const {action, year, month, day} = await DatePickerAndroid.open(options);
if (action === DatePickerAndroid.dismissedAction) {
newState[stateKey + 'Text'] = 'dismissed';
} else {
var date = new Date(year, month, day);
newState[stateKey + 'Text'] = date.toLocaleDateString();
newState[stateKey + 'Date'] = date;
}
this.setState(newState);
} catch ({code, message}) {
console.warn(`Error in example '${stateKey}': `, message);
}
},
render() {
return (
<UIExplorerPage title="DatePickerAndroid">
<UIExplorerBlock title="Simple date picker">
<TouchableWithoutFeedback
onPress={this.showPicker.bind(this, 'simple', {date: this.state.simpleDate})}>
<Text style={styles.text}>{this.state.simpleText}</Text>
</TouchableWithoutFeedback>
</UIExplorerBlock>
<UIExplorerBlock title="Date picker with pre-set date">
<TouchableWithoutFeedback
onPress={this.showPicker.bind(this, 'preset', {date: this.state.presetDate})}>
<Text style={styles.text}>{this.state.presetText}</Text>
</TouchableWithoutFeedback>
</UIExplorerBlock>
<UIExplorerBlock title="Date picker with minDate">
<TouchableWithoutFeedback
onPress={this.showPicker.bind(this, 'min', {
date: this.state.minDate,
minDate: new Date(),
})}>
<Text style={styles.text}>{this.state.minText}</Text>
</TouchableWithoutFeedback>
</UIExplorerBlock>
<UIExplorerBlock title="Date picker with maxDate">
<TouchableWithoutFeedback
onPress={this.showPicker.bind(this, 'max', {
date: this.state.maxDate,
maxDate: new Date(),
})}>
<Text style={styles.text}>{this.state.maxText}</Text>
</TouchableWithoutFeedback>
</UIExplorerBlock>
<UIExplorerBlock title="Date picker with all options">
<TouchableWithoutFeedback
onPress={this.showPicker.bind(this, 'all', {
date: this.state.allDate,
minDate: new Date(2020, 4, 1),
maxDate: new Date(2020, 4, 10),
})}>
<Text style={styles.text}>{this.state.allText}</Text>
</TouchableWithoutFeedback>
</UIExplorerBlock>
</UIExplorerPage>
);
},
});
var styles = StyleSheet.create({
text: {
color: 'black',
},
});
module.exports = DatePickerAndroidExample;

View File

@ -30,7 +30,7 @@ var UIExplorerPage = require('./UIExplorerPage');
var ListViewSimpleExample = React.createClass({
statics: {
title: '<ListView> - Simple',
title: '<ListView>',
description: 'Performant, scrollable list of data.'
},
@ -50,7 +50,7 @@ var ListViewSimpleExample = React.createClass({
render: function() {
return (
<UIExplorerPage
title={this.props.navigator ? null : '<ListView> - Simple'}
title={this.props.navigator ? null : '<ListView>'}
noSpacer={true}
noScroll={true}>
<ListView

View File

@ -27,6 +27,12 @@ const {
const Item = PickerAndroid.Item;
const PickerAndroidExample = React.createClass({
statics: {
title: '<PickerAndroid>',
description: 'Provides multiple options to choose from, using either a dropdown menu or a dialog.',
},
getInitialState: function() {
return {
selected1: 'key1',
@ -124,19 +130,11 @@ const PickerAndroidExample = React.createClass({
this.setState({mode: newMode});
},
onSelect: function(key, value) {
onSelect: function(key: string, value: string) {
const newState = {};
newState[key] = value;
this.setState(newState);
},
});
exports.title = '<PickerAndroid>';
exports.displayName = 'PickerAndroidExample';
exports.description = 'The Android Picker component provides multiple options to choose from';
exports.examples = [
{
title: 'PickerAndroidExample',
render(): ReactElement { return <PickerAndroidExample />; }
},
];
module.exports = PickerAndroidExample;

View File

@ -69,7 +69,7 @@ const RefreshControlExample = React.createClass({
isRefreshing: false,
loaded: 0,
rowData: Array.from(new Array(20)).map(
(val, i) => ({text: 'Initial row' + i, clicks: 0})),
(val, i) => ({text: 'Initial row ' + i, clicks: 0})),
};
},
@ -108,7 +108,7 @@ const RefreshControlExample = React.createClass({
// prepend 10 items
const rowData = Array.from(new Array(10))
.map((val, i) => ({
text: 'Loaded row' + (+this.state.loaded + i),
text: 'Loaded row ' + (+this.state.loaded + i),
clicks: 0,
}))
.concat(this.state.rowData);

View File

@ -0,0 +1,112 @@
/**
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
'use strict';
var React = require('react-native');
var {
TimePickerAndroid,
StyleSheet,
Text,
TouchableWithoutFeedback,
} = React;
var UIExplorerBlock = require('./UIExplorerBlock');
var UIExplorerPage = require('./UIExplorerPage');
var TimePickerAndroidExample = React.createClass({
statics: {
title: 'TimePickerAndroid',
description: 'Standard Android time picker dialog',
},
getInitialState() {
// *Text, *Hour and *Minute are set by successCallback -- this updates the text with the time
// picked by the user and makes it so the next time they open it the hour and minute they picked
// before is displayed.
return {
isoFormatText: 'pick a time (24-hour format)',
presetHour: 4,
presetMinute: 4,
presetText: 'pick a time, default: 4:04AM',
simpleText: 'pick a time',
};
},
async showPicker(stateKey, options) {
try {
const {action, minute, hour} = await TimePickerAndroid.open(options);
var newState = {};
if (action === TimePickerAndroid.timeSetAction) {
newState[stateKey + 'Text'] = _formatTime(hour, minute);
newState[stateKey + 'Hour'] = hour;
newState[stateKey + 'Minute'] = minute;
} else if (action === TimePickerAndroid.dismissedAction) {
newState[stateKey + 'Text'] = 'dismissed';
}
this.setState(newState);
} catch ({code, message}) {
console.warn(`Error in example '${stateKey}': `, message);
}
},
render() {
return (
<UIExplorerPage title="TimePickerAndroid">
<UIExplorerBlock title="Simple time picker">
<TouchableWithoutFeedback
onPress={this.showPicker.bind(this, 'simple')}>
<Text style={styles.text}>{this.state.simpleText}</Text>
</TouchableWithoutFeedback>
</UIExplorerBlock>
<UIExplorerBlock title="Time picker with pre-set time">
<TouchableWithoutFeedback
onPress={this.showPicker.bind(this, 'preset', {
hour: this.state.presetHour,
minute: this.state.presetMinute,
})}>
<Text style={styles.text}>{this.state.presetText}</Text>
</TouchableWithoutFeedback>
</UIExplorerBlock>
<UIExplorerBlock title="Time picker with 24-hour time format">
<TouchableWithoutFeedback
onPress={this.showPicker.bind(this, 'isoFormat', {
hour: this.state.isoFormatHour,
minute: this.state.isoFormatMinute,
is24Hour: true,
})}>
<Text style={styles.text}>{this.state.isoFormatText}</Text>
</TouchableWithoutFeedback>
</UIExplorerBlock>
</UIExplorerPage>
);
},
});
/**
* Returns e.g. '3:05'.
*/
function _formatTime(hour, minute) {
return hour + ':' + (minute < 10 ? '0' + minute : minute);
}
var styles = StyleSheet.create({
text: {
color: 'black',
},
});
module.exports = TimePickerAndroidExample;

View File

@ -47,6 +47,7 @@ var APIS = [
require('./BorderExample'),
require('./CameraRollExample'),
require('./ClipboardExample'),
require('./DatePickerAndroidExample'),
require('./GeolocationExample'),
require('./IntentAndroidExample.android'),
require('./LayoutEventsExample'),
@ -54,6 +55,7 @@ var APIS = [
require('./NetInfoExample'),
require('./PanResponderExample'),
require('./PointerEventsExample'),
require('./TimePickerAndroidExample'),
require('./TimerExample'),
require('./ToastAndroidExample.android'),
require('./XHRExample'),

View File

@ -26,10 +26,10 @@ module.exports = {
*/
getString() {
if (arguments.length > 0) {
let callback = arguments[0];
console.warn('Clipboard.getString(callback) is deprecated. Use the returned Promise instead');
Clipboard.getString().then(callback);
return;
let callback = arguments[0];
console.warn('Clipboard.getString(callback) is deprecated. Use the returned Promise instead');
Clipboard.getString().then(callback);
return;
}
return Clipboard.getString();
},
@ -40,7 +40,7 @@ module.exports = {
* Clipboard.setString('hello world');
* }
* ```
* @param this parameter is content that will be set into clipboard.
* @param the content to be stored in the clipboard.
*/
setString(content) {
Clipboard.setString(content);

View File

@ -0,0 +1,84 @@
/**
* 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.
*
* @providesModule DatePickerAndroid
* @flow
*/
'use strict';
const DatePickerModule = require('NativeModules').DatePickerAndroid;
/**
* Convert a Date to a timestamp.
*/
function _toMillis(options: Object, key: string) {
const dateVal = options[key];
// Is it a Date object?
if (typeof dateVal === 'object' && typeof dateVal.getMonth === 'function') {
options[key] = dateVal.getTime();
}
}
/**
* Opens the standard Android date picker dialog.
*
* ### Example
*
* ```
* try {
* const {action, year, month, day} = await DatePickerAndroid.open({
* // Use `new Date()` for current date.
* // May 25 2020. Month 0 is January.
* date: new Date(2020, 4, 25)
* });
* if (action !== DatePickerAndroid.dismissedAction) {
* // Selected year, month (0-11), day
* }
* } catch ({code, message}) {
* console.warn('Cannot open date picker', message);
* }
* ```
*/
class DatePickerAndroid {
/**
* Opens the standard Android date picker dialog.
*
* The available keys for the `options` object are:
* * `date` (`Date` object or timestamp in milliseconds) - date to show by default
* * `minDate` (`Date` or timestamp in milliseconds) - minimum date that can be selected
* * `maxDate` (`Date` object or timestamp in milliseconds) - minimum date that can be selected
*
* Returns a Promise which will be invoked an object containing `action`, `year`, `month` (0-11),
* `day` if the user picked a date. If the user dismissed the dialog, the Promise will
* still be resolved with action being `DatePickerAndroid.dismissedAction` and all the other keys
* being undefined. **Always** check whether the `action` before reading the values.
*
* Note the native date picker dialog has some UI glitches on Android 4 and lower
* when using the `minDate` and `maxDate` options.
*/
static async open(options: Object): Promise<Object> {
let optionsMs = options;
if (optionsMs) {
_toMillis(options, 'date');
_toMillis(options, 'minDate');
_toMillis(options, 'maxDate');
}
return DatePickerModule.open(options);
}
/**
* A date has been selected.
*/
static get dateSetAction() { return 'dateSetAction'; }
/**
* The dialog has been dismissed.
*/
static get dismissedAction() { return 'dismissedAction'; }
}
module.exports = DatePickerAndroid;

View File

@ -0,0 +1,24 @@
/**
* 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.
*
* @providesModule DatePickerAndroid
* @flow
*/
'use strict';
var warning = require('warning');
const DatePickerAndroid = {
async open(options: Object): Promise<Object> {
return Promise.reject({
message: 'DatePickerAndroid is not supported on this platform.'
});
},
}
module.exports = DatePickerAndroid;

View File

@ -0,0 +1,67 @@
/**
* 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.
*
* @providesModule TimePickerAndroid
* @flow
*/
'use strict';
const TimePickerModule = require('NativeModules').TimePickerAndroid;
/**
* Opens the standard Android time picker dialog.
*
* ### Example
*
* ```
* try {
* const {action, hour, minute} = await TimePickerAndroid.open({
* hour: 14,
* minute: 0,
* is24Hour: false, // Will display '2 PM'
* });
* if (action !== DatePickerAndroid.dismissedAction) {
* // Selected hour (0-23), minute (0-59)
* }
* } catch ({code, message}) {
* console.warn('Cannot open time picker', message);
* }
* ```
*/
class TimePickerAndroid {
/**
* Opens the standard Android time picker dialog.
*
* The available keys for the `options` object are:
* * `hour` (0-23) - the hour to show, defaults to the current time
* * `minute` (0-59) - the minute to show, defaults to the current time
* * `is24Hour` (boolean) - If `true`, the picker uses the 24-hour format. If `false`,
* the picker shows an AM/PM chooser. If undefined, the default for the current locale
* is used.
*
* Returns a Promise which will be invoked an object containing `action`, `hour` (0-23),
* `minute` (0-59) if the user picked a time. If the user dismissed the dialog, the Promise will
* still be resolved with action being `TimePickerAndroid.dismissedAction` and all the other keys
* being undefined. **Always** check whether the `action` before reading the values.
*/
static async open(options: Object): Promise<Object> {
return TimePickerModule.open(options);
}
/**
* A time has been selected.
*/
static get timeSetAction() { return 'timeSetAction'; }
/**
* The dialog has been dismissed.
*/
static get dismissedAction() { return 'dismissedAction'; }
};
module.exports = TimePickerAndroid;

View File

@ -0,0 +1,24 @@
/**
* 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.
*
* @providesModule TimePickerAndroid
* @flow
*/
'use strict';
var warning = require('warning');
const TimePickerAndroid = {
async open(options: Object): Promise<Object> {
return Promise.reject({
message: 'TimePickerAndroid is not supported on this platform.'
});
},
}
module.exports = TimePickerAndroid;

View File

@ -19,7 +19,7 @@ var ToastAndroid = {
message: string,
duration: number
): void {
warning(false, 'Cannot use ToastAndroid on iOS.');
warning(false, 'ToastAndroid is not supported on this platform.');
},
};

View File

@ -66,6 +66,7 @@ var ReactNative = {
get BackAndroid() { return require('BackAndroid'); },
get CameraRoll() { return require('CameraRoll'); },
get Clipboard() { return require('Clipboard'); },
get DatePickerAndroid() { return require('DatePickerAndroid'); },
get Dimensions() { return require('Dimensions'); },
get Easing() { return require('Easing'); },
get ImagePickerIOS() { return require('ImagePickerIOS'); },
@ -80,6 +81,7 @@ var ReactNative = {
get Settings() { return require('Settings'); },
get StatusBarIOS() { return require('StatusBarIOS'); },
get StyleSheet() { return require('StyleSheet'); },
get TimePickerAndroid() { return require('TimePickerAndroid'); },
get UIManager() { return require('UIManager'); },
get VibrationIOS() { return require('VibrationIOS'); },

View File

@ -78,6 +78,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
BackAndroid: require('BackAndroid'),
CameraRoll: require('CameraRoll'),
Clipboard: require('Clipboard'),
DatePickerAndroid: require('DatePickerAndroid'),
Dimensions: require('Dimensions'),
Easing: require('Easing'),
ImagePickerIOS: require('ImagePickerIOS'),
@ -92,6 +93,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
Settings: require('Settings'),
StatusBarIOS: require('StatusBarIOS'),
StyleSheet: require('StyleSheet'),
TimePickerAndroid: require('TimePickerAndroid'),
UIManager: require('UIManager'),
VibrationIOS: require('VibrationIOS'),

View File

@ -9,8 +9,6 @@
package com.facebook.react.bridge;
import javax.annotation.Nullable;
/**
* Interface that represents a JavaScript Promise which can be passed to the native module as a
* method parameter.
@ -19,10 +17,38 @@ import javax.annotation.Nullable;
* will be marked as "remoteAsync" and will return a promise when invoked from JavaScript.
*/
public interface Promise {
/**
* Successfully resolve the Promise.
*/
void resolve(Object value);
void reject(Throwable reason);
/**
* Report an error which wasn't caused by an exception.
*/
void reject(String code, String message);
/**
* Report an exception.
*/
void reject(String code, Throwable e);
/**
* Report an exception with a custom error message.
*/
void reject(String code, String message, Throwable e);
/**
* Report an error which wasn't caused by an exception.
* @deprecated Prefer passing a module-specific error code to JS.
* Using this method will pass the error code "EUNSPECIFIED".
*/
@Deprecated
void reject(String reason);
void reject(String code, Throwable extra);
void reject(String code, String reason, @Nullable Throwable extra);
void reject(String message);
/**
* Report an exception, with default error code.
* Useful in catch-all scenarios where it's unclear why the error occurred.
*/
void reject(Throwable reason);
}

View File

@ -34,23 +34,28 @@ public class PromiseImpl implements Promise {
}
@Override
public void reject(Throwable reason) {
reject(DEFAULT_ERROR, reason.getMessage(), reason);
public void reject(String code, String message) {
reject(code, message, /*Throwable*/null);
}
@Override
@Deprecated
public void reject(String reason) {
reject(DEFAULT_ERROR, reason, null);
public void reject(String message) {
reject(DEFAULT_ERROR, message, /*Throwable*/null);
}
@Override
public void reject(String code, Throwable extra) {
reject(code, extra.getMessage(), extra);
public void reject(String code, Throwable e) {
reject(code, e.getMessage(), e);
}
@Override
public void reject(String code, String reason, @Nullable Throwable extra) {
public void reject(Throwable e) {
reject(DEFAULT_ERROR, e.getMessage(), e);
}
@Override
public void reject(String code, String message, @Nullable Throwable e) {
if (mReject != null) {
if (code == null) {
code = DEFAULT_ERROR;
@ -60,7 +65,7 @@ public class PromiseImpl implements Promise {
// error instance.
WritableNativeMap errorInfo = new WritableNativeMap();
errorInfo.putString("code", code);
errorInfo.putString("message", reason);
errorInfo.putString("message", message);
// TODO(8850038): add the stack trace info in, need to figure out way to serialize that
mReject.invoke(errorInfo);
}

View File

@ -59,7 +59,6 @@ import com.facebook.react.common.ReactConstants;
*/
public class CameraRollManager extends ReactContextBaseJavaModule {
private static final String TAG = "Catalyst/CameraRollManager";
private static final String ERROR_UNABLE_TO_LOAD = "E_UNABLE_TO_LOAD";
private static final String ERROR_UNABLE_TO_LOAD_PERMISSION = "E_UNABLE_TO_LOAD_PERMISSION";
private static final String ERROR_UNABLE_TO_SAVE = "E_UNABLE_TO_SAVE";
@ -145,7 +144,7 @@ public class CameraRollManager extends ReactContextBaseJavaModule {
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
pictures.mkdirs();
if (!pictures.isDirectory()) {
mPromise.reject(ERROR_UNABLE_TO_LOAD, "External storage pictures directory not available", null);
mPromise.reject(ERROR_UNABLE_TO_LOAD, "External storage pictures directory not available");
return;
}
File dest = new File(pictures, source.getName());
@ -178,7 +177,7 @@ public class CameraRollManager extends ReactContextBaseJavaModule {
if (uri != null) {
mPromise.resolve(uri.toString());
} else {
mPromise.reject(ERROR_UNABLE_TO_SAVE, "Could not add image to gallery", null);
mPromise.reject(ERROR_UNABLE_TO_SAVE, "Could not add image to gallery");
}
}
});
@ -302,7 +301,7 @@ public class CameraRollManager extends ReactContextBaseJavaModule {
Images.Media.DATE_TAKEN + " DESC, " + Images.Media.DATE_MODIFIED + " DESC LIMIT " +
(mFirst + 1)); // set LIMIT to first + 1 so that we know how to populate page_info
if (photos == null) {
mPromise.reject(ERROR_UNABLE_TO_LOAD, "Could not get photos", null);
mPromise.reject(ERROR_UNABLE_TO_LOAD, "Could not get photos");
} else {
try {
putEdges(resolver, photos, response, mFirst);
@ -412,7 +411,7 @@ public class CameraRollManager extends ReactContextBaseJavaModule {
width = options.outWidth;
height = options.outHeight;
} catch (IOException e) {
FLog.e(TAG, "Could not get width/height for " + photoUri.toString(), e);
FLog.e(ReactConstants.TAG, "Could not get width/height for " + photoUri.toString(), e);
return false;
}
}

View File

@ -0,0 +1,20 @@
include_defs('//ReactAndroid/DEFS')
android_library(
name = 'datepicker',
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 = ':datepicker',
)

View File

@ -0,0 +1,103 @@
/**
* 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.datepicker;
import javax.annotation.Nullable;
import java.util.Calendar;
import android.annotation.SuppressLint;
import android.app.DatePickerDialog;
import android.app.DatePickerDialog.OnDateSetListener;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.os.Bundle;
import android.widget.DatePicker;
@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);
final DatePickerDialog dialog =
new DismissableDatePickerDialog(activityContext, onDateSetListener, year, month, day);
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;
}
}

View File

@ -0,0 +1,176 @@
/**
* 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.datepicker;
import javax.annotation.Nullable;
import java.util.Map;
import android.app.Activity;
import android.app.DatePickerDialog.OnDateSetListener;
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.os.Bundle;
import android.widget.DatePicker;
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 date picker dialog and get called back when
* the user selects a date.
*/
public class DatePickerDialogModule extends ReactContextBaseJavaModule {
@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 ACTION_DATE_SET = "dateSetAction";
/* package */ static final String ACTION_DISMISSED = "dismissedAction";
public DatePickerDialogModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return "DatePickerAndroid";
}
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().hasActiveCatalystInstance()) {
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().hasActiveCatalystInstance()) {
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>
* <li>
* {@code minDate} (timestamp in milliseconds) the minimum date the user should be allowed
* to select
* </li>
* <li>
* {@code maxDate} (timestamp in milliseconds) the maximum date the user should be allowed
* to select
* </li>
* </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.
*/
@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 DatePicker 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();
}
SupportDatePickerDialogFragment fragment = new SupportDatePickerDialogFragment();
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);
} else {
FragmentManager fragmentManager = activity.getFragmentManager();
DialogFragment oldFragment = (DialogFragment)fragmentManager.findFragmentByTag(FRAGMENT_TAG);
if (oldFragment != null) {
oldFragment.dismiss();
}
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));
}
return args;
}
}

View File

@ -0,0 +1,57 @@
/**
* 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.datepicker;
import javax.annotation.Nullable;
import android.app.DatePickerDialog;
import android.content.Context;
import android.os.Build;
/**
* <p>
* Certain versions of Android (Jellybean-KitKat) have a bug where when dismissed, the
* {@link DatePickerDialog} still calls the OnDateSetListener. This class works around that issue.
* </p>
*
* <p>
* See: <a href="https://code.google.com/p/android/issues/detail?id=34833">Issue 34833</a>
* </p>
*/
public class DismissableDatePickerDialog extends DatePickerDialog {
public DismissableDatePickerDialog(
Context context,
@Nullable OnDateSetListener callback,
int year,
int monthOfYear,
int dayOfMonth) {
super(context, callback, year, monthOfYear, dayOfMonth);
}
public DismissableDatePickerDialog(
Context context,
int theme,
@Nullable OnDateSetListener callback,
int year,
int monthOfYear,
int dayOfMonth) {
super(context, theme, callback, year, monthOfYear, dayOfMonth);
}
@Override
protected void onStop() {
// do *not* call super.onStop() on KitKat on lower, as that would erroneously call the
// OnDateSetListener when the dialog is dismissed, or call it twice when "OK" is pressed.
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
super.onStop();
}
}
}

View File

@ -0,0 +1,51 @@
/**
* 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.datepicker;
import javax.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.DatePickerDialog.OnDateSetListener;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
@SuppressLint("ValidFragment")
public class SupportDatePickerDialogFragment extends DialogFragment {
@Nullable
private OnDateSetListener mOnDateSetListener;
@Nullable
private OnDismissListener mOnDismissListener;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Bundle args = getArguments();
return DatePickerDialogFragment.createDialog(args, getActivity(), mOnDateSetListener);
}
@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;
}
}

View File

@ -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',
)

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -28,6 +28,7 @@ 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'),
@ -36,6 +37,7 @@ android_library(
react_native_target('java/com/facebook/react/modules/netinfo:netinfo'),
react_native_target('java/com/facebook/react/modules/network:network'),
react_native_target('java/com/facebook/react/modules/storage:storage'),
react_native_target('java/com/facebook/react/modules/timepicker:timepicker'),
react_native_target('java/com/facebook/react/modules/toast:toast'),
react_native_target('java/com/facebook/react/uimanager:uimanager'),
react_native_target('java/com/facebook/react/modules/websocket:websocket'),

View File

@ -17,16 +17,19 @@ import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.modules.appstate.AppStateModule;
import com.facebook.react.modules.camera.CameraRollManager;
import com.facebook.react.modules.clipboard.ClipboardModule;
import com.facebook.react.modules.dialog.DialogModule;
import com.facebook.react.modules.datepicker.DatePickerDialogModule;
import com.facebook.react.modules.fresco.FrescoModule;
import com.facebook.react.modules.intent.IntentModule;
import com.facebook.react.modules.location.LocationModule;
import com.facebook.react.modules.netinfo.NetInfoModule;
import com.facebook.react.modules.network.NetworkingModule;
import com.facebook.react.modules.storage.AsyncStorageModule;
import com.facebook.react.modules.timepicker.TimePickerDialogModule;
import com.facebook.react.modules.toast.ToastModule;
import com.facebook.react.modules.appstate.AppStateModule;
import com.facebook.react.modules.websocket.WebSocketModule;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.views.art.ARTRenderableViewManager;
@ -50,7 +53,6 @@ import com.facebook.react.views.view.ReactViewManager;
import com.facebook.react.views.viewpager.ReactViewPagerManager;
import com.facebook.react.views.swiperefresh.SwipeRefreshLayoutManager;
import com.facebook.react.views.webview.ReactWebViewManager;
import com.facebook.react.modules.clipboard.ClipboardModule;
/**
* Package defining basic modules and view managers.
@ -64,12 +66,14 @@ public class MainReactPackage implements ReactPackage {
new AsyncStorageModule(reactContext),
new CameraRollManager(reactContext),
new ClipboardModule(reactContext),
new DatePickerDialogModule(reactContext),
new DialogModule(reactContext),
new FrescoModule(reactContext),
new IntentModule(reactContext),
new LocationModule(reactContext),
new NetworkingModule(reactContext),
new NetInfoModule(reactContext),
new TimePickerDialogModule(reactContext),
new ToastModule(reactContext),
new WebSocketModule(reactContext));
}