From d4be81f40fb06d54eba3e3963e53debf266598fd Mon Sep 17 00:00:00 2001 From: provokateurin Date: Wed, 8 May 2024 19:45:33 +0200 Subject: [PATCH] refactor(neon_framework): Replace direct Blocs access with BehaviorSubjects Signed-off-by: provokateurin --- packages/neon_framework/lib/neon.dart | 4 ++-- .../lib/src/blocs/accounts.dart | 6 ++--- .../neon_framework/lib/src/blocs/apps.dart | 22 +++++++++---------- .../lib/src/blocs/maintenance_mode.dart | 2 +- .../lib/src/blocs/next_push.dart | 12 +++++----- .../lib/src/blocs/push_notifications.dart | 14 ++++++------ .../lib/src/blocs/unified_search.dart | 13 +++++------ .../lib/src/blocs/weather_status.dart | 4 +++- .../test/unified_search_bloc_test.dart | 2 +- 9 files changed, 39 insertions(+), 40 deletions(-) diff --git a/packages/neon_framework/lib/neon.dart b/packages/neon_framework/lib/neon.dart index b97d7f77c21..22629961bf3 100644 --- a/packages/neon_framework/lib/neon.dart +++ b/packages/neon_framework/lib/neon.dart @@ -59,14 +59,14 @@ Future runNeon({ ..setActiveAccount(account); } PushNotificationsBloc( - accountsBloc: accountsBloc, + accountsSubject: accountsBloc.accounts, globalOptions: globalOptions, ); final firstLaunchBloc = FirstLaunchBloc( disabled: firstLaunchDisabled, ); final nextPushBloc = NextPushBloc( - accountsBloc: accountsBloc, + accountsSubject: accountsBloc.accounts, globalOptions: globalOptions, disabled: nextPushDisabled, ); diff --git a/packages/neon_framework/lib/src/blocs/accounts.dart b/packages/neon_framework/lib/src/blocs/accounts.dart index 541e56aa669..8294e0f0138 100644 --- a/packages/neon_framework/lib/src/blocs/accounts.dart +++ b/packages/neon_framework/lib/src/blocs/accounts.dart @@ -337,9 +337,9 @@ class _AccountsBloc extends Bloc implements AccountsBloc { @override AppsBloc getAppsBlocFor(Account account) => appsBlocs[account] ??= AppsBloc( - capabilitiesBloc: getCapabilitiesBlocFor(account), - accountsBloc: this, + capabilitiesSubject: getCapabilitiesBlocFor(account).capabilities, account: account, + accountOptions: getOptionsFor(account), allAppImplementations: allAppImplementations, ); @@ -372,7 +372,7 @@ class _AccountsBloc extends Bloc implements AccountsBloc { @override UnifiedSearchBloc getUnifiedSearchBlocFor(Account account) => unifiedSearchBlocs[account] ??= UnifiedSearchBloc( - appsBloc: getAppsBlocFor(account), + activeAppSubject: getAppsBlocFor(account).activeApp, account: account, ); diff --git a/packages/neon_framework/lib/src/blocs/apps.dart b/packages/neon_framework/lib/src/blocs/apps.dart index 3af58cb8d34..69dc40dd6dd 100644 --- a/packages/neon_framework/lib/src/blocs/apps.dart +++ b/packages/neon_framework/lib/src/blocs/apps.dart @@ -6,11 +6,10 @@ import 'package:logging/logging.dart'; import 'package:meta/meta.dart'; import 'package:neon_framework/src/bloc/bloc.dart'; import 'package:neon_framework/src/bloc/result.dart'; -import 'package:neon_framework/src/blocs/accounts.dart'; -import 'package:neon_framework/src/blocs/capabilities.dart'; import 'package:neon_framework/src/models/account.dart'; import 'package:neon_framework/src/models/app_implementation.dart'; import 'package:neon_framework/src/models/notifications_interface.dart'; +import 'package:neon_framework/src/utils/account_options.dart'; import 'package:neon_framework/src/utils/findable.dart'; import 'package:neon_framework/src/utils/request_manager.dart'; import 'package:neon_framework/src/utils/server_version.dart'; @@ -25,9 +24,9 @@ abstract class AppsBloc implements InteractiveBloc { /// Create a new apps bloc. @internal factory AppsBloc({ - required CapabilitiesBloc capabilitiesBloc, - required AccountsBloc accountsBloc, + required BehaviorSubject> capabilitiesSubject, required Account account, + required AccountOptions accountOptions, required BuiltSet allAppImplementations, }) = _AppsBloc; @@ -67,9 +66,9 @@ abstract class AppsBloc implements InteractiveBloc { class _AppsBloc extends InteractiveBloc implements AppsBloc { /// Creates a new apps bloc. _AppsBloc({ - required this.capabilitiesBloc, - required this.accountsBloc, + required this.capabilitiesSubject, required this.account, + required this.accountOptions, required this.allAppImplementations, }) { apps.listen((result) { @@ -80,7 +79,7 @@ class _AppsBloc extends InteractiveBloc implements AppsBloc { } }); - capabilitiesBloc.capabilities.listen((result) { + capabilitiesSubject.listen((result) { notificationsAppImplementation.add( result.transform( (data) => data.capabilities.notificationsCapabilities?.notifications != null @@ -145,8 +144,7 @@ class _AppsBloc extends InteractiveBloc implements AppsBloc { return null; } - final options = accountsBloc.getOptionsFor(account); - for (final fallback in {options.initialApp.value, AppIDs.dashboard, AppIDs.files}) { + for (final fallback in {accountOptions.initialApp.value, AppIDs.dashboard, AppIDs.files}) { if (supportedApps.tryFind(fallback) != null) { return fallback; } @@ -161,7 +159,7 @@ class _AppsBloc extends InteractiveBloc implements AppsBloc { Future checkCompatibility() async { final apps = appImplementations.valueOrNull; - final capabilities = capabilitiesBloc.capabilities.valueOrNull; + final capabilities = capabilitiesSubject.valueOrNull; // ignore cached data if (capabilities == null || apps == null || !capabilities.hasSuccessfulData || !apps.hasSuccessfulData) { @@ -216,9 +214,9 @@ class _AppsBloc extends InteractiveBloc implements AppsBloc { ), ); - final CapabilitiesBloc capabilitiesBloc; - final AccountsBloc accountsBloc; + final BehaviorSubject> capabilitiesSubject; final Account account; + final AccountOptions accountOptions; final BuiltSet allAppImplementations; final apps = BehaviorSubject>>(); diff --git a/packages/neon_framework/lib/src/blocs/maintenance_mode.dart b/packages/neon_framework/lib/src/blocs/maintenance_mode.dart index b0d70d11dc9..95dc09b991f 100644 --- a/packages/neon_framework/lib/src/blocs/maintenance_mode.dart +++ b/packages/neon_framework/lib/src/blocs/maintenance_mode.dart @@ -2,8 +2,8 @@ import 'dart:async'; import 'package:http/http.dart' as http; import 'package:logging/logging.dart'; -import 'package:neon_framework/blocs.dart'; import 'package:neon_framework/models.dart'; +import 'package:neon_framework/src/bloc/bloc.dart'; import 'package:nextcloud/core.dart'; /// A Bloc checking if the server is in maintenance mode. diff --git a/packages/neon_framework/lib/src/blocs/next_push.dart b/packages/neon_framework/lib/src/blocs/next_push.dart index 287e8021f97..b6f94879dde 100644 --- a/packages/neon_framework/lib/src/blocs/next_push.dart +++ b/packages/neon_framework/lib/src/blocs/next_push.dart @@ -1,10 +1,10 @@ import 'dart:async'; +import 'package:built_collection/built_collection.dart'; import 'package:http/http.dart' as http; import 'package:logging/logging.dart'; import 'package:meta/meta.dart'; import 'package:neon_framework/src/bloc/bloc.dart'; -import 'package:neon_framework/src/blocs/accounts.dart'; import 'package:neon_framework/src/models/account.dart'; import 'package:neon_framework/src/models/disposable.dart'; import 'package:neon_framework/src/utils/global_options.dart'; @@ -15,7 +15,7 @@ import 'package:rxdart/rxdart.dart'; sealed class NextPushBloc implements Disposable { @internal factory NextPushBloc({ - required AccountsBloc accountsBloc, + required BehaviorSubject> accountsSubject, required GlobalOptions globalOptions, bool disabled, }) = _NextPushBloc; @@ -26,7 +26,7 @@ sealed class NextPushBloc implements Disposable { class _NextPushBloc extends Bloc implements NextPushBloc { _NextPushBloc({ - required this.accountsBloc, + required this.accountsSubject, required this.globalOptions, bool disabled = false, }) { @@ -36,7 +36,7 @@ class _NextPushBloc extends Bloc implements NextPushBloc { Rx.merge([ globalOptions.pushNotificationsEnabled.stream, globalOptions.pushNotificationsDistributor.stream, - accountsBloc.accounts, + accountsSubject, ]).debounceTime(const Duration(milliseconds: 100)).listen((_) async { if (!globalOptions.pushNotificationsEnabled.enabled || !globalOptions.pushNotificationsEnabled.value) { return; @@ -50,7 +50,7 @@ class _NextPushBloc extends Bloc implements NextPushBloc { } var isSupported = false; - for (final account in accountsBloc.accounts.value) { + for (final account in accountsSubject.value) { if (!supported.containsKey(account)) { try { final response = await account.client.uppush.check(); @@ -85,7 +85,7 @@ class _NextPushBloc extends Bloc implements NextPushBloc { @override final log = Logger('NextPushBloc'); - final AccountsBloc accountsBloc; + final BehaviorSubject> accountsSubject; final GlobalOptions globalOptions; final supported = {}; diff --git a/packages/neon_framework/lib/src/blocs/push_notifications.dart b/packages/neon_framework/lib/src/blocs/push_notifications.dart index 17cd36494fa..7bbf73ce7fd 100644 --- a/packages/neon_framework/lib/src/blocs/push_notifications.dart +++ b/packages/neon_framework/lib/src/blocs/push_notifications.dart @@ -5,7 +5,6 @@ import 'package:built_collection/built_collection.dart'; import 'package:logging/logging.dart'; import 'package:meta/meta.dart'; import 'package:neon_framework/src/bloc/bloc.dart'; -import 'package:neon_framework/src/blocs/accounts.dart'; import 'package:neon_framework/src/models/account.dart'; import 'package:neon_framework/src/platform/platform.dart'; import 'package:neon_framework/src/storage/keys.dart'; @@ -14,20 +13,21 @@ import 'package:neon_framework/src/utils/global_options.dart'; import 'package:neon_framework/src/utils/push_utils.dart'; import 'package:neon_framework/storage.dart'; import 'package:nextcloud/notifications.dart' as notifications; +import 'package:rxdart/rxdart.dart'; import 'package:unifiedpush/unifiedpush.dart'; /// Bloc for managing push notifications and registration. sealed class PushNotificationsBloc { @internal factory PushNotificationsBloc({ - required AccountsBloc accountsBloc, + required BehaviorSubject> accountsSubject, required GlobalOptions globalOptions, }) = _PushNotificationsBloc; } class _PushNotificationsBloc extends Bloc implements PushNotificationsBloc { _PushNotificationsBloc({ - required this.accountsBloc, + required this.accountsSubject, required this.globalOptions, }) { if (NeonPlatform.instance.canUsePushNotifications) { @@ -42,7 +42,7 @@ class _PushNotificationsBloc extends Bloc implements PushNotificationsBloc { @override final log = Logger('PushNotificationsBloc'); - final AccountsBloc accountsBloc; + final BehaviorSubject> accountsSubject; late final storage = NeonStorage().settingsStore(StorageKeys.lastEndpoint); final GlobalOptions globalOptions; @@ -59,7 +59,7 @@ class _PushNotificationsBloc extends Bloc implements PushNotificationsBloc { await setupUnifiedPush(); globalOptions.pushNotificationsDistributor.addListener(distributorListener); - accountsListener = accountsBloc.accounts.listen(registerUnifiedPushInstances); + accountsListener = accountsSubject.listen(registerUnifiedPushInstances); } else { globalOptions.pushNotificationsDistributor.removeListener(distributorListener); unawaited(accountsListener?.cancel()); @@ -72,7 +72,7 @@ class _PushNotificationsBloc extends Bloc implements PushNotificationsBloc { await UnifiedPush.initialize( onNewEndpoint: (endpoint, instance) async { - final account = accountsBloc.accounts.value.tryFind(instance); + final account = accountsSubject.value.tryFind(instance); if (account == null) { log.fine('Account for $instance not found, can not process endpoint'); return; @@ -105,7 +105,7 @@ class _PushNotificationsBloc extends Bloc implements PushNotificationsBloc { final distributor = globalOptions.pushNotificationsDistributor.value; final disabled = distributor == null; final sameDistributor = distributor == await UnifiedPush.getDistributor(); - final accounts = accountsBloc.accounts.value; + final accounts = accountsSubject.value; if (disabled || !sameDistributor) { await unregisterUnifiedPushInstances(accounts); } diff --git a/packages/neon_framework/lib/src/blocs/unified_search.dart b/packages/neon_framework/lib/src/blocs/unified_search.dart index 7c7a328c3ea..2f58f33fe76 100644 --- a/packages/neon_framework/lib/src/blocs/unified_search.dart +++ b/packages/neon_framework/lib/src/blocs/unified_search.dart @@ -8,7 +8,6 @@ import 'package:meta/meta.dart'; import 'package:neon_framework/models.dart'; import 'package:neon_framework/src/bloc/bloc.dart'; import 'package:neon_framework/src/bloc/result.dart'; -import 'package:neon_framework/src/blocs/apps.dart'; import 'package:neon_framework/src/utils/request_manager.dart'; import 'package:nextcloud/core.dart' as core; import 'package:rxdart/rxdart.dart'; @@ -17,7 +16,7 @@ import 'package:rxdart/rxdart.dart'; sealed class UnifiedSearchBloc implements InteractiveBloc { @internal factory UnifiedSearchBloc({ - required AppsBloc appsBloc, + required BehaviorSubject activeAppSubject, required Account account, }) = _UnifiedSearchBloc; @@ -39,10 +38,10 @@ sealed class UnifiedSearchBloc implements InteractiveBloc { class _UnifiedSearchBloc extends InteractiveBloc implements UnifiedSearchBloc { _UnifiedSearchBloc({ - required this.appsBloc, + required this.activeAppSubject, required this.account, }) { - appsBloc.activeApp.listen((_) { + activeAppSubject.listen((_) { term = ''; extendedSearchEnabled = false; results.add(BuiltMap()); @@ -52,7 +51,7 @@ class _UnifiedSearchBloc extends InteractiveBloc implements UnifiedSearchBloc { @override final log = Logger('UnifiedSearchBloc'); - final AppsBloc appsBloc; + final BehaviorSubject activeAppSubject; final Account account; String term = ''; bool extendedSearchEnabled = false; @@ -95,7 +94,7 @@ class _UnifiedSearchBloc extends InteractiveBloc implements UnifiedSearchBloc { } if (providers.value.hasData) { - final activeApp = appsBloc.activeApp.value; + final activeApp = activeAppSubject.value; var providerIDs = providers.value.requireData!.map((provider) => provider.id); if (!extendedSearchEnabled) { @@ -175,7 +174,7 @@ class _UnifiedSearchBloc extends InteractiveBloc implements UnifiedSearchBloc { Iterable>> sortResults( BuiltMap> results, ) sync* { - final activeApp = appsBloc.activeApp.value; + final activeApp = activeAppSubject.value; // Unlike non-matching providers (below) we don't filter the empty results, // as the active app is more relevant and we want to know if there are no results for the active app. diff --git a/packages/neon_framework/lib/src/blocs/weather_status.dart b/packages/neon_framework/lib/src/blocs/weather_status.dart index b1f2ff0e099..e7f207bfd22 100644 --- a/packages/neon_framework/lib/src/blocs/weather_status.dart +++ b/packages/neon_framework/lib/src/blocs/weather_status.dart @@ -3,8 +3,10 @@ import 'dart:async'; import 'package:built_collection/built_collection.dart'; import 'package:logging/logging.dart'; import 'package:meta/meta.dart'; -import 'package:neon_framework/blocs.dart'; import 'package:neon_framework/models.dart'; +import 'package:neon_framework/src/bloc/bloc.dart'; +import 'package:neon_framework/src/bloc/result.dart'; +import 'package:neon_framework/src/blocs/timer.dart'; import 'package:neon_framework/utils.dart'; import 'package:nextcloud/core.dart' as core; import 'package:nextcloud/weather_status.dart' as weather_status; diff --git a/packages/neon_framework/test/unified_search_bloc_test.dart b/packages/neon_framework/test/unified_search_bloc_test.dart index 1db342c799b..6e21ecec511 100644 --- a/packages/neon_framework/test/unified_search_bloc_test.dart +++ b/packages/neon_framework/test/unified_search_bloc_test.dart @@ -100,7 +100,7 @@ void main() { account = mockUnifiedSearchAccount(); bloc = UnifiedSearchBloc( - appsBloc: appsBloc, + activeAppSubject: appsBloc.activeApp, account: account, ); });