An example of "reactive/streaming repository" as a solution for BLoC to BLoC communication

Overview

Reactive Repositories

An example of listening to a Stream from repository layer (instead of explicitly using get/fetch) as a solution for BLoC to BLoC communication, inspired by updated documentation at bloc library and this tweet.

Check out the Medium article that explains everything in more detail


example

Example

The main thing to notice is how ListCubit reloads (and sorts by favorites) the ItemsScreen in reaction to DetailsCubit successfully toggling isFavorite, but DetailsCubit has no reference to ListCubit.

example

BLoC

class ListCubit extends Cubit<ListState> {
  ListCubit()
      : _itemsRepository = getIt.get(),
        _sorter = Sorter(),
        super(ListLoading()) {
    _subscribe();
  }

  final ItemsRepository _itemsRepository;
  final Sorter _sorter;
  late final StreamSubscription _subscription;

  void load({bool force = false}) async {
    emit(ListLoading());
    await _itemsRepository.fetchAll(force: force);
  }

  void reload() => load(force: true);

  void _subscribe() {
    _subscription = _itemsRepository.items.listen(
      (items) {
        final sortedItems = _sorter.sortByFavorite(items);
        emit(ListLoaded(sortedItems));
      },
      onError: (error) => emit(ListError('$error')),
    );
  }

  @override
  Future<void> close() {
    _subscription.cancel();
    return super.close();
  }
}

class DetailsCubit extends Cubit<DetailsState> {
  DetailsCubit()
      : _itemsRepository = getIt.get(),
        super(const DetailsLoading());

  final ItemsRepository _itemsRepository;
  Item? _currentItem;

  void load(int? itemId) async {
    emit(DetailsLoading(_currentItem));

    if (itemId == null) {
      emit(const DetailsError('Cannot parse itemId'));
      return;
    }

    try {
      _currentItem = await _itemsRepository.getOne(itemId);
      if (_currentItem != null) {
        emit(DetailsLoaded(_currentItem!));
      } else {
        emit(DetailsError('Cannot find item $itemId'));
      }
    } catch (e, st) {
      emit(DetailsError('$e: $st'));
    }
  }

  void toggleFavorite(int itemId) async {
    emit(DetailsLoading(_currentItem));

    _currentItem = await _itemsRepository.toggleFavorite(itemId);

    if (_currentItem != null) {
      emit(DetailsLoaded(_currentItem!));
    } else {
      emit(const DetailsError('Failed to toggle favorite'));
    }
  }
}

Repository

abstract class ItemsRepository {
  final _controller = StreamController<List<Item>>();

  Stream<List<Item>> get items => _controller.stream;

  void addToStream(List<Item> items) => _controller.sink.add(items);

  Future<void> fetchAll({bool force = false});
  Future<Item?> getOne(int itemId);
  Future<Item?> toggleFavorite(int itemId);
}

class FakeItemsRepository extends ItemsRepository {
  List<Item> _currentItems = [];

  @override
  Future<void> fetchAll({bool force = false}) async {
    if (_currentItems.isEmpty || force) {
      await Future.delayed(const Duration(milliseconds: 400));
      _currentItems = List.generate(12, (_) => Item.fake());
    }

    addToStream(_currentItems);
  }

  @override
  Future<Item?> getOne(int itemId) async {
    if (_currentItems.isEmpty) {
      await fetchAll();
    }

    try {
      return _currentItems.firstWhere((item) => item.id == itemId);
    } catch (e) {
      return null;
    }
  }

  @override
  Future<Item?> toggleFavorite(int itemId) async {
    await Future.delayed(const Duration(milliseconds: 200));

    final item = await getOne(itemId);
    if (item == null) {
      return null;
    }

    final toggledItem = item.copyWith(isFavorite: !item.isFavorite);
    _updateCurrentItemsWith(toggledItem);

    addToStream(_currentItems);

    return toggledItem;
  }

  void _updateCurrentItemsWith(Item item) {
    final index = _currentItems.indexWhere((it) => it.id == item.id);
    if (index != -1) {
      _currentItems[index] = item;
    }
  }
}
You might also like...

A starter kit for beginner learns with Bloc pattern, RxDart, sqflite, Fluro and Dio to architect a flutter project. This starter kit build an App Store app as a example

A starter kit for beginner learns with Bloc pattern, RxDart, sqflite, Fluro and Dio to architect a flutter project. This starter kit build an App Store app as a example

