flutter_provider_kit 0.0.1
flutter_provider_kit: ^0.0.1 copied to clipboard
A provider-based MVI architecture (MviViewModel, onAction, UiEventEmitter) and recommended folder structure, extending flutter_basic_kit_library.
flutter_provider_kit #
Read this in other languages: 한국어
A flutter_basic_kit_library extension that provides a provider-based architecture separating data / domain / presentation layers, plus the reusable base classes that architecture is built on (MviViewModel, UiEventEmitter, UseCase, Result).
What's included #
Result<T>— aSuccess/Failuresealed class, handled with Dart 3 pattern matching (switch)UseCase<Output, Params>— base class the use cases underdomain/use_case/extendMviViewModel<S, A>— aChangeNotifier-based class that holdsstate(S) and takes every user action through a single entry point,onAction(A action), dispatched withswitch(State/Action-style MVI)UiEventEmitter<E>— a mixin forMviViewModelthat emits one-off UI events (E) — snackbars, navigation — as aStream- Re-exports the whole
providerpackage (no need to addproviderseparately)
MviViewModel doesn't force a wrapper widget on you. Screens read state the standard provider way: context.watch<MyViewModel>().state. When a screen needs to change state, it doesn't grow another public method — it calls the single onAction(Action) entry point.
Install #
dependencies:
flutter_provider_kit: ^0.0.1
Recommended folder structure #
example/ implements a "photo search" feature end to end (with mock data) using this structure.
lib/
data/
data_source/
photo_api.dart # external API calls (mocked here)
repository/
photo_repository_impl.dart # implements the domain's abstract interface
domain/
model/
photo.dart # freezed model
repository/
photo_repository.dart # abstract interface
use_case/
get_photos_use_case.dart # extends UseCase<Output, Params>
presentation/
home/
components/
photo_widget.dart # widget local to home
home_screen.dart # reads state via context.watch<HomeViewModel>(), dispatches via onAction(Action)
home_action.dart # every user action the screen can produce (sealed)
home_state.dart # the state the screen reads on every rebuild
home_ui_event.dart # one-off events like snackbars/navigation
home_view_model.dart # extends MviViewModel<HomeState, HomeAction> with UiEventEmitter<HomeUiEvent>
di/
provider_setup.dart # manual wiring of repository/use_case/view_model
main.dart
test/
data/
photo_api_test.dart
ui/
home_view_model_test.dart
Layer rules #
- domain is pure business logic with no dependency on Flutter or external packages.
repository/holds only abstract interfaces; the real implementation lives indata/repository/. - data implements
domain's interfaces and isolates real API/DB calls insidedata_source/. - presentation is split into per-feature folders (
home/,detail/, ...), each bundling its ownstate/action/view_model/screen/components. - di is currently manual, function-based wiring (
provider_setup.dart). The structure is kept swappable forget_it/injectable(already bundled viaflutter_basic_kit_library) once that's needed — not decided yet.
Usage #
class HomeViewModel extends MviViewModel<HomeState, HomeAction>
with UiEventEmitter<HomeUiEvent> {
HomeViewModel(this._getPhotosUseCase) : super(const HomeState());
final GetPhotosUseCase _getPhotosUseCase;
@override
void onAction(HomeAction action) {
switch (action) {
case Search(:final query):
_search(query);
}
}
Future<void> _search(String query) async {
emit(state.copyWith(isLoading: true));
switch (await _getPhotosUseCase(query)) {
case Success(:final data):
emit(state.copyWith(photos: data, isLoading: false));
case Failure(:final error):
emit(state.copyWith(isLoading: false));
emitEvent(ShowErrorSnackBar(error.toString()));
}
}
}
// screen
final state = context.watch<HomeViewModel>().state;
context.read<HomeViewModel>().onAction(const Search('flutter'));
See example/ for the full working app.
Under consideration #
- A NestJS-CLI-style code generator for
repository/use_caseCRUD boilerplate (not started, to be discussed separately) - Whether to move DI to
get_it/injectable
Related packages #
| Package | Status |
|---|---|
| flutter_basic_kit_library | Published |
| flutter_provider_kit | this package |
| flutter_riverpod_kit | Published |
| flutter_bloc_kit | Published |
Versioning #
This package follows Semantic Versioning. See CHANGELOG.md for the full history.