askill
flutter-reviewer

flutter-reviewerSafety 95Repository

WHEN: Flutter/Dart code review, Widget patterns, State management checks, BLoC/Provider/Riverpod analysis WHAT: Widget best practices + State management patterns + Performance optimization + Platform channel review WHEN NOT: Native Android → kotlin-android-reviewer, Native iOS → ios-reviewer

1 stars
1.2k downloads
Updated 12/29/2025

Package Files

Loading files...
SKILL.md

Flutter Reviewer Skill

Purpose

Reviews Flutter/Dart code for widget patterns, state management, performance, and cross-platform best practices.

When to Use

  • Flutter project code review
  • "Widget", "BLoC", "Provider", "Riverpod", "GetX" mentions
  • Flutter performance, rebuild optimization inspection
  • Projects with pubspec.yaml containing flutter dependency

Project Detection

  • pubspec.yaml with flutter: dependency
  • lib/main.dart exists
  • android/ and ios/ directories present
  • .dart files with Flutter imports

Workflow

Step 1: Analyze Project

**Flutter**: 3.x
**Dart**: 3.x
**State Management**: BLoC / Provider / Riverpod / GetX
**Architecture**: Clean Architecture / MVVM / MVC
**Null Safety**: Enabled

Step 2: Select Review Areas

AskUserQuestion:

"Which areas to review?"
Options:
- Full Flutter pattern check (recommended)
- Widget build optimization
- State management patterns
- Platform channels/native code
- Navigation/routing patterns
multiSelect: true

Detection Rules

Widget Patterns

CheckRecommendationSeverity
Heavy logic in build()Move to initState or separate methodHIGH
Missing const constructorAdd const for immutable widgetsHIGH
Unnecessary setStateUse state management for complex stateMEDIUM
Large build methodExtract to smaller widgetsMEDIUM
Missing key in ListViewAdd key for correct item trackingHIGH
// BAD: Heavy logic in build
class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final result = expensiveCalculation();  // Called every build
    return Text(result);
  }
}

// GOOD: Compute outside or cache
class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  late String result;

  @override
  void initState() {
    super.initState();
    result = expensiveCalculation();
  }

  @override
  Widget build(BuildContext context) => Text(result);
}

// BAD: Missing const
class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text('Hello'),  // Rebuilds unnecessarily
    );
  }
}

// GOOD: Use const
class MyWidget extends StatelessWidget {
  const MyWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return const Text('Hello');  // Skipped in rebuilds
  }
}

// BAD: Missing key in ListView
ListView.builder(
  itemBuilder: (context, index) => ListTile(
    title: Text(items[index].name),
  ),
)

// GOOD: Add key
ListView.builder(
  itemBuilder: (context, index) => ListTile(
    key: ValueKey(items[index].id),
    title: Text(items[index].name),
  ),
)

State Management - BLoC

CheckRecommendationSeverity
BLoC without closeMemory leak riskCRITICAL
emit after closeRuntime error riskHIGH
Nested BlocBuilderUse BlocSelector or MultiBlocListenerMEDIUM
Business logic in UIMove to BLoCMEDIUM
// BAD: BLoC not closed
class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  final bloc = MyBloc();

  @override
  Widget build(BuildContext context) => BlocBuilder...
  // Missing dispose!
}

// GOOD: Close BLoC
@override
void dispose() {
  bloc.close();
  super.dispose();
}

// Better: Use BlocProvider
BlocProvider(
  create: (context) => MyBloc(),
  child: MyWidget(),  // Auto-disposed
)

// BAD: Nested BlocBuilder
BlocBuilder<BlocA, StateA>(
  builder: (context, stateA) {
    return BlocBuilder<BlocB, StateB>(
      builder: (context, stateB) {
        return Text('${stateA.value} ${stateB.value}');
      },
    );
  },
)

// GOOD: Use MultiBlocListener or BlocSelector
MultiBlocListener(
  listeners: [
    BlocListener<BlocA, StateA>(...),
    BlocListener<BlocB, StateB>(...),
  ],
  child: Builder(
    builder: (context) {
      final a = context.watch<BlocA>().state;
      final b = context.watch<BlocB>().state;
      return Text('${a.value} ${b.value}');
    },
  ),
)

State Management - Provider/Riverpod

CheckRecommendationSeverity
Provider not disposedMemory leakHIGH
ChangeNotifier without notifyListenersUI not updatedHIGH
context.read in buildUse context.watchHIGH
Missing ProviderScopeRiverpod won't workCRITICAL
// BAD: context.read in build (for reactive updates)
@override
Widget build(BuildContext context) {
  final value = context.read<MyProvider>().value;  // Won't rebuild!
  return Text(value);
}

