Content
Code patterns & best practices
General code styling rules
-
Method should always have a return value. If method doesn't return anything, it should be marked as void
-
Method naming: if method returns Widget, it should start with 'build'.
Widgets layer
Preferably create stateless widgets, not methods if you build a reusable UI block
Working with Flutter BLoC:
Event Handling in Bloc:
By default, we prefer using sealed event classes with a single **on<Event>** handler. This approach ensures compile-time exhaustiveness checks — if a new event subtype is added, the compiler will require handling it explicitly in the switch statement. It also improves code organization by keeping related event logic grouped together and easier to maintain.
// events.dart
sealed class WorkPackageFormEvent {}
final class WorkPackageFormInit extends WorkPackageFormEvent {}
final class WorkPackageFormRefresh extends WorkPackageFormEvent {}
final class WorkPackageFormSubmit extends WorkPackageFormEvent {}
final class WorkPackageFormUpdated extends WorkPackageFormEvent {}
// bloc.dart
on<WorkPackageFormEvent>(
(event, emit) => switch (event) {
WorkPackageFormInit() => _onInit(event, emit),
WorkPackageFormRefresh() => _onRefresh(event, emit),
WorkPackageFormSubmit() => _onSubmit(emit),
WorkPackageFormUpdated() => _onUpdated(event, emit),
},
);
If no event transformers (e.g., debounce, throttle, droppable, restartable) are required, always use the sealed-class + single-handler pattern for clarity and type safety.
When individual events require different concurrency or timing behaviors, use separate **on<SpecificEvent>** handlers to assign appropriate transformers and keep event processing independent.
on<WorkPackagesInitEvent>((event, emit) => _init(event, emit));
on<WorkPackagesRefreshEvent>((event, emit) => _refresh(event, emit));
on<WorkPackagesLoadEvent>((event, emit) => _load(event, emit));
// Example: distinct transformer for one event
on<WorkPackagesUpdateFilterEvent>(
transformer: debounceSequential(const Duration(milliseconds: 300)),
(event, emit) => _updateFilter(event, emit),
);
In summary:
✅ Default → sealed class + single on<Event> with switch
⚙️ Exception → multiple on<SpecificEvent> when distinct transformers are needed