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
c951f66f
Commit
c951f66f
authored
Nov 30, 2015
by
Ian Hickson
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #631 from Hixie/yak2-replace
Add a "replace()" API for the navigator.
parents
d293bb8c
d1253979
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
239 additions
and
1 deletion
+239
-1
navigator.dart
packages/flutter/lib/src/widgets/navigator.dart
+52
-1
overlay.dart
packages/flutter/lib/src/widgets/overlay.dart
+20
-0
routes.dart
packages/flutter/lib/src/widgets/routes.dart
+7
-0
routes_test.dart
packages/unit/test/widget/routes_test.dart
+160
-0
No files found.
packages/flutter/lib/src/widgets/navigator.dart
View file @
c951f66f
...
...
@@ -13,12 +13,21 @@ abstract class Route<T> {
List
<
OverlayEntry
>
get
overlayEntries
=>
const
<
OverlayEntry
>[];
/// Called when the route is inserted into the navigator.
/// Use this to install any overlays.
///
/// Use this to populate overlayEntries and add them to the overlay.
/// (The reason the Route is responsible for doing this, rather than the
/// Navigator, is that the Route will be responsible for _removing_ the
/// entries and this way it's symmetric.
///
/// The overlay argument will be null if this is the first route inserted.
void
install
(
OverlayState
overlay
,
OverlayEntry
insertionPoint
)
{
}
/// Called after install() when the route is pushed onto the navigator.
void
didPush
()
{
}
/// Called after install() when the route replaced another in the navigator.
void
didReplace
(
Route
oldRoute
)
{
}
/// A request was made to pop this route. If the route can handle it
/// internally (e.g. because it has its own stack of internal state) then
/// return false, otherwise return true. Returning false will prevent the
...
...
@@ -35,6 +44,10 @@ abstract class Route<T> {
/// navigator.
void
didPopNext
(
Route
nextRoute
)
{
}
/// The given old route, which was the route that came after this one, has
/// been replaced with the given new route.
void
didReplaceNext
(
Route
oldNextRoute
,
Route
newNextRoute
)
{
}
/// The route should remove its overlays and free any other resources.
///
/// A call to didPop() implies that the Route should call dispose() itself,
...
...
@@ -173,6 +186,44 @@ class NavigatorState extends State<Navigator> {
assert
(()
{
_debugLocked
=
false
;
return
true
;
});
}
/// Replaces one given route with another, but does not call didPush/didPop.
/// Instead, this calls install() on the new route, then didReplace() on the
/// new route passing the old route, then dispose() on the old route.
///
/// The old route must have overlays, otherwise we won't know where to insert
/// the overlays of the new route. The old route must not be currently visible
/// (i.e. a later route have overlays that are currently opaque), otherwise
/// the replacement would have a jarring effect.
///
/// It is safe to call this redundantly (replacing a route with itself). Such
/// calls are ignored.
void
replace
({
Route
oldRoute
,
Route
newRoute
})
{
assert
(!
_debugLocked
);
assert
(
oldRoute
!=
null
);
assert
(
newRoute
!=
null
);
if
(
oldRoute
==
newRoute
)
return
;
assert
(()
{
_debugLocked
=
true
;
return
true
;
});
assert
(
oldRoute
.
_navigator
==
this
);
assert
(
newRoute
.
_navigator
==
null
);
assert
(
oldRoute
.
overlayEntries
.
isNotEmpty
);
assert
(
newRoute
.
overlayEntries
.
isEmpty
);
assert
(!
overlay
.
debugIsVisible
(
oldRoute
.
overlayEntries
.
last
));
setState
(()
{
int
index
=
_history
.
indexOf
(
oldRoute
);
assert
(
index
>=
0
);
newRoute
.
_navigator
=
this
;
newRoute
.
install
(
overlay
,
oldRoute
.
overlayEntries
.
last
);
_history
[
index
]
=
newRoute
;
newRoute
.
didReplace
(
oldRoute
);
if
(
index
>
0
)
_history
[
index
-
1
].
didReplaceNext
(
oldRoute
,
newRoute
);
oldRoute
.
dispose
();
oldRoute
.
_navigator
=
null
;
});
assert
(()
{
_debugLocked
=
false
;
return
true
;
});
}
/// Removes the current route, notifying the observer (if any), and the
/// previous routes (using [Route.didPopNext]).
///
...
...
packages/flutter/lib/src/widgets/overlay.dart
View file @
c951f66f
...
...
@@ -83,6 +83,26 @@ class OverlayState extends State<Overlay> {
});
}
bool
debugIsVisible
(
OverlayEntry
entry
)
{
bool
result
=
false
;
assert
(
_entries
.
contains
(
entry
));
assert
(()
{
// This is an O(N) algorithm, and should not be necessary except for debug asserts.
// To avoid people depending on it, we only implement it in checked mode.
for
(
int
i
=
_entries
.
length
-
1
;
i
>
0
;
i
-=
1
)
{
OverlayEntry
candidate
=
_entries
[
i
];
if
(
candidate
==
entry
)
{
result
=
true
;
break
;
}
if
(
entry
.
opaque
)
break
;
}
return
true
;
});
return
result
;
}
Widget
build
(
BuildContext
context
)
{
List
<
Widget
>
backwardsChildren
=
<
Widget
>[];
...
...
packages/flutter/lib/src/widgets/routes.dart
View file @
c951f66f
...
...
@@ -119,6 +119,13 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
super
.
didPush
();
}
void
didReplace
(
Route
oldRoute
)
{
if
(
oldRoute
is
TransitionRoute
)
_performance
.
progress
=
oldRoute
.
_performance
.
progress
;
_performance
.
addStatusListener
(
handleStatusChanged
);
super
.
didReplace
(
oldRoute
);
}
bool
didPop
(
T
result
)
{
_result
=
result
;
_performance
.
reverse
();
...
...
packages/unit/test/widget/routes_test.dart
0 → 100644
View file @
c951f66f
// 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:flutter_test/flutter_test.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:test/test.dart'
;
final
List
<
String
>
results
=
<
String
>[];
class
TestRoute
extends
Route
<
String
>
{
TestRoute
(
this
.
name
);
final
String
name
;
List
<
OverlayEntry
>
get
overlayEntries
=>
_entries
;
List
<
OverlayEntry
>
_entries
=
<
OverlayEntry
>[];
void
log
(
String
s
)
{
results
.
add
(
'
$name
:
$s
'
);
}
void
install
(
OverlayState
overlay
,
OverlayEntry
insertionPoint
)
{
log
(
'install'
);
OverlayEntry
entry
=
new
OverlayEntry
(
builder:
(
BuildContext
context
)
=>
new
Container
(),
opaque:
true
);
_entries
.
add
(
entry
);
overlay
?.
insert
(
entry
,
above:
insertionPoint
);
}
void
didPush
()
{
log
(
'didPush'
);
}
void
didReplace
(
TestRoute
oldRoute
)
{
log
(
'didReplace
${oldRoute.name}
'
);
}
bool
didPop
(
String
result
)
{
log
(
'didPop
$result
'
);
return
super
.
didPop
(
result
);
}
void
didPushNext
(
TestRoute
nextRoute
)
{
log
(
'didPushNext
${nextRoute.name}
'
);
}
void
didPopNext
(
TestRoute
nextRoute
)
{
log
(
'didPopNext
${nextRoute.name}
'
);
}
void
didReplaceNext
(
TestRoute
oldNextRoute
,
TestRoute
newNextRoute
)
{
log
(
'didReplaceNext
${oldNextRoute.name}
${newNextRoute.name}
'
);
}
void
dispose
()
{
log
(
'dispose'
);
_entries
.
forEach
((
OverlayEntry
entry
)
{
entry
.
remove
();
});
_entries
.
clear
();
}
}
void
runNavigatorTest
(
WidgetTester
tester
,
NavigatorState
host
,
void
test
(
NavigatorState
transaction
),
List
<
String
>
expectations
)
{
expect
(
host
,
isNotNull
);
test
(
host
);
expect
(
results
,
equals
(
expectations
));
results
.
clear
();
tester
.
pump
();
}
void
main
(
)
{
test
(
'Route management'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
GlobalKey
<
NavigatorState
>
navigatorKey
=
new
GlobalKey
<
NavigatorState
>();
tester
.
pumpWidget
(
new
Navigator
(
key:
navigatorKey
,
onGenerateRoute:
(
_
)
=>
new
TestRoute
(
'initial'
)
));
NavigatorState
host
=
navigatorKey
.
currentState
;
runNavigatorTest
(
tester
,
host
,
(
NavigatorState
transaction
)
{
},
[
'initial: install'
,
'initial: didPush'
,
]
);
TestRoute
second
;
runNavigatorTest
(
tester
,
host
,
(
NavigatorState
transaction
)
{
transaction
.
push
(
second
=
new
TestRoute
(
'second'
));
},
[
'second: install'
,
'second: didPush'
,
'initial: didPushNext second'
,
]
);
runNavigatorTest
(
tester
,
host
,
(
NavigatorState
transaction
)
{
transaction
.
push
(
new
TestRoute
(
'third'
));
},
[
'third: install'
,
'third: didPush'
,
'second: didPushNext third'
,
]
);
runNavigatorTest
(
tester
,
host
,
(
NavigatorState
transaction
)
{
transaction
.
replace
(
oldRoute:
second
,
newRoute:
new
TestRoute
(
'two'
));
},
[
'two: install'
,
'two: didReplace second'
,
'initial: didReplaceNext second two'
,
'second: dispose'
,
]
);
runNavigatorTest
(
tester
,
host
,
(
NavigatorState
transaction
)
{
transaction
.
pop
(
'hello'
);
},
[
'third: didPop hello'
,
'two: didPopNext third'
,
]
);
runNavigatorTest
(
tester
,
host
,
(
NavigatorState
transaction
)
{
transaction
.
pop
(
'good bye'
);
},
[
'two: didPop good bye'
,
'initial: didPopNext two'
,
]
);
});
});
}
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