refacor: clean up and edit for analysis options

This commit is contained in:
Vick Top 2024-04-10 15:09:35 +02:00
parent fa3b0f14fe
commit 13e950fc43
14 changed files with 406 additions and 393 deletions

2
.gitignore vendored
View file

@ -43,7 +43,7 @@ app.*.map.json
/android/app/profile
/android/app/release
# iOS related
# Platform-specific files
ios/
android/
web/

5
example/.gitignore vendored
View file

@ -45,3 +45,8 @@ app.*.map.json
# iOS related
/ios/
lib/config/
pubspec.lock
dotenv

View file

@ -68,8 +68,7 @@ class _NotificationCenterDemoState extends State<NotificationCenterDemo> {
@override
Widget build(BuildContext context) {
var config = NotificationConfig(
service: Provider.of<FirebaseNotificationService>(
context), // Use the same instance of FirebaseNotificationService
service: Provider.of<FirebaseNotificationService>(context),
style: const NotificationStyle(
appTitleTextStyle: TextStyle(
color: Colors.black,
@ -77,8 +76,8 @@ class _NotificationCenterDemoState extends State<NotificationCenterDemo> {
),
titleTextStyle: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w500,
fontSize: 20,
fontWeight: FontWeight.w400,
fontSize: 16,
),
),
);

View file

@ -6,7 +6,8 @@ import '../config/firebase_collections.dart';
import 'package:flutter_notification_center/src/models/notification.dart';
import 'package:flutter_notification_center/src/services/notification_service.dart';
class FirebaseNotificationService with ChangeNotifier
class FirebaseNotificationService
with ChangeNotifier
implements NotificationService {
@override
List<NotificationModel> listOfActiveNotifications;
@ -39,11 +40,7 @@ class FirebaseNotificationService with ChangeNotifier
Map<String, dynamic> notificationMap = notification.toMap();
await notifications.doc(notification.id).set(notificationMap);
print('--- Trying to notify listeners ---');
listOfActiveNotifications.add(notification);
listOfActiveNotifications.forEach((notification) {
print('Notification ID: ${notification.id}');
});
notifyListeners();
} catch (e) {
debugPrint('Error creating document: $e');
@ -67,12 +64,7 @@ class FirebaseNotificationService with ChangeNotifier
}).toList();
listOfActiveNotifications = activeNotifications;
print('--- Trying to notify listeners ---');
listOfActiveNotifications.forEach((notification) {
print('Notification ID: ${notification.id}');
});
notifyListeners();
return listOfActiveNotifications;
} catch (e) {
debugPrint('Error getting active notifications: $e');
@ -151,6 +143,9 @@ class FirebaseNotificationService with ChangeNotifier
.collection(FirebaseCollectionNames.active_notifications)
.doc(notificationModel.id);
await documentReference.delete();
listOfActiveNotifications
.removeAt(listOfActiveNotifications.indexOf(notificationModel));
notifyListeners();
} catch (e) {
debugPrint('Error deleting document: $e');
}
@ -164,6 +159,8 @@ class FirebaseNotificationService with ChangeNotifier
.collection(FirebaseCollectionNames.active_notifications)
.doc(notificationModel.id);
await documentReference.update({'isRead': true});
notificationModel.isRead = true;
notifyListeners();
} catch (e) {
debugPrint('Error updating document: $e');
}

View file

@ -2,13 +2,11 @@
//
// SPDX-License-Identifier: BSD-3-Clause
library notification_center;
export 'package:flutter_notification_center/src/services/notification_service.dart';
export 'package:flutter_notification_center/src/notification_center.dart';
export 'package:flutter_notification_center/src/models/notification.dart';
export 'package:flutter_notification_center/src/models/notification_theme.dart';
export 'package:flutter_notification_center/src/models/notification_config.dart';
export 'package:flutter_notification_center/src/models/notification_translation.dart';
export 'package:flutter_notification_center/src/notification_bell.dart';
export 'package:flutter_notification_center/src/notification_bell_story.dart';
export "package:flutter_notification_center/src/models/notification.dart";
export "package:flutter_notification_center/src/models/notification_config.dart";
export "package:flutter_notification_center/src/models/notification_theme.dart";
export "package:flutter_notification_center/src/models/notification_translation.dart";
export "package:flutter_notification_center/src/notification_bell.dart";
export "package:flutter_notification_center/src/notification_bell_story.dart";
export "package:flutter_notification_center/src/notification_center.dart";
export "package:flutter_notification_center/src/services/notification_service.dart";

