Skip to content

Commit 9a0539d

Browse files
Martin Konicekfacebook-github-bot-8
authored andcommitted
Open source Android date and time pickers
Reviewed By: bestander Differential Revision: D2856486 fb-gh-sync-id: 0bb81136289e2f121387649765ba682103e4701b
1 parent 5f0ef12 commit 9a0539d

29 files changed

+1275
-41
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/**
2+
* The examples provided by Facebook are for non-commercial testing and
3+
* evaluation purposes only.
4+
*
5+
* Facebook reserves all rights not expressly granted.
6+
*
7+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
8+
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9+
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
10+
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
11+
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
12+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13+
*/
14+
'use strict';
15+
16+
var React = require('react-native');
17+
var {
18+
DatePickerAndroid,
19+
StyleSheet,
20+
Text,
21+
TouchableWithoutFeedback,
22+
} = React;
23+
24+
var UIExplorerBlock = require('./UIExplorerBlock');
25+
var UIExplorerPage = require('./UIExplorerPage');
26+
27+
var DatePickerAndroidExample = React.createClass({
28+
29+
statics: {
30+
title: 'DatePickerAndroid',
31+
description: 'Standard Android date picker dialog',
32+
},
33+
34+
getInitialState() {
35+
return {
36+
presetDate: new Date(2020, 4, 5),
37+
allDate: new Date(2020, 4, 5),
38+
simpleText: 'pick a date',
39+
minText: 'pick a date, no earlier than today',
40+
maxText: 'pick a date, no later than today',
41+
presetText: 'pick a date, preset to 2020/5/5',
42+
allText: 'pick a date between 2020/5/1 and 2020/5/10',
43+
};
44+
},
45+
46+
async showPicker(stateKey, options) {
47+
try {
48+
var newState = {};
49+
const {action, year, month, day} = await DatePickerAndroid.open(options);
50+
if (action === DatePickerAndroid.dismissedAction) {
51+
newState[stateKey + 'Text'] = 'dismissed';
52+
} else {
53+
var date = new Date(year, month, day);
54+
newState[stateKey + 'Text'] = date.toLocaleDateString();
55+
newState[stateKey + 'Date'] = date;
56+
}
57+
this.setState(newState);
58+
} catch ({code, message}) {
59+
console.warn(`Error in example '${stateKey}': `, message);
60+
}
61+
},
62+
63+
render() {
64+
return (
65+
<UIExplorerPage title="DatePickerAndroid">
66+
<UIExplorerBlock title="Simple date picker">
67+
<TouchableWithoutFeedback
68+
onPress={this.showPicker.bind(this, 'simple', {date: this.state.simpleDate})}>
69+
<Text style={styles.text}>{this.state.simpleText}</Text>
70+
</TouchableWithoutFeedback>
71+
</UIExplorerBlock>
72+
<UIExplorerBlock title="Date picker with pre-set date">
73+
<TouchableWithoutFeedback
74+
onPress={this.showPicker.bind(this, 'preset', {date: this.state.presetDate})}>
75+
<Text style={styles.text}>{this.state.presetText}</Text>
76+
</TouchableWithoutFeedback>
77+
</UIExplorerBlock>
78+
<UIExplorerBlock title="Date picker with minDate">
79+
<TouchableWithoutFeedback
80+
onPress={this.showPicker.bind(this, 'min', {
81+
date: this.state.minDate,
82+
minDate: new Date(),
83+
})}>
84+
<Text style={styles.text}>{this.state.minText}</Text>
85+
</TouchableWithoutFeedback>
86+
</UIExplorerBlock>
87+
<UIExplorerBlock title="Date picker with maxDate">
88+
<TouchableWithoutFeedback
89+
onPress={this.showPicker.bind(this, 'max', {
90+
date: this.state.maxDate,
91+
maxDate: new Date(),
92+
})}>
93+
<Text style={styles.text}>{this.state.maxText}</Text>
94+
</TouchableWithoutFeedback>
95+
</UIExplorerBlock>
96+
<UIExplorerBlock title="Date picker with all options">
97+
<TouchableWithoutFeedback
98+
onPress={this.showPicker.bind(this, 'all', {
99+
date: this.state.allDate,
100+
minDate: new Date(2020, 4, 1),
101+
maxDate: new Date(2020, 4, 10),
102+
})}>
103+
<Text style={styles.text}>{this.state.allText}</Text>
104+
</TouchableWithoutFeedback>
105+
</UIExplorerBlock>
106+
</UIExplorerPage>
107+
);
108+
},
109+
});
110+
111+
var styles = StyleSheet.create({
112+
text: {
113+
color: 'black',
114+
},
115+
});
116+
117+
module.exports = DatePickerAndroidExample;

