Skip to content

Commit 8477d62

Browse files
kevmoochunhtai
andauthored
[go_router]Add pkg:go_router_builder (flutter#1551)
Make corresponding changes to pkg:go_router Fixes flutter/flutter#99127 Co-authored-by: chunhtai <[email protected]>
1 parent c174f35 commit 8477d62

35 files changed

+2625
-4
lines changed

packages/go_router/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 3.1.0
2+
3+
- Added `GoRouteData` and `TypedGoRoute` to support `package:go_router_builder`.
4+
15
## 3.0.7
26

37
- Refactors runtime checks to assertions.

packages/go_router/lib/go_router.dart

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export 'src/go_router.dart';
1616
export 'src/go_router_refresh_stream.dart';
1717
export 'src/go_router_state.dart';
1818
export 'src/inherited_go_router.dart';
19+
export 'src/route_data.dart' show GoRouteData, TypedGoRoute;
1920
export 'src/typedefs.dart' show GoRouterPageBuilder, GoRouterRedirect;
2021
export 'src/url_path_strategy.dart';
2122

packages/go_router/lib/src/go_router_delegate.dart

+12-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import 'go_router_error_page.dart';
1515
import 'go_router_material.dart';
1616
import 'go_router_state.dart';
1717
import 'logging.dart';
18+
import 'route_data.dart';
1819
import 'typedefs.dart';
1920

2021
/// GoRouter implementation of the RouterDelegate base class.
@@ -746,9 +747,17 @@ class GoRouterDelegate extends RouterDelegate<Uri>
746747
pageKey: match.pageKey, // push() remaps the page key for uniqueness
747748
);
748749

