From 591b9217dd96b0b5603dfb678adaa378fe77d8e2 Mon Sep 17 00:00:00 2001 From: Nikolas Rimikis Date: Thu, 26 Oct 2023 08:17:39 +0200 Subject: [PATCH] docs(neon): document neon blocs Signed-off-by: Nikolas Rimikis --- packages/neon/neon/lib/src/bloc/bloc.dart | 25 +++++++++++++++++++ .../neon/neon/lib/src/blocs/accounts.dart | 7 ++++++ packages/neon/neon/lib/src/blocs/apps.dart | 15 +++++++++++ .../neon/neon/lib/src/blocs/capabilities.dart | 1 + 4 files changed, 48 insertions(+) diff --git a/packages/neon/neon/lib/src/bloc/bloc.dart b/packages/neon/neon/lib/src/bloc/bloc.dart index d3b94912..835a24ff 100644 --- a/packages/neon/neon/lib/src/bloc/bloc.dart +++ b/packages/neon/neon/lib/src/bloc/bloc.dart @@ -4,12 +4,23 @@ import 'package:flutter/foundation.dart'; import 'package:neon/src/models/disposable.dart'; import 'package:neon/src/utils/request_manager.dart'; +/// A Bloc for implementing the Business Logic Component pattern. +/// +/// This design pattern helps to separate presentation from business logic. +/// Following the BLoC pattern facilitates testability and reusability. +/// +/// If you are new to Flutter you might want to read: +/// https://www.didierboelens.com/blog/en/reactive-programming-streams-bloc abstract class Bloc implements Disposable { @override @mustCallSuper void dispose(); } +/// A bloc implementing basic data fetching. +/// +/// See: +/// * [Bloc]: for a generic bloc. abstract class InteractiveBloc extends Bloc { @override void dispose() { @@ -17,14 +28,28 @@ abstract class InteractiveBloc extends Bloc { } final _errorsStreamController = StreamController(); + + /// A stream of error events. late Stream errors = _errorsStreamController.stream.asBroadcastStream(); + /// Refreshes the state of the bloc. + /// + /// Commonly involves re-fetching data from the server. FutureOr refresh(); + /// Adds an error to the [errors] state. + @protected void addError(final Object error) { _errorsStreamController.add(error); } + /// Wraps the action [call]. + /// + /// If [disableTimeout] is `true` [RequestManager] will apply the default + /// timeout. On success the state will be refreshed through the [refresh] + /// callback falling back to [this.refresh] if not supplied. Any errors will + /// be forwarded to [addError]. + @protected // ignore: avoid_void_async void wrapAction( final AsyncCallback call, { diff --git a/packages/neon/neon/lib/src/blocs/accounts.dart b/packages/neon/neon/lib/src/blocs/accounts.dart index 91e085e9..6c985611 100644 --- a/packages/neon/neon/lib/src/blocs/accounts.dart +++ b/packages/neon/neon/lib/src/blocs/accounts.dart @@ -21,6 +21,7 @@ import 'package:rxdart/rxdart.dart'; const _keyAccounts = 'accounts'; +/// Events for the [AccountsBloc]. @internal abstract interface class AccountsBlocEvents { /// Logs in the given [account]. @@ -45,6 +46,7 @@ abstract interface class AccountsBlocEvents { void setActiveAccount(final Account account); } +/// States for the [AccountsBloc]. @internal abstract interface class AccountsBlocStates { /// All registered accounts. @@ -59,7 +61,12 @@ abstract interface class AccountsBlocStates { BehaviorSubject get activeAccount; } +/// The Bloc responsible for managing the [Account]s class AccountsBloc extends Bloc implements AccountsBlocEvents, AccountsBlocStates { + /// Creates a new account bloc. + /// + /// The last state will be loaded from storage and all necessary listeners + /// will be set up. AccountsBloc( this._globalOptions, this._allAppImplementations, diff --git a/packages/neon/neon/lib/src/blocs/apps.dart b/packages/neon/neon/lib/src/blocs/apps.dart index 7200037d..b65a67a3 100644 --- a/packages/neon/neon/lib/src/blocs/apps.dart +++ b/packages/neon/neon/lib/src/blocs/apps.dart @@ -16,6 +16,7 @@ import 'package:nextcloud/nextcloud.dart'; import 'package:provider/provider.dart'; import 'package:rxdart/rxdart.dart'; +/// Events for the [AppsBloc]. @internal abstract interface class AppsBlocEvents { /// Sets the active app using the [appID]. @@ -25,21 +26,31 @@ abstract interface class AppsBlocEvents { void setActiveApp(final String appID, {final bool skipAlreadySet = false}); } +/// States for the [AppsBloc]. @internal abstract interface class AppsBlocStates { + /// A collection of clients used in the app drawer. + /// + /// It does not contain clients for that are specially handled like for the notifications. BehaviorSubject>> get appImplementations; + /// The interface of the notifications app. BehaviorSubject> get notificationsAppImplementation; + /// The currently active app. BehaviorSubject get activeApp; + /// A subject emitting an event when the notifications page should be opened. BehaviorSubject get openNotifications; + /// A collection of unsupported apps and their minimum required version. BehaviorSubject> get appVersions; } +/// The Bloc responsible for managing the [AppImplementation]s. @internal class AppsBloc extends InteractiveBloc implements AppsBlocEvents, AppsBlocStates { + /// Creates a new apps bloc. AppsBloc( this._capabilitiesBloc, this._accountsBloc, @@ -229,9 +240,13 @@ class AppsBloc extends InteractiveBloc implements AppsBlocEvents, AppsBlocStates } } + /// Returns the active [Bloc] for the given [appImplementation]. + /// + /// If no bloc exists yet a new one will be instantiated and cached in [AppImplementation.blocsCache]. T getAppBloc(final AppImplementation appImplementation) => appImplementation.getBloc(_account); + /// Returns the active [Bloc] for every registered [AppImplementation] wrapped in a Provider. List> get appBlocProviders => _allAppImplementations.map((final appImplementation) => appImplementation.blocProvider).toList(); } diff --git a/packages/neon/neon/lib/src/blocs/capabilities.dart b/packages/neon/neon/lib/src/blocs/capabilities.dart index 6b01bcd5..3aa4710f 100644 --- a/packages/neon/neon/lib/src/blocs/capabilities.dart +++ b/packages/neon/neon/lib/src/blocs/capabilities.dart @@ -18,6 +18,7 @@ abstract interface class CapabilitiesBlocStates { @internal class CapabilitiesBloc extends InteractiveBloc implements CapabilitiesBlocEvents, CapabilitiesBlocStates { + /// Creates a new capabilities bloc. CapabilitiesBloc( this._account, ) {