Browse Source

Merge pull request #654 from nextcloud/refactor/sharedPreferences

Refactor/shared preferences
pull/664/head
Nikolas Rimikis 1 year ago committed by GitHub
parent
commit
db51fa1e16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      packages/app/integration_test/screenshot_test.dart
  2. 14
      packages/app/lib/apps.dart
  3. 2
      packages/app/lib/main.dart
  4. 12
      packages/app/pubspec.lock
  5. 3
      packages/app/pubspec.yaml
  6. 19
      packages/neon/neon/lib/neon.dart
  7. 7
      packages/neon/neon/lib/src/blocs/accounts.dart
  8. 18
      packages/neon/neon/lib/src/blocs/first_launch.dart
  9. 5
      packages/neon/neon/lib/src/blocs/push_notifications.dart
  10. 19
      packages/neon/neon/lib/src/models/app_implementation.dart
  11. 7
      packages/neon/neon/lib/src/models/notifications_interface.dart
  12. 47
      packages/neon/neon/lib/src/settings/models/storage.dart
  13. 5
      packages/neon/neon/lib/src/utils/global_options.dart
  14. 7
      packages/neon/neon/lib/src/utils/push_utils.dart
  15. 30
      packages/neon/neon/test/app_implementation_test.dart
  16. 14
      packages/neon/neon/test/storage_test.dart
  17. 14
      packages/neon/neon_files/lib/neon_files.dart
  18. 14
      packages/neon/neon_news/lib/neon_news.dart
  19. 14
      packages/neon/neon_notes/lib/neon_notes.dart
  20. 14
      packages/neon/neon_notifications/lib/neon_notifications.dart

2
packages/app/integration_test/screenshot_test.dart

