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
9e715205
Unverified
Commit
9e715205
authored
Oct 02, 2020
by
Rami
Committed by
GitHub
Oct 02, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Time Picker] Double tapping hours/minutes will switch time picker to input mode (#67076)
parent
a2eef79f
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
133 additions
and
0 deletions
+133
-0
time_picker.dart
packages/flutter/lib/src/material/time_picker.dart
+50
-0
time_picker_test.dart
packages/flutter/test/material/time_picker_test.dart
+83
-0
No files found.
packages/flutter/lib/src/material/time_picker.dart
View file @
9e715205
...
...
@@ -82,6 +82,8 @@ class _TimePickerFragmentContext {
@required
this
.
mode
,
@required
this
.
onTimeChange
,
@required
this
.
onModeChange
,
@required
this
.
onHourDoubleTapped
,
@required
this
.
onMinuteDoubleTapped
,
@required
this
.
use24HourDials
,
})
:
assert
(
selectedTime
!=
null
),
assert
(
mode
!=
null
),
...
...
@@ -93,6 +95,8 @@ class _TimePickerFragmentContext {
final
_TimePickerMode
mode
;
final
ValueChanged
<
TimeOfDay
>
onTimeChange
;
final
ValueChanged
<
_TimePickerMode
>
onModeChange
;
final
GestureTapCallback
onHourDoubleTapped
;
final
GestureTapCallback
onMinuteDoubleTapped
;
final
bool
use24HourDials
;
}
...
...
@@ -103,6 +107,8 @@ class _TimePickerHeader extends StatelessWidget {
@required
this
.
orientation
,
@required
this
.
onModeChanged
,
@required
this
.
onChanged
,
@required
this
.
onHourDoubleTapped
,
@required
this
.
onMinuteDoubleTapped
,
@required
this
.
use24HourDials
,
@required
this
.
helpText
,
})
:
assert
(
selectedTime
!=
null
),
...
...
@@ -115,6 +121,8 @@ class _TimePickerHeader extends StatelessWidget {
final
Orientation
orientation
;
final
ValueChanged
<
_TimePickerMode
>
onModeChanged
;
final
ValueChanged
<
TimeOfDay
>
onChanged
;
final
GestureTapCallback
onHourDoubleTapped
;
final
GestureTapCallback
onMinuteDoubleTapped
;
final
bool
use24HourDials
;
final
String
helpText
;
...
...
@@ -136,6 +144,8 @@ class _TimePickerHeader extends StatelessWidget {
mode:
mode
,
onTimeChange:
onChanged
,
onModeChange:
_handleChangeMode
,
onHourDoubleTapped:
onHourDoubleTapped
,
onMinuteDoubleTapped:
onMinuteDoubleTapped
,
use24HourDials:
use24HourDials
,
);
...
...
@@ -246,6 +256,7 @@ class _HourMinuteControl extends StatelessWidget {
const
_HourMinuteControl
({
@required
this
.
text
,
@required
this
.
onTap
,
@required
this
.
onDoubleTap
,
@required
this
.
isSelected
,
})
:
assert
(
text
!=
null
),
assert
(
onTap
!=
null
),
...
...
@@ -253,6 +264,7 @@ class _HourMinuteControl extends StatelessWidget {
final
String
text
;
final
GestureTapCallback
onTap
;
final
GestureTapCallback
onDoubleTap
;
final
bool
isSelected
;
@override
...
...
@@ -284,6 +296,7 @@ class _HourMinuteControl extends StatelessWidget {
shape:
shape
,
child:
InkWell
(
onTap:
onTap
,
onDoubleTap:
isSelected
?
onDoubleTap
:
null
,
child:
Center
(
child:
Text
(
text
,
...
...
@@ -359,6 +372,7 @@ class _HourControl extends StatelessWidget {
isSelected:
fragmentContext
.
mode
==
_TimePickerMode
.
hour
,
text:
formattedHour
,
onTap:
Feedback
.
wrapForTap
(()
=>
fragmentContext
.
onModeChange
(
_TimePickerMode
.
hour
),
context
),
onDoubleTap:
fragmentContext
.
onHourDoubleTapped
,
),
);
}
...
...
@@ -448,6 +462,7 @@ class _MinuteControl extends StatelessWidget {
isSelected:
fragmentContext
.
mode
==
_TimePickerMode
.
minute
,
text:
formattedMinute
,
onTap:
Feedback
.
wrapForTap
(()
=>
fragmentContext
.
onModeChange
(
_TimePickerMode
.
minute
),
context
),
onDoubleTap:
fragmentContext
.
onMinuteDoubleTapped
,
),
);
}
...
...
@@ -1265,6 +1280,8 @@ class _TimePickerInput extends StatefulWidget {
Key
key
,
@required
this
.
initialSelectedTime
,
@required
this
.
helpText
,
@required
this
.
autofocusHour
,
@required
this
.
autofocusMinute
,
@required
this
.
onChanged
,
})
:
assert
(
initialSelectedTime
!=
null
),
assert
(
onChanged
!=
null
),
...
...
@@ -1276,6 +1293,10 @@ class _TimePickerInput extends StatefulWidget {
/// Optionally provide your own help text to the time picker.
final
String
helpText
;
final
bool
autofocusHour
;
final
bool
autofocusMinute
;
final
ValueChanged
<
TimeOfDay
>
onChanged
;
@override
...
...
@@ -1430,6 +1451,7 @@ class _TimePickerInputState extends State<_TimePickerInput> {
_HourTextField
(
selectedTime:
_selectedTime
,
style:
hourMinuteStyle
,
autofocus:
widget
.
autofocusHour
,
validator:
_validateHour
,
onSavedSubmitted:
_handleHourSavedSubmitted
,
onChanged:
_handleHourChanged
,
...
...
@@ -1460,6 +1482,7 @@ class _TimePickerInputState extends State<_TimePickerInput> {
_MinuteTextField
(
selectedTime:
_selectedTime
,
style:
hourMinuteStyle
,
autofocus:
widget
.
autofocusMinute
,
validator:
_validateMinute
,
onSavedSubmitted:
_handleMinuteSavedSubmitted
,
),
...
...
@@ -1507,6 +1530,7 @@ class _HourTextField extends StatelessWidget {
Key
key
,
@required
this
.
selectedTime
,
@required
this
.
style
,
@required
this
.
autofocus
,
@required
this
.
validator
,
@required
this
.
onSavedSubmitted
,
@required
this
.
onChanged
,
...
...
@@ -1514,6 +1538,7 @@ class _HourTextField extends StatelessWidget {
final
TimeOfDay
selectedTime
;
final
TextStyle
style
;
final
bool
autofocus
;
final
FormFieldValidator
<
String
>
validator
;
final
ValueChanged
<
String
>
onSavedSubmitted
;
final
ValueChanged
<
String
>
onChanged
;
...
...
@@ -1523,6 +1548,7 @@ class _HourTextField extends StatelessWidget {
return
_HourMinuteTextField
(
selectedTime:
selectedTime
,
isHour:
true
,
autofocus:
autofocus
,
style:
style
,
semanticHintText:
MaterialLocalizations
.
of
(
context
).
timePickerHourLabel
,
validator:
validator
,
...
...
@@ -1537,12 +1563,14 @@ class _MinuteTextField extends StatelessWidget {
Key
key
,
@required
this
.
selectedTime
,
@required
this
.
style
,
@required
this
.
autofocus
,
@required
this
.
validator
,
@required
this
.
onSavedSubmitted
,
})
:
super
(
key:
key
);
final
TimeOfDay
selectedTime
;
final
TextStyle
style
;
final
bool
autofocus
;
final
FormFieldValidator
<
String
>
validator
;
final
ValueChanged
<
String
>
onSavedSubmitted
;
...
...
@@ -1551,6 +1579,7 @@ class _MinuteTextField extends StatelessWidget {
return
_HourMinuteTextField
(
selectedTime:
selectedTime
,
isHour:
false
,
autofocus:
autofocus
,
style:
style
,
semanticHintText:
MaterialLocalizations
.
of
(
context
).
timePickerMinuteLabel
,
validator:
validator
,
...
...
@@ -1564,6 +1593,7 @@ class _HourMinuteTextField extends StatefulWidget {
Key
key
,
@required
this
.
selectedTime
,
@required
this
.
isHour
,
@required
this
.
autofocus
,
@required
this
.
style
,
@required
this
.
semanticHintText
,
@required
this
.
validator
,
...
...
@@ -1573,6 +1603,7 @@ class _HourMinuteTextField extends StatefulWidget {
final
TimeOfDay
selectedTime
;
final
bool
isHour
;
final
bool
autofocus
;
final
TextStyle
style
;
final
String
semanticHintText
;
final
FormFieldValidator
<
String
>
validator
;
...
...
@@ -1658,6 +1689,7 @@ class _HourMinuteTextFieldState extends State<_HourMinuteTextField> {
child:
MediaQuery
(
data:
MediaQuery
.
of
(
context
).
copyWith
(
textScaleFactor:
1.0
),
child:
TextFormField
(
autofocus:
widget
.
autofocus
??
false
,
expands:
true
,
maxLines:
null
,
inputFormatters:
<
TextInputFormatter
>[
...
...
@@ -1746,6 +1778,8 @@ class _TimePickerDialogState extends State<_TimePickerDialog> {
_TimePickerMode
_mode
=
_TimePickerMode
.
hour
;
_TimePickerMode
_lastModeAnnounced
;
bool
_autoValidate
;
bool
_autofocusHour
;
bool
_autofocusMinute
;
TimeOfDay
get
selectedTime
=>
_selectedTime
;
TimeOfDay
_selectedTime
;
...
...
@@ -1788,6 +1822,8 @@ class _TimePickerDialogState extends State<_TimePickerDialog> {
break
;
case
TimePickerEntryMode
.
input
:
_formKey
.
currentState
.
save
();
_autofocusHour
=
false
;
_autofocusMinute
=
false
;
_entryMode
=
TimePickerEntryMode
.
dial
;
break
;
}
...
...
@@ -1833,6 +1869,16 @@ class _TimePickerDialogState extends State<_TimePickerDialog> {
});
}
void
_handleHourDoubleTapped
()
{
_autofocusHour
=
true
;
_handleEntryModeToggle
();
}
void
_handleMinuteDoubleTapped
()
{
_autofocusMinute
=
true
;
_handleEntryModeToggle
();
}
void
_handleHourSelected
()
{
setState
(()
{
_mode
=
_TimePickerMode
.
minute
;
...
...
@@ -1962,6 +2008,8 @@ class _TimePickerDialogState extends State<_TimePickerDialog> {
orientation:
orientation
,
onModeChanged:
_handleModeChanged
,
onChanged:
_handleTimeChanged
,
onHourDoubleTapped:
_handleHourDoubleTapped
,
onMinuteDoubleTapped:
_handleMinuteDoubleTapped
,
use24HourDials:
use24HourDials
,
helpText:
widget
.
helpText
,
);
...
...
@@ -2014,6 +2062,8 @@ class _TimePickerDialogState extends State<_TimePickerDialog> {
_TimePickerInput
(
initialSelectedTime:
_selectedTime
,
helpText:
widget
.
helpText
,
autofocusHour:
_autofocusHour
,
autofocusMinute:
_autofocusMinute
,
onChanged:
_handleTimeChanged
,
),
actions
,
...
...
packages/flutter/test/material/time_picker_test.dart
View file @
9e715205
...
...
@@ -803,6 +803,89 @@ void _testsInput() {
expect
(
find
.
byType
(
TextField
),
findsNothing
);
});
testWidgets
(
'Can double tap hours (when selected) to enter input mode'
,
(
WidgetTester
tester
)
async
{
await
mediaQueryBoilerplate
(
tester
,
false
,
entryMode:
TimePickerEntryMode
.
dial
);
final
Finder
hourFinder
=
find
.
ancestor
(
of:
find
.
text
(
'7'
),
matching:
find
.
byType
(
InkWell
),
);
expect
(
find
.
byType
(
TextField
),
findsNothing
);
// Double tap the hour.
await
tester
.
tap
(
hourFinder
);
await
tester
.
pump
(
const
Duration
(
milliseconds:
100
));
await
tester
.
tap
(
hourFinder
);
await
tester
.
pumpAndSettle
();
expect
(
find
.
byType
(
TextField
),
findsWidgets
);
});
testWidgets
(
'Can not double tap hours (when not selected) to enter input mode'
,
(
WidgetTester
tester
)
async
{
await
mediaQueryBoilerplate
(
tester
,
false
,
entryMode:
TimePickerEntryMode
.
dial
);
final
Finder
hourFinder
=
find
.
ancestor
(
of:
find
.
text
(
'7'
),
matching:
find
.
byType
(
InkWell
),
);
final
Finder
minuteFinder
=
find
.
ancestor
(
of:
find
.
text
(
'00'
),
matching:
find
.
byType
(
InkWell
),
);
expect
(
find
.
byType
(
TextField
),
findsNothing
);
// Switch to minutes mode.
await
tester
.
tap
(
minuteFinder
);
await
tester
.
pumpAndSettle
();
// Double tap the hour.
await
tester
.
tap
(
hourFinder
);
await
tester
.
pump
(
const
Duration
(
milliseconds:
100
));
await
tester
.
tap
(
hourFinder
);
await
tester
.
pumpAndSettle
();
expect
(
find
.
byType
(
TextField
),
findsNothing
);
});
testWidgets
(
'Can double tap minutes (when selected) to enter input mode'
,
(
WidgetTester
tester
)
async
{
await
mediaQueryBoilerplate
(
tester
,
false
,
entryMode:
TimePickerEntryMode
.
dial
);
final
Finder
minuteFinder
=
find
.
ancestor
(
of:
find
.
text
(
'00'
),
matching:
find
.
byType
(
InkWell
),
);
expect
(
find
.
byType
(
TextField
),
findsNothing
);
// Switch to minutes mode.
await
tester
.
tap
(
minuteFinder
);
await
tester
.
pumpAndSettle
();
// Double tap the minutes.
await
tester
.
tap
(
minuteFinder
);
await
tester
.
pump
(
const
Duration
(
milliseconds:
100
));
await
tester
.
tap
(
minuteFinder
);
await
tester
.
pumpAndSettle
();
expect
(
find
.
byType
(
TextField
),
findsWidgets
);
});
testWidgets
(
'Can not double tap minutes (when not selected) to enter input mode'
,
(
WidgetTester
tester
)
async
{
await
mediaQueryBoilerplate
(
tester
,
false
,
entryMode:
TimePickerEntryMode
.
dial
);
final
Finder
minuteFinder
=
find
.
ancestor
(
of:
find
.
text
(
'00'
),
matching:
find
.
byType
(
InkWell
),
);
expect
(
find
.
byType
(
TextField
),
findsNothing
);
// Double tap the minutes.
await
tester
.
tap
(
minuteFinder
);
await
tester
.
pump
(
const
Duration
(
milliseconds:
100
));
await
tester
.
tap
(
minuteFinder
);
await
tester
.
pumpAndSettle
();
expect
(
find
.
byType
(
TextField
),
findsNothing
);
});
testWidgets
(
'Entered text returns time'
,
(
WidgetTester
tester
)
async
{
TimeOfDay
result
;
...
...
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