View file

@ -1,4 +1,4 @@
import 'package:flutter/material.dart';
import "package:flutter/material.dart";
/// Enum representing the interval at which notifications occur.
enum OcurringInterval {
@ -17,6 +17,52 @@ enum OcurringInterval {
/// Model class representing a notification.
class NotificationModel {
/// Constructs a new NotificationModel instance.
///
/// [id]: Unique identifier for the notification.
/// [title]: Title of the notification.
/// [body]: Body content of the notification.
/// [dateTimePushed]: Date and time when the notification was pushed.
/// [scheduledFor]: Date and time when the notification is scheduled for.
/// [recurring]: Indicates if the notification is recurring.
/// [occuringInterval]: Interval at which the notification occurs,
/// applicable if it's recurring.
/// [isPinned]: Indicates if the notification is pinned.
/// [isRead]: Indicates if the notification has been read.
NotificationModel({
required this.id,
required this.title,
required this.body,
this.dateTimePushed,
this.scheduledFor,
this.recurring = false,
this.occuringInterval,
this.isPinned = false,
this.isRead = false,
this.icon = Icons.notifications,
});
/// Method to create a NotificationModel object from JSON data
NotificationModel.fromJson(Map<String, dynamic> json)
: id = json["id"],
title = json["title"],
body = json["body"],
dateTimePushed = json["dateTimePushed"] != null
? DateTime.parse(json["dateTimePushed"])
: null,
scheduledFor = json["scheduledFor"] != null
? DateTime.parse(json["scheduledFor"])
: null,
recurring = json["recurring"] ?? false,
occuringInterval = json["occuringInterval"] != null
? OcurringInterval.values[json["occuringInterval"]]
: null,
isPinned = json["isPinned"] ?? false,
isRead = json["isRead"] ?? false,
icon = json["icon"] != null
? IconData(json["icon"], fontFamily: Icons.notifications.fontFamily)
: Icons.notifications;
/// Unique identifier for the notification.
final String id;
@ -42,80 +88,31 @@ class NotificationModel {
final bool isPinned;
/// Indicates if the notification has been read.
final bool isRead;
bool isRead;
/// Icon to be displayed with the notification.
final IconData icon;
/// Constructs a new NotificationModel instance.
///
/// [id]: Unique identifier for the notification.
/// [title]: Title of the notification.
/// [body]: Body content of the notification.
/// [dateTimePushed]: Date and time when the notification was pushed.
/// [scheduledFor]: Date and time when the notification is scheduled for.
/// [recurring]: Indicates if the notification is recurring.
/// [occuringInterval]: Interval at which the notification occurs, applicable if it's recurring.
/// [isPinned]: Indicates if the notification is pinned.
/// [isRead]: Indicates if the notification has been read.
NotificationModel({
required this.id,
required this.title,
required this.body,
this.dateTimePushed,
this.scheduledFor,
this.recurring = false,
this.occuringInterval,
this.isPinned = false,
this.isRead = false,
this.icon = Icons.notifications,
});
/// Override toString() to provide custom string representation
@override
String toString() {
return 'NotificationModel{id: $id, title: $title, body: $body, dateTimePushed: $dateTimePushed, scheduledFor: $scheduledFor, recurring: $recurring, occuringInterval: $occuringInterval, isPinned: $isPinned, icon: $icon}';
}
/// Method to create a NotificationModel object from JSON data
static NotificationModel fromJson(Map<String, dynamic> json) {
return NotificationModel(
id: json['id'],
title: json['title'],
body: json['body'],
dateTimePushed: json['dateTimePushed'] != null
? DateTime.parse(json['dateTimePushed'])
: null,
scheduledFor: json['scheduledFor'] != null
? DateTime.parse(json['scheduledFor'])
: null,
recurring: json['recurring'] ?? false,
occuringInterval: json['occuringInterval'] != null
? OcurringInterval.values[json['occuringInterval']]
: null,
isPinned: json['isPinned'] ?? false,
isRead: json['isRead'] ?? false,
icon: json['icon'] != null
? IconData(json['icon'], fontFamily: Icons.notifications.fontFamily)
: Icons.notifications,
);
}
String toString() => "NotificationModel{id: $id, title: $title, body: $body, "
"dateTimePushed: $dateTimePushed, scheduledFor: $scheduledFor, "
"recurring: $recurring, occuringInterval: $occuringInterval, "
"isPinned: $isPinned, icon: $icon}";
/// Convert the NotificationModel object to a Map.
Map<String, dynamic> toMap() {
return {
'id': id,
'title': title,
'body': body,
'dateTimePushed': dateTimePushed?.toIso8601String(),
'scheduledFor': scheduledFor?.toIso8601String(),
'recurring': recurring,
'occuringInterval': occuringInterval?.index,
'isPinned': isPinned,
'isRead': isRead,
'icon': icon.codePoint,
};
}
Map<String, dynamic> toMap() => {
"id": id,
"title": title,
"body": body,
"dateTimePushed": dateTimePushed?.toIso8601String(),
"scheduledFor": scheduledFor?.toIso8601String(),
"recurring": recurring,
"occuringInterval": occuringInterval?.index,
"isPinned": isPinned,
"isRead": isRead,
"icon": icon.codePoint,
};
/// Create a copy of the NotificationModel with some fields replaced.
NotificationModel copyWith({
@ -129,18 +126,17 @@ class NotificationModel {
bool? isPinned,
bool? isRead,
IconData? icon,
}) {
return NotificationModel(
id: id ?? this.id,
title: title ?? this.title,
body: body ?? this.body,
dateTimePushed: dateTimePushed ?? this.dateTimePushed,
scheduledFor: scheduledFor ?? this.scheduledFor,
recurring: recurring ?? this.recurring,
occuringInterval: occuringInterval ?? this.occuringInterval,
isPinned: isPinned ?? this.isPinned,
isRead: isRead ?? this.isRead,
icon: icon ?? this.icon,
);
}
}) =>
NotificationModel(
id: id ?? this.id,
title: title ?? this.title,
body: body ?? this.body,
dateTimePushed: dateTimePushed ?? this.dateTimePushed,
scheduledFor: scheduledFor ?? this.scheduledFor,
recurring: recurring ?? this.recurring,
occuringInterval: occuringInterval ?? this.occuringInterval,
isPinned: isPinned ?? this.isPinned,
isRead: isRead ?? this.isRead,
icon: icon ?? this.icon,
);
}

View file

@ -1,17 +1,7 @@
import 'package:flutter_notification_center/flutter_notification_center.dart';
import 'package:flutter_notification_center/src/models/notification_translation.dart';
import "package:flutter_notification_center/flutter_notification_center.dart";
/// Configuration class for notifications.
class NotificationConfig {
/// The notification service to use for delivering notifications.
final NotificationService service;
/// The style of the notification.
final NotificationStyle style;
/// Translations for notification messages.
final NotificationTranslations translations;
/// Creates a new [NotificationConfig] instance.
///
/// The [service] parameter is required and specifies the notification service
@ -23,4 +13,13 @@ class NotificationConfig {
this.style = const NotificationStyle(),
this.translations = const NotificationTranslations(),
});
/// The notification service to use for delivering notifications.
final NotificationService service;
/// The style of the notification.
final NotificationStyle style;
/// Translations for notification messages.
final NotificationTranslations translations;
}

View file

@ -1,7 +1,28 @@
import 'package:flutter/material.dart';
import "package:flutter/material.dart";
/// Defines the appearance customization for notifications.
class NotificationStyle {
/// Creates a new [NotificationStyle] instance.
///
/// Each parameter is optional and allows customizing various aspects
/// of the notification appearance.
const NotificationStyle({
this.titleTextStyle,
this.subtitleTextStyle,
this.backgroundColor,
this.leadingIconColor,
this.trailingIconColor,
this.contentPadding,
this.titleTextAlign,
this.subtitleTextAlign,
this.dense,
this.tileDecoration,
this.emptyNotificationsBuilder,
this.appTitleTextStyle,
this.dividerColor,
this.isReadDotColor,
});
/// The text style for the title of the notification.
final TextStyle? titleTextStyle;
@ -38,22 +59,9 @@ class NotificationStyle {
/// The text style for the application title.
final TextStyle? appTitleTextStyle;
/// Creates a new [NotificationStyle] instance.
///
/// Each parameter is optional and allows customizing various aspects
/// of the notification appearance.
const NotificationStyle({
this.titleTextStyle,
this.subtitleTextStyle,
this.backgroundColor,
this.leadingIconColor,
this.trailingIconColor,
this.contentPadding,
this.titleTextAlign,
this.subtitleTextAlign,
this.dense,
this.tileDecoration,
this.emptyNotificationsBuilder,
this.appTitleTextStyle,
});
/// The color of the divider.
final Color? dividerColor;
/// The color of the dot indicating if the notification is read.
final Color? isReadDotColor;
}

View file

@ -1,21 +1,23 @@
/// Defines translations for notification messages.
class NotificationTranslations {
/// The title to be displayed in the app bar of the notification center.
final String appBarTitle;
/// The message to be displayed when there are no unread notifications available.
final String noNotifications;
/// Creates a new [NotificationTranslations] instance.
///
/// The [appBarTitle] parameter specifies the title to be displayed in the
/// app bar of the notification center. The default value is 'Notification Center'.
/// app bar of the notification center. The default value
/// is 'Notification Center'.
///
/// The [noNotifications] parameter specifies the message to be displayed when
/// there are no unread notifications available. The default value is
/// 'No unread notifications available.'.
const NotificationTranslations({
this.appBarTitle = 'Notification Center',
this.noNotifications = 'No unread notifications available.',
this.appBarTitle = "Notification Center",
this.noNotifications = "No unread notifications available.",
});
/// The title to be displayed in the app bar of the notification center.
final String appBarTitle;
/// The message to be displayed when there are no unread
/// notifications available.
final String noNotifications;
}

View file

@ -1,15 +1,30 @@
import 'package:flutter/material.dart';
import 'package:flutter_animated_widgets/flutter_animated_widgets.dart';
import 'package:flutter_notification_center/flutter_notification_center.dart';
import "package:flutter/material.dart";
import "package:flutter_animated_widgets/flutter_animated_widgets.dart";
import "package:flutter_notification_center/flutter_notification_center.dart";
/// A bell icon widget that displays the number of active notifications.
///
/// This widget displays a bell icon with an animation indicating the number
/// of active notifications. It interacts with the notification service provided
/// in the [config] to fetch the active notifications and update its display
/// accordingly.
class NotificationBell extends StatefulWidget {
/// Constructs a NotificationBell widget.
///
/// [config]: The notification configuration used to interact with the
/// notification service.
/// [onTap]: Callback function to be invoked when the bell icon is tapped.
const NotificationBell({
required this.config,
this.onTap,
super.key,
});
/// The notification configuration used to interact with
/// the notification service.
final NotificationConfig config;
/// Callback function to be invoked when the bell icon is tapped.
final VoidCallback? onTap;
@override
@ -17,12 +32,14 @@ class NotificationBell extends StatefulWidget {
}
class _NotificationBellState extends State<NotificationBell> {
var notificationAmount = 0;
/// The number of active notifications.
int notificationAmount = 0;
@override
void initState() {
super.initState();
// Fetch active notifications and update the notification count
WidgetsBinding.instance.addPostFrameCallback((_) async {
var amount = await widget.config.service.getActiveNotifications();
@ -33,14 +50,12 @@ class _NotificationBellState extends State<NotificationBell> {
}
@override
Widget build(BuildContext context) {
return IconButton(
onPressed: widget.onTap,
icon: AnimatedNotificationBell(
duration: const Duration(seconds: 1),
notificationCount: notificationAmount,
notificationIconSize: 45,
),
);
}
Widget build(BuildContext context) => IconButton(
onPressed: widget.onTap,
icon: AnimatedNotificationBell(
duration: const Duration(seconds: 1),
notificationCount: notificationAmount,
notificationIconSize: 45,
),
);
}

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_notification_center/flutter_notification_center.dart';
import "package:flutter/material.dart";
import "package:flutter_notification_center/flutter_notification_center.dart";
/// A widget representing a notification bell.
class NotificationBellWidgetStory extends StatelessWidget {
@ -8,25 +8,23 @@ class NotificationBellWidgetStory extends StatelessWidget {
/// The [config] parameter specifies the notification configuration.
const NotificationBellWidgetStory({
required this.config,
Key? key,
}) : super(key: key);
super.key,
});
/// The notification configuration.
final NotificationConfig config;
@override
Widget build(BuildContext context) {
return NotificationBell(
config: config,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => NotificationCenter(
config: config,
Widget build(BuildContext context) => NotificationBell(
config: config,
onTap: () async {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => NotificationCenter(
config: config,
),
),
),
);
},
);
}
);
},
);
}

View file

@ -1,199 +1,193 @@
import 'package:flutter/material.dart';
import 'package:flutter_notification_center/flutter_notification_center.dart';
import 'package:flutter_notification_center/src/notification_detail.dart';
import 'package:intl/intl.dart';
import "package:flutter/material.dart";
import "package:flutter_notification_center/flutter_notification_center.dart";
import "package:flutter_notification_center/src/notification_detail.dart";
/// Widget for displaying the notification center.
class NotificationCenter extends StatefulWidget {
/// Configuration for the notification center.
final NotificationConfig config;
/// Constructs a new NotificationCenter instance.
///
/// [config]: Configuration for the notification center.
const NotificationCenter({
required this.config,
Key? key,
}) : super(key: key);
super.key,
});
/// Configuration for the notification center.
final NotificationConfig config;
@override
_NotificationCenterState createState() => _NotificationCenterState();
NotificationCenterState createState() => NotificationCenterState();
}
class _NotificationCenterState extends State<NotificationCenter> {
/// State for the notification center.
class NotificationCenterState extends State<NotificationCenter> {
late Future<List<NotificationModel>> _notificationsFuture;
@override
void initState() {
super.initState();
// ignore: discarded_futures
_notificationsFuture = widget.config.service.getActiveNotifications();
widget.config.service.addListener(_listener);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.config.translations.appBarTitle,
style: widget.config.style.appTitleTextStyle,
void dispose() {
widget.config.service.removeListener(_listener);
super.dispose();
}
void _listener() {
setState(() {});
}
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: Text(
widget.config.translations.appBarTitle,
style: widget.config.style.appTitleTextStyle,
),
centerTitle: true,
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
},
),
),
centerTitle: true,
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
},
),
),
body: FutureBuilder<List<NotificationModel>>(
future: _notificationsFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else if (snapshot.data == null || snapshot.data!.isEmpty) {
return const Center(
child: Text('No unread notifications available.'));
} else {
return ListView.builder(
itemCount: snapshot.data!.length,
body: FutureBuilder<List<NotificationModel>>(
future: _notificationsFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text("Error: ${snapshot.error}"));
} else if (snapshot.data == null || snapshot.data!.isEmpty) {
return const Center(
child: Text("No unread notifications available."),
);
} else {
return ListView.builder(
itemCount: snapshot.data!.length * 2 -
1, // Double the itemCount to include dividers
itemBuilder: (context, index) {
final notification = snapshot.data![index];
final formattedDateTime = notification.dateTimePushed != null
? DateFormat('yyyy-MM-dd HH:mm')
.format(notification.dateTimePushed!)
: 'Pending';
return notification.isPinned
? GestureDetector(
onTap: () =>
_navigateToNotificationDetail(notification),
child: Container(
if (index.isOdd) {
// If index is odd, return a Divider with padding
return const Padding(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: Divider(
color: Colors.grey, // Customize as needed
thickness: 1.0, // Customize thickness as needed
),
);
}
var notification = snapshot.data![index ~/ 2];
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: notification.isPinned
? GestureDetector(
onTap: () async =>
_navigateToNotificationDetail(notification),
child: ListTile(
leading: Icon(notification.icon,
color: widget.config.style.leadingIconColor),
title: _buildNotificationTitle(notification.title,
widget.config.style.titleTextStyle),
subtitle: _buildNotificationSubtitle(
notification.body,
formattedDateTime,
notification.isRead),
leading: Icon(
notification.icon,
color: widget.config.style.leadingIconColor,
),
title: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
notification.title,
style: widget.config.style.titleTextStyle,
),
),
],
),
trailing: IconButton(
icon: const Icon(Icons.push_pin),
color: widget.config.style.trailingIconColor,
onPressed: () =>
onPressed: () async =>
_navigateToNotificationDetail(notification),
),
),
),
)
: Dismissible(
key: Key(notification.id),
onDismissed: (direction) {
setState(() {
widget.config.service
)
: Dismissible(
key: Key(notification.id),
onDismissed: (direction) async {
await widget.config.service
.dismissActiveNotification(notification);
_refreshNotifications();
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Notification dismissed'),
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Notification dismissed"),
),
);
},
background: Container(
color: Colors.red,
alignment: Alignment.centerRight,
child: const Icon(
Icons.delete,
color: Colors.white,
),
);
},
background: Container(
color: Colors.red,
alignment: Alignment.centerRight,
child: Icon(
Icons.delete,
color: Colors.white,
),
),
child: GestureDetector(
onTap: () =>
_navigateToNotificationDetail(notification),
child: Container(
child: GestureDetector(
onTap: () async =>
_navigateToNotificationDetail(notification),
child: ListTile(
leading: Icon(
Icons.notification_important,
color: widget.config.style.leadingIconColor,
),
title: _buildNotificationTitle(
notification.title,
widget.config.style.titleTextStyle),
subtitle: _buildNotificationSubtitle(
notification.body,
formattedDateTime,
notification.isRead),
title: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
notification.title,
style:
widget.config.style.titleTextStyle,
),
),
],
),
trailing: !notification.isRead
? Container(
margin:
const EdgeInsets.only(left: 4.0),
width: 12.0,
height: 12.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: widget.config.style
.isReadDotColor ??
Colors.red,
),
)
: null,
),
),
),
);
});
}
},
),
floatingActionButton: FloatingActionButton(
onPressed: _addNewNotification,
child: const Icon(Icons.add),
),
);
}
Widget _buildNotificationTitle(String title, TextStyle? textStyle) {
return Text(
title,
style: textStyle ?? const TextStyle(),
);
}
Widget _buildNotificationSubtitle(
String body, String formattedDateTime, bool isRead) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
body,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
Text(
formattedDateTime,
style: const TextStyle(
fontSize: 12,
color: Colors.grey,
),
),
],
),
);
},
);
}
},
),
if (!isRead)
Container(
margin: const EdgeInsets.only(left: 4.0),
width: 12.0,
height: 12.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.red,
),
),
],
);
}
floatingActionButton: FloatingActionButton(
onPressed: _addNewNotification,
child: const Icon(Icons.add),
),
);
void _refreshNotifications() {
setState(() {
_notificationsFuture = widget.config.service.getActiveNotifications();
});
}
void _navigateToNotificationDetail(NotificationModel notification) {
widget.config.service.markNotificationAsRead(notification);
Navigator.push(
Future<void> _navigateToNotificationDetail(
NotificationModel notification,
) async {
await widget.config.service.markNotificationAsRead(notification);
await Navigator.push(
// ignore: use_build_context_synchronously
context,
MaterialPageRoute(
builder: (context) => NotificationDetailPage(
@ -204,16 +198,14 @@ class _NotificationCenterState extends State<NotificationCenter> {
);
}
void _addNewNotification() {
widget.config.service.pushNotification(
Future<void> _addNewNotification() async {
await widget.config.service.pushNotification(
NotificationModel(
id: UniqueKey().toString(),
title: UniqueKey().toString(),
isPinned: true,
icon: Icons.notifications_active,
body: 'This is a new notification',
body: "This is a new notification",
),
);
_refreshNotifications();
}
}

View file

@ -1,63 +1,64 @@
import 'package:flutter/material.dart';
import 'package:flutter_notification_center/flutter_notification_center.dart';
import 'package:intl/intl.dart';
import "package:flutter/material.dart";
import "package:flutter_notification_center/flutter_notification_center.dart";
import "package:intl/intl.dart";
/// A page displaying the details of a notification.
class NotificationDetailPage extends StatelessWidget {
/// Creates a new [NotificationDetailPage] instance.
///
/// The [config] parameter specifies the notification configuration.
///
/// The [notification] parameter specifies the notification
/// to display details for.
const NotificationDetailPage({
required this.config,
required this.notification,
super.key,
});
/// The notification configuration.
final NotificationConfig config;
/// The notification to display details for.
final NotificationModel notification;
/// Creates a new [NotificationDetailPage] instance.
///
/// The [config] parameter specifies the notification configuration.
///
/// The [notification] parameter specifies the notification to display details for.
const NotificationDetailPage({
required this.config,
required this.notification,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
config.translations.appBarTitle,
style: config.style.appTitleTextStyle,
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: Text(
config.translations.appBarTitle,
style: config.style.appTitleTextStyle,
),
centerTitle: true,
),
centerTitle: true,
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
notification.title,
style: config.style.titleTextStyle ?? const TextStyle(),
),
const SizedBox(height: 10),
Text(
notification.body,
style: config.style.subtitleTextStyle ?? const TextStyle(),
),
const SizedBox(height: 10),
Text(
'Date: ${DateFormat('yyyy-MM-dd HH:mm').format(notification.dateTimePushed ?? DateTime.now())}',
style: TextStyle(
fontSize: 12,
color: Colors.grey,
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
notification.title,
style: config.style.titleTextStyle ?? const TextStyle(),
),
),
],
const SizedBox(height: 10),
Text(
notification.body,
style: config.style.subtitleTextStyle ?? const TextStyle(),
),
const SizedBox(height: 10),
Text(
'Date: ${DateFormat('yyyy-MM-dd HH:mm').format(
notification.dateTimePushed ?? DateTime.now(),
)}',
style: const TextStyle(
fontSize: 12,
color: Colors.grey,
),
),
],
),
),
),
),
);
}
);
}

