Commit a1bafaa3 authored by Collin Jackson's avatar Collin Jackson

Merge pull request #838 from collinjackson/improve_date_picker

Add date picker to widgets library and teach fitness app to use it
parents ce28a717 f164e560
...@@ -13,6 +13,12 @@ class DateUtils { ...@@ -13,6 +13,12 @@ class DateUtils {
static const MS_IN_WEEK = static const MS_IN_WEEK =
DateTime.DAYS_PER_WEEK * Duration.MILLISECONDS_PER_DAY; DateTime.DAYS_PER_WEEK * Duration.MILLISECONDS_PER_DAY;
// TODO(jmesserly): locale specific date format
static String _twoDigits(int n) {
if (n >= 10) return "${n}";
return "0${n}";
}
/** Formats a time in H:MM A format */ /** Formats a time in H:MM A format */
static String toHourMinutesString(Duration duration) { static String toHourMinutesString(Duration duration) {
assert(duration.inDays == 0); assert(duration.inDays == 0);
...@@ -68,14 +74,16 @@ class DateUtils { ...@@ -68,14 +74,16 @@ class DateUtils {
} else if (delta.inMilliseconds < MS_IN_WEEK) { } else if (delta.inMilliseconds < MS_IN_WEEK) {
return WEEKDAYS[then.weekday]; return WEEKDAYS[then.weekday];
} else { } else {
// TODO(jmesserly): locale specific date format String twoDigitMonth = _twoDigits(then.month);
String twoDigits(int n) { String twoDigitDay = _twoDigits(then.day);
if (n >= 10) return "${n}";
return "0${n}";
}
String twoDigitMonth = twoDigits(then.month);
String twoDigitDay = twoDigits(then.day);
return "${then.year}-${twoDigitMonth}-${twoDigitDay}"; return "${then.year}-${twoDigitMonth}-${twoDigitDay}";
} }
} }
static String toDateString(DateTime then) {
// TODO(jmesserly): locale specific date format
String twoDigitMonth = _twoDigits(then.month);
String twoDigitDay = _twoDigits(then.day);
return "${then.year}-${twoDigitMonth}-${twoDigitDay}";
}
} }
...@@ -21,7 +21,7 @@ abstract class FitnessItem { ...@@ -21,7 +21,7 @@ abstract class FitnessItem {
Map toJson() => { 'when' : when.toIso8601String() }; Map toJson() => { 'when' : when.toIso8601String() };
// TODO(jackson): Internationalize // TODO(jackson): Internationalize
String get displayDate => DateUtils.toRecentTimeString(when); String get displayDate => DateUtils.toDateString(when);
FitnessItemRow toRow({ FitnessItemHandler onDismissed }); FitnessItemRow toRow({ FitnessItemHandler onDismissed });
} }
......
...@@ -17,6 +17,7 @@ class Measurement extends FitnessItem { ...@@ -17,6 +17,7 @@ class Measurement extends FitnessItem {
Map toJson() { Map toJson() {
Map json = super.toJson(); Map json = super.toJson();
json['weight'] = weight; json['weight'] = weight;
json['type'] = runtimeType.toString();
return json; return json;
} }
...@@ -53,6 +54,55 @@ class MeasurementRow extends FitnessItemRow { ...@@ -53,6 +54,55 @@ class MeasurementRow extends FitnessItemRow {
} }
} }
class MeasurementDateDialog extends StatefulComponent {
MeasurementDateDialog({ this.navigator, this.previousDate });
Navigator navigator;
DateTime previousDate;
@override
void initState() {
_selectedDate = previousDate;
}
void syncConstructorArguments(MeasurementDateDialog source) {
navigator = source.navigator;
previousDate = source.previousDate;
}
DateTime _selectedDate;
void _handleDateChanged(DateTime value) {
setState(() {
_selectedDate = value;
});
}
Widget build() {
return new Dialog(
content: new DatePicker(
selectedDate: _selectedDate,
firstDate: new DateTime(2015, 8),
lastDate: new DateTime(2101),
onChanged: _handleDateChanged
),
contentPadding: EdgeDims.zero,
actions: [
new FlatButton(
child: new Text('CANCEL'),
onPressed: navigator.pop
),
new FlatButton(
child: new Text('OK'),
onPressed: () {
navigator.pop(_selectedDate);
}
),
]
);
}
}
class MeasurementFragment extends StatefulComponent { class MeasurementFragment extends StatefulComponent {
MeasurementFragment({ this.navigator, this.onCreated }); MeasurementFragment({ this.navigator, this.onCreated });
...@@ -66,6 +116,7 @@ class MeasurementFragment extends StatefulComponent { ...@@ -66,6 +116,7 @@ class MeasurementFragment extends StatefulComponent {
} }
String _weight = ""; String _weight = "";
DateTime _when = new DateTime.now();
String _errorMessage = null; String _errorMessage = null;
EventDisposition _handleSave() { EventDisposition _handleSave() {
...@@ -79,7 +130,7 @@ class MeasurementFragment extends StatefulComponent { ...@@ -79,7 +130,7 @@ class MeasurementFragment extends StatefulComponent {
}); });
return EventDisposition.processed; return EventDisposition.processed;
} }
onCreated(new Measurement(when: new DateTime.now(), weight: parsedWeight)); onCreated(new Measurement(when: _when, weight: parsedWeight));
navigator.pop(); navigator.pop();
return EventDisposition.processed; return EventDisposition.processed;
} }
...@@ -107,23 +158,44 @@ class MeasurementFragment extends StatefulComponent { ...@@ -107,23 +158,44 @@ class MeasurementFragment extends StatefulComponent {
static final GlobalKey weightKey = new GlobalKey(); static final GlobalKey weightKey = new GlobalKey();
EventDisposition _handleDatePressed(_) {
showDialog(navigator, (navigator) {
return new MeasurementDateDialog(navigator: navigator, previousDate: _when);
}).then((DateTime value) {
if (value == null)
return;
setState(() {
_when = value;
});
});
return EventDisposition.processed;
}
Widget buildBody() { Widget buildBody() {
Measurement measurement = new Measurement(when: new DateTime.now()); Measurement measurement = new Measurement(when: _when);
// TODO(jackson): Revisit the layout of this pane to be more maintainable
return new Material( return new Material(
type: MaterialType.canvas, type: MaterialType.canvas,
child: new ScrollableViewport( child: new Container(
child: new Container( padding: const EdgeDims.all(20.0),
padding: const EdgeDims.all(20.0), child: new Column([
child: new BlockBody([ new Listener(
new Text(measurement.displayDate), onGestureTap: _handleDatePressed,
new Input( child: new Container(
key: weightKey, height: 50.0,
placeholder: 'Enter weight', child: new Column([
keyboardType: KeyboardType_NUMBER, new Text('Measurement Date'),
onChanged: _handleWeightChanged new Text(measurement.displayDate, style: Theme.of(this).text.caption),
), ], alignItems: FlexAlignItems.start)
]) )
) ),
new Input(
key: weightKey,
placeholder: 'Enter weight',
keyboardType: KeyboardType_NUMBER,
onChanged: _handleWeightChanged
),
], alignItems: FlexAlignItems.stretch)
) )
); );
} }
......
// 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:sky/widgets.dart';
import 'package:sky/theme/colors.dart' as colors;
void main() => runApp(new DatePickerDemo());
class DatePickerDemo extends App {
DateTime _dateTime;
void initState() {
DateTime now = new DateTime.now();
_dateTime = new DateTime(now.year, now.month, now.day);
}
void _handleDateChanged(DateTime dateTime) {
setState(() {
_dateTime = dateTime;
});
}
Widget build() {
return new Theme(
data: new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: colors.Teal
),
child: new Stack([
new Scaffold(
toolbar: new ToolBar(center: new Text("Date Picker")),
body: new Material(
child: new Row(
[new Text(_dateTime.toString())],
alignItems: FlexAlignItems.end,
justifyContent: FlexJustifyContent.center
)
)
),
new Dialog(
content: new DatePicker(
selectedDate: _dateTime,
firstDate: new DateTime(2015, 8),
lastDate: new DateTime(2101),
onChanged: _handleDateChanged
),
contentPadding: EdgeDims.zero,
actions: [
new FlatButton(
child: new Text('CANCEL')
),
new FlatButton(
child: new Text('OK')
),
]
)
])
);
}
}
...@@ -10,6 +10,7 @@ export 'widgets/basic.dart'; ...@@ -10,6 +10,7 @@ export 'widgets/basic.dart';
export 'widgets/button_base.dart'; export 'widgets/button_base.dart';
export 'widgets/card.dart'; export 'widgets/card.dart';
export 'widgets/checkbox.dart'; export 'widgets/checkbox.dart';
export 'widgets/date_picker.dart';
export 'widgets/default_text_style.dart'; export 'widgets/default_text_style.dart';
export 'widgets/dialog.dart'; export 'widgets/dialog.dart';
export 'widgets/dismissable.dart'; export 'widgets/dismissable.dart';
......
This diff is collapsed.
...@@ -25,7 +25,9 @@ class Dialog extends Component { ...@@ -25,7 +25,9 @@ class Dialog extends Component {
Dialog({ Dialog({
Key key, Key key,
this.title, this.title,
this.titlePadding,
this.content, this.content,
this.contentPadding,
this.actions, this.actions,
this.onDismiss this.onDismiss
}): super(key: key); }): super(key: key);
...@@ -34,10 +36,17 @@ class Dialog extends Component { ...@@ -34,10 +36,17 @@ class Dialog extends Component {
/// of the dialog. /// of the dialog.
final Widget title; final Widget title;
// Padding around the title; uses material design default if none is supplied
// If there is no title, no padding will be provided
final EdgeDims titlePadding;
/// The (optional) content of the dialog is displayed in the center of the /// The (optional) content of the dialog is displayed in the center of the
/// dialog in a lighter font. /// dialog in a lighter font.
final Widget content; final Widget content;
// Padding around the content; uses material design default if none is supplied
final EdgeDims contentPadding;
/// The (optional) set of actions that are displayed at the bottom of the /// The (optional) set of actions that are displayed at the bottom of the
/// dialog. /// dialog.
final List<Widget> actions; final List<Widget> actions;
...@@ -59,8 +68,11 @@ class Dialog extends Component { ...@@ -59,8 +68,11 @@ class Dialog extends Component {
List<Widget> dialogBody = new List<Widget>(); List<Widget> dialogBody = new List<Widget>();
if (title != null) { if (title != null) {
EdgeDims padding = titlePadding;
if (padding == null)
padding = new EdgeDims(24.0, 24.0, content == null ? 20.0 : 0.0, 24.0);
dialogBody.add(new Padding( dialogBody.add(new Padding(
padding: new EdgeDims(24.0, 24.0, content == null ? 20.0 : 0.0, 24.0), padding: padding,
child: new DefaultTextStyle( child: new DefaultTextStyle(
style: Theme.of(this).text.title, style: Theme.of(this).text.title,
child: title child: title
...@@ -69,8 +81,11 @@ class Dialog extends Component { ...@@ -69,8 +81,11 @@ class Dialog extends Component {
} }
if (content != null) { if (content != null) {
EdgeDims padding = contentPadding;
if (padding == null)
padding = const EdgeDims(20.0, 24.0, 24.0, 24.0);
dialogBody.add(new Padding( dialogBody.add(new Padding(
padding: const EdgeDims(20.0, 24.0, 24.0, 24.0), padding: padding,
child: new DefaultTextStyle( child: new DefaultTextStyle(
style: Theme.of(this).text.subhead, style: Theme.of(this).text.subhead,
child: content child: content
......
...@@ -13,5 +13,6 @@ dependencies: ...@@ -13,5 +13,6 @@ dependencies:
sky_services: ^0.0.14 sky_services: ^0.0.14
sky_tools: ^0.0.10 sky_tools: ^0.0.10
vector_math: ^1.4.3 vector_math: ^1.4.3
intl: ^0.12.4+2
environment: environment:
sdk: '>=1.8.0 <2.0.0' sdk: '>=1.8.0 <2.0.0'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment