Skip to content

Return value when pop #3368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f74ad0d
Return value when pop
NazarenoCavazzon Mar 3, 2023
72db2d6
Merge branch 'main' into feat/return-value-when-pop
NazarenoCavazzon Mar 3, 2023
ba08b81
Fixes
NazarenoCavazzon Mar 3, 2023
845dfbd
Removed unnecessary completer
NazarenoCavazzon Mar 3, 2023
0105de8
removed addPostFrameCallback from docs
NazarenoCavazzon Mar 3, 2023
4a6352c
Moved implementation to ImperativeRouteMatch
NazarenoCavazzon Mar 3, 2023
ecee639
Documented complete() method
NazarenoCavazzon Mar 3, 2023
98e1216
Changes
NazarenoCavazzon Mar 3, 2023
1b5e37b
Update delegate.dart
NazarenoCavazzon Mar 3, 2023
b734714
Update go_router_test.dart
NazarenoCavazzon Mar 3, 2023
ba99cc5
Merge branch 'main' into feat/return-value-when-pop
NazarenoCavazzon Mar 3, 2023
9b556a3
Last fixes
NazarenoCavazzon Mar 3, 2023
8d34c15
Update match.dart
NazarenoCavazzon Mar 3, 2023
0f0eafc
Update packages/go_router/CHANGELOG.md
NazarenoCavazzon Mar 4, 2023
77f6ab9
Merge branch 'main' into feat/return-value-when-pop
NazarenoCavazzon Mar 6, 2023
251966a
Merge branch 'main' into feat/return-value-when-pop
NazarenoCavazzon Mar 9, 2023
ed87847
Merge branch 'main' into feat/return-value-when-pop
NazarenoCavazzon Mar 20, 2023
1661569
Merge branch 'main' into feat/return-value-when-pop
NazarenoCavazzon Mar 23, 2023
c3ed204
Update version to 6.5.0
NazarenoCavazzon Mar 23, 2023
02a4f5c
Updated from main
NazarenoCavazzon Mar 23, 2023
a44a5cc
Merge branch 'main' into feat/return-value-when-pop
NazarenoCavazzon Mar 23, 2023
801c7c6
Type annotations
NazarenoCavazzon Mar 23, 2023
5d88336
Update router.dart
NazarenoCavazzon Mar 23, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/go_router/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 6.5.0

