flutter_provider_kit 0.0.2 copy "flutter_provider_kit: ^0.0.2" to clipboard
flutter_provider_kit: ^0.0.2 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> — a Success/Failure sealed class, handled with Dart 3 pattern matching (switch)
  • UseCase<Output, Params> — base class the use cases under domain/use_case/ extend
  • MviViewModel<S, A> — a ChangeNotifier-based class that holds state (S) and takes every user action through a single entry point, onAction(A action), dispatched with switch (State/Action-style MVI)
  • UiEventEmitter<E> — a mixin for MviViewModel that emits one-off UI events (E) — snackbars, navigation — as a Stream
  • Re-exports the whole provider package (no need to add provider separately)

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

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 in data/repository/.
  • data implements domain's interfaces and isolates real API/DB calls inside data_source/.
  • presentation is split into per-feature folders (home/, detail/, ...), each bundling its own state/action/view_model/screen/components.
  • di is currently manual, function-based wiring (provider_setup.dart). The structure is kept swappable for get_it/injectable (already bundled via flutter_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_case CRUD boilerplate (not started, to be discussed separately)
  • Whether to move DI to get_it/injectable
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.

Additional information #

2
likes
0
points
319
downloads

Publisher

verified publisherdotpea.com

Weekly Downloads

A provider-based MVI architecture (MviViewModel, onAction, UiEventEmitter) and recommended folder structure, extending flutter_basic_kit_library.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, flutter_basic_kit_library, provider

More

Packages that depend on flutter_provider_kit