Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
370a279
Refactor internal classes and methods
johnpryan Jul 1, 2022
aaec44a
format
johnpryan Jul 12, 2022
61fbc2d
Sort imports
johnpryan Jul 12, 2022
632b012
Update changelog
johnpryan Jul 12, 2022
40e2c61
Address code review comments
johnpryan Jul 13, 2022
61da05d
remove routing library
johnpryan Jul 14, 2022
1c2577c
Move classes in go_router.dart into separate libraries
johnpryan Jul 14, 2022
db91f56
Move Configuration.validate() into constructor
johnpryan Jul 14, 2022
1eaf6c3
Remove comment
johnpryan Jul 14, 2022
ea01665
use continue in redirect loop
johnpryan Jul 14, 2022
d4c2ff9
Fix comments
johnpryan Jul 14, 2022
199c353
Sort imports
johnpryan Jul 14, 2022
b8a65af
Fix logging in configuration
johnpryan Jul 14, 2022
85fe41d
add visibleForTesting annotation
johnpryan Jul 14, 2022
ccb8097
Merge branch 'main' into refactor
johnpryan Jul 14, 2022
e0bb4f4
Updates from merge with main
johnpryan Jul 14, 2022
4c17bba
Format
johnpryan Jul 15, 2022
8449014
Add TODOs to make Router implementation classes private
johnpryan Jul 15, 2022
9b40f1e
Add copyright headers
johnpryan Jul 15, 2022
0e14a04
Fix tests
johnpryan Jul 15, 2022
73feaa8
Merge branch 'main' into refactor
johnpryan Jul 20, 2022
e3458e6
format
johnpryan Jul 20, 2022
13bc273
fix comment
johnpryan Jul 20, 2022
2a350ad
Update packages/go_router/lib/src/parser.dart
johnpryan Jul 21, 2022
fc82dbb
add whitespace
johnpryan Jul 21, 2022
86c8961
format
johnpryan Jul 21, 2022
7f8954c
Hide typedefs that weren't previously exported
johnpryan Jul 21, 2022
fdcf0ed
Delete empty file
johnpryan Jul 21, 2022
78e60a6
add missing import
johnpryan Jul 21, 2022
26b4c12
Specify version 4.1.2 in pubspec.yaml
johnpryan Jul 21, 2022
0c5436e
Update packages/go_router/lib/src/builder.dart
johnpryan Jul 21, 2022
348697b
Fix comment
johnpryan Jul 21, 2022
77f2244
Add isError and error getters to RouteMatchList
johnpryan Jul 21, 2022
820162d
Add issue links to TODO comments
johnpryan Jul 21, 2022
07f7ada
Add link to issue for TODO
johnpryan Jul 22, 2022
686d315
Merge branch 'main' into refactor
johnpryan Jul 22, 2022
5e282d3
Re-apply code from #2306 due to merge conflicts
johnpryan Jul 22, 2022
714e682
Add issue references
johnpryan Jul 22, 2022
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
30 changes: 30 additions & 0 deletions packages/go_router/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/

# IntelliJ related
*.iml
*.ipr
*.iws
.idea/

# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/

# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.packages
build/
4 changes: 4 additions & 0 deletions packages/go_router/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 4.1.1

- Refactors internal classes and methods

## 4.1.0

- Adds `bool canPop()` to `GoRouterDelegate`, `GoRouter` and `GoRouterHelper`.
Expand Down
3 changes: 2 additions & 1 deletion packages/go_router/example/lib/router_stream_refresh.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ class _AppState extends State<App> {
return null;
},
// changes on the listenable will cause the router to refresh it's route
refreshListenable: GoRouterRefreshStream(loggedInState.stream),
// TODO(johnpryan): Change type to Stream, remove GoRouterRefreshStream
refreshListenable: StreamListenable(loggedInState.stream),
);
super.initState();
}
Expand Down
284 changes: 272 additions & 12 deletions packages/go_router/lib/go_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,284 @@
/// deep linking, data-driven routes and more
library go_router;

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

import 'src/go_router.dart';
import 'src/configuration.dart';
import 'src/logging.dart';
import 'src/matching.dart';
import 'src/platform.dart';
import 'src/routing.dart';
import 'src/typedefs.dart';