Flutter Starter Kit - App Store Example A starter kit for beginner learns with Bloc pattern, RxDart, sqflite, Fluro and Dio to architect a flutter pro

Jan 8, 2023

Example implement todo with BLOC flutter

exampletododevindo A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you start

Aug 9, 2021

Flutter web example with Firebase Authentication, Firestore Collection, BloC Pattern

flutter_auth_web Flutter Firebase auth. Getting Started This project is a starting point for a Flutter application. A few resources to get you started

Feb 26, 2022

Flutter Control is complex library to maintain App and State management. Library merges multiple functionality under one hood. This approach helps to tidily bound separated logic into complex solution.

Flutter Control is complex library to maintain App and State management. Library merges multiple functionality under one hood. This approach helps to tidily bound separated logic into complex solution.

Flutter Control is complex library to maintain App and State management. Library merges multiple functionality under one hood. This approach helps to

Feb 23, 2022

Flutter plugin that provides a quick&dirty workaround for incompatibility between VMWare Airwatch MDM solution and Dart Sockets implementation

airwatch_socket_workaround This plugin has been created to enable flutter apps to reach endpoints that are only reachable using a VMWare airwatch per

Nov 11, 2022

Creating cross-platform solution to help keep individuals connected

Back-to-Hue-Frontend Creating cross-platform solution to help keep individuals connected First Draft: No backend Google Maps API, format into desired

Mar 30, 2022

Cubit is a lightweight state management solution

Cubit is a lightweight state management solution

Cubit is a lightweight state management solution. It is a subset of the bloc package that does not rely on events and instead uses methods to emit new states.

Nov 23, 2022

Kc - A Simple App Solution for Calculation Fraction (Kali) size of a Lehenga. this is very useful for Fashion designers and tailors. Simple UI with best User Experience.

kc A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if this is yo

Jan 8, 2022

Lightweight i18n solution for Flutter

fast_i18n Lightweight i18n solution. Use JSON, YAML or CSV files to create typesafe translations. About this library 🚀 Minimal setup, create JSON fil

Dec 26, 2022
Owner
Sandro Lovnički
Computer Scientist, Mathematician, Software Engineer, Flutter Enthusiast
Sandro Lovnički
Anonchat-v2 - Anonchat - A microprotocol for communication build on Dart using sockets

AnonChat Originally made by Arslee on arslee07/anonchat. What's this? Anonchat i

null 6 Nov 11, 2022
Dart package to which makes data communication easy among different modules of your application.

LiveStream - Dart LiveStream is a data holder class which can observe change of data in real-time and emit values too. Here's emitter subscriber patte

Shreyas Patil 75 Sep 28, 2022
Allows communication between your bot and the Web App built in Flutter displayed inside Telegram.

tele_web_app It enables communication between your bot and the Flutter-embedded Web App displayed inside Telegram by making use of interoperability be

Yeikel Uriarte Arteaga 16 Dec 8, 2022
A Flutter plugin that allows communication with a Parse Server

Parse For Flutter! Hi, this is a Flutter plugin that allows communication with a Parse Server, (https://parseplatform.org) either hosted on your own s

Doğuş Dicle 0 Apr 14, 2022
This a library to simplify isolate thread communication.

This a library to simplify islate thread communication. It abstracts the data transfer between islate and the main thread into a simple channel, and t

吴楚衡 3 Oct 31, 2022
This repo is an example of clean architecture using the GetX state-management solution.

GetX Clean Architecture A Flutter Clean Architecture Using GetX. This repo is forked from: https://github.com/phamdinhduc795397/flutter-getx-clean-arc

Md. Siam 78 Jan 3, 2023
Flutter bloc example - An app for State management using BLoC pattern in Flutter

Flutter BLoC My first app for State management using BLoC pattern in Flutter Col

Harshil Patel 1 Jun 16, 2022
Petrus Nguyễn Thái Học 193 Dec 29, 2022
Lottie-package-example-Flutter - A simple example about lottie package in Flutter

Lottie Package example - Flutter ScreenShot ⚠️ Essential Packages lottie: ^1.2.1

AmirHossein Bayat 3 Dec 7, 2022
Smooth-Page-Indicator-Example-Flutter - A simple example about smooth page indicator in Flutter

Smooth Page Indicator Example - Flutter Screenshots ⚠️ Essential Packages smooth

AmirHossein Bayat 6 Dec 7, 2022