Merge remote-tracking branch 'origin/refactor/notification-service' into feat/front_end

This commit is contained in:
Jacques 2024-04-04 14:30:43 +02:00
commit 2ad7ab5028
7 changed files with 268 additions and 81 deletions

View file

@ -18,32 +18,31 @@ class NotificationCenterDemo extends StatefulWidget {
class _NotificationCenterDemoState extends State<NotificationCenterDemo> {
var config = NotificationConfig(
service: NotificationService(
listOfNotifications: [
service: LocalNotificationService(
listOfActiveNotifications: [
NotificationModel(
id: 1,
title: 'Notification title 1',
body: 'Notification body 1',
dateTime: DateTime.now(),
isRead: false,
dateTimePushed: DateTime.now(),
),
NotificationModel(
id: 2,
title: 'RECURRING',
body: 'RECURRING',
dateTime: DateTime.now(),
isRead: false,
isScheduled: true,
dateTimePushed: DateTime.now(),
),
NotificationModel(
id: 3,
title: 'Notification title 2',
body: 'Notification body 2',
dateTime: DateTime.now(),
isRead: false,
dateTimePushed: DateTime.now(),
),
NotificationModel(
id: 4,
title: 'Notification title 3',
body: 'Notification body 3',
dateTime: DateTime.now(),
isRead: false,
dateTimePushed: DateTime.now(),
),
],
),

View file

@ -5,6 +5,7 @@
library notification_center;
export 'package:flutter_notification_center/src/services/notification_service.dart';
export 'package:flutter_notification_center/src/services/local_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';

View file

@ -1,26 +1,32 @@
enum ScheduleType {
minute,
enum OcurringInterval {
daily,
weekly,
monthly,
debug
}
class NotificationModel {
NotificationModel({
this.id,
required this.id,
required this.title,
required this.body,
required this.dateTime,
required this.isRead,
this.isScheduled = false,
this.dateTimePushed,
this.scheduledFor,
this.recurring = false,
this.occuringInterval,
});
int? id;
int id;
String title;
String body;
DateTime dateTime;
bool isRead;
bool isScheduled;
ScheduleType? scheduledFor;
DateTime? dateTimePushed;
DateTime? scheduledFor;
bool recurring;
OcurringInterval? occuringInterval;
// 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}';
}
}

View file

@ -17,13 +17,28 @@ class NotificationBell extends StatefulWidget {
}
class _NotificationBellState extends State<NotificationBell> {
var notificationAmount = 0;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
var amount = await widget.config.service.getActiveNotifications();
setState(() {
notificationAmount = amount.length;
});
});
}
@override
Widget build(BuildContext context) {
return IconButton(
onPressed: widget.onTap,
icon: AnimatedNotificationBell(
duration: const Duration(seconds: 1),
notificationCount: widget.config.service.listOfNotifications.length,
notificationCount: notificationAmount,
notificationIconSize: 45,
),
);

View file

@ -6,8 +6,8 @@ class NotificationCenter extends StatefulWidget {
final NotificationConfig config;
const NotificationCenter({
super.key,
required this.config,
super.key,
});
@override
@ -15,20 +15,16 @@ class NotificationCenter extends StatefulWidget {
}
class _NotificationCenterState extends State<NotificationCenter> {
late List<NotificationModel> listOfNotifications;
late Future<List<NotificationModel>> _notificationsFuture;
@override
void initState() {
super.initState();
listOfNotifications = widget.config.service.getNotifications();
_notificationsFuture = widget.config.service.getActiveNotifications();
}
@override
Widget build(BuildContext context) {
final unreadNotifications = listOfNotifications
.where((notification) => !notification.isRead)
.toList();
return Scaffold(
appBar: AppBar(
title: Text(
@ -43,55 +39,80 @@ class _NotificationCenterState extends State<NotificationCenter> {
},
),
),
body: unreadNotifications.isEmpty
? widget.config.style.emptyNotificationsBuilder?.call() ??
Center(
child: Text(widget.config.translations.appBarTitle),
)
: ListView.builder(
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 {
final unreadNotifications = snapshot.data!.toList();
return ListView.builder(
itemCount: unreadNotifications.length,
itemBuilder: (context, index) {
final notification = unreadNotifications[index];
final formattedDateTime = DateFormat('yyyy-MM-dd HH:mm')
.format(notification.dateTime);
return Container(
decoration: widget.config.style.tileDecoration,
child: ListTile(
title: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
notification.title,
style: widget.config.style.titleTextStyle ??
const TextStyle(),
final formattedDateTime = notification.dateTimePushed != null
? DateFormat('yyyy-MM-dd HH:mm')
.format(notification.dateTimePushed!)
: 'Pending';
return ListTile(
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
notification.title,
style: widget.config.style.titleTextStyle ??
const TextStyle(),
),
Text(
notification.body,
style: widget.config.style.subtitleTextStyle ??
const TextStyle(),
),
Text(
formattedDateTime,
style: const TextStyle(
fontSize: 12,
color: Colors.grey,
),
Text(
notification.body,
style: widget.config.style.subtitleTextStyle ??
const TextStyle(),
),
Text(
formattedDateTime,
style: const TextStyle(
fontSize: 12,
color: Colors.grey,
),
),
],
),
trailing: IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
setState(() {
notification.isRead = true;
});
},
),
),
],
),
trailing: IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
setState(() {
widget.config.service
.dismissActiveNotification(notification);
print('Notification dismissed: $notification');
});
},
),
);
},
),
);
}
},
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await widget.config.service.createRecurringNotification(
NotificationModel(
id: 3,
title: 'HALLO',
body: 'DIT IS DE BODY',
recurring: true,
occuringInterval: OcurringInterval.debug,
scheduledFor: DateTime.now().add(const Duration(seconds: 5))),
);
},
child: const Icon(Icons.add),
),
);
}
}

