agentsclimarketplace

Flutter guide

Skill aleksandr-chaika/flutter-clean-arch-skills/skills/flutter-guide

Complete Flutter development pipeline — Clean Architecture + BLoC + Maestro QE. Autonomous agents for PM, dev, review, testing

Install
npx -y skills add aleksandr-chaika/flutter-clean-arch-skills --skill flutter-guide

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Flutter/BLoC Clean Architecture patterns, review checklists, and testing guides. Background knowledge for flutter-dev, flutter-reviewer, flutter-tester. Not user-invocable.

SKILL.md

6.2 KB, as published. Nobody here has run it

Flutter Guide — Clean Architecture + BLoC

Reference Guide

TopicReferenceUse When
Clean Architecturereferences/clean-architecture.mdLayer rules, dependency direction
BLoC Patternsreferences/bloc-patterns.md@freezed events/states, handlers, transformers
UI Guidelinesreferences/ui-guidelines.mdAppColors, AppTextStyles, SVGImage
Review Checklistreferences/review-checklist.mdCode review, quality checks
Mocking Guidereferences/mocking-guide.mdMocktail, MockBloc, ProviderContainer
Test Patternsreferences/test-patterns.mdUseCase tests, BLoC tests, widget tests

Project Structure

lib/
├── core/          # AppError, extensions, DI (GetIt)
├── data/
│   ├── mapper/    # Entity <-> Model mappers
│   ├── network/   # API client, models (@JsonSerializable), interceptors
│   ├── repository/ # Repository implementations
│   └── services/
├── domain/
│   ├── entity/    # Domain entities (@freezed)
│   ├── repository/ # Abstract interfaces
│   ├── services/
│   └── usecases/
├── presentation/
│   ├── {feature}/
│   │   ├── bloc.dart       # FeatureBloc
│   │   ├── events.dart     # @freezed events
│   │   ├── states.dart     # @freezed states
│   │   └── view/           # Pages + widgets
│   └── common/
└── resources/     # Colors, text styles, localization

Dependency Rule

Presentation -> Domain <- Data — Domain depends on NOTHING.

Critical Rules

1. MANDATORY: @freezed for Events and States

@freezed
class FeatureEvent with _$FeatureEvent {
  const factory FeatureEvent.started() = _Started;
  const factory FeatureEvent.loadData({required int id}) = _LoadData;
}

@freezed
class FeatureState with _$FeatureState {
  const factory FeatureState.initial() = _Initial;
  const factory FeatureState.loading() = _Loading;
  const factory FeatureState.loaded(Data data) = _Loaded;
  const factory FeatureState.error(AppError error) = _Error;
}

2. BLoC Individual Event Handlers

class FeatureBloc extends Bloc<FeatureEvent, FeatureState> {
  FeatureBloc() : super(const FeatureState.initial()) {
    on<_Started>(_onStarted);
    on<_LoadData>(_onLoadData);
  }

  Future<void> _onLoadData(_LoadData event, Emitter<FeatureState> emit) async {
    emit(const FeatureState.loading());
    final result = await _repository.getData(event.id);
    result.fold(
      (error) => emit(FeatureState.error(error)),
      (data) => emit(FeatureState.loaded(data)),
    );
  }
}

NEVER use event.when() or state.when() in BLoC handlers. NEVER use a single handler for all events.

3. Either for Error Handling

abstract class UserRepository {
  Future<Either<AppError, User>> getUser(int id);
}

4. Type-Safe Models

// Domain Entity
@freezed
class UserEntity with _$UserEntity {
  const factory UserEntity({
    required String id,
    required String name,
    required UserRole role,
  }) = _UserEntity;
}

// API Model
@freezed
@JsonSerializable()
class UserApiModel with _$UserApiModel {
  const factory UserApiModel({...}) = _UserApiModel;
  factory UserApiModel.fromJson(Map<String, dynamic> json) =>
      _$UserApiModelFromJson(json);
}

// Mapper
extension UserApiMapper on UserApiModel {
  UserEntity toDomain() => UserEntity(id: id, name: name, role: UserRole.fromString(role));
}

Dart 3.x: Use Modern Features

  • Sealed classes for exhaustive state matching (alternative to @freezed unions)
  • Pattern matching in switch expressions
  • Records for lightweight multiple return values
  • Null safety everywhere, no ! operator without justification

Performance Rules

  • const constructors everywhere possible
  • Keys on list items (ValueKey(item.id))
  • ListView.builder for large lists
  • buildWhen in BlocBuilder for granular rebuilds
  • CachedNetworkImage with memCacheWidth/memCacheHeight
  • Extract expensive subtrees into separate const widgets
  • No expensive operations in build() methods

Anti-Patterns (FORBIDDEN)

PatternReason
Map<String, dynamic> for dataNo type safety
event.when() in BLoC handlersUse individual handlers
state.when() in BLoC handlersOnly for UI
Single handler for all eventsHard to maintain
Hardcoded strings in UIUse AppLocalization
SvgPicture.asset()Use SVGImage()
Redundant commentsCode must be self-documenting
dynamic typeNo type safety

UI Patterns

// BlocBuilder with buildWhen
BlocBuilder<FeatureBloc, FeatureState>(
  buildWhen: (previous, current) => previous != current,
  builder: (context, state) {
    return state.when(
      initial: () => const SizedBox.shrink(),
      loading: () => const LoadingWidget(),
      loaded: (data) => DataWidget(data: data),
      error: (error) => ErrorWidget(error: error),
    );
  },
)

// BlocListener for side effects
BlocListener<FeatureBloc, FeatureState>(
  listenWhen: (previous, current) => current is _Error,
  listener: (context, state) {
    if (state is _Error) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(state.error.message)),
      );
    }
  },
)

Code Generation

flutter pub run build_runner build --delete-conflicting-outputs

Testing Summary

  • BLoC tests (MANDATORY): bloc_test with blocTest<>(), seed, expect, verify
  • Flow tests (MANDATORY): after create -> list updated, after delete -> item removed
  • Widget tests: BlocProvider + MockBloc
  • Coverage: 80%+ with flutter test --coverage

Review Summary

  1. Architecture compliance (correct layer, inward dependencies)
  2. Type safety (no dynamic, no Map<String, dynamic>)
  3. BLoC patterns (individual handlers, no event.when(), no state.when())
  4. @freezed on all events/states
  5. UI standards (AppColors, AppTextStyles, AppLocalization, const)
  6. No redundant comments

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.