Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
4560ebcf
Unverified
Commit
4560ebcf
authored
May 08, 2020
by
Darren Austin
Committed by
GitHub
May 08, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implementation of the Material Date Range Picker. (#55939)
parent
cd67da26
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
2356 additions
and
65 deletions
+2356
-65
calendar_date_range_picker.dart
.../lib/src/material/pickers/calendar_date_range_picker.dart
+773
-0
date_picker_common.dart
.../flutter/lib/src/material/pickers/date_picker_common.dart
+52
-1
date_picker_dialog.dart
.../flutter/lib/src/material/pickers/date_picker_dialog.dart
+38
-18
date_picker_header.dart
.../flutter/lib/src/material/pickers/date_picker_header.dart
+8
-6
date_range_picker_dialog.dart
...er/lib/src/material/pickers/date_range_picker_dialog.dart
+715
-0
date_utils.dart
packages/flutter/lib/src/material/pickers/date_utils.dart
+35
-0
input_date_picker.dart
...s/flutter/lib/src/material/pickers/input_date_picker.dart
+41
-39
input_date_range_picker.dart
...ter/lib/src/material/pickers/input_date_range_picker.dart
+276
-0
pickers.dart
packages/flutter/lib/src/material/pickers/pickers.dart
+6
-1
date_range_picker_test.dart
packages/flutter/test/material/date_range_picker_test.dart
+412
-0
No files found.
packages/flutter/lib/src/material/pickers/calendar_date_range_picker.dart
0 → 100644
View file @
4560ebcf
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/material/pickers/date_picker_common.dart
View file @
4560ebcf
...
...
@@ -2,11 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:ui'
show
hashValues
;
import
'package:flutter/foundation.dart'
;
/// Mode of the date picker dialog.
///
/// Either a calendar or text input. In [calendar] mode, a calendar view is
/// displayed and the user taps the day they wish to select. In [input] mode a
/// [TextField] is displayed and the user types in the date they wish to select.
///
/// See also:
///
/// * [showDatePicker] and [showDateRangePicker], which use this to control
/// the initial entry mode of their dialogs.
enum
DatePickerEntryMode
{
/// Tapping on a calendar.
calendar
,
...
...
@@ -34,5 +43,47 @@ enum DatePickerMode {
/// Signature for predicating dates for enabled date selections.
///
/// See [showDatePicker].
/// See [showDatePicker], which has a [SelectableDayPredicate] parameter used
/// to specify allowable days in the date picker.
typedef
SelectableDayPredicate
=
bool
Function
(
DateTime
day
);
/// Encapsulates a start and end [DateTime] that represent the range of dates
/// between them.
///
/// See also:
/// * [showDateRangePicker], which displays a dialog that allows the user to
/// select a date range.
@immutable
class
DateTimeRange
{
/// Creates a date range for the given start and end [DateTime].
///
/// [start] and [end] must be non-null.
const
DateTimeRange
({
@required
this
.
start
,
@required
this
.
end
,
})
:
assert
(
start
!=
null
),
assert
(
end
!=
null
);
/// The start of the range of dates.
final
DateTime
start
;
/// The end of the range of dates.
final
DateTime
end
;
/// Returns a [Duration] of the time between [start] and [end].
///
/// See [DateTime.difference] for more details.
Duration
get
duration
=>
end
.
difference
(
start
);
@override
bool
operator
==(
Object
other
)
{
if
(
other
.
runtimeType
!=
runtimeType
)
return
false
;
return
other
is
DateTimeRange
&&
other
.
start
==
start
&&
other
.
end
==
end
;
}
@override
int
get
hashCode
=>
hashValues
(
start
,
end
);
}
packages/flutter/lib/src/material/pickers/date_picker_dialog.dart
View file @
4560ebcf
...
...
@@ -30,6 +30,9 @@ const Size _calendarLandscapeDialogSize = Size(496.0, 346.0);
const
Size
_inputPortraitDialogSize
=
Size
(
330.0
,
270.0
);
const
Size
_inputLandscapeDialogSize
=
Size
(
496
,
160.0
);
const
Duration
_dialogSizeAnimationDuration
=
Duration
(
milliseconds:
200
);
const
double
_inputFormPortraitHeight
=
98.0
;
const
double
_inputFormLandscapeHeight
=
108.0
;
/// Shows a dialog containing a Material Design date picker.
///
...
...
@@ -60,17 +63,16 @@ const Duration _dialogSizeAnimationDuration = Duration(milliseconds: 200);
/// this can be used to only allow weekdays for selection. If provided, it must
/// return true for [initialDate].
///
/// Optional strings for the [cancelText], [confirmText], [errorFormatText],
/// [errorInvalidText], [fieldHintText], [fieldLabelText], and [helpText] allow
/// you to override the default text used for various parts of the dialog:
/// The following optional string parameters allow you to override the default
/// text used for various parts of the dialog:
///
/// * [helpText], label displayed at the top of the dialog.
/// * [cancelText], label on the cancel button.
/// * [confirmText], label on the ok button.
/// * [errorFormatText], message used when the input text isn't in a proper date format.
/// * [errorInvalidText], message used when the input text isn't a selectable date.
/// * [fieldHintText], text used to prompt the user when no text has been entered in the field.
/// * [fieldLabelText], label for the date text input field.
/// * [helpText], label on the top of the dialog.
///
/// An optional [locale] argument can be used to set the locale for the date
/// picker. It defaults to the ambient locale provided by [Localizations].
...
...
@@ -92,6 +94,14 @@ const Duration _dialogSizeAnimationDuration = Duration(milliseconds: 200);
/// calendar date picker initially appear in the [DatePickerMode.year] or
/// [DatePickerMode.day] mode. It defaults to [DatePickerMode.day], and
/// must be non-null.
///
/// See also:
///
/// * [showDateRangePicker], which shows a material design date range picker
/// used to select a range of dates.
/// * [CalendarDatePicker], which provides the calendar grid used by the date picker dialog.
/// * [InputDatePickerFormField], which provides a text input field for entering dates.
///
Future
<
DateTime
>
showDatePicker
({
@required
BuildContext
context
,
@required
DateTime
initialDate
,
...
...
@@ -304,7 +314,7 @@ class _DatePickerDialogState extends State<_DatePickerDialog> {
Navigator
.
pop
(
context
);
}
void
_hand
el
EntryModeToggle
()
{
void
_hand
le
EntryModeToggle
()
{
setState
(()
{
switch
(
_entryMode
)
{
case
DatePickerEntryMode
.
calendar
:
...
...
@@ -407,18 +417,28 @@ class _DatePickerDialogState extends State<_DatePickerDialog> {
picker
=
Form
(
key:
_formKey
,
autovalidate:
_autoValidate
,
child:
InputDatePickerFormField
(
initialDate:
_selectedDate
,
firstDate:
widget
.
firstDate
,
lastDate:
widget
.
lastDate
,
onDateSubmitted:
_handleDateChanged
,
onDateSaved:
_handleDateChanged
,
selectableDayPredicate:
widget
.
selectableDayPredicate
,
errorFormatText:
widget
.
errorFormatText
,
errorInvalidText:
widget
.
errorInvalidText
,
fieldHintText:
widget
.
fieldHintText
,
fieldLabelText:
widget
.
fieldLabelText
,
autofocus:
true
,
child:
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
24
),
height:
orientation
==
Orientation
.
portrait
?
_inputFormPortraitHeight
:
_inputFormLandscapeHeight
,
child:
Column
(
children:
<
Widget
>[
const
Spacer
(),
InputDatePickerFormField
(
initialDate:
_selectedDate
,
firstDate:
widget
.
firstDate
,
lastDate:
widget
.
lastDate
,
onDateSubmitted:
_handleDateChanged
,
onDateSaved:
_handleDateChanged
,
selectableDayPredicate:
widget
.
selectableDayPredicate
,
errorFormatText:
widget
.
errorFormatText
,
errorInvalidText:
widget
.
errorInvalidText
,
fieldHintText:
widget
.
fieldHintText
,
fieldLabelText:
widget
.
fieldLabelText
,
autofocus:
true
,
),
const
Spacer
(),
],
),
),
);
entryModeIcon
=
Icons
.
calendar_today
;
...
...
@@ -436,7 +456,7 @@ class _DatePickerDialogState extends State<_DatePickerDialog> {
isShort:
orientation
==
Orientation
.
landscape
,
icon:
entryModeIcon
,
iconTooltip:
entryModeTooltip
,
onIconPressed:
_hand
el
EntryModeToggle
,
onIconPressed:
_hand
le
EntryModeToggle
,
);
final
Size
dialogSize
=
_dialogSize
(
context
)
*
textScaleFactor
;
...
...
packages/flutter/lib/src/material/pickers/date_picker_header.dart
View file @
4560ebcf
...
...
@@ -25,6 +25,7 @@ const double _headerPaddingLandscape = 16.0;
///
/// * Single Date picker with calendar mode.
/// * Single Date picker with manual input mode.
/// * Date Range picker with manual input mode.
///
/// [helpText], [orientation], [icon], [onIconPressed] are required and must be
/// non-null.
...
...
@@ -112,7 +113,7 @@ class DatePickerHeader extends StatelessWidget {
titleText
,
semanticsLabel:
titleSemanticsLabel
??
titleText
,
style:
titleStyle
,
maxLines:
(
isShort
||
orientation
==
Orientation
.
portrait
)
?
1
:
2
,
maxLines:
orientation
==
Orientation
.
portrait
?
1
:
2
,
overflow:
TextOverflow
.
ellipsis
,
);
final
IconButton
icon
=
IconButton
(
...
...
@@ -169,13 +170,14 @@ class DatePickerHeader extends StatelessWidget {
child:
help
,
),
SizedBox
(
height:
isShort
?
16
:
56
),
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
_headerPaddingLandscape
,
Expanded
(
child:
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
_headerPaddingLandscape
,
),
child:
title
,
),
child:
title
,
),
const
Spacer
(),
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
4
,
...
...
packages/flutter/lib/src/material/pickers/date_range_picker_dialog.dart
0 → 100644
View file @
4560ebcf
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/material/pickers/date_utils.dart
View file @
4560ebcf
...
...
@@ -12,11 +12,18 @@
import
'../material_localizations.dart'
;
import
'date_picker_common.dart'
;
/// Returns a [DateTime] with just the date of the original, but no time set.
DateTime
dateOnly
(
DateTime
date
)
{
return
DateTime
(
date
.
year
,
date
.
month
,
date
.
day
);
}
/// Returns a [DateTimeRange] with the dates of the original without any times set.
DateTimeRange
datesOnly
(
DateTimeRange
range
)
{
return
DateTimeRange
(
start:
dateOnly
(
range
.
start
),
end:
dateOnly
(
range
.
end
));
}
/// Returns true if the two [DateTime] objects have the same day, month, and
/// year.
bool
isSameDay
(
DateTime
dateA
,
DateTime
dateB
)
{
...
...
@@ -120,3 +127,31 @@ int getDaysInMonth(int year, int month) {
const
List
<
int
>
daysInMonth
=
<
int
>[
31
,
-
1
,
31
,
30
,
31
,
30
,
31
,
31
,
30
,
31
,
30
,
31
];
return
daysInMonth
[
month
-
1
];
}
/// Returns a locale-appropriate string to describe the start of a date range.
///
/// If `startDate` is null, then it defaults to 'Start Date', otherwise if it
/// is in the same year as the `endDate` then it will use the short month
/// day format (i.e. 'Jan 21'). Otherwise it will return the short date format
/// (i.e. 'Jan 21, 2020').
String
formatRangeStartDate
(
MaterialLocalizations
localizations
,
DateTime
startDate
,
DateTime
endDate
)
{
return
startDate
==
null
?
'Start Date'
:
(
endDate
==
null
||
startDate
.
year
==
endDate
.
year
)
?
localizations
.
formatShortMonthDay
(
startDate
)
:
localizations
.
formatShortDate
(
startDate
);
}
/// Returns an locale-appropriate string to describe the end of a date range.
///
/// If `endDate` is null, then it defaults to 'End Date', otherwise if it
/// is in the same year as the `startDate` and the `currentDate` then it will
/// just use the short month day format (i.e. 'Jan 21'), otherwise it will
/// include the year (i.e. 'Jan 21, 2020').
String
formatRangeEndDate
(
MaterialLocalizations
localizations
,
DateTime
startDate
,
DateTime
endDate
,
DateTime
currentDate
)
{
return
endDate
==
null
?
'End Date'
:
(
startDate
!=
null
&&
startDate
.
year
==
endDate
.
year
&&
startDate
.
year
==
currentDate
.
year
)
?
localizations
.
formatShortMonthDay
(
endDate
)
:
localizations
.
formatShortDate
(
endDate
);
}
packages/flutter/lib/src/material/pickers/input_date_picker.dart
View file @
4560ebcf
...
...
@@ -8,15 +8,11 @@ import 'package:flutter/widgets.dart';
import
'../input_border.dart'
;
import
'../input_decorator.dart'
;
import
'../material_localizations.dart'
;
import
'../text_field.dart'
;
import
'../text_form_field.dart'
;
import
'date_picker_common.dart'
;
import
'date_utils.dart'
as
utils
;
const
double
_inputPortraitHeight
=
98.0
;
const
double
_inputLandscapeHeight
=
108.0
;
/// A [TextFormField] configured to accept and validate a date entered by the user.
///
/// The text entered into this field will be constrained to only allow digits
...
...
@@ -227,54 +223,60 @@ class _InputDatePickerFormFieldState extends State<InputDatePickerFormField> {
return
OrientationBuilder
(
builder:
(
BuildContext
context
,
Orientation
orientation
)
{
assert
(
orientation
!=
null
);
return
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
24
),
height:
orientation
==
Orientation
.
portrait
?
_inputPortraitHeight
:
_inputLandscapeHeight
,
child:
Column
(
children:
<
Widget
>[
const
Spacer
(),
TextFormField
(
decoration:
InputDecoration
(
border:
const
UnderlineInputBorder
(),
filled:
true
,
// TODO(darrenaustin): localize 'mm/dd/yyyy' and 'Enter Date'
hintText:
widget
.
fieldHintText
??
'mm/dd/yyyy'
,
labelText:
widget
.
fieldLabelText
??
'Enter Date'
,
),
validator:
_validateDate
,
inputFormatters:
<
TextInputFormatter
>[
// TODO(darrenaustin): localize date separator '/'
_DateTextInputFormatter
(
'/'
),
],
keyboardType:
TextInputType
.
datetime
,
onSaved:
_handleSaved
,
onFieldSubmitted:
_handleSubmitted
,
autofocus:
widget
.
autofocus
,
controller:
_controller
,
),
const
Spacer
(),
],
return
TextFormField
(
decoration:
InputDecoration
(
border:
const
UnderlineInputBorder
(),
filled:
true
,
// TODO(darrenaustin): localize 'mm/dd/yyyy' and 'Enter Date'
hintText:
widget
.
fieldHintText
??
'mm/dd/yyyy'
,
labelText:
widget
.
fieldLabelText
??
'Enter Date'
,
),
validator:
_validateDate
,
inputFormatters:
<
TextInputFormatter
>[
// TODO(darrenaustin): localize date separator '/'
DateTextInputFormatter
(
'/'
),
],
keyboardType:
TextInputType
.
datetime
,
onSaved:
_handleSaved
,
onFieldSubmitted:
_handleSubmitted
,
autofocus:
widget
.
autofocus
,
controller:
_controller
,
);
});
}
}
class
_DateTextInputFormatter
extends
TextInputFormatter
{
_DateTextInputFormatter
(
this
.
separator
);
/// A `TextInputFormatter` set up to format dates.
///
/// Note: this is not publicly exported (see pickers.dart), as it is
/// just meant for internal use by `InputDatePickerFormField` and
/// `InputDateRangePicker`.
class
DateTextInputFormatter
extends
TextInputFormatter
{
/// Creates a date formatter with the given separator.
DateTextInputFormatter
(
this
.
separator
)
:
_filterFormatter
=
WhitelistingTextInputFormatter
(
RegExp
(
'[
\\
d
$_commonSeparators
\\
$separator
]+'
));
/// List of common separators that are used in dates. This is used to make
/// sure that if given platform's [TextInputType.datetime] keyboard doesn't
/// provide the given locale's separator character, they can still enter the
/// separator using one of these characters (slash, period, comma, dash, or
/// space).
static
const
String
_commonSeparators
=
r'\/\.,-\s'
;
/// The date separator for the current locale.
final
String
separator
;
final
WhitelistingTextInputFormatter
_filterFormatter
=
// Only allow digits and separators (slash, dot, comma, hyphen, space)
.
WhitelistingTextInputFormatter
(
RegExp
(
r'[\d\/\.,-\s]+'
))
;
// Formatter that will filter out all characters except digits and date
// separators
.
final
WhitelistingTextInputFormatter
_filterFormatter
;
@override
TextEditingValue
formatEditUpdate
(
TextEditingValue
oldValue
,
TextEditingValue
newValue
)
{
final
TextEditingValue
filteredValue
=
_filterFormatter
.
formatEditUpdate
(
oldValue
,
newValue
);
return
filteredValue
.
copyWith
(
// Replace any
separator character
with the given separator
// Replace any
non-digits
with the given separator
text:
filteredValue
.
text
.
replaceAll
(
RegExp
(
r'[\D]'
),
separator
),
);
}
...
...
packages/flutter/lib/src/material/pickers/input_date_range_picker.dart
0 → 100644
View file @
4560ebcf
// Copyright 2014 The Flutter 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
'../input_border.dart'
;
import
'../input_decorator.dart'
;
import
'../material_localizations.dart'
;
import
'../text_field.dart'
;
import
'date_utils.dart'
as
utils
;
import
'input_date_picker.dart'
show
DateTextInputFormatter
;
/// Provides a pair of text fields that allow the user to enter the start and
/// end dates that represent a range of dates.
///
/// Note: this is not publicly exported (see pickers.dart), as it is just an
/// internal component used by [showDateRangePicker].
class
InputDateRangePicker
extends
StatefulWidget
{
/// Creates a row with two text fields configured to accept the start and end dates
/// of a date range.
InputDateRangePicker
({
Key
key
,
DateTime
initialStartDate
,
DateTime
initialEndDate
,
@required
DateTime
firstDate
,
@required
DateTime
lastDate
,
@required
this
.
onStartDateChanged
,
@required
this
.
onEndDateChanged
,
this
.
helpText
,
this
.
errorFormatText
,
this
.
errorInvalidText
,
this
.
errorInvalidRangeText
,
this
.
fieldStartHintText
,
this
.
fieldEndHintText
,
this
.
fieldStartLabelText
,
this
.
fieldEndLabelText
,
this
.
autofocus
=
false
,
this
.
autovalidate
=
false
,
})
:
initialStartDate
=
initialStartDate
==
null
?
null
:
utils
.
dateOnly
(
initialStartDate
),
initialEndDate
=
initialEndDate
==
null
?
null
:
utils
.
dateOnly
(
initialEndDate
),
assert
(
firstDate
!=
null
),
firstDate
=
utils
.
dateOnly
(
firstDate
),
assert
(
lastDate
!=
null
),
lastDate
=
utils
.
dateOnly
(
lastDate
),
assert
(
firstDate
!=
null
),
assert
(
lastDate
!=
null
),
assert
(
autofocus
!=
null
),
assert
(
autovalidate
!=
null
),
super
(
key:
key
);
/// The [DateTime] that represents the start of the initial date range selection.
final
DateTime
initialStartDate
;
/// The [DateTime] that represents the end of the initial date range selection.
final
DateTime
initialEndDate
;
/// The earliest allowable [DateTime] that the user can select.
final
DateTime
firstDate
;
/// The latest allowable [DateTime] that the user can select.
final
DateTime
lastDate
;
/// Called when the user changes the start date of the selected range.
final
ValueChanged
<
DateTime
>
onStartDateChanged
;
/// Called when the user changes the end date of the selected range.
final
ValueChanged
<
DateTime
>
onEndDateChanged
;
/// The text that is displayed at the top of the header.
///
/// This is used to indicate to the user what they are selecting a date for.
final
String
helpText
;
/// Error text used to indicate the text in a field is not a valid date.
final
String
errorFormatText
;
/// Error text used to indicate the date in a field is not in the valid range
/// of [firstDate] - [lastDate].
final
String
errorInvalidText
;
/// Error text used to indicate the dates given don't form a valid date
/// range (i.e. the start date is after the end date).
final
String
errorInvalidRangeText
;
/// Hint text shown when the start date field is empty.
final
String
fieldStartHintText
;
/// Hint text shown when the end date field is empty.
final
String
fieldEndHintText
;
/// Label used for the start date field.
final
String
fieldStartLabelText
;
/// Label used for the end date field.
final
String
fieldEndLabelText
;
/// {@macro flutter.widgets.editableText.autofocus}
final
bool
autofocus
;
/// If true, this the date fields will validate and update their error text
/// immediately after every change. Otherwise, you must call
/// [InputDateRangePickerState.validate] to validate.
final
bool
autovalidate
;
@override
InputDateRangePickerState
createState
()
=>
InputDateRangePickerState
();
}
/// The current state of an [InputDateRangePicker]. Can be used to
/// [validate] the date field entries.
class
InputDateRangePickerState
extends
State
<
InputDateRangePicker
>
{
String
_startInputText
;
String
_endInputText
;
DateTime
_startDate
;
DateTime
_endDate
;
TextEditingController
_startController
;
TextEditingController
_endController
;
String
_startErrorText
;
String
_endErrorText
;
bool
_autoSelected
=
false
;
List
<
TextInputFormatter
>
_inputFormatters
;
@override
void
initState
()
{
super
.
initState
();
_startDate
=
widget
.
initialStartDate
;
_startController
=
TextEditingController
();
_endDate
=
widget
.
initialEndDate
;
_endController
=
TextEditingController
();
}
@override
void
dispose
()
{
_startController
.
dispose
();
_endController
.
dispose
();
super
.
dispose
();
}
@override
void
didChangeDependencies
()
{
super
.
didChangeDependencies
();
final
MaterialLocalizations
localizations
=
MaterialLocalizations
.
of
(
context
);
_inputFormatters
=
<
TextInputFormatter
>[
// TODO(darrenaustin): localize date separator '/'
DateTextInputFormatter
(
'/'
),
];
if
(
_startDate
!=
null
)
{
_startInputText
=
localizations
.
formatCompactDate
(
_startDate
);
final
bool
selectText
=
widget
.
autofocus
&&
!
_autoSelected
;
_updateController
(
_startController
,
_startInputText
,
selectText
);
_autoSelected
=
selectText
;
}
if
(
_endDate
!=
null
)
{
_endInputText
=
localizations
.
formatCompactDate
(
_endDate
);
_updateController
(
_endController
,
_endInputText
,
false
);
}
}
/// Validates that the text in the start and end fields represent a valid
/// date range.
///
/// Will return true if the range is valid. If not, it will
/// return false and display an appropriate error message under one of the
/// text fields.
bool
validate
()
{
String
startError
=
_validateDate
(
_startDate
);
final
String
endError
=
_validateDate
(
_endDate
);
if
(
startError
==
null
&&
endError
==
null
)
{
if
(
_startDate
.
isAfter
(
_endDate
))
{
// TODO(darrenaustin): localize 'Invalid range.'
startError
=
widget
.
errorInvalidRangeText
??
'Invalid range.'
;
}
}
setState
(()
{
_startErrorText
=
startError
;
_endErrorText
=
endError
;
});
return
startError
==
null
&&
endError
==
null
;
}
DateTime
_parseDate
(
String
text
)
{
final
MaterialLocalizations
localizations
=
MaterialLocalizations
.
of
(
context
);
return
localizations
.
parseCompactDate
(
text
);
}
String
_validateDate
(
DateTime
date
)
{
if
(
date
==
null
)
{
// TODO(darrenaustin): localize 'Invalid format.'
return
widget
.
errorFormatText
??
'Invalid format.'
;
}
else
if
(
date
.
isBefore
(
widget
.
firstDate
)
||
date
.
isAfter
(
widget
.
lastDate
))
{
// TODO(darrenaustin): localize 'Out of range.'
return
widget
.
errorInvalidText
??
'Out of range.'
;
}
return
null
;
}
void
_updateController
(
TextEditingController
controller
,
String
text
,
bool
selectText
)
{
TextEditingValue
textEditingValue
=
controller
.
value
.
copyWith
(
text:
text
);
if
(
selectText
)
{
textEditingValue
=
textEditingValue
.
copyWith
(
selection:
TextSelection
(
baseOffset:
0
,
extentOffset:
text
.
length
,
));
}
controller
.
value
=
textEditingValue
;
}
void
_handleStartChanged
(
String
text
)
{
setState
(()
{
_startInputText
=
text
;
_startDate
=
_parseDate
(
text
);
widget
.
onStartDateChanged
?.
call
(
_startDate
);
});
if
(
widget
.
autovalidate
)
{
validate
();
}
}
void
_handleEndChanged
(
String
text
)
{
setState
(()
{
_endInputText
=
text
;
_endDate
=
_parseDate
(
text
);
widget
.
onEndDateChanged
?.
call
(
_endDate
);
});
if
(
widget
.
autovalidate
)
{
validate
();
}
}
@override
Widget
build
(
BuildContext
context
)
{
return
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
<
Widget
>[
Expanded
(
child:
TextField
(
controller:
_startController
,
decoration:
InputDecoration
(
border:
const
UnderlineInputBorder
(),
filled:
true
,
// TODO(darrenaustin): localize 'mm/dd/yyyy' and 'Start Date'
hintText:
widget
.
fieldStartHintText
??
'mm/dd/yyyy'
,
labelText:
widget
.
fieldStartLabelText
??
'Start Date'
,
errorText:
_startErrorText
,
),
inputFormatters:
_inputFormatters
,
keyboardType:
TextInputType
.
datetime
,
onChanged:
_handleStartChanged
,
autofocus:
widget
.
autofocus
,
),
),
const
SizedBox
(
width:
8
),
Expanded
(
child:
TextField
(
controller:
_endController
,
decoration:
InputDecoration
(
border:
const
UnderlineInputBorder
(),
filled:
true
,
// TODO(darrenaustin): localize 'mm/dd/yyyy' and 'End Date'
hintText:
widget
.
fieldEndHintText
??
'mm/dd/yyyy'
,
labelText:
widget
.
fieldEndLabelText
??
'End Date'
,
errorText:
_endErrorText
,
),
inputFormatters:
_inputFormatters
,
keyboardType:
TextInputType
.
datetime
,
onChanged:
_handleEndChanged
,
),
),
],
);
}
}
packages/flutter/lib/src/material/pickers/pickers.dart
View file @
4560ebcf
...
...
@@ -4,7 +4,12 @@
// Date Picker public API
export
'calendar_date_picker.dart'
show
CalendarDatePicker
;
export
'date_picker_common.dart'
show
DatePickerEntryMode
,
DatePickerMode
,
SelectableDayPredicate
;
export
'date_picker_common.dart'
show
DatePickerEntryMode
,
DatePickerMode
,
DateTimeRange
,
SelectableDayPredicate
;
export
'date_picker_deprecated.dart'
;
export
'date_picker_dialog.dart'
show
showDatePicker
;
export
'date_range_picker_dialog.dart'
show
showDateRangePicker
;
export
'input_date_picker.dart'
show
InputDatePickerFormField
;
packages/flutter/test/material/date_range_picker_test.dart
0 → 100644
View file @
4560ebcf
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment