Skip to content

Commit 8cf6f38

Browse files
committed
Add support for relative routes
1 parent 6a12043 commit 8cf6f38

21 files changed

+979
-88
lines changed

packages/go_router_builder/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 3.3.0
2+
3+
- Adds support for `TypedRelativeGoRoute`.
4+
15
## 3.2.1
26

37
- Changes generated whitespace for better compatibility with new Dart formatter.

packages/go_router_builder/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,33 @@ class MyGoRouteData extends GoRouteData with _$MyGoRouteData {
455455

456456
An example is available [here](https://github.com/flutter/packages/blob/main/packages/go_router_builder/example/lib/shell_route_with_keys_example.dart).
457457

458+
## Relative routes
459+
460+
Define a relative route by extending RelativeGoRouteData.
461+
462+
<?code-excerpt "example/lib/readme_excerpts.dart (relativeRoute)"?>
463+
```dart
464+
@TypedRelativeGoRoute<DetailsRoute>(
465+
path: 'details',
466+
)
467+
class DetailsRoute extends RelativeGoRouteData with _$DetailsRoute {
468+
const DetailsRoute();
469+
470+
@override
471+
Widget build(BuildContext context, GoRouterState state) =>
472+
const DetailsScreen();
473+
}
474+
```
475+
476+
Navigate using the `goRelative` or `pushRelative` methods provided by the code generator:
477+
478+
<?code-excerpt "example/lib/readme_excerpts.dart (goRelative)"?>
479+
```dart
480+
void onTapRelative() => const DetailsRoute().goRelative(context);
481+
```
482+
483+
Relative routing methods are not idempotent and will cause an error when the relative location does not match a route.
484+
458485
## Run tests
459486

460487
To run unit tests, run command `dart tool/run_tests.dart` from `packages/go_router_builder/`.
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// ignore_for_file: public_member_api_docs, unreachable_from_main
6+
7+
import 'package:flutter/material.dart';
8+
import 'package:go_router/go_router.dart';
9+
10+
part 'go_relative.g.dart';
11+
12+
void main() => runApp(const MyApp());
13+
14+
/// The main app.
15+
class MyApp extends StatelessWidget {
16+
/// Constructs a [MyApp]
17+
const MyApp({super.key});
18+
19+
@override
20+
Widget build(BuildContext context) {
21+
return MaterialApp.router(
22+
routerConfig: _router,
23+
);
24+
}
25+
}
26+
27+
/// The route configuration.
28+
final GoRouter _router = GoRouter(
29+
routes: $appRoutes,
30+
);
31+
const TypedRelativeGoRoute<DetailsRoute> detailRoute =
32+
TypedRelativeGoRoute<DetailsRoute>(
33+
path: 'details/:detailId',
34+
routes: <TypedRoute<RouteData>>[
35+
TypedRelativeGoRoute<SettingsRoute>(path: 'settings/:settingId'),
36+
],
37+
);
38+
39+
@TypedGoRoute<HomeRoute>(
40+
path: '/',
41+
routes: <TypedRoute<RouteData>>[
42+
TypedGoRoute<DashboardRoute>(
43+
path: '/dashboard',
44+
routes: <TypedRoute<RouteData>>[detailRoute],
45+
),
46+
detailRoute,
47+
],
48+
)
49+
class HomeRoute extends GoRouteData with _$HomeRoute {
50+
@override
51+
Widget build(BuildContext context, GoRouterState state) {
52+
return const HomeScreen();
53+
}
54+
}
55+
56+
class DashboardRoute extends GoRouteData with _$DashboardRoute {
57+
@override
58+
Widget build(BuildContext context, GoRouterState state) {
59+
return const DashboardScreen();
60+
}
61+
}
62+
63+
class DetailsRoute extends RelativeGoRouteData with _$DetailsRoute {
64+
const DetailsRoute({required this.detailId});
65+
final String detailId;
66+
67+
@override
68+
Widget build(BuildContext context, GoRouterState state) {
69+
return DetailsScreen(id: detailId);
70+
}
71+
}
72+
73+
class SettingsRoute extends RelativeGoRouteData with _$SettingsRoute {
74+
const SettingsRoute({
75+
required this.settingId,
76+
});
77+
final String settingId;
78+
79+
@override
80+
Widget build(BuildContext context, GoRouterState state) {
81+
return SettingsScreen(id: settingId);
82+
}
83+
}
84+
85+
/// The home screen
86+
class HomeScreen extends StatelessWidget {
87+
/// Constructs a [HomeScreen]
88+
const HomeScreen({super.key});
89+
90+
@override
91+
Widget build(BuildContext context) {
92+
return Scaffold(
93+
appBar: AppBar(title: const Text('Home Screen')),
94+
body: Column(
95+
mainAxisAlignment: MainAxisAlignment.center,
96+
children: <Widget>[
97+
ElevatedButton(
98+
onPressed: () {
99+
const DetailsRoute(detailId: 'DetailsId').goRelative(context);
100+
},
101+
child: const Text('Go to the Details screen'),
102+
),
103+
ElevatedButton(
104+
onPressed: () {
105+
DashboardRoute().go(context);
106+
},
107+
child: const Text('Go to the Dashboard screen'),
108+
),
109+
],
110+
),
111+
);
112+
}
113+
}
114+
115+
/// The home screen
116+
class DashboardScreen extends StatelessWidget {
117+
/// Constructs a [DashboardScreen]
118+
const DashboardScreen({super.key});
119+
120+
@override
121+
Widget build(BuildContext context) {
122+
return Scaffold(
123+
appBar: AppBar(title: const Text('Dashboard Screen')),
124+
body: Column(
125+
children: <Widget>[
126+
ElevatedButton(
127+
onPressed: () {
128+
const DetailsRoute(detailId: 'DetailsId').goRelative(context);
129+
},
130+
child: const Text('Go to the Details screen'),
131+
),
132+
ElevatedButton(
133+
onPressed: () => context.pop(),
134+
child: const Text('Go back'),
135+
),
136+
],
137+
),
138+
);
139+
}
140+
}
141+
142+
/// The details screen
143+
class DetailsScreen extends StatelessWidget {
144+
/// Constructs a [DetailsScreen]
145+
const DetailsScreen({
146+
super.key,
147+
required this.id,
148+
});
149+
150+
final String id;
151+
152+
@override
153+
Widget build(BuildContext context) {
154+
return Scaffold(
155+
appBar: AppBar(title: Text('Details Screen $id')),
156+
body: Center(
157+
child: Column(
158+
children: <Widget>[
159+
ElevatedButton(
160+
onPressed: () => context.pop(),
161+
child: const Text('Go back'),
162+
),
163+
ElevatedButton(
164+
onPressed: () => const SettingsRoute(
165+
settingId: 'SettingsId',
166+
).goRelative(context),
167+
child: const Text('Go to the Settings screen'),
168+
),
169+
],
170+
),
171+
),
172+
);
173+
}
174+
}
175+
176+
/// The details screen
177+
class SettingsScreen extends StatelessWidget {
178+
/// Constructs a [SettingsScreen]
179+
const SettingsScreen({
180+
super.key,
181+
required this.id,
182+
});
183+
184+
final String id;
185+
186+
@override
187+
Widget build(BuildContext context) {
188+
return Scaffold(
189+
appBar: AppBar(title: Text('Settings Screen $id')),
190+
body: Center(
191+
child: TextButton(
192+
onPressed: () => context.pop(),
193+
child: const Text('Go back'),
194+
),
195+
),
196+
);
197+
}
198+
}

packages/go_router_builder/example/lib/go_relative.g.dart

Lines changed: 152 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)