Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
3 changes: 3 additions & 0 deletions packages/go_router/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 4.2.0

- Adds `void replace()` and `replaceNamed` to `GoRouterDelegate`, `GoRouter` and `GoRouterHelper`.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: add an empty line between two versions

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops sorry for that, I added that in 8ec9776

## 4.1.1

- Fixes a bug where calling namedLocation does not support case-insensitive way.
Expand Down
29 changes: 29 additions & 0 deletions packages/go_router/lib/go_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,35 @@ extension GoRouterHelper on BuildContext {
extra: extra,
);

/// Replaces the top-most page of the page stack with the given URL location
/// w/ optional query parameters, e.g. `/family/f2/person/p1?color=blue`.
///
/// See also:
/// * [go] which navigates to the location.
/// * [push] which pushes the location onto the page stack.
void replace(String location, {Object? extra}) =>
GoRouter.of(this).replace(location, extra: extra);

/// Replaces the top-most page of the page stack with the named route w/
/// optional parameters, e.g. `name='person', params={'fid': 'f2', 'pid':
/// 'p1'}`.
///
/// See also:
/// * [goNamed] which navigates a named route.
/// * [pushNamed] which pushes a named route onto the page stack.
void replaceNamed(
String name, {
Map<String, String> params = const <String, String>{},
Map<String, String> queryParams = const <String, String>{},
Object? extra,
}) =>
GoRouter.of(this).replaceNamed(
name,
params: params,
queryParams: queryParams,
extra: extra,
);

/// Returns `true` if there is more than 1 page on the stack.
bool canPop() => GoRouter.of(this).canPop();

Expand Down
35 changes: 35 additions & 0 deletions packages/go_router/lib/src/go_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,41 @@ class GoRouter extends ChangeNotifier with NavigatorObserver {
extra: extra,
);

/// Replaces the top-most page of the page stack with the given URL location
/// w/ optional query parameters, e.g. `/family/f2/person/p1?color=blue`.
///
/// See also:
/// * [go] which navigates to the location.
/// * [push] which pushes the location onto the page stack.
void replace(String location, {Object? extra}) {
routeInformationParser
.parseRouteInformation(
DebugGoRouteInformation(location: location, state: extra),
)
.then<void>((List<GoRouteMatch> matches) {
routerDelegate.replace(matches.last);
});
}

/// Replaces the top-most page of the page stack with the named route w/
/// optional parameters, e.g. `name='person', params={'fid': 'f2', 'pid':
/// 'p1'}`.
///
/// See also:
/// * [goNamed] which navigates a named route.
/// * [pushNamed] which pushes a named route onto the page stack.
void replaceNamed(
String name, {
Map<String, String> params = const <String, String>{},
Map<String, String> queryParams = const <String, String>{},
Object? extra,
}) {
replace(
namedLocation(name, params: params, queryParams: queryParams),
extra: extra,
);
}

/// Returns `true` if there is more than 1 page on the stack.
bool canPop() => routerDelegate.canPop();

Expand Down
9 changes: 9 additions & 0 deletions packages/go_router/lib/src/go_router_delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ class GoRouterDelegate extends RouterDelegate<List<GoRouteMatch>>
notifyListeners();
}

/// Replaces the top-most page of the page stack with the given one.
///
/// See also:
/// * [push] which pushes the given location onto the page stack.
void replace(GoRouteMatch match) {
_matches.last = match;
notifyListeners();
}

/// Returns `true` if there is more than 1 page on the stack.
bool canPop() {
return _matches.length > 1;
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: 4.1.1
version: 4.2.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
46 changes: 46 additions & 0 deletions packages/go_router/test/go_router_delegate_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,52 @@ void main() {
);
});

group('replace', () {
Copy link
Contributor

Choose a reason for hiding this comment

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

consider adding a test for replaceNamed too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added a test for replaceNamed in 44e35ef Tell me what you think about it

testWidgets(
'It should replace the last match with the given one',
(WidgetTester tester) async {
final GoRouter goRouter = GoRouter(
initialLocation: '/',
routes: <GoRoute>[
GoRoute(path: '/', builder: (_, __) => const SizedBox()),
GoRoute(path: '/page-0', builder: (_, __) => const SizedBox()),
GoRoute(path: '/page-1', builder: (_, __) => const SizedBox()),
],
);
await tester.pumpWidget(
MaterialApp.router(
routeInformationProvider: goRouter.routeInformationProvider,
routeInformationParser: goRouter.routeInformationParser,
routerDelegate: goRouter.routerDelegate,
),
);

goRouter.push('/page-0');

goRouter.routerDelegate.addListener(expectAsync0(() {}));
final GoRouteMatch first = goRouter.routerDelegate.matches.first;
final GoRouteMatch last = goRouter.routerDelegate.matches.last;
goRouter.replace('/page-1');
expect(goRouter.routerDelegate.matches.length, 2);
expect(
goRouter.routerDelegate.matches.first,
first,
reason: 'The first match should still be in the list of matches',
);
expect(
goRouter.routerDelegate.matches.last,
isNot(last),
reason: 'The last match should have been removed',
);
expect(
goRouter.routerDelegate.matches.last.fullpath,
'/page-1',
reason: 'The new location should have been pushed',
);
},
);
});

testWidgets('dispose unsubscribes from refreshListenable',
(WidgetTester tester) async {
final FakeRefreshListenable refreshListenable = FakeRefreshListenable();
Expand Down