749-
yield match.route.pageBuilder != null
750-
? match.route.pageBuilder!(context, state)
751-
: _pageBuilder(context, state, match.route.builder);
750+
final GoRouterPageBuilder? pageBuilder = match.route.pageBuilder;
751+
752+
Page<dynamic>? page;
753+
if (pageBuilder != null) {
754+
page = pageBuilder(context, state);
755+
if (page is NoOpPage) {
756+
page = null;
757+
}
758+
}
759+
760+
yield page ?? _pageBuilder(context, state, match.route.builder);
752761
}
753762
}
754763

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
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+
import 'package:flutter/widgets.dart';
6+
import 'package:meta/meta.dart';
7+
import 'package:meta/meta_meta.dart';
8+
9+
import 'go_route.dart';
10+
import 'go_router_state.dart';
11+
12+
/// Baseclass for supporting
13+
/// [typed routing](https://gorouter.dev/typed-routing).
14+
///
15+
/// Subclasses must override one of [build], [buildPage], or [redirect].
16+
abstract class GoRouteData {
17+
/// Allows subclasses to have `const` constructors.
18+
///
19+
/// [GoRouteData] is abstract and cannot be instantiated directly.
20+
const GoRouteData();
21+
22+
/// Creates the [Widget] for `this` route.
23+
///
24+
/// Subclasses must override one of [build], [buildPage], or [redirect].
25+
///
26+
/// Corresponds to [GoRoute.builder].
27+
Widget build(BuildContext context) => throw UnimplementedError(
28+
'One of `build` or `buildPage` must be implemented.',
29+
);
30+
31+
/// A page builder for this route.
32+
///
33+
/// Subclasses can override this function to provide a custom [Page].
34+
///
35+
/// Subclasses must override one of [build], [buildPage], or [redirect].
36+
///
37+
/// Corresponds to [GoRoute.pageBuilder].
38+
///
39+
/// By default, returns a [Page] instance that is ignored, causing a default
40+
/// [Page] implementation to be used with the results of [build].
41+
Page<void> buildPage(BuildContext context) => const NoOpPage();
42+
43+
/// An optional redirect function for this route.
44+
///
45+
/// Subclasses must override one of [build], [buildPage], or [redirect].
46+
///
47+
/// Corresponds to [GoRoute.redirect].
48+
String? redirect() => null;
49+
50+
/// A helper function used by generated code.
51+
///
52+
/// Should not be used directly.
53+
static String $location(String path, {Map<String, String>? queryParams}) =>
54+
Uri.parse(path)
55+
.replace(
56+
queryParameters:
57+
// Avoid `?` in generated location if `queryParams` is empty
58+
queryParams?.isNotEmpty == true ? queryParams : null,
59+
)
60+
.toString();
61+
62+
/// A helper function used by generated code.
63+
///
64+
/// Should not be used directly.
65+
static GoRoute $route<T extends GoRouteData>({
66+
required String path,
67+
required T Function(GoRouterState) factory,
68+
List<GoRoute> routes = const <GoRoute>[],
69+
}) {
70+
T factoryImpl(GoRouterState state) {
71+
final Object? extra = state.extra;
72+
73+
// If the "extra" value is of type `T` then we know it's the source
74+
// instance of `GoRouteData`, so it doesn't need to be recreated.
75+
if (extra is T) {
76+
return extra;
77+
}
78+
79+
return (_stateObjectExpando[state] ??= factory(state)) as T;
80+
}
81+
82+
Widget builder(BuildContext context, GoRouterState state) =>
83+
factoryImpl(state).build(context);
84+
85+
Page<void> pageBuilder(BuildContext context, GoRouterState state) =>
86+
factoryImpl(state).buildPage(context);
87+
88+
String? redirect(GoRouterState state) => factoryImpl(state).redirect();
89+
90+
return GoRoute(
91+
path: path,
92+
builder: builder,
93+
pageBuilder: pageBuilder,
94+
redirect: redirect,
95+
routes: routes,
96+
);
97+
}
98+
99+
/// Used to cache [GoRouteData] that corresponds to a given [GoRouterState]
100+
/// to minimize the number of times it has to be deserialized.
101+
static final Expando<GoRouteData> _stateObjectExpando = Expando<GoRouteData>(
102+
'GoRouteState to GoRouteData expando',
103+
);
104+
}
105+
106+
/// Annotation for types that support typed routing.
107+
@Target(<TargetKind>{TargetKind.library, TargetKind.classType})
108+
class TypedGoRoute<T extends GoRouteData> {
109+
/// Instantiates a new instance of [TypedGoRoute].
110+
const TypedGoRoute({
111+
required this.path,
112+
this.routes = const <TypedGoRoute<GoRouteData>>[],
113+
});
114+
115+
/// The path that corresponds to this rout.
116+
///
117+
/// See [GoRoute.path].
118+
final String path;
119+
120+
/// Child route definitions.
121+
///
122+
/// See [GoRoute.routes].
123+
final List<TypedGoRoute<GoRouteData>> routes;
124+
}
125+
126+
/// Internal class used to signal that the default page behavior should be used.
127+
@internal
128+
class NoOpPage extends Page<void> {
129+
/// Creates an instance of NoOpPage;
130+
const NoOpPage();
131+
132+
@override
133+
Route<void> createRoute(BuildContext context) =>
134+
throw UnsupportedError('Should never be called');
135+
}

packages/go_router/pubspec.yaml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: go_router
22
description: A declarative router for Flutter based on Navigation 2 supporting
33
deep linking, data-driven routes and more
4-
version: 3.0.7
4+
version: 3.1.0
55
repository: https://github.com/flutter/packages/tree/main/packages/go_router
66
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22
77

@@ -16,6 +16,7 @@ dependencies:
1616
flutter_web_plugins:
1717
sdk: flutter
1818
logging: ^1.0.0
19+
meta: ^1.7.0
1920

2021
dev_dependencies:
2122
flutter_test:

packages/go_router_builder/AUTHORS

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Below is a list of people and organizations that have contributed
2+
# to the Flutter project. Names should be added to the list like so:
3+
#
4+
# Name/Organization <email address>
5+
6+
Google Inc.
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
### 1.0.0
2+
3+
- First release.

packages/go_router_builder/LICENSE

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Copyright 2013 The Flutter Authors. All rights reserved.
2+
3+
Redistribution and use in source and binary forms, with or without modification,
4+
are permitted provided that the following conditions are met:
5+
6+
* Redistributions of source code must retain the above copyright
7+
notice, this list of conditions and the following disclaimer.
8+
* Redistributions in binary form must reproduce the above
9+
copyright notice, this list of conditions and the following
10+
disclaimer in the documentation and/or other materials provided
11+
with the distribution.
12+
* Neither the name of Google Inc. nor the names of its
13+
contributors may be used to endorse or promote products derived
14+
from this software without specific prior written permission.
15+
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

0 commit comments

Comments
 (0)