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
f9fd71bc
Unverified
Commit
f9fd71bc
authored
Aug 08, 2020
by
chunhtai
Committed by
GitHub
Aug 08, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement Router widget and widgets app api (#60299)
parent
12b8d9db
Changes
16
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
2997 additions
and
187 deletions
+2997
-187
app.dart
packages/flutter/lib/src/cupertino/app.dart
+139
-47
app.dart
packages/flutter/lib/src/material/app.dart
+178
-74
system_channels.dart
packages/flutter/lib/src/services/system_channels.dart
+9
-7
system_navigator.dart
packages/flutter/lib/src/services/system_navigator.dart
+33
-0
app.dart
packages/flutter/lib/src/widgets/app.dart
+182
-14
binding.dart
packages/flutter/lib/src/widgets/binding.dart
+34
-1
navigator.dart
packages/flutter/lib/src/widgets/navigator.dart
+4
-3
route_notification_messages.dart
.../flutter/lib/src/widgets/route_notification_messages.dart
+0
-41
router.dart
packages/flutter/lib/src/widgets/router.dart
+1248
-0
widgets.dart
packages/flutter/lib/widgets.dart
+1
-0
app_test.dart
packages/flutter/test/cupertino/app_test.dart
+99
-0
app_test.dart
packages/flutter/test/material/app_test.dart
+99
-0
app_test.dart
packages/flutter/test/widgets/app_test.dart
+112
-0
binding_test.dart
packages/flutter/test/widgets/binding_test.dart
+42
-0
route_notification_messages_test.dart
...lutter/test/widgets/route_notification_messages_test.dart
+112
-0
router_test.dart
packages/flutter/test/widgets/router_test.dart
+705
-0
No files found.
packages/flutter/lib/src/cupertino/app.dart
View file @
f9fd71bc
...
...
@@ -104,6 +104,50 @@ class CupertinoApp extends StatefulWidget {
assert
(
checkerboardOffscreenLayers
!=
null
),
assert
(
showSemanticsDebugger
!=
null
),
assert
(
debugShowCheckedModeBanner
!=
null
),
routeInformationProvider
=
null
,
routeInformationParser
=
null
,
routerDelegate
=
null
,
backButtonDispatcher
=
null
,
super
(
key:
key
);
/// Creates a [CupertinoApp] that uses the [Router] instead of a [Navigator].
const
CupertinoApp
.
router
({
Key
key
,
this
.
routeInformationProvider
,
@required
this
.
routeInformationParser
,
@required
this
.
routerDelegate
,
this
.
backButtonDispatcher
,
this
.
theme
,
this
.
builder
,
this
.
title
=
''
,
this
.
onGenerateTitle
,
this
.
color
,
this
.
locale
,
this
.
localizationsDelegates
,
this
.
localeListResolutionCallback
,
this
.
localeResolutionCallback
,
this
.
supportedLocales
=
const
<
Locale
>[
Locale
(
'en'
,
'US'
)],
this
.
showPerformanceOverlay
=
false
,
this
.
checkerboardRasterCacheImages
=
false
,
this
.
checkerboardOffscreenLayers
=
false
,
this
.
showSemanticsDebugger
=
false
,
this
.
debugShowCheckedModeBanner
=
true
,
this
.
shortcuts
,
this
.
actions
,
})
:
assert
(
title
!=
null
),
assert
(
showPerformanceOverlay
!=
null
),
assert
(
checkerboardRasterCacheImages
!=
null
),
assert
(
checkerboardOffscreenLayers
!=
null
),
assert
(
showSemanticsDebugger
!=
null
),
assert
(
debugShowCheckedModeBanner
!=
null
),
navigatorObservers
=
null
,
navigatorKey
=
null
,
onGenerateRoute
=
null
,
home
=
null
,
onGenerateInitialRoutes
=
null
,
onUnknownRoute
=
null
,
routes
=
null
,
initialRoute
=
null
,
super
(
key:
key
);
/// {@macro flutter.widgets.widgetsApp.navigatorKey}
...
...
@@ -143,6 +187,18 @@ class CupertinoApp extends StatefulWidget {
/// {@macro flutter.widgets.widgetsApp.navigatorObservers}
final
List
<
NavigatorObserver
>
navigatorObservers
;
/// {@macro flutter.widgets.widgetsApp.routeInformationProvider}
final
RouteInformationProvider
routeInformationProvider
;
/// {@macro flutter.widgets.widgetsApp.routeInformationParser}
final
RouteInformationParser
<
Object
>
routeInformationParser
;
/// {@macro flutter.widgets.widgetsApp.routerDelegate}
final
RouterDelegate
<
Object
>
routerDelegate
;
/// {@macro flutter.widgets.widgetsApp.backButtonDispatcher}
final
BackButtonDispatcher
backButtonDispatcher
;
/// {@macro flutter.widgets.widgetsApp.builder}
final
TransitionBuilder
builder
;
...
...
@@ -286,6 +342,7 @@ class _AlwaysCupertinoScrollBehavior extends ScrollBehavior {
class
_CupertinoAppState
extends
State
<
CupertinoApp
>
{
HeroController
_heroController
;
bool
get
_usesRouter
=>
widget
.
routerDelegate
!=
null
;
@override
void
initState
()
{
...
...
@@ -304,26 +361,56 @@ class _CupertinoAppState extends State<CupertinoApp> {
yield
DefaultCupertinoLocalizations
.
delegate
;
}
@override
Widget
build
(
BuildContext
context
)
{
final
CupertinoThemeData
effectiveThemeData
=
widget
.
theme
??
const
CupertinoThemeData
();
Widget
_inspectorSelectButtonBuilder
(
BuildContext
context
,
VoidCallback
onPressed
)
{
return
CupertinoButton
.
filled
(
child:
const
Icon
(
CupertinoIcons
.
search
,
size:
28.0
,
color:
CupertinoColors
.
white
,
),
padding:
EdgeInsets
.
zero
,
onPressed:
onPressed
,
);
}
return
ScrollConfiguration
(
behavior:
_AlwaysCupertinoScrollBehavior
(),
child:
CupertinoUserInterfaceLevel
(
data:
CupertinoUserInterfaceLevelData
.
base
,
child:
CupertinoTheme
(
data:
effectiveThemeData
,
child:
Builder
(
builder:
(
BuildContext
context
)
{
return
HeroControllerScope
(
controller:
_heroController
,
child:
WidgetsApp
(
WidgetsApp
_buildWidgetApp
(
BuildContext
context
)
{
final
CupertinoThemeData
effectiveThemeData
=
CupertinoTheme
.
of
(
context
);
final
Color
color
=
CupertinoDynamicColor
.
resolve
(
widget
.
color
??
effectiveThemeData
.
primaryColor
,
context
);
if
(
_usesRouter
)
{
return
WidgetsApp
.
router
(
key:
GlobalObjectKey
(
this
),
routeInformationProvider:
widget
.
routeInformationProvider
,
routeInformationParser:
widget
.
routeInformationParser
,
routerDelegate:
widget
.
routerDelegate
,
backButtonDispatcher:
widget
.
backButtonDispatcher
,
builder:
widget
.
builder
,
title:
widget
.
title
,
onGenerateTitle:
widget
.
onGenerateTitle
,
textStyle:
effectiveThemeData
.
textTheme
.
textStyle
,
color:
color
,
locale:
widget
.
locale
,
localizationsDelegates:
_localizationsDelegates
,
localeResolutionCallback:
widget
.
localeResolutionCallback
,
localeListResolutionCallback:
widget
.
localeListResolutionCallback
,
supportedLocales:
widget
.
supportedLocales
,
showPerformanceOverlay:
widget
.
showPerformanceOverlay
,
checkerboardRasterCacheImages:
widget
.
checkerboardRasterCacheImages
,
checkerboardOffscreenLayers:
widget
.
checkerboardOffscreenLayers
,
showSemanticsDebugger:
widget
.
showSemanticsDebugger
,
debugShowCheckedModeBanner:
widget
.
debugShowCheckedModeBanner
,
inspectorSelectButtonBuilder:
_inspectorSelectButtonBuilder
,
shortcuts:
widget
.
shortcuts
,
actions:
widget
.
actions
,
);
}
return
WidgetsApp
(
key:
GlobalObjectKey
(
this
),
navigatorKey:
widget
.
navigatorKey
,
navigatorObservers:
widget
.
navigatorObservers
,
pageRouteBuilder:
<
T
>(
RouteSettings
settings
,
WidgetBuilder
builder
)
=>
CupertinoPageRoute
<
T
>(
settings:
settings
,
builder:
builder
),
pageRouteBuilder:
<
T
>(
RouteSettings
settings
,
WidgetBuilder
builder
)
{
return
CupertinoPageRoute
<
T
>(
settings:
settings
,
builder:
builder
);
},
home:
widget
.
home
,
routes:
widget
.
routes
,
initialRoute:
widget
.
initialRoute
,
...
...
@@ -333,8 +420,8 @@ class _CupertinoAppState extends State<CupertinoApp> {
builder:
widget
.
builder
,
title:
widget
.
title
,
onGenerateTitle:
widget
.
onGenerateTitle
,
textStyle:
CupertinoTheme
.
of
(
context
)
.
textTheme
.
textStyle
,
color:
CupertinoDynamicColor
.
resolve
(
widget
.
color
??
effectiveThemeData
.
primaryColor
,
context
)
,
textStyle:
effectiveThemeData
.
textTheme
.
textStyle
,
color:
color
,
locale:
widget
.
locale
,
localizationsDelegates:
_localizationsDelegates
,
localeResolutionCallback:
widget
.
localeResolutionCallback
,
...
...
@@ -345,22 +432,27 @@ class _CupertinoAppState extends State<CupertinoApp> {
checkerboardOffscreenLayers:
widget
.
checkerboardOffscreenLayers
,
showSemanticsDebugger:
widget
.
showSemanticsDebugger
,
debugShowCheckedModeBanner:
widget
.
debugShowCheckedModeBanner
,
inspectorSelectButtonBuilder:
(
BuildContext
context
,
VoidCallback
onPressed
)
{
return
CupertinoButton
.
filled
(
child:
const
Icon
(
CupertinoIcons
.
search
,
size:
28.0
,
color:
CupertinoColors
.
white
,
),
padding:
EdgeInsets
.
zero
,
onPressed:
onPressed
,
);
},
inspectorSelectButtonBuilder:
_inspectorSelectButtonBuilder
,
shortcuts:
widget
.
shortcuts
,
actions:
widget
.
actions
,
),
);
},
}
@override
Widget
build
(
BuildContext
context
)
{
final
CupertinoThemeData
effectiveThemeData
=
widget
.
theme
??
const
CupertinoThemeData
();
return
ScrollConfiguration
(
behavior:
_AlwaysCupertinoScrollBehavior
(),
child:
CupertinoUserInterfaceLevel
(
data:
CupertinoUserInterfaceLevelData
.
base
,
child:
CupertinoTheme
(
data:
effectiveThemeData
,
child:
HeroControllerScope
(
controller:
_heroController
,
child:
Builder
(
builder:
_buildWidgetApp
,
),
),
),
),
...
...
packages/flutter/lib/src/material/app.dart
View file @
f9fd71bc
...
...
@@ -7,6 +7,7 @@
import
'dart:ui'
as
ui
;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
...
...
@@ -205,6 +206,58 @@ class MaterialApp extends StatefulWidget {
assert
(
checkerboardOffscreenLayers
!=
null
),
assert
(
showSemanticsDebugger
!=
null
),
assert
(
debugShowCheckedModeBanner
!=
null
),
routeInformationProvider
=
null
,
routeInformationParser
=
null
,
routerDelegate
=
null
,
backButtonDispatcher
=
null
,
super
(
key:
key
);
/// Creates a [MaterialApp] that uses the [Router] instead of a [Navigator].
const
MaterialApp
.
router
({
Key
key
,
this
.
routeInformationProvider
,
@required
this
.
routeInformationParser
,
@required
this
.
routerDelegate
,
this
.
backButtonDispatcher
,
this
.
builder
,
this
.
title
=
''
,
this
.
onGenerateTitle
,
this
.
color
,
this
.
theme
,
this
.
darkTheme
,
this
.
highContrastTheme
,
this
.
highContrastDarkTheme
,
this
.
themeMode
=
ThemeMode
.
system
,
this
.
locale
,
this
.
localizationsDelegates
,
this
.
localeListResolutionCallback
,
this
.
localeResolutionCallback
,
this
.
supportedLocales
=
const
<
Locale
>[
Locale
(
'en'
,
'US'
)],
this
.
debugShowMaterialGrid
=
false
,
this
.
showPerformanceOverlay
=
false
,
this
.
checkerboardRasterCacheImages
=
false
,
this
.
checkerboardOffscreenLayers
=
false
,
this
.
showSemanticsDebugger
=
false
,
this
.
debugShowCheckedModeBanner
=
true
,
this
.
shortcuts
,
this
.
actions
,
})
:
assert
(
routeInformationParser
!=
null
),
assert
(
routerDelegate
!=
null
),
assert
(
title
!=
null
),
assert
(
debugShowMaterialGrid
!=
null
),
assert
(
showPerformanceOverlay
!=
null
),
assert
(
checkerboardRasterCacheImages
!=
null
),
assert
(
checkerboardOffscreenLayers
!=
null
),
assert
(
showSemanticsDebugger
!=
null
),
assert
(
debugShowCheckedModeBanner
!=
null
),
navigatorObservers
=
null
,
navigatorKey
=
null
,
onGenerateRoute
=
null
,
home
=
null
,
onGenerateInitialRoutes
=
null
,
onUnknownRoute
=
null
,
routes
=
null
,
initialRoute
=
null
,
super
(
key:
key
);
/// {@macro flutter.widgets.widgetsApp.navigatorKey}
...
...
@@ -238,6 +291,18 @@ class MaterialApp extends StatefulWidget {
/// {@macro flutter.widgets.widgetsApp.navigatorObservers}
final
List
<
NavigatorObserver
>
navigatorObservers
;
/// {@macro flutter.widgets.widgetsApp.routeInformationProvider}
final
RouteInformationProvider
routeInformationProvider
;
/// {@macro flutter.widgets.widgetsApp.routeInformationParser}
final
RouteInformationParser
<
Object
>
routeInformationParser
;
/// {@macro flutter.widgets.widgetsApp.routerDelegate}
final
RouterDelegate
<
Object
>
routerDelegate
;
/// {@macro flutter.widgets.widgetsApp.backButtonDispatcher}
final
BackButtonDispatcher
backButtonDispatcher
;
/// {@macro flutter.widgets.widgetsApp.builder}
///
/// Material specific features such as [showDialog] and [showMenu], and widgets
...
...
@@ -611,6 +676,8 @@ class _MaterialScrollBehavior extends ScrollBehavior {
class
_MaterialAppState
extends
State
<
MaterialApp
>
{
HeroController
_heroController
;
bool
get
_usesRouter
=>
widget
.
routerDelegate
!=
null
;
@override
void
initState
()
{
super
.
initState
();
...
...
@@ -629,24 +696,15 @@ class _MaterialAppState extends State<MaterialApp> {
yield
DefaultCupertinoLocalizations
.
delegate
;
}
@override
Widget
build
(
BuildContext
context
)
{
Widget
result
=
HeroControllerScope
(
controller:
_heroController
,
child:
WidgetsApp
(
key:
GlobalObjectKey
(
this
),
navigatorKey:
widget
.
navigatorKey
,
navigatorObservers:
widget
.
navigatorObservers
,
pageRouteBuilder:
<
T
>(
RouteSettings
settings
,
WidgetBuilder
builder
)
{
return
MaterialPageRoute
<
T
>(
settings:
settings
,
builder:
builder
);
},
home:
widget
.
home
,
routes:
widget
.
routes
,
initialRoute:
widget
.
initialRoute
,
onGenerateRoute:
widget
.
onGenerateRoute
,
onGenerateInitialRoutes:
widget
.
onGenerateInitialRoutes
,
onUnknownRoute:
widget
.
onUnknownRoute
,
builder:
(
BuildContext
context
,
Widget
child
)
{
Widget
_inspectorSelectButtonBuilder
(
BuildContext
context
,
VoidCallback
onPressed
)
{
return
FloatingActionButton
(
child:
const
Icon
(
Icons
.
search
),
onPressed:
onPressed
,
mini:
true
,
);
}
Widget
_materialBuilder
(
BuildContext
context
,
Widget
child
)
{
// Resolve which theme to use based on brightness and high contrast.
final
ThemeMode
mode
=
widget
.
themeMode
??
ThemeMode
.
system
;
final
Brightness
platformBrightness
=
MediaQuery
.
platformBrightnessOf
(
context
);
...
...
@@ -686,18 +744,29 @@ class _MaterialAppState extends State<MaterialApp> {
)
:
child
,
);
},
title:
widget
.
title
,
onGenerateTitle:
widget
.
onGenerateTitle
,
textStyle:
_errorTextStyle
,
}
Widget
_buildWidgetApp
(
BuildContext
context
)
{
// The color property is always pulled from the light theme, even if dark
// mode is activated. This was done to simplify the technical details
// of switching themes and it was deemed acceptable because this color
// property is only used on old Android OSes to color the app bar in
// Android's switcher UI.
//
// blue is the primary color of the default theme
color:
widget
.
color
??
widget
.
theme
?.
primaryColor
??
Colors
.
blue
,
// blue is the primary color of the default theme.
final
Color
materialColor
=
widget
.
color
??
widget
.
theme
?.
primaryColor
??
Colors
.
blue
;
if
(
_usesRouter
)
{
return
WidgetsApp
.
router
(
key:
GlobalObjectKey
(
this
),
routeInformationProvider:
widget
.
routeInformationProvider
,
routeInformationParser:
widget
.
routeInformationParser
,
routerDelegate:
widget
.
routerDelegate
,
backButtonDispatcher:
widget
.
backButtonDispatcher
,
builder:
_materialBuilder
,
title:
widget
.
title
,
onGenerateTitle:
widget
.
onGenerateTitle
,
textStyle:
_errorTextStyle
,
color:
materialColor
,
locale:
widget
.
locale
,
localizationsDelegates:
_localizationsDelegates
,
localeResolutionCallback:
widget
.
localeResolutionCallback
,
...
...
@@ -708,17 +777,49 @@ class _MaterialAppState extends State<MaterialApp> {
checkerboardOffscreenLayers:
widget
.
checkerboardOffscreenLayers
,
showSemanticsDebugger:
widget
.
showSemanticsDebugger
,
debugShowCheckedModeBanner:
widget
.
debugShowCheckedModeBanner
,
inspectorSelectButtonBuilder:
(
BuildContext
context
,
VoidCallback
onPressed
)
{
return
FloatingActionButton
(
child:
const
Icon
(
Icons
.
search
),
onPressed:
onPressed
,
mini:
true
,
inspectorSelectButtonBuilder:
_inspectorSelectButtonBuilder
,
shortcuts:
widget
.
shortcuts
,
actions:
widget
.
actions
,
);
}
return
WidgetsApp
(
key:
GlobalObjectKey
(
this
),
navigatorKey:
widget
.
navigatorKey
,
navigatorObservers:
widget
.
navigatorObservers
,
pageRouteBuilder:
<
T
>(
RouteSettings
settings
,
WidgetBuilder
builder
)
{
return
MaterialPageRoute
<
T
>(
settings:
settings
,
builder:
builder
);
},
home:
widget
.
home
,
routes:
widget
.
routes
,
initialRoute:
widget
.
initialRoute
,
onGenerateRoute:
widget
.
onGenerateRoute
,
onGenerateInitialRoutes:
widget
.
onGenerateInitialRoutes
,
onUnknownRoute:
widget
.
onUnknownRoute
,
builder:
_materialBuilder
,
title:
widget
.
title
,
onGenerateTitle:
widget
.
onGenerateTitle
,
textStyle:
_errorTextStyle
,
color:
materialColor
,
locale:
widget
.
locale
,
localizationsDelegates:
_localizationsDelegates
,
localeResolutionCallback:
widget
.
localeResolutionCallback
,
localeListResolutionCallback:
widget
.
localeListResolutionCallback
,
supportedLocales:
widget
.
supportedLocales
,
showPerformanceOverlay:
widget
.
showPerformanceOverlay
,
checkerboardRasterCacheImages:
widget
.
checkerboardRasterCacheImages
,
checkerboardOffscreenLayers:
widget
.
checkerboardOffscreenLayers
,
showSemanticsDebugger:
widget
.
showSemanticsDebugger
,
debugShowCheckedModeBanner:
widget
.
debugShowCheckedModeBanner
,
inspectorSelectButtonBuilder:
_inspectorSelectButtonBuilder
,
shortcuts:
widget
.
shortcuts
,
actions:
widget
.
actions
,
),
);
}
@override
Widget
build
(
BuildContext
context
)
{
Widget
result
=
_buildWidgetApp
(
context
);
assert
(()
{
if
(
widget
.
debugShowMaterialGrid
)
{
...
...
@@ -735,7 +836,10 @@ class _MaterialAppState extends State<MaterialApp> {
return
ScrollConfiguration
(
behavior:
_MaterialScrollBehavior
(),
child:
HeroControllerScope
(
controller:
_heroController
,
child:
result
,
)
);
}
}
packages/flutter/lib/src/services/system_channels.dart
View file @
f9fd71bc
...
...
@@ -26,16 +26,18 @@ class SystemChannels {
/// * `pushRoute`, which is called with a single string argument when the
/// operating system instructs the application to open a particular page.
///
/// * `pushRouteInformation`, which is called with a map, which contains a
/// location string and a state object, when the operating system instructs
/// the application to open a particular page. These parameters are stored
/// under the key `location` and `state` in the map.
///
/// The following methods are used for the opposite direction data flow. The
/// framework notifies the engine about the route changes.
///
/// * `routePushed`, which is called when a route is pushed. (e.g. A modal
/// replaces the entire screen.)
///
/// * `routePopped`, which is called when a route is popped. (e.g. A dialog,
/// such as time picker is closed.)
/// * `routeUpdated`, which is called when current route has changed.
///
/// * `routeReplaced`, which is called when a route is replaced.
/// * `routeInformationUpdated`, which is called by the [Router] when the
/// application navigate to a new location.
///
/// See also:
///
...
...
@@ -46,7 +48,7 @@ class SystemChannels {
/// [Navigator.push], [Navigator.pushReplacement], [Navigator.pop] and
/// [Navigator.replace], utilize this channel's methods to send route
/// change information from framework to engine.
static
const
MethodChannel
navigation
=
MethodChannel
(
static
const
MethodChannel
navigation
=
Optional
MethodChannel
(
'flutter/navigation'
,
JSONMethodCodec
(),
);
...
...
packages/flutter/lib/src/services/system_navigator.dart
View file @
f9fd71bc
...
...
@@ -35,4 +35,37 @@ class SystemNavigator {
static
Future
<
void
>
pop
({
bool
?
animated
})
async
{
await
SystemChannels
.
platform
.
invokeMethod
<
void
>(
'SystemNavigator.pop'
,
animated
);
}
/// Notifies the platform for a route information change.
///
/// On Web, creates a new browser history entry and update URL with the route
/// information.
static
void
routeInformationUpdated
({
required
String
location
,
Object
?
state
})
{
SystemChannels
.
navigation
.
invokeMethod
<
void
>(
'routeInformationUpdated'
,
<
String
,
dynamic
>{
'location'
:
location
,
'state'
:
state
,
},
);
}
/// Notifies the platform of a route change.
///
/// On Web, updates the URL bar with the [routeName].
static
void
routeUpdated
({
String
?
routeName
,
String
?
previousRouteName
})
{
SystemChannels
.
navigation
.
invokeMethod
<
void
>(
'routeUpdated'
,
<
String
,
dynamic
>{
'previousRouteName'
:
previousRouteName
,
'routeName'
:
routeName
,
},
);
}
}
packages/flutter/lib/src/widgets/app.dart
View file @
f9fd71bc
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/binding.dart
View file @
f9fd71bc
...
...
@@ -18,6 +18,7 @@ import 'app.dart';
import
'debug.dart'
;
import
'focus_manager.dart'
;
import
'framework.dart'
;
import
'router.dart'
;
import
'widget_inspector.dart'
;
export
'dart:ui'
show
AppLifecycleState
,
Locale
;
...
...
@@ -95,7 +96,7 @@ abstract class WidgetsBindingObserver {
/// [SystemChannels.navigation].
Future
<
bool
>
didPopRoute
()
=>
Future
<
bool
>.
value
(
false
);
/// Called when the host tells the app to push a new route onto the
/// Called when the host tells the app
lication
to push a new route onto the
/// navigator.
///
/// Observers are expected to return true if they were able to
...
...
@@ -106,6 +107,22 @@ abstract class WidgetsBindingObserver {
/// [SystemChannels.navigation].
Future
<
bool
>
didPushRoute
(
String
route
)
=>
Future
<
bool
>.
value
(
false
);
/// Called when the host tells the application to push a new
/// [RouteInformation] and a restoration state onto the router.
///
/// Observers are expected to return true if they were able to
/// handle the notification. Observers are notified in registration
/// order until one returns true.
///
/// This method exposes the `pushRouteInformation` notification from
/// [SystemChannels.navigation].
///
/// The default implementation is to call the [didPushRoute] directly with the
/// [RouteInformation.location].
Future
<
bool
>
didPushRouteInformation
(
RouteInformation
routeInformation
)
{
return
didPushRoute
(
routeInformation
.
location
);
}
/// Called when the application's dimensions change. For example,
/// when a phone is rotated.
///
...
...
@@ -654,12 +671,28 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
}
}
Future
<
void
>
_handlePushRouteInformation
(
Map
<
dynamic
,
dynamic
>
routeArguments
)
async
{
for
(
final
WidgetsBindingObserver
observer
in
List
<
WidgetsBindingObserver
>.
from
(
_observers
))
{
if
(
await
observer
.
didPushRouteInformation
(
RouteInformation
(
location:
routeArguments
[
'location'
]
as
String
,
state:
routeArguments
[
'state'
]
as
Object
,
)
)
)
return
;
}
}
Future
<
dynamic
>
_handleNavigationInvocation
(
MethodCall
methodCall
)
{
switch
(
methodCall
.
method
)
{
case
'popRoute'
:
return
handlePopRoute
();
case
'pushRoute'
:
return
handlePushRoute
(
methodCall
.
arguments
as
String
);
case
'pushRouteInformation'
:
return
_handlePushRouteInformation
(
methodCall
.
arguments
as
Map
<
dynamic
,
dynamic
>);
}
return
Future
<
dynamic
>.
value
();
}
...
...
packages/flutter/lib/src/widgets/navigator.dart
View file @
f9fd71bc
...
...
@@ -21,7 +21,6 @@ import 'focus_scope.dart';
import
'framework.dart'
;
import
'heroes.dart'
;
import
'overlay.dart'
;
import
'route_notification_messages.dart'
;
import
'routes.dart'
;
import
'ticker_provider.dart'
;
...
...
@@ -3308,8 +3307,10 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin {
_RouteEntry
.
isPresentPredicate
,
orElse:
()
=>
null
);
final
String
routeName
=
lastEntry
?.
route
?.
settings
?.
name
;
if
(
routeName
!=
_lastAnnouncedRouteName
)
{
RouteNotificationMessages
.
maybeNotifyRouteChange
(
routeName
,
_lastAnnouncedRouteName
);
SystemNavigator
.
routeUpdated
(
routeName:
routeName
,
previousRouteName:
_lastAnnouncedRouteName
);
_lastAnnouncedRouteName
=
routeName
;
}
}
...
...
packages/flutter/lib/src/widgets/route_notification_messages.dart
deleted
100644 → 0
View file @
12b8d9db
// 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.
// @dart = 2.8
import
'package:flutter/foundation.dart'
;
import
'package:flutter/services.dart'
;
/// Messages for route change notifications.
class
RouteNotificationMessages
{
// This class is not meant to be instantiated or extended; this constructor
// prevents instantiation and extension.
// ignore: unused_element
RouteNotificationMessages
.
_
();
/// When the engine is Web notify the platform for a route change.
static
void
maybeNotifyRouteChange
(
String
routeName
,
String
previousRouteName
)
{
if
(
kIsWeb
)
{
_notifyRouteChange
(
routeName
,
previousRouteName
);
}
else
{
// No op.
}
}
/// Notifies the platform of a route change.
///
/// See also:
///
/// * [SystemChannels.navigation], which handles subsequent navigation
/// requests.
static
void
_notifyRouteChange
(
String
routeName
,
String
previousRouteName
)
{
SystemChannels
.
navigation
.
invokeMethod
<
void
>(
'routeUpdated'
,
<
String
,
dynamic
>{
'previousRouteName'
:
previousRouteName
,
'routeName'
:
routeName
,
},
);
}
}
packages/flutter/lib/src/widgets/router.dart
0 → 100644
View file @
f9fd71bc
This diff is collapsed.
Click to expand it.
packages/flutter/lib/widgets.dart
View file @
f9fd71bc
...
...
@@ -85,6 +85,7 @@ export 'src/widgets/primary_scroll_controller.dart';
export
'src/widgets/raw_keyboard_listener.dart'
;
export
'src/widgets/restoration.dart'
;
export
'src/widgets/restoration_properties.dart'
;
export
'src/widgets/router.dart'
;
export
'src/widgets/routes.dart'
;
export
'src/widgets/safe_area.dart'
;
export
'src/widgets/scroll_activity.dart'
;
...
...
packages/flutter/test/cupertino/app_test.dart
View file @
f9fd71bc
...
...
@@ -6,6 +6,8 @@
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/services.dart'
;
void
main
(
)
{
testWidgets
(
'Heroes work'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -147,4 +149,101 @@ void main() {
expect
(
key2
.
currentState
,
isA
<
NavigatorState
>());
expect
(
key1
.
currentState
,
isNull
);
});
testWidgets
(
'CupertinoApp.router works'
,
(
WidgetTester
tester
)
async
{
final
PlatformRouteInformationProvider
provider
=
PlatformRouteInformationProvider
(
initialRouteInformation:
const
RouteInformation
(
location:
'initial'
,
),
);
final
SimpleNavigatorRouterDelegate
delegate
=
SimpleNavigatorRouterDelegate
(
builder:
(
BuildContext
context
,
RouteInformation
information
)
{
return
Text
(
information
.
location
);
},
onPopPage:
(
Route
<
void
>
route
,
void
result
,
SimpleNavigatorRouterDelegate
delegate
)
{
delegate
.
routeInformation
=
const
RouteInformation
(
location:
'popped'
,
);
return
route
.
didPop
(
result
);
}
);
await
tester
.
pumpWidget
(
CupertinoApp
.
router
(
routeInformationProvider:
provider
,
routeInformationParser:
SimpleRouteInformationParser
(),
routerDelegate:
delegate
,
));
expect
(
find
.
text
(
'initial'
),
findsOneWidget
);
// Simulate android back button intent.
final
ByteData
message
=
const
JSONMethodCodec
().
encodeMethodCall
(
const
MethodCall
(
'popRoute'
));
await
ServicesBinding
.
instance
.
defaultBinaryMessenger
.
handlePlatformMessage
(
'flutter/navigation'
,
message
,
(
_
)
{
});
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'popped'
),
findsOneWidget
);
});
}
typedef
SimpleRouterDelegateBuilder
=
Widget
Function
(
BuildContext
,
RouteInformation
);
typedef
SimpleNavigatorRouterDelegatePopPage
<
T
>
=
bool
Function
(
Route
<
T
>
route
,
T
result
,
SimpleNavigatorRouterDelegate
delegate
);
class
SimpleRouteInformationParser
extends
RouteInformationParser
<
RouteInformation
>
{
SimpleRouteInformationParser
();
@override
Future
<
RouteInformation
>
parseRouteInformation
(
RouteInformation
information
)
{
return
SynchronousFuture
<
RouteInformation
>(
information
);
}
@override
RouteInformation
restoreRouteInformation
(
RouteInformation
configuration
)
{
return
configuration
;
}
}
class
SimpleNavigatorRouterDelegate
extends
RouterDelegate
<
RouteInformation
>
with
PopNavigatorRouterDelegateMixin
<
RouteInformation
>,
ChangeNotifier
{
SimpleNavigatorRouterDelegate
({
@required
this
.
builder
,
this
.
onPopPage
,
});
@override
GlobalKey
<
NavigatorState
>
navigatorKey
=
GlobalKey
<
NavigatorState
>();
RouteInformation
get
routeInformation
=>
_routeInformation
;
RouteInformation
_routeInformation
;
set
routeInformation
(
RouteInformation
newValue
)
{
_routeInformation
=
newValue
;
notifyListeners
();
}
SimpleRouterDelegateBuilder
builder
;
SimpleNavigatorRouterDelegatePopPage
<
void
>
onPopPage
;
@override
Future
<
void
>
setNewRoutePath
(
RouteInformation
configuration
)
{
_routeInformation
=
configuration
;
return
SynchronousFuture
<
void
>(
null
);
}
bool
_handlePopPage
(
Route
<
void
>
route
,
void
data
)
{
return
onPopPage
(
route
,
data
,
this
);
}
@override
Widget
build
(
BuildContext
context
)
{
return
Navigator
(
key:
navigatorKey
,
onPopPage:
_handlePopPage
,
pages:
<
Page
<
void
>>[
// We need at least two pages for the pop to propagate through.
// Otherwise, the navigator will bubble the pop to the system navigator.
CupertinoPage
<
void
>(
builder:
(
BuildContext
context
)
=>
const
Text
(
'base'
),
),
CupertinoPage
<
void
>(
key:
ValueKey
<
String
>(
routeInformation
?.
location
),
builder:
(
BuildContext
context
)
=>
builder
(
context
,
routeInformation
),
)
],
);
}
}
packages/flutter/test/material/app_test.dart
View file @
f9fd71bc
...
...
@@ -4,7 +4,9 @@
// @dart = 2.8
import
'package:flutter/foundation.dart'
;
import
'package:flutter/semantics.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/material.dart'
;
...
...
@@ -947,6 +949,37 @@ void main() {
expect
(
key2
.
currentState
,
isA
<
NavigatorState
>());
expect
(
key1
.
currentState
,
isNull
);
});
testWidgets
(
'MaterialApp.router works'
,
(
WidgetTester
tester
)
async
{
final
PlatformRouteInformationProvider
provider
=
PlatformRouteInformationProvider
(
initialRouteInformation:
const
RouteInformation
(
location:
'initial'
,
),
);
final
SimpleNavigatorRouterDelegate
delegate
=
SimpleNavigatorRouterDelegate
(
builder:
(
BuildContext
context
,
RouteInformation
information
)
{
return
Text
(
information
.
location
);
},
onPopPage:
(
Route
<
void
>
route
,
void
result
,
SimpleNavigatorRouterDelegate
delegate
)
{
delegate
.
routeInformation
=
const
RouteInformation
(
location:
'popped'
,
);
return
route
.
didPop
(
result
);
}
);
await
tester
.
pumpWidget
(
MaterialApp
.
router
(
routeInformationProvider:
provider
,
routeInformationParser:
SimpleRouteInformationParser
(),
routerDelegate:
delegate
,
));
expect
(
find
.
text
(
'initial'
),
findsOneWidget
);
// Simulate android back button intent.
final
ByteData
message
=
const
JSONMethodCodec
().
encodeMethodCall
(
const
MethodCall
(
'popRoute'
));
await
ServicesBinding
.
instance
.
defaultBinaryMessenger
.
handlePlatformMessage
(
'flutter/navigation'
,
message
,
(
_
)
{
});
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'popped'
),
findsOneWidget
);
});
}
class
MockAccessibilityFeature
implements
AccessibilityFeatures
{
...
...
@@ -968,3 +1001,69 @@ class MockAccessibilityFeature implements AccessibilityFeatures {
@override
bool
get
reduceMotion
=>
true
;
}
typedef
SimpleRouterDelegateBuilder
=
Widget
Function
(
BuildContext
,
RouteInformation
);
typedef
SimpleNavigatorRouterDelegatePopPage
<
T
>
=
bool
Function
(
Route
<
T
>
route
,
T
result
,
SimpleNavigatorRouterDelegate
delegate
);
class
SimpleRouteInformationParser
extends
RouteInformationParser
<
RouteInformation
>
{
SimpleRouteInformationParser
();
@override
Future
<
RouteInformation
>
parseRouteInformation
(
RouteInformation
information
)
{
return
SynchronousFuture
<
RouteInformation
>(
information
);
}
@override
RouteInformation
restoreRouteInformation
(
RouteInformation
configuration
)
{
return
configuration
;
}
}
class
SimpleNavigatorRouterDelegate
extends
RouterDelegate
<
RouteInformation
>
with
PopNavigatorRouterDelegateMixin
<
RouteInformation
>,
ChangeNotifier
{
SimpleNavigatorRouterDelegate
({
@required
this
.
builder
,
this
.
onPopPage
,
});
@override
GlobalKey
<
NavigatorState
>
navigatorKey
=
GlobalKey
<
NavigatorState
>();
RouteInformation
get
routeInformation
=>
_routeInformation
;
RouteInformation
_routeInformation
;
set
routeInformation
(
RouteInformation
newValue
)
{
_routeInformation
=
newValue
;
notifyListeners
();
}
SimpleRouterDelegateBuilder
builder
;
SimpleNavigatorRouterDelegatePopPage
<
void
>
onPopPage
;
@override
Future
<
void
>
setNewRoutePath
(
RouteInformation
configuration
)
{
_routeInformation
=
configuration
;
return
SynchronousFuture
<
void
>(
null
);
}
bool
_handlePopPage
(
Route
<
void
>
route
,
void
data
)
{
return
onPopPage
(
route
,
data
,
this
);
}
@override
Widget
build
(
BuildContext
context
)
{
return
Navigator
(
key:
navigatorKey
,
onPopPage:
_handlePopPage
,
pages:
<
Page
<
void
>>[
// We need at least two pages for the pop to propagate through.
// Otherwise, the navigator will bubble the pop to the system navigator.
MaterialPage
<
void
>(
builder:
(
BuildContext
context
)
=>
const
Text
(
'base'
),
),
MaterialPage
<
void
>(
key:
ValueKey
<
String
>(
routeInformation
?.
location
),
builder:
(
BuildContext
context
)
=>
builder
(
context
,
routeInformation
),
)
],
);
}
}
packages/flutter/test/widgets/app_test.dart
View file @
f9fd71bc
...
...
@@ -264,4 +264,116 @@ void main() {
expect
(
find
.
text
(
'non-regular page one'
),
findsOneWidget
);
expect
(
find
.
text
(
'regular page'
),
findsNothing
);
});
testWidgets
(
'WidgetsApp.router works'
,
(
WidgetTester
tester
)
async
{
final
PlatformRouteInformationProvider
provider
=
PlatformRouteInformationProvider
(
initialRouteInformation:
const
RouteInformation
(
location:
'initial'
,
),
);
final
SimpleNavigatorRouterDelegate
delegate
=
SimpleNavigatorRouterDelegate
(
builder:
(
BuildContext
context
,
RouteInformation
information
)
{
return
Text
(
information
.
location
);
},
onPopPage:
(
Route
<
void
>
route
,
void
result
,
SimpleNavigatorRouterDelegate
delegate
)
{
delegate
.
routeInformation
=
const
RouteInformation
(
location:
'popped'
,
);
return
route
.
didPop
(
result
);
}
);
await
tester
.
pumpWidget
(
WidgetsApp
.
router
(
routeInformationProvider:
provider
,
routeInformationParser:
SimpleRouteInformationParser
(),
routerDelegate:
delegate
,
color:
const
Color
(
0xFF123456
),
));
expect
(
find
.
text
(
'initial'
),
findsOneWidget
);
// Simulate android back button intent.
final
ByteData
message
=
const
JSONMethodCodec
().
encodeMethodCall
(
const
MethodCall
(
'popRoute'
));
await
ServicesBinding
.
instance
.
defaultBinaryMessenger
.
handlePlatformMessage
(
'flutter/navigation'
,
message
,
(
_
)
{
});
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'popped'
),
findsOneWidget
);
});
testWidgets
(
'WidgetsApp.router has correct default'
,
(
WidgetTester
tester
)
async
{
final
SimpleNavigatorRouterDelegate
delegate
=
SimpleNavigatorRouterDelegate
(
builder:
(
BuildContext
context
,
RouteInformation
information
)
{
return
Text
(
information
.
location
);
},
);
await
tester
.
pumpWidget
(
WidgetsApp
.
router
(
routeInformationParser:
SimpleRouteInformationParser
(),
routerDelegate:
delegate
,
color:
const
Color
(
0xFF123456
),
));
expect
(
find
.
text
(
'/'
),
findsOneWidget
);
});
}
typedef
SimpleRouterDelegateBuilder
=
Widget
Function
(
BuildContext
,
RouteInformation
);
typedef
SimpleNavigatorRouterDelegatePopPage
<
T
>
=
bool
Function
(
Route
<
T
>
route
,
T
result
,
SimpleNavigatorRouterDelegate
delegate
);
class
SimpleRouteInformationParser
extends
RouteInformationParser
<
RouteInformation
>
{
SimpleRouteInformationParser
();
@override
Future
<
RouteInformation
>
parseRouteInformation
(
RouteInformation
information
)
{
return
SynchronousFuture
<
RouteInformation
>(
information
);
}
@override
RouteInformation
restoreRouteInformation
(
RouteInformation
configuration
)
{
return
configuration
;
}
}
class
SimpleNavigatorRouterDelegate
extends
RouterDelegate
<
RouteInformation
>
with
PopNavigatorRouterDelegateMixin
<
RouteInformation
>,
ChangeNotifier
{
SimpleNavigatorRouterDelegate
({
@required
this
.
builder
,
this
.
onPopPage
,
});
@override
GlobalKey
<
NavigatorState
>
navigatorKey
=
GlobalKey
<
NavigatorState
>();
RouteInformation
get
routeInformation
=>
_routeInformation
;
RouteInformation
_routeInformation
;
set
routeInformation
(
RouteInformation
newValue
)
{
_routeInformation
=
newValue
;
notifyListeners
();
}
SimpleRouterDelegateBuilder
builder
;
SimpleNavigatorRouterDelegatePopPage
<
void
>
onPopPage
;
@override
Future
<
void
>
setNewRoutePath
(
RouteInformation
configuration
)
{
_routeInformation
=
configuration
;
return
SynchronousFuture
<
void
>(
null
);
}
bool
_handlePopPage
(
Route
<
void
>
route
,
void
data
)
{
return
onPopPage
(
route
,
data
,
this
);
}
@override
Widget
build
(
BuildContext
context
)
{
return
Navigator
(
key:
navigatorKey
,
onPopPage:
_handlePopPage
,
pages:
<
Page
<
void
>>[
// We need at least two pages for the pop to propagate through.
// Otherwise, the navigator will bubble the pop to the system navigator.
MaterialPage
<
void
>(
builder:
(
BuildContext
context
)
=>
const
Text
(
'base'
),
),
MaterialPage
<
void
>(
key:
ValueKey
<
String
>(
routeInformation
?.
location
),
builder:
(
BuildContext
context
)
=>
builder
(
context
,
routeInformation
),
)
],
);
}
}
packages/flutter/test/widgets/binding_test.dart
View file @
f9fd71bc
...
...
@@ -40,6 +40,16 @@ class PushRouteObserver with WidgetsBindingObserver {
}
}
class
PushRouteInformationObserver
with
WidgetsBindingObserver
{
RouteInformation
pushedRouteInformation
;
@override
Future
<
bool
>
didPushRouteInformation
(
RouteInformation
routeInformation
)
async
{
pushedRouteInformation
=
routeInformation
;
return
true
;
}
}
void
main
(
)
{
setUp
(()
{
WidgetsFlutterBinding
.
ensureInitialized
();
...
...
@@ -90,6 +100,38 @@ void main() {
WidgetsBinding
.
instance
.
removeObserver
(
observer
);
});
testWidgets
(
'didPushRouteInformation calls didPushRoute by default'
,
(
WidgetTester
tester
)
async
{
final
PushRouteObserver
observer
=
PushRouteObserver
();
WidgetsBinding
.
instance
.
addObserver
(
observer
);
const
Map
<
String
,
dynamic
>
testRouteInformation
=
<
String
,
dynamic
>{
'location'
:
'testRouteName'
,
'state'
:
'state'
,
'restorationData'
:
<
dynamic
,
dynamic
>{
'test'
:
'config'
}
};
final
ByteData
message
=
const
JSONMethodCodec
().
encodeMethodCall
(
const
MethodCall
(
'pushRouteInformation'
,
testRouteInformation
));
await
ServicesBinding
.
instance
.
defaultBinaryMessenger
.
handlePlatformMessage
(
'flutter/navigation'
,
message
,
(
_
)
{
});
expect
(
observer
.
pushedRoute
,
'testRouteName'
);
WidgetsBinding
.
instance
.
removeObserver
(
observer
);
});
testWidgets
(
'didPushRouteInformation callback'
,
(
WidgetTester
tester
)
async
{
final
PushRouteInformationObserver
observer
=
PushRouteInformationObserver
();
WidgetsBinding
.
instance
.
addObserver
(
observer
);
const
Map
<
String
,
dynamic
>
testRouteInformation
=
<
String
,
dynamic
>{
'location'
:
'testRouteName'
,
'state'
:
'state'
,
};
final
ByteData
message
=
const
JSONMethodCodec
().
encodeMethodCall
(
const
MethodCall
(
'pushRouteInformation'
,
testRouteInformation
));
await
ServicesBinding
.
instance
.
defaultBinaryMessenger
.
handlePlatformMessage
(
'flutter/navigation'
,
message
,
(
_
)
{
});
expect
(
observer
.
pushedRouteInformation
.
location
,
'testRouteName'
);
expect
(
observer
.
pushedRouteInformation
.
state
,
'state'
);
WidgetsBinding
.
instance
.
removeObserver
(
observer
);
});
testWidgets
(
'Application lifecycle affects frame scheduling'
,
(
WidgetTester
tester
)
async
{
final
BinaryMessenger
defaultBinaryMessenger
=
ServicesBinding
.
instance
.
defaultBinaryMessenger
;
ByteData
message
;
...
...
packages/flutter/test/widgets/route_notification_messages_test.dart
View file @
f9fd71bc
...
...
@@ -36,6 +36,13 @@ class OnTapPage extends StatelessWidget {
}
}
Map
<
String
,
dynamic
>
convertRouteInformationToMap
(
RouteInformation
routeInformation
)
{
return
<
String
,
dynamic
>{
'location'
:
routeInformation
.
location
,
'state'
:
routeInformation
.
state
,
};
}
void
main
(
)
{
testWidgets
(
'Push and Pop should send platform messages'
,
(
WidgetTester
tester
)
async
{
final
Map
<
String
,
WidgetBuilder
>
routes
=
<
String
,
WidgetBuilder
>{
...
...
@@ -258,4 +265,109 @@ void main() {
}),
);
});
testWidgets
(
'PlatformRouteInformationProvider reports URL'
,
(
WidgetTester
tester
)
async
{
final
List
<
MethodCall
>
log
=
<
MethodCall
>[];
SystemChannels
.
navigation
.
setMockMethodCallHandler
((
MethodCall
methodCall
)
async
{
log
.
add
(
methodCall
);
});
final
PlatformRouteInformationProvider
provider
=
PlatformRouteInformationProvider
(
initialRouteInformation:
const
RouteInformation
(
location:
'initial'
,
),
);
final
SimpleRouterDelegate
delegate
=
SimpleRouterDelegate
(
reportConfiguration:
true
,
builder:
(
BuildContext
context
,
RouteInformation
information
)
{
return
Text
(
information
.
location
);
}
);
await
tester
.
pumpWidget
(
MaterialApp
.
router
(
routeInformationProvider:
provider
,
routeInformationParser:
SimpleRouteInformationParser
(),
routerDelegate:
delegate
,
));
expect
(
find
.
text
(
'initial'
),
findsOneWidget
);
// Triggers a router rebuild and verify the route information is reported
// to the web engine.
delegate
.
routeInformation
=
const
RouteInformation
(
location:
'update'
,
state:
'state'
,
);
await
tester
.
pump
();
expect
(
find
.
text
(
'update'
),
findsOneWidget
);
expect
(
log
,
hasLength
(
1
));
// TODO(chunhtai): check routeInformationUpdated instead once the engine
// side is done.
expect
(
log
.
last
,
isMethodCall
(
'routeInformationUpdated'
,
arguments:
<
String
,
dynamic
>{
'location'
:
'update'
,
'state'
:
'state'
,
}),
);
});
}
typedef
SimpleRouterDelegateBuilder
=
Widget
Function
(
BuildContext
,
RouteInformation
);
typedef
SimpleRouterDelegatePopRoute
=
Future
<
bool
>
Function
();
class
SimpleRouteInformationParser
extends
RouteInformationParser
<
RouteInformation
>
{
SimpleRouteInformationParser
();
@override
Future
<
RouteInformation
>
parseRouteInformation
(
RouteInformation
information
)
{
return
SynchronousFuture
<
RouteInformation
>(
information
);
}
@override
RouteInformation
restoreRouteInformation
(
RouteInformation
configuration
)
{
return
configuration
;
}
}
class
SimpleRouterDelegate
extends
RouterDelegate
<
RouteInformation
>
with
ChangeNotifier
{
SimpleRouterDelegate
({
@required
this
.
builder
,
this
.
onPopRoute
,
this
.
reportConfiguration
=
false
,
});
RouteInformation
get
routeInformation
=>
_routeInformation
;
RouteInformation
_routeInformation
;
set
routeInformation
(
RouteInformation
newValue
)
{
_routeInformation
=
newValue
;
notifyListeners
();
}
SimpleRouterDelegateBuilder
builder
;
SimpleRouterDelegatePopRoute
onPopRoute
;
final
bool
reportConfiguration
;
@override
RouteInformation
get
currentConfiguration
{
if
(
reportConfiguration
)
return
routeInformation
;
return
null
;
}
@override
Future
<
void
>
setNewRoutePath
(
RouteInformation
configuration
)
{
_routeInformation
=
configuration
;
return
SynchronousFuture
<
void
>(
null
);
}
@override
Future
<
bool
>
popRoute
()
{
if
(
onPopRoute
!=
null
)
return
onPopRoute
();
return
SynchronousFuture
<
bool
>(
true
);
}
@override
Widget
build
(
BuildContext
context
)
=>
builder
(
context
,
routeInformation
);
}
packages/flutter/test/widgets/router_test.dart
0 → 100644
View file @
f9fd71bc
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