export 'src/custom_transition_page.dart';
export 'src/go_route.dart';
export 'src/go_router.dart';
export 'src/go_router_refresh_stream.dart';
export 'src/go_router_state.dart';
export 'src/inherited_go_router.dart';
export 'src/route_data.dart' show GoRouteData, TypedGoRoute;
export 'src/typedefs.dart' show GoRouterPageBuilder, GoRouterRedirect;
export 'src/url_path_strategy.dart';
export 'src/configuration.dart' show GoRouterState, GoRoute;
export 'src/misc/refresh_stream.dart';
export 'src/pages/custom_transition_page.dart';
export 'src/platform.dart' show UrlPathStrategy;
export 'src/typed_routing.dart' show GoRouteData, TypedGoRoute;
export 'src/typedefs.dart';

/// The top-level go router class.
///
/// Create one of these to initialize your app's routing policy.
// ignore: prefer_mixin
class GoRouter extends ChangeNotifier with NavigatorObserver {
/// Default constructor to configure a GoRouter with a routes builder
/// and an error page builder.
GoRouter({
required List<GoRoute> routes,
// TODO(johnpryan): Change to a route, improve error API
GoRouterPageBuilder? errorPageBuilder,
GoRouterWidgetBuilder? errorBuilder,
GoRouterRedirect? redirect,
Listenable? refreshListenable,
int redirectLimit = 5,
bool routerNeglect = false,
String? initialLocation,
// TODO(johnpryan): Deprecate this parameter
UrlPathStrategy? urlPathStrategy,
List<NavigatorObserver>? observers,
bool debugLogDiagnostics = false,
// TODO(johnpryan): Deprecate this parameter
GoRouterNavigatorBuilder? navigatorBuilder,
String? restorationScopeId,
}) {
if (urlPathStrategy != null) {
setUrlPathStrategy(urlPathStrategy);
}

setLogging(enabled: debugLogDiagnostics);
WidgetsFlutterBinding.ensureInitialized();

routeConfiguration = RouteConfiguration(
routes: routes,
topRedirect: redirect ?? (_) => null,
redirectLimit: redirectLimit,
);

routeConfiguration.validate();

routeInformationParser = GoRouterInformationParser(
configuration: routeConfiguration,
debugRequireGoRouteInformationProvider: true,
);
routeInformationProvider = GoRouteInformationProvider(
initialRouteInformation: RouteInformation(
location: _effectiveInitialLocation(initialLocation)),
refreshListenable: refreshListenable);

routerDelegate = GoRouterDelegate(
configuration: routeConfiguration,
errorPageBuilder: errorPageBuilder,
errorBuilder: errorBuilder,
routerNeglect: routerNeglect,
observers: <NavigatorObserver>[
...observers ?? <NavigatorObserver>[],
this
],
restorationScopeId: restorationScopeId,
// wrap the returned Navigator to enable GoRouter.of(context).go() et al,
// allowing the caller to wrap the navigator themselves
builderWithNav:
(BuildContext context, GoRouterState state, Navigator nav) =>
InheritedGoRouter(
goRouter: this,
child: navigatorBuilder?.call(context, state, nav) ?? nav,
),
);
assert(() {
log.info('setting initial location $initialLocation');
return true;
}());
}

/// The route configuration for the app.
late final RouteConfiguration routeConfiguration;

/// The route information parser used by the go router.
late final GoRouterInformationParser routeInformationParser;

/// The router delegate used by the go router.
late final GoRouterDelegate routerDelegate;

/// The route information provider used by the go router.
late final GoRouteInformationProvider routeInformationProvider;

/// Get the current location.
String get location =>
routerDelegate.currentConfiguration.location.toString();

/// Get a location from route name and parameters.
/// This is useful for redirecting to a named location.
String namedLocation(
String name, {
Map<String, String> params = const <String, String>{},
Map<String, String> queryParams = const <String, String>{},
}) =>
routeInformationParser.configuration.namedLocation(
name,
params: params,
queryParams: queryParams,
);

/// Navigate to a URI location w/ optional query parameters, e.g.
/// `/family/f2/person/p1?color=blue`
void go(String location, {Object? extra}) {
assert(() {
log.info('going to $location');
return true;
}());
routeInformationProvider.value =
RouteInformation(location: location, state: extra);
}

/// Navigate to a named route w/ optional parameters, e.g.
/// `name='person', params={'fid': 'f2', 'pid': 'p1'}`
/// Navigate to the named route.
void goNamed(
String name, {
Map<String, String> params = const <String, String>{},
Map<String, String> queryParams = const <String, String>{},
Object? extra,
}) =>
go(
namedLocation(name, params: params, queryParams: queryParams),
extra: extra,
);

/// Push a URI location onto the page stack w/ optional query parameters, e.g.
/// `/family/f2/person/p1?color=blue`
void push(String location, {Object? extra}) {
assert(() {
log.info('pushing $location');
return true;
}());
routeInformationParser
.parseRouteInformation(
DebugGoRouteInformation(location: location, state: extra))
.then<void>((RouteMatchList matches) {
routerDelegate.push(matches.last);
});
}

/// Push a named route onto the page stack w/ optional parameters, e.g.
/// `name='person', params={'fid': 'f2', 'pid': 'p1'}`
void pushNamed(
String name, {
Map<String, String> params = const <String, String>{},
Map<String, String> queryParams = const <String, String>{},
Object? extra,
}) =>
push(
namedLocation(name, params: params, queryParams: queryParams),
extra: extra,
);

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

/// Pop the top page off the GoRouter's page stack.
void pop() {
assert(() {
log.info('popping $location');
return true;
}());
routerDelegate.pop();
}

/// Refresh the route.
void refresh() {
assert(() {
log.info('refreshing $location');
return true;
}());
routeInformationProvider.notifyListeners();
}

/// Set the app's URL path strategy (defaults to hash). call before runApp().
static void setUrlPathStrategy(UrlPathStrategy strategy) =>
setUrlPathStrategyImpl(strategy);

/// Find the current GoRouter in the widget tree.
static GoRouter of(BuildContext context) {
final InheritedGoRouter? inherited =
context.dependOnInheritedWidgetOfExactType<InheritedGoRouter>();
assert(inherited != null, 'No GoRouter found in context');
return inherited!.goRouter;
}

/// The [Navigator] pushed `route`.
@override
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) =>
notifyListeners();