View file

@ -0,0 +1,136 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_notification_center/src/models/notification.dart';
import 'package:flutter_notification_center/src/services/notification_service.dart';
class LocalNotificationService implements NotificationService {
@override
List<NotificationModel> listOfActiveNotifications;
@override
List<NotificationModel> listOfPlannedNotifications;
late Timer _timer;
LocalNotificationService(
{this.listOfActiveNotifications = const [],
this.listOfPlannedNotifications = const []}) {
_startTimer();
}
void _startTimer() {
_timer = Timer.periodic(const Duration(seconds: 5), (timer) {
debugPrint('Checking for scheduled notifications...');
checkForScheduledNotifications();
});
}
void _cancelTimer() {
_timer.cancel();
}
@override
Future pushNotification(NotificationModel notification) async {
notification.dateTimePushed = DateTime.now();
listOfActiveNotifications.add(notification);
}
@override
Future<List<NotificationModel>> getActiveNotifications() async {
print('Getting all active notifications...');
return listOfActiveNotifications;
}
@override
Future createScheduledNotification(NotificationModel notification) async {
listOfPlannedNotifications = [...listOfPlannedNotifications, notification];
print('Creating scheduled notification: $notification');
}
@override
Future createRecurringNotification(NotificationModel notification) async {
// If recurring, update the scheduled date for the next occurrence
notification.title = notification.id.toString();
await pushNotification(notification);
if (notification.recurring) {
switch (notification.occuringInterval) {
case OcurringInterval.daily:
notification.scheduledFor =
notification.scheduledFor!.add(const Duration(days: 1));
break;
case OcurringInterval.weekly:
notification.scheduledFor =
notification.scheduledFor!.add(const Duration(days: 7));
break;
case OcurringInterval.monthly:
// Add logic for monthly recurrence, e.g., adding 1 month to the scheduled date
break;
case OcurringInterval.debug:
notification.scheduledFor =
notification.scheduledFor!.add(const Duration(seconds: 5));
break;
case null:
// TODO: Handle this case.
}
// Create the next recurring notification
listOfPlannedNotifications = [
...listOfPlannedNotifications,
notification
];
print('Created recurring notification for: ${notification.scheduledFor}');
}
}
@override
Future deleteScheduledNotification(NotificationModel notification) async {
listOfPlannedNotifications =
listOfPlannedNotifications.where((n) => n != notification).toList();
print('Notification deleted: $notification');
}
@override
Future dismissActiveNotification(NotificationModel notification) async {
int id = notification.id;
listOfActiveNotifications.removeWhere((n) => n.id == id);
print('Notification with ID $id dismissed');
print('List of active notifications: $listOfActiveNotifications');
}
@override
Future<void> checkForScheduledNotifications() async {
DateTime currentTime = DateTime.now();
if (listOfPlannedNotifications.isEmpty) {
print('There are no scheduled notifications to be pushed');
return;
}
for (NotificationModel notification
in listOfPlannedNotifications.toList()) {
// Check if scheduledFor is not null
if (notification.scheduledFor != null) {
// Check if the scheduled date and time is before or equal to the current date and time
if (notification.scheduledFor!.isBefore(currentTime) ||
notification.scheduledFor!.isAtSameMomentAs(currentTime)) {
// Push the notification if it's due
await pushNotification(notification);
print('Scheduled notification pushed: $notification');
// If recurring, update the scheduled date for the next occurrence
if (notification.recurring) {
// Increment the ID for recurring notifications
notification.id += 1;
notification.title = notification.id.toString();
print('New RECURRING ID IS: ${notification.id}');
// Create the next recurring notification
await createRecurringNotification(notification);
} else {
// Delete the notification if not recurring
print('Non-recurring notification removed: $notification');
}
}
}
}
}
}

View file

@ -1,15 +1,24 @@
import 'package:flutter_notification_center/src/models/notification.dart';
class NotificationService {
List<NotificationModel> listOfNotifications;
abstract class NotificationService {
List<NotificationModel> listOfActiveNotifications;
List<NotificationModel> listOfPlannedNotifications;
NotificationService({this.listOfNotifications = const []});
NotificationService(
{this.listOfActiveNotifications = const [],
this.listOfPlannedNotifications = const []});
void addNotification(NotificationModel notification) {
listOfNotifications.add(notification);
}
Future pushNotification(NotificationModel notification);
List<NotificationModel> getNotifications() {
return listOfNotifications;
}
Future<List<NotificationModel>> getActiveNotifications();
Future createScheduledNotification(NotificationModel notification);
Future createRecurringNotification(NotificationModel notification);
Future deleteScheduledNotification(NotificationModel notificationId);
Future dismissActiveNotification(NotificationModel notificationId);
Future checkForScheduledNotifications();
}