diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e668e3..c23c3c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [1.1.0] - 15 April 2024 + +* Initial Release + ## [1.0.0] - 14 April 2024 * Initial Release \ No newline at end of file diff --git a/README.md b/README.md index 0db415a..d872611 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ A Flutter package for creating notification center displaying a list of notifica - Dismissable notifications: A dismissable notification can be dismissed by the user from the notification center. - Notification detail page: Clicking on a notification takes the user to a notification detail page. - Notification types: Notification types that can be created are: instant, scheduled, recurring. +- Notification popups: If a notification is pushed a popup can appear in form of a dialog or snackbar. ## Setup @@ -23,6 +24,10 @@ The `NotificationConfig` has its own parameters, as specified below: | seperateNotificationsWithDivider | If true notifications will be seperated with dividers within the notification center | | translations | The translations that will be used | | notificationWidgetBuilder | The widget that defines the styles and logic for every notification | +| enableNotificationPopups | If set to false no popups will be shown if a new notification is pushed | +| showAsSnackBar | If true notifications popups will show as snackbar. If false shown as dialog| + +If you set `enableNotificationPopups` to true, you can use `PopupHandler` in the `newNotificationCallback` to display popups in case a new notification is pushed. The `notificationWidgetBuilder` expects the following parameters, as specified below: | Parameter | Explanation | @@ -48,7 +53,6 @@ Create recurring notification: To create a pinned notification, set isPinned = true when creating the notification. - ### Example See [Example Code](example/lib/main.dart) for more info. diff --git a/packages/flutter_notification_center/example/lib/main.dart b/packages/flutter_notification_center/example/lib/main.dart index 60c78b7..b7a96a8 100644 --- a/packages/flutter_notification_center/example/lib/main.dart +++ b/packages/flutter_notification_center/example/lib/main.dart @@ -6,7 +6,6 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:flutter_notification_center_firebase/flutter_notification_center_firebase.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:flutter_notification_center/flutter_notification_center.dart'; -import 'package:provider/provider.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -15,11 +14,8 @@ void main() async { await _signInUser(); runApp( - ChangeNotifierProvider( - create: (_) => FirebaseNotificationService(), - child: const MaterialApp( - home: NotificationCenterDemo(), - ), + const MaterialApp( + home: NotificationCenterDemo(), ), ); } @@ -42,7 +38,7 @@ Future _configureApp() async { } Future _signInUser() async { - //TO DO: Implement your own sign in logic + /// Implement your own sign in logic here } class NotificationCenterDemo extends StatefulWidget { @@ -53,10 +49,20 @@ class NotificationCenterDemo extends StatefulWidget { } class _NotificationCenterDemoState extends State { + late NotificationConfig config; + late PopupHandler popupHandler; + @override - Widget build(BuildContext context) { - var config = NotificationConfig( - service: Provider.of(context), + void initState() { + super.initState(); + var service = + FirebaseNotificationService(newNotificationCallback: (notification) { + popupHandler.handleNotificationPopup(notification); + }); + config = NotificationConfig( + service: service, + enableNotificationPopups: true, + showAsSnackBar: false, notificationWidgetBuilder: (notification, context) => CustomNotificationWidget( notification: notification, @@ -75,13 +81,17 @@ class _NotificationCenterDemoState extends State { isReadDotColor: Colors.red, showNotificationIcon: true, ), - notificationService: Provider.of(context), + notificationService: service, notificationTranslations: const NotificationTranslations(), context: context, ), seperateNotificationsWithDivider: true, ); + popupHandler = PopupHandler(context: context, config: config); + } + @override + Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Notification Center Demo'), diff --git a/packages/flutter_notification_center/example/pubspec.yaml b/packages/flutter_notification_center/example/pubspec.yaml index de3c852..518eb91 100644 --- a/packages/flutter_notification_center/example/pubspec.yaml +++ b/packages/flutter_notification_center/example/pubspec.yaml @@ -24,7 +24,6 @@ dependencies: firebase_auth: ^4.2.6 firebase_core: ^2.5.0 firebase_storage: ^11.0.14 - provider: ^6.1.2 flutter_notification_center: path: ../ diff --git a/packages/flutter_notification_center/lib/flutter_notification_center.dart b/packages/flutter_notification_center/lib/flutter_notification_center.dart index fe636f9..8e84e2f 100644 --- a/packages/flutter_notification_center/lib/flutter_notification_center.dart +++ b/packages/flutter_notification_center/lib/flutter_notification_center.dart @@ -7,6 +7,9 @@ export "src/models/notification_config.dart"; export "src/models/notification_theme.dart"; export "src/models/notification_translation.dart"; export "src/notification_bell.dart"; +export "src/notification_dialog.dart"; +export "src/popup_handler.dart"; +export "src/notification_snackbar.dart"; export "src/notification_detail.dart"; export "src/notification_bell_story.dart"; export "src/notification_center.dart"; diff --git a/packages/flutter_notification_center/lib/src/models/notification_config.dart b/packages/flutter_notification_center/lib/src/models/notification_config.dart index b6e8f94..3bfa40a 100644 --- a/packages/flutter_notification_center/lib/src/models/notification_config.dart +++ b/packages/flutter_notification_center/lib/src/models/notification_config.dart @@ -10,12 +10,13 @@ class NotificationConfig { /// to use. The [style] parameter is optional and defines the style of the /// notification. The [translations] parameter is also optional and provides /// translations for notification messages. - const NotificationConfig({ - required this.service, - this.seperateNotificationsWithDivider = true, - this.translations = const NotificationTranslations(), - this.notificationWidgetBuilder, - }); + const NotificationConfig( + {required this.service, + this.seperateNotificationsWithDivider = true, + this.translations = const NotificationTranslations(), + this.notificationWidgetBuilder, + this.showAsSnackBar = true, + this.enableNotificationPopups = true}); /// The notification service to use for delivering notifications. final NotificationService service; @@ -29,4 +30,10 @@ class NotificationConfig { /// Widget for building each notification item. final Widget Function(NotificationModel, BuildContext)? notificationWidgetBuilder; + + /// Whether to show notifications as snackbars. If false show notifications as a dialog. + final bool showAsSnackBar; + + /// Whether to show notification popups. + final bool enableNotificationPopups; } diff --git a/packages/flutter_notification_center/lib/src/notification_dialog.dart b/packages/flutter_notification_center/lib/src/notification_dialog.dart new file mode 100644 index 0000000..209785c --- /dev/null +++ b/packages/flutter_notification_center/lib/src/notification_dialog.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class NotificationDialog extends StatelessWidget { + final String title; + final String body; + final DateTime? datetimePublished; + + const NotificationDialog({ + super.key, + required this.title, + required this.body, + this.datetimePublished, + }); + + @override + Widget build(BuildContext context) { + String formattedDateTime = datetimePublished != null + ? DateFormat('dd MMM HH:mm').format(datetimePublished!) + : 'N/A'; + + return AlertDialog( + title: Text( + title, + style: const TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + content: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(height: 4), + Text( + body, + style: const TextStyle( + fontSize: 16.0, + color: Colors.black, + ), + ), + const SizedBox(height: 8), + Text( + formattedDateTime, + style: const TextStyle( + fontSize: 16.0, + color: Colors.black, + ), + ), + ], + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text( + 'Dismiss', + style: TextStyle( + color: Colors.red, + ), + ), + ), + ], + ); + } +} diff --git a/packages/flutter_notification_center/lib/src/notification_snackbar.dart b/packages/flutter_notification_center/lib/src/notification_snackbar.dart new file mode 100644 index 0000000..264936d --- /dev/null +++ b/packages/flutter_notification_center/lib/src/notification_snackbar.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class NotificationSnackbar extends SnackBar { + NotificationSnackbar({ + super.key, + required String title, + required String body, + DateTime? datetimePublished, + }) : super( + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: const TextStyle( + fontSize: 20.0, + color: Colors.white, + ), + ), + const SizedBox(height: 4), + Text( + body, + style: const TextStyle( + fontSize: 16.0, + color: Colors.white, + ), + ), + const SizedBox(height: 4), + Text( + datetimePublished != null + ? DateFormat('dd MMM HH:mm').format(datetimePublished) + : 'N/A', + style: const TextStyle( + fontSize: 12.0, + color: Colors.white, + ), + ), + ], + ), + duration: const Duration(seconds: 8), + action: SnackBarAction( + label: 'Dismiss', + onPressed: () {}, + textColor: Colors.white, + ), + ); +} diff --git a/packages/flutter_notification_center/lib/src/popup_handler.dart b/packages/flutter_notification_center/lib/src/popup_handler.dart new file mode 100644 index 0000000..863178f --- /dev/null +++ b/packages/flutter_notification_center/lib/src/popup_handler.dart @@ -0,0 +1,37 @@ +// Define a PopupHandler class to handle notification popups +import 'package:flutter/material.dart'; + +import 'package:flutter_notification_center/flutter_notification_center.dart'; + +class PopupHandler { + final BuildContext context; + final NotificationConfig config; + + PopupHandler({ + required this.context, + required this.config, + }); + + void handleNotificationPopup(NotificationModel notification) { + if (!config.enableNotificationPopups) return; + + if (config.showAsSnackBar) { + ScaffoldMessenger.of(context).showSnackBar( + NotificationSnackbar( + title: notification.title, + body: notification.body, + datetimePublished: DateTime.now(), + ), + ); + } else { + showDialog( + context: context, + builder: (context) => NotificationDialog( + title: notification.title, + body: notification.body, + datetimePublished: notification.dateTimePushed, + ), + ); + } + } +} diff --git a/packages/flutter_notification_center/lib/src/services/notification_service.dart b/packages/flutter_notification_center/lib/src/services/notification_service.dart index 2a7e063..cd92147 100644 --- a/packages/flutter_notification_center/lib/src/services/notification_service.dart +++ b/packages/flutter_notification_center/lib/src/services/notification_service.dart @@ -26,7 +26,8 @@ abstract class NotificationService with ChangeNotifier { List listOfPlannedNotifications; /// Pushes a notification to the service. - Future pushNotification(NotificationModel notification); + Future pushNotification(NotificationModel notification, + [Function(NotificationModel model)? onNewNotification]); /// Retrieves the list of active notifications. Future> getActiveNotifications(); diff --git a/packages/flutter_notification_center_firebase/lib/src/services/firebase_notification_service.dart b/packages/flutter_notification_center_firebase/lib/src/services/firebase_notification_service.dart index 1350723..b2cc09a 100644 --- a/packages/flutter_notification_center_firebase/lib/src/services/firebase_notification_service.dart +++ b/packages/flutter_notification_center_firebase/lib/src/services/firebase_notification_service.dart @@ -8,6 +8,8 @@ import '../config/firebase_collections.dart'; class FirebaseNotificationService with ChangeNotifier implements NotificationService { + final Function(NotificationModel) newNotificationCallback; + @override List listOfActiveNotifications; @override @@ -17,7 +19,8 @@ class FirebaseNotificationService late Timer _timer; FirebaseNotificationService( - {this.listOfActiveNotifications = const [], + {required this.newNotificationCallback, + this.listOfActiveNotifications = const [], this.listOfPlannedNotifications = const []}) { _startTimer(); } @@ -30,7 +33,8 @@ class FirebaseNotificationService } @override - Future pushNotification(NotificationModel notification) async { + Future pushNotification(NotificationModel notification, + [Function(NotificationModel model)? onNewNotification]) async { try { CollectionReference notifications = FirebaseFirestore.instance .collection(FirebaseCollectionNames.activeNotifications); @@ -41,6 +45,14 @@ class FirebaseNotificationService await notifications.doc(notification.id).set(notificationMap); listOfActiveNotifications.add(notification); + + //Show popup with notification conte + if (onNewNotification != null) { + onNewNotification(notification); + } else { + newNotificationCallback(notification); + } + notifyListeners(); } catch (e) { debugPrint('Error creating document: $e'); @@ -191,7 +203,8 @@ class FirebaseNotificationService for (NotificationModel notification in plannedNotifications) { if (notification.scheduledFor!.isBefore(currentTime) || notification.scheduledFor!.isAtSameMomentAs(currentTime)) { - await pushNotification(notification); + await pushNotification(notification, newNotificationCallback); + await deletePlannedNotification(notification); //Plan new recurring notification instance diff --git a/packages/flutter_notification_center_firebase/pubspec.yaml b/packages/flutter_notification_center_firebase/pubspec.yaml index 570d640..bcca28b 100644 --- a/packages/flutter_notification_center_firebase/pubspec.yaml +++ b/packages/flutter_notification_center_firebase/pubspec.yaml @@ -21,7 +21,6 @@ dependencies: firebase_storage: ^11.0.14 cupertino_icons: ^1.0.2 - provider: ^6.1.2 flutter_notification_center: path: ../flutter_notification_center diff --git a/pubspec.yaml b/pubspec.yaml index 983031a..3f2a9d6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ description: "A new Flutter project." # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 1.0.0 +version: 1.1.0 environment: sdk: '>=3.3.2 <4.0.0'