Skip to content

Commit 7f6cf17

Browse files
authored
Merge pull request #99 from flutter-news-app-full-source-code/feat/In-App-Notification-Persistence
feat(push-notification): persist in-app notifications before sending …
2 parents 451befc + 094e1e2 commit 7f6cf17

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ The API automatically validates the structure of all incoming data, ensuring tha
7474
---
7575

7676
### 📲 Dynamic & Personalized Notifications
77-
A complete, multi-provider notification engine that empowers you to engage users with timely, relevant, and personalized alerts.
78-
- **Editorial-Driven Alerts:** Any piece of content can be designated as "breaking news" from the content dashboard, triggering immediate, high-priority alerts to subscribed users.
77+
A complete, multi-provider notification engine that empowers you to engage users with timely and relevant alerts, seamlessly integrated into their app experience.
78+
- **Editorial-Driven Alerts:** Any piece of content can be designated as "breaking news" from the content dashboard, triggering immediate, high-priority push notifications that are also captured in each user's in-app notification center.
7979
- **User-Crafted Notification Streams:** Users can create and save persistent **Saved Headline Filters** based on any combination of content filters (such as topics, sources, or regions). They can then subscribe to notifications for that filter, receiving alerts only for the news they care about.
8080
- **Flexible Delivery Mechanisms:** The system is architected to support multiple notification types for each subscription, from immediate alerts to scheduled daily or weekly digests.
8181
- **Provider Agnostic:** The engine is built to be provider-agnostic, with out-of-the-box support for Firebase (FCM) and OneSignal. The active provider can be switched remotely without any code changes.

lib/src/config/app_dependencies.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ class AppDependencies {
385385
pushNotificationDeviceRepository: pushNotificationDeviceRepository,
386386
userContentPreferencesRepository: userContentPreferencesRepository,
387387
remoteConfigRepository: remoteConfigRepository,
388+
inAppNotificationRepository: inAppNotificationRepository,
388389
firebaseClient: firebasePushNotificationClient,
389390
oneSignalClient: oneSignalPushNotificationClient,
390391
log: Logger('DefaultPushNotificationService'),

lib/src/services/push_notification_service.dart

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:core/core.dart';
44
import 'package:data_repository/data_repository.dart';
55
import 'package:flutter_news_app_api_server_full_source_code/src/services/push_notification_client.dart';
66
import 'package:logging/logging.dart';
7+
import 'package:mongo_dart/mongo_dart.dart';
78

89
/// An abstract interface for the push notification service.
910
///
@@ -35,12 +36,14 @@ class DefaultPushNotificationService implements IPushNotificationService {
3536
required DataRepository<UserContentPreferences>
3637
userContentPreferencesRepository,
3738
required DataRepository<RemoteConfig> remoteConfigRepository,
39+
required DataRepository<InAppNotification> inAppNotificationRepository,
3840
required IPushNotificationClient? firebaseClient,
3941
required IPushNotificationClient? oneSignalClient,
4042
required Logger log,
4143
}) : _pushNotificationDeviceRepository = pushNotificationDeviceRepository,
4244
_userContentPreferencesRepository = userContentPreferencesRepository,
4345
_remoteConfigRepository = remoteConfigRepository,
46+
_inAppNotificationRepository = inAppNotificationRepository,
4447
_firebaseClient = firebaseClient,
4548
_oneSignalClient = oneSignalClient,
4649
_log = log;
@@ -50,6 +53,7 @@ class DefaultPushNotificationService implements IPushNotificationService {
5053
final DataRepository<UserContentPreferences>
5154
_userContentPreferencesRepository;
5255
final DataRepository<RemoteConfig> _remoteConfigRepository;
56+
final DataRepository<InAppNotification> _inAppNotificationRepository;
5357
final IPushNotificationClient? _firebaseClient;
5458
final IPushNotificationClient? _oneSignalClient;
5559
final Logger _log;
@@ -188,6 +192,35 @@ class DefaultPushNotificationService implements IPushNotificationService {
188192
'Found ${tokens.length} devices to target via $primaryProvider.',
189193
);
190194

195+
// Before sending the push, persist the InAppNotification record for
196+
// each targeted user. This ensures the notification is available in
197+
// their inbox immediately.
198+
try {
199+
final notificationCreationFutures = userIds.map((userId) {
200+
final notification = InAppNotification(
201+
id: ObjectId().oid,
202+
userId: userId,
203+
payload: PushNotificationPayload(
204+
title: headline.title,
205+
body: headline.excerpt,
206+
imageUrl: headline.imageUrl,
207+
data: {
208+
'headlineId': headline.id,
209+
'contentType': 'headline',
210+
'notificationType':
211+
PushNotificationSubscriptionDeliveryType.breakingOnly.name,
212+
},
213+
),
214+
createdAt: DateTime.now(),
215+
);
216+
return _inAppNotificationRepository.create(item: notification);
217+
});
218+
await Future.wait(notificationCreationFutures);
219+
_log.info('Persisted ${userIds.length} in-app notifications.');
220+
} catch (e, s) {
221+
_log.severe('Failed to persist in-app notifications.', e, s);
222+
}
223+
191224
// 7. Construct the notification payload.
192225
final payload = PushNotificationPayload(
193226
title: headline.title,

0 commit comments

Comments
 (0)