--- description: "BLoC / Cubit conventions for {{PROJECT_NAME}}" alwaysApply: true --- # BLoC / Cubit Standards — {{PROJECT_NAME}} ## When to use BLoC vs Cubit - **Cubit**: simple state with no meaningful event history (toggle, counter, pagination) - **BLoC**: event-driven flows where event history or transitions matter (auth, checkout, form wizard) ## Event and State classes ```dart // Events — sealed class (exhaustive switch) sealed class AuthEvent { const AuthEvent(); } final class AuthLoginRequested extends AuthEvent { final String email, password; const AuthLoginRequested({required this.email, required this.password}); } final class AuthLogoutRequested extends AuthEvent { const AuthLogoutRequested(); } // States — sealed class, immutable sealed class AuthState { const AuthState(); } final class AuthInitial extends AuthState { const AuthInitial(); } final class AuthLoading extends AuthState { const AuthLoading(); } final class AuthAuthenticated extends AuthState { final User user; const AuthAuthenticated(this.user); } final class AuthUnauthenticated extends AuthState { const AuthUnauthenticated(); } final class AuthFailure extends AuthState { final String message; const AuthFailure(this.message); } ``` ## BlocProvider placement - Create `BlocProvider` at the **route level** (in {{ROUTING}} route definitions) - `MultiBlocProvider` at route level for screens needing multiple blocs - **NEVER** create `BlocProvider` inside a widget's `build()` method ## Usage rules - **NEVER** call `bloc.add()` inside `build()` — only in gesture callbacks or `initState()` - Use `BlocConsumer` only when BOTH `listen` + `build` logic are needed - Use `BlocSelector` when only a subset of state triggers a rebuild - Every BLoC must override `close()` and cancel `StreamSubscription`s ## BlocBuilder patterns ```dart BlocBuilder( builder: (context, state) => switch (state) { AuthInitial() => const SizedBox.shrink(), AuthLoading() => const LoadingIndicator(), AuthAuthenticated(user: final u) => HomeScreen(user: u), AuthUnauthenticated() => const LoginScreen(), AuthFailure(message: final m) => ErrorScreen(message: m), }, ) ``` ## File locations in {{PROJECT_NAME}} - `lib/features/[feature]/presentation/bloc/[feature]_bloc.dart` - `lib/features/[feature]/presentation/bloc/[feature]_event.dart` - `lib/features/[feature]/presentation/bloc/[feature]_state.dart`