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
f86d1089
Unverified
Commit
f86d1089
authored
Apr 30, 2022
by
chunhtai
Committed by
GitHub
Apr 30, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adds RouterConfig to simply API (#102786)
parent
02b300d9
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
536 additions
and
85 deletions
+536
-85
app.dart
packages/flutter/lib/src/cupertino/app.dart
+16
-7
app.dart
packages/flutter/lib/src/material/app.dart
+15
-8
app.dart
packages/flutter/lib/src/widgets/app.dart
+88
-40
router.dart
packages/flutter/lib/src/widgets/router.dart
+77
-9
app_test.dart
packages/flutter/test/cupertino/app_test.dart
+104
-0
app_test.dart
packages/flutter/test/material/app_test.dart
+104
-0
app_test.dart
packages/flutter/test/widgets/app_test.dart
+110
-0
router_test.dart
packages/flutter/test/widgets/router_test.dart
+22
-21
No files found.
packages/flutter/lib/src/cupertino/app.dart
View file @
f86d1089
...
...
@@ -188,15 +188,19 @@ class CupertinoApp extends StatefulWidget {
routeInformationProvider
=
null
,
routeInformationParser
=
null
,
routerDelegate
=
null
,
backButtonDispatcher
=
null
;
backButtonDispatcher
=
null
,
routerConfig
=
null
;
/// Creates a [CupertinoApp] that uses the [Router] instead of a [Navigator].
///
/// {@macro flutter.widgets.WidgetsApp.router}
const
CupertinoApp
.
router
({
super
.
key
,
this
.
routeInformationProvider
,
required
RouteInformationParser
<
Object
>
this
.
routeInformationParser
,
required
RouterDelegate
<
Object
>
this
.
routerDelegate
,
this
.
routeInformationParser
,
this
.
routerDelegate
,
this
.
backButtonDispatcher
,
this
.
routerConfig
,
this
.
theme
,
this
.
builder
,
this
.
title
=
''
,
...
...
@@ -217,7 +221,8 @@ class CupertinoApp extends StatefulWidget {
this
.
restorationScopeId
,
this
.
scrollBehavior
,
this
.
useInheritedMediaQuery
=
false
,
})
:
assert
(
title
!=
null
),
})
:
assert
(
routerDelegate
!=
null
||
routerConfig
!=
null
),
assert
(
title
!=
null
),
assert
(
showPerformanceOverlay
!=
null
),
assert
(
checkerboardRasterCacheImages
!=
null
),
assert
(
checkerboardOffscreenLayers
!=
null
),
...
...
@@ -282,6 +287,9 @@ class CupertinoApp extends StatefulWidget {
/// {@macro flutter.widgets.widgetsApp.backButtonDispatcher}
final
BackButtonDispatcher
?
backButtonDispatcher
;
/// {@macro flutter.widgets.widgetsApp.routerConfig}
final
RouterConfig
<
Object
>?
routerConfig
;
/// {@macro flutter.widgets.widgetsApp.builder}
final
TransitionBuilder
?
builder
;
...
...
@@ -478,7 +486,7 @@ class CupertinoScrollBehavior extends ScrollBehavior {
class
_CupertinoAppState
extends
State
<
CupertinoApp
>
{
late
HeroController
_heroController
;
bool
get
_usesRouter
=>
widget
.
routerDelegate
!=
null
;
bool
get
_usesRouter
=>
widget
.
routerDelegate
!=
null
||
widget
.
routerConfig
!=
null
;
@override
void
initState
()
{
...
...
@@ -519,8 +527,9 @@ class _CupertinoAppState extends State<CupertinoApp> {
return
WidgetsApp
.
router
(
key:
GlobalObjectKey
(
this
),
routeInformationProvider:
widget
.
routeInformationProvider
,
routeInformationParser:
widget
.
routeInformationParser
!,
routerDelegate:
widget
.
routerDelegate
!,
routeInformationParser:
widget
.
routeInformationParser
,
routerDelegate:
widget
.
routerDelegate
,
routerConfig:
widget
.
routerConfig
,
backButtonDispatcher:
widget
.
backButtonDispatcher
,
builder:
widget
.
builder
,
title:
widget
.
title
,
...
...
packages/flutter/lib/src/material/app.dart
View file @
f86d1089
...
...
@@ -248,15 +248,19 @@ class MaterialApp extends StatefulWidget {
routeInformationProvider
=
null
,
routeInformationParser
=
null
,
routerDelegate
=
null
,
backButtonDispatcher
=
null
;
backButtonDispatcher
=
null
,
routerConfig
=
null
;
/// Creates a [MaterialApp] that uses the [Router] instead of a [Navigator].
///
/// {@macro flutter.widgets.WidgetsApp.router}
const
MaterialApp
.
router
({
super
.
key
,
this
.
scaffoldMessengerKey
,
this
.
routeInformationProvider
,
required
RouteInformationParser
<
Object
>
this
.
routeInformationParser
,
required
RouterDelegate
<
Object
>
this
.
routerDelegate
,
this
.
routeInformationParser
,
this
.
routerDelegate
,
this
.
routerConfig
,
this
.
backButtonDispatcher
,
this
.
builder
,
this
.
title
=
''
,
...
...
@@ -283,8 +287,7 @@ class MaterialApp extends StatefulWidget {
this
.
restorationScopeId
,
this
.
scrollBehavior
,
this
.
useInheritedMediaQuery
=
false
,
})
:
assert
(
routeInformationParser
!=
null
),
assert
(
routerDelegate
!=
null
),
})
:
assert
(
routerDelegate
!=
null
||
routerConfig
!=
null
),
assert
(
title
!=
null
),
assert
(
debugShowMaterialGrid
!=
null
),
assert
(
showPerformanceOverlay
!=
null
),
...
...
@@ -353,6 +356,9 @@ class MaterialApp extends StatefulWidget {
/// {@macro flutter.widgets.widgetsApp.backButtonDispatcher}
final
BackButtonDispatcher
?
backButtonDispatcher
;
/// {@macro flutter.widgets.widgetsApp.routerConfig}
final
RouterConfig
<
Object
>?
routerConfig
;
/// {@macro flutter.widgets.widgetsApp.builder}
///
/// Material specific features such as [showDialog] and [showMenu], and widgets
...
...
@@ -832,7 +838,7 @@ class MaterialScrollBehavior extends ScrollBehavior {
class
_MaterialAppState
extends
State
<
MaterialApp
>
{
late
HeroController
_heroController
;
bool
get
_usesRouter
=>
widget
.
routerDelegate
!=
null
;
bool
get
_usesRouter
=>
widget
.
routerDelegate
!=
null
||
widget
.
routerConfig
!=
null
;
@override
void
initState
()
{
...
...
@@ -925,8 +931,9 @@ class _MaterialAppState extends State<MaterialApp> {
return
WidgetsApp
.
router
(
key:
GlobalObjectKey
(
this
),
routeInformationProvider:
widget
.
routeInformationProvider
,
routeInformationParser:
widget
.
routeInformationParser
!,
routerDelegate:
widget
.
routerDelegate
!,
routeInformationParser:
widget
.
routeInformationParser
,
routerDelegate:
widget
.
routerDelegate
,
routerConfig:
widget
.
routerConfig
,
backButtonDispatcher:
widget
.
backButtonDispatcher
,
builder:
_materialBuilder
,
title:
widget
.
title
,
...
...
packages/flutter/lib/src/widgets/app.dart
View file @
f86d1089
...
...
@@ -399,15 +399,23 @@ class WidgetsApp extends StatefulWidget {
routeInformationProvider
=
null
,
routeInformationParser
=
null
,
routerDelegate
=
null
,
backButtonDispatcher
=
null
;
backButtonDispatcher
=
null
,
routerConfig
=
null
;
/// Creates a [WidgetsApp] that uses the [Router] instead of a [Navigator].
///
/// {@template flutter.widgets.WidgetsApp.router}
/// If the [routerConfig] is provided, the other router related delegates,
/// [routeInformationParser], [routeInformationProvider], [routerDelegate],
/// and [backButtonDispatcher], must all be null.
/// {@endtemplate}
WidgetsApp
.
router
({
super
.
key
,
this
.
routeInformationProvider
,
required
RouteInformationParser
<
Object
>
this
.
routeInformationParser
,
required
RouterDelegate
<
Object
>
this
.
routerDelegate
,
BackButtonDispatcher
?
backButtonDispatcher
,
this
.
routeInformationParser
,
this
.
routerDelegate
,
this
.
routerConfig
,
this
.
backButtonDispatcher
,
this
.
builder
,
this
.
title
=
''
,
this
.
onGenerateTitle
,
...
...
@@ -429,11 +437,21 @@ class WidgetsApp extends StatefulWidget {
this
.
actions
,
this
.
restorationScopeId
,
this
.
useInheritedMediaQuery
=
false
,
})
:
assert
(
routeInformationParser
!=
null
&&
routerDelegate
!=
null
,
'The routeInformationParser and routerDelegate cannot be null.'
,
),
})
:
assert
((){
if
(
routerConfig
!=
null
)
{
assert
(
(
routeInformationProvider
??
routeInformationParser
??
routerDelegate
??
backButtonDispatcher
)
==
null
,
'If the routerConfig is provided, all the other router delegates must not be provided'
,
);
return
true
;
}
assert
(
routerDelegate
!=
null
,
'Either one of routerDelegate or routerConfig must be provided'
);
assert
(
routeInformationProvider
==
null
||
routeInformationParser
!=
null
,
'If routeInformationProvider is provided, routeInformationParser must also be provided'
,
);
return
true
;
}()),
assert
(
title
!=
null
),
assert
(
color
!=
null
),
assert
(
supportedLocales
!=
null
&&
supportedLocales
.
isNotEmpty
),
...
...
@@ -444,7 +462,6 @@ class WidgetsApp extends StatefulWidget {
assert
(
debugShowCheckedModeBanner
!=
null
),
assert
(
debugShowWidgetInspector
!=
null
),
navigatorObservers
=
null
,
backButtonDispatcher
=
backButtonDispatcher
??
RootBackButtonDispatcher
(),
navigatorKey
=
null
,
onGenerateRoute
=
null
,
pageRouteBuilder
=
null
,
...
...
@@ -524,7 +541,7 @@ class WidgetsApp extends StatefulWidget {
///
/// See also:
///
/// * [Router.routeInformationParser]
:
which receives this object when this
/// * [Router.routeInformationParser]
,
which receives this object when this
/// widget builds the [Router].
/// {@endtemplate}
final
RouteInformationParser
<
Object
>?
routeInformationParser
;
...
...
@@ -540,7 +557,7 @@ class WidgetsApp extends StatefulWidget {
///
/// See also:
///
/// * [Router.routerDelegate]
:
which receives this object when this widget
/// * [Router.routerDelegate]
,
which receives this object when this widget
/// builds the [Router].
/// {@endtemplate}
final
RouterDelegate
<
Object
>?
routerDelegate
;
...
...
@@ -555,7 +572,7 @@ class WidgetsApp extends StatefulWidget {
///
/// See also:
///
/// * [Router.backButtonDispatcher]
:
which receives this object when this
/// * [Router.backButtonDispatcher]
,
which receives this object when this
/// widget builds the [Router].
/// {@endtemplate}
final
BackButtonDispatcher
?
backButtonDispatcher
;
...
...
@@ -573,11 +590,25 @@ class WidgetsApp extends StatefulWidget {
///
/// See also:
///
/// * [Router.routeInformationProvider]
:
which receives this object when this
/// * [Router.routeInformationProvider]
,
which receives this object when this
/// widget builds the [Router].
/// {@endtemplate}
final
RouteInformationProvider
?
routeInformationProvider
;
/// {@template flutter.widgets.widgetsApp.routerConfig}
/// An object to configure the underlying [Router].
///
/// If the [routerConfig] is provided, the other router related delegates,
/// [routeInformationParser], [routeInformationProvider], [routerDelegate],
/// and [backButtonDispatcher], must all be null.
///
/// See also:
///
/// * [Router.withConfig], which receives this object when this
/// widget builds the [Router].
/// {@endtemplate}
final
RouterConfig
<
Object
>?
routerConfig
;
/// {@template flutter.widgets.widgetsApp.home}
/// The widget for the default route of the app ([Navigator.defaultRouteName],
/// which is `/`).
...
...
@@ -1295,42 +1326,53 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
super
.
dispose
();
}
void
_clearRouterResource
()
{
_defaultRouteInformationProvider
?.
dispose
();
_defaultRouteInformationProvider
=
null
;
_defaultBackButtonDispatcher
=
null
;
}
void
_clearNavigatorResource
()
{
_navigator
=
null
;
}
void
_updateRouting
({
WidgetsApp
?
oldWidget
})
{
if
(
_usesRouter
)
{
assert
(!
_usesNavigator
);
_navigator
=
null
;
if
(
oldWidget
==
null
||
oldWidget
.
routeInformationProvider
!=
widget
.
routeInformationProvider
)
{
if
(
_usesRouterWithDelegates
)
{
assert
(!
_usesNavigator
&&
!
_usesRouterWithConfig
);
_clearNavigatorResource
();
if
(
widget
.
routeInformationProvider
==
null
&&
widget
.
routeInformationParser
!=
null
)
{
_defaultRouteInformationProvider
??=
PlatformRouteInformationProvider
(
initialRouteInformation:
RouteInformation
(
location:
_initialRouteName
,
),
);
}
else
{
_defaultRouteInformationProvider
?.
dispose
();
_defaultRouteInformationProvider
=
null
;
if
(
widget
.
routeInformationProvider
==
null
)
{
_defaultRouteInformationProvider
=
PlatformRouteInformationProvider
(
initialRouteInformation:
RouteInformation
(
location:
_initialRouteName
,
),
);
}
}
if
(
widget
.
backButtonDispatcher
==
null
)
{
_defaultBackButtonDispatcher
??=
RootBackButtonDispatcher
();
}
}
else
if
(
_usesNavigator
)
{
assert
(!
_usesRouter
);
_defaultRouteInformationProvider
?.
dispose
();
_defaultRouteInformationProvider
=
null
;
assert
(!
_usesRouterWithDelegates
&&
!
_usesRouterWithConfig
);
_clearRouterResource
();
if
(
_navigator
==
null
||
widget
.
navigatorKey
!=
oldWidget
!.
navigatorKey
)
{
_navigator
=
widget
.
navigatorKey
??
GlobalObjectKey
<
NavigatorState
>(
this
);
}
assert
(
_navigator
!=
null
);
}
else
{
assert
(
widget
.
builder
!=
null
);
assert
(!
_usesRouter
);
assert
(!
_usesNavigator
);
_navigator
=
null
;
_defaultRouteInformationProvider
?.
dispose
();
_defaultRouteInformationProvider
=
null
;
assert
(
widget
.
builder
!=
null
||
_usesRouterWithConfig
);
assert
(!
_usesRouterWithDelegates
&&
!
_usesNavigator
);
_clearRouterResource
();
_clearNavigatorResource
();
}
// If we use a navigator, we have a navigator key.
assert
(
_usesNavigator
==
(
_navigator
!=
null
));
}
bool
get
_usesRouter
=>
widget
.
routerDelegate
!=
null
;
bool
get
_usesRouterWithDelegates
=>
widget
.
routerDelegate
!=
null
;
bool
get
_usesRouterWithConfig
=>
widget
.
routerConfig
!=
null
;
bool
get
_usesNavigator
=>
widget
.
home
!=
null
||
(
widget
.
routes
?.
isNotEmpty
??
false
)
||
widget
.
onGenerateRoute
!=
null
...
...
@@ -1340,6 +1382,8 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
RouteInformationProvider
?
get
_effectiveRouteInformationProvider
=>
widget
.
routeInformationProvider
??
_defaultRouteInformationProvider
;
PlatformRouteInformationProvider
?
_defaultRouteInformationProvider
;
BackButtonDispatcher
get
_effectiveBackButtonDispatcher
=>
widget
.
backButtonDispatcher
??
_defaultBackButtonDispatcher
!;
RootBackButtonDispatcher
?
_defaultBackButtonDispatcher
;
// NAVIGATOR
...
...
@@ -1409,7 +1453,7 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
assert
(
mounted
);
// The back button dispatcher should handle the pop route if we use a
// router.
if
(
_usesRouter
)
if
(
_usesRouter
WithDelegates
)
return
false
;
final
NavigatorState
?
navigator
=
_navigator
?.
currentState
;
...
...
@@ -1423,7 +1467,7 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
assert
(
mounted
);
// The route name provider should handle the push route if we uses a
// router.
if
(
_usesRouter
)
if
(
_usesRouter
WithDelegates
)
return
false
;
final
NavigatorState
?
navigator
=
_navigator
?.
currentState
;
...
...
@@ -1535,14 +1579,13 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
@override
Widget
build
(
BuildContext
context
)
{
Widget
?
routing
;
if
(
_usesRouter
)
{
assert
(
_effectiveRouteInformationProvider
!=
null
);
if
(
_usesRouterWithDelegates
)
{
routing
=
Router
<
Object
>(
restorationScopeId:
'router'
,
routeInformationProvider:
_effectiveRouteInformationProvider
,
routeInformationParser:
widget
.
routeInformationParser
,
routerDelegate:
widget
.
routerDelegate
!,
backButtonDispatcher:
widget
.
b
ackButtonDispatcher
,
backButtonDispatcher:
_effectiveB
ackButtonDispatcher
,
);
}
else
if
(
_usesNavigator
)
{
assert
(
_navigator
!=
null
);
...
...
@@ -1560,6 +1603,11 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
observers:
widget
.
navigatorObservers
!,
reportsRouteUpdateToEngine:
true
,
);
}
else
if
(
_usesRouterWithConfig
)
{
routing
=
Router
<
Object
>.
withConfig
(
restorationScopeId:
'router'
,
config:
widget
.
routerConfig
!,
);
}
Widget
result
;
...
...
packages/flutter/lib/src/widgets/router.dart
View file @
f86d1089
...
...
@@ -73,6 +73,46 @@ class RouteInformation {
final
Object
?
state
;
}
/// A convenient bundle to configure a [Router] widget.
///
/// To configure a [Router] widget, one needs to provide several delegates,
/// [RouteInformationProvider], [RouteInformationParser], [RouterDelegate],
/// and [BackButtonDispatcher]. This abstract class provides way to bundle these
/// delegates into a single object to configure a [Router].
///
/// The [routerDelegate] must not be null. The [backButtonDispatcher],
/// [routeInformationProvider], and [routeInformationProvider] are optional.
///
/// The [routeInformationProvider] and [routeInformationParser] must
/// both be provided or not provided.
class
RouterConfig
<
T
>
{
/// Creates a [RouterConfig].
///
/// The [routerDelegate] must not be null. The [backButtonDispatcher],
/// [routeInformationProvider], and [routeInformationParser] are optional.
///
/// The [routeInformationProvider] and [routeInformationParser] must
/// both be provided or not provided.
const
RouterConfig
({
this
.
routeInformationProvider
,
this
.
routeInformationParser
,
required
this
.
routerDelegate
,
this
.
backButtonDispatcher
,
})
:
assert
((
routeInformationProvider
==
null
)
==
(
routeInformationParser
==
null
));
/// The [RouteInformationProvider] that is used to configure the [Router].
final
RouteInformationProvider
?
routeInformationProvider
;
/// The [RouteInformationParser] that is used to configure the [Router].
final
RouteInformationParser
<
T
>?
routeInformationParser
;
/// The [RouterDelegate] that is used to configure the [Router].
final
RouterDelegate
<
T
>
routerDelegate
;
/// The [BackButtonDispatcher] that is used to configure the [Router].
final
BackButtonDispatcher
?
backButtonDispatcher
;
}
/// The dispatcher for opening and closing pages of an application.
///
/// This widget listens for routing information from the operating system (e.g.
...
...
@@ -275,8 +315,8 @@ class Router<T> extends StatefulWidget {
/// router does not depend on route information. A common example is a sub router
/// that builds its content completely based on the app state.
///
///
If the [routeInformationProvider] or [restorationScopeId] is not null, then
///
[routeInformationParser] must also not be null
.
///
The [routeInformationProvider] and [routeInformationParser] must
///
both be provided or not provided
.
///
/// The [routerDelegate] must not be null.
const
Router
({
...
...
@@ -286,11 +326,38 @@ class Router<T> extends StatefulWidget {
required
this
.
routerDelegate
,
this
.
backButtonDispatcher
,
this
.
restorationScopeId
,
})
:
assert
(
(
routeInformationProvider
==
null
&&
restorationScopeId
==
null
)
||
routeInformationParser
!=
null
,
'A routeInformationParser must be provided when a routeInformationProvider or a restorationId is specified.'
),
assert
(
routerDelegate
!=
null
);
})
:
assert
(
routeInformationProvider
==
null
||
routeInformationParser
!=
null
,
'A routeInformationParser must be provided when a routeInformationProvider is specified.'
,
),
assert
(
routerDelegate
!=
null
);
/// Creates a router with a [RouterConfig].
///
/// The [RouterConfig.routeInformationProvider] and
/// [RouterConfig.routeInformationParser] can be null if this router does not
/// depend on route information. A common example is a sub router that builds
/// its content completely based on the app state.
///
/// If the [RouterConfig.routeInformationProvider] is not null, then
/// [RouterConfig.routeInformationParser] must also not be
/// null.
///
/// The [RouterConfig.routerDelegate] must not be null.
factory
Router
.
withConfig
({
Key
?
key
,
required
RouterConfig
<
T
>
config
,
String
?
restorationScopeId
,
})
{
return
Router
<
T
>(
key:
key
,
routeInformationProvider:
config
.
routeInformationProvider
,
routeInformationParser:
config
.
routeInformationParser
,
routerDelegate:
config
.
routerDelegate
,
backButtonDispatcher:
config
.
backButtonDispatcher
,
restorationScopeId:
restorationScopeId
,
);
}
/// The route information provider for the router.
///
...
...
@@ -299,8 +366,8 @@ class Router<T> extends StatefulWidget {
/// it notifies.
///
/// This can be null if this router does not rely on the route information
/// to build its content. In such case, the [routeInformationParser]
can also be
/// null.
/// to build its content. In such case, the [routeInformationParser]
must also
///
be
null.
final
RouteInformationProvider
?
routeInformationProvider
;
/// The route information parser for the router.
...
...
@@ -511,6 +578,7 @@ class _RouterState<T> extends State<Router<T>> with RestorationMixin {
void
restoreState
(
RestorationBucket
?
oldBucket
,
bool
initialRestore
)
{
registerForRestoration
(
_routeInformation
,
'route'
);
if
(
_routeInformation
.
value
!=
null
)
{
assert
(
widget
.
routeInformationParser
!=
null
);
_processRouteInformation
(
_routeInformation
.
value
!,
()
=>
widget
.
routerDelegate
.
setRestoredRoutePath
);
}
else
if
(
widget
.
routeInformationProvider
!=
null
)
{
_processRouteInformation
(
widget
.
routeInformationProvider
!.
value
,
()
=>
widget
.
routerDelegate
.
setInitialRoutePath
);
...
...
packages/flutter/test/cupertino/app_test.dart
View file @
f86d1089
...
...
@@ -176,6 +176,110 @@ void main() {
expect
(
find
.
text
(
'popped'
),
findsOneWidget
);
});
testWidgets
(
'CupertinoApp.router route information parser is optional'
,
(
WidgetTester
tester
)
async
{
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
);
},
);
delegate
.
routeInformation
=
const
RouteInformation
(
location:
'initial'
);
await
tester
.
pumpWidget
(
CupertinoApp
.
router
(
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
);
});
testWidgets
(
'CupertinoApp.router throw if route information provider is provided but no route information parser'
,
(
WidgetTester
tester
)
async
{
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
);
},
);
delegate
.
routeInformation
=
const
RouteInformation
(
location:
'initial'
);
final
PlatformRouteInformationProvider
provider
=
PlatformRouteInformationProvider
(
initialRouteInformation:
const
RouteInformation
(
location:
'initial'
,
),
);
await
tester
.
pumpWidget
(
CupertinoApp
.
router
(
routeInformationProvider:
provider
,
routerDelegate:
delegate
,
));
expect
(
tester
.
takeException
(),
isAssertionError
);
});
testWidgets
(
'CupertinoApp.router throw if route configuration is provided along with other delegate'
,
(
WidgetTester
tester
)
async
{
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
);
},
);
delegate
.
routeInformation
=
const
RouteInformation
(
location:
'initial'
);
final
RouterConfig
<
RouteInformation
>
routerConfig
=
RouterConfig
<
RouteInformation
>(
routerDelegate:
delegate
);
await
tester
.
pumpWidget
(
CupertinoApp
.
router
(
routerDelegate:
delegate
,
routerConfig:
routerConfig
,
));
expect
(
tester
.
takeException
(),
isAssertionError
);
});
testWidgets
(
'CupertinoApp.router router config works'
,
(
WidgetTester
tester
)
async
{
final
RouterConfig
<
RouteInformation
>
routerConfig
=
RouterConfig
<
RouteInformation
>(
routeInformationProvider:
PlatformRouteInformationProvider
(
initialRouteInformation:
const
RouteInformation
(
location:
'initial'
,
),
),
routeInformationParser:
SimpleRouteInformationParser
(),
routerDelegate:
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
);
},
),
backButtonDispatcher:
RootBackButtonDispatcher
()
);
await
tester
.
pumpWidget
(
CupertinoApp
.
router
(
routerConfig:
routerConfig
,
));
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
(
'CupertinoApp has correct default ScrollBehavior'
,
(
WidgetTester
tester
)
async
{
late
BuildContext
capturedContext
;
await
tester
.
pumpWidget
(
...
...
packages/flutter/test/material/app_test.dart
View file @
f86d1089
...
...
@@ -1023,6 +1023,110 @@ void main() {
expect
(
find
.
text
(
'popped'
),
findsOneWidget
);
});
testWidgets
(
'MaterialApp.router route information parser is optional'
,
(
WidgetTester
tester
)
async
{
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
);
},
);
delegate
.
routeInformation
=
const
RouteInformation
(
location:
'initial'
);
await
tester
.
pumpWidget
(
MaterialApp
.
router
(
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
);
});
testWidgets
(
'MaterialApp.router throw if route information provider is provided but no route information parser'
,
(
WidgetTester
tester
)
async
{
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
);
},
);
delegate
.
routeInformation
=
const
RouteInformation
(
location:
'initial'
);
final
PlatformRouteInformationProvider
provider
=
PlatformRouteInformationProvider
(
initialRouteInformation:
const
RouteInformation
(
location:
'initial'
,
),
);
await
tester
.
pumpWidget
(
MaterialApp
.
router
(
routeInformationProvider:
provider
,
routerDelegate:
delegate
,
));
expect
(
tester
.
takeException
(),
isAssertionError
);
});
testWidgets
(
'MaterialApp.router throw if route configuration is provided along with other delegate'
,
(
WidgetTester
tester
)
async
{
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
);
},
);
delegate
.
routeInformation
=
const
RouteInformation
(
location:
'initial'
);
final
RouterConfig
<
RouteInformation
>
routerConfig
=
RouterConfig
<
RouteInformation
>(
routerDelegate:
delegate
);
await
tester
.
pumpWidget
(
MaterialApp
.
router
(
routerDelegate:
delegate
,
routerConfig:
routerConfig
,
));
expect
(
tester
.
takeException
(),
isAssertionError
);
});
testWidgets
(
'MaterialApp.router router config works'
,
(
WidgetTester
tester
)
async
{
final
RouterConfig
<
RouteInformation
>
routerConfig
=
RouterConfig
<
RouteInformation
>(
routeInformationProvider:
PlatformRouteInformationProvider
(
initialRouteInformation:
const
RouteInformation
(
location:
'initial'
,
),
),
routeInformationParser:
SimpleRouteInformationParser
(),
routerDelegate:
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
);
},
),
backButtonDispatcher:
RootBackButtonDispatcher
()
);
await
tester
.
pumpWidget
(
MaterialApp
.
router
(
routerConfig:
routerConfig
,
));
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
(
'MaterialApp.builder can build app without a Navigator'
,
(
WidgetTester
tester
)
async
{
Widget
?
builderChild
;
await
tester
.
pumpWidget
(
MaterialApp
(
...
...
packages/flutter/test/widgets/app_test.dart
View file @
f86d1089
...
...
@@ -305,6 +305,116 @@ void main() {
expect
(
find
.
text
(
'popped'
),
findsOneWidget
);
});
testWidgets
(
'WidgetsApp.router route information parser is optional'
,
(
WidgetTester
tester
)
async
{
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
);
},
);
delegate
.
routeInformation
=
const
RouteInformation
(
location:
'initial'
);
await
tester
.
pumpWidget
(
WidgetsApp
.
router
(
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 throw if route information provider is provided but no route information parser'
,
(
WidgetTester
tester
)
async
{
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
);
},
);
delegate
.
routeInformation
=
const
RouteInformation
(
location:
'initial'
);
final
PlatformRouteInformationProvider
provider
=
PlatformRouteInformationProvider
(
initialRouteInformation:
const
RouteInformation
(
location:
'initial'
,
),
);
await
expectLater
(()
async
{
await
tester
.
pumpWidget
(
WidgetsApp
.
router
(
routeInformationProvider:
provider
,
routerDelegate:
delegate
,
color:
const
Color
(
0xFF123456
),
));
},
throwsAssertionError
);
});
testWidgets
(
'WidgetsApp.router throw if route configuration is provided along with other delegate'
,
(
WidgetTester
tester
)
async
{
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
);
},
);
delegate
.
routeInformation
=
const
RouteInformation
(
location:
'initial'
);
final
RouterConfig
<
RouteInformation
>
routerConfig
=
RouterConfig
<
RouteInformation
>(
routerDelegate:
delegate
);
await
expectLater
(()
async
{
await
tester
.
pumpWidget
(
WidgetsApp
.
router
(
routerDelegate:
delegate
,
routerConfig:
routerConfig
,
color:
const
Color
(
0xFF123456
),
));
},
throwsAssertionError
);
});
testWidgets
(
'WidgetsApp.router router config works'
,
(
WidgetTester
tester
)
async
{
final
RouterConfig
<
RouteInformation
>
routerConfig
=
RouterConfig
<
RouteInformation
>(
routeInformationProvider:
PlatformRouteInformationProvider
(
initialRouteInformation:
const
RouteInformation
(
location:
'initial'
,
),
),
routeInformationParser:
SimpleRouteInformationParser
(),
routerDelegate:
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
);
},
),
backButtonDispatcher:
RootBackButtonDispatcher
()
);
await
tester
.
pumpWidget
(
WidgetsApp
.
router
(
routerConfig:
routerConfig
,
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
)
{
...
...
packages/flutter/test/widgets/router_test.dart
View file @
f86d1089
...
...
@@ -202,27 +202,7 @@ void main() {
throwsA
(
isAssertionError
.
having
(
(
AssertionError
e
)
=>
e
.
message
,
'message'
,
'A routeInformationParser must be provided when a routeInformationProvider or a restorationId is specified.'
,
)),
);
});
testWidgets
(
'Router throw when passing restorationId without routeInformationParser'
,
(
WidgetTester
tester
)
async
{
expect
(
()
{
Router
<
RouteInformation
>(
restorationScopeId:
'foo'
,
routerDelegate:
SimpleRouterDelegate
(
builder:
(
BuildContext
context
,
RouteInformation
?
information
)
{
return
Text
(
information
!.
location
!);
},
),
);
},
throwsA
(
isAssertionError
.
having
(
(
AssertionError
e
)
=>
e
.
message
,
'message'
,
'A routeInformationParser must be provided when a routeInformationProvider or a restorationId is specified.'
,
'A routeInformationParser must be provided when a routeInformationProvider is specified.'
,
)),
);
});
...
...
@@ -1470,6 +1450,27 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect
(
find
.
text
(
'
$expectedMaxLines
'
),
findsOneWidget
);
expect
(
parserCalled
,
isFalse
);
});
testWidgets
(
'Router can initialize with RouterConfig'
,
(
WidgetTester
tester
)
async
{
const
String
expected
=
'text'
;
final
RouterConfig
<
RouteInformation
>
config
=
RouterConfig
<
RouteInformation
>(
routeInformationProvider:
SimpleRouteInformationProvider
()..
value
=
const
RouteInformation
(
location:
'/'
),
routeInformationParser:
SimpleRouteInformationParser
(),
routerDelegate:
SimpleRouterDelegate
(
builder:
(
_
,
__
)
=>
const
Text
(
expected
),
),
backButtonDispatcher:
RootBackButtonDispatcher
(),
);
final
Router
<
RouteInformation
>
router
=
Router
<
RouteInformation
>.
withConfig
(
config:
config
);
expect
(
router
.
routerDelegate
,
config
.
routerDelegate
);
expect
(
router
.
routeInformationParser
,
config
.
routeInformationParser
);
expect
(
router
.
routeInformationProvider
,
config
.
routeInformationProvider
);
expect
(
router
.
backButtonDispatcher
,
config
.
backButtonDispatcher
);
await
tester
.
pumpWidget
(
buildBoilerPlate
(
router
));
expect
(
find
.
text
(
expected
),
findsOneWidget
);
});
}
Widget
buildBoilerPlate
(
Widget
child
)
{
...
...
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