- Supports returning values on pop.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please publish a new version

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to 6.5.0

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the conflict is back :(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I'm resolving them rn

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything is a mess hahahaha, I'll rebase it to main and made the implementation again 🙃

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chunhtai now there shouldn't be any more conflicts


## 6.4.1
- Adds `initialExtra` to **GoRouter** to pass extra data alongside `initialRoute`.

Expand All @@ -22,6 +26,7 @@

- Adds `GoRouter.maybeOf` to get the closest `GoRouter` from the context, if there is any.


## 6.0.10

- Adds helpers for go_router_builder for ShellRoute support
Expand Down
17 changes: 17 additions & 0 deletions packages/go_router/doc/navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,21 @@ Navigator.of(context).push(
);
```

## Returning values
Waiting for a value to be returned:

```dart
onTap: () {
final bool? result = await context.push<bool>('/page2');
if(result ?? false)...
}
```

Returning a value:

```dart
onTap: () => context.pop(true)
```


[Named routes]: https://pub.dev/documentation/go_router/latest/topics/Named%20routes-topic.html
28 changes: 22 additions & 6 deletions packages/go_router/lib/src/delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,9 @@ class GoRouterDelegate extends RouterDelegate<RouteMatchList>
return ValueKey<String>('$path-p$count');
}

void _push(RouteMatchList matches, ValueKey<String> pageKey) {
final ImperativeRouteMatch newPageKeyMatch = ImperativeRouteMatch(
Future<T?> _push<T extends Object?>(
RouteMatchList matches, ValueKey<String> pageKey) async {
final ImperativeRouteMatch<T> newPageKeyMatch = ImperativeRouteMatch<T>(
route: matches.last.route,
subloc: matches.last.subloc,
extra: matches.last.extra,
Expand All @@ -93,6 +94,7 @@ class GoRouterDelegate extends RouterDelegate<RouteMatchList>
);

_matchList.push(newPageKeyMatch);
return newPageKeyMatch._future;
}

/// Pushes the given location onto the page stack.
Expand All @@ -103,12 +105,13 @@ class GoRouterDelegate extends RouterDelegate<RouteMatchList>
/// * [replace] which replaces the top-most page of the page stack but treats
/// it as the same page. The page key will be reused. This will preserve the
/// state and not run any page animation.
void push(RouteMatchList matches) {
Future<T?> push<T extends Object?>(RouteMatchList matches) async {
assert(matches.last.route is! ShellRoute);

final ValueKey<String> pageKey = _getNewKeyForPath(matches.fullpath);
_push(matches, pageKey);
final Future<T?> future = _push(matches, pageKey);
notifyListeners();
return future;
}

/// Returns `true` if the active Navigator can pop.
Expand All @@ -127,6 +130,7 @@ class GoRouterDelegate extends RouterDelegate<RouteMatchList>
final _NavigatorStateIterator iterator = _createNavigatorStateIterator();
while (iterator.moveNext()) {
if (iterator.current.canPop()) {
iterator.matchList.last.complete(result);
iterator.current.pop<T>(result);
return;
}
Expand Down Expand Up @@ -308,7 +312,7 @@ class _NavigatorStateIterator extends Iterator<NavigatorState> {

/// The route match that represent route pushed through [GoRouter.push].
// TODO(chunhtai): Removes this once imperative API no longer insert route match.
class ImperativeRouteMatch extends RouteMatch {
class ImperativeRouteMatch<T> extends RouteMatch {
/// Constructor for [ImperativeRouteMatch].
ImperativeRouteMatch({
required super.route,
Expand All @@ -317,8 +321,20 @@ class ImperativeRouteMatch extends RouteMatch {
required super.error,
required super.pageKey,
required this.matches,
});
}) : _completer = Completer<T?>();

/// The matches that produces this route match.
final RouteMatchList matches;

/// The completer for the future returned by [GoRouter.push].
final Completer<T?> _completer;

@override
void complete([dynamic value]) {
_completer.complete(value as T?);
}

/// The future of the [RouteMatch] completer.
/// When the future completes, this will return the value passed to [complete].
Future<T?> get _future => _completer.future;
}
4 changes: 3 additions & 1 deletion packages/go_router/lib/src/match.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';

import 'matching.dart';
Expand Down Expand Up @@ -61,6 +60,9 @@ class RouteMatch {
throw MatcherError('Unexpected route type: $route', restLoc);
}

/// Called when the corresponding [Route] associated with this route match is completed.
void complete([Object? value]) {}

/// The matched route.
final RouteBase route;

Expand Down
8 changes: 4 additions & 4 deletions packages/go_router/lib/src/misc/extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,17 @@ extension GoRouterHelper on BuildContext {
/// * [replace] which replaces the top-most page of the page stack but treats
/// it as the same page. The page key will be reused. This will preserve the
/// state and not run any page animation.
void push(String location, {Object? extra}) =>
GoRouter.of(this).push(location, extra: extra);
Future<T?> push<T extends Object?>(String location, {Object? extra}) =>
GoRouter.of(this).push<T>(location, extra: extra);

/// Navigate to a named route onto the page stack.
void pushNamed(
Future<T?> pushNamed<T extends Object?>(
String name, {
Map<String, String> params = const <String, String>{},
Map<String, dynamic> queryParams = const <String, dynamic>{},
Object? extra,
}) =>
GoRouter.of(this).pushNamed(
GoRouter.of(this).pushNamed<T>(
name,
params: params,
queryParams: queryParams,
Expand Down
2 changes: 1 addition & 1 deletion packages/go_router/lib/src/parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class GoRouteInformationParser extends RouteInformationParser<RouteMatchList> {
}
if (configuration.matches.last is ImperativeRouteMatch) {
configuration =
(configuration.matches.last as ImperativeRouteMatch).matches;
(configuration.matches.last as ImperativeRouteMatch<Object?>).matches;
}
return RouteInformation(
location: configuration.uri.toString(),
Expand Down
19 changes: 9 additions & 10 deletions packages/go_router/lib/src/router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ class GoRouter extends ChangeNotifier implements RouterConfig<RouteMatchList> {
routerDelegate.currentConfiguration.matches.last
is ImperativeRouteMatch) {
newLocation = (routerDelegate.currentConfiguration.matches.last
as ImperativeRouteMatch)
as ImperativeRouteMatch<Object?>)
.matches
.uri
.toString();
Expand Down Expand Up @@ -219,32 +219,31 @@ class GoRouter extends ChangeNotifier implements RouterConfig<RouteMatchList> {
/// * [replace] which replaces the top-most page of the page stack but treats
/// it as the same page. The page key will be reused. This will preserve the
/// state and not run any page animation.
void push(String location, {Object? extra}) {
Future<T?> push<T extends Object?>(String location, {Object? extra}) async {
assert(() {
log.info('pushing $location');
return true;
}());
_routeInformationParser
.parseRouteInformationWithDependencies(
final RouteMatchList matches =
await _routeInformationParser.parseRouteInformationWithDependencies(
RouteInformation(location: location, state: extra),
// TODO(chunhtai): avoid accessing the context directly through global key.
// https://github.com/flutter/flutter/issues/99112
_routerDelegate.navigatorKey.currentContext!,
)
.then<void>((RouteMatchList matches) {
_routerDelegate.push(matches);
});
);

return _routerDelegate.push<T>(matches);
}

/// Push a named route onto the page stack w/ optional parameters, e.g.
/// `name='person', params={'fid': 'f2', 'pid': 'p1'}`
void pushNamed(
Future<T?> pushNamed<T extends Object?>(
String name, {
Map<String, String> params = const <String, String>{},
Map<String, dynamic> queryParams = const <String, dynamic>{},
Object? extra,
}) =>
push(
push<T>(
namedLocation(name, params: params, queryParams: queryParams),
extra: extra,
);
Expand Down
2 changes: 1 addition & 1 deletion packages/go_router/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: go_router
description: A declarative router for Flutter based on Navigation 2 supporting
deep linking, data-driven routes and more
version: 6.4.1
version: 6.5.0
repository: https://github.com/flutter/packages/tree/main/packages/go_router
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22

Expand Down
6 changes: 3 additions & 3 deletions packages/go_router/test/delegate_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ void main() {
reason: 'The last match should have been removed',
);
expect(
(goRouter.routerDelegate.matches.last as ImperativeRouteMatch)
(goRouter.routerDelegate.matches.last as ImperativeRouteMatch<Object?>)
.matches
.uri
.toString(),
Expand Down Expand Up @@ -270,7 +270,7 @@ void main() {
reason: 'The last match should have been removed',
);
expect(
(goRouter.routerDelegate.matches.last as ImperativeRouteMatch)
(goRouter.routerDelegate.matches.last as ImperativeRouteMatch<Object?>)
.matches
.uri
.toString(),
Expand Down Expand Up @@ -393,7 +393,7 @@ void main() {
reason: 'The last match should have been removed',
);
expect(
(goRouter.routerDelegate.matches.last as ImperativeRouteMatch)
(goRouter.routerDelegate.matches.last as ImperativeRouteMatch<Object?>)
.matches
.uri
.toString(),
Expand Down
48 changes: 46 additions & 2 deletions packages/go_router/test/go_router_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2439,8 +2439,8 @@ void main() {
expect(router.location, loc);
expect(matches.matches, hasLength(2));
expect(find.byType(PersonScreen), findsOneWidget);
final ImperativeRouteMatch imperativeRouteMatch =
matches.matches.last as ImperativeRouteMatch;
final ImperativeRouteMatch<Object?> imperativeRouteMatch =
matches.matches.last as ImperativeRouteMatch<Object?>;
expect(imperativeRouteMatch.matches.pathParameters['fid'], fid);
expect(imperativeRouteMatch.matches.pathParameters['pid'], pid);
});
Expand Down Expand Up @@ -2698,6 +2698,26 @@ void main() {
expect(router.extra, extra);
});

testWidgets('calls [push] on closest GoRouter and waits for result',
(WidgetTester tester) async {
final GoRouterPushSpy router = GoRouterPushSpy(routes: routes);
await tester.pumpWidget(
MaterialApp.router(
routeInformationProvider: router.routeInformationProvider,
routeInformationParser: router.routeInformationParser,
routerDelegate: router.routerDelegate,
title: 'GoRouter Example',
),
);
final String? result = await router.push<String>(
location,
extra: extra,
);
expect(result, extra);
expect(router.myLocation, location);
expect(router.extra, extra);
});

testWidgets('calls [pushNamed] on closest GoRouter',
(WidgetTester tester) async {
final GoRouterPushNamedSpy router = GoRouterPushNamedSpy(routes: routes);
Expand All @@ -2719,6 +2739,30 @@ void main() {
expect(router.extra, extra);
});

testWidgets('calls [pushNamed] on closest GoRouter and waits for result',
(WidgetTester tester) async {
final GoRouterPushNamedSpy router = GoRouterPushNamedSpy(routes: routes);
await tester.pumpWidget(
MaterialApp.router(
routeInformationProvider: router.routeInformationProvider,
routeInformationParser: router.routeInformationParser,
routerDelegate: router.routerDelegate,
title: 'GoRouter Example',
),
);
final String? result = await router.pushNamed<String>(
name,
params: params,
queryParams: queryParams,
extra: extra,
);
expect(result, extra);
expect(router.extra, extra);
expect(router.name, name);
expect(router.params, params);
expect(router.queryParams, queryParams);
});

testWidgets('calls [pop] on closest GoRouter', (WidgetTester tester) async {
final GoRouterPopSpy router = GoRouterPopSpy(routes: routes);
await tester.pumpWidget(
Expand Down
3 changes: 2 additions & 1 deletion packages/go_router/test/inherited_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,12 @@ class MockGoRouter extends GoRouter {
late String latestPushedName;

@override
void pushNamed(String name,
Future<T?> pushNamed<T extends Object?>(String name,
{Map<String, String> params = const <String, String>{},
Map<String, dynamic> queryParams = const <String, dynamic>{},
Object? extra}) {
latestPushedName = name;
return Future<T?>.value();
}

@override
Expand Down
6 changes: 4 additions & 2 deletions packages/go_router/test/test_helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,10 @@ class GoRouterPushSpy extends GoRouter {
Object? extra;

@override
void push(String location, {Object? extra}) {
Future<T?> push<T extends Object?>(String location, {Object? extra}) {
myLocation = location;
this.extra = extra;
return Future<T?>.value(extra as T?);
}
}

Expand All @@ -110,7 +111,7 @@ class GoRouterPushNamedSpy extends GoRouter {
Object? extra;

@override
void pushNamed(
Future<T?> pushNamed<T extends Object?>(
String name, {
Map<String, String> params = const <String, String>{},
Map<String, dynamic> queryParams = const <String, dynamic>{},
Expand All @@ -120,6 +121,7 @@ class GoRouterPushNamedSpy extends GoRouter {
this.params = params;
this.queryParams = queryParams;
this.extra = extra;
return Future<T?>.value(extra as T?);
}
}

Expand Down