// GOOD: context.watch for reactive
@override
Widget build(BuildContext context) {
  final value = context.watch<MyProvider>().value;
  return Text(value);
}

// BAD: Missing notifyListeners
class MyNotifier extends ChangeNotifier {
  int _count = 0;
  int get count => _count;

  void increment() {
    _count++;
    // Missing notifyListeners()!
  }
}

// GOOD: Call notifyListeners
void increment() {
  _count++;
  notifyListeners();
}

// Riverpod: Missing ProviderScope
void main() {
  runApp(MyApp());  // Riverpod providers won't work!
}

// GOOD: Wrap with ProviderScope
void main() {
  runApp(
    ProviderScope(
      child: MyApp(),
    ),
  );
}

Performance Optimization

CheckProblemSolution
Unnecessary rebuildsPerformanceconst, shouldRebuild, select
Heavy imagesMemory/performancecached_network_image, resize
Sync file I/OUI jankUse compute() or Isolate
AnimationController not disposedMemory leakDispose in dispose()
// BAD: Sync heavy operation
void loadData() {
  final data = File('large.json').readAsStringSync();
  final parsed = jsonDecode(data);  // Blocks UI!
}

// GOOD: Use compute/Isolate
Future<void> loadData() async {
  final data = await compute(parseJson, filePath);
}

// BAD: AnimationController leak
class _MyState extends State<MyWidget> with TickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this);
  }
  // Missing dispose!
}

// GOOD: Dispose controller
@override
void dispose() {
  _controller.dispose();
  super.dispose();
}

Platform Channels

CheckRecommendationSeverity
Missing null checkCrash on nullHIGH
No error handlingSilent failuresMEDIUM
Main thread blockingANR/UI freezeHIGH
Hard-coded channel nameMaintenance issueLOW
// BAD: No error handling
Future<String> getPlatformVersion() async {
  final version = await platform.invokeMethod('getVersion');
  return version;
}

// GOOD: Error handling
Future<String> getPlatformVersion() async {
  try {
    final version = await platform.invokeMethod<String>('getVersion');
    return version ?? 'Unknown';
  } on PlatformException catch (e) {
    return 'Failed: ${e.message}';
  }
}

Response Template

## Flutter Code Review Results

**Project**: [name]
**Flutter**: 3.x | **Dart**: 3.x
**State Management**: BLoC/Provider/Riverpod
**Files Analyzed**: X

### Widget Patterns
| Status | File | Issue |
|--------|------|-------|
| HIGH | lib/screens/home.dart | Missing const constructor (line 45) |
| HIGH | lib/widgets/list_item.dart | Missing key in ListView |

### State Management
| Status | File | Issue |
|--------|------|-------|
| CRITICAL | lib/blocs/user_bloc.dart | BLoC not closed (line 23) |
| HIGH | lib/providers/cart.dart | Missing notifyListeners |

### Performance
| Status | File | Issue |
|--------|------|-------|
| HIGH | lib/services/data.dart | Sync file I/O blocking UI |
| MEDIUM | lib/screens/gallery.dart | Large images not cached |

### Recommended Actions
1. [ ] Add const to immutable widgets
2. [ ] Close BLoCs in dispose or use BlocProvider
3. [ ] Use compute() for heavy operations
4. [ ] Add keys to ListView items

Best Practices

  1. Widgets: Use const, extract small widgets, add keys
  2. State: Choose appropriate state management, dispose resources
  3. Performance: Avoid rebuilds, use isolates for heavy work
  4. Platform: Handle errors, use typed method channels
  5. Testing: Widget tests, golden tests, integration tests

Integration

  • code-reviewer skill: General Dart code quality
  • test-generator skill: Flutter test generation
  • kotlin-android-reviewer skill: Platform channel Android side
  • ios-reviewer skill: Platform channel iOS side

Notes

  • Based on Flutter 3.x, Dart 3.x with null safety
  • Supports BLoC, Provider, Riverpod, GetX patterns
  • Includes platform channel best practices

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

90/100Analyzed 2/19/2026

Excellent Flutter code review skill with comprehensive coverage of widget patterns, state management (BLoC/Provider/Riverpod), performance optimization, and platform channels. Features structured workflow, clear detection rules with severity levels, extensive code examples showing anti-patterns vs best practices, and a response template. Tags are mismatched (CI/CD for Flutter skill) but content is high quality and highly actionable. Located in dedicated skills folder with proper depth, suggesting good reusability."

95
85
88
90
92

Metadata

Licenseunknown
Version-
Updated12/29/2025
Publisherphysics91

Tags

ci-cdgithub-actionstesting