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

View file

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

View file

@ -1,26 +1,32 @@
enum ScheduleType { enum OcurringInterval {
minute,
daily, daily,
weekly, weekly,
monthly, monthly,
debug
} }
class NotificationModel { class NotificationModel {
NotificationModel({ NotificationModel({
this.id, required this.id,
required this.title, required this.title,
required this.body, required this.body,
required this.dateTime, this.dateTimePushed,
required this.isRead,
this.isScheduled = false,
this.scheduledFor, this.scheduledFor,
this.recurring = false,
this.occuringInterval,
}); });
int? id; int id;
String title; String title;
String body; String body;
DateTime dateTime; DateTime? dateTimePushed;
bool isRead; DateTime? scheduledFor;
bool isScheduled; bool recurring;
ScheduleType? scheduledFor; 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> { 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return IconButton( return IconButton(
onPressed: widget.onTap, onPressed: widget.onTap,
icon: AnimatedNotificationBell( icon: AnimatedNotificationBell(
duration: const Duration(seconds: 1), duration: const Duration(seconds: 1),
notificationCount: widget.config.service.listOfNotifications.length, notificationCount: notificationAmount,
notificationIconSize: 45, notificationIconSize: 45,
), ),
); );

View file

@ -6,8 +6,8 @@ class NotificationCenter extends StatefulWidget {
final NotificationConfig config; final NotificationConfig config;
const NotificationCenter({ const NotificationCenter({
super.key,
required this.config, required this.config,
super.key,
}); });
@override @override
@ -15,20 +15,16 @@ class NotificationCenter extends StatefulWidget {
} }
class _NotificationCenterState extends State<NotificationCenter> { class _NotificationCenterState extends State<NotificationCenter> {
late List<NotificationModel> listOfNotifications; late Future<List<NotificationModel>> _notificationsFuture;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
listOfNotifications = widget.config.service.getNotifications(); _notificationsFuture = widget.config.service.getActiveNotifications();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final unreadNotifications = listOfNotifications
.where((notification) => !notification.isRead)
.toList();
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text( title: Text(
@ -43,55 +39,80 @@ class _NotificationCenterState extends State<NotificationCenter> {
}, },
), ),
), ),
body: unreadNotifications.isEmpty body: FutureBuilder<List<NotificationModel>>(
? widget.config.style.emptyNotificationsBuilder?.call() ?? future: _notificationsFuture,
Center( builder: (context, snapshot) {
child: Text(widget.config.translations.appBarTitle), if (snapshot.connectionState == ConnectionState.waiting) {
) return const Center(child: CircularProgressIndicator());
: ListView.builder( } 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, itemCount: unreadNotifications.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final notification = unreadNotifications[index]; final notification = unreadNotifications[index];
final formattedDateTime = DateFormat('yyyy-MM-dd HH:mm') final formattedDateTime = notification.dateTimePushed != null
.format(notification.dateTime); ? DateFormat('yyyy-MM-dd HH:mm')
return Container( .format(notification.dateTimePushed!)
decoration: widget.config.style.tileDecoration, : 'Pending';
child: ListTile( return ListTile(
title: Column( title: Column(
mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ Text(
Text( notification.title,
notification.title, style: widget.config.style.titleTextStyle ??
style: widget.config.style.titleTextStyle ?? const TextStyle(),
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(), trailing: IconButton(
), icon: const Icon(Icons.clear),
Text( onPressed: () {
formattedDateTime, setState(() {
style: const TextStyle( widget.config.service
fontSize: 12, .dismissActiveNotification(notification);
color: Colors.grey, print('Notification dismissed: $notification');
), });
), },
],
),
trailing: IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
setState(() {
notification.isRead = true;
});
},
),
), ),
); );
}, },
), );
}
},
),
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'; import 'package:flutter_notification_center/src/models/notification.dart';
class NotificationService { abstract class NotificationService {
List<NotificationModel> listOfNotifications; List<NotificationModel> listOfActiveNotifications;
List<NotificationModel> listOfPlannedNotifications;
NotificationService({this.listOfNotifications = const []}); NotificationService(
{this.listOfActiveNotifications = const [],
this.listOfPlannedNotifications = const []});
void addNotification(NotificationModel notification) { Future pushNotification(NotificationModel notification);
listOfNotifications.add(notification);
}
List<NotificationModel> getNotifications() { Future<List<NotificationModel>> getActiveNotifications();
return listOfNotifications;
} Future createScheduledNotification(NotificationModel notification);
Future createRecurringNotification(NotificationModel notification);
Future deleteScheduledNotification(NotificationModel notificationId);
Future dismissActiveNotification(NotificationModel notificationId);
Future checkForScheduledNotifications();
} }