Commit 1097d92a authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Fix DatePicker (#5061)

Fundamentally the core problem was that we were not saying how wide a
date picker should be. It should be 330 pixels, if I'm measuring the
spec's mocks correctly.
parent 9f509daf
......@@ -118,8 +118,7 @@ class _DatePickerState extends State<DatePicker> {
);
break;
}
return new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
return new BlockBody(
children: <Widget>[
header,
new Container(
......@@ -213,7 +212,6 @@ const double _kMaxDayPickerHeight = _kDayPickerRowHeight * (_kMaxDayPickerRowCou
class _DayPickerGridDelegate extends GridDelegateWithInOrderChildPlacement {
@override
GridSpecification getGridSpecification(BoxConstraints constraints, int childCount) {
assert(constraints.maxWidth < double.INFINITY);
final int columnCount = DateTime.DAYS_PER_WEEK;
return new GridSpecification.fromRegularTiles(
tileWidth: constraints.maxWidth / columnCount,
......@@ -459,34 +457,37 @@ class _MonthPickerState extends State<MonthPicker> {
@override
Widget build(BuildContext context) {
return new Stack(
children: <Widget>[
new PageableLazyList(
key: _dayPickerListKey,
initialScrollOffset: _monthDelta(config.firstDate, config.selectedDate).toDouble(),
scrollDirection: Axis.horizontal,
itemCount: _monthDelta(config.firstDate, config.lastDate) + 1,
itemBuilder: _buildItems
),
new Positioned(
top: 0.0,
left: 8.0,
child: new IconButton(
icon: new Icon(Icons.chevron_left),
tooltip: 'Previous month',
onPressed: _handlePreviousMonth
)
),
new Positioned(
top: 0.0,
right: 8.0,
child: new IconButton(
icon: new Icon(Icons.chevron_right),
tooltip: 'Next month',
onPressed: _handleNextMonth
return new SizedBox(
width: 330.0,
child: new Stack(
children: <Widget>[
new PageableLazyList(
key: _dayPickerListKey,
initialScrollOffset: _monthDelta(config.firstDate, config.selectedDate).toDouble(),
scrollDirection: Axis.horizontal,
itemCount: _monthDelta(config.firstDate, config.lastDate) + 1,
itemBuilder: _buildItems
),
new Positioned(
top: 0.0,
left: 8.0,
child: new IconButton(
icon: new Icon(Icons.chevron_left),
tooltip: 'Previous month',
onPressed: _handlePreviousMonth
)
),
new Positioned(
top: 0.0,
right: 8.0,
child: new IconButton(
icon: new Icon(Icons.chevron_right),
tooltip: 'Next month',
onPressed: _handleNextMonth
)
)
)
]
]
)
);
}
......
......@@ -33,7 +33,7 @@ class TimeOfDay {
///
/// The [hour] argument must be between 0 and 23, inclusive. The [minute]
/// argument must be between 0 and 59, inclusive.
const TimeOfDay({ this.hour, this.minute });
const TimeOfDay({ @required this.hour, @required this.minute });
/// Returns a new TimeOfDay with the hour and/or minute replaced.
TimeOfDay replacing({ int hour, int minute }) {
......@@ -42,7 +42,7 @@ class TimeOfDay {
return new TimeOfDay(hour: hour ?? this.hour, minute: minute ?? this.minute);
}
/// The selected hour, in 24 hour time from 0..23
/// The selected hour, in 24 hour time from 0..23.
final int hour;
/// The selected minute.
......
......@@ -197,6 +197,8 @@ class RenderConstrainedBox extends RenderProxyBox {
@override
double computeMinIntrinsicWidth(double height) {
if (_additionalConstraints.hasBoundedWidth && _additionalConstraints.hasTightWidth)
return _additionalConstraints.minWidth;
final double width = super.computeMinIntrinsicWidth(height);
if (_additionalConstraints.hasBoundedWidth)
return _additionalConstraints.constrainWidth(width);
......@@ -205,6 +207,8 @@ class RenderConstrainedBox extends RenderProxyBox {
@override
double computeMaxIntrinsicWidth(double height) {
if (_additionalConstraints.hasBoundedWidth && _additionalConstraints.hasTightWidth)
return _additionalConstraints.minWidth;
final double width = super.computeMaxIntrinsicWidth(height);
if (_additionalConstraints.hasBoundedWidth)
return _additionalConstraints.constrainWidth(width);
......@@ -213,6 +217,8 @@ class RenderConstrainedBox extends RenderProxyBox {
@override
double computeMinIntrinsicHeight(double width) {
if (_additionalConstraints.hasBoundedHeight && _additionalConstraints.hasTightHeight)
return _additionalConstraints.minHeight;
final double height = super.computeMinIntrinsicHeight(width);
if (_additionalConstraints.hasBoundedHeight)
return _additionalConstraints.constrainHeight(height);
......@@ -221,6 +227,8 @@ class RenderConstrainedBox extends RenderProxyBox {
@override
double computeMaxIntrinsicHeight(double width) {
if (_additionalConstraints.hasBoundedHeight && _additionalConstraints.hasTightHeight)
return _additionalConstraints.minHeight;
final double height = super.computeMaxIntrinsicHeight(width);
if (_additionalConstraints.hasBoundedHeight)
return _additionalConstraints.constrainHeight(height);
......
......@@ -400,7 +400,7 @@ abstract class RenderVirtualViewport<T extends ContainerBoxParentDataMixin<Rende
assert(() {
if (!RenderObject.debugCheckingIntrinsics) {
throw new FlutterError(
'RenderVirtualViewport does not support returning intrinsic dimensions.\n'
'$runtimeType does not support returning intrinsic dimensions.\n'
'Calculating the intrinsic dimensions would require walking the entire '
'child list, which cannot reliably and efficiently be done for render '
'objects that potentially generate their child list during layout.'
......
// Copyright 2016 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/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('tap-select an day', (WidgetTester tester) async {
Key _datePickerKey = new UniqueKey();
DateTime _selectedDate = new DateTime(2016, DateTime.JULY, 26);
await tester.pumpWidget(
new Overlay(
initialEntries: <OverlayEntry>[
new OverlayEntry(
builder: (BuildContext context) => new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return new Positioned(
width: 400.0,
child: new Block(
children: <Widget>[
new Material(
child: new DatePicker(
firstDate: new DateTime(0),
lastDate: new DateTime(9999),
key: _datePickerKey,
selectedDate: _selectedDate,
onChanged: (DateTime value) {
setState(() {
_selectedDate = value;
});
}
)
)
]
)
);
}
)
)
]
)
);
await tester.tapAt(const Point(50.0, 200.0));
expect(_selectedDate, equals(new DateTime(2016, DateTime.JULY, 26)));
await tester.pump(const Duration(seconds: 2));
await tester.tapAt(const Point(300.0, 200.0));
expect(_selectedDate, equals(new DateTime(2016, DateTime.JULY, 1)));
await tester.pump(const Duration(seconds: 2));
await tester.tapAt(const Point(380.0, 120.0));
await tester.pump();
await tester.pump(const Duration(seconds: 2));
expect(_selectedDate, equals(new DateTime(2016, DateTime.JULY, 1)));
await tester.tapAt(const Point(300.0, 200.0));
expect(_selectedDate, equals(new DateTime(2016, DateTime.AUGUST, 5)));
await tester.pump(const Duration(seconds: 2));
await tester.scroll(find.byKey(_datePickerKey), const Offset(-300.0, 0.0));
await tester.pump();
await tester.pump(const Duration(seconds: 2));
expect(_selectedDate, equals(new DateTime(2016, DateTime.AUGUST, 5)));
await tester.tapAt(const Point(45.0, 370.0));
expect(_selectedDate, equals(new DateTime(2016, DateTime.SEPTEMBER, 25)));
await tester.pump(const Duration(seconds: 2));
await tester.scroll(find.byKey(_datePickerKey), const Offset(300.0, 10.0));
await tester.pump();
await tester.pump(const Duration(seconds: 2));
expect(_selectedDate, equals(new DateTime(2016, DateTime.SEPTEMBER, 25)));
await tester.tapAt(const Point(210.0, 280.0));
expect(_selectedDate, equals(new DateTime(2016, DateTime.AUGUST, 17)));
await tester.pump(const Duration(seconds: 2));
});
testWidgets('render picker with intrinsic dimensions', (WidgetTester tester) async {
await tester.pumpWidget(
new Overlay(
initialEntries: <OverlayEntry>[
new OverlayEntry(
builder: (BuildContext context) => new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return new IntrinsicWidth(
child: new IntrinsicHeight(
child: new Material(
child: new Block(
children: <Widget>[
new DatePicker(
firstDate: new DateTime(0),
lastDate: new DateTime(9999),
onChanged: null,
selectedDate: new DateTime(2000, DateTime.JANUARY, 1)
)
]
)
)
)
);
}
)
)
]
)
);
await tester.pump(const Duration(seconds: 5));
});
}
......@@ -15,7 +15,7 @@ void main() {
builder: (BuildContext context, StateSetter setState) {
return new Material(
child: new Center(
child: new SizedBox(
child: new SizedBox(
width: 200.0,
height: 400.0,
child: new TimePicker(
......@@ -56,6 +56,20 @@ void main() {
await tester.pump(const Duration(seconds: 1)); // Finish settling animation.
});
testWidgets('render picker with intrinsic dimensions', (WidgetTester tester) async {
await tester.pumpWidget(
new IntrinsicWidth(
child: new IntrinsicHeight(
child: new TimePicker(
onChanged: null,
selectedTime: new TimeOfDay(hour: 0, minute: 0)
)
)
)
);
await tester.pump(const Duration(seconds: 5));
});
testWidgets('drag-select an hour', (WidgetTester tester) async {
Key _timePickerKey = new UniqueKey();
TimeOfDay _selectedTime = const TimeOfDay(hour: 7, minute: 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