flutter-code-quality
Organize Flutter/Dart code to follow project conventions. Use after implementation to restructure folders, fix widget file organization, align naming patterns, or clean up code to match project standards.
Flutter Code Quality
Comprehensive guidelines for Flutter/Dart code quality, widget organization, and folder structure. Combines pattern-level rules (anti-patterns, idioms) with structural guidance (build method organization, folder conventions).
How It Works
- Read code quality guidelines from the local reference file
- Apply embedded widget organization and folder structure rules
- Check files against all guidelines
- Output findings in terse
file:lineformat
Code Quality Guidelines
Read guidelines before each review:
Read .claude/references/code_quality.md
Contains: anti-patterns, widget patterns, state management, collections, hooks, theme/styling, etc.
Widget Organization Guidelines (Embedded)
Build Method Structure
Order inside build():
- Providers (reads/watches)
- Hooks (if using flutter_hooks)
- Derived variables needed for rendering
- Widget variables (in render order)
When to Use What
| Scenario | Pattern |
|---|---|
| Widget always shown, no conditions | Local variable: final header = Container(...); |
| Widget depends on condition/null check | Builder function: Widget? _buildContent() { if (data == null) return null; ... } |
| Subtree is large, reusable, or has own state | Extract to standalone widget in own file |
| Function needs 3 or fewer params | Define outside build() as class method |
| Function needs 4+ params (esp. hooks) | Define inside build() to capture scope |
Rules
- No file-private widgets - If big enough to be a widget, it gets its own file
- Define local variables in render order - Top-to-bottom matches screen layout
- Extract non-trivial conditions -
final canSubmit = isValid && !isLoading && selectedId != null; - Pass
WidgetRefonly when function needs both ref and context - Useref.contextinside
Async UX Conventions
- Button loading - Watch provider state, not separate
useState<bool> - Retriable errors - Listen to provider, show toast on error, user retries by tapping again
- First-load errors - Render error view with retry button that invalidates provider
Sorting/Filtering
- Simple options: Use enum with computed properties
- Options with behavior: Use sealed class
- Complex multi-field filtering: Dedicated
Filterclass
Folder Structure Guidelines (Embedded)
Core Rules
- Organize by feature - Each feature gets its own folder
- Screens at feature root -
account_screen.dart,edit_account_screen.dart - Create subfolders only when justified:
widgets/when 2+ reusable widgets existproviders/when 2+ provider files existdomain/usually always (models, repositories)
- Split large features into subfeatures - Each subfeature follows same rules
Example
lib/features/
account/
account_screen.dart
edit_account_screen.dart
widgets/
account_avatar.dart
account_form.dart
providers/
account_provider.dart
domain/
account.dart
account_repository.dart
Application Priority
When reviewing code, apply in this order:
- Code Quality Patterns (from
.claude/references/code_quality.md) - Anti-patterns, idioms, provider patterns - Widget Organization (above) - Build structure, extraction rules, async UX
- Folder Structure (above) - File placement, feature boundaries
Anti-Patterns Quick Reference
Flag these patterns (details in .claude/references/code_quality.md):
useState<bool>for loading states- Manual try-catch in provider actions
.toList()..sort()instead of.sorted()_handleAction(ref, controller, user, state)with 4+ params- Hardcoded hex colors
- Deep
lib/features/x/presentation/directories - Barrel files that only re-export
- Boolean flags instead of sealed classes
- Magic numbers scattered across widgets
where((e) => e.status == Status.active)instead of computed property- Generic provider names like
expansionVisibilityProvider .asData?.valueinstead of.value
Output Format
Group by file. Use file:line format. Terse findings.
## lib/home/home_screen.dart
lib/home/home_screen.dart:42 - useState for loading state -> use provider
lib/home/home_screen.dart:67 - .toList()..sort() -> .sorted()
lib/home/home_screen.dart:89 - hardcoded Color(0xFF...) -> context.color.*
## lib/models/user.dart
pass
State issue + location. Skip explanation unless fix non-obvious. No preamble.