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
5b713147
Unverified
Commit
5b713147
authored
Apr 29, 2022
by
chunhtai
Committed by
GitHub
Apr 29, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add RouteInformationParser.parseRouteInformationWithDependencies (#102414)
parent
e4bd552e
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
225 additions
and
4 deletions
+225
-4
router.dart
packages/flutter/lib/src/widgets/router.dart
+46
-4
router_test.dart
packages/flutter/test/widgets/router_test.dart
+179
-0
No files found.
packages/flutter/lib/src/widgets/router.dart
View file @
5b713147
...
...
@@ -494,6 +494,7 @@ class _RouterState<T> extends State<Router<T>> with RestorationMixin {
Object
?
_currentRouterTransaction
;
RouteInformationReportingType
?
_currentIntentionToReport
;
final
_RestorableRouteInformation
_routeInformation
=
_RestorableRouteInformation
();
late
bool
_routeParsePending
;
@override
String
?
get
restorationId
=>
widget
.
restorationScopeId
;
...
...
@@ -580,7 +581,15 @@ class _RouterState<T> extends State<Router<T>> with RestorationMixin {
@override
void
didChangeDependencies
()
{
_routeParsePending
=
true
;
super
.
didChangeDependencies
();
// The super.didChangeDependencies may have parsed the route information.
// This can happen if the didChangeDependencies is triggered by state
// restoration or first build.
if
(
widget
.
routeInformationProvider
!=
null
&&
_routeParsePending
)
{
_processRouteInformation
(
widget
.
routeInformationProvider
!.
value
,
()
=>
widget
.
routerDelegate
.
setNewRoutePath
);
}
_routeParsePending
=
false
;
_maybeNeedToReportRouteInformation
();
}
...
...
@@ -621,9 +630,11 @@ class _RouterState<T> extends State<Router<T>> with RestorationMixin {
}
void
_processRouteInformation
(
RouteInformation
information
,
ValueGetter
<
_RouteSetter
<
T
>>
delegateRouteSetter
)
{
assert
(
_routeParsePending
);
_routeParsePending
=
false
;
_currentRouterTransaction
=
Object
();
widget
.
routeInformationParser
!
.
parseRouteInformation
(
information
)
.
parseRouteInformation
WithDependencies
(
information
,
context
)
.
then
<
void
>(
_processParsedRouteInformation
(
_currentRouterTransaction
,
delegateRouteSetter
));
}
...
...
@@ -641,6 +652,7 @@ class _RouterState<T> extends State<Router<T>> with RestorationMixin {
void
_handleRouteInformationProviderNotification
()
{
assert
(
widget
.
routeInformationProvider
!.
value
!=
null
);
_routeParsePending
=
true
;
_processRouteInformation
(
widget
.
routeInformationProvider
!.
value
,
()
=>
widget
.
routerDelegate
.
setNewRoutePath
);
}
...
...
@@ -685,8 +697,10 @@ class _RouterState<T> extends State<Router<T>> with RestorationMixin {
routerDelegate:
widget
.
routerDelegate
,
routerState:
this
,
child:
Builder
(
// We use a Builder so that the build method below
// will have a BuildContext that contains the _RouterScope.
// Use a Builder so that the build method below will have a
// BuildContext that contains the _RouterScope. This also prevents
// dependencies look ups in routerDelegate from rebuilding Router
// widget that may result in re-parsing the route information.
builder:
widget
.
routerDelegate
.
build
,
),
),
...
...
@@ -1079,11 +1093,16 @@ class _BackButtonListenerState extends State<BackButtonListener> {
/// route information from [Router.routeInformationProvider] and any subsequent
/// new route notifications from it. The [Router] widget calls the [parseRouteInformation]
/// with the route information from [Router.routeInformationProvider].
///
/// One of the [parseRouteInformation] or
/// [parseRouteInformationWithDependencies] must be implemented, otherwise a
/// runtime error will be thrown.
abstract
class
RouteInformationParser
<
T
>
{
/// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
const
RouteInformationParser
();
/// {@template flutter.widgets.RouteInformationParser.parseRouteInformation}
/// Converts the given route information into parsed data to pass to a
/// [RouterDelegate].
///
...
...
@@ -1094,7 +1113,30 @@ abstract class RouteInformationParser<T> {
/// Consider using a [SynchronousFuture] if the result can be computed
/// synchronously, so that the [Router] does not need to wait for the next
/// microtask to pass the data to the [RouterDelegate].
Future
<
T
>
parseRouteInformation
(
RouteInformation
routeInformation
);
/// {@endtemplate}
///
/// One can implement [parseRouteInformationWithDependencies] instead if
/// the parsing depends on other dependencies from the [BuildContext].
Future
<
T
>
parseRouteInformation
(
RouteInformation
routeInformation
)
{
throw
UnimplementedError
(
'One of the parseRouteInformation or '
'parseRouteInformationWithDependencies must be implemented'
);
}
/// {@macro flutter.widgets.RouteInformationParser.parseRouteInformation}
///
/// The input [BuildContext] can be used for looking up [InheritedWidget]s
/// If one uses [BuildContext.dependOnInheritedWidgetOfExactType], a
/// dependency will be created. The [Router] will reparse the
/// [RouteInformation] from its [RouteInformationProvider] if the dependency
/// notifies its listeners.
///
/// One can also use [BuildContext.getElementForInheritedWidgetOfExactType] to
/// look up [InheritedWidget]s without creating dependencies.
Future
<
T
>
parseRouteInformationWithDependencies
(
RouteInformation
routeInformation
,
BuildContext
context
)
{
return
parseRouteInformation
(
routeInformation
);
}
/// Restore the route information from the given configuration.
///
...
...
packages/flutter/test/widgets/router_test.dart
View file @
5b713147
...
...
@@ -1308,6 +1308,168 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect
(
find
.
text
(
'Current route: /404'
),
findsOneWidget
);
expect
(
reportedRouteInformation
[
1
].
location
,
'/404'
);
});
testWidgets
(
'RouterInformationParser can look up dependencies and reparse'
,
(
WidgetTester
tester
)
async
{
final
SimpleRouteInformationProvider
provider
=
SimpleRouteInformationProvider
();
provider
.
value
=
const
RouteInformation
(
location:
'initial'
,
);
final
BackButtonDispatcher
dispatcher
=
RootBackButtonDispatcher
();
int
expectedMaxLines
=
1
;
bool
parserCalled
=
false
;
final
Widget
router
=
Router
<
RouteInformation
>(
routeInformationProvider:
provider
,
routeInformationParser:
CustomRouteInformationParser
((
RouteInformation
information
,
BuildContext
context
)
{
parserCalled
=
true
;
final
DefaultTextStyle
style
=
DefaultTextStyle
.
of
(
context
);
return
RouteInformation
(
location:
'
${style.maxLines}
'
);
}),
routerDelegate:
SimpleRouterDelegate
(
builder:
(
BuildContext
context
,
RouteInformation
?
information
)
{
return
Text
(
information
!.
location
!);
},
onPopRoute:
()
{
provider
.
value
=
const
RouteInformation
(
location:
'popped'
,
);
return
SynchronousFuture
<
bool
>(
true
);
},
),
backButtonDispatcher:
dispatcher
,
);
await
tester
.
pumpWidget
(
buildBoilerPlate
(
DefaultTextStyle
(
style:
const
TextStyle
(),
maxLines:
expectedMaxLines
,
child:
router
,
),
));
expect
(
find
.
text
(
'
$expectedMaxLines
'
),
findsOneWidget
);
expect
(
parserCalled
,
isTrue
);
parserCalled
=
false
;
expectedMaxLines
=
2
;
await
tester
.
pumpWidget
(
buildBoilerPlate
(
DefaultTextStyle
(
style:
const
TextStyle
(),
maxLines:
expectedMaxLines
,
child:
router
,
),
));
await
tester
.
pump
();
expect
(
find
.
text
(
'
$expectedMaxLines
'
),
findsOneWidget
);
expect
(
parserCalled
,
isTrue
);
});
testWidgets
(
'RouterInformationParser can look up dependencies without reparsing'
,
(
WidgetTester
tester
)
async
{
final
SimpleRouteInformationProvider
provider
=
SimpleRouteInformationProvider
();
provider
.
value
=
const
RouteInformation
(
location:
'initial'
,
);
final
BackButtonDispatcher
dispatcher
=
RootBackButtonDispatcher
();
const
int
expectedMaxLines
=
1
;
bool
parserCalled
=
false
;
final
Widget
router
=
Router
<
RouteInformation
>(
routeInformationProvider:
provider
,
routeInformationParser:
CustomRouteInformationParser
((
RouteInformation
information
,
BuildContext
context
)
{
parserCalled
=
true
;
final
DefaultTextStyle
style
=
context
.
getElementForInheritedWidgetOfExactType
<
DefaultTextStyle
>()!.
widget
as
DefaultTextStyle
;
return
RouteInformation
(
location:
'
${style.maxLines}
'
);
}),
routerDelegate:
SimpleRouterDelegate
(
builder:
(
BuildContext
context
,
RouteInformation
?
information
)
{
return
Text
(
information
!.
location
!);
},
onPopRoute:
()
{
provider
.
value
=
const
RouteInformation
(
location:
'popped'
,
);
return
SynchronousFuture
<
bool
>(
true
);
},
),
backButtonDispatcher:
dispatcher
,
);
await
tester
.
pumpWidget
(
buildBoilerPlate
(
DefaultTextStyle
(
style:
const
TextStyle
(),
maxLines:
expectedMaxLines
,
child:
router
,
),
));
expect
(
find
.
text
(
'
$expectedMaxLines
'
),
findsOneWidget
);
expect
(
parserCalled
,
isTrue
);
parserCalled
=
false
;
const
int
newMaxLines
=
2
;
// This rebuild should not trigger re-parsing.
await
tester
.
pumpWidget
(
buildBoilerPlate
(
DefaultTextStyle
(
style:
const
TextStyle
(),
maxLines:
newMaxLines
,
child:
router
,
),
));
await
tester
.
pump
();
expect
(
find
.
text
(
'
$newMaxLines
'
),
findsNothing
);
expect
(
find
.
text
(
'
$expectedMaxLines
'
),
findsOneWidget
);
expect
(
parserCalled
,
isFalse
);
});
testWidgets
(
'Looks up dependencies in RouterDelegate does not trigger re-parsing'
,
(
WidgetTester
tester
)
async
{
final
SimpleRouteInformationProvider
provider
=
SimpleRouteInformationProvider
();
provider
.
value
=
const
RouteInformation
(
location:
'initial'
,
);
final
BackButtonDispatcher
dispatcher
=
RootBackButtonDispatcher
();
int
expectedMaxLines
=
1
;
bool
parserCalled
=
false
;
final
Widget
router
=
Router
<
RouteInformation
>(
routeInformationProvider:
provider
,
routeInformationParser:
CustomRouteInformationParser
((
RouteInformation
information
,
BuildContext
context
)
{
parserCalled
=
true
;
return
information
;
}),
routerDelegate:
SimpleRouterDelegate
(
builder:
(
BuildContext
context
,
RouteInformation
?
information
)
{
final
DefaultTextStyle
style
=
DefaultTextStyle
.
of
(
context
);
return
Text
(
'
${style.maxLines}
'
);
},
onPopRoute:
()
{
provider
.
value
=
const
RouteInformation
(
location:
'popped'
,
);
return
SynchronousFuture
<
bool
>(
true
);
},
),
backButtonDispatcher:
dispatcher
,
);
await
tester
.
pumpWidget
(
buildBoilerPlate
(
DefaultTextStyle
(
style:
const
TextStyle
(),
maxLines:
expectedMaxLines
,
child:
router
,
),
));
expect
(
find
.
text
(
'
$expectedMaxLines
'
),
findsOneWidget
);
// Initial route will be parsed regardless.
expect
(
parserCalled
,
isTrue
);
parserCalled
=
false
;
expectedMaxLines
=
2
;
await
tester
.
pumpWidget
(
buildBoilerPlate
(
DefaultTextStyle
(
style:
const
TextStyle
(),
maxLines:
expectedMaxLines
,
child:
router
,
),
));
await
tester
.
pump
();
expect
(
find
.
text
(
'
$expectedMaxLines
'
),
findsOneWidget
);
expect
(
parserCalled
,
isFalse
);
});
}
Widget
buildBoilerPlate
(
Widget
child
)
{
...
...
@@ -1322,6 +1484,7 @@ typedef SimpleRouterDelegateBuilder = Widget Function(BuildContext, RouteInforma
typedef
SimpleRouterDelegatePopRoute
=
Future
<
bool
>
Function
();
typedef
SimpleNavigatorRouterDelegatePopPage
<
T
>
=
bool
Function
(
Route
<
T
>
route
,
T
result
);
typedef
RouterReportRouterInformation
=
void
Function
(
RouteInformation
,
RouteInformationReportingType
);
typedef
CustomRouteInformationParserCallback
=
RouteInformation
Function
(
RouteInformation
,
BuildContext
);
class
SimpleRouteInformationParser
extends
RouteInformationParser
<
RouteInformation
>
{
SimpleRouteInformationParser
();
...
...
@@ -1337,6 +1500,22 @@ class SimpleRouteInformationParser extends RouteInformationParser<RouteInformati
}
}
class
CustomRouteInformationParser
extends
RouteInformationParser
<
RouteInformation
>
{
const
CustomRouteInformationParser
(
this
.
callback
);
final
CustomRouteInformationParserCallback
callback
;
@override
Future
<
RouteInformation
>
parseRouteInformationWithDependencies
(
RouteInformation
information
,
BuildContext
context
)
{
return
SynchronousFuture
<
RouteInformation
>(
callback
(
information
,
context
));
}
@override
RouteInformation
restoreRouteInformation
(
RouteInformation
configuration
)
{
return
configuration
;
}
}
class
SimpleRouterDelegate
extends
RouterDelegate
<
RouteInformation
>
with
ChangeNotifier
{
SimpleRouterDelegate
({
this
.
builder
,
...
...
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