We are working on a** flutter app **that allow users to schedule a medicine reminder so they can add the name and the dosage,etc…, and the times they want to get notified so we tried to use awesome notification package and implement it but the notifications didn’t come so what we can do ? (we used firebase firestore to store data)
here is a snippet of code for the notification setup :
import 'package:awesome_notifications/awesome_notifications.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fireproject/Medicine_log/models/medicine.dart';
import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
import 'package:fireproject/Medicine_log/models/medicine.dart';
// Notification service class for managing and scheduling notifications.
class NotificationService {
// Firestore instance for fetching medication data.
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
// Variable to keep track of notification IDs.
int _notificationId = 0;
// Constructor to initialize time zones for scheduling.
NotificationService() {
tz.initializeTimeZones();
}
// Method to handle events when a notification is created.
@pragma('vm:entry-point')
static Future<void> onNotificationCreatedMethod(
ReceivedNotification receivedNotification) async {}
// Method to handle events when a notification is displayed.
@pragma('vm:entry-point')
static Future<void> onNotificationsDisplayedMethod(
ReceivedNotification receivedNotification) async {}
// Method to handle events when a notification dismiss action is received.
@pragma('vm:entry-point')
static Future<void> onDismissActionReceivedMethod(
ReceivedAction receivedAction) async {}
// Method to handle events when a user taps on a notification or action button.
@pragma('vm:entry-point')
static Future<void> onActionReceiveMethod(
ReceivedAction receivedAction) async {}
// Method to schedule notifications based on the medicine data.
Future<void> scheduleNotificationsBasedOnMedicine() async {
// Set the timezone location for scheduling.
final location = tz.getLocation('Asia/Amman');
// Fetch all medicines from Firestore.
QuerySnapshot querySnapshot = await _firestore.collection('medicine').get();
for (var doc in querySnapshot.docs) {
Medicine medicine = Medicine.fromFirestore(doc);
// Loop through each reminder time for the medicine.
for (var reminderTimestamp in medicine.reminderTime) {
DateTime utcScheduledTime = reminderTimestamp.toDate();
tz.TZDateTime scheduledTime =
tz.TZDateTime.from(utcScheduledTime, location);
// Schedule the notification.
await AwesomeNotifications().createNotification(
content: NotificationContent(
id: _notificationId++, // Incrementing ID for each notification.
channelKey: 'basic_channel',
title: 'Medicijne Herinnering', // Title for the notification.
body:
'${medicine.dosage} ${medicine.name} innemen.', // Body text for the notification.
),
schedule: NotificationCalendar.fromDate(
date: scheduledTime), // Scheduling details.
);
}
}
}
}
and this is for add reminder page :
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fireproject/notification/notification_serivce.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:intl/intl.dart';
import 'package:fireproject/Medicine_log/models/medicine.dart';
import 'package:fireproject/Medicine_log/widgets/time_input.dart';
import 'package:fireproject/Medicine_log/widgets/medication_card.dart';
import 'package:multi_select_flutter/multi_select_flutter.dart';
import '../widgets/date_selector.dart';
import '../widgets/footer.dart';
import '../widgets/input_style.dart';
import '../services/medication_service.dart';
import 'package:timezone/timezone.dart' as tz;
class medScreen extends StatefulWidget {
final Medicine? medicineToEdit;
const medScreen(
{super.key, this.medicineToEdit}); // Constructor for HomeScreen
@override
State<medScreen> createState() => _HomeScreenState();
}
// FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
// FlutterLocalNotificationsPlugin();
class _HomeScreenState extends State<medScreen> {
final GlobalKey<FormState> _formKey =
GlobalKey<FormState>(); // Form key for validation
final ValueNotifier<int> selectedImageIndexNotifier = ValueNotifier<int>(-1);
final List<String> _allDays = [
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday',
];
// List of image URLs for medication images
List imageUrls = [
'assets/images/—Pngtree—pharmacy drug health tablet pharmaceutical_6861618.png',
'assets/images/black-outlined-bottle.png',
'assets/images/black-outlined-pill.png',
'assets/images/blue-pill.png',
'assets/images/blue-yellow-tablet.png',
'assets/images/colored-bottle.png',
'assets/images/green-pill.png',
'assets/images/orange-tablet.png',
'assets/images/pink-pill.png',
'assets/images/pink-tablet.png',
'assets/images/white-tablet.png',
];
// Controllers for medication input fields
final TextEditingController _medicationNameController =
TextEditingController();
final TextEditingController _quantityController = TextEditingController();
final TextEditingController _doseController = TextEditingController();
List<String> _selectedDays = []; // List to store selected days
List<Timestamp> _reminderTimes = []; // List to store reminder times
String selectedImageUrl = ''; // Selected medication image URL
DateTime _selectedDate = DateTime.now(); // Selected date for medication
// Function to show the medication input form as a bottom sheet
void _showFormBottomSheet() {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (BuildContext context) {
return _buildMedicationFormSheet(context);
},
);
}
// Future<void> _initializeLocalNotifications() async {
// const AndroidInitializationSettings initializationSettingsAndroid =
// AndroidInitializationSettings('app_icon');
// final InitializationSettings initializationSettings =
// InitializationSettings(
// android: initializationSettingsAndroid,
// );
// await flutterLocalNotificationsPlugin.initialize(
// initializationSettings,
// );
// }
// Future<void> _scheduleMedicationNotifications(
// List<Timestamp> reminderTimes) async {
// for (var time in reminderTimes) {
// final dateTime = time.toDate();
// await flutterLocalNotificationsPlugin.zonedSchedule(
// 0,
// 'Medication Reminder',
// 'Time to take your medication',
// tz.TZDateTime.from(dateTime, tz.local),
// const NotificationDetails(
// android: AndroidNotificationDetails(
// 'your channel id',
// 'your channel name',
// importance: Importance.max,
// priority: Priority.high,
// ),
// ),
// androidAllowWhileIdle: true,
// uiLocalNotificationDateInterpretation:
// UILocalNotificationDateInterpretation.absoluteTime,
// );
// }
// }
// Function to update the reminder times
void _updateReminderTime(List<Timestamp> times) {
setState(() {
_reminderTimes = times;
});
}
// Function to update the selected medication image URL
void _updateSelectedImageUrl(int index) {
setState(() {
selectedImageIndexNotifier.value = index;
selectedImageUrl = imageUrls[index];
});
}
// Function to handle date selection
void _onDateSelected(DateTime newDate) {
setState(() {
_selectedDate = newDate;
});
}
@override
void initState() {
// _initializeLocalNotifications();
super.initState();
if (widget.medicineToEdit != null) {
// If editing an existing medicine, populate input fields
_medicationNameController.text = widget.medicineToEdit!.name;
_quantityController.text = widget.medicineToEdit!.amount;
_doseController.text = widget.medicineToEdit!.dosage;
_selectedDays = widget.medicineToEdit!.days;
_reminderTimes = widget.medicineToEdit!.reminderTime;
selectedImageUrl = widget.medicineToEdit!.image;
// Trigger the bottom sheet to show after the build is complete
WidgetsBinding.instance.addPostFrameCallback((_) {
_showFormBottomSheet();
});
}
}
Future<List<Timestamp>> fetchReminderTimesFromFirestore() async {
List<Timestamp> reminderTimes = [];
try {
// Reference to the 'medicine' collection in Firestore
CollectionReference medicineCollection =
FirebaseFirestore.instance.collection('medicine');
// Fetch documents from Firestore
QuerySnapshot querySnapshot = await medicineCollection.get();
// Iterate through each document in the collection
querySnapshot.docs.forEach((doc) {
// Extract reminder times from the document data
List<dynamic> reminderTimesData = doc['reminder_time'];
// Convert dynamic data to Timestamp objects
List<Timestamp> reminderTimesForDocument = reminderTimesData
.map((timeData) => Timestamp.fromMillisecondsSinceEpoch(
timeData.seconds * 1000)) // Convert seconds to milliseconds
.toList();
// Add reminder times to the list
reminderTimes.addAll(reminderTimesForDocument);
});
} catch (e) {
print('Error fetching reminder times: $e');
// Return an empty list or handle the error as per your requirement
}
return reminderTimes;
}
// Function to build the medication input form as a bottom sheet
Widget _buildMedicationFormSheet(BuildContext context) {
return SizedBox(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(left: 20, right: 20, top: 40),
child: Form(
key: _formKey,
child: Column(
children: [
// Header with back button and title
Row(
children: [
IconButton(
icon: const Icon(
Icons.arrow_back_ios,
color: Color(0xffeb6081),
size: 20,
),
onPressed: () {
Navigator.pop(context);
},
constraints: const BoxConstraints(),
),
Expanded(
child: Container(
alignment: Alignment.centerLeft,
child: const Text(
'Schedule your medicine intake',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
color: Color(0xffeb6081),
),
),
),
),
],
),
const SizedBox(height: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Medicine name'),
const SizedBox(
height: 8,
),
// Input field for medication name
inputStyle(
prefixIcon: Icons.medication_rounded,
hintText: 'Ex. panadol',
controller: _medicationNameController,
)
],
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Quantity'),
const SizedBox(height: 8),
// Input field for medication quantity
inputStyle(
prefixIcon: Icons.medical_information,
hintText: '1 pil/tablet',
controller: _quantityController)
],
),
),
const SizedBox(width: 20),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Dosage'),
const SizedBox(
height: 8,
),
// Input field for medication dosage
inputStyle(
prefixIcon: Icons.my_library_add_rounded,
hintText: '500mg/ml',
controller: _doseController),
],
),
),
],
),
const SizedBox(height: 12),
// MultiSelect widget for selecting days
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MultiSelectBottomSheetField(
initialChildSize: 0.7,
maxChildSize: 0.95,
listType: MultiSelectListType.CHIP,
searchable: true,
buttonText: const Text('which days'), // Button text
title: const Text(
'select days to repeat'), // Title for the selection
items: _allDays
.map((day) => MultiSelectItem(day, day))
.toList(),
onConfirm: (values) {
// Callback when days are confirmed
setState(() {
_selectedDays = List<String>.from(values);
});
},
chipDisplay: MultiSelectChipDisplay(
onTap: (value) {
setState(() {
_selectedDays.remove(value);
});
},
),
),
],
),
const SizedBox(height: 12),
// TimeInputWidget for selecting reminder times
TimeInputWidget(
onTimeChanged: _updateReminderTime,
),
const SizedBox(height: 12),
// Medication image selection
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Medicine type'), // Title for medication image
SizedBox(
height: 80,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: imageUrls.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
_updateSelectedImageUrl(
index); // Update the selected image URL
},
child: ValueListenableBuilder<int>(
valueListenable: selectedImageIndexNotifier,
builder: (context, selectedImageIndex, child) {
return Container(
width: 80,
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
),
decoration: BoxDecoration(
border: Border.all(
color: selectedImageIndex == index
? Colors
.blue // Border color when selected
: Colors
.transparent, // No border when not selected
width: 2.0, // Border width
),
),
transform: Matrix4.identity()
..scale(0.8), // Scale down the image
child: Column(
children: [
Expanded(
child: Image.asset(imageUrls[index]),
),
],
),
);
},
),
);
},
),
),
],
),
// Submit button for saving medication
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 8.0),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith<Color>(
(states) => const Color(0xffeb6081), // Button color
),
minimumSize: MaterialStateProperty.resolveWith<Size>(
(states) => Size(
MediaQuery.of(context).size.width * 0.95,
50.0,
),
),
),
onPressed: () async {
if (_formKey.currentState!.validate()) {
// Create or update a Medicine object
Medicine medicine = Medicine(
id: widget.medicineToEdit
?.id, // Use existing ID if in update mode
name: _medicationNameController.text,
dosage: _doseController.text,
image: selectedImageUrl,
days: _selectedDays,
reminderTime: _reminderTimes,
amount: _quantityController.text,
);
MedicationService medicationService =
MedicationService();
try {
if (widget.medicineToEdit == null) {
// Create mode: Save a new medicine
await medicationService.createMedicine(medicine);
if (kDebugMode) {
print('Medicine created successfully');
}
} else {
// Update mode: Update existing medicine
await medicationService.updateMedicine(medicine);
if (kDebugMode) {
print('Medicine updated successfully');
}
}
// Clear input fields and state variables
_medicationNameController.clear();
_doseController.clear();
_quantityController.clear();
_selectedDays.clear();
_reminderTimes.clear();
selectedImageUrl = '';
// _scheduleMedicationNotifications;
Navigator.of(context).pop(); // Close the bottom sheet
} catch (e) {
if (kDebugMode) {
print('Error processing medicine: $e');
}
}
}
},
child: const Text(
'ADD', // Button text
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.normal,
color: Colors.white),
),
),
),
],
),
),
),
),
);
}
@override
Widget build(BuildContext context) {
// Format the selected date for display
String formattedDate =
DateFormat('d MMMM').format(_selectedDate); // Use _selectedDate
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
// Display the DateSelector widget
DateSelector(
formattedDate: formattedDate,
onDateSelected: _onDateSelected, // Set up the callback
),
// Display the MedicationCard widget and pass the selected date
MedicationCard(
selectedDate:
_selectedDate), // Pass the selected date to MedicationCard
],
),
),
bottomNavigationBar: Footer(
onButtonPressed: _showFormBottomSheet, // Show the medication input form
),
);
}
}
Waseem Thiab is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.