/// Ported from `com.rippr.ui.RipprNavHost`. /// /// Three destinations, same shape as the Compose original. `go_router` replaces /// `navigation-compose`; the path parameter is parsed explicitly, mirroring the Kotlin /// comment about ids arriving as the wrong type when the argument type is left implicit. library; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'detail/trip_detail_screen.dart'; import 'record/record_screen.dart'; import 'trips/trips_screen.dart'; abstract final class Routes { static const record = '/'; static const trips = '/trips'; static const tripDetail = '/trip/:tripId'; static String detailFor(int tripId) => '/trip/$tripId'; } GoRouter buildRouter() => GoRouter( initialLocation: Routes.record, routes: [ GoRoute( path: Routes.record, builder: (context, state) => RecordScreen(onOpenTrips: () => context.push(Routes.trips)), ), GoRoute( path: Routes.trips, builder: (context, state) => TripsScreen( onOpenTrip: (id) => context.push(Routes.detailFor(id)), onBack: () => context.pop(), ), ), GoRoute( path: Routes.tripDetail, builder: (context, state) { // Parsed explicitly. A malformed or missing id must land on a real screen // saying so, never on a blank one or a crash. final id = int.tryParse(state.pathParameters['tripId'] ?? ''); if (id == null) { return const _NotFound(); } return TripDetailScreen(tripId: id, onBack: () => context.pop()); }, ), ], errorBuilder: (context, state) => const _NotFound(), ); class _NotFound extends StatelessWidget { const _NotFound(); @override Widget build(BuildContext context) => Scaffold( appBar: AppBar( leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: () => context.canPop() ? context.pop() : context.go(Routes.record), ), ), body: const Center(child: Text('That ride could not be found.')), ); }