|
| 1 | +# AI rules for Flutter |
| 2 | + |
| 3 | +You are an expert in Flutter and Dart development. Your goal is to build |
| 4 | +beautiful, performant, and maintainable applications following modern best |
| 5 | +practices. |
| 6 | + |
| 7 | +## Project Structure |
| 8 | +* Assumes a standard Flutter project structure with `lib/main.dart` as the |
| 9 | + primary application entry point. |
| 10 | + |
| 11 | +## Package Management |
| 12 | +* To manage packages, use the `pub` tool, if available. |
| 13 | +* If a new feature requires an external package, use the `pub_dev_search` |
| 14 | + tool, if it is available. Otherwise, identify the most suitable and stable |
| 15 | + package from pub.dev. |
| 16 | +* To add a regular dependency, use the `pub` tool, if it is available. |
| 17 | + Otherwise, run `flutter pub add <package_name>`. |
| 18 | +* To add a development dependency, use the `pub` tool, if it is available, |
| 19 | + with `dev:<package name>`. Otherwise, run |
| 20 | + `flutter pub add dev:<package_name>`. |
| 21 | +* To add a dependency override, use the `pub` tool, if it is available, |
| 22 | + with `override:<package name>:1.0.0`. Otherwise, run |
| 23 | + `flutter pub add override:<package_name>:1.0.0`. |
| 24 | +* To remove a dependency, use the `pub` tool, if it is available. Otherwise, |
| 25 | + run `dart pub remove <package_name>`. |
| 26 | + |
| 27 | +## Code Quality |
| 28 | +* Adhere to maintainable code structure and separation of concerns (e.g., UI |
| 29 | + logic separate from business logic). |
| 30 | +* Adhere to meaningful and consistent naming conventions. |
| 31 | + |
| 32 | +## Dart Best Practices |
| 33 | +* Follow the official Effective Dart guidelines |
| 34 | + (https://dart.dev/effective-dart) |
| 35 | +* Define related classes within the same library file. For large libraries, |
| 36 | + export smaller, private libraries from a single top-level library. |
| 37 | +* Group related libraries in the same folder. |
| 38 | +* Add documentation comments to all public APIs, including classes, |
| 39 | + constructors, methods, and top-level functions. |
| 40 | +* Write clear comments for complex or non-obvious code. Avoid over-commenting. |
| 41 | +* Don't add trailing comments. |
| 42 | +* Ensure proper use of `async`/`await` for asynchronous operations with robust |
| 43 | + error handling. |
| 44 | +* Use pattern matching features where they simplify the code. |
| 45 | + |
| 46 | +## Flutter Best Practices |
| 47 | +* Widgets (especially `StatelessWidget`) are immutable; when the UI needs to |
| 48 | + change, Flutter rebuilds the widget tree. |
| 49 | +* Prefer composing smaller widgets over extending existing ones. |
| 50 | +* Use small, private `Widget` classes instead of private helper methods that |
| 51 | + return a `Widget`. |
| 52 | +* Break down large `build()` methods into smaller, reusable private Widget |
| 53 | + classes. |
| 54 | +* Use `ListView.builder` to create lazy-loaded lists for performance. |
| 55 | +* Use `const` constructors for widgets and in `build()` methods whenever |
| 56 | + possible to optimize performance. |
| 57 | +* Avoid performing expensive operations, like network calls or complex |
| 58 | + computations, directly within `build()` methods. |
| 59 | + |
| 60 | +## Application Architecture |
| 61 | +* Aim for separation of concerns similar to MVC/MVVM, with defined Model, |
| 62 | + View, and ViewModel/Controller roles. |
| 63 | + |
| 64 | +### State Management |
| 65 | +* Prefer Flutter's built-in state management solutions. Do not use a |
| 66 | + third-party package unless explicitly requested. |
| 67 | +* Use `Streams` and `StreamBuilder` for handling a sequence of asynchronous |
| 68 | + events. |
| 69 | +* Use `Futures` and `FutureBuilder` for handling a single asynchronous |
| 70 | + operation that will complete in the future. |
| 71 | +* Use `ValueNotifier` with `ValueListenableBuilder` for simple, local state |
| 72 | + that involves a single value. |
| 73 | + |
| 74 | + ```dart |
| 75 | + // Define a ValueNotifier to hold the state. |
| 76 | + final ValueNotifier<int> _counter = ValueNotifier<int>(0); |
| 77 | +
|
| 78 | + // Use ValueListenableBuilder to listen and rebuild. |
| 79 | + ValueListenableBuilder<int>( |
| 80 | + valueListenable: _counter, |
| 81 | + builder: (context, value, child) { |
| 82 | + return Text('Count: $value'); |
| 83 | + }, |
| 84 | + ); |
| 85 | + ``` |
| 86 | +
|
| 87 | +* For state that is more complex or shared across multiple widgets, use |
| 88 | + `ChangeNotifier`. |
| 89 | +* Use `ListenableBuilder` to listen to changes from a `ChangeNotifier` or |
| 90 | + other `Listenable`. |
| 91 | +* When a more robust solution is needed, structure the app using the |
| 92 | + Model-View-ViewModel (MVVM) pattern. |
| 93 | +* Use manual dependency injection via constructors to make a class's |
| 94 | + dependencies explicit in its API. |
| 95 | +* If a dependency injection solution beyond manual constructor injection is explicitly requested, `provider` can be used to make services, repositories, or |
| 96 | + complex state objects available to the UI layer without tight coupling |
| 97 | + (note: this document generally defaults against third-party packages for |
| 98 | + state management unless explicitly requested). |
| 99 | +
|
| 100 | +### Data Flow |
| 101 | +* Define data structures (classes) to represent the data used in the |
| 102 | + application. |
| 103 | +* Abstract data sources (e.g., API calls, database operations) using |
| 104 | + Repositories/Services to promote testability. |
| 105 | +
|
| 106 | +### Routing |
| 107 | +* Use `go_router` for declarative navigation, deep linking, and web support. |
| 108 | +
|
| 109 | + ```dart |
| 110 | + // 1. Add the dependency |
| 111 | + // flutter pub add go_router |
| 112 | +
|
| 113 | + // 2. Configure the router |
| 114 | + final GoRouter _router = GoRouter( |
| 115 | + routes: <RouteBase>[ |
| 116 | + GoRoute( |
| 117 | + path: '/', |
| 118 | + builder: (context, state) => const HomeScreen(), |
| 119 | + routes: <RouteBase>[ |
| 120 | + GoRoute( |
| 121 | + path: 'details/:id', // Route with a path parameter |
| 122 | + builder: (context, state) { |
| 123 | + final String id = state.pathParameters['id']!; |
| 124 | + return DetailScreen(id: id); |
| 125 | + }, |
| 126 | + ), |
| 127 | + ], |
| 128 | + ), |
| 129 | + ], |
| 130 | + ); |
| 131 | +
|
| 132 | + // 3. Use it in your MaterialApp |
| 133 | + MaterialApp.router( |
| 134 | + routerConfig: _router, |
| 135 | + ); |
| 136 | + ``` |
| 137 | +
|
| 138 | +* Use the built-in `Navigator` for short-lived screens that do not need to be |
| 139 | + deep-linkable, such as dialogs or temporary views. |
| 140 | +
|
| 141 | + ```dart |
| 142 | + // Push a new screen onto the stack |
| 143 | + Navigator.push( |
| 144 | + context, |
| 145 | + MaterialPageRoute(builder: (context) => const DetailsScreen()), |
| 146 | + ); |
| 147 | +
|
| 148 | + // Pop the current screen to go back |
| 149 | + Navigator.pop(context); |
| 150 | + ``` |
| 151 | +
|
| 152 | +### Data Handling & Serialization |
| 153 | +* Use `json_serializable` and `json_annotation` for parsing and encoding JSON |
| 154 | + data. |
| 155 | +* When encoding data, use `fieldRename: FieldRename.snake` to convert Dart's |
| 156 | + camelCase fields to snake_case JSON keys. |
| 157 | +
|
| 158 | + ```dart |
| 159 | + // In your model file |
| 160 | + import 'package:json_annotation/json_annotation.dart'; |
| 161 | +
|
| 162 | + part 'user.g.dart'; |
| 163 | +
|
| 164 | + @JsonSerializable(fieldRename: FieldRename.snake) |
| 165 | + class User { |
| 166 | + final String firstName; |
| 167 | + final String lastName; |
| 168 | +
|
| 169 | + User({required this.firstName, required this.lastName}); |
| 170 | +
|
| 171 | + factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json); |
| 172 | + Map<String, dynamic> toJson() => _$UserToJson(this); |
| 173 | + } |
| 174 | + ``` |
| 175 | +
|
| 176 | +### Logging |
| 177 | +* Use the `log` function from `dart:developer` for structured logging that |
| 178 | + integrates with Dart DevTools. |
| 179 | +
|
| 180 | + ```dart |
| 181 | + import 'dart:developer' as developer; |
| 182 | +
|
| 183 | + // For simple messages |
| 184 | + developer.log('User logged in successfully.'); |
| 185 | +
|
| 186 | + // For structured error logging |
| 187 | + try { |
| 188 | + // ... code that might fail |
| 189 | + } catch (e, s) { |
| 190 | + developer.log( |
| 191 | + 'Failed to fetch data', |
| 192 | + name: 'myapp.network', |
| 193 | + level: 1000, // SEVERE |
| 194 | + error: e, |
| 195 | + stackTrace: s, |
| 196 | + ); |
| 197 | + } |
| 198 | + ``` |
| 199 | +
|
| 200 | +## Error Handling |
| 201 | +* Implement mechanisms to gracefully handle errors across the application |
| 202 | + (e.g., using try-catch blocks, Either types for functional error handling, |
| 203 | + or global error handlers). |
| 204 | +
|
| 205 | +## Code Generation |
| 206 | +* Use `build_runner` for all code generation tasks, such as for |
| 207 | + `json_serializable`. |
| 208 | +* After modifying files that require code generation, run the build command: |
| 209 | +
|
| 210 | + ```shell |
| 211 | + dart run build_runner build --delete-conflicting-outputs |
| 212 | + ``` |
| 213 | +
|
| 214 | +## Testing |
| 215 | +* To run tests, use the `run_tests` tool if it is available, otherwise use |
| 216 | + `flutter test`. |
| 217 | +* Use `package:test` for unit tests. |
| 218 | +* Use `package:flutter_test` for widget tests. |
| 219 | +* Use `package:integration_test` for integration tests. |
| 220 | +* Prefer using `package:checks` for more expressive and readable assertions |
| 221 | + over the default `matchers`. |
| 222 | +
|
| 223 | +## Visual Design & Theming |
| 224 | +* Build beautiful and intuitive user interfaces that follow modern design |
| 225 | + guidelines. |
| 226 | +* Ensure the app is mobile responsive and adapts to different screen sizes, |
| 227 | + working perfectly on mobile and web. |
| 228 | +* If there are multiple pages for the user to interact with, provide an |
| 229 | + intuitive and easy navigation bar or controls. |
| 230 | +* Stress and emphasize font sizes to ease understanding, e.g., hero text, |
| 231 | + section headlines, list headlines, keywords in paragraphs. |
| 232 | +* Apply subtle noise texture to the main background to add a premium, tactile |
| 233 | + feel. |
| 234 | +* Multi-layered drop shadows create a strong sense of depth; cards have a |
| 235 | + soft, deep shadow to look "lifted." |
| 236 | +* Incorporate icons to enhance the user’s understanding and the logical |
| 237 | + navigation of the app. |
| 238 | +* Buttons, checkboxes, sliders, lists, charts, graphs, and other interactive |
| 239 | + elements have a shadow with elegant use of color to create a "glow" effect. |
| 240 | +
|
| 241 | +### Theming |
| 242 | +* Define a centralized `ThemeData` object to ensure a consistent |
| 243 | + application-wide style. |
| 244 | +* Use Material 3 by setting `useMaterial3: true` in your `ThemeData`. |
| 245 | +* Implement support for both light and dark themes, ideal for a user-facing |
| 246 | + theme toggle (`ThemeMode.light`, `ThemeMode.dark`, `ThemeMode.system`). |
| 247 | +* Generate harmonious color palettes from a single color using |
| 248 | + `ColorScheme.fromSeed`. |
| 249 | +
|
| 250 | + ```dart |
| 251 | + final ThemeData lightTheme = ThemeData( |
| 252 | + useMaterial3: true, |
| 253 | + colorScheme: ColorScheme.fromSeed( |
| 254 | + seedColor: Colors.deepPurple, |
| 255 | + brightness: Brightness.light, |
| 256 | + ), |
| 257 | + // ... other theme properties |
| 258 | + ); |
| 259 | + ``` |
| 260 | +* Include a wide range of color concentrations and hues in the palette to |
| 261 | + create a vibrant and energetic look and feel. |
| 262 | +* Use specific theme properties (e.g., `appBarTheme`, `elevatedButtonTheme`) |
| 263 | + to customize the appearance of individual Material components. |
| 264 | +* For custom fonts, use the `google_fonts` package. Define a `TextTheme` to |
| 265 | + apply fonts consistently. |
| 266 | +
|
| 267 | + ```dart |
| 268 | + // 1. Add the dependency |
| 269 | + // flutter pub add google_fonts |
| 270 | +
|
| 271 | + // 2. Define a TextTheme with a custom font |
| 272 | + final TextTheme appTextTheme = TextTheme( |
| 273 | + displayLarge: GoogleFonts.oswald(fontSize: 57, fontWeight: FontWeight.bold), |
| 274 | + titleLarge: GoogleFonts.roboto(fontSize: 22, fontWeight: FontWeight.w500), |
| 275 | + bodyMedium: GoogleFonts.openSans(fontSize: 14), |
| 276 | + ); |
| 277 | + ``` |
| 278 | +
|
| 279 | +### Assets and Images |
| 280 | +* If images are needed, make them relevant and meaningful, with appropriate |
| 281 | + size, layout, and licensing (e.g., freely available). Provide placeholder |
| 282 | + images if real ones are not available. |
| 283 | +* Declare all asset paths in your `pubspec.yaml` file. |
| 284 | +
|
| 285 | + ```yaml |
| 286 | + flutter: |
| 287 | + uses-material-design: true |
| 288 | + assets: |
| 289 | + - assets/images/ |
| 290 | + ``` |
| 291 | +
|
| 292 | +* Use `Image.asset` to display local images from your asset bundle. |
| 293 | +
|
| 294 | + ```dart |
| 295 | + Image.asset('assets/images/placeholder.png') |
| 296 | + ``` |
| 297 | +
|
| 298 | +* Use `ImageIcon` to display an icon from an `ImageProvider`, useful for custom icons not in the `Icons` class. |
| 299 | +* Use `Image.network` to display images from a URL, and always include |
| 300 | + `loadingBuilder` and `errorBuilder` for a better user experience. |
| 301 | +
|
| 302 | + ```dart |
| 303 | + Image.network( |
| 304 | + 'https://picsum.photos/200/300', |
| 305 | + loadingBuilder: (context, child, progress) { |
| 306 | + if (progress == null) return child; |
| 307 | + return const Center(child: CircularProgressIndicator()); |
| 308 | + }, |
| 309 | + errorBuilder: (context, error, stackTrace) { |
| 310 | + return const Icon(Icons.error); |
| 311 | + }, |
| 312 | + ) |
| 313 | + ``` |
| 314 | +
|
| 315 | +## Accessibility (A11Y) |
| 316 | +* Implement accessibility features to empower all users, assuming a wide |
| 317 | + variety of users with different physical abilities, mental abilities, age |
| 318 | + groups, education levels, and learning styles. |
0 commit comments