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
ffb95f05
Commit
ffb95f05
authored
Nov 20, 2015
by
Ian Hickson
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #517 from Hixie/snackbar-dismiss
Expose the close()/closed API for snack bars
parents
98333cb2
ee8c0ad3
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
121 additions
and
14 deletions
+121
-14
scaffold.dart
packages/flutter/lib/src/material/scaffold.dart
+29
-14
snack_bar_test.dart
packages/unit/test/widget/snack_bar_test.dart
+92
-0
No files found.
packages/flutter/lib/src/material/scaffold.dart
View file @
ffb95f05
...
...
@@ -102,20 +102,31 @@ class ScaffoldState extends State<Scaffold> {
// SNACKBAR API
Queue
<
S
nackBar
>
_snackBars
=
new
Queue
<
SnackBar
>();
Queue
<
S
caffoldFeatureController
<
SnackBar
>>
_snackBars
=
new
Queue
<
ScaffoldFeatureController
<
SnackBar
>
>();
Performance
_snackBarPerformance
;
Timer
_snackBarTimer
;
void
showSnackBar
(
SnackBar
snackbar
)
{
ScaffoldFeatureController
showSnackBar
(
SnackBar
snackbar
)
{
_snackBarPerformance
??=
SnackBar
.
createPerformance
()
..
addStatusListener
(
_handleSnackBarStatusChange
);
if
(
_snackBars
.
isEmpty
)
{
assert
(
_snackBarPerformance
.
isDismissed
);
_snackBarPerformance
.
forward
();
}
ScaffoldFeatureController
<
SnackBar
>
controller
;
controller
=
new
ScaffoldFeatureController
<
SnackBar
>.
_
(
snackbar
.
withPerformance
(
_snackBarPerformance
),
new
Completer
(),
()
{
assert
(
_snackBars
.
first
==
controller
);
_hideSnackBar
();
},
null
// SnackBar doesn't use a builder function so setState() wouldn't rebuild it
);
setState
(()
{
_snackBars
.
addLast
(
snackbar
.
withPerformance
(
_snackBarPerformance
)
);
_snackBars
.
addLast
(
controller
);
});
return
controller
;
}
void
_handleSnackBarStatusChange
(
PerformanceStatus
status
)
{
...
...
@@ -141,6 +152,9 @@ class ScaffoldState extends State<Scaffold> {
}
void
_hideSnackBar
()
{
assert
(
_snackBarPerformance
.
status
==
PerformanceStatus
.
forward
||
_snackBarPerformance
.
status
==
PerformanceStatus
.
completed
);
_snackBars
.
first
.
_completer
.
complete
();
_snackBarPerformance
.
reverse
();
_snackBarTimer
=
null
;
}
...
...
@@ -149,9 +163,9 @@ class ScaffoldState extends State<Scaffold> {
// PERSISTENT BOTTOM SHEET API
List
<
Widget
>
_dismissedBottomSheets
;
BottomSheet
Controller
_currentBottomSheet
;
ScaffoldFeature
Controller
_currentBottomSheet
;
BottomSheet
Controller
showBottomSheet
(
WidgetBuilder
builder
)
{
ScaffoldFeature
Controller
showBottomSheet
(
WidgetBuilder
builder
)
{
if
(
_currentBottomSheet
!=
null
)
{
_currentBottomSheet
.
close
();
assert
(
_currentBottomSheet
==
null
);
...
...
@@ -189,9 +203,9 @@ class ScaffoldState extends State<Scaffold> {
);
Navigator
.
of
(
context
).
push
(
route
);
setState
(()
{
_currentBottomSheet
=
new
BottomSheet
Controller
.
_
(
_currentBottomSheet
=
new
ScaffoldFeature
Controller
.
_
(
bottomSheet
,
completer
.
future
,
completer
,
()
=>
Navigator
.
of
(
context
).
remove
(
route
),
setState
);
...
...
@@ -223,7 +237,7 @@ class ScaffoldState extends State<Scaffold> {
ModalRoute
route
=
ModalRoute
.
of
(
context
);
if
(
route
==
null
||
route
.
isCurrent
)
{
if
(
_snackBarPerformance
.
isCompleted
&&
_snackBarTimer
==
null
)
_snackBarTimer
=
new
Timer
(
_snackBars
.
first
.
duration
,
_hideSnackBar
);
_snackBarTimer
=
new
Timer
(
_snackBars
.
first
.
_widget
.
duration
,
_hideSnackBar
);
}
else
{
_snackBarTimer
?.
cancel
();
_snackBarTimer
=
null
;
...
...
@@ -249,7 +263,7 @@ class ScaffoldState extends State<Scaffold> {
}
if
(
_snackBars
.
isNotEmpty
)
_addIfNonNull
(
children
,
_snackBars
.
first
,
_Child
.
snackBar
);
_addIfNonNull
(
children
,
_snackBars
.
first
.
_widget
,
_Child
.
snackBar
);
_addIfNonNull
(
children
,
config
.
floatingActionButton
,
_Child
.
floatingActionButton
);
...
...
@@ -258,11 +272,12 @@ class ScaffoldState extends State<Scaffold> {
}
class
BottomSheetController
{
const
BottomSheetController
.
_
(
this
.
_widget
,
this
.
closed
,
this
.
close
,
this
.
setState
);
final
Widget
_widget
;
final
Future
closed
;
final
VoidCallback
close
;
// call this to close the bottom sheet
class
ScaffoldFeatureController
<
T
extends
Widget
>
{
const
ScaffoldFeatureController
.
_
(
this
.
_widget
,
this
.
_completer
,
this
.
close
,
this
.
setState
);
final
T
_widget
;
final
Completer
_completer
;
Future
get
closed
=>
_completer
.
future
;
final
VoidCallback
close
;
// call this to close the bottom sheet or snack bar
final
StateSetter
setState
;
}
...
...
packages/unit/test/widget/snack_bar_test.dart
View file @
ffb95f05
...
...
@@ -145,4 +145,96 @@ void main() {
expect
(
tester
.
findText
(
'bar2'
),
isNull
);
});
});
test
(
'SnackBar cancel test'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
int
snackBarCount
=
0
;
Key
tapTarget
=
new
Key
(
'tap-target'
);
int
time
;
ScaffoldFeatureController
<
SnackBar
>
lastController
;
tester
.
pumpWidget
(
new
MaterialApp
(
routes:
<
String
,
RouteBuilder
>{
'/'
:
(
RouteArguments
args
)
{
return
new
Scaffold
(
body:
new
Builder
(
builder:
(
BuildContext
context
)
{
return
new
GestureDetector
(
onTap:
()
{
snackBarCount
+=
1
;
lastController
=
Scaffold
.
of
(
context
).
showSnackBar
(
new
SnackBar
(
content:
new
Text
(
"bar
$snackBarCount
"
),
duration:
new
Duration
(
seconds:
time
)
));
},
behavior:
HitTestBehavior
.
opaque
,
child:
new
Container
(
height:
100.0
,
width:
100.0
,
key:
tapTarget
)
);
}
)
);
}
}
));
expect
(
tester
.
findText
(
'bar1'
),
isNull
);
expect
(
tester
.
findText
(
'bar2'
),
isNull
);
time
=
1000
;
tester
.
tap
(
tester
.
findElementByKey
(
tapTarget
));
// queue bar1
ScaffoldFeatureController
<
SnackBar
>
firstController
=
lastController
;
time
=
2
;
tester
.
tap
(
tester
.
findElementByKey
(
tapTarget
));
// queue bar2
expect
(
tester
.
findText
(
'bar1'
),
isNull
);
expect
(
tester
.
findText
(
'bar2'
),
isNull
);
tester
.
pump
();
// schedule animation for bar1
expect
(
tester
.
findText
(
'bar1'
),
isNotNull
);
expect
(
tester
.
findText
(
'bar2'
),
isNull
);
tester
.
pump
();
// begin animation
expect
(
tester
.
findText
(
'bar1'
),
isNotNull
);
expect
(
tester
.
findText
(
'bar2'
),
isNull
);
tester
.
pump
(
new
Duration
(
milliseconds:
750
));
// 0.75s // animation last frame; two second timer starts here
expect
(
tester
.
findText
(
'bar1'
),
isNotNull
);
expect
(
tester
.
findText
(
'bar2'
),
isNull
);
tester
.
pump
(
new
Duration
(
milliseconds:
750
));
// 1.50s
expect
(
tester
.
findText
(
'bar1'
),
isNotNull
);
expect
(
tester
.
findText
(
'bar2'
),
isNull
);
tester
.
pump
(
new
Duration
(
milliseconds:
750
));
// 2.25s
expect
(
tester
.
findText
(
'bar1'
),
isNotNull
);
expect
(
tester
.
findText
(
'bar2'
),
isNull
);
tester
.
pump
(
new
Duration
(
milliseconds:
10000
));
// 12.25s
expect
(
tester
.
findText
(
'bar1'
),
isNotNull
);
expect
(
tester
.
findText
(
'bar2'
),
isNull
);
firstController
.
close
();
// snackbar is manually dismissed
tester
.
pump
(
new
Duration
(
milliseconds:
750
));
// 13.00s // reverse animation is scheduled
tester
.
pump
();
// begin animation
expect
(
tester
.
findText
(
'bar1'
),
isNotNull
);
expect
(
tester
.
findText
(
'bar2'
),
isNull
);
tester
.
pump
(
new
Duration
(
milliseconds:
750
));
// 13.75s // last frame of animation, snackbar removed from build, new snack bar put in its place
expect
(
tester
.
findText
(
'bar1'
),
isNull
);
expect
(
tester
.
findText
(
'bar2'
),
isNotNull
);
tester
.
pump
();
// begin animation
expect
(
tester
.
findText
(
'bar1'
),
isNull
);
expect
(
tester
.
findText
(
'bar2'
),
isNotNull
);
tester
.
pump
(
new
Duration
(
milliseconds:
750
));
// 14.50s // animation last frame; two second timer starts here
expect
(
tester
.
findText
(
'bar1'
),
isNull
);
expect
(
tester
.
findText
(
'bar2'
),
isNotNull
);
tester
.
pump
(
new
Duration
(
milliseconds:
750
));
// 15.25s
expect
(
tester
.
findText
(
'bar1'
),
isNull
);
expect
(
tester
.
findText
(
'bar2'
),
isNotNull
);
tester
.
pump
(
new
Duration
(
milliseconds:
750
));
// 16.00s
expect
(
tester
.
findText
(
'bar1'
),
isNull
);
expect
(
tester
.
findText
(
'bar2'
),
isNotNull
);
tester
.
pump
(
new
Duration
(
milliseconds:
750
));
// 16.75s // timer triggers to dismiss snackbar, reverse animation is scheduled
tester
.
pump
();
// begin animation
expect
(
tester
.
findText
(
'bar1'
),
isNull
);
expect
(
tester
.
findText
(
'bar2'
),
isNotNull
);
tester
.
pump
(
new
Duration
(
milliseconds:
750
));
// 17.50s // last frame of animation, snackbar removed from build, new snack bar put in its place
expect
(
tester
.
findText
(
'bar1'
),
isNull
);
expect
(
tester
.
findText
(
'bar2'
),
isNull
);
});
});
}
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