From 08efadd54df26142f26a50d5fe885fdeac5a2503 Mon Sep 17 00:00:00 2001 From: Nikolas Rimikis Date: Wed, 13 Sep 2023 14:05:41 +0200 Subject: [PATCH] feat(neon,neon_files,neon_news,neon_notifications): add a `NeonProvider` that handles disposing of `Disposable`s and does not listen by default. Signed-off-by: Nikolas Rimikis --- packages/neon/neon/lib/neon.dart | 37 ++----- packages/neon/neon/lib/src/app.dart | 12 +- .../lib/src/models/app_implementation.dart | 5 +- packages/neon/neon/lib/src/pages/home.dart | 5 +- .../lib/src/pages/login_check_account.dart | 4 +- .../neon/lib/src/pages/route_not_found.dart | 4 +- .../neon/neon/lib/src/pages/settings.dart | 16 +-- packages/neon/neon/lib/src/router.dart | 18 +-- .../neon/lib/src/utils/global_popups.dart | 8 +- .../neon/neon/lib/src/utils/provider.dart | 103 ++++++++++++++++++ .../src/widgets/account_selection_dialog.dart | 4 +- .../src/widgets/account_switcher_button.dart | 6 +- .../neon/lib/src/widgets/account_tile.dart | 4 +- .../neon/neon/lib/src/widgets/app_bar.dart | 7 +- .../neon/lib/src/widgets/cached_image.dart | 4 +- .../neon/neon/lib/src/widgets/drawer.dart | 8 +- .../neon/neon/lib/src/widgets/exception.dart | 4 +- .../src/widgets/unified_search_results.dart | 4 +- .../neon/lib/src/widgets/user_avatar.dart | 4 +- packages/neon/neon/lib/utils.dart | 1 + packages/neon/neon_files/lib/neon_files.dart | 1 - packages/neon/neon_files/lib/pages/main.dart | 2 +- .../neon/neon_files/lib/widgets/actions.dart | 3 +- packages/neon/neon_news/lib/neon_news.dart | 1 - packages/neon/neon_news/lib/pages/main.dart | 2 +- packages/neon/neon_notes/lib/neon_notes.dart | 1 - packages/neon/neon_notes/lib/pages/main.dart | 2 +- .../lib/neon_notifications.dart | 1 - .../neon_notifications/lib/pages/main.dart | 6 +- 29 files changed, 180 insertions(+), 97 deletions(-) create mode 100644 packages/neon/neon/lib/src/utils/provider.dart diff --git a/packages/neon/neon/lib/neon.dart b/packages/neon/neon/lib/neon.dart index ba72a974..b009b112 100644 --- a/packages/neon/neon/lib/neon.dart +++ b/packages/neon/neon/lib/neon.dart @@ -9,10 +9,12 @@ import 'package:neon/src/blocs/next_push.dart'; import 'package:neon/src/blocs/push_notifications.dart'; import 'package:neon/src/models/account.dart'; import 'package:neon/src/models/app_implementation.dart'; +import 'package:neon/src/models/disposable.dart'; import 'package:neon/src/platform/platform.dart'; import 'package:neon/src/settings/models/storage.dart'; import 'package:neon/src/theme/neon.dart'; import 'package:neon/src/utils/global_options.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/utils/request_manager.dart'; import 'package:neon/src/utils/user_agent.dart'; import 'package:package_info_plus/package_info_plus.dart'; @@ -65,37 +67,16 @@ Future runNeon({ runApp( MultiProvider( providers: [ - Provider( - create: (final _) => globalOptions, - dispose: (final _, final globalOptions) => globalOptions.dispose(), - ), - Provider( - create: (final _) => accountsBloc, - dispose: (final _, final accountsBloc) => accountsBloc.dispose(), - ), - Provider( - create: (final _) => pushNotificationsBloc, - dispose: (final _, final pushNotificationsBloc) => pushNotificationsBloc.dispose(), - ), - Provider( - create: (final _) => firstLaunchBloc, - dispose: (final _, final firstLaunchBloc) => firstLaunchBloc.dispose(), - ), - Provider( - create: (final _) => nextPushBloc, - dispose: (final _, final nextPushBloc) => nextPushBloc.dispose(), - ), + NeonProvider.value(value: globalOptions), + NeonProvider.value(value: accountsBloc), + NeonProvider.value(value: pushNotificationsBloc), + NeonProvider.value(value: firstLaunchBloc), + NeonProvider.value(value: nextPushBloc), Provider>( create: (final _) => appImplementations, - dispose: (final _, final appImplementations) { - for (final app in appImplementations) { - app.dispose(); - } - }, - ), - Provider( - create: (final _) => packageInfo, + dispose: (final _, final appImplementations) => appImplementations.disposeAll(), ), + Provider.value(value: packageInfo), ], child: NeonApp(neonTheme: theme), ), diff --git a/packages/neon/neon/lib/src/app.dart b/packages/neon/neon/lib/src/app.dart index 8129bcec..bb12f6e0 100644 --- a/packages/neon/neon/lib/src/app.dart +++ b/packages/neon/neon/lib/src/app.dart @@ -21,9 +21,9 @@ import 'package:neon/src/theme/theme.dart'; import 'package:neon/src/utils/global.dart'; import 'package:neon/src/utils/global_options.dart'; import 'package:neon/src/utils/localizations.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/utils/push_utils.dart'; import 'package:nextcloud/nextcloud.dart'; -import 'package:provider/provider.dart'; import 'package:quick_actions/quick_actions.dart'; import 'package:tray_manager/tray_manager.dart' as tray; import 'package:window_manager/window_manager.dart'; @@ -59,9 +59,9 @@ class _NeonAppState extends State with WidgetsBindingObserver, tray.Tra void initState() { super.initState(); - _appImplementations = Provider.of>(context, listen: false); - _globalOptions = Provider.of(context, listen: false); - _accountsBloc = Provider.of(context, listen: false); + _appImplementations = NeonProvider.of>(context); + _globalOptions = NeonProvider.of(context); + _accountsBloc = NeonProvider.of(context); WidgetsBinding.instance.addObserver(this); if (NeonPlatform.instance.canUseSystemTray) { @@ -144,7 +144,7 @@ class _NeonAppState extends State with WidgetsBindingObserver, tray.Tra return; } - final allAppImplementations = Provider.of>(context, listen: false); + final allAppImplementations = NeonProvider.of>(context); final app = allAppImplementations.tryFind(AppIDs.notifications) as NotificationsAppInterface?; if (app == null) { @@ -160,7 +160,7 @@ class _NeonAppState extends State with WidgetsBindingObserver, tray.Tra } _accountsBloc.setActiveAccount(account); - final allAppImplementations = Provider.of>(context, listen: false); + final allAppImplementations = NeonProvider.of>(context); final notificationsApp = allAppImplementations.tryFind(AppIDs.notifications) as NotificationsAppInterface?; if (notificationsApp != null) { diff --git a/packages/neon/neon/lib/src/models/app_implementation.dart b/packages/neon/neon/lib/src/models/app_implementation.dart index f60d3fe9..25017dd3 100644 --- a/packages/neon/neon/lib/src/models/app_implementation.dart +++ b/packages/neon/neon/lib/src/models/app_implementation.dart @@ -10,6 +10,7 @@ import 'package:neon/src/models/account_cache.dart'; import 'package:neon/src/models/disposable.dart'; import 'package:neon/src/settings/models/options_collection.dart'; import 'package:neon/src/settings/models/storage.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/widgets/drawer_destination.dart'; import 'package:provider/provider.dart'; import 'package:rxdart/rxdart.dart'; @@ -41,7 +42,7 @@ abstract class AppImplementation Provider get blocProvider => Provider( create: (final context) { - final accountsBloc = Provider.of(context, listen: false); + final accountsBloc = NeonProvider.of(context); final account = accountsBloc.activeAccount.value!; return getBloc(account); @@ -53,7 +54,7 @@ abstract class AppImplementation Widget get page; NeonNavigationDestination destination(final BuildContext context) { - final accountsBloc = Provider.of(context, listen: false); + final accountsBloc = NeonProvider.of(context); final account = accountsBloc.activeAccount.value!; final bloc = getBloc(account); diff --git a/packages/neon/neon/lib/src/pages/home.dart b/packages/neon/neon/lib/src/pages/home.dart index b41cc966..7866ce61 100644 --- a/packages/neon/neon/lib/src/pages/home.dart +++ b/packages/neon/neon/lib/src/pages/home.dart @@ -11,6 +11,7 @@ import 'package:neon/src/models/app_implementation.dart'; import 'package:neon/src/utils/global_options.dart'; import 'package:neon/src/utils/global_options.dart' as global_options; import 'package:neon/src/utils/global_popups.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/widgets/app_bar.dart'; import 'package:neon/src/widgets/drawer.dart'; import 'package:neon/src/widgets/exception.dart'; @@ -39,8 +40,8 @@ class _HomePageState extends State { @override void initState() { super.initState(); - _globalOptions = Provider.of(context, listen: false); - _accountsBloc = Provider.of(context, listen: false); + _globalOptions = NeonProvider.of(context); + _accountsBloc = NeonProvider.of(context); _account = _accountsBloc.activeAccount.value!; _appsBloc = _accountsBloc.activeAppsBloc; diff --git a/packages/neon/neon/lib/src/pages/login_check_account.dart b/packages/neon/neon/lib/src/pages/login_check_account.dart index 50399e0e..31b8f775 100644 --- a/packages/neon/neon/lib/src/pages/login_check_account.dart +++ b/packages/neon/neon/lib/src/pages/login_check_account.dart @@ -10,10 +10,10 @@ import 'package:neon/src/blocs/login_check_account.dart'; import 'package:neon/src/models/account.dart'; import 'package:neon/src/router.dart'; import 'package:neon/src/theme/dialog.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/widgets/account_tile.dart'; import 'package:neon/src/widgets/exception.dart'; import 'package:neon/src/widgets/validation_tile.dart'; -import 'package:provider/provider.dart'; @internal class LoginCheckAccountPage extends StatefulWidget { @@ -84,7 +84,7 @@ class _LoginCheckAccountPageState extends State { child: ElevatedButton( onPressed: state.hasData ? () { - Provider.of(context, listen: false) + NeonProvider.of(context) ..updateAccount(state.requireData) ..setActiveAccount(state.requireData); diff --git a/packages/neon/neon/lib/src/pages/route_not_found.dart b/packages/neon/neon/lib/src/pages/route_not_found.dart index 804d792e..1966e8d7 100644 --- a/packages/neon/neon/lib/src/pages/route_not_found.dart +++ b/packages/neon/neon/lib/src/pages/route_not_found.dart @@ -5,7 +5,7 @@ import 'package:meta/meta.dart'; import 'package:neon/l10n/localizations.dart'; import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/router.dart'; -import 'package:provider/provider.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:url_launcher/url_launcher.dart'; @internal @@ -30,7 +30,7 @@ class _RouteNotFoundPageState extends State { } Future _checkLaunchable() async { - final accountsBloc = Provider.of(context, listen: false); + final accountsBloc = NeonProvider.of(context); if (!accountsBloc.hasAccounts) { return; } diff --git a/packages/neon/neon/lib/src/pages/settings.dart b/packages/neon/neon/lib/src/pages/settings.dart index 1f233500..660456bd 100644 --- a/packages/neon/neon/lib/src/pages/settings.dart +++ b/packages/neon/neon/lib/src/pages/settings.dart @@ -21,10 +21,10 @@ import 'package:neon/src/theme/branding.dart'; import 'package:neon/src/theme/dialog.dart'; import 'package:neon/src/utils/confirmation_dialog.dart'; import 'package:neon/src/utils/global_options.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/utils/save_file.dart'; import 'package:neon/src/widgets/exception.dart'; import 'package:package_info_plus/package_info_plus.dart'; -import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher_string.dart'; @internal @@ -55,9 +55,9 @@ class SettingsPage extends StatefulWidget { class _SettingsPageState extends State { @override Widget build(final BuildContext context) { - final globalOptions = Provider.of(context); - final accountsBloc = Provider.of(context, listen: false); - final appImplementations = Provider.of>(context); + final globalOptions = NeonProvider.of(context); + final accountsBloc = NeonProvider.of(context); + final appImplementations = NeonProvider.of>(context); final branding = Branding.of(context); final appBar = AppBar( @@ -265,7 +265,7 @@ class _SettingsPageState extends State { applicationName: branding.name, applicationIcon: branding.logo, applicationLegalese: branding.legalese, - applicationVersion: Provider.of(context, listen: false).version, + applicationVersion: NeonProvider.of(context).version, ); }, ), @@ -350,9 +350,9 @@ class _SettingsPageState extends State { } SettingsExportHelper _buildSettingsExportHelper(final BuildContext context) { - final globalOptions = Provider.of(context, listen: false); - final accountsBloc = Provider.of(context, listen: false); - final appImplementations = Provider.of>(context, listen: false); + final globalOptions = NeonProvider.of(context); + final accountsBloc = NeonProvider.of(context); + final appImplementations = NeonProvider.of>(context); return SettingsExportHelper( exportables: { diff --git a/packages/neon/neon/lib/src/router.dart b/packages/neon/neon/lib/src/router.dart index 6e666b70..1b4b11fa 100644 --- a/packages/neon/neon/lib/src/router.dart +++ b/packages/neon/neon/lib/src/router.dart @@ -19,8 +19,8 @@ import 'package:neon/src/pages/login_qrcode.dart'; import 'package:neon/src/pages/nextcloud_app_settings.dart'; import 'package:neon/src/pages/route_not_found.dart'; import 'package:neon/src/pages/settings.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/utils/stream_listenable.dart'; -import 'package:provider/provider.dart'; part 'router.g.dart'; @@ -79,7 +79,7 @@ class AccountSettingsRoute extends GoRouteData { @override Widget build(final BuildContext context, final GoRouterState state) { - final bloc = Provider.of(context, listen: false); + final bloc = NeonProvider.of(context); final account = bloc.accounts.value.find(accountid); return AccountSettingsPage( @@ -133,7 +133,7 @@ class HomeRoute extends GoRouteData { @override Widget build(final BuildContext context, final GoRouterState state) { - final accountsBloc = Provider.of(context, listen: false); + final accountsBloc = NeonProvider.of(context); final account = accountsBloc.activeAccount.valueOrNull!; return HomePage(key: Key(account.id)); @@ -167,7 +167,7 @@ class LoginRoute extends GoRouteData { @override FutureOr redirect(final BuildContext context, final GoRouterState state) { - final hasAccounts = Provider.of(context, listen: false).hasAccounts; + final hasAccounts = NeonProvider.of(context).hasAccounts; if (state.fullPath == location && hasAccounts) { return const _AddAccountRoute().location; @@ -190,7 +190,7 @@ class LoginFlowRoute extends GoRouteData { @override FutureOr redirect(final BuildContext context, final GoRouterState state) { - final hasAccounts = Provider.of(context, listen: false).hasAccounts; + final hasAccounts = NeonProvider.of(context).hasAccounts; if (state.fullPath == location && hasAccounts) { return _AddAccountFlowRoute(serverUrl: serverUrl).location; @@ -209,7 +209,7 @@ class LoginQrcodeRoute extends GoRouteData { @override FutureOr redirect(final BuildContext context, final GoRouterState state) { - final hasAccounts = Provider.of(context, listen: false).hasAccounts; + final hasAccounts = NeonProvider.of(context).hasAccounts; if (state.fullPath == location && hasAccounts) { return const _AddAccountQrcodeRoute().location; @@ -254,7 +254,7 @@ class LoginCheckServerStatusRoute extends GoRouteData { @override FutureOr redirect(final BuildContext context, final GoRouterState state) { - final hasAccounts = Provider.of(context, listen: false).hasAccounts; + final hasAccounts = NeonProvider.of(context).hasAccounts; if (state.fullPath == location && hasAccounts) { if (loginName != null && password != null) { @@ -295,7 +295,7 @@ class LoginCheckAccountRoute extends GoRouteData { @override FutureOr redirect(final BuildContext context, final GoRouterState state) { - final hasAccounts = Provider.of(context, listen: false).hasAccounts; + final hasAccounts = NeonProvider.of(context).hasAccounts; if (state.fullPath == location && hasAccounts) { return _AddAccountCheckAccountRoute( @@ -375,7 +375,7 @@ class NextcloudAppSettingsRoute extends GoRouteData { @override Widget build(final BuildContext context, final GoRouterState state) { - final appImplementations = Provider.of>(context, listen: false); + final appImplementations = NeonProvider.of>(context); final appImplementation = appImplementations.tryFind(appid)!; return NextcloudAppSettingsPage(appImplementation: appImplementation); diff --git a/packages/neon/neon/lib/src/utils/global_popups.dart b/packages/neon/neon/lib/src/utils/global_popups.dart index 9381d5c1..1b96bc2d 100644 --- a/packages/neon/neon/lib/src/utils/global_popups.dart +++ b/packages/neon/neon/lib/src/utils/global_popups.dart @@ -9,7 +9,7 @@ import 'package:neon/src/pages/settings.dart'; import 'package:neon/src/platform/platform.dart'; import 'package:neon/src/router.dart'; import 'package:neon/src/utils/global_options.dart'; -import 'package:provider/provider.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:url_launcher/url_launcher_string.dart'; @internal @@ -42,9 +42,9 @@ class GlobalPopups { return; } - final globalOptions = Provider.of(context, listen: false); - final firstLaunchBloc = Provider.of(context, listen: false); - final nextPushBloc = Provider.of(context, listen: false); + final globalOptions = NeonProvider.of(context); + final firstLaunchBloc = NeonProvider.of(context); + final nextPushBloc = NeonProvider.of(context); _subscriptions.addAll([ if (NeonPlatform.instance.canUsePushNotifications) ...[ diff --git a/packages/neon/neon/lib/src/utils/provider.dart b/packages/neon/neon/lib/src/utils/provider.dart new file mode 100644 index 00000000..45dfd59c --- /dev/null +++ b/packages/neon/neon/lib/src/utils/provider.dart @@ -0,0 +1,103 @@ +import 'package:flutter/widgets.dart'; +import 'package:neon/src/models/disposable.dart'; +import 'package:provider/provider.dart'; +import 'package:provider/single_child_widget.dart'; + +/// A [Provider] that manages the lifecycle of a [Disposable] value it provides +/// by delegating [Create] and calling [Disposable.dispose]. +class NeonProvider extends SingleChildStatelessWidget { + /// Creates a value, stores it, and exposes it to its descendants. + const NeonProvider({ + required final Create create, + super.key, + this.child, + this.lazy = true, + }) : _create = create, + _value = null, + super(child: child); + + /// Expose an existing value without disposing it. + /// + /// {@macro provider.updateshouldnotify} + const NeonProvider.value({ + required final T value, + super.key, + this.child, + }) : _value = value, + _create = null, + lazy = true, + super(child: child); + + /// Optional widget below this widget in the tree having access to the value. + /// + /// {@macro flutter.widgets.ProxyWidget.child} + final Widget? child; + + /// Whether the value should be created lazily. + /// Defaults to `true`. + final bool lazy; + + final Create? _create; + + final T? _value; + + /// Method that allows widgets to access the value as long as their + /// `BuildContext` contains a [NeonProvider] or [Provider] instance of the + /// specified type. + /// + /// Calling this method is equivalent to calling: + /// + /// ```dart + /// Provider.of(context, listen: false); + /// ``` + /// + /// If we want to access an instance of `DisposableA` which was provided higher up + /// in the widget tree we can do so via: + /// + /// ```dart + /// NeonProvider.of(context); + /// ``` + static T of( + final BuildContext context, { + final bool listen = false, + }) { + try { + return Provider.of(context, listen: listen); + } on ProviderNotFoundException catch (e) { + if (e.valueType != T) { + rethrow; + } + throw FlutterError( + ''' + NeonProvider.of() called with a context that does not contain a $T. + No ancestor could be found starting from the context that was passed to NeonProvider.of<$T>(). + + This can happen if the context you used comes from a widget above the NeonProvider. + + The context used was: $context + ''', + ); + } + } + + @override + Widget buildWithChild(final BuildContext context, final Widget? child) { + assert( + child != null, + '$runtimeType used outside of MultiBlocProvider must specify a child', + ); + final value = _value; + return value != null + ? InheritedProvider.value( + value: value, + lazy: lazy, + child: child, + ) + : InheritedProvider( + create: _create, + dispose: (final _, final value) => value.dispose(), + lazy: lazy, + child: child, + ); + } +} diff --git a/packages/neon/neon/lib/src/widgets/account_selection_dialog.dart b/packages/neon/neon/lib/src/widgets/account_selection_dialog.dart index 94fbcd66..5c5a449a 100644 --- a/packages/neon/neon/lib/src/widgets/account_selection_dialog.dart +++ b/packages/neon/neon/lib/src/widgets/account_selection_dialog.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:meta/meta.dart'; import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/theme/dialog.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/widgets/account_tile.dart'; -import 'package:provider/provider.dart'; @internal class NeonAccountSelectionDialog extends StatelessWidget { @@ -18,7 +18,7 @@ class NeonAccountSelectionDialog extends StatelessWidget { @override Widget build(final BuildContext context) { - final accountsBloc = Provider.of(context, listen: false); + final accountsBloc = NeonProvider.of(context); final accounts = accountsBloc.accounts.value; final activeAccount = accountsBloc.activeAccount.value!; diff --git a/packages/neon/neon/lib/src/widgets/account_switcher_button.dart b/packages/neon/neon/lib/src/widgets/account_switcher_button.dart index bc5db8a3..f06c29ad 100644 --- a/packages/neon/neon/lib/src/widgets/account_switcher_button.dart +++ b/packages/neon/neon/lib/src/widgets/account_switcher_button.dart @@ -5,9 +5,9 @@ import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/models/account.dart'; import 'package:neon/src/pages/settings.dart'; import 'package:neon/src/router.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/widgets/account_selection_dialog.dart'; import 'package:neon/src/widgets/user_avatar.dart'; -import 'package:provider/provider.dart'; @internal class AccountSwitcherButton extends StatelessWidget { @@ -16,7 +16,7 @@ class AccountSwitcherButton extends StatelessWidget { }); Future _onPressed(final BuildContext context) async { - final accountsBloc = Provider.of(context, listen: false); + final accountsBloc = NeonProvider.of(context); final account = await showDialog( context: context, @@ -42,7 +42,7 @@ class AccountSwitcherButton extends StatelessWidget { @override Widget build(final BuildContext context) { - final accountsBloc = Provider.of(context, listen: false); + final accountsBloc = NeonProvider.of(context); final account = accountsBloc.activeAccount.value!; return IconButton( diff --git a/packages/neon/neon/lib/src/widgets/account_tile.dart b/packages/neon/neon/lib/src/widgets/account_tile.dart index 6361e938..923e550d 100644 --- a/packages/neon/neon/lib/src/widgets/account_tile.dart +++ b/packages/neon/neon/lib/src/widgets/account_tile.dart @@ -3,11 +3,11 @@ import 'package:meta/meta.dart'; import 'package:neon/src/bloc/result_builder.dart'; import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/models/account.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/widgets/exception.dart'; import 'package:neon/src/widgets/linear_progress_indicator.dart'; import 'package:neon/src/widgets/user_avatar.dart'; import 'package:nextcloud/nextcloud.dart'; -import 'package:provider/provider.dart'; @internal class NeonAccountTile extends StatelessWidget { @@ -32,7 +32,7 @@ class NeonAccountTile extends StatelessWidget { @override Widget build(final BuildContext context) { - final userDetailsBloc = Provider.of(context, listen: false).getUserDetailsBlocFor(account); + final userDetailsBloc = NeonProvider.of(context).getUserDetailsBlocFor(account); return ListTile( textColor: textColor, diff --git a/packages/neon/neon/lib/src/widgets/app_bar.dart b/packages/neon/neon/lib/src/widgets/app_bar.dart index e6051f53..99a8e5b1 100644 --- a/packages/neon/neon/lib/src/widgets/app_bar.dart +++ b/packages/neon/neon/lib/src/widgets/app_bar.dart @@ -9,6 +9,7 @@ import 'package:neon/src/blocs/apps.dart'; import 'package:neon/src/models/account.dart'; import 'package:neon/src/models/app_implementation.dart'; import 'package:neon/src/models/notifications_interface.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/widgets/account_switcher_button.dart'; import 'package:neon/src/widgets/app_implementation_icon.dart'; import 'package:neon/src/widgets/exception.dart'; @@ -28,7 +29,7 @@ class NeonAppBar extends StatefulWidget implements PreferredSizeWidget { } class _NeonAppBarState extends State { - late final AccountsBloc accountsBloc = Provider.of(context, listen: false); + late final AccountsBloc accountsBloc = NeonProvider.of(context); late final accounts = accountsBloc.accounts.value; late final account = accountsBloc.activeAccount.value!; late final appsBloc = accountsBloc.activeAppsBloc; @@ -157,7 +158,7 @@ class SearchIconButton extends StatelessWidget { @override Widget build(final BuildContext context) => IconButton( onPressed: () { - Provider.of(context, listen: false).activeUnifiedSearchBloc.enable(); + NeonProvider.of(context).activeUnifiedSearchBloc.enable(); }, tooltip: AppLocalizations.of(context).search, icon: const Icon( @@ -186,7 +187,7 @@ class _NotificationIconButtonState extends State { @override void initState() { super.initState(); - _accountsBloc = Provider.of(context, listen: false); + _accountsBloc = NeonProvider.of(context); _appsBloc = _accountsBloc.activeAppsBloc; _accounts = _accountsBloc.accounts.value; _account = _accountsBloc.activeAccount.value!; diff --git a/packages/neon/neon/lib/src/widgets/cached_image.dart b/packages/neon/neon/lib/src/widgets/cached_image.dart index 61240bf0..11de17d9 100644 --- a/packages/neon/neon/lib/src/widgets/cached_image.dart +++ b/packages/neon/neon/lib/src/widgets/cached_image.dart @@ -8,9 +8,9 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:neon/nextcloud.dart'; import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/models/account.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/widgets/exception.dart'; import 'package:neon/src/widgets/linear_progress_indicator.dart'; -import 'package:provider/provider.dart'; typedef CacheReviver = FutureOr Function(CacheManager cacheManager); typedef ImageDownloader = FutureOr Function(); @@ -220,7 +220,7 @@ class NeonApiImage extends StatelessWidget { @override Widget build(final BuildContext context) { - final account = Provider.of(context, listen: false).activeAccount.value!; + final account = NeonProvider.of(context).activeAccount.value!; return NeonCachedImage.custom( getImage: () async => getImage(account.client), diff --git a/packages/neon/neon/lib/src/widgets/drawer.dart b/packages/neon/neon/lib/src/widgets/drawer.dart index a7735831..5fa594be 100644 --- a/packages/neon/neon/lib/src/widgets/drawer.dart +++ b/packages/neon/neon/lib/src/widgets/drawer.dart @@ -8,12 +8,12 @@ import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/blocs/apps.dart'; import 'package:neon/src/models/app_implementation.dart'; import 'package:neon/src/router.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/widgets/cached_image.dart'; import 'package:neon/src/widgets/drawer_destination.dart'; import 'package:neon/src/widgets/exception.dart'; import 'package:neon/src/widgets/linear_progress_indicator.dart'; import 'package:nextcloud/nextcloud.dart'; -import 'package:provider/provider.dart'; @internal class NeonDrawer extends StatelessWidget { @@ -23,7 +23,7 @@ class NeonDrawer extends StatelessWidget { @override Widget build(final BuildContext context) { - final accountsBloc = Provider.of(context, listen: false); + final accountsBloc = NeonProvider.of(context); final appsBloc = accountsBloc.activeAppsBloc; return ResultBuilder.behaviorSubject( @@ -63,7 +63,7 @@ class __NeonDrawerState extends State<_NeonDrawer> { void initState() { super.initState(); - _accountsBloc = Provider.of(context, listen: false); + _accountsBloc = NeonProvider.of(context); _appsBloc = _accountsBloc.activeAppsBloc; _apps = widget.apps.toList(); @@ -118,7 +118,7 @@ class NeonDrawerHeader extends StatelessWidget { @override Widget build(final BuildContext context) { - final accountsBloc = Provider.of(context, listen: false); + final accountsBloc = NeonProvider.of(context); final capabilitiesBloc = accountsBloc.activeCapabilitiesBloc; final branding = ResultBuilder.behaviorSubject( diff --git a/packages/neon/neon/lib/src/widgets/exception.dart b/packages/neon/neon/lib/src/widgets/exception.dart index c181b34f..1656594a 100644 --- a/packages/neon/neon/lib/src/widgets/exception.dart +++ b/packages/neon/neon/lib/src/widgets/exception.dart @@ -8,8 +8,8 @@ import 'package:neon/l10n/localizations.dart'; import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/router.dart'; import 'package:neon/src/utils/exceptions.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:nextcloud/nextcloud.dart'; -import 'package:provider/provider.dart'; class NeonException extends StatelessWidget { const NeonException( @@ -189,7 +189,7 @@ class NeonException extends StatelessWidget { static void _openLoginPage(final BuildContext context) { unawaited( LoginCheckServerStatusRoute( - serverUrl: Provider.of(context, listen: false).activeAccount.value!.serverURL, + serverUrl: NeonProvider.of(context).activeAccount.value!.serverURL, ).push(context), ); } diff --git a/packages/neon/neon/lib/src/widgets/unified_search_results.dart b/packages/neon/neon/lib/src/widgets/unified_search_results.dart index 2404c45e..b3a419fc 100644 --- a/packages/neon/neon/lib/src/widgets/unified_search_results.dart +++ b/packages/neon/neon/lib/src/widgets/unified_search_results.dart @@ -8,6 +8,7 @@ import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/blocs/unified_search.dart'; import 'package:neon/src/models/account.dart'; import 'package:neon/src/theme/sizes.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/widgets/cached_image.dart'; import 'package:neon/src/widgets/exception.dart'; import 'package:neon/src/widgets/image_wrapper.dart'; @@ -15,7 +16,6 @@ import 'package:neon/src/widgets/linear_progress_indicator.dart'; import 'package:neon/src/widgets/list_view.dart'; import 'package:neon/src/widgets/server_icon.dart'; import 'package:nextcloud/nextcloud.dart'; -import 'package:provider/provider.dart'; @internal class NeonUnifiedSearchResults extends StatelessWidget { @@ -25,7 +25,7 @@ class NeonUnifiedSearchResults extends StatelessWidget { @override Widget build(final BuildContext context) { - final accountsBloc = Provider.of(context, listen: false); + final accountsBloc = NeonProvider.of(context); final bloc = accountsBloc.activeUnifiedSearchBloc; return ResultBuilder.behaviorSubject( stream: bloc.results, diff --git a/packages/neon/neon/lib/src/widgets/user_avatar.dart b/packages/neon/neon/lib/src/widgets/user_avatar.dart index d5b0f0c3..6e7c3f16 100644 --- a/packages/neon/neon/lib/src/widgets/user_avatar.dart +++ b/packages/neon/neon/lib/src/widgets/user_avatar.dart @@ -9,10 +9,10 @@ import 'package:neon/src/bloc/result_builder.dart'; import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/models/account.dart'; import 'package:neon/src/theme/sizes.dart'; +import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/widgets/cached_image.dart'; import 'package:neon/src/widgets/server_icon.dart'; import 'package:nextcloud/nextcloud.dart'; -import 'package:provider/provider.dart'; import 'package:rxdart/rxdart.dart'; class NeonUserAvatar extends StatefulWidget { @@ -38,7 +38,7 @@ class NeonUserAvatar extends StatefulWidget { } class _UserAvatarState extends State { - late final _userStatusBloc = Provider.of(context, listen: false).getUserStatusesBlocFor(widget.account); + late final _userStatusBloc = NeonProvider.of(context).getUserStatusesBlocFor(widget.account); late double size; @override diff --git a/packages/neon/neon/lib/utils.dart b/packages/neon/neon/lib/utils.dart index a0ecb48e..37d6669f 100644 --- a/packages/neon/neon/lib/utils.dart +++ b/packages/neon/neon/lib/utils.dart @@ -2,6 +2,7 @@ export 'package:neon/src/utils/app_route.dart'; export 'package:neon/src/utils/confirmation_dialog.dart'; export 'package:neon/src/utils/exceptions.dart'; export 'package:neon/src/utils/hex_color.dart'; +export 'package:neon/src/utils/provider.dart'; export 'package:neon/src/utils/rename_dialog.dart'; export 'package:neon/src/utils/request_manager.dart' hide Cache; export 'package:neon/src/utils/validators.dart'; diff --git a/packages/neon/neon_files/lib/neon_files.dart b/packages/neon/neon_files/lib/neon_files.dart index b978663e..e7563c43 100644 --- a/packages/neon/neon_files/lib/neon_files.dart +++ b/packages/neon/neon_files/lib/neon_files.dart @@ -27,7 +27,6 @@ import 'package:neon_files/widgets/file_list_tile.dart'; import 'package:open_file/open_file.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; -import 'package:provider/provider.dart'; import 'package:queue/queue.dart'; import 'package:rxdart/rxdart.dart'; diff --git a/packages/neon/neon_files/lib/pages/main.dart b/packages/neon/neon_files/lib/pages/main.dart index ecd5f2da..862375b0 100644 --- a/packages/neon/neon_files/lib/pages/main.dart +++ b/packages/neon/neon_files/lib/pages/main.dart @@ -15,7 +15,7 @@ class _FilesMainPageState extends State { @override void initState() { super.initState(); - bloc = Provider.of(context, listen: false); + bloc = NeonProvider.of(context); bloc.errors.listen((final error) { NeonException.showSnackbar(context, error); diff --git a/packages/neon/neon_files/lib/widgets/actions.dart b/packages/neon/neon_files/lib/widgets/actions.dart index 1e39ea41..d5727200 100644 --- a/packages/neon/neon_files/lib/widgets/actions.dart +++ b/packages/neon/neon_files/lib/widgets/actions.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; import 'package:neon/utils.dart'; import 'package:neon_files/l10n/localizations.dart'; import 'package:neon_files/neon_files.dart'; -import 'package:provider/provider.dart'; class FileActions extends StatelessWidget { const FileActions({ @@ -14,7 +13,7 @@ class FileActions extends StatelessWidget { final FileDetails details; Future onSelected(final BuildContext context, final FilesFileAction action) async { - final bloc = Provider.of(context, listen: false); + final bloc = NeonProvider.of(context); final browserBloc = bloc.browser; switch (action) { case FilesFileAction.toggleFavorite: diff --git a/packages/neon/neon_news/lib/neon_news.dart b/packages/neon/neon_news/lib/neon_news.dart index 63b766bf..286323fe 100644 --- a/packages/neon/neon_news/lib/neon_news.dart +++ b/packages/neon/neon_news/lib/neon_news.dart @@ -21,7 +21,6 @@ import 'package:neon/utils.dart'; import 'package:neon/widgets.dart'; import 'package:neon_news/l10n/localizations.dart'; import 'package:neon_news/routes.dart'; -import 'package:provider/provider.dart'; import 'package:rxdart/rxdart.dart'; import 'package:share_plus/share_plus.dart'; import 'package:url_launcher/url_launcher_string.dart'; diff --git a/packages/neon/neon_news/lib/pages/main.dart b/packages/neon/neon_news/lib/pages/main.dart index a28abe62..e3390279 100644 --- a/packages/neon/neon_news/lib/pages/main.dart +++ b/packages/neon/neon_news/lib/pages/main.dart @@ -16,7 +16,7 @@ class _NewsMainPageState extends State { @override void initState() { super.initState(); - bloc = Provider.of(context, listen: false); + bloc = NeonProvider.of(context); bloc.errors.listen((final error) { NeonException.showSnackbar(context, error); diff --git a/packages/neon/neon_notes/lib/neon_notes.dart b/packages/neon/neon_notes/lib/neon_notes.dart index 5140bee3..aa8054b7 100644 --- a/packages/neon/neon_notes/lib/neon_notes.dart +++ b/packages/neon/neon_notes/lib/neon_notes.dart @@ -19,7 +19,6 @@ import 'package:neon/utils.dart'; import 'package:neon/widgets.dart'; import 'package:neon_notes/l10n/localizations.dart'; import 'package:neon_notes/routes.dart'; -import 'package:provider/provider.dart'; import 'package:queue/queue.dart'; import 'package:rxdart/rxdart.dart'; import 'package:url_launcher/url_launcher_string.dart'; diff --git a/packages/neon/neon_notes/lib/pages/main.dart b/packages/neon/neon_notes/lib/pages/main.dart index eecab6b3..97436c62 100644 --- a/packages/neon/neon_notes/lib/pages/main.dart +++ b/packages/neon/neon_notes/lib/pages/main.dart @@ -17,7 +17,7 @@ class _NotesMainPageState extends State { void initState() { super.initState(); - bloc = Provider.of(context, listen: false); + bloc = NeonProvider.of(context); bloc.errors.listen((final error) { handleNotesException(context, error); diff --git a/packages/neon/neon_notifications/lib/neon_notifications.dart b/packages/neon/neon_notifications/lib/neon_notifications.dart index 271969cd..bd0632a9 100644 --- a/packages/neon/neon_notifications/lib/neon_notifications.dart +++ b/packages/neon/neon_notifications/lib/neon_notifications.dart @@ -14,7 +14,6 @@ import 'package:neon/utils.dart'; import 'package:neon/widgets.dart'; import 'package:neon_notifications/l10n/localizations.dart'; import 'package:neon_notifications/routes.dart'; -import 'package:provider/provider.dart'; import 'package:rxdart/rxdart.dart'; part 'blocs/notifications.dart'; diff --git a/packages/neon/neon_notifications/lib/pages/main.dart b/packages/neon/neon_notifications/lib/pages/main.dart index 6b2e9d37..e747d60c 100644 --- a/packages/neon/neon_notifications/lib/pages/main.dart +++ b/packages/neon/neon_notifications/lib/pages/main.dart @@ -16,7 +16,7 @@ class _NotificationsMainPageState extends State { void initState() { super.initState(); - bloc = Provider.of(context, listen: false) as NotificationsBloc; + bloc = NeonProvider.of(context) as NotificationsBloc; bloc.errors.listen((final error) { NeonException.showSnackbar(context, error); @@ -51,7 +51,7 @@ class _NotificationsMainPageState extends State { final BuildContext context, final NotificationsNotification notification, ) { - final app = Provider.of>(context, listen: false).tryFind(notification.app); + final app = NeonProvider.of>(context).tryFind(notification.app); return ListTile( title: Text(notification.subject), @@ -90,7 +90,7 @@ class _NotificationsMainPageState extends State { } if (app != null) { // TODO: use go_router once implemented - final accountsBloc = Provider.of(context, listen: false); + final accountsBloc = NeonProvider.of(context); await accountsBloc.activeAppsBloc.setActiveApp(app.id); } else { final colorScheme = Theme.of(context).colorScheme;