From d3ef21618100fdec73e8cce4c9b30cf23d7f1e6e Mon Sep 17 00:00:00 2001 From: provokateurin Date: Wed, 11 Sep 2024 20:31:35 +0200 Subject: [PATCH] fix(neon_framework): Migrate to notifications_push_repository Signed-off-by: provokateurin --- packages/neon_framework/example/pubspec.lock | 7 + .../example/pubspec_overrides.yaml | 4 +- packages/neon_framework/lib/l10n/en.arb | 5 +- .../lib/l10n/localizations.dart | 18 +- .../lib/l10n/localizations_en.dart | 8 +- packages/neon_framework/lib/neon.dart | 35 ++- packages/neon_framework/lib/src/app.dart | 2 +- .../lib/src/blocs/next_push.dart | 11 +- .../lib/src/blocs/push_notifications.dart | 127 ++--------- .../lib/src/models/push_notification.dart | 63 ------ .../lib/src/models/push_notification.g.dart | 199 ------------------ .../lib/src/pages/settings.dart | 32 +-- .../neon_framework/lib/src/storage/keys.dart | 8 +- .../neon_framework/lib/src/testing/mocks.dart | 1 - .../lib/src/utils/global_options.dart | 60 +----- .../lib/src/utils/global_popups.dart | 4 +- .../lib/src/utils/push_utils.dart | 52 ++--- packages/neon_framework/lib/storage.dart | 1 + .../account_repository/pubspec_overrides.yaml | 4 +- .../dashboard_app/pubspec_overrides.yaml | 4 +- .../packages/files_app/pubspec_overrides.yaml | 4 +- .../packages/news_app/pubspec_overrides.yaml | 4 +- .../packages/notes_app/pubspec_overrides.yaml | 4 +- .../notifications_app/pubspec_overrides.yaml | 4 +- .../packages/talk_app/pubspec_overrides.yaml | 4 +- packages/neon_framework/pubspec.yaml | 7 +- .../neon_framework/pubspec_overrides.yaml | 4 +- 27 files changed, 143 insertions(+), 533 deletions(-) delete mode 100644 packages/neon_framework/lib/src/models/push_notification.dart delete mode 100644 packages/neon_framework/lib/src/models/push_notification.g.dart diff --git a/packages/neon_framework/example/pubspec.lock b/packages/neon_framework/example/pubspec.lock index 942a1a00200..f136da0423b 100644 --- a/packages/neon_framework/example/pubspec.lock +++ b/packages/neon_framework/example/pubspec.lock @@ -878,6 +878,13 @@ packages: relative: true source: path version: "1.0.0" + notifications_push_repository: + dependency: "direct overridden" + description: + path: "../packages/notifications_push_repository" + relative: true + source: path + version: "0.1.0" open_filex: dependency: transitive description: diff --git a/packages/neon_framework/example/pubspec_overrides.yaml b/packages/neon_framework/example/pubspec_overrides.yaml index 54f35f0f5b8..54fec378c9b 100644 --- a/packages/neon_framework/example/pubspec_overrides.yaml +++ b/packages/neon_framework/example/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: cookie_store,dashboard_app,dynamite_runtime,files_app,interceptor_http_client,neon_framework,neon_http_client,neon_lints,news_app,nextcloud,notes_app,notifications_app,sort_box,talk_app +# melos_managed_dependency_overrides: cookie_store,dashboard_app,dynamite_runtime,files_app,interceptor_http_client,neon_framework,neon_http_client,neon_lints,news_app,nextcloud,notes_app,notifications_app,notifications_push_repository,sort_box,talk_app dependency_overrides: cookie_store: path: ../../cookie_store @@ -24,6 +24,8 @@ dependency_overrides: path: ../packages/notes_app notifications_app: path: ../packages/notifications_app + notifications_push_repository: + path: ../packages/notifications_push_repository sort_box: path: ../packages/sort_box talk_app: diff --git a/packages/neon_framework/lib/l10n/en.arb b/packages/neon_framework/lib/l10n/en.arb index 4cdc22f24f7..afea68a2788 100644 --- a/packages/neon_framework/lib/l10n/en.arb +++ b/packages/neon_framework/lib/l10n/en.arb @@ -146,9 +146,8 @@ "globalOptionsThemeOLEDAsDark": "OLED theme as dark theme", "globalOptionsThemeUseNextcloudTheme": "Use Nextcloud theme", "globalOptionsThemeCustomBackground": "Custom background", - "globalOptionsPushNotificationsEnabled": "Enabled", - "globalOptionsPushNotificationsEnabledDisabledNotice": "No UnifiedPush distributor could be found or you denied the permission for showing notifications. Please go to the app settings and allow notifications and go to https://unifiedpush.org/users/distributors and setup any of the listed distributors. Then re-open this app and you should be able to enable notifications", - "globalOptionsPushNotificationsDistributor": "UnifiedPush Distributor", + "globalOptionsPushNotifications": "UnifiedPush", + "globalOptionsPushNotificationsDisabled": "Disabled", "globalOptionsPushNotificationsDistributorGotifyUP": "Gotify-UP (FOSS)", "globalOptionsPushNotificationsDistributorFirebaseEmbedded": "Firebase (proprietary)", "globalOptionsPushNotificationsDistributorNtfy": "ntfy (FOSS)", diff --git a/packages/neon_framework/lib/l10n/localizations.dart b/packages/neon_framework/lib/l10n/localizations.dart index 037e2200da9..802b2f8d04c 100644 --- a/packages/neon_framework/lib/l10n/localizations.dart +++ b/packages/neon_framework/lib/l10n/localizations.dart @@ -559,23 +559,17 @@ abstract class NeonLocalizations { /// **'Custom background'** String get globalOptionsThemeCustomBackground; - /// No description provided for @globalOptionsPushNotificationsEnabled. + /// No description provided for @globalOptionsPushNotifications. /// /// In en, this message translates to: - /// **'Enabled'** - String get globalOptionsPushNotificationsEnabled; + /// **'UnifiedPush'** + String get globalOptionsPushNotifications; - /// No description provided for @globalOptionsPushNotificationsEnabledDisabledNotice. + /// No description provided for @globalOptionsPushNotificationsDisabled. /// /// In en, this message translates to: - /// **'No UnifiedPush distributor could be found or you denied the permission for showing notifications. Please go to the app settings and allow notifications and go to https://unifiedpush.org/users/distributors and setup any of the listed distributors. Then re-open this app and you should be able to enable notifications'** - String get globalOptionsPushNotificationsEnabledDisabledNotice; - - /// No description provided for @globalOptionsPushNotificationsDistributor. - /// - /// In en, this message translates to: - /// **'UnifiedPush Distributor'** - String get globalOptionsPushNotificationsDistributor; + /// **'Disabled'** + String get globalOptionsPushNotificationsDisabled; /// No description provided for @globalOptionsPushNotificationsDistributorGotifyUP. /// diff --git a/packages/neon_framework/lib/l10n/localizations_en.dart b/packages/neon_framework/lib/l10n/localizations_en.dart index 01215946372..adbeda1ceb5 100644 --- a/packages/neon_framework/lib/l10n/localizations_en.dart +++ b/packages/neon_framework/lib/l10n/localizations_en.dart @@ -282,14 +282,10 @@ class NeonLocalizationsEn extends NeonLocalizations { String get globalOptionsThemeCustomBackground => 'Custom background'; @override - String get globalOptionsPushNotificationsEnabled => 'Enabled'; + String get globalOptionsPushNotifications => 'UnifiedPush'; @override - String get globalOptionsPushNotificationsEnabledDisabledNotice => - 'No UnifiedPush distributor could be found or you denied the permission for showing notifications. Please go to the app settings and allow notifications and go to https://unifiedpush.org/users/distributors and setup any of the listed distributors. Then re-open this app and you should be able to enable notifications'; - - @override - String get globalOptionsPushNotificationsDistributor => 'UnifiedPush Distributor'; + String get globalOptionsPushNotificationsDisabled => 'Disabled'; @override String get globalOptionsPushNotificationsDistributorGotifyUP => 'Gotify-UP (FOSS)'; diff --git a/packages/neon_framework/lib/neon.dart b/packages/neon_framework/lib/neon.dart index 03a29b6cb62..23d319d3916 100644 --- a/packages/neon_framework/lib/neon.dart +++ b/packages/neon_framework/lib/neon.dart @@ -5,22 +5,27 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:logging/logging.dart'; +import 'package:neon_framework/models.dart'; import 'package:neon_framework/src/app.dart'; import 'package:neon_framework/src/blocs/accounts.dart'; import 'package:neon_framework/src/blocs/first_launch.dart'; import 'package:neon_framework/src/blocs/next_push.dart'; import 'package:neon_framework/src/blocs/push_notifications.dart'; -import 'package:neon_framework/src/models/app_implementation.dart'; import 'package:neon_framework/src/models/disposable.dart'; import 'package:neon_framework/src/platform/platform.dart'; +import 'package:neon_framework/src/storage/keys.dart'; +import 'package:neon_framework/src/storage/sqlite_persistence.dart'; import 'package:neon_framework/src/theme/neon.dart'; import 'package:neon_framework/src/utils/global_options.dart'; import 'package:neon_framework/src/utils/provider.dart'; +import 'package:neon_framework/src/utils/push_utils.dart'; import 'package:neon_framework/src/utils/timezone.dart'; import 'package:neon_framework/src/utils/user_agent.dart'; import 'package:neon_framework/storage.dart'; +import 'package:notifications_push_repository/notifications_push_repository.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:provider/provider.dart'; +import 'package:rxdart/rxdart.dart'; import 'package:timezone/data/latest.dart' as tzdata; import 'package:timezone/timezone.dart' as tz; @@ -53,19 +58,39 @@ Future runNeon({ final packageInfo = await PackageInfo.fromPlatform(); buildUserAgent(packageInfo); + final notificationsPushStorage = NotificationsPushStorage( + devicePrivateKeyPersistence: NeonStorage().singleValueStore(StorageKeys.notificationsDevicePrivateKey), + pushSubscriptionsPersistence: SQLiteCachedPersistence( + prefix: 'notifications-push-subscriptions', + ), + ); + + // TODO: THIS DOES NOT WORK YET DUE TO A CYCLIC DEPENDENCY, THE ACCOUNT REPOSITORY IS NEEDED + final accountsSubject = BehaviorSubject>.seeded(BuiltList()); + + final notificationsPushRepository = NotificationsPushRepository( + accountsSubject: accountsSubject, + storage: notificationsPushStorage, + onMessage: PushUtils.onMessage, + ); + + final distributors = await notificationsPushRepository.distributors; final globalOptions = GlobalOptions( packageInfo, + distributors, ); - final accountsBloc = AccountsBloc( + PushNotificationsBloc( globalOptions: globalOptions, - allAppImplementations: appImplementations, + notificationsPushRepository: notificationsPushRepository, ); - PushNotificationsBloc( - accountsSubject: accountsBloc.accounts, + final accountsBloc = AccountsBloc( globalOptions: globalOptions, + allAppImplementations: appImplementations, ); + unawaited(accountsBloc.accounts.pipe(accountsSubject)); + final firstLaunchBloc = FirstLaunchBloc(); final nextPushBloc = NextPushBloc( accountsSubject: accountsBloc.accounts, diff --git a/packages/neon_framework/lib/src/app.dart b/packages/neon_framework/lib/src/app.dart index 029807f986d..3917d3e11d4 100644 --- a/packages/neon_framework/lib/src/app.dart +++ b/packages/neon_framework/lib/src/app.dart @@ -14,7 +14,6 @@ import 'package:neon_framework/src/blocs/unified_search.dart'; import 'package:neon_framework/src/models/account.dart'; import 'package:neon_framework/src/models/app_implementation.dart'; import 'package:neon_framework/src/models/notifications_interface.dart'; -import 'package:neon_framework/src/models/push_notification.dart'; import 'package:neon_framework/src/platform/platform.dart'; import 'package:neon_framework/src/router.dart'; import 'package:neon_framework/src/theme/neon.dart'; @@ -28,6 +27,7 @@ import 'package:neon_framework/src/utils/provider.dart'; import 'package:neon_framework/src/utils/push_utils.dart'; import 'package:neon_framework/src/widgets/options_collection_builder.dart'; import 'package:nextcloud/notifications.dart' as notifications; +import 'package:notifications_push_repository/notifications_push_repository.dart'; import 'package:provider/provider.dart'; import 'package:quick_actions/quick_actions.dart'; import 'package:universal_io/io.dart'; diff --git a/packages/neon_framework/lib/src/blocs/next_push.dart b/packages/neon_framework/lib/src/blocs/next_push.dart index b800ec497b2..77e36c8f17f 100644 --- a/packages/neon_framework/lib/src/blocs/next_push.dart +++ b/packages/neon_framework/lib/src/blocs/next_push.dart @@ -33,15 +33,12 @@ class _NextPushBloc extends Bloc implements NextPushBloc { if (disabled) { return; } - changesSubscription = Rx.merge([ - globalOptions.pushNotificationsEnabled.stream, + changesSubscription = Rx.merge([ globalOptions.pushNotificationsDistributor.stream, accountsSubject, - ]).debounceTime(const Duration(milliseconds: 100)).listen((_) async { - if (!globalOptions.pushNotificationsEnabled.enabled || !globalOptions.pushNotificationsEnabled.value) { - return; - } - if (globalOptions.pushNotificationsDistributor.value != null) { + ]).listen((_) async { + final distributor = await globalOptions.pushNotificationsDistributor.stream.first; + if (distributor != null) { return; } if (globalOptions.pushNotificationsDistributor.values.containsKey(unifiedPushNextPushID)) { diff --git a/packages/neon_framework/lib/src/blocs/push_notifications.dart b/packages/neon_framework/lib/src/blocs/push_notifications.dart index 664720e57f2..8dc2c5e00d4 100644 --- a/packages/neon_framework/lib/src/blocs/push_notifications.dart +++ b/packages/neon_framework/lib/src/blocs/push_notifications.dart @@ -1,145 +1,60 @@ import 'dart:async'; -import 'dart:convert'; -import 'package:built_collection/built_collection.dart'; import 'package:logging/logging.dart'; import 'package:meta/meta.dart'; -import 'package:neon_framework/models.dart'; import 'package:neon_framework/src/bloc/bloc.dart'; import 'package:neon_framework/src/platform/platform.dart'; -import 'package:neon_framework/src/storage/keys.dart'; -import 'package:neon_framework/src/utils/findable.dart'; import 'package:neon_framework/src/utils/global_options.dart'; -import 'package:neon_framework/src/utils/push_utils.dart'; -import 'package:neon_framework/storage.dart'; -import 'package:nextcloud/notifications.dart' as notifications; -import 'package:rxdart/rxdart.dart'; -import 'package:unifiedpush/unifiedpush.dart'; +import 'package:notifications_push_repository/notifications_push_repository.dart'; +import 'package:permission_handler/permission_handler.dart'; -/// Bloc for managing push notifications and registration. +/// Bloc for managing push subscriptions. sealed class PushNotificationsBloc { @internal factory PushNotificationsBloc({ - required BehaviorSubject> accountsSubject, required GlobalOptions globalOptions, + required NotificationsPushRepository notificationsPushRepository, }) = _PushNotificationsBloc; } class _PushNotificationsBloc extends Bloc implements PushNotificationsBloc { _PushNotificationsBloc({ - required this.accountsSubject, required this.globalOptions, + required this.notificationsPushRepository, }) { if (NeonPlatform.instance.canUsePushNotifications) { - unawaited(UnifiedPush.getDistributors().then(globalOptions.updateDistributors)); - - globalOptions.pushNotificationsEnabled.addListener(pushNotificationsEnabledListener); - // Call the listener to update everything - unawaited(pushNotificationsEnabledListener()); + unawaited(changeDistributor()); + globalOptions.pushNotificationsDistributor.addListener(changeDistributor); } } @override final log = Logger('PushNotificationsBloc'); - final BehaviorSubject> accountsSubject; - late final storage = NeonStorage().settingsStore(StorageKeys.lastEndpoint); final GlobalOptions globalOptions; - - StreamSubscription>? accountsListener; + final NotificationsPushRepository notificationsPushRepository; + String? oldDistributor; @override void dispose() { - unawaited(accountsListener?.cancel()); - globalOptions.pushNotificationsEnabled.removeListener(pushNotificationsEnabledListener); + globalOptions.pushNotificationsDistributor.removeListener(changeDistributor); } - Future pushNotificationsEnabledListener() async { - if (globalOptions.pushNotificationsEnabled.value) { - await setupUnifiedPush(); - - globalOptions.pushNotificationsDistributor.addListener(distributorListener); - accountsListener = accountsSubject.listen(registerUnifiedPushInstances); - } else { - globalOptions.pushNotificationsDistributor.removeListener(distributorListener); - unawaited(accountsListener?.cancel()); + Future changeDistributor() async { + final newDistributor = globalOptions.pushNotificationsDistributor.value; + if (newDistributor == oldDistributor) { + return; } - } - - Future setupUnifiedPush() async { - // We just use a single RSA keypair for all accounts - final keypair = PushUtils.loadRSAKeypair(); - - await UnifiedPush.initialize( - onNewEndpoint: (endpoint, instance) async { - final account = accountsSubject.value.tryFind(instance); - if (account == null) { - log.fine('Account for $instance not found, can not process endpoint'); - return; - } - - if (storage.getString(account.id) == endpoint) { - log.fine('Endpoint not changed'); - return; - } - - log.fine('Registering account $instance for push notifications on $endpoint'); - - final subscription = await account.client.notifications.push.registerDevice( - $body: notifications.PushRegisterDeviceRequestApplicationJson( - (b) => b - ..pushTokenHash = notifications.generatePushTokenHash(endpoint) - ..devicePublicKey = keypair.publicKey.toFormattedPEM() - ..proxyServer = '$endpoint#', // This is a hack to make the Nextcloud server directly push to the endpoint - ), - ); + oldDistributor = newDistributor; - await storage.setString(account.id, endpoint); + final response = await Permission.notification.request(); + if (!response.isGranted) { + log.fine('Notifications permission denied, disabling push notifications'); - log.fine( - 'Account $instance registered for push notifications ${json.encode(subscription.body.ocs.data.toJson())}', - ); - }, - onMessage: PushUtils.onMessage, - ); - } - - Future distributorListener() async { - final distributor = globalOptions.pushNotificationsDistributor.value; - final disabled = distributor == null; - final sameDistributor = distributor == await UnifiedPush.getDistributor(); - final accounts = accountsSubject.value; - if (disabled || !sameDistributor) { - await unregisterUnifiedPushInstances(accounts); - } - if (!disabled && !sameDistributor) { - log.fine('UnifiedPush distributor changed to $distributor'); - await UnifiedPush.saveDistributor(distributor); + globalOptions.pushNotificationsDistributor.reset(); + return; } - if (!disabled) { - await registerUnifiedPushInstances(accounts); - } - } - Future unregisterUnifiedPushInstances(BuiltList accounts) async { - for (final account in accounts) { - try { - await account.client.notifications.push.removeDevice(); - await UnifiedPush.unregister(account.id); - await storage.remove(account.id); - } on Exception catch (error) { - log.warning( - 'Failed to unregister device.', - error, - ); - } - } - } - - Future registerUnifiedPushInstances(BuiltList accounts) async { - // Notifications will only work on accounts with app password - for (final account in accounts.where((a) => a.password != null)) { - await UnifiedPush.registerApp(account.id); - } + await notificationsPushRepository.changeDistributor(newDistributor); } } diff --git a/packages/neon_framework/lib/src/models/push_notification.dart b/packages/neon_framework/lib/src/models/push_notification.dart deleted file mode 100644 index 1011aa9a720..00000000000 --- a/packages/neon_framework/lib/src/models/push_notification.dart +++ /dev/null @@ -1,63 +0,0 @@ -import 'package:built_value/built_value.dart'; -import 'package:built_value/serializer.dart'; -import 'package:built_value/standard_json_plugin.dart'; -import 'package:crypton/crypton.dart'; -import 'package:meta/meta.dart'; -import 'package:nextcloud/notifications.dart' as notifications; - -part 'push_notification.g.dart'; - -/// Data for a push notification. -@internal -abstract class PushNotification implements Built { - factory PushNotification([void Function(PushNotificationBuilder)? updates]) = _$PushNotification; - - const PushNotification._(); - - /// Creates a new PushNotification object from the given [json] data containing an encrypted [subject]. - /// - /// Use [PushNotification.fromJson] when the [subject] is not encrypted. - factory PushNotification.fromEncrypted( - Map json, - String accountID, - RSAPrivateKey privateKey, - ) { - final subject = notifications.DecryptedSubject.fromEncrypted(privateKey, json['subject'] as String); - - return PushNotification( - (b) => b - ..accountID = accountID - ..priority = json['priority'] as String - ..type = json['type'] as String - ..subject.replace(subject), - ); - } - - /// Creates a new PushNotification object from the given [json] data. - /// - /// Use [PushNotification.fromEncrypted] when you the [subject] is still encrypted. - factory PushNotification.fromJson(Map json) => _serializers.deserializeWith(serializer, json)!; - - /// Parses this object into a json like map. - Map toJson() => _serializers.serializeWith(serializer, this)! as Map; - - static Serializer get serializer => _$pushNotificationSerializer; - - /// The account associated to this notification. - String get accountID; - - /// The priority of the notification. - String get priority; - - /// The type of the notification. - String get type; - - /// The subject of this notification. - notifications.DecryptedSubject get subject; -} - -@SerializersFor([ - PushNotification, - notifications.DecryptedSubject, -]) -final Serializers _serializers = (_$_serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build(); diff --git a/packages/neon_framework/lib/src/models/push_notification.g.dart b/packages/neon_framework/lib/src/models/push_notification.g.dart deleted file mode 100644 index 419fa9c63df..00000000000 --- a/packages/neon_framework/lib/src/models/push_notification.g.dart +++ /dev/null @@ -1,199 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'push_notification.dart'; - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -Serializers _$_serializers = (Serializers().toBuilder() - ..add(notifications.DecryptedSubject.serializer) - ..add(PushNotification.serializer)) - .build(); -Serializer _$pushNotificationSerializer = _$PushNotificationSerializer(); - -class _$PushNotificationSerializer implements StructuredSerializer { - @override - final Iterable types = const [PushNotification, _$PushNotification]; - @override - final String wireName = 'PushNotification'; - - @override - Iterable serialize(Serializers serializers, PushNotification object, - {FullType specifiedType = FullType.unspecified}) { - final result = [ - 'accountID', - serializers.serialize(object.accountID, specifiedType: const FullType(String)), - 'priority', - serializers.serialize(object.priority, specifiedType: const FullType(String)), - 'type', - serializers.serialize(object.type, specifiedType: const FullType(String)), - 'subject', - serializers.serialize(object.subject, specifiedType: const FullType(notifications.DecryptedSubject)), - ]; - - return result; - } - - @override - PushNotification deserialize(Serializers serializers, Iterable serialized, - {FullType specifiedType = FullType.unspecified}) { - final result = PushNotificationBuilder(); - - final iterator = serialized.iterator; - while (iterator.moveNext()) { - final key = iterator.current! as String; - iterator.moveNext(); - final Object? value = iterator.current; - switch (key) { - case 'accountID': - result.accountID = serializers.deserialize(value, specifiedType: const FullType(String))! as String; - break; - case 'priority': - result.priority = serializers.deserialize(value, specifiedType: const FullType(String))! as String; - break; - case 'type': - result.type = serializers.deserialize(value, specifiedType: const FullType(String))! as String; - break; - case 'subject': - result.subject.replace(serializers.deserialize(value, - specifiedType: const FullType(notifications.DecryptedSubject))! as notifications.DecryptedSubject); - break; - } - } - - return result.build(); - } -} - -class _$PushNotification extends PushNotification { - @override - final String accountID; - @override - final String priority; - @override - final String type; - @override - final notifications.DecryptedSubject subject; - - factory _$PushNotification([void Function(PushNotificationBuilder)? updates]) => - (PushNotificationBuilder()..update(updates))._build(); - - _$PushNotification._({required this.accountID, required this.priority, required this.type, required this.subject}) - : super._() { - BuiltValueNullFieldError.checkNotNull(accountID, r'PushNotification', 'accountID'); - BuiltValueNullFieldError.checkNotNull(priority, r'PushNotification', 'priority'); - BuiltValueNullFieldError.checkNotNull(type, r'PushNotification', 'type'); - BuiltValueNullFieldError.checkNotNull(subject, r'PushNotification', 'subject'); - } - - @override - PushNotification rebuild(void Function(PushNotificationBuilder) updates) => (toBuilder()..update(updates)).build(); - - @override - PushNotificationBuilder toBuilder() => PushNotificationBuilder()..replace(this); - - @override - bool operator ==(Object other) { - if (identical(other, this)) return true; - return other is PushNotification && - accountID == other.accountID && - priority == other.priority && - type == other.type && - subject == other.subject; - } - - @override - int get hashCode { - var _$hash = 0; - _$hash = $jc(_$hash, accountID.hashCode); - _$hash = $jc(_$hash, priority.hashCode); - _$hash = $jc(_$hash, type.hashCode); - _$hash = $jc(_$hash, subject.hashCode); - _$hash = $jf(_$hash); - return _$hash; - } - - @override - String toString() { - return (newBuiltValueToStringHelper(r'PushNotification') - ..add('accountID', accountID) - ..add('priority', priority) - ..add('type', type) - ..add('subject', subject)) - .toString(); - } -} - -class PushNotificationBuilder implements Builder { - _$PushNotification? _$v; - - String? _accountID; - String? get accountID => _$this._accountID; - set accountID(String? accountID) => _$this._accountID = accountID; - - String? _priority; - String? get priority => _$this._priority; - set priority(String? priority) => _$this._priority = priority; - - String? _type; - String? get type => _$this._type; - set type(String? type) => _$this._type = type; - - notifications.DecryptedSubjectBuilder? _subject; - notifications.DecryptedSubjectBuilder get subject => _$this._subject ??= notifications.DecryptedSubjectBuilder(); - set subject(notifications.DecryptedSubjectBuilder? subject) => _$this._subject = subject; - - PushNotificationBuilder(); - - PushNotificationBuilder get _$this { - final $v = _$v; - if ($v != null) { - _accountID = $v.accountID; - _priority = $v.priority; - _type = $v.type; - _subject = $v.subject.toBuilder(); - _$v = null; - } - return this; - } - - @override - void replace(PushNotification other) { - ArgumentError.checkNotNull(other, 'other'); - _$v = other as _$PushNotification; - } - - @override - void update(void Function(PushNotificationBuilder)? updates) { - if (updates != null) updates(this); - } - - @override - PushNotification build() => _build(); - - _$PushNotification _build() { - _$PushNotification _$result; - try { - _$result = _$v ?? - _$PushNotification._( - accountID: BuiltValueNullFieldError.checkNotNull(accountID, r'PushNotification', 'accountID'), - priority: BuiltValueNullFieldError.checkNotNull(priority, r'PushNotification', 'priority'), - type: BuiltValueNullFieldError.checkNotNull(type, r'PushNotification', 'type'), - subject: subject.build()); - } catch (_) { - late String _$failedField; - try { - _$failedField = 'subject'; - subject.build(); - } catch (e) { - throw BuiltValueNestedFieldError(r'PushNotification', _$failedField, e.toString()); - } - rethrow; - } - replace(_$result); - return _$result; - } -} - -// ignore_for_file: deprecated_member_use_from_same_package,type=lint diff --git a/packages/neon_framework/lib/src/pages/settings.dart b/packages/neon_framework/lib/src/pages/settings.dart index 81d5c06f0cd..ccbc89401cb 100644 --- a/packages/neon_framework/lib/src/pages/settings.dart +++ b/packages/neon_framework/lib/src/pages/settings.dart @@ -16,7 +16,6 @@ import 'package:neon_framework/src/settings/widgets/option_settings_tile.dart'; import 'package:neon_framework/src/settings/widgets/settings_category.dart'; import 'package:neon_framework/src/settings/widgets/settings_list.dart'; import 'package:neon_framework/src/settings/widgets/settings_tile.dart'; -import 'package:neon_framework/src/settings/widgets/text_settings_tile.dart'; import 'package:neon_framework/src/theme/branding.dart'; import 'package:neon_framework/src/theme/dialog.dart'; import 'package:neon_framework/src/theme/icons.dart'; @@ -314,29 +313,14 @@ class SettingsPage extends StatelessWidget { Widget buildNotificationsCategory(BuildContext context) { final globalOptions = NeonProvider.of(context); - return ValueListenableBuilder( - valueListenable: globalOptions.pushNotificationsEnabled, - builder: (context, _, __) => SettingsCategory( - title: Text(NeonLocalizations.of(context).optionsCategoryPushNotifications), - key: ValueKey(SettingsCategories.pushNotifications.name), - tiles: [ - if (!globalOptions.pushNotificationsEnabled.enabled) - TextSettingsTile( - text: NeonLocalizations.of(context).globalOptionsPushNotificationsEnabledDisabledNotice, - style: TextStyle( - fontWeight: FontWeight.w600, - fontStyle: FontStyle.italic, - color: Theme.of(context).colorScheme.error, - ), - ), - ToggleSettingsTile( - option: globalOptions.pushNotificationsEnabled, - ), - SelectSettingsTile( - option: globalOptions.pushNotificationsDistributor, - ), - ], - ), + return SettingsCategory( + title: Text(NeonLocalizations.of(context).optionsCategoryPushNotifications), + key: ValueKey(SettingsCategories.pushNotifications.name), + tiles: [ + SelectSettingsTile( + option: globalOptions.pushNotificationsDistributor, + ), + ], ); } diff --git a/packages/neon_framework/lib/src/storage/keys.dart b/packages/neon_framework/lib/src/storage/keys.dart index cf80c4c48bd..d4902cb97c8 100644 --- a/packages/neon_framework/lib/src/storage/keys.dart +++ b/packages/neon_framework/lib/src/storage/keys.dart @@ -28,14 +28,14 @@ enum StorageKeys implements Storable { /// The key for the `AccountsBloc` last used account. lastUsedAccount._('last-used-account'), - /// The key used by the `PushNotificationsBloc` to persist the last used endpoint. - lastEndpoint._('last-endpoint'), + /// The key used by the `PushNotificationsBloc` to persist subscriptions. + pushSubscriptions._('push-subscriptions'), /// The key for the `FirstLaunchBloc`. firstLaunch._('first-launch'), - /// The key for the `PushUtils`. - notifications._('notifications'); + /// The key for the storing the device private key used for push notification encryption. + notificationsDevicePrivateKey._('notifications-device-private-key'); const StorageKeys._(this.value); diff --git a/packages/neon_framework/lib/src/testing/mocks.dart b/packages/neon_framework/lib/src/testing/mocks.dart index 779a0b97155..e326b17965b 100644 --- a/packages/neon_framework/lib/src/testing/mocks.dart +++ b/packages/neon_framework/lib/src/testing/mocks.dart @@ -12,7 +12,6 @@ import 'package:neon_framework/src/blocs/accounts.dart'; import 'package:neon_framework/src/models/account_cache.dart'; import 'package:neon_framework/src/models/disposable.dart'; import 'package:neon_framework/src/settings/models/exportable.dart'; -import 'package:neon_framework/src/storage/persistence.dart'; import 'package:neon_framework/src/utils/account_options.dart'; import 'package:neon_framework/storage.dart'; import 'package:nextcloud/provisioning_api.dart' as provisioning_api; diff --git a/packages/neon_framework/lib/src/utils/global_options.dart b/packages/neon_framework/lib/src/utils/global_options.dart index a844099185a..7abcfbca691 100644 --- a/packages/neon_framework/lib/src/utils/global_options.dart +++ b/packages/neon_framework/lib/src/utils/global_options.dart @@ -8,7 +8,6 @@ import 'package:neon_framework/src/settings/models/options_collection.dart'; import 'package:neon_framework/src/storage/keys.dart'; import 'package:neon_framework/storage.dart'; import 'package:package_info_plus/package_info_plus.dart'; -import 'package:permission_handler/permission_handler.dart'; import 'package:universal_io/io.dart'; /// The package id of the NextPush UnifiedPush distributor. @@ -21,8 +20,8 @@ class GlobalOptions extends OptionsCollection { /// Creates a new global options collection. GlobalOptions( this._packageInfo, + this._distributors, ) : super(NeonStorage().settingsStore(StorageKeys.global)) { - pushNotificationsEnabled.addListener(_pushNotificationsEnabledListener); rememberLastUsedAccount.addListener(_rememberLastUsedAccountListener); } @@ -37,21 +36,8 @@ class GlobalOptions extends OptionsCollection { } } - Future _pushNotificationsEnabledListener() async { - if (pushNotificationsEnabled.value) { - final response = await Permission.notification.request(); - if (response.isPermanentlyDenied) { - pushNotificationsEnabled.enabled = false; - } - if (!response.isGranted) { - pushNotificationsEnabled.value = false; - } - } else { - pushNotificationsDistributor.reset(); - } - } - final PackageInfo _packageInfo; + final BuiltList _distributors; late final _distributorsMap = { _packageInfo.packageName: (context) => @@ -74,7 +60,6 @@ class GlobalOptions extends OptionsCollection { themeOLEDAsDark, themeUseNextcloudTheme, themeCustomBackground, - pushNotificationsEnabled, pushNotificationsDistributor, startupMinimized, startupMinimizeInsteadOfExit, @@ -87,7 +72,6 @@ class GlobalOptions extends OptionsCollection { void dispose() { super.dispose(); - pushNotificationsEnabled.removeListener(_pushNotificationsEnabledListener); rememberLastUsedAccount.removeListener(_rememberLastUsedAccountListener); } @@ -102,20 +86,6 @@ class GlobalOptions extends OptionsCollection { ); } - /// Updates the values of [pushNotificationsDistributor]. - /// - /// If the new `distributors` does not contain the currently active one - /// both [pushNotificationsDistributor] and [pushNotificationsEnabled] will be reset. - void updateDistributors(List distributors) { - pushNotificationsDistributor.values = Map.fromEntries( - distributors.map( - (distributor) => MapEntry(distributor, _distributorsMap[distributor] ?? (_) => distributor), - ), - ); - - pushNotificationsEnabled.enabled = pushNotificationsDistributor.values.isNotEmpty; - } - /// The theme mode of the app implementing the Neon framework. late final themeMode = SelectOption( storage: storage, @@ -162,27 +132,16 @@ class GlobalOptions extends OptionsCollection { enabled: themeUseNextcloudTheme, ); - /// Whether to enable the push notifications plugin. - /// - /// Setting this option to true will request the permission to show notifications. - /// Disabling this option will reset [pushNotificationsDistributor]. - /// - /// Defaults to `false`. - late final pushNotificationsEnabled = ToggleOption( - storage: storage, - key: GlobalOptionKeys.pushNotificationsEnabled, - label: (context) => NeonLocalizations.of(context).globalOptionsPushNotificationsEnabled, - defaultValue: false, - ); - /// The registered distributor for push notifications. - late final pushNotificationsDistributor = SelectOption.depend( + late final pushNotificationsDistributor = SelectOption( storage: storage, key: GlobalOptionKeys.pushNotificationsDistributor, - label: (context) => NeonLocalizations.of(context).globalOptionsPushNotificationsDistributor, + label: (context) => NeonLocalizations.of(context).globalOptionsPushNotifications, defaultValue: null, - values: {}, - enabled: pushNotificationsEnabled, + values: { + null: (context) => NeonLocalizations.of(context).globalOptionsPushNotificationsDisabled, + for (final distributor in _distributors) distributor: _distributorsMap[distributor] ?? (_) => distributor, + }, ); /// Whether to start the app minimized. @@ -260,9 +219,6 @@ enum GlobalOptionKeys implements Storable { /// The storage key for [GlobalOptions.themeCustomBackground] themeCustomBackground._('theme-custom-background'), - /// The storage key for [GlobalOptions.pushNotificationsEnabled] - pushNotificationsEnabled._('push-notifications-enabled'), - /// The storage key for [GlobalOptions.pushNotificationsDistributor] pushNotificationsDistributor._('push-notifications-distributor'), diff --git a/packages/neon_framework/lib/src/utils/global_popups.dart b/packages/neon_framework/lib/src/utils/global_popups.dart index 3ed8068e32a..cbeab2cbcc6 100644 --- a/packages/neon_framework/lib/src/utils/global_popups.dart +++ b/packages/neon_framework/lib/src/utils/global_popups.dart @@ -66,7 +66,7 @@ class GlobalPopups { _subscriptions.addAll([ firstLaunchBloc.onFirstLaunch.listen((_) { assert(context.mounted, 'Context should be mounted'); - if (!globalOptions.pushNotificationsEnabled.enabled) { + if (globalOptions.pushNotificationsDistributor.value != null) { return; } @@ -84,7 +84,7 @@ class GlobalPopups { }), nextPushBloc.onNextPushSupported.listen((_) async { assert(context.mounted, 'Context should be mounted'); - if (!globalOptions.pushNotificationsEnabled.enabled) { + if (globalOptions.pushNotificationsDistributor.value != null) { return; } diff --git a/packages/neon_framework/lib/src/utils/push_utils.dart b/packages/neon_framework/lib/src/utils/push_utils.dart index 2f4450ee010..bf599b0512d 100644 --- a/packages/neon_framework/lib/src/utils/push_utils.dart +++ b/packages/neon_framework/lib/src/utils/push_utils.dart @@ -4,7 +4,6 @@ import 'dart:typed_data'; import 'dart:ui'; import 'package:crypto/crypto.dart'; -import 'package:crypton/crypton.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_svg/flutter_svg.dart' show SvgBytesLoader, vg; @@ -15,8 +14,8 @@ import 'package:meta/meta.dart'; import 'package:neon_framework/models.dart'; import 'package:neon_framework/src/bloc/result.dart'; import 'package:neon_framework/src/blocs/accounts.dart'; -import 'package:neon_framework/src/models/push_notification.dart'; import 'package:neon_framework/src/storage/keys.dart'; +import 'package:neon_framework/src/storage/sqlite_persistence.dart'; import 'package:neon_framework/src/theme/colors.dart'; import 'package:neon_framework/src/utils/findable.dart'; import 'package:neon_framework/src/utils/image_utils.dart'; @@ -24,6 +23,7 @@ import 'package:neon_framework/src/utils/localizations.dart'; import 'package:neon_framework/src/utils/request_manager.dart'; import 'package:neon_framework/storage.dart'; import 'package:nextcloud/notifications.dart' as notifications; +import 'package:notifications_push_repository/notifications_push_repository.dart'; import 'package:rxdart/rxdart.dart'; import 'package:timezone/timezone.dart' as tz; @@ -44,25 +44,6 @@ class PushUtils { /// The callback will only be set if the current flutter engine was opened in the foreground. static Future Function(PushNotification notification)? onLocalNotificationClicked; - static RSAKeypair loadRSAKeypair() { - final storage = NeonStorage().settingsStore(StorageKeys.notifications); - const keyDevicePrivateKey = 'device-private-key'; - - final RSAKeypair keypair; - final privateKey = storage.getString(keyDevicePrivateKey); - if (privateKey == null || privateKey.isEmpty) { - _log.fine('Generating RSA keys for push notifications'); - // The key size has to be 2048, other sizes are not accepted by Nextcloud (at the moment at least) - // ignore: avoid_redundant_argument_values - keypair = RSAKeypair.fromRandom(keySize: 2048); - unawaited(storage.setString(keyDevicePrivateKey, keypair.privateKey.toPEM())); - } else { - keypair = RSAKeypair(RSAPrivateKey.fromPEM(privateKey)); - } - - return keypair; - } - static Future initLocalNotifications({ DidReceiveNotificationResponseCallback? onDidReceiveNotificationResponse, }) async { @@ -80,7 +61,7 @@ class PushUtils { return localNotificationsPlugin; } - static Future onMessage(Uint8List messages, String instance) async { + static Future onMessage(Uint8List encryptedPushNotifications, String accountID) async { WidgetsFlutterBinding.ensureInitialized(); final localNotificationsPlugin = await initLocalNotifications( @@ -96,27 +77,26 @@ class PushUtils { ); await NeonStorage().init(); - final keypair = loadRSAKeypair(); - for (final message in Uri(query: utf8.decode(messages)).queryParameters.values) { - final data = json.decode(message) as Map; - final pushNotification = PushNotification.fromEncrypted( - data, - instance, - keypair.privateKey, - ); - + final storage = NotificationsPushStorage( + devicePrivateKeyPersistence: NeonStorage().singleValueStore(StorageKeys.notificationsDevicePrivateKey), + pushSubscriptionsPersistence: SQLiteCachedPersistence( + prefix: 'notifications-push-subscriptions', + ), + ); + final pushNotifications = await parseEncryptedPushNotifications(storage, encryptedPushNotifications, accountID); + for (final pushNotification in pushNotifications) { if (pushNotification.subject.delete ?? false) { - await localNotificationsPlugin.cancel(_getNotificationID(instance, pushNotification)); + await localNotificationsPlugin.cancel(_getNotificationID(accountID, pushNotification)); } else if (pushNotification.subject.deleteAll ?? false) { await localNotificationsPlugin.cancelAll(); - await onPushNotificationReceived?.call(instance); + await onPushNotificationReceived?.call(accountID); } else if (pushNotification.type == 'background') { _log.fine('Got unknown background notification ${json.encode(pushNotification.toJson())}'); } else { final localizations = await appLocalizationsFromSystem(); final accounts = loadAccounts(); - final account = accounts.tryFind(instance); + final account = accounts.tryFind(accountID); notifications.Notification? notification; AndroidBitmap? largeIconBitmap; @@ -156,7 +136,7 @@ class PushUtils { final when = notification != null ? tz.TZDateTime.parse(tz.UTC, notification.datetime) : null; await localNotificationsPlugin.show( - _getNotificationID(instance, pushNotification), + _getNotificationID(accountID, pushNotification), message != null && appName != null ? '$appName: $title' : title, message, NotificationDetails( @@ -181,7 +161,7 @@ class PushUtils { } } - await onPushNotificationReceived?.call(instance); + await onPushNotificationReceived?.call(accountID); } } diff --git a/packages/neon_framework/lib/storage.dart b/packages/neon_framework/lib/storage.dart index 6cf00b16351..3288cd61612 100644 --- a/packages/neon_framework/lib/storage.dart +++ b/packages/neon_framework/lib/storage.dart @@ -4,6 +4,7 @@ library; export 'package:neon_framework/src/storage/keys.dart' show Storable; +export 'package:neon_framework/src/storage/persistence.dart'; export 'package:neon_framework/src/storage/request_cache.dart' show RequestCache; export 'package:neon_framework/src/storage/settings_store.dart' show SettingsStore; export 'package:neon_framework/src/storage/single_value_store.dart' show SingleValueStore; diff --git a/packages/neon_framework/packages/account_repository/pubspec_overrides.yaml b/packages/neon_framework/packages/account_repository/pubspec_overrides.yaml index 5c2f161f46d..807b7b55fe5 100644 --- a/packages/neon_framework/packages/account_repository/pubspec_overrides.yaml +++ b/packages/neon_framework/packages/account_repository/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_framework,neon_http_client,neon_lints,nextcloud,sort_box +# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_framework,neon_http_client,neon_lints,nextcloud,notifications_push_repository,sort_box dependency_overrides: cookie_store: path: ../../../cookie_store @@ -14,5 +14,7 @@ dependency_overrides: path: ../../../neon_lints nextcloud: path: ../../../nextcloud + notifications_push_repository: + path: ../notifications_push_repository sort_box: path: ../sort_box diff --git a/packages/neon_framework/packages/dashboard_app/pubspec_overrides.yaml b/packages/neon_framework/packages/dashboard_app/pubspec_overrides.yaml index 5c2f161f46d..807b7b55fe5 100644 --- a/packages/neon_framework/packages/dashboard_app/pubspec_overrides.yaml +++ b/packages/neon_framework/packages/dashboard_app/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_framework,neon_http_client,neon_lints,nextcloud,sort_box +# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_framework,neon_http_client,neon_lints,nextcloud,notifications_push_repository,sort_box dependency_overrides: cookie_store: path: ../../../cookie_store @@ -14,5 +14,7 @@ dependency_overrides: path: ../../../neon_lints nextcloud: path: ../../../nextcloud + notifications_push_repository: + path: ../notifications_push_repository sort_box: path: ../sort_box diff --git a/packages/neon_framework/packages/files_app/pubspec_overrides.yaml b/packages/neon_framework/packages/files_app/pubspec_overrides.yaml index 5c2f161f46d..807b7b55fe5 100644 --- a/packages/neon_framework/packages/files_app/pubspec_overrides.yaml +++ b/packages/neon_framework/packages/files_app/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_framework,neon_http_client,neon_lints,nextcloud,sort_box +# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_framework,neon_http_client,neon_lints,nextcloud,notifications_push_repository,sort_box dependency_overrides: cookie_store: path: ../../../cookie_store @@ -14,5 +14,7 @@ dependency_overrides: path: ../../../neon_lints nextcloud: path: ../../../nextcloud + notifications_push_repository: + path: ../notifications_push_repository sort_box: path: ../sort_box diff --git a/packages/neon_framework/packages/news_app/pubspec_overrides.yaml b/packages/neon_framework/packages/news_app/pubspec_overrides.yaml index 5c2f161f46d..807b7b55fe5 100644 --- a/packages/neon_framework/packages/news_app/pubspec_overrides.yaml +++ b/packages/neon_framework/packages/news_app/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_framework,neon_http_client,neon_lints,nextcloud,sort_box +# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_framework,neon_http_client,neon_lints,nextcloud,notifications_push_repository,sort_box dependency_overrides: cookie_store: path: ../../../cookie_store @@ -14,5 +14,7 @@ dependency_overrides: path: ../../../neon_lints nextcloud: path: ../../../nextcloud + notifications_push_repository: + path: ../notifications_push_repository sort_box: path: ../sort_box diff --git a/packages/neon_framework/packages/notes_app/pubspec_overrides.yaml b/packages/neon_framework/packages/notes_app/pubspec_overrides.yaml index 5c2f161f46d..807b7b55fe5 100644 --- a/packages/neon_framework/packages/notes_app/pubspec_overrides.yaml +++ b/packages/neon_framework/packages/notes_app/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_framework,neon_http_client,neon_lints,nextcloud,sort_box +# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_framework,neon_http_client,neon_lints,nextcloud,notifications_push_repository,sort_box dependency_overrides: cookie_store: path: ../../../cookie_store @@ -14,5 +14,7 @@ dependency_overrides: path: ../../../neon_lints nextcloud: path: ../../../nextcloud + notifications_push_repository: + path: ../notifications_push_repository sort_box: path: ../sort_box diff --git a/packages/neon_framework/packages/notifications_app/pubspec_overrides.yaml b/packages/neon_framework/packages/notifications_app/pubspec_overrides.yaml index 5c2f161f46d..807b7b55fe5 100644 --- a/packages/neon_framework/packages/notifications_app/pubspec_overrides.yaml +++ b/packages/neon_framework/packages/notifications_app/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_framework,neon_http_client,neon_lints,nextcloud,sort_box +# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_framework,neon_http_client,neon_lints,nextcloud,notifications_push_repository,sort_box dependency_overrides: cookie_store: path: ../../../cookie_store @@ -14,5 +14,7 @@ dependency_overrides: path: ../../../neon_lints nextcloud: path: ../../../nextcloud + notifications_push_repository: + path: ../notifications_push_repository sort_box: path: ../sort_box diff --git a/packages/neon_framework/packages/talk_app/pubspec_overrides.yaml b/packages/neon_framework/packages/talk_app/pubspec_overrides.yaml index 5c2f161f46d..807b7b55fe5 100644 --- a/packages/neon_framework/packages/talk_app/pubspec_overrides.yaml +++ b/packages/neon_framework/packages/talk_app/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_framework,neon_http_client,neon_lints,nextcloud,sort_box +# melos_managed_dependency_overrides: cookie_store,dynamite_runtime,interceptor_http_client,neon_framework,neon_http_client,neon_lints,nextcloud,notifications_push_repository,sort_box dependency_overrides: cookie_store: path: ../../../cookie_store @@ -14,5 +14,7 @@ dependency_overrides: path: ../../../neon_lints nextcloud: path: ../../../nextcloud + notifications_push_repository: + path: ../notifications_push_repository sort_box: path: ../sort_box diff --git a/packages/neon_framework/pubspec.yaml b/packages/neon_framework/pubspec.yaml index f8e0e906d2f..5f803675c94 100644 --- a/packages/neon_framework/pubspec.yaml +++ b/packages/neon_framework/pubspec.yaml @@ -15,7 +15,6 @@ dependencies: url: https://github.com/nextcloud/neon path: packages/cookie_store crypto: ^3.0.0 - crypton: ^2.0.0 cupertino_icons: ^1.0.0 # Do not remove this, is it needed on iOS/macOS. It will not include icons on other platforms because Apple forbids it. dynamic_color: ^1.0.0 dynamite_runtime: ^0.5.0 @@ -44,6 +43,10 @@ dependencies: url: https://github.com/nextcloud/neon path: packages/neon_http_client nextcloud: ^7.0.0 + notifications_push_repository: + git: + url: https://github.com/nextcloud/neon + path: packages/neon_framework/packages/notifications_push_repository package_info_plus: ^8.0.0 path: ^1.0.0 path_provider: ^2.1.0 @@ -61,8 +64,6 @@ dependencies: sqflite_common_ffi: ^2.3.2 sqflite_common_ffi_web: ^0.4.2+3 timezone: ^0.9.4 - unifiedpush: ^5.0.0 - unifiedpush_android: ^2.0.0 universal_io: ^2.0.0 url_launcher: ^6.1.4 vector_graphics: ^1.0.0 diff --git a/packages/neon_framework/pubspec_overrides.yaml b/packages/neon_framework/pubspec_overrides.yaml index 568e695dc68..726f3a81315 100644 --- a/packages/neon_framework/pubspec_overrides.yaml +++ b/packages/neon_framework/pubspec_overrides.yaml @@ -1,4 +1,4 @@ -# melos_managed_dependency_overrides: cookie_store,cookie_store_conformance_tests,dynamite_runtime,interceptor_http_client,neon_http_client,neon_lints,nextcloud,sort_box +# melos_managed_dependency_overrides: cookie_store,cookie_store_conformance_tests,dynamite_runtime,interceptor_http_client,neon_http_client,neon_lints,nextcloud,notifications_push_repository,sort_box dependency_overrides: cookie_store: path: ../cookie_store @@ -14,5 +14,7 @@ dependency_overrides: path: ../neon_lints nextcloud: path: ../nextcloud + notifications_push_repository: + path: packages/notifications_push_repository sort_box: path: packages/sort_box