diff --git a/CHANGELOG.md b/CHANGELOG.md index aadb92f..5774228 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # 0.9.4 * Fixed: an issue where pages were incorrectly rebuilding, causing state such as the active tab to reset +* Fixed: you can now use the ternary operator in page builders without having to do extra casts # 0.9.3 diff --git a/lib/routemaster.dart b/lib/routemaster.dart index 39b65c5..ddb9d5a 100644 --- a/lib/routemaster.dart +++ b/lib/routemaster.dart @@ -22,10 +22,10 @@ part 'src/observers.dart'; part 'src/route_data.dart'; /// A function that builds a [Page] from given [RouteData]. -typedef PageBuilder = Page Function(RouteData route); +typedef PageBuilder = RouteSettings Function(RouteData route); /// A function that returns a [Page] when the given [path] couldn't be found. -typedef UnknownRouteCallback = Page Function(String path); +typedef UnknownRouteCallback = RouteSettings Function(String path); /// A standard simple routing table which takes a map of routes. /// @@ -84,7 +84,7 @@ class RouteMap { /// 2. Use the routing delegate to, for instance, redirect to another route /// and return null. /// - Page onUnknownRoute(String path) { + RouteSettings onUnknownRoute(String path) { if (_onUnknownRoute != null) { return _onUnknownRoute!(path); } @@ -598,10 +598,13 @@ class RoutemasterDelegate extends RouterDelegate ); // Get a page wrapper object for the current route + final page = routerData.builder(routeData); + _assertIsPage(page, routeData.fullPath); + final current = isLastRoute ? _createPageWrapper( routeRequest: request, - page: routerData.builder(routeData), + page: page as Page, routeData: routeData, ) : _getOrCreatePageWrapper( @@ -696,7 +699,7 @@ class RoutemasterDelegate extends RouterDelegate // No current route, create a new one return _createPageWrapper( routeRequest: routeRequest, - page: routerResult.builder(routeData), + page: routerResult.builder(routeData) as Page, routeData: routeData, ); } @@ -712,9 +715,12 @@ class RoutemasterDelegate extends RouterDelegate isReplacement: routeRequest.isReplacement, ); + final page = routerResult.builder(routeData); + _assertIsPage(page, routeData.fullPath); + final wrapper = _createPageWrapper( routeRequest: routeRequest, - page: routerResult.builder(routeData), + page: routerResult.builder(routeData) as Page, routeData: routeData, ); @@ -789,7 +795,10 @@ class RoutemasterDelegate extends RouterDelegate List _onUnknownRoute(_RouteRequest routeRequest) { final requestedPath = routeRequest.uri; - final result = _state.routeMap!.onUnknownRoute(requestedPath.toString()); + final fullPath = requestedPath.toString(); + final result = _state.routeMap!.onUnknownRoute(fullPath); + + _assertIsPage(result, fullPath); if (result is Redirect) { final redirectResult = _createAllPageWrappers( @@ -805,11 +814,15 @@ class RoutemasterDelegate extends RouterDelegate } // Return 404 page - final routeData = RouteData.fromUri( - requestedPath, - isReplacement: routeRequest.isReplacement, - ); - return [PageWrapper.fromPage(routeData: routeData, page: result)]; + return [ + PageWrapper.fromPage( + routeData: RouteData.fromUri( + requestedPath, + isReplacement: routeRequest.isReplacement, + ), + page: result as Page, + ) + ]; } List _debugCheckRedirectLoop( @@ -1151,3 +1164,10 @@ class _StackNavigatorState extends NavigatorState { super.dispose(); } } + +void _assertIsPage(RouteSettings page, String route) { + assert( + page is Page, + "Route builders must return a Page object. The route builder for '$route' instead returned an object of type '${page.runtimeType}'.", + ); +} diff --git a/pubspec.yaml b/pubspec.yaml index 4f4e688..ad8c260 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: routemaster description: Easy-to-use Navigator 2.0 router for web, mobile and desktop. URL-based routing, simple navigation of tabs and nested routes. -version: 0.9.4-dev1 +version: 0.9.4 homepage: https://github.com/tomgilder/routemaster environment: diff --git a/test/router_test.dart b/test/router_test.dart index dbff906..d15bbe7 100644 --- a/test/router_test.dart +++ b/test/router_test.dart @@ -525,6 +525,64 @@ void main() { expect(find.byType(PageTwo), findsOneWidget); }); + + test('Can use ternary operator in route map', () { + const id = 0; + + // This just needs to compile to pass + RouteMap( + onUnknownRoute: (_) { + return id == 0 ? const Redirect('/two') : const MaterialPageOne(); + }, + routes: { + '/two': (_) { + return id == 0 ? const NotFound() : const MaterialPageOne(); + }, + }, + ); + }); + + testWidgets('Asserts when Page not returned from not found', (tester) async { + final delegate = RoutemasterDelegate( + routesBuilder: (_) => RouteMap( + onUnknownRoute: (_) => NotAPage(), + routes: {'/': (_) => const MaterialPageOne()}, + ), + ); + + await tester.pumpWidget( + MaterialApp.router( + routeInformationParser: const RoutemasterParser(), + routerDelegate: delegate, + ), + ); + + delegate.push('/404'); + await tester.pump(); + + final exception = tester.takeException() as AssertionError; + expect( + exception.message, + "Route builders must return a Page object. The route builder for '/404' instead returned an object of type 'NotAPage'.", + ); + }); + + testWidgets('Asserts when Page not returned from builder', (tester) async { + await tester.pumpWidget( + MaterialApp.router( + routeInformationParser: const RoutemasterParser(), + routerDelegate: RoutemasterDelegate( + routesBuilder: (_) => RouteMap(routes: {'/': (_) => NotAPage()}), + ), + ), + ); + + final exception = tester.takeException() as AssertionError; + expect( + exception.message, + "Route builders must return a Page object. The route builder for '/' instead returned an object of type 'NotAPage'.", + ); + }); } class QueryParamEcho extends StatelessWidget { @@ -537,3 +595,5 @@ class QueryParamEcho extends StatelessWidget { return Scaffold(body: Text(query)); } } + +class NotAPage extends RouteSettings {}