SKILL.md
$2a
2. Implement Basic Imperative Navigation
If simple navigation is selected, use the Navigator widget to push and pop Route objects.
Pushing a new route:
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (context) => const SecondScreen(),
),
);
Popping a route:
Navigator.of(context).pop();
3. Implement Data Passing Between Screens
Pass data to new screens using constructor arguments (preferred for imperative navigation) or RouteSettings (for named routes).
Passing via Constructor:
// Navigating and passing data
Navigator.push(
context,
MaterialPageRoute<void>(
builder: (context) => DetailScreen(todo: currentTodo),
),
);
// Receiving data
class DetailScreen extends StatelessWidget {
const DetailScreen({super.key, required this.todo});
final Todo todo;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(todo.title)),
body: Text(todo.description),
);
}
}
Passing via RouteSettings (Named Routes):
// Navigating and passing data
Navigator.pushNamed(
context,
'/details',
arguments: currentTodo,
);
// Extracting data in the destination widget
final todo = ModalRoute.of(context)!.settings.arguments as Todo;
4. Implement Named Routes (If Required)
If named routes are explicitly required, configure MaterialApp with initialRoute and routes or onGenerateRoute.
MaterialApp(
title: 'Named Routes App',
initialRoute: '/',
routes: {
'/': (context) => const FirstScreen(),
'/second': (context) => const SecondScreen(),
},
// OR use onGenerateRoute for dynamic argument extraction
onGenerateRoute: (settings) {
if (settings.name == '/details') {
final args = settings.arguments as Todo;
return MaterialPageRoute(
builder: (context) => DetailScreen(todo: args),
);
}
assert(false, 'Need to implement ${settings.name}');
return null;
},
)
5. Implement Nested Navigation
For sub-flows, instantiate a new Navigator widget within the widget tree. You MUST assign a GlobalKey<NavigatorState> to manage the nested stack.
class SetupFlowState extends State<SetupFlow> {
final _navigatorKey = GlobalKey<NavigatorState>();
void _onDiscoveryComplete() {
_navigatorKey.currentState!.pushNamed('/select_device');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Setup Flow')),
body: Navigator(
key: _navigatorKey,
initialRoute: '/find_devices',
onGenerateRoute: _onGenerateRoute,
),
);
}
Route<Widget> _onGenerateRoute(RouteSettings settings) {
Widget page;
switch (settings.name) {
case '/find_devices':
page = WaitingPage(onWaitComplete: _onDiscoveryComplete);
break;
case '/select_device':
page = const SelectDevicePage();
break;
default:
throw StateError('Unexpected route name: ${settings.name}!');
}
return MaterialPageRoute(builder: (context) => page, settings: settings);
}
}
6. Validate and Fix
Review the implemented routing logic to ensure stability:
- Verify that
Navigator.pop()does not inadvertently close the application if the stack is empty (useNavigator.canPop(context)if necessary).
- If using
initialRoute, verify that thehomeproperty is NOT defined inMaterialApp.
- If extracting arguments via
ModalRoute, verify that null checks or type casts are safely handled.
Constraints
- Do NOT use named routes (
MaterialApp.routes) for applications requiring complex deep linking or web support; use theRouterAPI instead.
- Do NOT define a
homeproperty inMaterialAppif aninitialRouteis provided.
- You MUST use a
GlobalKey<NavigatorState>when implementing a nestedNavigatorto ensure the correct navigation stack is targeted.
- Do NOT include external URLs or links in the generated code or comments.
- Always cast
ModalRoute.of(context)!.settings.argumentsto the specific expected type and handle potential nulls if the route can be accessed without arguments.