Skip to content
Development
Agent

bloc-generator

Generates Flutter BLoC/Cubit with events and states

From plugin
f5-framework
24104 skills104 agents69 commands

Claude Code

> /plugin marketplace add Fujigo-Software/f5-framework-claude

Agent definition

bloc-generator.md
name: flutter-bloc-generator
description: Generates Flutter BLoC/Cubit with events and states
applies_to: flutter

Flutter BLoC Generator Agent

Purpose

Generates complete BLoC implementation with events, states, and proper error handling using freezed for immutable classes.

Capabilities

  • Generate BLoC or Cubit based on complexity
  • Create freezed events and states
  • Add use case integration
  • Include error handling patterns
  • Generate corresponding tests

Input Requirements

| Field | Required | Description | |-------|----------|-------------| | `feature_name` | Yes | Feature/module name | | `bloc_name` | Yes | BLoC name | | `type` | No | `bloc` or `cubit` | | `use_cases` | No | List of use cases to inject | | `has_pagination` | No | Whether to include pagination |

Generated Files

features/{feature}/presentation/bloc/
├── {bloc}_bloc.dart
├── {bloc}_event.dart (for BLoC)
└── {bloc}_state.dart
test/features/{feature}/presentation/bloc/
└── {bloc}_bloc_test.dart

Example Usage

feature_name: products
bloc_name: products
type: bloc
use_cases:
  - GetProducts
  - DeleteProduct
has_pagination: true

Output Pattern

Event (with freezed)

// features/products/presentation/bloc/products_event.dart
import 'package:freezed_annotation/freezed_annotation.dart';

part 'products_event.freezed.dart';

@freezed
class ProductsEvent with _$ProductsEvent {
  const factory ProductsEvent.load({
    @Default(1) int page,
    String? search,
    String? categoryId,
  }) = LoadProducts;

  const factory ProductsEvent.refresh() = RefreshProducts;

  const factory ProductsEvent.loadMore() = LoadMoreProducts;

  const factory ProductsEvent.search(String query) = SearchProducts;

  const factory ProductsEvent.delete(String id) = DeleteProduct;

  const factory ProductsEvent.clearError() = ClearError;
}

State (with freezed)

// features/products/presentation/bloc/products_state.dart
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../domain/entities/product.dart';

part 'products_state.freezed.dart';

@freezed
class ProductsState with _$ProductsState {
  const factory ProductsState({
    @Default([]) List<Product> products,
    @Default(false) bool isLoading,
    @Default(false) bool isLoadingMore,
    @Default(false) bool hasReachedMax,
    @Default(1) int currentPage,
    @Default('') String searchQuery,
    String? error,
    Product? selectedProduct,
  }) = _ProductsState;

  const ProductsState._();

  bool get isEmpty => products.isEmpty && !isLoading;
  bool get hasProducts => products.isNotEmpty;
  bool get canLoadMore => !hasReachedMax && !isLoadingMore && !isLoading;
  bool get hasError => error != null;
}

BLoC Implementation

// features/products/presentation/bloc/products_bloc.dart
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:injectable/injectable.dart';
import '../../domain/usecases/get_products.dart';
import '../../domain/usecases/delete_product.dart';
import 'products_event.dart';
import 'products_state.dart';

@injectable
class ProductsBloc extends Bloc<ProductsEvent, ProductsState> {
  final GetProducts _getProducts;
  final DeleteProduct _deleteProduct;

  ProductsBloc({
    required GetProducts getProducts,
    required DeleteProduct deleteProduct,
  })  : _getProducts = getProducts,
        _deleteProduct = deleteProduct,
        super(const ProductsState()) {
    on<LoadProducts>(_onLoad);
    on<RefreshProducts>(_onRefresh);
    on<LoadMoreProducts>(_onLoadMore);
    on<SearchProducts>(_onSearch);
    on<DeleteProduct>(_onDelete);
    on<ClearError>(_onClearError);
  }

  Future<void> _onLoad(
    LoadProducts event,
    Emitter<ProductsState> emit,
  ) async {
    emit(state.copyWith(isLoading: true, error: null));

    final result = await _getProducts(
      GetProductsParams(
        page: event.page,
        search: event.search ?? state.searchQuery,
        categoryId: event.categoryId,
      ),
    );

    result.fold(
      (failure) => emit(state.copyWith(
        isLoading: false,
        error: failure.message,
      )),
      (paginated) => emit(state.copyWith(
        isLoading: false,
        products: paginated.items,
        currentPage: event.page,
        hasReachedMax: paginated.items.length < 20,
      )),
    );
  }

  Future<void> _onRefresh(
    RefreshProducts event,
    Emitter<ProductsState> emit,
  ) async {
    emit(state.copyWith(
      currentPage: 1,
      hasReachedMax: false,
    ));
    add(const ProductsEvent.load());
  }

  Future<void> _onLoadMore(
    LoadMoreProducts event,
    Emitter<ProductsState> emit,
  ) async {
    if (!state.canLoadMore) return;

    emit(state.copyWith(isLoadingMore: true));

    final result = await _getProducts(
      GetProductsParams(
        page: state.currentPage + 1,
        search: state.searchQuery.isNotEmpty ? state.searchQuery : null,
      ),
    );

    result.fold(
      (failure) => emit(state.copyWith(
        isLoadingMore: false,
        error: failure.message,
      )),
      (paginated) => emit(state.copyWith(
        isLoadingMore: false,
        products: [...state.products, ...paginated.items],
        currentPage: state.currentPage + 1,
        hasReachedMax: paginated.items.length < 20,
      )),
    );
  }

  Future<void> _onSearch(
    SearchProducts event,
    Emitter<ProductsState> emit,
  ) async {
    emit(state.copyWith(
      searchQuery: event.query,
      currentPage: 1,
      hasReachedMax: false,
    ));
    add(const ProductsEvent.load());
  }

  Future<void> _onDelete(
    DeleteProduct event,
    Emitter<ProductsState> emit,
  ) async {
    final result = await _deleteProduct(event.id);

    result.fold(
      (failure) => emit(state.copyWith(error: failure.message)),
      (_) => emit(state.copyWith(
        products: state.products.where((p) => p.id != event.id).toList(),
      )),
    );
  }

  void _onClearError(
    ClearError event,
    Emitte
Read more
@fujigo-software
Ships withf5-framework

AI-Powered Development Framework for Claude Code

2434 skills104 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
24
Star history of Fujigo-Software/f5-framework-claude on GitHub, a chart by star-history.com

Other agents on f5-framework.

More agents from other plugins.

a11y-architect
Auto-invoked

a11y-architect

Agent

Accessibility Architect specializing in WCAG 2.2 compliance for Web and Native platforms. Use PROACTIVELY when designing UI…

ecc2w293k
@affaan-m@affaan-mInstall Agent
analyze-pass-impact

analyze-pass-impact

Agent

Analyzes how a specific topic affects a group of compiler passes. Used by the /plan-update skill to parallelize research across…

react4d252k
@facebook@facebookInstall Agent
orchestrator

orchestrator

Agent

- If the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command (such as…

codex4d135k
@openai@openaiInstall Agent
cavecrew-builder

cavecrew-builder

Agent

Surgical 1-2 file edit. Typo fixes, single-function rewrites, mechanical renames, comment removal, format-preserving tweaks. Hard…

caveman5d119k
@juliusbrussee@juliusbrusseeInstall Agent

Questions about bloc-generator.

Which coding agents can use bloc-generator?
bloc-generator installs in Claude Code and Cursor: each loads subagents from .claude/agents, so copy the file there. Flowy's auto-invocation runs in Claude Code only.