Merge pull request #562 from abarth/time_picker
Start working on a TimePicker
This commit is contained in:
@@ -5,14 +5,16 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'chip_demo.dart';
|
||||
import 'gallery_page.dart';
|
||||
import 'date_picker_demo.dart';
|
||||
import 'gallery_page.dart';
|
||||
import 'time_picker_demo.dart';
|
||||
import 'widget_demo.dart';
|
||||
import 'drop_down_demo.dart';
|
||||
|
||||
final List<WidgetDemo> _kDemos = <WidgetDemo>[
|
||||
kChipDemo,
|
||||
kDatePickerDemo,
|
||||
kTimePickerDemo,
|
||||
kDropDownDemo,
|
||||
];
|
||||
|
||||
|
||||
45
examples/material_gallery/lib/time_picker_demo.dart
Normal file
45
examples/material_gallery/lib/time_picker_demo.dart
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'widget_demo.dart';
|
||||
|
||||
class TimePickerDemo extends StatefulComponent {
|
||||
_TimePickerDemoState createState() => new _TimePickerDemoState();
|
||||
}
|
||||
|
||||
class _TimePickerDemoState extends State<TimePickerDemo> {
|
||||
TimeOfDay _selectedTime = const TimeOfDay(hour: 7, minute: 28);
|
||||
|
||||
Future _handleSelectTime() async {
|
||||
TimeOfDay picked = await showTimePicker(
|
||||
context: context,
|
||||
initialTime: _selectedTime
|
||||
);
|
||||
if (picked != _selectedTime) {
|
||||
setState(() {
|
||||
_selectedTime = picked;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return new Column([
|
||||
new Text('${_selectedTime.hour}:${_selectedTime.minute}'),
|
||||
new RaisedButton(
|
||||
onPressed: _handleSelectTime,
|
||||
child: new Text('SELECT TIME')
|
||||
),
|
||||
], justifyContent: FlexJustifyContent.center);
|
||||
}
|
||||
}
|
||||
|
||||
final WidgetDemo kTimePickerDemo = new WidgetDemo(
|
||||
title: 'Time Picker',
|
||||
routeName: '/time-picker',
|
||||
builder: (_) => new TimePickerDemo()
|
||||
);
|
||||
@@ -50,6 +50,8 @@ export 'src/material/switch.dart';
|
||||
export 'src/material/tabs.dart';
|
||||
export 'src/material/theme.dart';
|
||||
export 'src/material/theme_data.dart';
|
||||
export 'src/material/time_picker.dart';
|
||||
export 'src/material/time_picker_dialog.dart';
|
||||
export 'src/material/title.dart';
|
||||
export 'src/material/tool_bar.dart';
|
||||
export 'src/material/typography.dart';
|
||||
|
||||
@@ -14,9 +14,7 @@ import 'ink_well.dart';
|
||||
import 'theme.dart';
|
||||
import 'typography.dart';
|
||||
|
||||
enum DatePickerMode { day, year }
|
||||
|
||||
typedef void DatePickerModeChanged(DatePickerMode value);
|
||||
enum _DatePickerMode { day, year }
|
||||
|
||||
class DatePicker extends StatefulComponent {
|
||||
DatePicker({
|
||||
@@ -39,9 +37,9 @@ class DatePicker extends StatefulComponent {
|
||||
}
|
||||
|
||||
class _DatePickerState extends State<DatePicker> {
|
||||
DatePickerMode _mode = DatePickerMode.day;
|
||||
_DatePickerMode _mode = _DatePickerMode.day;
|
||||
|
||||
void _handleModeChanged(DatePickerMode mode) {
|
||||
void _handleModeChanged(_DatePickerMode mode) {
|
||||
userFeedback.performHapticFeedback(HapticFeedbackType.VIRTUAL_KEY);
|
||||
setState(() {
|
||||
_mode = mode;
|
||||
@@ -51,7 +49,7 @@ class _DatePickerState extends State<DatePicker> {
|
||||
void _handleYearChanged(DateTime dateTime) {
|
||||
userFeedback.performHapticFeedback(HapticFeedbackType.VIRTUAL_KEY);
|
||||
setState(() {
|
||||
_mode = DatePickerMode.day;
|
||||
_mode = _DatePickerMode.day;
|
||||
});
|
||||
if (config.onChanged != null)
|
||||
config.onChanged(dateTime);
|
||||
@@ -73,7 +71,7 @@ class _DatePickerState extends State<DatePicker> {
|
||||
);
|
||||
Widget picker;
|
||||
switch (_mode) {
|
||||
case DatePickerMode.day:
|
||||
case _DatePickerMode.day:
|
||||
picker = new MonthPicker(
|
||||
selectedDate: config.selectedDate,
|
||||
onChanged: _handleDayChanged,
|
||||
@@ -82,7 +80,7 @@ class _DatePickerState extends State<DatePicker> {
|
||||
itemExtent: _calendarHeight
|
||||
);
|
||||
break;
|
||||
case DatePickerMode.year:
|
||||
case _DatePickerMode.year:
|
||||
picker = new YearPicker(
|
||||
selectedDate: config.selectedDate,
|
||||
onChanged: _handleYearChanged,
|
||||
@@ -110,10 +108,10 @@ class _DatePickerHeader extends StatelessComponent {
|
||||
}
|
||||
|
||||
DateTime selectedDate;
|
||||
DatePickerMode mode;
|
||||
DatePickerModeChanged onModeChanged;
|
||||
_DatePickerMode mode;
|
||||
ValueChanged<_DatePickerMode> onModeChanged;
|
||||
|
||||
void _handleChangeMode(DatePickerMode value) {
|
||||
void _handleChangeMode(_DatePickerMode value) {
|
||||
if (value != mode)
|
||||
onModeChanged(value);
|
||||
}
|
||||
@@ -125,12 +123,12 @@ class _DatePickerHeader extends StatelessComponent {
|
||||
Color yearColor;
|
||||
switch(theme.primaryColorBrightness) {
|
||||
case ThemeBrightness.light:
|
||||
dayColor = mode == DatePickerMode.day ? Colors.black87 : Colors.black54;
|
||||
yearColor = mode == DatePickerMode.year ? Colors.black87 : Colors.black54;
|
||||
dayColor = mode == _DatePickerMode.day ? Colors.black87 : Colors.black54;
|
||||
yearColor = mode == _DatePickerMode.year ? Colors.black87 : Colors.black54;
|
||||
break;
|
||||
case ThemeBrightness.dark:
|
||||
dayColor = mode == DatePickerMode.day ? Colors.white : Colors.white70;
|
||||
yearColor = mode == DatePickerMode.year ? Colors.white : Colors.white70;
|
||||
dayColor = mode == _DatePickerMode.day ? Colors.white : Colors.white70;
|
||||
yearColor = mode == _DatePickerMode.year ? Colors.white : Colors.white70;
|
||||
break;
|
||||
}
|
||||
TextStyle dayStyle = headerTheme.display3.copyWith(color: dayColor, height: 1.0, fontSize: 100.0);
|
||||
@@ -142,15 +140,15 @@ class _DatePickerHeader extends StatelessComponent {
|
||||
decoration: new BoxDecoration(backgroundColor: theme.primaryColor),
|
||||
child: new Column(<Widget>[
|
||||
new GestureDetector(
|
||||
onTap: () => _handleChangeMode(DatePickerMode.day),
|
||||
onTap: () => _handleChangeMode(_DatePickerMode.day),
|
||||
child: new Text(new DateFormat("MMM").format(selectedDate).toUpperCase(), style: monthStyle)
|
||||
),
|
||||
new GestureDetector(
|
||||
onTap: () => _handleChangeMode(DatePickerMode.day),
|
||||
onTap: () => _handleChangeMode(_DatePickerMode.day),
|
||||
child: new Text(new DateFormat("d").format(selectedDate), style: dayStyle)
|
||||
),
|
||||
new GestureDetector(
|
||||
onTap: () => _handleChangeMode(DatePickerMode.year),
|
||||
onTap: () => _handleChangeMode(_DatePickerMode.year),
|
||||
child: new Text(new DateFormat("yyyy").format(selectedDate), style: yearStyle)
|
||||
)
|
||||
])
|
||||
|
||||
125
packages/flutter/lib/src/material/time_picker.dart
Normal file
125
packages/flutter/lib/src/material/time_picker.dart
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'colors.dart';
|
||||
import 'theme.dart';
|
||||
import 'typography.dart';
|
||||
|
||||
class TimeOfDay {
|
||||
const TimeOfDay({ this.hour, this.minute });
|
||||
|
||||
/// The selected hour, in 24 hour time from 0..23
|
||||
final int hour;
|
||||
|
||||
/// The selected minute.
|
||||
final int minute;
|
||||
}
|
||||
|
||||
enum _TimePickerMode { hour, minute }
|
||||
|
||||
class TimePicker extends StatefulComponent {
|
||||
TimePicker({
|
||||
this.selectedTime,
|
||||
this.onChanged
|
||||
}) {
|
||||
assert(selectedTime != null);
|
||||
}
|
||||
|
||||
final TimeOfDay selectedTime;
|
||||
final ValueChanged<TimeOfDay> onChanged;
|
||||
|
||||
_TimePickerState createState() => new _TimePickerState();
|
||||
}
|
||||
|
||||
class _TimePickerState extends State<TimePicker> {
|
||||
_TimePickerMode _mode = _TimePickerMode.hour;
|
||||
|
||||
void _handleModeChanged(_TimePickerMode mode) {
|
||||
userFeedback.performHapticFeedback(HapticFeedbackType.VIRTUAL_KEY);
|
||||
setState(() {
|
||||
_mode = mode;
|
||||
});
|
||||
}
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
Widget header = new _TimePickerHeader(
|
||||
selectedTime: config.selectedTime,
|
||||
mode: _mode,
|
||||
onModeChanged: _handleModeChanged
|
||||
);
|
||||
return new Column(<Widget>[
|
||||
header,
|
||||
new AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
child: new Container(
|
||||
margin: const EdgeDims.all(12.0),
|
||||
decoration: new BoxDecoration(
|
||||
backgroundColor: Colors.grey[300],
|
||||
shape: Shape.circle
|
||||
)
|
||||
)
|
||||
)
|
||||
], alignItems: FlexAlignItems.stretch);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Shows the selected date in large font and toggles between year and day mode
|
||||
class _TimePickerHeader extends StatelessComponent {
|
||||
_TimePickerHeader({ this.selectedTime, this.mode, this.onModeChanged }) {
|
||||
assert(selectedTime != null);
|
||||
assert(mode != null);
|
||||
}
|
||||
|
||||
TimeOfDay selectedTime;
|
||||
_TimePickerMode mode;
|
||||
ValueChanged<_TimePickerMode> onModeChanged;
|
||||
|
||||
void _handleChangeMode(_TimePickerMode value) {
|
||||
if (value != mode)
|
||||
onModeChanged(value);
|
||||
}
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
ThemeData theme = Theme.of(context);
|
||||
TextTheme headerTheme = theme.primaryTextTheme;
|
||||
|
||||
Color activeColor;
|
||||
Color inactiveColor;
|
||||
switch(theme.primaryColorBrightness) {
|
||||
case ThemeBrightness.light:
|
||||
activeColor = Colors.black87;
|
||||
inactiveColor = Colors.black54;
|
||||
break;
|
||||
case ThemeBrightness.dark:
|
||||
activeColor = Colors.white;
|
||||
inactiveColor = Colors.white70;
|
||||
break;
|
||||
}
|
||||
TextStyle activeStyle = headerTheme.display3.copyWith(color: activeColor, height: 1.0);
|
||||
TextStyle inactiveStyle = headerTheme.display3.copyWith(color: inactiveColor, height: 1.0);
|
||||
|
||||
TextStyle hourStyle = mode == _TimePickerMode.hour ? activeStyle : inactiveStyle;
|
||||
TextStyle minuteStyle = mode == _TimePickerMode.minute ? activeStyle : inactiveStyle;
|
||||
|
||||
return new Container(
|
||||
padding: new EdgeDims.all(10.0),
|
||||
decoration: new BoxDecoration(backgroundColor: theme.primaryColor),
|
||||
child: new Row(<Widget>[
|
||||
new GestureDetector(
|
||||
onTap: () => _handleChangeMode(_TimePickerMode.hour),
|
||||
child: new Text(selectedTime.hour.toString(), style: hourStyle)
|
||||
),
|
||||
new Text(':', style: inactiveStyle),
|
||||
new GestureDetector(
|
||||
onTap: () => _handleChangeMode(_TimePickerMode.minute),
|
||||
child: new Text(selectedTime.minute.toString(), style: minuteStyle)
|
||||
),
|
||||
], justifyContent: FlexJustifyContent.end)
|
||||
);
|
||||
}
|
||||
}
|
||||
68
packages/flutter/lib/src/material/time_picker_dialog.dart
Normal file
68
packages/flutter/lib/src/material/time_picker_dialog.dart
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'dialog.dart';
|
||||
import 'time_picker.dart';
|
||||
import 'flat_button.dart';
|
||||
|
||||
class _TimePickerDialog extends StatefulComponent {
|
||||
_TimePickerDialog({
|
||||
Key key,
|
||||
this.initialTime
|
||||
}) : super(key: key);
|
||||
|
||||
final TimeOfDay initialTime;
|
||||
|
||||
_TimePickerDialogState createState() => new _TimePickerDialogState();
|
||||
}
|
||||
|
||||
class _TimePickerDialogState extends State<_TimePickerDialog> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
_selectedTime = config.initialTime;
|
||||
}
|
||||
|
||||
TimeOfDay _selectedTime;
|
||||
|
||||
void _handleCancel() {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
void _handleOk() {
|
||||
Navigator.of(context).pop(_selectedTime);
|
||||
}
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return new Dialog(
|
||||
content: new TimePicker(
|
||||
selectedTime: _selectedTime
|
||||
),
|
||||
contentPadding: EdgeDims.zero,
|
||||
actions: <Widget>[
|
||||
new FlatButton(
|
||||
child: new Text('CANCEL'),
|
||||
onPressed: _handleCancel
|
||||
),
|
||||
new FlatButton(
|
||||
child: new Text('OK'),
|
||||
onPressed: _handleOk
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<TimeOfDay> showTimePicker({
|
||||
BuildContext context,
|
||||
TimeOfDay initialTime
|
||||
}) async {
|
||||
return await showDialog(
|
||||
context: context,
|
||||
child: new _TimePickerDialog(initialTime: initialTime)
|
||||
) ?? initialTime;
|
||||
}
|
||||
Reference in New Issue
Block a user