/// The [Navigator] popped `route`.
@override
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) =>
notifyListeners();

/// The [Navigator] removed `route`.
@override
void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) =>
notifyListeners();

/// The [Navigator] replaced `oldRoute` with `newRoute`.
@override
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) =>
notifyListeners();

@override
void dispose() {
routeInformationProvider.dispose();
routerDelegate.dispose();
super.dispose();
}

String _effectiveInitialLocation(String? initialLocation) {
final String platformDefault =
WidgetsBinding.instance.platformDispatcher.defaultRouteName;
if (initialLocation == null) {
return platformDefault;
} else if (platformDefault == '/') {
return initialLocation;
} else {
return platformDefault;
}
}
}

/// GoRouter implementation of InheritedWidget.
///
/// Used for to find the current GoRouter in the widget tree. This is useful
/// when routing from anywhere in your app.
class InheritedGoRouter extends InheritedWidget {
/// Default constructor for the inherited go router.
const InheritedGoRouter({
required Widget child,
required this.goRouter,
Key? key,
}) : super(child: child, key: key);

/// The [GoRouter] that is made available to the widget tree.
final GoRouter goRouter;

/// Used by the Router architecture as part of the InheritedWidget.
@override
// ignore: prefer_expression_function_bodies
bool updateShouldNotify(covariant InheritedGoRouter oldWidget) {
// avoid rebuilding the widget tree if the router has not changed
return goRouter != oldWidget.goRouter;
}

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<GoRouter>('goRouter', goRouter));
}
}

/// Dart extension to add navigation function to a BuildContext object, e.g.
/// context.go('/');
// NOTE: adding this here instead of in /src to work-around a Dart analyzer bug
// and fix: https://github.com/csells/go_router/issues/116
extension GoRouterHelper on BuildContext {
/// Get a location from route name and parameters.
String namedLocation(
Expand Down
Loading