Examples/UIExplorer/ListViewExample.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ var UIExplorerPage = require('./UIExplorerPage');
3030

3131
var ListViewSimpleExample = React.createClass({
3232
statics: {
33-
title: '<ListView> - Simple',
33+
title: '<ListView>',
3434
description: 'Performant, scrollable list of data.'
3535
},
3636

@@ -50,7 +50,7 @@ var ListViewSimpleExample = React.createClass({
5050
render: function() {
5151
return (
5252
<UIExplorerPage
53-
title={this.props.navigator ? null : '<ListView> - Simple'}
53+
title={this.props.navigator ? null : '<ListView>'}
5454
noSpacer={true}
5555
noScroll={true}>
5656
<ListView

Examples/UIExplorer/PickerAndroidExample.js

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ const {
2727
const Item = PickerAndroid.Item;
2828

2929
const PickerAndroidExample = React.createClass({
30+
31+
statics: {
32+
title: '<PickerAndroid>',
33+
description: 'Provides multiple options to choose from, using either a dropdown menu or a dialog.',
34+
},
35+
3036
getInitialState: function() {
3137
return {
3238
selected1: 'key1',
@@ -124,19 +130,11 @@ const PickerAndroidExample = React.createClass({
124130
this.setState({mode: newMode});
125131
},
126132

127-
onSelect: function(key, value) {
133+
onSelect: function(key: string, value: string) {
128134
const newState = {};
129135
newState[key] = value;
130136
this.setState(newState);
131137
},
132138
});
133139

134-
exports.title = '<PickerAndroid>';
135-
exports.displayName = 'PickerAndroidExample';
136-
exports.description = 'The Android Picker component provides multiple options to choose from';
137-
exports.examples = [
138-
{
139-
title: 'PickerAndroidExample',
140-
render(): ReactElement { return <PickerAndroidExample />; }
141-
},
142-
];
140+
module.exports = PickerAndroidExample;

Examples/UIExplorer/RefreshControlExample.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ const RefreshControlExample = React.createClass({
6969
isRefreshing: false,
7070
loaded: 0,
7171
rowData: Array.from(new Array(20)).map(
72-
(val, i) => ({text: 'Initial row' + i, clicks: 0})),
72+
(val, i) => ({text: 'Initial row ' + i, clicks: 0})),
7373
};
7474
},
7575

@@ -108,7 +108,7 @@ const RefreshControlExample = React.createClass({
108108
// prepend 10 items
109109
const rowData = Array.from(new Array(10))
110110
.map((val, i) => ({
111-
text: 'Loaded row' + (+this.state.loaded + i),
111+
text: 'Loaded row ' + (+this.state.loaded + i),
112112
clicks: 0,
113113
}))
114114
.concat(this.state.rowData);
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/**
2+
* The examples provided by Facebook are for non-commercial testing and
3+
* evaluation purposes only.
4+
*
5+
* Facebook reserves all rights not expressly granted.
6+
*
7+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
8+
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9+
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
10+
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
11+
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
12+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13+
*/
14+
'use strict';
15+
16+
var React = require('react-native');
17+
var {
18+
TimePickerAndroid,
19+
StyleSheet,
20+
Text,
21+
TouchableWithoutFeedback,
22+
} = React;
23+
24+
var UIExplorerBlock = require('./UIExplorerBlock');
25+
var UIExplorerPage = require('./UIExplorerPage');
26+
27+
var TimePickerAndroidExample = React.createClass({
28+
29+
statics: {
30+
title: 'TimePickerAndroid',
31+
description: 'Standard Android time picker dialog',
32+
},
33+
34+
getInitialState() {
35+
// *Text, *Hour and *Minute are set by successCallback -- this updates the text with the time
36+
// picked by the user and makes it so the next time they open it the hour and minute they picked
37+
// before is displayed.
38+
return {
39+
isoFormatText: 'pick a time (24-hour format)',
40+
presetHour: 4,
41+
presetMinute: 4,
42+
presetText: 'pick a time, default: 4:04AM',
43+
simpleText: 'pick a time',
44+
};
45+
},
46+
47+
async showPicker(stateKey, options) {
48+
try {
49+
const {action, minute, hour} = await TimePickerAndroid.open(options);
50+
var newState = {};
51+
if (action === TimePickerAndroid.timeSetAction) {
52+
newState[stateKey + 'Text'] = _formatTime(hour, minute);
53+
newState[stateKey + 'Hour'] = hour;
54+
newState[stateKey + 'Minute'] = minute;
55+
} else if (action === TimePickerAndroid.dismissedAction) {
56+
newState[stateKey + 'Text'] = 'dismissed';
57+
}
58+
this.setState(newState);
59+
} catch ({code, message}) {
60+
console.warn(`Error in example '${stateKey}': `, message);
61+
}
62+
},
63+
64+
render() {
65+
return (
66+
<UIExplorerPage title="TimePickerAndroid">
67+
<UIExplorerBlock title="Simple time picker">
68+
<TouchableWithoutFeedback
69+
onPress={this.showPicker.bind(this, 'simple')}>
70+
<Text style={styles.text}>{this.state.simpleText}</Text>
71+
</TouchableWithoutFeedback>
72+
</UIExplorerBlock>
73+
<UIExplorerBlock title="Time picker with pre-set time">
74+
<TouchableWithoutFeedback
75+
onPress={this.showPicker.bind(this, 'preset', {
76+
hour: this.state.presetHour,
77+
minute: this.state.presetMinute,
78+
})}>
79+
<Text style={styles.text}>{this.state.presetText}</Text>
80+
</TouchableWithoutFeedback>
81+
</UIExplorerBlock>
82+
83+
<UIExplorerBlock title="Time picker with 24-hour time format">
84+
<TouchableWithoutFeedback
85+
onPress={this.showPicker.bind(this, 'isoFormat', {
86+
hour: this.state.isoFormatHour,
87+
minute: this.state.isoFormatMinute,
88+
is24Hour: true,
89+
})}>
90+
<Text style={styles.text}>{this.state.isoFormatText}</Text>
91+
</TouchableWithoutFeedback>
92+
</UIExplorerBlock>
93+
</UIExplorerPage>
94+
);
95+
},
96+
});
97+
98+
/**
99+
* Returns e.g. '3:05'.
100+
*/
101+
function _formatTime(hour, minute) {
102+
return hour + ':' + (minute < 10 ? '0' + minute : minute);
103+
}
104+
105+
var styles = StyleSheet.create({
106+
text: {
107+
color: 'black',
108+
},
109+
});
110+
111+
module.exports = TimePickerAndroidExample;
112+

Examples/UIExplorer/UIExplorerList.android.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,15 @@ var APIS = [
4747
require('./BorderExample'),
4848
require('./CameraRollExample'),
4949
require('./ClipboardExample'),
50+
require('./DatePickerAndroidExample'),
5051
require('./GeolocationExample'),
5152
require('./IntentAndroidExample.android'),
5253
require('./LayoutEventsExample'),
5354
require('./LayoutExample'),
5455
require('./NetInfoExample'),
5556
require('./PanResponderExample'),
5657
require('./PointerEventsExample'),
58+
require('./TimePickerAndroidExample'),
5759
require('./TimerExample'),
5860
require('./ToastAndroidExample.android'),
5961
require('./XHRExample'),

Libraries/Components/Clipboard/Clipboard.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ module.exports = {
2626
*/
2727
getString() {
2828
if (arguments.length > 0) {
29-
let callback = arguments[0];
30-
console.warn('Clipboard.getString(callback) is deprecated. Use the returned Promise instead');
31-
Clipboard.getString().then(callback);
32-
return;
29+
let callback = arguments[0];
30+
console.warn('Clipboard.getString(callback) is deprecated. Use the returned Promise instead');
31+
Clipboard.getString().then(callback);
32+
return;
3333
}
3434
return Clipboard.getString();
3535
},
@@ -40,7 +40,7 @@ module.exports = {
4040
* Clipboard.setString('hello world');
4141
* }
4242
* ```
43-
* @param this parameter is content that will be set into clipboard.
43+
* @param the content to be stored in the clipboard.
4444
*/
4545
setString(content) {
4646
Clipboard.setString(content);

0 commit comments

Comments
 (0)