Skip to content

Commit

Permalink
docs(neon): document neon blocs
Browse files Browse the repository at this point in the history
Signed-off-by: Nikolas Rimikis <[email protected]>
  • Loading branch information
Leptopoda committed Oct 26, 2023
1 parent ab10025 commit 35bf337
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 0 deletions.
25 changes: 25 additions & 0 deletions packages/neon/neon/lib/src/bloc/bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,52 @@ 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() {
unawaited(_errorsStreamController.close());
}

final _errorsStreamController = StreamController<Object>();

/// A stream of error events.
late Stream<Object> errors = _errorsStreamController.stream.asBroadcastStream();

/// Refreshes the state of the bloc.
///
/// Commonly involves re fetching data from the server.
FutureOr<void> 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, {
Expand Down
7 changes: 7 additions & 0 deletions packages/neon/neon/lib/src/blocs/accounts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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].
Expand All @@ -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.
Expand All @@ -59,7 +61,12 @@ abstract interface class AccountsBlocStates {
BehaviorSubject<Account?> 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,
Expand Down
15 changes: 15 additions & 0 deletions packages/neon/neon/lib/src/blocs/apps.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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].
Expand All @@ -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<Result<Iterable<AppImplementation>>> get appImplementations;

/// The interface of the notifications app.
BehaviorSubject<Result<NotificationsAppInterface?>> get notificationsAppImplementation;

/// The currently active app.
BehaviorSubject<AppImplementation> get activeApp;

/// A subject emitting an event when the notifications page should be opened.
BehaviorSubject<void> get openNotifications;

/// A collection of unsupported apps and their minimum required version.
BehaviorSubject<Map<String, String?>> 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,
Expand Down Expand Up @@ -224,9 +235,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<T extends Bloc>(final AppImplementation<T, dynamic> appImplementation) =>
appImplementation.getBloc(_account);

/// Returns the active [Bloc] for every registered [AppImplementation] wrapped in a Provider.
List<Provider<Bloc>> get appBlocProviders =>
_allAppImplementations.map((final appImplementation) => appImplementation.blocProvider).toList();
}
1 change: 1 addition & 0 deletions packages/neon/neon/lib/src/blocs/capabilities.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ abstract interface class CapabilitiesBlocStates {

@internal
class CapabilitiesBloc extends InteractiveBloc implements CapabilitiesBlocEvents, CapabilitiesBlocStates {
/// Creates a new capabilities bloc.
CapabilitiesBloc(
this._account,
) {
Expand Down

0 comments on commit 35bf337

Please sign in to comment.