bloc_ai 1.1.3
bloc_ai: ^1.1.3 copied to clipboard
BlocAI: a Flutter package for strict Bloc clean architecture.
BlocAI #
bloc_ai is a Flutter package that enforces an MVP architecture powered by
flutter_bloc.
The package centers around an extendable BaseApp (a MaterialApp root),
which wires presenter lifecycle, view attachment, and Bloc/Cubit state
propagation at app entry.
What this package enforces #
- One-way flow:
View -> Presenter intent -> Bloc/Cubit state -> View render - Typed contracts for
MvpState,MvpView, andMvpPresenter - A
BlocPresenterbase class that listens toStateStreamableSource - Lifecycle hooks (
onInit,onDispose, attach/detach view) in a consistent path
Quick start (BaseApp first) #
class CounterState extends MvpState {
const CounterState(this.value);
final int value;
}
class CounterView implements MvpView<CounterState> {
@override
void render(CounterState state) {}
}
class CounterCubit extends Cubit<CounterState> {
CounterCubit() : super(const CounterState(0));
void increment() => emit(CounterState(state.value + 1));
}
class CounterPresenter extends BlocPresenter<CounterView, CounterState> {
CounterPresenter(this.cubit, this.repository) : super(cubit);
final CounterCubit cubit;
final CounterRepository repository;
void onIncrementTap() => cubit.setCount(repository.incrementFrom(cubit.state.value));
}
class AppRoot extends BaseApp<CounterPresenter, CounterView, CounterState> {
const AppRoot({super.key});
@override
List<RepositoryProvider<Object?>> get repositoryProviders =>
<RepositoryProvider<Object?>>[
RepositoryProvider<Object?>.value(value: CounterRepository()),
];
@override
List<BlocProviderSingleChildWidget> get blocProviders =>
<BlocProviderSingleChildWidget>[
BlocProvider<CounterCubit>(create: (_) => CounterCubit()),
];
@override
CounterPresenter createPresenter(BuildContext context) {
final cubit = BlocProvider.of<CounterCubit>(context);
final repo = RepositoryProvider.of<Object?>(context) as CounterRepository;
return CounterPresenter(cubit, repo);
}
@override
CounterView createView(BuildContext context) => CounterView();
@override
Widget buildHome(BuildContext context, CounterState state, CounterPresenter presenter) {
return Scaffold(
body: TextButton(
onPressed: presenter.onIncrementTap,
child: Text('Count: ${state.value}'),
),
);
}
}
Recommended module structure #
feature/
data/
domain/
presentation/
bloc/
presenter/
view/
Do and don't #
- Do keep user intents in presenter methods.
- Do keep business state in Bloc/Cubit.
- Do keep rendering concerns in
MvpViewand widgets. - Do extend
BaseAppso architecture enforcement starts from app entry. - Don't call repositories directly from widgets.
- Don't mutate UI state outside Bloc/Cubit transitions.
Example #
A minimal runnable example app lives in example/ and shows
BaseApp + BaseBloc + BasePage together.
AI Enforcement Contracts #
Machine-readable enforcement files for AI tools are available in ai/:
ai/architecture_rules.jsonai/feature_scaffold_contract.json