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
058a9343
Unverified
Commit
058a9343
authored
May 20, 2021
by
Ian Hickson
Committed by
GitHub
May 20, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Migrate the navigator API to routeInformationUpdated. (#82594)
parent
b9645bfd
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
170 additions
and
77 deletions
+170
-77
system_channels.dart
packages/flutter/lib/src/services/system_channels.dart
+12
-3
system_navigator.dart
packages/flutter/lib/src/services/system_navigator.dart
+51
-8
navigator.dart
packages/flutter/lib/src/widgets/navigator.dart
+14
-6
router.dart
packages/flutter/lib/src/widgets/router.dart
+6
-0
system_navigator_test.dart
packages/flutter/test/services/system_navigator_test.dart
+41
-6
route_notification_messages_test.dart
...lutter/test/widgets/route_notification_messages_test.dart
+46
-54
No files found.
packages/flutter/lib/src/services/system_channels.dart
View file @
058a9343
...
@@ -32,10 +32,19 @@ class SystemChannels {
...
@@ -32,10 +32,19 @@ class SystemChannels {
/// The following methods are used for the opposite direction data flow. The
/// The following methods are used for the opposite direction data flow. The
/// framework notifies the engine about the route changes.
/// framework notifies the engine about the route changes.
///
///
/// * `
routeUpdated`, which is called when current route has changed
.
/// * `
selectSingleEntryHistory`, which enables a single-entry history mode
.
///
///
/// * `routeInformationUpdated`, which is called by the [Router] when the
/// * `selectMultiEntryHistory`, which enables a multiple-entry history mode.
/// application navigate to a new location.
///
/// * `routeInformationUpdated`, which is called when the application
/// navigates to a new location, and which takes two arguments, `location`
/// (a URL) and `state` (an object).
///
/// * `routeUpdated`, a deprecated API which can be called in the same
/// situations as `routeInformationUpdated` but whose arguments are
/// `routeName` (a URL) and `previousRouteName` (which is ignored).
///
/// These APIs are exposed by the [SystemNavigator] class.
///
///
/// See also:
/// See also:
///
///
...
...
packages/flutter/lib/src/services/system_navigator.dart
View file @
058a9343
...
@@ -33,15 +33,50 @@ class SystemNavigator {
...
@@ -33,15 +33,50 @@ class SystemNavigator {
await
SystemChannels
.
platform
.
invokeMethod
<
void
>(
'SystemNavigator.pop'
,
animated
);
await
SystemChannels
.
platform
.
invokeMethod
<
void
>(
'SystemNavigator.pop'
,
animated
);
}
}
/// Selects the single-entry history mode.
///
/// On web, this switches the browser history model to one that only tracks a
/// single entry, so that calling [routeInformationUpdated] replaces the
/// current entry.
///
/// Currently, this is ignored on other platforms.
///
/// See also:
///
/// * [selectMultiEntryHistory], which enables the browser history to have
/// multiple entries.
static
Future
<
void
>
selectSingleEntryHistory
()
{
return
SystemChannels
.
navigation
.
invokeMethod
<
void
>(
'selectSingleEntryHistory'
);
}
/// Selects the multiple-entry history mode.
///
/// On web, this switches the browser history model to one that tracks alll
/// updates to [routeInformationUpdated] to form a history stack. This is the
/// default.
///
/// Currently, this is ignored on other platforms.
///
/// See also:
///
/// * [selectSingleEntryHistory], which forces the history to only have one
/// entry.
static
Future
<
void
>
selectMultiEntryHistory
()
{
return
SystemChannels
.
navigation
.
invokeMethod
<
void
>(
'selectMultiEntryHistory'
);
}
/// Notifies the platform for a route information change.
/// Notifies the platform for a route information change.
///
///
/// On Web, creates a new browser history entry and update URL with the route
/// On web, creates a new browser history entry and update URL with the route
/// information.
/// information. Whether the history holds one entry or multiple entries is
static
void
routeInformationUpdated
({
/// determined by [selectSingleEntryHistory] and [selectMultiEntryHistory].
///
/// Currently, this is ignored on other platforms.
static
Future
<
void
>
routeInformationUpdated
({
required
String
location
,
required
String
location
,
Object
?
state
,
Object
?
state
,
})
{
})
{
SystemChannels
.
navigation
.
invokeMethod
<
void
>(
return
SystemChannels
.
navigation
.
invokeMethod
<
void
>(
'routeInformationUpdated'
,
'routeInformationUpdated'
,
<
String
,
dynamic
>{
<
String
,
dynamic
>{
'location'
:
location
,
'location'
:
location
,
...
@@ -50,14 +85,22 @@ class SystemNavigator {
...
@@ -50,14 +85,22 @@ class SystemNavigator {
);
);
}
}
/// Notifies the platform of a route change.
/// Notifies the platform of a route change, and selects single-entry history
/// mode.
///
/// This is equivalent to calling [selectSingleEntryHistory] and
/// [routeInformationUpdated] together.
///
///
/// On Web, updates the URL bar with the [routeName].
/// The `previousRouteName` argument is ignored.
static
void
routeUpdated
({
@Deprecated
(
'Use routeInformationUpdated instead. '
'This feature was deprecated after v2.3.0-1.0.pre.'
)
static
Future
<
void
>
routeUpdated
({
String
?
routeName
,
String
?
routeName
,
String
?
previousRouteName
,
String
?
previousRouteName
,
})
{
})
{
SystemChannels
.
navigation
.
invokeMethod
<
void
>(
return
SystemChannels
.
navigation
.
invokeMethod
<
void
>(
'routeUpdated'
,
'routeUpdated'
,
<
String
,
dynamic
>{
<
String
,
dynamic
>{
'previousRouteName'
:
previousRouteName
,
'previousRouteName'
:
previousRouteName
,
...
...
packages/flutter/lib/src/widgets/navigator.dart
View file @
058a9343
...
@@ -1624,6 +1624,13 @@ class Navigator extends StatefulWidget {
...
@@ -1624,6 +1624,13 @@ class Navigator extends StatefulWidget {
/// route update message to the engine when it detects top-most route changes.
/// route update message to the engine when it detects top-most route changes.
/// The messages are used by the web engine to update the browser URL bar.
/// The messages are used by the web engine to update the browser URL bar.
///
///
/// If the property is set to true when the [Navigator] is first created,
/// single-entry history mode is requested using
/// [SystemNavigator.selectSingleEntryHistory]. This means this property
/// should not be used at the same time as [PlatformRouteInformationProvider]
/// is used with a [Router] (including when used with [MaterialApp.router],
/// for example).
///
/// If there are multiple navigators in the widget tree, at most one of them
/// If there are multiple navigators in the widget tree, at most one of them
/// can set this property to true (typically, the top-most one created from
/// can set this property to true (typically, the top-most one created from
/// the [WidgetsApp]). Otherwise, the web engine may receive multiple route
/// the [WidgetsApp]). Otherwise, the web engine may receive multiple route
...
@@ -3397,6 +3404,10 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
...
@@ -3397,6 +3404,10 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
.
getElementForInheritedWidgetOfExactType
<
HeroControllerScope
>()
.
getElementForInheritedWidgetOfExactType
<
HeroControllerScope
>()
?.
widget
as
HeroControllerScope
?;
?.
widget
as
HeroControllerScope
?;
_updateHeroController
(
heroControllerScope
?.
controller
);
_updateHeroController
(
heroControllerScope
?.
controller
);
if
(
widget
.
reportsRouteUpdateToEngine
)
{
SystemNavigator
.
selectSingleEntryHistory
();
}
}
}
// Use [_nextPagelessRestorationScopeId] to get the next id.
// Use [_nextPagelessRestorationScopeId] to get the next id.
...
@@ -4062,17 +4073,14 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
...
@@ -4062,17 +4073,14 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
// notifications.
// notifications.
_flushRouteAnnouncement
();
_flushRouteAnnouncement
();
// Announce
s
route name changes.
// Announce route name changes.
if
(
widget
.
reportsRouteUpdateToEngine
)
{
if
(
widget
.
reportsRouteUpdateToEngine
)
{
final
_RouteEntry
?
lastEntry
=
_history
.
cast
<
_RouteEntry
?>().
lastWhere
(
final
_RouteEntry
?
lastEntry
=
_history
.
cast
<
_RouteEntry
?>().
lastWhere
(
(
_RouteEntry
?
e
)
=>
e
!=
null
&&
_RouteEntry
.
isPresentPredicate
(
e
),
orElse:
()
=>
null
,
(
_RouteEntry
?
e
)
=>
e
!=
null
&&
_RouteEntry
.
isPresentPredicate
(
e
),
orElse:
()
=>
null
,
);
);
final
String
?
routeName
=
lastEntry
?.
route
.
settings
.
name
;
final
String
?
routeName
=
lastEntry
?.
route
.
settings
.
name
;
if
(
routeName
!=
_lastAnnouncedRouteName
)
{
if
(
routeName
!=
null
&&
routeName
!=
_lastAnnouncedRouteName
)
{
SystemNavigator
.
routeUpdated
(
SystemNavigator
.
routeInformationUpdated
(
location:
routeName
);
routeName:
routeName
,
previousRouteName:
_lastAnnouncedRouteName
,
);
_lastAnnouncedRouteName
=
routeName
;
_lastAnnouncedRouteName
=
routeName
;
}
}
}
}
...
...
packages/flutter/lib/src/widgets/router.dart
View file @
058a9343
...
@@ -1318,6 +1318,11 @@ abstract class RouteInformationProvider extends ValueListenable<RouteInformation
...
@@ -1318,6 +1318,11 @@ abstract class RouteInformationProvider extends ValueListenable<RouteInformation
/// This provider also reports the new route information from the [Router] widget
/// This provider also reports the new route information from the [Router] widget
/// back to engine using message channel method, the
/// back to engine using message channel method, the
/// [SystemNavigator.routeInformationUpdated].
/// [SystemNavigator.routeInformationUpdated].
///
/// Each time [SystemNavigator.routeInformationUpdated] is called, the
/// [SystemNavigator.selectMultiEntryHistory] method is also called. This
/// overrides the initialization behavior of
/// [Navigator.reportsRouteUpdateToEngine].
class
PlatformRouteInformationProvider
extends
RouteInformationProvider
with
WidgetsBindingObserver
,
ChangeNotifier
{
class
PlatformRouteInformationProvider
extends
RouteInformationProvider
with
WidgetsBindingObserver
,
ChangeNotifier
{
/// Create a platform route information provider.
/// Create a platform route information provider.
///
///
...
@@ -1329,6 +1334,7 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid
...
@@ -1329,6 +1334,7 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid
@override
@override
void
routerReportsNewRouteInformation
(
RouteInformation
routeInformation
)
{
void
routerReportsNewRouteInformation
(
RouteInformation
routeInformation
)
{
SystemNavigator
.
selectMultiEntryHistory
();
SystemNavigator
.
routeInformationUpdated
(
SystemNavigator
.
routeInformationUpdated
(
location:
routeInformation
.
location
!,
location:
routeInformation
.
location
!,
state:
routeInformation
.
state
,
state:
routeInformation
.
state
,
...
...
packages/flutter/test/services/system_navigator_test.dart
View file @
058a9343
...
@@ -2,23 +2,58 @@
...
@@ -2,23 +2,58 @@
// Use of this source code is governed by a BSD-style license that can be
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// found in the LICENSE file.
import
'package:flutter/foundation.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
void
main
(
)
{
void
main
(
)
{
TestWidgetsFlutterBinding
.
ensureInitialized
();
TestWidgetsFlutterBinding
.
ensureInitialized
();
test
(
'System navigator control test'
,
()
async
{
final
List
<
MethodCall
>
log
=
<
MethodCall
>[];
final
List
<
MethodCall
>
log
=
<
MethodCall
>[];
Future
<
void
>
verify
(
AsyncCallback
test
,
List
<
Object
>
expectations
)
async
{
log
.
clear
();
await
test
();
expect
(
log
,
expectations
);
}
test
(
'System navigator control test - platform messages'
,
()
async
{
SystemChannels
.
platform
.
setMockMethodCallHandler
((
MethodCall
methodCall
)
async
{
SystemChannels
.
platform
.
setMockMethodCallHandler
((
MethodCall
methodCall
)
async
{
log
.
add
(
methodCall
);
log
.
add
(
methodCall
);
});
});
await
SystemNavigator
.
pop
();
await
verify
(()
=>
SystemNavigator
.
pop
(),
<
Object
>[
isMethodCall
(
'SystemNavigator.pop'
,
arguments:
null
),
]);
SystemChannels
.
platform
.
setMockMethodCallHandler
(
null
);
});
test
(
'System navigator control test - navigation messages'
,
()
async
{
SystemChannels
.
navigation
.
setMockMethodCallHandler
((
MethodCall
methodCall
)
async
{
log
.
add
(
methodCall
);
});
await
verify
(()
=>
SystemNavigator
.
selectSingleEntryHistory
(),
<
Object
>[
isMethodCall
(
'selectSingleEntryHistory'
,
arguments:
null
),
]);
await
verify
(()
=>
SystemNavigator
.
selectMultiEntryHistory
(),
<
Object
>[
isMethodCall
(
'selectMultiEntryHistory'
,
arguments:
null
),
]);
await
verify
(()
=>
SystemNavigator
.
routeInformationUpdated
(
location:
'a'
),
<
Object
>[
isMethodCall
(
'routeInformationUpdated'
,
arguments:
<
String
,
dynamic
>{
'location'
:
'a'
,
'state'
:
null
}),
]);
await
verify
(()
=>
SystemNavigator
.
routeInformationUpdated
(
location:
'a'
,
state:
true
),
<
Object
>[
isMethodCall
(
'routeInformationUpdated'
,
arguments:
<
String
,
dynamic
>{
'location'
:
'a'
,
'state'
:
true
}),
]);
await
verify
(()
=>
SystemNavigator
.
routeUpdated
(
routeName:
'a'
,
previousRouteName:
'b'
),
<
Object
>[
isMethodCall
(
'routeUpdated'
,
arguments:
<
String
,
dynamic
>{
'routeName'
:
'a'
,
'previousRouteName'
:
'b'
}),
]);
expect
(
log
,
hasLength
(
1
));
SystemChannels
.
navigation
.
setMockMethodCallHandler
(
null
);
expect
(
log
.
single
,
isMethodCall
(
'SystemNavigator.pop'
,
arguments:
null
));
});
});
}
}
packages/flutter/test/widgets/route_notification_messages_test.dart
View file @
058a9343
...
@@ -63,46 +63,46 @@ void main() {
...
@@ -63,46 +63,46 @@ void main() {
routes:
routes
,
routes:
routes
,
));
));
expect
(
log
,
hasLength
(
1
));
expect
(
log
,
<
Object
>[
expect
(
isMethodCall
(
'selectSingleEntryHistory'
,
arguments:
null
),
log
.
last
,
isMethodCall
(
'routeInformationUpdated'
,
isMethodCall
(
'routeUpdated'
,
arguments:
<
String
,
dynamic
>{
arguments:
<
String
,
dynamic
>{
'
previousRouteName'
:
null
,
'
location'
:
'/'
,
'
routeName'
:
'/'
,
'
state'
:
null
,
},
},
),
),
);
]);
log
.
clear
();
await
tester
.
tap
(
find
.
text
(
'/'
));
await
tester
.
tap
(
find
.
text
(
'/'
));
await
tester
.
pump
();
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
expect
(
log
,
hasLength
(
2
));
expect
(
log
,
hasLength
(
1
));
expect
(
expect
(
log
.
last
,
log
.
last
,
isMethodCall
(
isMethodCall
(
'routeUpdated'
,
'route
Information
Updated'
,
arguments:
<
String
,
dynamic
>{
arguments:
<
String
,
dynamic
>{
'
previousRouteName'
:
'/
'
,
'
location'
:
'/A
'
,
'
routeName'
:
'/A'
,
'
state'
:
null
,
},
},
),
),
);
);
log
.
clear
();
await
tester
.
tap
(
find
.
text
(
'A'
));
await
tester
.
tap
(
find
.
text
(
'A'
));
await
tester
.
pump
();
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
expect
(
log
,
hasLength
(
3
));
expect
(
log
,
hasLength
(
1
));
expect
(
expect
(
log
.
last
,
log
.
last
,
isMethodCall
(
isMethodCall
(
'routeUpdated'
,
'route
Information
Updated'
,
arguments:
<
String
,
dynamic
>{
arguments:
<
String
,
dynamic
>{
'
previousRouteName'
:
'/A
'
,
'
location'
:
'/
'
,
'
routeName'
:
'/'
,
'
state'
:
null
,
},
},
),
),
);
);
...
@@ -168,46 +168,46 @@ void main() {
...
@@ -168,46 +168,46 @@ void main() {
routes:
routes
,
routes:
routes
,
));
));
expect
(
log
,
hasLength
(
1
));
expect
(
log
,
<
Object
>[
expect
(
isMethodCall
(
'selectSingleEntryHistory'
,
arguments:
null
),
log
.
last
,
isMethodCall
(
'routeInformationUpdated'
,
isMethodCall
(
'routeUpdated'
,
arguments:
<
String
,
dynamic
>{
arguments:
<
String
,
dynamic
>{
'
previousRouteName'
:
null
,
'
location'
:
'/'
,
'
routeName'
:
'/'
,
'
state'
:
null
,
},
},
),
),
);
]);
log
.
clear
();
await
tester
.
tap
(
find
.
text
(
'/'
));
await
tester
.
tap
(
find
.
text
(
'/'
));
await
tester
.
pump
();
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
expect
(
log
,
hasLength
(
2
));
expect
(
log
,
hasLength
(
1
));
expect
(
expect
(
log
.
last
,
log
.
last
,
isMethodCall
(
isMethodCall
(
'routeUpdated'
,
'route
Information
Updated'
,
arguments:
<
String
,
dynamic
>{
arguments:
<
String
,
dynamic
>{
'
previousRouteName'
:
'/
'
,
'
location'
:
'/A
'
,
'
routeName'
:
'/A'
,
'
state'
:
null
,
},
},
),
),
);
);
log
.
clear
();
await
tester
.
tap
(
find
.
text
(
'A'
));
await
tester
.
tap
(
find
.
text
(
'A'
));
await
tester
.
pump
();
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
expect
(
log
,
hasLength
(
3
));
expect
(
log
,
hasLength
(
1
));
expect
(
expect
(
log
.
last
,
log
.
last
,
isMethodCall
(
isMethodCall
(
'routeUpdated'
,
'route
Information
Updated'
,
arguments:
<
String
,
dynamic
>{
arguments:
<
String
,
dynamic
>{
'
previousRouteName'
:
'/A
'
,
'
location'
:
'/B
'
,
'
routeName'
:
'/B'
,
'
state'
:
null
,
},
},
),
),
);
);
...
@@ -237,27 +237,22 @@ void main() {
...
@@ -237,27 +237,22 @@ void main() {
},
},
));
));
expect
(
log
,
hasLength
(
1
));
expect
(
log
,
<
Object
>[
expect
(
isMethodCall
(
'selectSingleEntryHistory'
,
arguments:
null
),
log
.
last
,
isMethodCall
(
'routeInformationUpdated'
,
isMethodCall
(
'routeUpdated'
,
arguments:
<
String
,
dynamic
>{
arguments:
<
String
,
dynamic
>{
'previousRouteName'
:
null
,
'location'
:
'/home'
,
'routeName'
:
'/home'
,
'state'
:
null
,
}),
},
);
),
]);
log
.
clear
();
await
tester
.
tap
(
find
.
text
(
'Home'
));
await
tester
.
tap
(
find
.
text
(
'Home'
));
await
tester
.
pump
();
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
expect
(
log
,
hasLength
(
2
));
expect
(
log
,
isEmpty
);
expect
(
log
.
last
,
isMethodCall
(
'routeUpdated'
,
arguments:
<
String
,
dynamic
>{
'previousRouteName'
:
'/home'
,
'routeName'
:
null
,
}),
);
});
});
testWidgets
(
'PlatformRouteInformationProvider reports URL'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'PlatformRouteInformationProvider reports URL'
,
(
WidgetTester
tester
)
async
{
...
@@ -294,16 +289,13 @@ void main() {
...
@@ -294,16 +289,13 @@ void main() {
await
tester
.
pump
();
await
tester
.
pump
();
expect
(
find
.
text
(
'update'
),
findsOneWidget
);
expect
(
find
.
text
(
'update'
),
findsOneWidget
);
expect
(
log
,
hasLength
(
1
));
expect
(
log
,
<
Object
>[
// TODO(chunhtai): check routeInformationUpdated instead once the engine
isMethodCall
(
'selectMultiEntryHistory'
,
arguments:
null
),
// side is done.
expect
(
log
.
last
,
isMethodCall
(
'routeInformationUpdated'
,
arguments:
<
String
,
dynamic
>{
isMethodCall
(
'routeInformationUpdated'
,
arguments:
<
String
,
dynamic
>{
'location'
:
'update'
,
'location'
:
'update'
,
'state'
:
'state'
,
'state'
:
'state'
,
}),
}),
);
]
);
});
});
}
}
...
...
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