mirror of
https://github.com/Iconica-Development/flutter_notification_center.git
synced 2025-05-18 16:43:44 +02:00
refacor: clean up and edit for analysis options
This commit is contained in:
parent
fa3b0f14fe
commit
13e950fc43
14 changed files with 406 additions and 393 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -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
5
example/.gitignore
vendored
|
@ -45,3 +45,8 @@ app.*.map.json
|
|||
|
||||
# iOS related
|
||||
/ios/
|
||||
|
||||
lib/config/
|
||||
pubspec.lock
|
||||
dotenv
|
||||
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue