mirror of
https://github.com/Iconica-Development/flutter_notification_center.git
synced 2025-05-18 16:43:44 +02:00
Merge pull request #3 from Iconica-Development/feat/popup
Add option for snackbar and dialog popups
This commit is contained in:
commit
4b3bcb2d6c
13 changed files with 219 additions and 25 deletions
|
@ -1,3 +1,7 @@
|
|||
## [1.1.0] - 15 April 2024
|
||||
|
||||
* Initial Release
|
||||
|
||||
## [1.0.0] - 14 April 2024
|
||||
|
||||
* Initial Release
|
|
@ -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.
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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: ../
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
),
|
||||
);
|
||||
}
|
|
@ -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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
Loading…
Reference in a new issue