Hello Everyone!
Im currently working on our capstone project and I'm having a hard time creating scheduled notification using flutter_local_notification. Do anyone suggest any other package I can use for the scheduled notification on our capstone project?
Schedule Notification
I've tried flutter_local_notifications but it isn't working
btw, this is my code
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:intl/intl.dart';
import 'package:mechanicwho/methods/capitalize_first_letters/capitalize_first_letters.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:rxdart/rxdart.dart';
import 'package:timezone/timezone.dart' as tz;
import 'package:timezone/data/latest.dart' as tz;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mechanicwho/class/app_notification.dart';
final notificationsProvider = StateNotifierProvider.family<
AppNotificationsNotifier, List<AppNotification>, String>(
(ref, username) => AppNotificationsNotifier(username),
);
class AppNotificationsNotifier extends StateNotifier<List<AppNotification>> {
final String username;
AppNotificationsNotifier(this.username) : super([]) {
fetchNotifications();
}
Future<void> fetchNotifications() async {
try {
FirebaseFirestore.instance
.collection('notifications')
.where('username', isEqualTo: username)
.snapshots()
.listen((snapshot) {
final notifications = snapshot.docs.map((doc) {
return AppNotification(
id: doc['id'],
username: doc['username'],
type: doc['type'],
notificationTime: (doc['notificationTime'] as Timestamp).toDate(),
scheduledTime: (doc['scheduledTime'] as Timestamp).toDate(),
status: doc['status'],
location: doc['location'],
isRead: doc['isRead'],
onPressed: (context) {
_getOnPressed(doc['type'])(context);
},
);
}).toList();
// Sort notifications by time
notifications
.sort((a, b) => b.notificationTime.compareTo(a.notificationTime));
state = notifications;
// Schedule reminders for today's notifications
for (var notif in notifications) {
if (notif.type == 'schedule' && _isToday(notif.scheduledTime!)) {
_scheduleDailyReminder(notif);
}
}
});
} catch (e) {
throw Exception('Failed to fetch notifications: $e');
}
}
bool _isToday(DateTime date) {
final now = DateTime.now();
return now.year == date.year &&
now.month == date.month &&
now.day == date.day;
}
void _scheduleDailyReminder(AppNotification notif) async {
try {
final now = tz.TZDateTime.now(tz.local);
final scheduledTime = tz.TZDateTime.from(notif.scheduledTime!, tz.local);
// format the appointment time
String formattedTime = DateFormat('hh:mm a').format(notif.scheduledTime!);
print('Now: $now');
print('Scheduled Time: $scheduledTime');
// schedule notification at 7 AM on the day of the appointment
final tz.TZDateTime sevenAm = tz.TZDateTime(tz.local, scheduledTime.year, scheduledTime.month, scheduledTime.day, 7, 0);
print('7 AM Time: $sevenAm');
// Convert tz.TZDateTime to DateTime for scheduling
if (sevenAm.isAfter(now)) {
await LocalNotifications.showScheduleNotification(
id: int.tryParse('${notif.id}07') ?? 0, // Unique ID for 7 AM notification
title: 'Reminder: Today\'s Appointment',
body:
'You have an appointment today at ${capitalizeFirstLetter(notif.location ?? "")} at $formattedTime.',
scheduledDate: sevenAm.toLocal(), // Convert to DateTime if necessary
);
print('Notification scheduled for 7 AM at: $sevenAm');
} else {
print('7 AM notification is in the past.');
}
// Schedule notification 1 hour before the appointment
final tz.TZDateTime oneHourBefore = scheduledTime.subtract(Duration(hours: 1));
print('1 Hour Before Time: $oneHourBefore');
// Convert tz.TZDateTime to DateTime for scheduling
if (oneHourBefore.isAfter(now)) {
await LocalNotifications.showScheduleNotification(
id: int.tryParse('${notif.id}01') ?? 0, // Unique ID for 1 hour before notification
title: 'Reminder: Appointment in 1 Hour',
body:
'You have an appointment at ${capitalizeFirstLetter(notif.location ?? "")} at $formattedTime.',
scheduledDate: oneHourBefore.toLocal(), // Convert to DateTime if necessary
);
print('Notification scheduled 1 hour before at: $oneHourBefore');
} else {
print('1 hour before notification is in the past.');
}
} catch (e) {
print('Error scheduling reminder: $e');
}
}
void Function(BuildContext) _getOnPressed(String type) {
switch (type) {
case 'complaint':
return _complaintOnPressed;
default:
return _scheduleOnPressed;
}
}
static void _complaintOnPressed(BuildContext context) {
Navigator.pushNamed(context, '/notification_complaint_report');
}
static void _scheduleOnPressed(BuildContext context) {
Navigator.pushNamed(context, '/driver_appointment_details');
}
Future<void> markAsRead(AppNotification notification) async {
try {
final getNotif = await FirebaseFirestore.instance
.collection('notifications')
.where('username', isEqualTo: notification.username)
.where('notificationTime', isEqualTo: notification.notificationTime)
.get();
for (var doc in getNotif.docs) {
await doc.reference.update({'isRead': true});
}
// Update the state to reflect the change
state = state.map((notif) {
if (notif.notificationTime == notification.notificationTime) {
return notification.copyWith(isRead: true);
}
return notif;
}).toList();
} catch (e) {
throw Exception('Failed to mark notification as read: $e');
}
}
}
class LocalNotifications {
static final FlutterLocalNotificationsPlugin
_flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
// Initialize the local notification
static Future<void> init() async {
tz.initializeTimeZones();
tz.setLocalLocation(tz.getLocation('Asia/Manila'));
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
final InitializationSettings initializationSettings =
InitializationSettings(android: initializationSettingsAndroid);
await _flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: onNotificationTap,
onDidReceiveBackgroundNotificationResponse: onNotificationTap,
);
}
// Request notification permission
static Future<void> requestNotificationPermission() async {
print("requestNotificationPermission method called");
bool isGranted = await Permission.notification.isGranted;
print("Permission status before request: $isGranted");
if (isGranted) {
print("Notification permission already granted.");
} else {
PermissionStatus status = await Permission.notification.request();
print("Permission status after request: ${status.isGranted}");
if (status.isGranted) {
print("Notification permission granted.");
} else {
print("Notification permission denied.");
}
}
}
// Schedule the notification
static Future<void> showScheduleNotification({
required int id,
required String title,
required String body,
required DateTime scheduledDate,
String? payload,
}) async {
const NotificationDetails notificationDetails = NotificationDetails(
android: AndroidNotificationDetails(
'appointment_reminder',
'Reminders',
importance: Importance.high,
priority: Priority.high,
),
);
await _flutterLocalNotificationsPlugin.zonedSchedule(
id,
title,
body,
tz.TZDateTime.from(scheduledDate, tz.local),
notificationDetails,
androidAllowWhileIdle: true,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime,
matchDateTimeComponents: DateTimeComponents.time,
payload: payload,
);
}
static void onNotificationTap(NotificationResponse notificationResponse) {
onClickNotification.add(notificationResponse.payload!);
}
static final onClickNotification = BehaviorSubject<String>();
static Future<void> showImmediateNotification({
required int id,
required String title,
required String body,
String? payload,
}) async {
const NotificationDetails notificationDetails = NotificationDetails(
android: AndroidNotificationDetails(
'appointment_reminder',
'Reminders',
importance: Importance.high,
priority: Priority.high,
),
);
await _flutterLocalNotificationsPlugin.show(
id,
title,
body,
notificationDetails,
payload: payload,
);
}
}