Skip to content

Commit 31d0358

Browse files
committed
Add support for relative routes
1 parent 34948d1 commit 31d0358

21 files changed

+968
-70
lines changed

packages/go_router_builder/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## NEXT
1+
## 3.0.2
22

3+
- Adds support for `TypedRelativeGoRoute`.
34
- Restricts `build` to versions less than 2.5.0.
45

56
## 3.0.1

packages/go_router_builder/README.md

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

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

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

458485
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)