View file

@ -1,27 +1,30 @@
import 'dart:async';
import "dart:async";
import 'package:flutter_notification_center/src/models/notification.dart';
import "package:flutter/material.dart";
import "package:flutter_notification_center/src/models/notification.dart";
/// An abstract class representing a service for managing notifications.
abstract class NotificationService {
/// A list of active notifications.
List<NotificationModel> listOfActiveNotifications;
/// A list of planned notifications.
List<NotificationModel> listOfPlannedNotifications;
abstract class NotificationService with ChangeNotifier {
/// Creates a new [NotificationService] instance.
///
/// The [listOfActiveNotifications] parameter specifies the list of active notifications,
/// The [listOfActiveNotifications] parameter specifies the
/// list of active notifications,
/// with a default value of an empty list.
///
/// The [listOfPlannedNotifications] parameter specifies the list of planned notifications,
/// The [listOfPlannedNotifications] parameter specifies the
/// list of planned notifications,
/// with a default value of an empty list.
NotificationService({
this.listOfActiveNotifications = const [],
this.listOfPlannedNotifications = const [],
});
/// A list of active notifications.
List<NotificationModel> listOfActiveNotifications;
/// A list of planned notifications.
List<NotificationModel> listOfPlannedNotifications;
/// Pushes a notification to the service.
Future pushNotification(NotificationModel notification);