一键导入
add-bloc
Generate a BLoC or Cubit for an existing feature using Dart 3 sealed classes and Equatable. Use when adding state management to a feature.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Generate a BLoC or Cubit for an existing feature using Dart 3 sealed classes and Equatable. Use when adding state management to a feature.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Verify that all code changes adhere to the professor's grading criteria and Aptis App coding standards.
Scaffold a new Flutter feature with a full 3-layer Clean Architecture structure (data/domain/presentation). Use when creating a new e-commerce feature from scratch.
Audit a feature for Clean Architecture violations and produce a prioritized fix list. Use when generated code may have broken layer rules, missing use cases, or incorrect BLoC patterns.
Register all components of a feature in injection_container.dart following the correct factory vs singleton rules. Use after scaffolding a new feature or when DI registration is missing.
| name | add-bloc |
| description | Generate a BLoC or Cubit for an existing feature using Dart 3 sealed classes and Equatable. Use when adding state management to a feature. |
Generates event + state + bloc files with Dart 3 sealed classes.
| Use BLoC when | Use Cubit when |
|---|---|
| Multiple named events from the UI | Simple load/error state |
| Need to trace specific event flows | Toggle, counter, selection |
| auth, product, checkout, order | cart, profile, theme, nav |
// lib/features/{feature}/presentation/bloc/{feature}_event.dart
import 'package:equatable/equatable.dart';
sealed class {Feature}Event extends Equatable {
const {Feature}Event();
@override
List<Object?> get props => [];
}
final class {Feature}ListRequested extends {Feature}Event {
const {Feature}ListRequested();
}
final class {Feature}DetailRequested extends {Feature}Event {
final String id;
const {Feature}DetailRequested(this.id);
@override
List<Object?> get props => [id];
}
// lib/features/{feature}/presentation/bloc/{feature}_state.dart
import 'package:equatable/equatable.dart';
import '../../domain/entities/{feature}_entity.dart';
sealed class {Feature}State extends Equatable {
const {Feature}State();
@override
List<Object?> get props => [];
}
final class {Feature}Initial extends {Feature}State {
const {Feature}Initial();
}
final class {Feature}Loading extends {Feature}State {
const {Feature}Loading();
}
final class {Feature}Loaded extends {Feature}State {
final List<{Feature}Entity> items;
const {Feature}Loaded(this.items);
@override
List<Object?> get props => [items];
}
final class {Feature}DetailLoaded extends {Feature}State {
final {Feature}Entity item;
const {Feature}DetailLoaded(item);
@override
List<Object?> get props => [item];
}
final class {Feature}Error extends {Feature}State {
final String message;
const {Feature}Error(this.message);
@override
List<Object?> get props => [message];
}
// lib/features/{feature}/presentation/bloc/{feature}_bloc.dart
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_ecommerce/core/errors/result.dart';
import '../../domain/usecases/get_{feature}s_usecase.dart';
import '../../domain/repositories/{feature}_repository.dart';
import '{feature}_event.dart';
import '{feature}_state.dart';
class {Feature}Bloc extends Bloc<{Feature}Event, {Feature}State> {
final Get{Feature}sUseCase _getUseCase;
final {Feature}Repository _repository;
{Feature}Bloc({
required Get{Feature}sUseCase getUseCase,
required {Feature}Repository repository,
}) : _getUseCase = getUseCase,
_repository = repository,
super(const {Feature}Initial()) {
on<{Feature}ListRequested>(_onListRequested);
on<{Feature}DetailRequested>(_onDetailRequested);
}
Future<void> _onListRequested(
{Feature}ListRequested event,
Emitter<{Feature}State> emit,
) async {
emit(const {Feature}Loading());
final result = await _getUseCase();
switch (result) {
case Success(:final data):
emit({Feature}Loaded(data));
case ResultFailure(:final failure):
emit({Feature}Error(failure.message));
}
}
Future<void> _onDetailRequested(
{Feature}DetailRequested event,
Emitter<{Feature}State> emit,
) async {
emit(const {Feature}Loading());
final result = await _repository.getById(event.id);
switch (result) {
case Success(:final data):
emit({Feature}DetailLoaded(data));
case ResultFailure(:final failure):
emit({Feature}Error(failure.message));
}
}
}
// lib/features/{feature}/presentation/cubit/{feature}_state.dart
import 'package:equatable/equatable.dart';
import '../../domain/entities/{feature}_entity.dart';
sealed class {Feature}State extends Equatable {
const {Feature}State();
@override List<Object?> get props => [];
}
final class {Feature}Initial extends {Feature}State { const {Feature}Initial(); }
final class {Feature}Loading extends {Feature}State { const {Feature}Loading(); }
final class {Feature}Loaded extends {Feature}State {
final List<{Feature}Entity> items;
const {Feature}Loaded(this.items);
@override List<Object?> get props => [items];
}
final class {Feature}Error extends {Feature}State {
final String message;
const {Feature}Error(this.message);
@override List<Object?> get props => [message];
}
// lib/features/{feature}/presentation/cubit/{feature}_cubit.dart
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_ecommerce/core/errors/result.dart';
import '../../domain/repositories/{feature}_repository.dart';
import '{feature}_state.dart';
class {Feature}Cubit extends Cubit<{Feature}State> {
final {Feature}Repository _repository;
{Feature}Cubit(this._repository) : super(const {Feature}Initial());
Future<void> load() async {
emit(const {Feature}Loading());
final result = await _repository.getAll();
switch (result) {
case Success(:final data): emit({Feature}Loaded(data));
case ResultFailure(:final failure): emit({Feature}Error(failure.message));
}
}
}
// Dispatch event safely from initState
@override
void initState() {
super.initState();
Future.microtask(() {
if (!mounted) return;
context.read<{Feature}Bloc>().add(const {Feature}ListRequested());
});
}
// Consume state — use switch expression on sealed class
BlocBuilder<{Feature}Bloc, {Feature}State>(
builder: (context, state) => switch (state) {
{Feature}Loading() => const CircularProgressIndicator(),
{Feature}Loaded(:final items) => ListView.builder(
itemCount: items.length,
itemBuilder: (_, i) => Text(items[i].id),
),
{Feature}Error(:final message) => Text(message),
_ => const SizedBox.shrink(),
},
)
default: arm in a switch on sealed state — defeats exhaustivenesscontext.read<>() directly in initState() — use Future.microtaskabstract class for Event/State — must be sealed class