Merge pull request #3 from Iconica-Development/feat/popup

Add option for snackbar and dialog popups
This commit is contained in:
Gorter-dev 2024-04-15 14:31:44 +02:00 committed by GitHub
commit 4b3bcb2d6c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 219 additions and 25 deletions

View file

@ -1,3 +1,7 @@
## [1.1.0] - 15 April 2024
* Initial Release
## [1.0.0] - 14 April 2024
* Initial Release

View file

@ -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.

View file

@ -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<void> _configureApp() async {
}
Future<void> _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<NotificationCenterDemo> {
late NotificationConfig config;
late PopupHandler popupHandler;
@override
Widget build(BuildContext context) {
var config = NotificationConfig(
service: Provider.of<FirebaseNotificationService>(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<NotificationCenterDemo> {
isReadDotColor: Colors.red,
showNotificationIcon: true,
),
notificationService: Provider.of<FirebaseNotificationService>(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'),

View file

@ -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: ../

View file

@ -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";

View file

@ -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;
}

View file

@ -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: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text(
'Dismiss',
style: TextStyle(
color: Colors.red,
),
),
),
],
);
}
}

View file

@ -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,
),
);
}

View file

@ -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,
),
);
}
}
}

View file

@ -26,7 +26,8 @@ abstract class NotificationService with ChangeNotifier {
List<NotificationModel> 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<List<NotificationModel>> getActiveNotifications();

View file

@ -8,6 +8,8 @@ import '../config/firebase_collections.dart';
class FirebaseNotificationService
with ChangeNotifier
implements NotificationService {
final Function(NotificationModel) newNotificationCallback;
@override
List<NotificationModel> 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<void> pushNotification(NotificationModel notification) async {
Future<void> 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

View file

@ -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

View file

@ -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'