@ -20,7 +20,7 @@ Future runTestApp(
final Account? account, final Account? account,
}) async { }) async {
await runNeon( await runNeon(
getAppImplementations: getAppImplementations, appImplementations: appImplementations,
theme: neonTheme, theme: neonTheme,
bindingOverride: binding, bindingOverride: binding,
account: account, account: account,

14
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_news/neon_news.dart';
import 'package:neon_notes/neon_notes.dart'; import 'package:neon_notes/neon_notes.dart';
import 'package:neon_notifications/neon_notifications.dart'; import 'package:neon_notifications/neon_notifications.dart';
import 'package:shared_preferences/shared_preferences.dart';
List<AppImplementation> getAppImplementations( final List<AppImplementation> appImplementations = [
final SharedPreferences sharedPreferences, FilesApp(),
) => NewsApp(),
[ NotesApp(),
FilesApp(sharedPreferences), NotificationsApp(),
NewsApp(sharedPreferences),
NotesApp(sharedPreferences),
NotificationsApp(sharedPreferences),
]; ];

2
packages/app/lib/main.dart

@ -4,7 +4,7 @@ import 'package:neon/neon.dart';
Future main() async { Future main() async {
await runNeon( await runNeon(
getAppImplementations: getAppImplementations, appImplementations: appImplementations,
theme: neonTheme, theme: neonTheme,
); );
} }

12
packages/app/pubspec.lock

@ -349,10 +349,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: flutter_local_notifications name: flutter_local_notifications
sha256: "3cc40fe8c50ab8383f3e053a499f00f975636622ecdc8e20a77418ece3b1e975" sha256: "3002092e5b8ce2f86c3361422e52e6db6776c23ee21e0b2f71b892bf4259ef04"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "15.1.0+1" version: "15.1.1"
flutter_local_notifications_linux: flutter_local_notifications_linux:
dependency: transitive dependency: transitive
description: description:
@ -383,7 +383,7 @@ packages:
source: hosted source: hosted
version: "0.6.17+1" version: "0.6.17+1"
flutter_native_splash: flutter_native_splash:
dependency: "direct main" dependency: transitive
description: description:
name: flutter_native_splash name: flutter_native_splash
sha256: ecff62b3b893f2f665de7e4ad3de89f738941fcfcaaba8ee601e749efafa4698 sha256: ecff62b3b893f2f665de7e4ad3de89f738941fcfcaaba8ee601e749efafa4698
@ -1044,7 +1044,7 @@ packages:
source: hosted source: hosted
version: "3.3.0" version: "3.3.0"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct dev"
description: description:
name: shared_preferences name: shared_preferences
sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1" sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1"
@ -1443,10 +1443,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter name: webview_flutter
sha256: "789d52bd789373cc1e100fb634af2127e86c99cf9abde09499743270c5de8d00" sha256: "04a0782fb058b7c71f2048935583488f4d32e9147ca403abc4e58f1de9964629"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.2.2" version: "4.2.3"
webview_flutter_android: webview_flutter_android:
dependency: transitive dependency: transitive
description: description:

3
packages/app/pubspec.yaml

@ -9,7 +9,6 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_native_splash: ^2.3.2
flutter_svg: ^2.0.7 flutter_svg: ^2.0.7
neon: neon:
git: git:
@ -31,7 +30,6 @@ dependencies:
git: git:
url: https://github.com/nextcloud/neon url: https://github.com/nextcloud/neon
path: packages/neon/neon_notifications path: packages/neon/neon_notifications
shared_preferences: ^2.2.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@ -43,6 +41,7 @@ dev_dependencies:
git: git:
url: https://github.com/nextcloud/neon url: https://github.com/nextcloud/neon
path: packages/neon_lints path: packages/neon_lints
shared_preferences: ^2.2.0
flutter: flutter:
uses-material-design: true uses-material-design: true

19
packages/neon/neon/lib/neon.dart

@ -10,16 +10,16 @@ import 'package:neon/src/blocs/push_notifications.dart';
import 'package:neon/src/models/account.dart'; import 'package:neon/src/models/account.dart';
import 'package:neon/src/models/app_implementation.dart'; import 'package:neon/src/models/app_implementation.dart';
import 'package:neon/src/platform/platform.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/theme/neon.dart';
import 'package:neon/src/utils/global_options.dart'; import 'package:neon/src/utils/global_options.dart';
import 'package:neon/src/utils/request_manager.dart'; import 'package:neon/src/utils/request_manager.dart';
import 'package:neon/src/utils/user_agent.dart'; import 'package:neon/src/utils/user_agent.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
Future runNeon({ Future runNeon({
required final Iterable<AppImplementation> Function(SharedPreferences) getAppImplementations, required final Iterable<AppImplementation> appImplementations,
required final NeonTheme theme, required final NeonTheme theme,
@visibleForTesting final WidgetsBinding? bindingOverride, @visibleForTesting final WidgetsBinding? bindingOverride,
@visibleForTesting final Account? account, @visibleForTesting final Account? account,
@ -29,24 +29,20 @@ Future runNeon({
final binding = bindingOverride ?? WidgetsFlutterBinding.ensureInitialized(); final binding = bindingOverride ?? WidgetsFlutterBinding.ensureInitialized();
FlutterNativeSplash.preserve(widgetsBinding: binding); FlutterNativeSplash.preserve(widgetsBinding: binding);
final sharedPreferences = await SharedPreferences.getInstance();
await NeonPlatform.setup(); await NeonPlatform.setup();
await RequestManager.instance.initCache(); await RequestManager.instance.initCache();
final allAppImplementations = getAppImplementations(sharedPreferences); await AppStorage.init();
final packageInfo = await PackageInfo.fromPlatform(); final packageInfo = await PackageInfo.fromPlatform();
buildUserAgent(packageInfo); buildUserAgent(packageInfo);
final globalOptions = GlobalOptions( final globalOptions = GlobalOptions(
sharedPreferences,
packageInfo, packageInfo,
); );
final accountsBloc = AccountsBloc( final accountsBloc = AccountsBloc(
sharedPreferences,
globalOptions, globalOptions,
allAppImplementations, appImplementations,
); );
if (account != null) { if (account != null) {
accountsBloc accountsBloc
@ -55,11 +51,9 @@ Future runNeon({
} }
final pushNotificationsBloc = PushNotificationsBloc( final pushNotificationsBloc = PushNotificationsBloc(
accountsBloc, accountsBloc,
sharedPreferences,
globalOptions, globalOptions,
); );
final firstLaunchBloc = FirstLaunchBloc( final firstLaunchBloc = FirstLaunchBloc(
sharedPreferences,
disabled: firstLaunchDisabled, disabled: firstLaunchDisabled,
); );
final nextPushBloc = NextPushBloc( final nextPushBloc = NextPushBloc(
@ -71,9 +65,6 @@ Future runNeon({
runApp( runApp(
MultiProvider( MultiProvider(
providers: [ providers: [
Provider<SharedPreferences>(
create: (final _) => sharedPreferences,
),
Provider<GlobalOptions>( Provider<GlobalOptions>(
create: (final _) => globalOptions, create: (final _) => globalOptions,
), ),
@ -90,7 +81,7 @@ Future runNeon({
create: (final _) => nextPushBloc, create: (final _) => nextPushBloc,
), ),
Provider<Iterable<AppImplementation>>( Provider<Iterable<AppImplementation>>(
create: (final _) => allAppImplementations, create: (final _) => appImplementations,
), ),
Provider<PackageInfo>( Provider<PackageInfo>(
create: (final _) => packageInfo, create: (final _) => packageInfo,

7
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/account_options.dart';
import 'package:neon/src/utils/global_options.dart'; import 'package:neon/src/utils/global_options.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
import 'package:shared_preferences/shared_preferences.dart';
const _keyAccounts = 'accounts'; const _keyAccounts = 'accounts';
@ -56,7 +55,6 @@ abstract interface class AccountsBlocStates {
class AccountsBloc extends Bloc implements AccountsBlocEvents, AccountsBlocStates { class AccountsBloc extends Bloc implements AccountsBlocEvents, AccountsBlocStates {
AccountsBloc( AccountsBloc(
this._sharedPreferences,
this._globalOptions, this._globalOptions,
this._allAppImplementations, this._allAppImplementations,
) { ) {
@ -96,8 +94,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 GlobalOptions _globalOptions;
final Iterable<AppImplementation> _allAppImplementations; final Iterable<AppImplementation> _allAppImplementations;
final _keyLastUsedAccount = 'last-used-account'; final _keyLastUsedAccount = 'last-used-account';
@ -213,7 +210,7 @@ class AccountsBloc extends Bloc implements AccountsBlocEvents, AccountsBlocState
/// Use [activeOptions] to get them for the [activeAccount]. /// Use [activeOptions] to get them for the [activeAccount].
AccountSpecificOptions getOptionsFor(final Account account) => AccountSpecificOptions getOptionsFor(final Account account) =>
_accountsOptions[account.id] ??= AccountSpecificOptions( _accountsOptions[account.id] ??= AccountSpecificOptions(
AppStorage('accounts-${account.id}', _sharedPreferences), AppStorage('accounts-${account.id}'),
getAppsBlocFor(account), getAppsBlocFor(account),
); );

18
packages/neon/neon/lib/src/blocs/first_launch.dart

@ -2,8 +2,8 @@ import 'dart:async';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:neon/src/bloc/bloc.dart'; import 'package:neon/src/bloc/bloc.dart';
import 'package:neon/src/settings/models/storage.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
import 'package:shared_preferences/shared_preferences.dart';
abstract class FirstLaunchBlocEvents {} abstract class FirstLaunchBlocEvents {}
@ -11,20 +11,20 @@ abstract class FirstLaunchBlocStates {
BehaviorSubject get onFirstLaunch; BehaviorSubject get onFirstLaunch;
} }
@immutable
@internal @internal
class FirstLaunchBloc extends Bloc implements FirstLaunchBlocEvents, FirstLaunchBlocStates { class FirstLaunchBloc extends Bloc implements FirstLaunchBlocEvents, FirstLaunchBlocStates {
FirstLaunchBloc( FirstLaunchBloc({
this._sharedPreferences, {
final bool disabled = false, final bool disabled = false,
}) { }) : _storage = AppStorage(_keyFirstLaunch) {
if (!disabled && !_sharedPreferences.containsKey(_keyFirstLaunch)) { if (!disabled && !_storage.containsKey(_keyFirstLaunch)) {
onFirstLaunch.add(null); onFirstLaunch.add(null);
unawaited(_sharedPreferences.setBool(_keyFirstLaunch, false)); unawaited(_storage.setBool(_keyFirstLaunch, false));
} }
} }
final SharedPreferences _sharedPreferences; final AppStorage _storage;
final _keyFirstLaunch = 'first-launch'; static const _keyFirstLaunch = 'first-launch';
@override @override
void dispose() { void dispose() {
@ -32,5 +32,5 @@ class FirstLaunchBloc extends Bloc implements FirstLaunchBlocEvents, FirstLaunch
} }
@override @override
BehaviorSubject onFirstLaunch = BehaviorSubject(); final BehaviorSubject onFirstLaunch = BehaviorSubject();
} }

5
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/global_options.dart';
import 'package:neon/src/utils/push_utils.dart'; import 'package:neon/src/utils/push_utils.dart';
import 'package:nextcloud/nextcloud.dart'; import 'package:nextcloud/nextcloud.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:unifiedpush/unifiedpush.dart'; import 'package:unifiedpush/unifiedpush.dart';
abstract class PushNotificationsBlocEvents {} abstract class PushNotificationsBlocEvents {}
@ -26,7 +25,6 @@ abstract class PushNotificationsBlocStates {
class PushNotificationsBloc extends Bloc implements PushNotificationsBlocEvents, PushNotificationsBlocStates { class PushNotificationsBloc extends Bloc implements PushNotificationsBlocEvents, PushNotificationsBlocStates {
PushNotificationsBloc( PushNotificationsBloc(
this._accountsBloc, this._accountsBloc,
this._sharedPreferences,
this._globalOptions, this._globalOptions,
) { ) {
if (NeonPlatform.instance.canUsePushNotifications) { if (NeonPlatform.instance.canUsePushNotifications) {
@ -39,8 +37,7 @@ class PushNotificationsBloc extends Bloc implements PushNotificationsBlocEvents,
} }
final AccountsBloc _accountsBloc; final AccountsBloc _accountsBloc;
final SharedPreferences _sharedPreferences; late final _storage = AppStorage(AppIDs.notifications);
late final _storage = AppStorage(AppIDs.notifications, _sharedPreferences);
final GlobalOptions _globalOptions; final GlobalOptions _globalOptions;
final _notificationsController = StreamController<PushNotification>(); final _notificationsController = StreamController<PushNotification>();

19
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/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:meta/meta.dart';
import 'package:neon/l10n/localizations.dart'; import 'package:neon/l10n/localizations.dart';
import 'package:neon/src/bloc/bloc.dart'; import 'package:neon/src/bloc/bloc.dart';
import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/blocs/accounts.dart';
@ -11,15 +12,10 @@ import 'package:neon/src/settings/models/storage.dart';
import 'package:neon/src/widgets/drawer_destination.dart'; import 'package:neon/src/widgets/drawer_destination.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
import 'package:shared_preferences/shared_preferences.dart';
@immutable
abstract class AppImplementation<T extends Bloc, R extends NextcloudAppOptions> { abstract class AppImplementation<T extends Bloc, R extends NextcloudAppOptions> {
AppImplementation( AppImplementation();
final SharedPreferences sharedPreferences,
) {
final storage = AppStorage('app-$id', sharedPreferences);
options = buildOptions(storage);
}
String get id; String get id;
LocalizationsDelegate get localizationsDelegate; LocalizationsDelegate get localizationsDelegate;
@ -28,10 +24,11 @@ abstract class AppImplementation<T extends Bloc, R extends NextcloudAppOptions>
String nameFromLocalization(final AppLocalizations localizations) => localizations.appImplementationName(id); String nameFromLocalization(final AppLocalizations localizations) => localizations.appImplementationName(id);
String name(final BuildContext context) => nameFromLocalization(AppLocalizations.of(context)); String name(final BuildContext context) => nameFromLocalization(AppLocalizations.of(context));
late final R options;
@protected @protected
R buildOptions(final AppStorage storage); late final AppStorage storage = AppStorage('app-$id');
@mustBeOverridden
R get options;
final Map<String, T> _blocs = {}; final Map<String, T> _blocs = {};
@ -118,7 +115,7 @@ abstract class AppImplementation<T extends Bloc, R extends NextcloudAppOptions>
/// A custom theme that will be injected into the widget tree. /// A custom theme that will be injected into the widget tree.
/// ///
/// You can later acess it through `Theme.of(context).extension<ThemeName>()`. /// You can later acess it through `Theme.of(context).extension<ThemeName>()`.
ThemeExtension? theme; final ThemeExtension? theme = null;
} }
extension AppImplementationFind on Iterable<AppImplementation> { extension AppImplementationFind on Iterable<AppImplementation> {

7
packages/neon/neon/lib/src/models/notifications_interface.dart

@ -1,10 +1,15 @@
import 'package:meta/meta.dart';
import 'package:neon/src/bloc/bloc.dart'; import 'package:neon/src/bloc/bloc.dart';
import 'package:neon/src/models/app_implementation.dart'; import 'package:neon/src/models/app_implementation.dart';
import 'package:neon/src/settings/models/nextcloud_app_options.dart'; import 'package:neon/src/settings/models/nextcloud_app_options.dart';
abstract interface class NotificationsAppInterface<T extends NotificationsBlocInterface, abstract interface class NotificationsAppInterface<T extends NotificationsBlocInterface,
R extends NotificationsOptionsInterface> extends AppImplementation<T, R> { R extends NotificationsOptionsInterface> extends AppImplementation<T, R> {
NotificationsAppInterface(super.sharedPreferences); NotificationsAppInterface();
@override
@mustBeOverridden
R get options => throw UnimplementedError();
} }
abstract interface class NotificationsBlocInterface extends InteractiveBloc { abstract interface class NotificationsBlocInterface extends InteractiveBloc {

47
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'; import 'package:shared_preferences/shared_preferences.dart';
abstract interface class SettingsStorage { abstract interface class SettingsStorage {
@ -14,35 +15,55 @@ abstract interface class SettingsStorage {
} }
class AppStorage implements SettingsStorage { class AppStorage implements SettingsStorage {
AppStorage( AppStorage(this._id);
this._id,
this._sharedPreferences,
);
final String _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'; 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 @override
Future<bool> remove(final String key) => _sharedPreferences.remove(_formatKey(key)); Future<bool> remove(final String key) => reqireDatabase.remove(_formatKey(key));
@override @override
String? getString(final String key) => _sharedPreferences.getString(_formatKey(key)); String? getString(final String key) => reqireDatabase.getString(_formatKey(key));
@override @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 @override
bool? getBool(final String key) => _sharedPreferences.getBool(_formatKey(key)); bool? getBool(final String key) => reqireDatabase.getBool(_formatKey(key));
@override @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<String>? getStringList(final String key) => _sharedPreferences.getStringList(_formatKey(key)); List<String>? getStringList(final String key) => reqireDatabase.getStringList(_formatKey(key));
Future setStringList(final String key, final List<String> value) => Future setStringList(final String key, final List<String> value) =>
_sharedPreferences.setStringList(_formatKey(key), value); reqireDatabase.setStringList(_formatKey(key), value);
} }

5
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:neon/src/settings/models/toggle_option.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:shared_preferences/shared_preferences.dart';
const unifiedPushNextPushID = 'org.unifiedpush.distributor.nextpush'; const unifiedPushNextPushID = 'org.unifiedpush.distributor.nextpush';
@ -19,7 +18,6 @@ const unifiedPushNextPushID = 'org.unifiedpush.distributor.nextpush';
@immutable @immutable
class GlobalOptions { class GlobalOptions {
GlobalOptions( GlobalOptions(
this._sharedPreferences,
this._packageInfo, this._packageInfo,
) { ) {
pushNotificationsEnabled.addListener(_pushNotificationsEnabledListener); pushNotificationsEnabled.addListener(_pushNotificationsEnabledListener);
@ -51,8 +49,7 @@ class GlobalOptions {
} }
} }
final SharedPreferences _sharedPreferences; late final AppStorage _storage = AppStorage('global');
late final AppStorage _storage = AppStorage('global', _sharedPreferences);
final PackageInfo _packageInfo; final PackageInfo _packageInfo;
late final _distributorsMap = <String, String Function(BuildContext)>{ late final _distributorsMap = <String, String Function(BuildContext)>{

7
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/global.dart';
import 'package:neon/src/utils/localizations.dart'; import 'package:neon/src/utils/localizations.dart';
import 'package:nextcloud/nextcloud.dart'; import 'package:nextcloud/nextcloud.dart';
import 'package:shared_preferences/shared_preferences.dart';
@internal @internal
@immutable @immutable
@ -71,9 +70,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) { for (final message in Uri(query: utf8.decode(messages)).queryParameters.values) {
final data = json.decode(message) as Map<String, dynamic>; final data = json.decode(message) as Map<String, dynamic>;
@ -99,7 +98,7 @@ class PushUtils {
NotificationsNotification? notification; NotificationsNotification? notification;
AndroidBitmap<Object>? largeIconBitmap; AndroidBitmap<Object>? largeIconBitmap;
try { try {
accounts = loadAccounts(AppStorage('accounts', sharedPreferences)); accounts = loadAccounts(AppStorage('accounts'));
account = accounts.tryFind(instance); account = accounts.tryFind(instance);
if (account != null) { if (account != null) {
notification = notification =

30
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<StateError>()));
expect(apps.find(app2.id), equals(app2));
});
});
}

14
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<StateError>()));
SharedPreferences.setMockInitialValues({});
await AppStorage.init();
expect(AppStorage.reqireDatabase, isA<SharedPreferences>());
});
}

14
packages/neon/neon_files/lib/neon_files.dart

@ -44,19 +44,19 @@ part 'widgets/browser_view.dart';
part 'widgets/file_preview.dart'; part 'widgets/file_preview.dart';
class FilesApp extends AppImplementation<FilesBloc, FilesAppSpecificOptions> { class FilesApp extends AppImplementation<FilesBloc, FilesAppSpecificOptions> {
FilesApp(super.sharedPreferences); FilesApp();
@override @override
String id = AppIDs.files; final String id = AppIDs.files;
@override @override
LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate; final LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate;
@override @override
List<Locale> supportedLocales = AppLocalizations.supportedLocales; final List<Locale> supportedLocales = AppLocalizations.supportedLocales;
@override @override
FilesAppSpecificOptions buildOptions(final AppStorage storage) => FilesAppSpecificOptions(storage); late final FilesAppSpecificOptions options = FilesAppSpecificOptions(storage);
@override @override
FilesBloc buildBloc(final Account account) => FilesBloc( FilesBloc buildBloc(final Account account) => FilesBloc(
@ -65,8 +65,8 @@ class FilesApp extends AppImplementation<FilesBloc, FilesAppSpecificOptions> {
); );
@override @override
Widget get page => const FilesMainPage(); final Widget page = const FilesMainPage();
@override @override
RouteBase get route => $filesAppRoute; final RouteBase route = $filesAppRoute;
} }

14
packages/neon/neon_news/lib/neon_news.dart

@ -52,19 +52,19 @@ part 'widgets/folder_view.dart';
part 'widgets/folders_view.dart'; part 'widgets/folders_view.dart';
class NewsApp extends AppImplementation<NewsBloc, NewsAppSpecificOptions> { class NewsApp extends AppImplementation<NewsBloc, NewsAppSpecificOptions> {
NewsApp(super.sharedPreferences); NewsApp();
@override @override
String id = AppIDs.news; final String id = AppIDs.news;
@override @override
LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate; final LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate;
@override @override
List<Locale> supportedLocales = AppLocalizations.supportedLocales; final List<Locale> supportedLocales = AppLocalizations.supportedLocales;
@override @override
NewsAppSpecificOptions buildOptions(final AppStorage storage) => NewsAppSpecificOptions(storage); late final NewsAppSpecificOptions options = NewsAppSpecificOptions(storage);
@override @override
NewsBloc buildBloc(final Account account) => NewsBloc( NewsBloc buildBloc(final Account account) => NewsBloc(
@ -73,10 +73,10 @@ class NewsApp extends AppImplementation<NewsBloc, NewsAppSpecificOptions> {
); );
@override @override
Widget get page => const NewsMainPage(); final Widget page = const NewsMainPage();
@override @override
RouteBase get route => $newsAppRoute; final RouteBase route = $newsAppRoute;
@override @override
BehaviorSubject<int> getUnreadCounter(final NewsBloc bloc) => bloc.unreadCounter; BehaviorSubject<int> getUnreadCounter(final NewsBloc bloc) => bloc.unreadCounter;

14
packages/neon/neon_notes/lib/neon_notes.dart

@ -42,19 +42,19 @@ part 'widgets/notes_floating_action_button.dart';
part 'widgets/notes_view.dart'; part 'widgets/notes_view.dart';
class NotesApp extends AppImplementation<NotesBloc, NotesAppSpecificOptions> { class NotesApp extends AppImplementation<NotesBloc, NotesAppSpecificOptions> {
NotesApp(super.sharedPreferences); NotesApp();
@override @override
String id = AppIDs.notes; final String id = AppIDs.notes;
@override @override
List<Locale> supportedLocales = AppLocalizations.supportedLocales; final List<Locale> supportedLocales = AppLocalizations.supportedLocales;
@override @override
LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate; final LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate;
@override @override
NotesAppSpecificOptions buildOptions(final AppStorage storage) => NotesAppSpecificOptions(storage); late final NotesAppSpecificOptions options = NotesAppSpecificOptions(storage);
@override @override
NotesBloc buildBloc(final Account account) => NotesBloc( NotesBloc buildBloc(final Account account) => NotesBloc(
@ -63,8 +63,8 @@ class NotesApp extends AppImplementation<NotesBloc, NotesAppSpecificOptions> {
); );
@override @override
Widget get page => const NotesMainPage(); final Widget page = const NotesMainPage();
@override @override
RouteBase get route => $notesAppRoute; final RouteBase route = $notesAppRoute;
} }

14
packages/neon/neon_notifications/lib/neon_notifications.dart

@ -22,19 +22,19 @@ part 'pages/main.dart';
class NotificationsApp extends AppImplementation<NotificationsBloc, NotificationsAppSpecificOptions> class NotificationsApp extends AppImplementation<NotificationsBloc, NotificationsAppSpecificOptions>
implements NotificationsAppInterface<NotificationsBloc, NotificationsAppSpecificOptions> { implements NotificationsAppInterface<NotificationsBloc, NotificationsAppSpecificOptions> {
NotificationsApp(super.sharedPreferences); NotificationsApp();
@override @override
String id = AppIDs.notifications; final String id = AppIDs.notifications;
@override @override
LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate; final LocalizationsDelegate localizationsDelegate = AppLocalizations.delegate;
@override @override
List<Locale> supportedLocales = AppLocalizations.supportedLocales; final List<Locale> supportedLocales = AppLocalizations.supportedLocales;
@override @override
NotificationsAppSpecificOptions buildOptions(final AppStorage storage) => NotificationsAppSpecificOptions(storage); late final NotificationsAppSpecificOptions options = NotificationsAppSpecificOptions(storage);
@override @override
NotificationsBloc buildBloc(final Account account) => NotificationsBloc( NotificationsBloc buildBloc(final Account account) => NotificationsBloc(
@ -43,10 +43,10 @@ class NotificationsApp extends AppImplementation<NotificationsBloc, Notification
); );
@override @override
Widget get page => const NotificationsMainPage(); final Widget page = const NotificationsMainPage();
@override @override
RouteBase get route => $notificationsAppRoute; final RouteBase route = $notificationsAppRoute;
@override @override
BehaviorSubject<int> getUnreadCounter(final NotificationsBloc bloc) => bloc.unreadCounter; BehaviorSubject<int> getUnreadCounter(final NotificationsBloc bloc) => bloc.unreadCounter;

Loading…
Cancel
Save