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 {
...
@@ -104,6 +104,50 @@ class CupertinoApp extends StatefulWidget {
assert
(
checkerboardOffscreenLayers
!=
null
),
assert
(
checkerboardOffscreenLayers
!=
null
),
assert
(
showSemanticsDebugger
!=
null
),
assert
(
showSemanticsDebugger
!=
null
),
assert
(
debugShowCheckedModeBanner
!=
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
);
super
(
key:
key
);
/// {@macro flutter.widgets.widgetsApp.navigatorKey}
/// {@macro flutter.widgets.widgetsApp.navigatorKey}
...
@@ -143,6 +187,18 @@ class CupertinoApp extends StatefulWidget {
...
@@ -143,6 +187,18 @@ class CupertinoApp extends StatefulWidget {
/// {@macro flutter.widgets.widgetsApp.navigatorObservers}
/// {@macro flutter.widgets.widgetsApp.navigatorObservers}
final
List
<
NavigatorObserver
>
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}
/// {@macro flutter.widgets.widgetsApp.builder}
final
TransitionBuilder
builder
;
final
TransitionBuilder
builder
;
...
@@ -286,6 +342,7 @@ class _AlwaysCupertinoScrollBehavior extends ScrollBehavior {
...
@@ -286,6 +342,7 @@ class _AlwaysCupertinoScrollBehavior extends ScrollBehavior {
class
_CupertinoAppState
extends
State
<
CupertinoApp
>
{
class
_CupertinoAppState
extends
State
<
CupertinoApp
>
{
HeroController
_heroController
;
HeroController
_heroController
;
bool
get
_usesRouter
=>
widget
.
routerDelegate
!=
null
;
@override
@override
void
initState
()
{
void
initState
()
{
...
@@ -304,26 +361,56 @@ class _CupertinoAppState extends State<CupertinoApp> {
...
@@ -304,26 +361,56 @@ class _CupertinoAppState extends State<CupertinoApp> {
yield
DefaultCupertinoLocalizations
.
delegate
;
yield
DefaultCupertinoLocalizations
.
delegate
;
}
}
@override
Widget
_inspectorSelectButtonBuilder
(
BuildContext
context
,
VoidCallback
onPressed
)
{
Widget
build
(
BuildContext
context
)
{
return
CupertinoButton
.
filled
(
final
CupertinoThemeData
effectiveThemeData
=
widget
.
theme
??
const
CupertinoThemeData
();
child:
const
Icon
(
CupertinoIcons
.
search
,
size:
28.0
,
color:
CupertinoColors
.
white
,
),
padding:
EdgeInsets
.
zero
,
onPressed:
onPressed
,
);
}
return
ScrollConfiguration
(
WidgetsApp
_buildWidgetApp
(
BuildContext
context
)
{
behavior:
_AlwaysCupertinoScrollBehavior
(),
final
CupertinoThemeData
effectiveThemeData
=
CupertinoTheme
.
of
(
context
);
child:
CupertinoUserInterfaceLevel
(
final
Color
color
=
CupertinoDynamicColor
.
resolve
(
widget
.
color
??
effectiveThemeData
.
primaryColor
,
context
);
data:
CupertinoUserInterfaceLevelData
.
base
,
child:
CupertinoTheme
(
if
(
_usesRouter
)
{
data:
effectiveThemeData
,
return
WidgetsApp
.
router
(
child:
Builder
(
key:
GlobalObjectKey
(
this
),
builder:
(
BuildContext
context
)
{
routeInformationProvider:
widget
.
routeInformationProvider
,
return
HeroControllerScope
(
routeInformationParser:
widget
.
routeInformationParser
,
controller:
_heroController
,
routerDelegate:
widget
.
routerDelegate
,
child:
WidgetsApp
(
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
),
key:
GlobalObjectKey
(
this
),
navigatorKey:
widget
.
navigatorKey
,
navigatorKey:
widget
.
navigatorKey
,
navigatorObservers:
widget
.
navigatorObservers
,
navigatorObservers:
widget
.
navigatorObservers
,
pageRouteBuilder:
<
T
>(
RouteSettings
settings
,
WidgetBuilder
builder
)
=>
pageRouteBuilder:
<
T
>(
RouteSettings
settings
,
WidgetBuilder
builder
)
{
CupertinoPageRoute
<
T
>(
settings:
settings
,
builder:
builder
),
return
CupertinoPageRoute
<
T
>(
settings:
settings
,
builder:
builder
);
},
home:
widget
.
home
,
home:
widget
.
home
,
routes:
widget
.
routes
,
routes:
widget
.
routes
,
initialRoute:
widget
.
initialRoute
,
initialRoute:
widget
.
initialRoute
,
...
@@ -333,8 +420,8 @@ class _CupertinoAppState extends State<CupertinoApp> {
...
@@ -333,8 +420,8 @@ class _CupertinoAppState extends State<CupertinoApp> {
builder:
widget
.
builder
,
builder:
widget
.
builder
,
title:
widget
.
title
,
title:
widget
.
title
,
onGenerateTitle:
widget
.
onGenerateTitle
,
onGenerateTitle:
widget
.
onGenerateTitle
,
textStyle:
CupertinoTheme
.
of
(
context
)
.
textTheme
.
textStyle
,
textStyle:
effectiveThemeData
.
textTheme
.
textStyle
,
color:
CupertinoDynamicColor
.
resolve
(
widget
.
color
??
effectiveThemeData
.
primaryColor
,
context
)
,
color:
color
,
locale:
widget
.
locale
,
locale:
widget
.
locale
,
localizationsDelegates:
_localizationsDelegates
,
localizationsDelegates:
_localizationsDelegates
,
localeResolutionCallback:
widget
.
localeResolutionCallback
,
localeResolutionCallback:
widget
.
localeResolutionCallback
,
...
@@ -345,22 +432,27 @@ class _CupertinoAppState extends State<CupertinoApp> {
...
@@ -345,22 +432,27 @@ class _CupertinoAppState extends State<CupertinoApp> {
checkerboardOffscreenLayers:
widget
.
checkerboardOffscreenLayers
,
checkerboardOffscreenLayers:
widget
.
checkerboardOffscreenLayers
,
showSemanticsDebugger:
widget
.
showSemanticsDebugger
,
showSemanticsDebugger:
widget
.
showSemanticsDebugger
,
debugShowCheckedModeBanner:
widget
.
debugShowCheckedModeBanner
,
debugShowCheckedModeBanner:
widget
.
debugShowCheckedModeBanner
,
inspectorSelectButtonBuilder:
(
BuildContext
context
,
VoidCallback
onPressed
)
{
inspectorSelectButtonBuilder:
_inspectorSelectButtonBuilder
,
return
CupertinoButton
.
filled
(
child:
const
Icon
(
CupertinoIcons
.
search
,
size:
28.0
,
color:
CupertinoColors
.
white
,
),
padding:
EdgeInsets
.
zero
,
onPressed:
onPressed
,
);
},
shortcuts:
widget
.
shortcuts
,
shortcuts:
widget
.
shortcuts
,
actions:
widget
.
actions
,
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 @@
...
@@ -7,6 +7,7 @@
import
'dart:ui'
as
ui
;
import
'dart:ui'
as
ui
;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter/widgets.dart'
;
...
@@ -205,6 +206,58 @@ class MaterialApp extends StatefulWidget {
...
@@ -205,6 +206,58 @@ class MaterialApp extends StatefulWidget {
assert
(
checkerboardOffscreenLayers
!=
null
),
assert
(
checkerboardOffscreenLayers
!=
null
),
assert
(
showSemanticsDebugger
!=
null
),
assert
(
showSemanticsDebugger
!=
null
),
assert
(
debugShowCheckedModeBanner
!=
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
);
super
(
key:
key
);
/// {@macro flutter.widgets.widgetsApp.navigatorKey}
/// {@macro flutter.widgets.widgetsApp.navigatorKey}
...
@@ -238,6 +291,18 @@ class MaterialApp extends StatefulWidget {
...
@@ -238,6 +291,18 @@ class MaterialApp extends StatefulWidget {
/// {@macro flutter.widgets.widgetsApp.navigatorObservers}
/// {@macro flutter.widgets.widgetsApp.navigatorObservers}
final
List
<
NavigatorObserver
>
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}
/// {@macro flutter.widgets.widgetsApp.builder}
///
///
/// Material specific features such as [showDialog] and [showMenu], and widgets
/// Material specific features such as [showDialog] and [showMenu], and widgets
...
@@ -611,6 +676,8 @@ class _MaterialScrollBehavior extends ScrollBehavior {
...
@@ -611,6 +676,8 @@ class _MaterialScrollBehavior extends ScrollBehavior {
class
_MaterialAppState
extends
State
<
MaterialApp
>
{
class
_MaterialAppState
extends
State
<
MaterialApp
>
{
HeroController
_heroController
;
HeroController
_heroController
;
bool
get
_usesRouter
=>
widget
.
routerDelegate
!=
null
;
@override
@override
void
initState
()
{
void
initState
()
{
super
.
initState
();
super
.
initState
();
...
@@ -629,24 +696,15 @@ class _MaterialAppState extends State<MaterialApp> {
...
@@ -629,24 +696,15 @@ class _MaterialAppState extends State<MaterialApp> {
yield
DefaultCupertinoLocalizations
.
delegate
;
yield
DefaultCupertinoLocalizations
.
delegate
;
}
}
@override
Widget
_inspectorSelectButtonBuilder
(
BuildContext
context
,
VoidCallback
onPressed
)
{
Widget
build
(
BuildContext
context
)
{
return
FloatingActionButton
(
Widget
result
=
HeroControllerScope
(
child:
const
Icon
(
Icons
.
search
),
controller:
_heroController
,
onPressed:
onPressed
,
child:
WidgetsApp
(
mini:
true
,
key:
GlobalObjectKey
(
this
),
);
navigatorKey:
widget
.
navigatorKey
,
}
navigatorObservers:
widget
.
navigatorObservers
,
pageRouteBuilder:
<
T
>(
RouteSettings
settings
,
WidgetBuilder
builder
)
{
Widget
_materialBuilder
(
BuildContext
context
,
Widget
child
)
{
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
)
{
// Resolve which theme to use based on brightness and high contrast.
// Resolve which theme to use based on brightness and high contrast.
final
ThemeMode
mode
=
widget
.
themeMode
??
ThemeMode
.
system
;
final
ThemeMode
mode
=
widget
.
themeMode
??
ThemeMode
.
system
;
final
Brightness
platformBrightness
=
MediaQuery
.
platformBrightnessOf
(
context
);
final
Brightness
platformBrightness
=
MediaQuery
.
platformBrightnessOf
(
context
);
...
@@ -686,18 +744,29 @@ class _MaterialAppState extends State<MaterialApp> {
...
@@ -686,18 +744,29 @@ class _MaterialAppState extends State<MaterialApp> {
)
)
:
child
,
:
child
,
);
);
},
}
title:
widget
.
title
,
onGenerateTitle:
widget
.
onGenerateTitle
,
Widget
_buildWidgetApp
(
BuildContext
context
)
{
textStyle:
_errorTextStyle
,
// The color property is always pulled from the light theme, even if dark
// The color property is always pulled from the light theme, even if dark
// mode is activated. This was done to simplify the technical details
// mode is activated. This was done to simplify the technical details
// of switching themes and it was deemed acceptable because this color
// 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
// property is only used on old Android OSes to color the app bar in
// Android's switcher UI.
// Android's switcher UI.
//
//
// blue is the primary color of the default theme
// blue is the primary color of the default theme.
color:
widget
.
color
??
widget
.
theme
?.
primaryColor
??
Colors
.
blue
,
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
,
locale:
widget
.
locale
,
localizationsDelegates:
_localizationsDelegates
,
localizationsDelegates:
_localizationsDelegates
,
localeResolutionCallback:
widget
.
localeResolutionCallback
,
localeResolutionCallback:
widget
.
localeResolutionCallback
,
...
@@ -708,17 +777,49 @@ class _MaterialAppState extends State<MaterialApp> {
...
@@ -708,17 +777,49 @@ class _MaterialAppState extends State<MaterialApp> {
checkerboardOffscreenLayers:
widget
.
checkerboardOffscreenLayers
,
checkerboardOffscreenLayers:
widget
.
checkerboardOffscreenLayers
,
showSemanticsDebugger:
widget
.
showSemanticsDebugger
,
showSemanticsDebugger:
widget
.
showSemanticsDebugger
,
debugShowCheckedModeBanner:
widget
.
debugShowCheckedModeBanner
,
debugShowCheckedModeBanner:
widget
.
debugShowCheckedModeBanner
,
inspectorSelectButtonBuilder:
(
BuildContext
context
,
VoidCallback
onPressed
)
{
inspectorSelectButtonBuilder:
_inspectorSelectButtonBuilder
,
return
FloatingActionButton
(
shortcuts:
widget
.
shortcuts
,
child:
const
Icon
(
Icons
.
search
),
actions:
widget
.
actions
,
onPressed:
onPressed
,
mini:
true
,
);
);
}
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
,
shortcuts:
widget
.
shortcuts
,
actions:
widget
.
actions
,
actions:
widget
.
actions
,
),
);
);
}
@override
Widget
build
(
BuildContext
context
)
{
Widget
result
=
_buildWidgetApp
(
context
);
assert
(()
{
assert
(()
{
if
(
widget
.
debugShowMaterialGrid
)
{
if
(
widget
.
debugShowMaterialGrid
)
{
...
@@ -735,7 +836,10 @@ class _MaterialAppState extends State<MaterialApp> {
...
@@ -735,7 +836,10 @@ class _MaterialAppState extends State<MaterialApp> {
return
ScrollConfiguration
(
return
ScrollConfiguration
(
behavior:
_MaterialScrollBehavior
(),
behavior:
_MaterialScrollBehavior
(),
child:
HeroControllerScope
(
controller:
_heroController
,
child:
result
,
child:
result
,
)
);
);
}
}
}
}
packages/flutter/lib/src/services/system_channels.dart
View file @
f9fd71bc
...
@@ -26,16 +26,18 @@ class SystemChannels {
...
@@ -26,16 +26,18 @@ class SystemChannels {
/// * `pushRoute`, which is called with a single string argument when the
/// * `pushRoute`, which is called with a single string argument when the
/// operating system instructs the application to open a particular page.
/// 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
/// 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.
///
///
/// * `routePushed`, which is called when a route is pushed. (e.g. A modal
/// * `routeUpdated`, which is called when current route has changed.
/// replaces the entire screen.)
///
/// * `routePopped`, which is called when a route is popped. (e.g. A dialog,
/// such as time picker is closed.)
///
///
/// * `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:
/// See also:
///
///
...
@@ -46,7 +48,7 @@ class SystemChannels {
...
@@ -46,7 +48,7 @@ class SystemChannels {
/// [Navigator.push], [Navigator.pushReplacement], [Navigator.pop] and
/// [Navigator.push], [Navigator.pushReplacement], [Navigator.pop] and
/// [Navigator.replace], utilize this channel's methods to send route
/// [Navigator.replace], utilize this channel's methods to send route
/// change information from framework to engine.
/// change information from framework to engine.
static
const
MethodChannel
navigation
=
MethodChannel
(
static
const
MethodChannel
navigation
=
Optional
MethodChannel
(
'flutter/navigation'
,
'flutter/navigation'
,
JSONMethodCodec
(),
JSONMethodCodec
(),
);
);
...
...
packages/flutter/lib/src/services/system_navigator.dart
View file @
f9fd71bc
...
@@ -35,4 +35,37 @@ class SystemNavigator {
...
@@ -35,4 +35,37 @@ class SystemNavigator {
static
Future
<
void
>
pop
({
bool
?
animated
})
async
{
static
Future
<
void
>
pop
({
bool
?
animated
})
async
{
await
SystemChannels
.
platform
.
invokeMethod
<
void
>(
'SystemNavigator.pop'
,
animated
);
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';
...
@@ -18,6 +18,7 @@ import 'app.dart';
import
'debug.dart'
;
import
'debug.dart'
;
import
'focus_manager.dart'
;
import
'focus_manager.dart'
;
import
'framework.dart'
;
import
'framework.dart'
;
import
'router.dart'
;
import
'widget_inspector.dart'
;
import
'widget_inspector.dart'
;
export
'dart:ui'
show
AppLifecycleState
,
Locale
;
export
'dart:ui'
show
AppLifecycleState
,
Locale
;
...
@@ -95,7 +96,7 @@ abstract class WidgetsBindingObserver {
...
@@ -95,7 +96,7 @@ abstract class WidgetsBindingObserver {
/// [SystemChannels.navigation].
/// [SystemChannels.navigation].
Future
<
bool
>
didPopRoute
()
=>
Future
<
bool
>.
value
(
false
);
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.
/// navigator.
///
///
/// Observers are expected to return true if they were able to
/// Observers are expected to return true if they were able to
...
@@ -106,6 +107,22 @@ abstract class WidgetsBindingObserver {
...
@@ -106,6 +107,22 @@ abstract class WidgetsBindingObserver {
/// [SystemChannels.navigation].
/// [SystemChannels.navigation].
Future
<
bool
>
didPushRoute
(
String
route
)
=>
Future
<
bool
>.
value
(
false
);
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,
/// Called when the application's dimensions change. For example,
/// when a phone is rotated.
/// when a phone is rotated.
///
///
...
@@ -654,12 +671,28 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
...
@@ -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
)
{
Future
<
dynamic
>
_handleNavigationInvocation
(
MethodCall
methodCall
)
{
switch
(
methodCall
.
method
)
{
switch
(
methodCall
.
method
)
{
case
'popRoute'
:
case
'popRoute'
:
return
handlePopRoute
();
return
handlePopRoute
();
case
'pushRoute'
:
case
'pushRoute'
:
return
handlePushRoute
(
methodCall
.
arguments
as
String
);
return
handlePushRoute
(
methodCall
.
arguments
as
String
);
case
'pushRouteInformation'
:
return
_handlePushRouteInformation
(
methodCall
.
arguments
as
Map
<
dynamic
,
dynamic
>);
}
}
return
Future
<
dynamic
>.
value
();
return
Future
<
dynamic
>.
value
();
}
}
...
...
packages/flutter/lib/src/widgets/navigator.dart
View file @
f9fd71bc
...
@@ -21,7 +21,6 @@ import 'focus_scope.dart';
...
@@ -21,7 +21,6 @@ import 'focus_scope.dart';
import
'framework.dart'
;
import
'framework.dart'
;
import
'heroes.dart'
;
import
'heroes.dart'
;
import
'overlay.dart'
;
import
'overlay.dart'
;
import
'route_notification_messages.dart'
;
import
'routes.dart'
;
import
'routes.dart'
;
import
'ticker_provider.dart'
;
import
'ticker_provider.dart'
;
...
@@ -3308,8 +3307,10 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin {
...
@@ -3308,8 +3307,10 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin {
_RouteEntry
.
isPresentPredicate
,
orElse:
()
=>
null
);
_RouteEntry
.
isPresentPredicate
,
orElse:
()
=>
null
);
final
String
routeName
=
lastEntry
?.
route
?.
settings
?.
name
;
final
String
routeName
=
lastEntry
?.
route
?.
settings
?.
name
;
if
(
routeName
!=
_lastAnnouncedRouteName
)
{
if
(
routeName
!=
_lastAnnouncedRouteName
)
{
RouteNotificationMessages
.
maybeNotifyRouteChange
(
SystemNavigator
.
routeUpdated
(
routeName
,
_lastAnnouncedRouteName
);
routeName:
routeName
,
previousRouteName:
_lastAnnouncedRouteName
);
_lastAnnouncedRouteName
=
routeName
;
_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';
...
@@ -85,6 +85,7 @@ export 'src/widgets/primary_scroll_controller.dart';
export
'src/widgets/raw_keyboard_listener.dart'
;
export
'src/widgets/raw_keyboard_listener.dart'
;
export
'src/widgets/restoration.dart'
;
export
'src/widgets/restoration.dart'
;
export
'src/widgets/restoration_properties.dart'
;
export
'src/widgets/restoration_properties.dart'
;
export
'src/widgets/router.dart'
;
export
'src/widgets/routes.dart'
;
export
'src/widgets/routes.dart'
;
export
'src/widgets/safe_area.dart'
;
export
'src/widgets/safe_area.dart'
;
export
'src/widgets/scroll_activity.dart'
;
export
'src/widgets/scroll_activity.dart'
;
...
...
packages/flutter/test/cupertino/app_test.dart
View file @
f9fd71bc
...
@@ -6,6 +6,8 @@
...
@@ -6,6 +6,8 @@
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/services.dart'
;
void
main
(
)
{
void
main
(
)
{
testWidgets
(
'Heroes work'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Heroes work'
,
(
WidgetTester
tester
)
async
{
...
@@ -147,4 +149,101 @@ void main() {
...
@@ -147,4 +149,101 @@ void main() {
expect
(
key2
.
currentState
,
isA
<
NavigatorState
>());
expect
(
key2
.
currentState
,
isA
<
NavigatorState
>());
expect
(
key1
.
currentState
,
isNull
);
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 @@
...
@@ -4,7 +4,9 @@
// @dart = 2.8
// @dart = 2.8
import
'package:flutter/foundation.dart'
;
import
'package:flutter/semantics.dart'
;
import
'package:flutter/semantics.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
...
@@ -947,6 +949,37 @@ void main() {
...
@@ -947,6 +949,37 @@ void main() {
expect
(
key2
.
currentState
,
isA
<
NavigatorState
>());
expect
(
key2
.
currentState
,
isA
<
NavigatorState
>());
expect
(
key1
.
currentState
,
isNull
);
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
{
class
MockAccessibilityFeature
implements
AccessibilityFeatures
{
...
@@ -968,3 +1001,69 @@ class MockAccessibilityFeature implements AccessibilityFeatures {
...
@@ -968,3 +1001,69 @@ class MockAccessibilityFeature implements AccessibilityFeatures {
@override
@override
bool
get
reduceMotion
=>
true
;
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() {
...
@@ -264,4 +264,116 @@ void main() {
expect
(
find
.
text
(
'non-regular page one'
),
findsOneWidget
);
expect
(
find
.
text
(
'non-regular page one'
),
findsOneWidget
);
expect
(
find
.
text
(
'regular page'
),
findsNothing
);
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 {
...
@@ -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
(
)
{
void
main
(
)
{
setUp
(()
{
setUp
(()
{
WidgetsFlutterBinding
.
ensureInitialized
();
WidgetsFlutterBinding
.
ensureInitialized
();
...
@@ -90,6 +100,38 @@ void main() {
...
@@ -90,6 +100,38 @@ void main() {
WidgetsBinding
.
instance
.
removeObserver
(
observer
);
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
{
testWidgets
(
'Application lifecycle affects frame scheduling'
,
(
WidgetTester
tester
)
async
{
final
BinaryMessenger
defaultBinaryMessenger
=
ServicesBinding
.
instance
.
defaultBinaryMessenger
;
final
BinaryMessenger
defaultBinaryMessenger
=
ServicesBinding
.
instance
.
defaultBinaryMessenger
;
ByteData
message
;
ByteData
message
;
...
...
packages/flutter/test/widgets/route_notification_messages_test.dart
View file @
f9fd71bc
...
@@ -36,6 +36,13 @@ class OnTapPage extends StatelessWidget {
...
@@ -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
(
)
{
void
main
(
)
{
testWidgets
(
'Push and Pop should send platform messages'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Push and Pop should send platform messages'
,
(
WidgetTester
tester
)
async
{
final
Map
<
String
,
WidgetBuilder
>
routes
=
<
String
,
WidgetBuilder
>{
final
Map
<
String
,
WidgetBuilder
>
routes
=
<
String
,
WidgetBuilder
>{
...
@@ -258,4 +265,109 @@ void main() {
...
@@ -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