From 4d5e0109bcc290586ab04c1459a0246fabe28314 Mon Sep 17 00:00:00 2001 From: Nikolas Rimikis Date: Tue, 29 Aug 2023 08:18:28 +0200 Subject: [PATCH 1/7] refactor(neon): add SharedPreferences instance to AppStorage Signed-off-by: Nikolas Rimikis --- packages/neon/neon/lib/neon.dart | 3 ++ .../neon/neon/lib/src/blocs/accounts.dart | 4 +- .../lib/src/blocs/push_notifications.dart | 2 +- .../lib/src/models/app_implementation.dart | 2 +- .../neon/lib/src/settings/models/storage.dart | 47 ++++++++++++++----- .../neon/lib/src/utils/global_options.dart | 2 +- .../neon/neon/lib/src/utils/push_utils.dart | 6 +-- 7 files changed, 45 insertions(+), 21 deletions(-) diff --git a/packages/neon/neon/lib/neon.dart b/packages/neon/neon/lib/neon.dart index d8f8001a..22d99305 100644 --- a/packages/neon/neon/lib/neon.dart +++ b/packages/neon/neon/lib/neon.dart @@ -10,6 +10,7 @@ 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/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/request_manager.dart'; @@ -33,6 +34,8 @@ Future runNeon({ await NeonPlatform.setup(); await RequestManager.instance.initCache(); + await AppStorage.init(); + final allAppImplementations = getAppImplementations(sharedPreferences); final packageInfo = await PackageInfo.fromPlatform(); diff --git a/packages/neon/neon/lib/src/blocs/accounts.dart b/packages/neon/neon/lib/src/blocs/accounts.dart index 8068d10a..e3f77c46 100644 --- a/packages/neon/neon/lib/src/blocs/accounts.dart +++ b/packages/neon/neon/lib/src/blocs/accounts.dart @@ -96,7 +96,7 @@ class AccountsBloc extends Bloc implements AccountsBlocEvents, AccountsBlocState } } - late final AppStorage _storage = AppStorage('accounts', _sharedPreferences); + late final AppStorage _storage = AppStorage('accounts'); final SharedPreferences _sharedPreferences; final GlobalOptions _globalOptions; final Iterable _allAppImplementations; @@ -213,7 +213,7 @@ class AccountsBloc extends Bloc implements AccountsBlocEvents, AccountsBlocState /// Use [activeOptions] to get them for the [activeAccount]. AccountSpecificOptions getOptionsFor(final Account account) => _accountsOptions[account.id] ??= AccountSpecificOptions( - AppStorage('accounts-${account.id}', _sharedPreferences), + AppStorage('accounts-${account.id}'), getAppsBlocFor(account), ); diff --git a/packages/neon/neon/lib/src/blocs/push_notifications.dart b/packages/neon/neon/lib/src/blocs/push_notifications.dart index d280b379..ae61b769 100644 --- a/packages/neon/neon/lib/src/blocs/push_notifications.dart +++ b/packages/neon/neon/lib/src/blocs/push_notifications.dart @@ -40,7 +40,7 @@ class PushNotificationsBloc extends Bloc implements PushNotificationsBlocEvents, final AccountsBloc _accountsBloc; final SharedPreferences _sharedPreferences; - late final _storage = AppStorage(AppIDs.notifications, _sharedPreferences); + late final _storage = AppStorage(AppIDs.notifications); final GlobalOptions _globalOptions; final _notificationsController = StreamController(); diff --git a/packages/neon/neon/lib/src/models/app_implementation.dart b/packages/neon/neon/lib/src/models/app_implementation.dart index 83aa5c47..0e0ee87e 100644 --- a/packages/neon/neon/lib/src/models/app_implementation.dart +++ b/packages/neon/neon/lib/src/models/app_implementation.dart @@ -17,7 +17,7 @@ abstract class AppImplementation AppImplementation( final SharedPreferences sharedPreferences, ) { - final storage = AppStorage('app-$id', sharedPreferences); + final storage = AppStorage('app-$id'); options = buildOptions(storage); } diff --git a/packages/neon/neon/lib/src/settings/models/storage.dart b/packages/neon/neon/lib/src/settings/models/storage.dart index 7ae22cf2..d033964d 100644 --- a/packages/neon/neon/lib/src/settings/models/storage.dart +++ b/packages/neon/neon/lib/src/settings/models/storage.dart @@ -1,3 +1,4 @@ +import 'package:meta/meta.dart'; import 'package:shared_preferences/shared_preferences.dart'; abstract interface class SettingsStorage { @@ -14,35 +15,55 @@ abstract interface class SettingsStorage { } class AppStorage implements SettingsStorage { - AppStorage( - this._id, - this._sharedPreferences, - ); + AppStorage(this._id); final String _id; - final SharedPreferences _sharedPreferences; + + /// Shared preferences instance. + /// + /// Use [reqireDatabase] to access it. + /// Make sure it has been initialized wiht [init] before. + static SharedPreferences? _sharedPreferences; + + /// Sets up the [SharedPreferences] instance. + /// + /// Required to be called before accessing [reqireDatabase]. + static Future init() async { + _sharedPreferences = await SharedPreferences.getInstance(); + } + + @visibleForTesting + static SharedPreferences get reqireDatabase { + if (_sharedPreferences == null) { + throw StateError( + 'AppStorage has not been initialized yet. Please make sure AppStorage.init() has been called before and completed.', + ); + } + + return _sharedPreferences!; + } String _formatKey(final String key) => '$_id-$key'; - bool containsKey(final String key) => _sharedPreferences.containsKey(_formatKey(key)); + bool containsKey(final String key) => reqireDatabase.containsKey(_formatKey(key)); @override - Future remove(final String key) => _sharedPreferences.remove(_formatKey(key)); + Future remove(final String key) => reqireDatabase.remove(_formatKey(key)); @override - String? getString(final String key) => _sharedPreferences.getString(_formatKey(key)); + String? getString(final String key) => reqireDatabase.getString(_formatKey(key)); @override - Future setString(final String key, final String value) => _sharedPreferences.setString(_formatKey(key), value); + Future setString(final String key, final String value) => reqireDatabase.setString(_formatKey(key), value); @override - bool? getBool(final String key) => _sharedPreferences.getBool(_formatKey(key)); + bool? getBool(final String key) => reqireDatabase.getBool(_formatKey(key)); @override - Future setBool(final String key, final bool value) => _sharedPreferences.setBool(_formatKey(key), value); + Future setBool(final String key, final bool value) => reqireDatabase.setBool(_formatKey(key), value); - List? getStringList(final String key) => _sharedPreferences.getStringList(_formatKey(key)); + List? getStringList(final String key) => reqireDatabase.getStringList(_formatKey(key)); Future setStringList(final String key, final List value) => - _sharedPreferences.setStringList(_formatKey(key), value); + reqireDatabase.setStringList(_formatKey(key), value); } diff --git a/packages/neon/neon/lib/src/utils/global_options.dart b/packages/neon/neon/lib/src/utils/global_options.dart index 15657168..70aa436a 100644 --- a/packages/neon/neon/lib/src/utils/global_options.dart +++ b/packages/neon/neon/lib/src/utils/global_options.dart @@ -52,7 +52,7 @@ class GlobalOptions { } final SharedPreferences _sharedPreferences; - late final AppStorage _storage = AppStorage('global', _sharedPreferences); + late final AppStorage _storage = AppStorage('global'); final PackageInfo _packageInfo; late final _distributorsMap = { diff --git a/packages/neon/neon/lib/src/utils/push_utils.dart b/packages/neon/neon/lib/src/utils/push_utils.dart index 353bfc01..302a75be 100644 --- a/packages/neon/neon/lib/src/utils/push_utils.dart +++ b/packages/neon/neon/lib/src/utils/push_utils.dart @@ -71,9 +71,9 @@ class PushUtils { } }, ); - final sharedPreferences = await SharedPreferences.getInstance(); + await AppStorage.init(); - final keypair = await loadRSAKeypair(AppStorage(AppIDs.notifications, sharedPreferences)); + final keypair = await loadRSAKeypair(AppStorage(AppIDs.notifications)); for (final message in Uri(query: utf8.decode(messages)).queryParameters.values) { final data = json.decode(message) as Map; @@ -99,7 +99,7 @@ class PushUtils { NotificationsNotification? notification; AndroidBitmap? largeIconBitmap; try { - accounts = loadAccounts(AppStorage('accounts', sharedPreferences)); + accounts = loadAccounts(AppStorage('accounts')); account = accounts.tryFind(instance); if (account != null) { notification = From 00e53cfb052e64fb6551918b8c94e58a7501b078 Mon Sep 17 00:00:00 2001 From: Nikolas Rimikis Date: Tue, 29 Aug 2023 08:18:28 +0200 Subject: [PATCH 2/7] refactor(neon): use AppStorage in FirstLaunchBloc Signed-off-by: Nikolas Rimikis --- packages/neon/neon/lib/neon.dart | 1 - .../neon/neon/lib/src/blocs/first_launch.dart | 18 +++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/neon/neon/lib/neon.dart b/packages/neon/neon/lib/neon.dart index 22d99305..20c9cf2b 100644 --- a/packages/neon/neon/lib/neon.dart +++ b/packages/neon/neon/lib/neon.dart @@ -62,7 +62,6 @@ Future runNeon({ globalOptions, ); final firstLaunchBloc = FirstLaunchBloc( - sharedPreferences, disabled: firstLaunchDisabled, ); final nextPushBloc = NextPushBloc( diff --git a/packages/neon/neon/lib/src/blocs/first_launch.dart b/packages/neon/neon/lib/src/blocs/first_launch.dart index ed7c63f4..fef5589c 100644 --- a/packages/neon/neon/lib/src/blocs/first_launch.dart +++ b/packages/neon/neon/lib/src/blocs/first_launch.dart @@ -2,8 +2,8 @@ import 'dart:async'; import 'package:meta/meta.dart'; import 'package:neon/src/bloc/bloc.dart'; +import 'package:neon/src/settings/models/storage.dart'; import 'package:rxdart/rxdart.dart'; -import 'package:shared_preferences/shared_preferences.dart'; abstract class FirstLaunchBlocEvents {} @@ -11,20 +11,20 @@ abstract class FirstLaunchBlocStates { BehaviorSubject get onFirstLaunch; } +@immutable @internal class FirstLaunchBloc extends Bloc implements FirstLaunchBlocEvents, FirstLaunchBlocStates { - FirstLaunchBloc( - this._sharedPreferences, { + FirstLaunchBloc({ final bool disabled = false, - }) { - if (!disabled && !_sharedPreferences.containsKey(_keyFirstLaunch)) { + }) : _storage = AppStorage(_keyFirstLaunch) { + if (!disabled && !_storage.containsKey(_keyFirstLaunch)) { onFirstLaunch.add(null); - unawaited(_sharedPreferences.setBool(_keyFirstLaunch, false)); + unawaited(_storage.setBool(_keyFirstLaunch, false)); } } - final SharedPreferences _sharedPreferences; - final _keyFirstLaunch = 'first-launch'; + final AppStorage _storage; + static const _keyFirstLaunch = 'first-launch'; @override void dispose() { @@ -32,5 +32,5 @@ class FirstLaunchBloc extends Bloc implements FirstLaunchBlocEvents, FirstLaunch } @override - BehaviorSubject onFirstLaunch = BehaviorSubject(); + final BehaviorSubject onFirstLaunch = BehaviorSubject(); } From 6f7958e979378a2d004bb6bce56380cd11fefcfd Mon Sep 17 00:00:00 2001 From: Nikolas Rimikis Date: Tue, 29 Aug 2023 08:18:28 +0200 Subject: [PATCH 3/7] refactor(neon): remove unused SharedPreferences references Signed-off-by: Nikolas Rimikis --- packages/neon/neon/lib/neon.dart | 6 ------ packages/neon/neon/lib/src/blocs/accounts.dart | 3 --- packages/neon/neon/lib/src/blocs/push_notifications.dart | 3 --- packages/neon/neon/lib/src/utils/global_options.dart | 3 --- packages/neon/neon/lib/src/utils/push_utils.dart | 1 - 5 files changed, 16 deletions(-) diff --git a/packages/neon/neon/lib/neon.dart b/packages/neon/neon/lib/neon.dart index 20c9cf2b..93cb201f 100644 --- a/packages/neon/neon/lib/neon.dart +++ b/packages/neon/neon/lib/neon.dart @@ -42,12 +42,10 @@ Future runNeon({ buildUserAgent(packageInfo); final globalOptions = GlobalOptions( - sharedPreferences, packageInfo, ); final accountsBloc = AccountsBloc( - sharedPreferences, globalOptions, allAppImplementations, ); @@ -58,7 +56,6 @@ Future runNeon({ } final pushNotificationsBloc = PushNotificationsBloc( accountsBloc, - sharedPreferences, globalOptions, ); final firstLaunchBloc = FirstLaunchBloc( @@ -73,9 +70,6 @@ Future runNeon({ runApp( MultiProvider( providers: [ - Provider( - create: (final _) => sharedPreferences, - ), Provider( create: (final _) => globalOptions, ), diff --git a/packages/neon/neon/lib/src/blocs/accounts.dart b/packages/neon/neon/lib/src/blocs/accounts.dart index e3f77c46..10605cea 100644 --- a/packages/neon/neon/lib/src/blocs/accounts.dart +++ b/packages/neon/neon/lib/src/blocs/accounts.dart @@ -14,7 +14,6 @@ import 'package:neon/src/settings/models/storage.dart'; import 'package:neon/src/utils/account_options.dart'; import 'package:neon/src/utils/global_options.dart'; import 'package:rxdart/rxdart.dart'; -import 'package:shared_preferences/shared_preferences.dart'; const _keyAccounts = 'accounts'; @@ -56,7 +55,6 @@ abstract interface class AccountsBlocStates { class AccountsBloc extends Bloc implements AccountsBlocEvents, AccountsBlocStates { AccountsBloc( - this._sharedPreferences, this._globalOptions, this._allAppImplementations, ) { @@ -97,7 +95,6 @@ class AccountsBloc extends Bloc implements AccountsBlocEvents, AccountsBlocState } late final AppStorage _storage = AppStorage('accounts'); - final SharedPreferences _sharedPreferences; final GlobalOptions _globalOptions; final Iterable _allAppImplementations; final _keyLastUsedAccount = 'last-used-account'; diff --git a/packages/neon/neon/lib/src/blocs/push_notifications.dart b/packages/neon/neon/lib/src/blocs/push_notifications.dart index ae61b769..c25a71f1 100644 --- a/packages/neon/neon/lib/src/blocs/push_notifications.dart +++ b/packages/neon/neon/lib/src/blocs/push_notifications.dart @@ -13,7 +13,6 @@ import 'package:neon/src/settings/models/storage.dart'; import 'package:neon/src/utils/global_options.dart'; import 'package:neon/src/utils/push_utils.dart'; import 'package:nextcloud/nextcloud.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:unifiedpush/unifiedpush.dart'; abstract class PushNotificationsBlocEvents {} @@ -26,7 +25,6 @@ abstract class PushNotificationsBlocStates { class PushNotificationsBloc extends Bloc implements PushNotificationsBlocEvents, PushNotificationsBlocStates { PushNotificationsBloc( this._accountsBloc, - this._sharedPreferences, this._globalOptions, ) { if (NeonPlatform.instance.canUsePushNotifications) { @@ -39,7 +37,6 @@ class PushNotificationsBloc extends Bloc implements PushNotificationsBlocEvents, } final AccountsBloc _accountsBloc; - final SharedPreferences _sharedPreferences; late final _storage = AppStorage(AppIDs.notifications); final GlobalOptions _globalOptions; diff --git a/packages/neon/neon/lib/src/utils/global_options.dart b/packages/neon/neon/lib/src/utils/global_options.dart index 70aa436a..d6b319f1 100644 --- a/packages/neon/neon/lib/src/utils/global_options.dart +++ b/packages/neon/neon/lib/src/utils/global_options.dart @@ -11,7 +11,6 @@ import 'package:neon/src/settings/models/storage.dart'; import 'package:neon/src/settings/models/toggle_option.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:permission_handler/permission_handler.dart'; -import 'package:shared_preferences/shared_preferences.dart'; const unifiedPushNextPushID = 'org.unifiedpush.distributor.nextpush'; @@ -19,7 +18,6 @@ const unifiedPushNextPushID = 'org.unifiedpush.distributor.nextpush'; @immutable class GlobalOptions { GlobalOptions( - this._sharedPreferences, this._packageInfo, ) { pushNotificationsEnabled.addListener(_pushNotificationsEnabledListener); @@ -51,7 +49,6 @@ class GlobalOptions { } } - final SharedPreferences _sharedPreferences; late final AppStorage _storage = AppStorage('global'); final PackageInfo _packageInfo; diff --git a/packages/neon/neon/lib/src/utils/push_utils.dart b/packages/neon/neon/lib/src/utils/push_utils.dart index 302a75be..1588dbce 100644 --- a/packages/neon/neon/lib/src/utils/push_utils.dart +++ b/packages/neon/neon/lib/src/utils/push_utils.dart @@ -18,7 +18,6 @@ import 'package:neon/src/theme/colors.dart'; import 'package:neon/src/utils/global.dart'; import 'package:neon/src/utils/localizations.dart'; import 'package:nextcloud/nextcloud.dart'; -import 'package:shared_preferences/shared_preferences.dart'; @internal @immutable From c323c707c82adfc7c3f22b393b828aacfadb0575 Mon Sep 17 00:00:00 2001 From: Nikolas Rimikis Date: Tue, 29 Aug 2023 08:18:29 +0200 Subject: [PATCH 4/7] refactor(neon,neon_files,neon_news,neon_notes,neon_notifications): remove SharedPreferences reference Signed-off-by: Nikolas Rimikis --- .../app/integration_test/screenshot_test.dart | 2 +- packages/app/lib/apps.dart | 16 ++++++---------- packages/app/lib/main.dart | 2 +- packages/app/pubspec.lock | 12 ++++++------ packages/app/pubspec.yaml | 3 +-- packages/neon/neon/lib/neon.dart | 11 +++-------- .../neon/lib/src/models/app_implementation.dart | 5 +---- .../lib/src/models/notifications_interface.dart | 2 +- packages/neon/neon_files/lib/neon_files.dart | 2 +- packages/neon/neon_news/lib/neon_news.dart | 2 +- packages/neon/neon_notes/lib/neon_notes.dart | 2 +- .../lib/neon_notifications.dart | 2 +- 12 files changed, 24 insertions(+), 37 deletions(-) diff --git a/packages/app/integration_test/screenshot_test.dart b/packages/app/integration_test/screenshot_test.dart index 7ad759e4..5c093a2a 100644 --- a/packages/app/integration_test/screenshot_test.dart +++ b/packages/app/integration_test/screenshot_test.dart @@ -20,7 +20,7 @@ Future runTestApp( final Account? account, }) async { await runNeon( - getAppImplementations: getAppImplementations, + appImplementations: appImplementations, theme: neonTheme, bindingOverride: binding, account: account, diff --git a/packages/app/lib/apps.dart b/packages/app/lib/apps.dart index b93b4baa..7fe30719 100644 --- a/packages/app/lib/apps.dart +++ b/packages/app/lib/apps.dart @@ -3,14 +3,10 @@ import 'package:neon_files/neon_files.dart'; import 'package:neon_news/neon_news.dart'; import 'package:neon_notes/neon_notes.dart'; import 'package:neon_notifications/neon_notifications.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -List getAppImplementations( - final SharedPreferences sharedPreferences, -) => - [ - FilesApp(sharedPreferences), - NewsApp(sharedPreferences), - NotesApp(sharedPreferences), - NotificationsApp(sharedPreferences), - ]; +final List appImplementations = [ + FilesApp(), + NewsApp(), + NotesApp(), + NotificationsApp(), +]; diff --git a/packages/app/lib/main.dart b/packages/app/lib/main.dart index fcfdac75..62c13ad3 100644 --- a/packages/app/lib/main.dart +++ b/packages/app/lib/main.dart @@ -4,7 +4,7 @@ import 'package:neon/neon.dart'; Future main() async { await runNeon( - getAppImplementations: getAppImplementations, + appImplementations: appImplementations, theme: neonTheme, ); } diff --git a/packages/app/pubspec.lock b/packages/app/pubspec.lock index c06c2b75..e2a64504 100644 --- a/packages/app/pubspec.lock +++ b/packages/app/pubspec.lock @@ -349,10 +349,10 @@ packages: dependency: transitive description: name: flutter_local_notifications - sha256: "3cc40fe8c50ab8383f3e053a499f00f975636622ecdc8e20a77418ece3b1e975" + sha256: "3002092e5b8ce2f86c3361422e52e6db6776c23ee21e0b2f71b892bf4259ef04" url: "https://pub.dev" source: hosted - version: "15.1.0+1" + version: "15.1.1" flutter_local_notifications_linux: dependency: transitive description: @@ -383,7 +383,7 @@ packages: source: hosted version: "0.6.17+1" flutter_native_splash: - dependency: "direct main" + dependency: transitive description: name: flutter_native_splash sha256: ecff62b3b893f2f665de7e4ad3de89f738941fcfcaaba8ee601e749efafa4698 @@ -1044,7 +1044,7 @@ packages: source: hosted version: "3.3.0" shared_preferences: - dependency: "direct main" + dependency: "direct dev" description: name: shared_preferences sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1" @@ -1443,10 +1443,10 @@ packages: dependency: transitive description: name: webview_flutter - sha256: "789d52bd789373cc1e100fb634af2127e86c99cf9abde09499743270c5de8d00" + sha256: "04a0782fb058b7c71f2048935583488f4d32e9147ca403abc4e58f1de9964629" url: "https://pub.dev" source: hosted - version: "4.2.2" + version: "4.2.3" webview_flutter_android: dependency: transitive description: diff --git a/packages/app/pubspec.yaml b/packages/app/pubspec.yaml index fd67684a..9e744172 100644 --- a/packages/app/pubspec.yaml +++ b/packages/app/pubspec.yaml @@ -9,7 +9,6 @@ environment: dependencies: flutter: sdk: flutter - flutter_native_splash: ^2.3.2 flutter_svg: ^2.0.7 neon: git: @@ -31,7 +30,6 @@ dependencies: git: url: https://github.com/nextcloud/neon path: packages/neon/neon_notifications - shared_preferences: ^2.2.0 dev_dependencies: flutter_test: @@ -43,6 +41,7 @@ dev_dependencies: git: url: https://github.com/nextcloud/neon path: packages/neon_lints + shared_preferences: ^2.2.0 flutter: uses-material-design: true diff --git a/packages/neon/neon/lib/neon.dart b/packages/neon/neon/lib/neon.dart index 93cb201f..8b23e1b6 100644 --- a/packages/neon/neon/lib/neon.dart +++ b/packages/neon/neon/lib/neon.dart @@ -17,10 +17,9 @@ 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'; import 'package:provider/provider.dart'; -import 'package:shared_preferences/shared_preferences.dart'; Future runNeon({ - required final Iterable Function(SharedPreferences) getAppImplementations, + required final Iterable appImplementations, required final NeonTheme theme, @visibleForTesting final WidgetsBinding? bindingOverride, @visibleForTesting final Account? account, @@ -30,14 +29,10 @@ Future runNeon({ final binding = bindingOverride ?? WidgetsFlutterBinding.ensureInitialized(); FlutterNativeSplash.preserve(widgetsBinding: binding); - final sharedPreferences = await SharedPreferences.getInstance(); - await NeonPlatform.setup(); await RequestManager.instance.initCache(); await AppStorage.init(); - final allAppImplementations = getAppImplementations(sharedPreferences); - final packageInfo = await PackageInfo.fromPlatform(); buildUserAgent(packageInfo); @@ -47,7 +42,7 @@ Future runNeon({ final accountsBloc = AccountsBloc( globalOptions, - allAppImplementations, + appImplementations, ); if (account != null) { accountsBloc @@ -86,7 +81,7 @@ Future runNeon({ create: (final _) => nextPushBloc, ), Provider>( - create: (final _) => allAppImplementations, + create: (final _) => appImplementations, ), Provider( create: (final _) => packageInfo, diff --git a/packages/neon/neon/lib/src/models/app_implementation.dart b/packages/neon/neon/lib/src/models/app_implementation.dart index 0e0ee87e..0b5bcafd 100644 --- a/packages/neon/neon/lib/src/models/app_implementation.dart +++ b/packages/neon/neon/lib/src/models/app_implementation.dart @@ -11,12 +11,9 @@ import 'package:neon/src/settings/models/storage.dart'; import 'package:neon/src/widgets/drawer_destination.dart'; import 'package:provider/provider.dart'; import 'package:rxdart/rxdart.dart'; -import 'package:shared_preferences/shared_preferences.dart'; abstract class AppImplementation { - AppImplementation( - final SharedPreferences sharedPreferences, - ) { + AppImplementation() { final storage = AppStorage('app-$id'); options = buildOptions(storage); } diff --git a/packages/neon/neon/lib/src/models/notifications_interface.dart b/packages/neon/neon/lib/src/models/notifications_interface.dart index bf2fcdb1..b67b3cee 100644 --- a/packages/neon/neon/lib/src/models/notifications_interface.dart +++ b/packages/neon/neon/lib/src/models/notifications_interface.dart @@ -4,7 +4,7 @@ import 'package:neon/src/settings/models/nextcloud_app_options.dart'; abstract interface class NotificationsAppInterface extends AppImplementation { - NotificationsAppInterface(super.sharedPreferences); + NotificationsAppInterface(); } abstract interface class NotificationsBlocInterface extends InteractiveBloc { diff --git a/packages/neon/neon_files/lib/neon_files.dart b/packages/neon/neon_files/lib/neon_files.dart index ea3f00e0..b7c48b13 100644 --- a/packages/neon/neon_files/lib/neon_files.dart +++ b/packages/neon/neon_files/lib/neon_files.dart @@ -44,7 +44,7 @@ part 'widgets/browser_view.dart'; part 'widgets/file_preview.dart'; class FilesApp extends AppImplementation { - FilesApp(super.sharedPreferences); + FilesApp(); @override String id = AppIDs.files; diff --git a/packages/neon/neon_news/lib/neon_news.dart b/packages/neon/neon_news/lib/neon_news.dart index 47b3bf13..acb4ad08 100644 --- a/packages/neon/neon_news/lib/neon_news.dart +++ b/packages/neon/neon_news/lib/neon_news.dart @@ -52,7 +52,7 @@ part 'widgets/folder_view.dart'; part 'widgets/folders_view.dart'; class NewsApp extends AppImplementation { - NewsApp(super.sharedPreferences); + NewsApp(); @override String id = AppIDs.news; diff --git a/packages/neon/neon_notes/lib/neon_notes.dart b/packages/neon/neon_notes/lib/neon_notes.dart index 7f511280..af8fbb94 100644 --- a/packages/neon/neon_notes/lib/neon_notes.dart +++ b/packages/neon/neon_notes/lib/neon_notes.dart @@ -42,7 +42,7 @@ part 'widgets/notes_floating_action_button.dart'; part 'widgets/notes_view.dart'; class NotesApp extends AppImplementation { - NotesApp(super.sharedPreferences); + NotesApp(); @override String id = AppIDs.notes; diff --git a/packages/neon/neon_notifications/lib/neon_notifications.dart b/packages/neon/neon_notifications/lib/neon_notifications.dart index 20e9aee6..902dd7b4 100644 --- a/packages/neon/neon_notifications/lib/neon_notifications.dart +++ b/packages/neon/neon_notifications/lib/neon_notifications.dart @@ -22,7 +22,7 @@ part 'pages/main.dart'; class NotificationsApp extends AppImplementation implements NotificationsAppInterface { - NotificationsApp(super.sharedPreferences); + NotificationsApp(); @override String id = AppIDs.notifications; From 060eaf0bafb80b512e982ba7c6ff7daf7ed8e117 Mon Sep 17 00:00:00 2001 From: Nikolas Rimikis Date: Tue, 29 Aug 2023 08:18:29 +0200 Subject: [PATCH 5/7] refactor(neon,neon_files,neon_news,neon_notes,neon_notifications): make AppImplementation immutable and cleanup options initialization Signed-off-by: Nikolas Rimikis --- .../neon/lib/src/models/app_implementation.dart | 16 ++++++++-------- .../lib/src/models/notifications_interface.dart | 5 +++++ packages/neon/neon_files/lib/neon_files.dart | 2 +- packages/neon/neon_news/lib/neon_news.dart | 2 +- packages/neon/neon_notes/lib/neon_notes.dart | 2 +- .../lib/neon_notifications.dart | 2 +- 6 files changed, 17 insertions(+), 12 deletions(-) diff --git a/packages/neon/neon/lib/src/models/app_implementation.dart b/packages/neon/neon/lib/src/models/app_implementation.dart index 0b5bcafd..4628d10d 100644 --- a/packages/neon/neon/lib/src/models/app_implementation.dart +++ b/packages/neon/neon/lib/src/models/app_implementation.dart @@ -2,6 +2,7 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:go_router/go_router.dart'; +import 'package:meta/meta.dart'; import 'package:neon/l10n/localizations.dart'; import 'package:neon/src/bloc/bloc.dart'; import 'package:neon/src/blocs/accounts.dart'; @@ -12,11 +13,9 @@ import 'package:neon/src/widgets/drawer_destination.dart'; import 'package:provider/provider.dart'; import 'package:rxdart/rxdart.dart'; +@immutable abstract class AppImplementation { - AppImplementation() { - final storage = AppStorage('app-$id'); - options = buildOptions(storage); - } + AppImplementation(); String get id; LocalizationsDelegate get localizationsDelegate; @@ -25,10 +24,11 @@ abstract class AppImplementation String nameFromLocalization(final AppLocalizations localizations) => localizations.appImplementationName(id); String name(final BuildContext context) => nameFromLocalization(AppLocalizations.of(context)); - late final R options; - @protected - R buildOptions(final AppStorage storage); + late final AppStorage storage = AppStorage('app-$id'); + + @mustBeOverridden + R get options; final Map _blocs = {}; @@ -115,7 +115,7 @@ abstract class AppImplementation /// A custom theme that will be injected into the widget tree. /// /// You can later acess it through `Theme.of(context).extension()`. - ThemeExtension? theme; + final ThemeExtension? theme = null; } extension AppImplementationFind on Iterable { diff --git a/packages/neon/neon/lib/src/models/notifications_interface.dart b/packages/neon/neon/lib/src/models/notifications_interface.dart index b67b3cee..7164dc24 100644 --- a/packages/neon/neon/lib/src/models/notifications_interface.dart +++ b/packages/neon/neon/lib/src/models/notifications_interface.dart @@ -1,3 +1,4 @@ +import 'package:meta/meta.dart'; import 'package:neon/src/bloc/bloc.dart'; import 'package:neon/src/models/app_implementation.dart'; import 'package:neon/src/settings/models/nextcloud_app_options.dart'; @@ -5,6 +6,10 @@ import 'package:neon/src/settings/models/nextcloud_app_options.dart'; abstract interface class NotificationsAppInterface extends AppImplementation { NotificationsAppInterface(); + + @override + @mustBeOverridden + R get options => throw UnimplementedError(); } abstract interface class NotificationsBlocInterface extends InteractiveBloc { diff --git a/packages/neon/neon_files/lib/neon_files.dart b/packages/neon/neon_files/lib/neon_files.dart index b7c48b13..724f058b 100644 --- a/packages/neon/neon_files/lib/neon_files.dart +++ b/packages/neon/neon_files/lib/neon_files.dart @@ -56,7 +56,7 @@ class FilesApp extends AppImplementation { List supportedLocales = AppLocalizations.supportedLocales; @override - FilesAppSpecificOptions buildOptions(final AppStorage storage) => FilesAppSpecificOptions(storage); + late final FilesAppSpecificOptions options = FilesAppSpecificOptions(storage); @override FilesBloc buildBloc(final Account account) => FilesBloc( diff --git a/packages/neon/neon_news/lib/neon_news.dart b/packages/neon/neon_news/lib/neon_news.dart index acb4ad08..c6cf5125 100644 --- a/packages/neon/neon_news/lib/neon_news.dart +++ b/packages/neon/neon_news/lib/neon_news.dart @@ -64,7 +64,7 @@ class NewsApp extends AppImplementation { List supportedLocales = AppLocalizations.supportedLocales; @override - NewsAppSpecificOptions buildOptions(final AppStorage storage) => NewsAppSpecificOptions(storage); + late final NewsAppSpecificOptions options = NewsAppSpecificOptions(storage); @override NewsBloc buildBloc(final Account account) => NewsBloc( diff --git a/packages/neon/neon_notes/lib/neon_notes.dart b/packages/neon/neon_notes/lib/neon_notes.dart index af8fbb94..96040a89 100644 --- a/packages/neon/neon_notes/lib/neon_notes.dart +++ b/packages/neon/neon_notes/lib/neon_notes.dart @@ -54,7 +54,7 @@ class NotesApp extends AppImplementation { LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate; @override - NotesAppSpecificOptions buildOptions(final AppStorage storage) => NotesAppSpecificOptions(storage); + late final NotesAppSpecificOptions options = NotesAppSpecificOptions(storage); @override NotesBloc buildBloc(final Account account) => NotesBloc( diff --git a/packages/neon/neon_notifications/lib/neon_notifications.dart b/packages/neon/neon_notifications/lib/neon_notifications.dart index 902dd7b4..9da97fca 100644 --- a/packages/neon/neon_notifications/lib/neon_notifications.dart +++ b/packages/neon/neon_notifications/lib/neon_notifications.dart @@ -34,7 +34,7 @@ class NotificationsApp extends AppImplementation supportedLocales = AppLocalizations.supportedLocales; @override - NotificationsAppSpecificOptions buildOptions(final AppStorage storage) => NotificationsAppSpecificOptions(storage); + late final NotificationsAppSpecificOptions options = NotificationsAppSpecificOptions(storage); @override NotificationsBloc buildBloc(final Account account) => NotificationsBloc( From 26676dc1c7450985710e0fc5387e0a3f314d3961 Mon Sep 17 00:00:00 2001 From: Nikolas Rimikis Date: Tue, 29 Aug 2023 08:18:29 +0200 Subject: [PATCH 6/7] refactor(neon_files,neon_news,neon_notes,neon_notifications): make concrete AppImplementations immutable Signed-off-by: Nikolas Rimikis --- packages/neon/neon_files/lib/neon_files.dart | 10 +++++----- packages/neon/neon_news/lib/neon_news.dart | 10 +++++----- packages/neon/neon_notes/lib/neon_notes.dart | 10 +++++----- .../neon_notifications/lib/neon_notifications.dart | 10 +++++----- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/neon/neon_files/lib/neon_files.dart b/packages/neon/neon_files/lib/neon_files.dart index 724f058b..0f21a143 100644 --- a/packages/neon/neon_files/lib/neon_files.dart +++ b/packages/neon/neon_files/lib/neon_files.dart @@ -47,13 +47,13 @@ class FilesApp extends AppImplementation { FilesApp(); @override - String id = AppIDs.files; + final String id = AppIDs.files; @override - LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate; + final LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate; @override - List supportedLocales = AppLocalizations.supportedLocales; + final List supportedLocales = AppLocalizations.supportedLocales; @override late final FilesAppSpecificOptions options = FilesAppSpecificOptions(storage); @@ -65,8 +65,8 @@ class FilesApp extends AppImplementation { ); @override - Widget get page => const FilesMainPage(); + final Widget page = const FilesMainPage(); @override - RouteBase get route => $filesAppRoute; + final RouteBase route = $filesAppRoute; } diff --git a/packages/neon/neon_news/lib/neon_news.dart b/packages/neon/neon_news/lib/neon_news.dart index c6cf5125..8e5c18cd 100644 --- a/packages/neon/neon_news/lib/neon_news.dart +++ b/packages/neon/neon_news/lib/neon_news.dart @@ -55,13 +55,13 @@ class NewsApp extends AppImplementation { NewsApp(); @override - String id = AppIDs.news; + final String id = AppIDs.news; @override - LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate; + final LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate; @override - List supportedLocales = AppLocalizations.supportedLocales; + final List supportedLocales = AppLocalizations.supportedLocales; @override late final NewsAppSpecificOptions options = NewsAppSpecificOptions(storage); @@ -73,10 +73,10 @@ class NewsApp extends AppImplementation { ); @override - Widget get page => const NewsMainPage(); + final Widget page = const NewsMainPage(); @override - RouteBase get route => $newsAppRoute; + final RouteBase route = $newsAppRoute; @override BehaviorSubject getUnreadCounter(final NewsBloc bloc) => bloc.unreadCounter; diff --git a/packages/neon/neon_notes/lib/neon_notes.dart b/packages/neon/neon_notes/lib/neon_notes.dart index 96040a89..f44a5384 100644 --- a/packages/neon/neon_notes/lib/neon_notes.dart +++ b/packages/neon/neon_notes/lib/neon_notes.dart @@ -45,13 +45,13 @@ class NotesApp extends AppImplementation { NotesApp(); @override - String id = AppIDs.notes; + final String id = AppIDs.notes; @override - List supportedLocales = AppLocalizations.supportedLocales; + final List supportedLocales = AppLocalizations.supportedLocales; @override - LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate; + final LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate; @override late final NotesAppSpecificOptions options = NotesAppSpecificOptions(storage); @@ -63,8 +63,8 @@ class NotesApp extends AppImplementation { ); @override - Widget get page => const NotesMainPage(); + final Widget page = const NotesMainPage(); @override - RouteBase get route => $notesAppRoute; + final RouteBase route = $notesAppRoute; } diff --git a/packages/neon/neon_notifications/lib/neon_notifications.dart b/packages/neon/neon_notifications/lib/neon_notifications.dart index 9da97fca..7082cfff 100644 --- a/packages/neon/neon_notifications/lib/neon_notifications.dart +++ b/packages/neon/neon_notifications/lib/neon_notifications.dart @@ -25,13 +25,13 @@ class NotificationsApp extends AppImplementation supportedLocales = AppLocalizations.supportedLocales; + final List supportedLocales = AppLocalizations.supportedLocales; @override late final NotificationsAppSpecificOptions options = NotificationsAppSpecificOptions(storage); @@ -43,10 +43,10 @@ class NotificationsApp extends AppImplementation const NotificationsMainPage(); + final Widget page = const NotificationsMainPage(); @override - RouteBase get route => $notificationsAppRoute; + final RouteBase route = $notificationsAppRoute; @override BehaviorSubject getUnreadCounter(final NotificationsBloc bloc) => bloc.unreadCounter; From 5c0b2cbc7ec6ba54a3f8ae4e579a06083890a5c1 Mon Sep 17 00:00:00 2001 From: Nikolas Rimikis Date: Tue, 29 Aug 2023 08:33:51 +0200 Subject: [PATCH 7/7] test(neon): add some AppStorage and AppImplementation tests Signed-off-by: Nikolas Rimikis --- .../neon/test/app_implementation_test.dart | 30 +++++++++++++++++++ packages/neon/neon/test/storage_test.dart | 14 +++++++++ 2 files changed, 44 insertions(+) create mode 100644 packages/neon/neon/test/app_implementation_test.dart create mode 100644 packages/neon/neon/test/storage_test.dart diff --git a/packages/neon/neon/test/app_implementation_test.dart b/packages/neon/neon/test/app_implementation_test.dart new file mode 100644 index 00000000..4747ac76 --- /dev/null +++ b/packages/neon/neon/test/app_implementation_test.dart @@ -0,0 +1,30 @@ +import 'package:mocktail/mocktail.dart'; +import 'package:neon/src/models/app_implementation.dart'; +import 'package:test/test.dart'; + +// ignore: missing_override_of_must_be_overridden +class AppImplementationMock extends Mock implements AppImplementation {} + +void main() { + group('group name', () { + test('AccountFind', () { + final app1 = AppImplementationMock(); + final app2 = AppImplementationMock(); + + final apps = { + app1, + app2, + }; + + when(() => app1.id).thenReturn('app1'); + when(() => app2.id).thenReturn('app2'); + + expect(apps.tryFind(null), isNull); + expect(apps.tryFind('invalidID'), isNull); + expect(apps.tryFind(app2.id), equals(app2)); + + expect(() => apps.find('invalidID'), throwsA(isA())); + expect(apps.find(app2.id), equals(app2)); + }); + }); +} diff --git a/packages/neon/neon/test/storage_test.dart b/packages/neon/neon/test/storage_test.dart new file mode 100644 index 00000000..bda8df24 --- /dev/null +++ b/packages/neon/neon/test/storage_test.dart @@ -0,0 +1,14 @@ +import 'package:neon/src/settings/models/storage.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:test/test.dart'; + +void main() { + test('AppStorage', () async { + expect(() => AppStorage.reqireDatabase, throwsA(isA())); + + SharedPreferences.setMockInitialValues({}); + await AppStorage.init(); + + expect(AppStorage.reqireDatabase, isA()); + }); +}