From 19ed1f61b8488cccb6892c6a8422e7e001e01213 Mon Sep 17 00:00:00 2001 From: mehedihasannovi Date: Mon, 2 Sep 2024 22:27:20 +0600 Subject: [PATCH] add notification --- .vscode/launch.json | 2 + android/app/src/debug/AndroidManifest.xml | 4 +- android/app/src/main/AndroidManifest.xml | 6 +- devtools_options.yaml | 1 + .../controllers/fastscreen_controller.dart | 26 +- .../home/controllers/home_controller.dart | 38 +-- lib/app/modules/home/views/home_view.dart | 97 +++--- .../controllers/praytime_controller.dart | 27 +- .../modules/praytime/views/praytime_view.dart | 10 +- .../modules/settings/views/settings_view.dart | 5 +- lib/app/service/backgroundService.dart | 56 --- .../notification/firebasenotification.dart | 104 ++++++ .../service/notification/notification.dart | 323 ++++++------------ lib/main.dart | 21 +- pubspec.lock | 32 ++ pubspec.yaml | 3 +- 16 files changed, 340 insertions(+), 415 deletions(-) delete mode 100644 lib/app/service/backgroundService.dart create mode 100644 lib/app/service/notification/firebasenotification.dart diff --git a/.vscode/launch.json b/.vscode/launch.json index a8e32bc..838d120 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,6 +4,7 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { "name": "ramadanplanner", "request": "launch", @@ -21,5 +22,6 @@ "type": "dart", "flutterMode": "release" } + ] } \ No newline at end of file diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 6e06de0..0de8d4e 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -1,11 +1,11 @@ - + - + diff --git a/devtools_options.yaml b/devtools_options.yaml index fa0b357..2bc8e05 100644 --- a/devtools_options.yaml +++ b/devtools_options.yaml @@ -1,3 +1,4 @@ description: This file stores settings for Dart & Flutter DevTools. documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states extensions: + - provider: true \ No newline at end of file diff --git a/lib/app/modules/fastscreen/controllers/fastscreen_controller.dart b/lib/app/modules/fastscreen/controllers/fastscreen_controller.dart index fe424ef..b146725 100644 --- a/lib/app/modules/fastscreen/controllers/fastscreen_controller.dart +++ b/lib/app/modules/fastscreen/controllers/fastscreen_controller.dart @@ -6,8 +6,11 @@ import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:ramadanplanner/app/model/locationmodel.dart'; import 'package:ramadanplanner/app/routes/app_pages.dart'; +import 'package:ramadanplanner/app/service/notification/firebasenotification.dart'; class FastscreenController extends GetxController { + final FirebaseNotificationService firebasenotificationService = FirebaseNotificationService(); + final TextEditingController name = TextEditingController(); List locationList = []; LocationModel? selectedLocation; @@ -48,16 +51,29 @@ class FastscreenController extends GetxController { } } + screenChange() { + if (Hive.box("user").get("name") != null) { + Get.offAllNamed(Routes.NAVIGATIONBAR); + } + } + @override - void onInit() { - Future.delayed(Duration.zero, () { - if (Hive.box("user").get("name") != null) { - Get.offAllNamed(Routes.NAVIGATIONBAR); - } + void onInit() { + Future.delayed( const Duration( + milliseconds: 10, + ), () { + screenChange(); + firebasenotificationService.requestNotificationPermissions(); }); super.onInit(); fetchLocations(); } + + @override + void onClose() { + name.dispose(); + super.onClose(); + } } diff --git a/lib/app/modules/home/controllers/home_controller.dart b/lib/app/modules/home/controllers/home_controller.dart index d84c832..032fbf1 100644 --- a/lib/app/modules/home/controllers/home_controller.dart +++ b/lib/app/modules/home/controllers/home_controller.dart @@ -23,7 +23,7 @@ import '../../../data/hadis.dart'; import 'package:http/http.dart' as http; class HomeController extends GetxController { - + HijriCalendar currentDate = HijriCalendar.now(); @@ -51,29 +51,6 @@ class HomeController extends GetxController { return dataIndex; } -// This function is for edit name button this will show a dialog box to edit name -// and when user fast time open the app it will show a dialog box to enter name - - // getusername() { - // Timer(const Duration(seconds: 0), () { - // Get.defaultDialog( - // backgroundColor: AppColors.secondaryColor, - // buttonColor: AppColors.quaternaryColor, - // titleStyle: const TextStyle(color: Colors.white), - // titlePadding: const EdgeInsets.all(10), - // confirmTextColor: Colors.black, - // barrierDismissible: false, - // radius: 5, - // title: "আপনার নাম এবং লোকেশন সিলেক্ট করুন", - // content: - - // onConfirm: () { - - // }); - // }); - // } - - // THis function use for Location and Timezone for the app to get the current time and location @override @@ -83,18 +60,7 @@ class HomeController extends GetxController { getDataIndexForCurrentDate(); - NotificationService() - .scheduleNotification( - // scheduledDate: nextInstanceOfOneAm(1), - title: "আজকের দিনের কাজ", - body: "${dinerkaj[getDataIndexForCurrentDate()]}", - ) - .then((value) => print( - "Notification Scheduled", - )); - -// here load the location and timezone - + // getpraylanght; super.onInit(); } diff --git a/lib/app/modules/home/views/home_view.dart b/lib/app/modules/home/views/home_view.dart index e586cb4..e724655 100644 --- a/lib/app/modules/home/views/home_view.dart +++ b/lib/app/modules/home/views/home_view.dart @@ -25,70 +25,46 @@ class HomeView extends GetView { return Scaffold( extendBody: true, extendBodyBehindAppBar: true, - appBar: AppBar( - backgroundColor: Colors.transparent, - elevation: 0, - title: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + body: ListView( + padding: EdgeInsets.zero, + children: [ SizedBox( - height: 2.h, + height: 4.h, ), - AppText( - text: "আস-সালামু আলাইকুম", - fontSize: 14, - fontWeight: FontWeight.normal, - color: Colors.grey, - // textAlign: TextAlign.left, + Padding( + padding: const EdgeInsets.only(left: 20), + child: AppText( + text: "আস-সালামু আলাইকুম", + fontSize: 14, + fontWeight: FontWeight.normal, + color: Colors.grey, + // textAlign: TextAlign.left, + ), ), const SizedBox( height: 5, ), - GetBuilder( - init: HomeController(), - initState: (_) {}, - builder: (_) { - return Row( - children: [ - AppText( - text: Hive.box('user').get('name') ?? "User", - fontSize: 16, - fontWeight: FontWeight.w400, - color: Colors.white, - ), - - - ], - ); - }, - ), - ]), - actions: [ - IconButton( - onPressed: () async { - // Get.toNamed(Routes.ABOUT); - Hive.box("user").delete('name'); - Hive.box("user").delete('location'); - // print(Hive.box("user").get("location"),); - }, - icon: const Icon( - CupertinoIcons.heart_circle, - color: AppColors.quinaryColor, - )), - IconButton( - onPressed: () async { - Get.toNamed(Routes.ABOUT); - + Padding( + padding: const EdgeInsets.only(left: 20), + child: GetBuilder( + init: HomeController(), + initState: (_) {}, + builder: (_) { + return Row( + children: [ + AppText( + text: Hive.box('user').get('name') ?? "User", + fontSize: 16, + fontWeight: FontWeight.w400, + color: Colors.white, + ), + ], + ); }, - icon: const Icon( - CupertinoIcons.heart_circle, - color: AppColors.quinaryColor, - )), - ], - ), - body: ListView( - padding: EdgeInsets.zero, - children: [ + ), + ), SizedBox( - height: 10.h, + height: 4.h, ), Container( margin: const EdgeInsets.all(20), @@ -204,7 +180,7 @@ class HomeView extends GetView { builder: (_) { final dinerkaj = Hive.box('Dtrack').length; return manuButton("দিনের কাজ", "$dinerkaj/9", - () => Get.toNamed(Routes.DAILY_TRACKING)); + () => Get.toNamed(Routes.DAILY_TRACKING , )); }, ), GetBuilder( @@ -212,8 +188,11 @@ class HomeView extends GetView { initState: (_) {}, builder: (_) { final quranData = Hive.box('quranData').length; - return manuButton("কোরআন", "$quranData/3", - () => Get.toNamed(Routes.QURAN_TRACKER)); + return manuButton( + "কোরআন", + "$quranData/3", + () => Get.toNamed(Routes.QURAN_TRACKER, + )); }, ), manuButton("আল্লাহ'র নাম", "99", diff --git a/lib/app/modules/praytime/controllers/praytime_controller.dart b/lib/app/modules/praytime/controllers/praytime_controller.dart index b366529..f737f0a 100644 --- a/lib/app/modules/praytime/controllers/praytime_controller.dart +++ b/lib/app/modules/praytime/controllers/praytime_controller.dart @@ -15,14 +15,14 @@ class PraytimeController extends GetxController { late double latitude; late double longitude; late Coordinates myCoordinates; - + final params = CalculationMethod.karachi.getParameters(); final madhab = Madhab.hanafi; PrayerTimes? prayerTimes; // Get formatted time as a String String get formattedTime { - return DateFormat('HH:mm').format(currentTime.value); + return DateFormat('HH:mm').format(currentTime.value,); } String date = DateFormat('d MMMM, yyyy').format(DateTime.now()); @@ -68,19 +68,20 @@ class PraytimeController extends GetxController { // List of prayer times in order, each with a name and time final List> prayerTimesList = [ - {'name': 'Fajr', 'time': prayerTimes.fajr}, - {'name': 'Sunrise', 'time': prayerTimes.sunrise}, - {'name': 'Dhuhr', 'time': prayerTimes.dhuhr}, - {'name': 'Asr', 'time': prayerTimes.asr}, - {'name': 'Maghrib', 'time': prayerTimes.maghrib}, - {'name': 'Isha', 'time': prayerTimes.isha}, + {'name': 'ফজর', 'time': prayerTimes.fajr}, + {'name': 'সূর্যোদয়', 'time': prayerTimes.sunrise}, + {'name': 'যুহর', 'time': prayerTimes.dhuhr}, + {'name': 'আসর', 'time': prayerTimes.asr}, + {'name': 'মাগরিব', 'time': prayerTimes.maghrib}, + {'name': 'ইশা', 'time': prayerTimes.isha}, ]; // Find the current prayer time final currentPrayer = prayerTimesList.lastWhere( - (prayer) => now.isAfter(prayer['time'] as DateTime) || now.isAtSameMomentAs(prayer['time'] as DateTime), - orElse: () => {'name': 'None', 'time': prayerTimesList.first['time']} - ); + (prayer) => + now.isAfter(prayer['time'] as DateTime) || + now.isAtSameMomentAs(prayer['time'] as DateTime), + orElse: () => {'name': 'None', 'time': prayerTimesList.first['time']}); final nextPrayer = prayerTimesList.firstWhere( (prayer) => (prayer['time'] as DateTime).isAfter(now), @@ -93,13 +94,13 @@ class PraytimeController extends GetxController { final minutes = difference.inMinutes % 60; // Format the output - return '${currentPrayer['name']} ${hours < 0 && minutes < 0 ? 'Less than 0h 01m' : '${hours}h ${minutes}m'} until ${nextPrayer['name']} (${DateFormat('hh:mm a').format(nextPrayer['time'] as DateTime)})'; + return '${currentPrayer['name']} ${hours < 0 && minutes < 0 ? 'Less than 0h 01m' : '${hours}h ${minutes}m'} পরবর্তী নামাজ ${nextPrayer['name']} (${DateFormat('hh:mm a').format(nextPrayer['time'] as DateTime)})'; } @override void onInit() { super.onInit(); - + // Initialize latitude and longitude latitude = Hive.box("user").get("latitude"); longitude = Hive.box("user").get("longitude"); diff --git a/lib/app/modules/praytime/views/praytime_view.dart b/lib/app/modules/praytime/views/praytime_view.dart index 7cf1d20..f8f764c 100644 --- a/lib/app/modules/praytime/views/praytime_view.dart +++ b/lib/app/modules/praytime/views/praytime_view.dart @@ -112,7 +112,7 @@ class PraytimeView extends GetView { height: 20, ), prayTime( - title: 'Fajr', + title: 'ফজর', time: controller.getFajrTime(), icon: 'assets/icon/Icon_Fajr.svg', ), @@ -122,22 +122,22 @@ class PraytimeView extends GetView { icon: 'assets/icon/Sunrise.svg', ), prayTime( - title: 'Dhuhr', + title: 'সূর্যোদয়', time: controller.getdhuhrTime(), icon: 'assets/icon/Icon_Dhuhr.svg', ), prayTime( - title: 'Asr', + title: 'আসর', time: controller.getasrTime(), icon: 'assets/icon/Icon_Asr.svg', ), prayTime( - title: 'Maghrib', + title: 'মাগরিব', time: controller.getmaghribTime(), icon: 'assets/icon/Icon_Maghrib.svg', ), prayTime( - title: 'Isha', + title: 'ইশা', time: controller.getishaTime(), icon: 'assets/icon/Icon_Isha.svg', ), diff --git a/lib/app/modules/settings/views/settings_view.dart b/lib/app/modules/settings/views/settings_view.dart index 0d43d4e..995fe97 100644 --- a/lib/app/modules/settings/views/settings_view.dart +++ b/lib/app/modules/settings/views/settings_view.dart @@ -23,7 +23,7 @@ class SettingsView extends GetView { fontSize: 14.sp, )), body: Container( - margin: const EdgeInsets.all(25), + margin: const EdgeInsets.only(top: 25, left: 20, right: 20), child: ListView( children: [ AppText( @@ -86,13 +86,12 @@ class SettingsView extends GetView { ontap: () { controller.applaunchUrl(); }), - settingButton( leadingIcon: Icons.info_outlined, title: "Version", trailingIcon: Icons.arrow_forward_ios, isIcon: false, - ontap:null), + ontap: null), ], ), )), diff --git a/lib/app/service/backgroundService.dart b/lib/app/service/backgroundService.dart deleted file mode 100644 index a9a7897..0000000 --- a/lib/app/service/backgroundService.dart +++ /dev/null @@ -1,56 +0,0 @@ -// ignore_for_file: file_names -// import 'dart:io'; -// import 'dart:ui'; - -// import 'package:flutter/material.dart'; -// import 'package:flutter_background_service/flutter_background_service.dart'; - -// Future initializeService() async { -// final service = FlutterBackgroundService(); - -// await service.configure( -// androidConfiguration: AndroidConfiguration( -// // this will be executed when app is in foreground or background in separated isolate -// onStart: onStart, - -// // auto start service -// autoStart: true, -// isForegroundMode: true, - -// notificationChannelId: 'my_foreground', -// initialNotificationTitle: 'AWESOME SERVICE', -// initialNotificationContent: 'Initializing', -// foregroundServiceNotificationId: 888, -// ), -// iosConfiguration: IosConfiguration( -// // auto start service -// autoStart: true, - -// // this will be executed when app is in foreground in separated isolate -// onForeground: onStart, - -// // you have to enable background fetch capability on xcode project -// onBackground: onIosBackground, -// ), -// ); - -// service.startService(); -// } - -// @pragma('vm:entry-point') -// Future onIosBackground(ServiceInstance service) async { -// WidgetsFlutterBinding.ensureInitialized(); -// DartPluginRegistrant.ensureInitialized(); -// return true; -// } - -// @pragma('vm:entry-point') -// void onStart(ServiceInstance service) async { -// // Only available for flutter 3.0.0 and later -// DartPluginRegistrant.ensureInitialized(); - -// // -// service.on('stopService').listen((event) { -// service.stopSelf(); -// }); -// } diff --git a/lib/app/service/notification/firebasenotification.dart b/lib/app/service/notification/firebasenotification.dart new file mode 100644 index 0000000..97501c6 --- /dev/null +++ b/lib/app/service/notification/firebasenotification.dart @@ -0,0 +1,104 @@ +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:get/get.dart'; +import 'package:ramadanplanner/app/routes/app_pages.dart'; + +class FirebaseNotificationService { + final FirebaseMessaging _messaging = FirebaseMessaging.instance; + final FlutterLocalNotificationsPlugin _localNotificationsPlugin = + FlutterLocalNotificationsPlugin(); + + // Singleton pattern + static final FirebaseNotificationService _instance = FirebaseNotificationService._internal(); + factory FirebaseNotificationService() => _instance; + FirebaseNotificationService._internal(); + + // Initialize the service + Future initialize() async { + await Firebase.initializeApp(); + _initializeLocalNotifications(); + _setupFirebaseMessaging(); + } + + // Initialize local notifications + Future _initializeLocalNotifications() async { + const AndroidInitializationSettings initializationSettingsAndroid = + AndroidInitializationSettings('@mipmap/ic_launcher'); + + const InitializationSettings initializationSettings = + InitializationSettings(android: initializationSettingsAndroid); + + await _localNotificationsPlugin.initialize( + initializationSettings, + // onSelectNotification: _onSelectNotification, + ); + } + + // Show a local notification + Future _showNotification(RemoteMessage message) async { + const AndroidNotificationDetails androidDetails = + AndroidNotificationDetails( + 'your_channel_id', + 'your_channel_name', + // 'your_channel_description', + importance: Importance.max, + priority: Priority.high, + ticker: 'ticker', + ); + + const NotificationDetails platformDetails = + NotificationDetails(android: androidDetails); + + await _localNotificationsPlugin.show( + message.hashCode, + message.notification?.title, + message.notification?.body, + platformDetails, + payload: message.data['screen'], + ); + } + + // Handle notification taps + Future _onSelectNotification(String? payload) async { + if (payload != null) { + if (payload == 'DailyTrackingView') { + Get.toNamed(Routes.DAILY_TRACKING); + } + // else if (payload == 'SomeOtherView') { + // // Get.to(SomeOtherView()); + // } + } + } + + // Setup Firebase messaging listeners + void _setupFirebaseMessaging() { + FirebaseMessaging.onMessage.listen((RemoteMessage message) { + _showNotification(message); + }); + + FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { + _onSelectNotification(message.data['screen']); + }); + + _messaging.getInitialMessage().then((RemoteMessage? message) { + if (message != null) { + _onSelectNotification(message.data['screen']); + } + }); + } + + void requestNotificationPermissions() { + FirebaseMessaging.instance.requestPermission( + alert: true, + badge: true, + sound: true, + ); +} + + // Background message handler + static Future backgroundMessageHandler(RemoteMessage message) async { + await Firebase.initializeApp(); + _instance._showNotification(message); + } +} diff --git a/lib/app/service/notification/notification.dart b/lib/app/service/notification/notification.dart index 1f64e36..5ed44ef 100644 --- a/lib/app/service/notification/notification.dart +++ b/lib/app/service/notification/notification.dart @@ -1,242 +1,115 @@ -// ignore_for_file: unused_import, unnecessary_brace_in_string_interps - -import 'package:flutter/material.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; -import 'dart:isolate'; - -import 'package:hive_flutter/adapters.dart'; -import 'package:ramadanplanner/Util/app_colors.dart'; +import 'package:get/get.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:ramadanplanner/app/data/dinerkaj.dart'; +import 'package:ramadanplanner/app/routes/app_pages.dart'; import 'package:timezone/data/latest.dart' as tz; import 'package:timezone/timezone.dart' as tz; -class NotificationService { - final FlutterLocalNotificationsPlugin notificationsPlugin = +class NotificationService extends GetxService { + final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); - Future initNotification() async { - AndroidInitializationSettings initializationSettingsAndroid = - const AndroidInitializationSettings('@mipmap/ic_launcher'); + Future init() async { + // Initialize the flutter_local_notifications plugin + const AndroidInitializationSettings initializationSettingsAndroid = + AndroidInitializationSettings('@mipmap/ic_launcher'); + const InitializationSettings initializationSettings = InitializationSettings( + android: initializationSettingsAndroid, + ); - var initializationSettingsIOS = DarwinInitializationSettings( - requestAlertPermission: true, - requestBadgePermission: true, - requestSoundPermission: true, - defaultPresentAlert: true, - defaultPresentBadge: true, - defaultPresentSound: true, - onDidReceiveLocalNotification: - (int id, String? title, String? body, String? payload) async {}); + await flutterLocalNotificationsPlugin.initialize( + initializationSettings, + onDidReceiveNotificationResponse: (details) { + // Handle notification tap + Get.toNamed(Routes.DAILY_TRACKING); + }, + ); - var initializationSettings = InitializationSettings( - android: initializationSettingsAndroid, iOS: initializationSettingsIOS); - await notificationsPlugin.initialize(initializationSettings, - onDidReceiveNotificationResponse: - (NotificationResponse notificationResponse) async {}); - } + // Initialize time zone data + tz.initializeTimeZones(); - notificationDetails() { - return const NotificationDetails( - android: AndroidNotificationDetails( - 'channelId', - 'channelName', - importance: Importance.max, - priority: Priority.high, - visibility: NotificationVisibility.public, - color: AppColors.primaryColor, - playSound: true, - enableVibration: true, - icon: 'flutter_logo', - fullScreenIntent: true, - showWhen: true, - showProgress: true, - ledColor: Colors.red, - ledOnMs: 1000, - ledOffMs: 500, - autoCancel: true, - ), - iOS: DarwinNotificationDetails()); - } + // Request notification permissions + await requestPermissions(); - Future showNotification( - {int id = 0, String? title, String? body, String? payLoad}) async { - return notificationsPlugin.show( - id, title, body, await notificationDetails()); - } + // Schedule daily notifications + scheduleDailyNotifications(); - Future scheduleNotification({ - int id = 0, - String? title, - String? body, - String? payLoad, - }) async { - return notificationsPlugin.zonedSchedule( - id, title, body, nextInstanceOfOneAm(), await notificationDetails(), - androidAllowWhileIdle: true, - uiLocalNotificationDateInterpretation: - UILocalNotificationDateInterpretation.absoluteTime); + return this; } -} -tz.TZDateTime nextInstanceOfOneAm() { - final tz.TZDateTime now = tz.TZDateTime.now(tz.local); - tz.TZDateTime scheduledDate = - tz.TZDateTime(tz.local, now.year, now.month, now.day, 6); // 1 am - if (scheduledDate.isBefore(now)) { - scheduledDate = scheduledDate.add(const Duration(days: 1)); + Future requestPermissions() async { + final status = await Permission.notification.status; + if (status.isDenied) { + // Request permission + final result = await Permission.notification.request(); + if (result.isDenied) { + // Handle the case when permission is denied + Get.snackbar( + 'Permission Denied', + 'Notification permissions are required to receive notifications.', + snackPosition: SnackPosition.bottom, + ); + } else if (result.isPermanentlyDenied) { + // Handle the case when permission is permanently denied + Get.snackbar( + 'Permission Required', + 'Notification permissions are required. Please enable them in app settings.', + snackPosition: SnackPosition.bottom, + ); + // Redirect to app settings + openAppSettings(); + } + } else if (status.isPermanentlyDenied) { + // Handle the case when permission is permanently denied + Get.snackbar( + 'Permission Required', + 'Notification permissions are required. Please enable them in app settings.', + snackPosition: SnackPosition.bottom, + ); + // Redirect to app settings + openAppSettings(); + } } - print("This is tha Time is notifi ${scheduledDate}"); - - return scheduledDate; -} - - - - - - - + void scheduleDailyNotifications() { + // Schedule 6 PM notification + _scheduleNotification(18, 0, 'আস-সালামু আলাইকুম', "আজকের দিনের কাজ \n ${dinerkaj[DateTime.now().day]}"); + // Schedule 8 AM notification + _scheduleNotification(8, 0, 'আস-সালামু আলাইকুম', "আজকের দিনের কাজ \n ${dinerkaj[DateTime.now().day]}"); + } - -// class NotificationServices { -// static Future initializeNotification() async { -// await AwesomeNotifications().initialize( -// null, -// [ -// NotificationChannel( -// channelKey: 'high_importance_channel', -// channelGroupKey: 'High Importance Notifications', -// channelName: 'basic Notification', -// channelDescription: 'Notification channel for basic tests', -// defaultColor: AppColors.primaryColor, -// ledColor: AppColors.primaryColor, -// channelShowBadge: true, -// onlyAlertOnce: true, -// playSound: true, -// enableLights: true, -// enableVibration: true, -// criticalAlerts: true, -// ) -// ], -// channelGroups: [ -// NotificationChannelGroup( -// channelGroupName: 'group1', -// channelGroupKey: 'High Importance Notifications', -// ), -// ], -// debug: true); -// await AwesomeNotifications().isNotificationAllowed().then( -// (isAllowed) async { -// if (!isAllowed) { -// await AwesomeNotifications().requestPermissionToSendNotifications(); -// } -// }, -// ); -// await AwesomeNotifications().setListeners( -// onActionReceivedMethod: onActionReceivedMethod, -// onNotificationDisplayedMethod: onNotificationDisplayedMethod, -// onDismissActionReceivedMethod: onDismissActionReceivedMethod, -// onNotificationCreatedMethod: onNotificationCreatedMethod, - -// ); -// } -// static Future onNotificationCreatedMethod ( ReceivedNotification receivedNotification) async { -// print('Notification Created'); -// } - -// static Future onNotificationDisplayedMethod ( ReceivedNotification receivedNotification) async { -// print('Notification Created'); -// } - -// static Future onDismissActionReceivedMethod ( ReceivedAction receivedAction) async { -// print('Notification Created'); -// } - -// static Future onActionReceivedMethod ( ReceivedAction receivedAction) async { -// print('Notification Created'); -// final payload = receivedAction.payload ?? {}; -// if (payload['navigate'] == 'true') { -// Get.toNamed(Routes.PRAY_TRACKER); -// } - -// } - -// static Future showNotification({ -// required final String title, -// required final String body, -// final String? summary, -// final Map? payload, -// final ActionType actionType = ActionType.Default, -// final NotificationLayout notificationLayout = NotificationLayout.Default, -// final NotificationCategory? category, -// final String? bigPicture, -// final List? actionButtons, -// final bool schedule = false, -// final int? interval, -// // final bool isrepeat = false, -// })async{ -// assert (!schedule || (schedule != null)); -// await AwesomeNotifications().createNotification(content: -// NotificationContent( -// id: -1, -// channelKey: 'high_importance_channel', -// title: title, -// body: body, -// notificationLayout: notificationLayout, -// summary: summary, -// actionType: actionType, -// payload: payload, -// displayOnForeground: true, -// displayOnBackground: true, -// fullScreenIntent: true, -// category: category, -// bigPicture: bigPicture, -// backgroundColor: AppColors.primaryColor, -// badge: 1, - -// ), -// actionButtons: actionButtons, -// schedule: schedule ? NotificationInterval( -// timeZone: await AwesomeNotifications().getLocalTimeZoneIdentifier(), -// // repeats: true, -// interval: nextInstanceOfOneAm().minute, -// preciseAlarm: true, -// // repeats: isrepeat, - -// ) : null, - - -// ); -// } - -// } - - -// // triggerNotification( -// // String titel, String body, dynamic schedule, bool isRepeat) { -// // AwesomeNotifications().createNotification( -// // content: NotificationContent( -// // // customSound: "assets/sound/notification.mp3", -// // id: 10, -// // channelKey: 'basic_channel', -// // title: titel, -// // body: body, -// // notificationLayout: NotificationLayout.BigText, -// // // icon: "assets/images/logo.png", -// // backgroundColor: AppColors.primaryColor, -// // badge: 1, -// // displayOnForeground: true, -// // displayOnBackground: true, -// // fullScreenIntent: true, -// // ), - -// // // ); -// // schedule: NotificationCalendar( -// // timeZone: DateTime.now().timeZoneName, -// // repeats: isRepeat, - -// // )); -// // } - - + void _scheduleNotification(int hour, int minute, String title, String body) { + final tz.TZDateTime now = tz.TZDateTime.now(tz.local); + final tz.TZDateTime scheduledDate = tz.TZDateTime( + tz.local, + now.year, + now.month, + now.day, + hour, + minute, + ); + + flutterLocalNotificationsPlugin.zonedSchedule( + 0, + title, + body, + scheduledDate.isBefore(now) + ? scheduledDate.add(const Duration(days: 1)) + : scheduledDate, + const NotificationDetails( + android: AndroidNotificationDetails( + 'your_channel_id', + 'your_channel_name', + importance: Importance.max, + priority: Priority.high, + ), + ), + androidAllowWhileIdle: true, + uiLocalNotificationDateInterpretation: + UILocalNotificationDateInterpretation.wallClockTime, + matchDateTimeComponents: DateTimeComponents.time, // Repeat daily + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index 19a525f..81a70ea 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,9 @@ // ignore_for_file: depend_on_referenced_packages, unused_import +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:ramadanplanner/app/modules/navigationbar/views/navigationbar_view.dart'; - +import 'package:ramadanplanner/app/service/notification/firebasenotification.dart'; import 'package:sizer/sizer.dart'; import 'package:get/get.dart'; import 'Util/app_colors.dart'; @@ -19,13 +20,18 @@ void main() async { // await FlutterBackgroundService.initialize(onStart); await hiveData(); -// await NotificationService().initNotification(); - tz.initializeTimeZones(); - // await Firebase.initializeApp( - // options: DefaultFirebaseOptions.currentPlatform, - // ); +// Initialize NotificationService + + tz.initializeTimeZones(); + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); + await Firebase.initializeApp(); + FirebaseNotificationService().initialize(); + await NotificationService().init(); + // Register background message handler + FirebaseMessaging.onBackgroundMessage(FirebaseNotificationService.backgroundMessageHandler); - WidgetsFlutterBinding.ensureInitialized(); runApp(const MyApp()); } @@ -62,6 +68,7 @@ class _MyAppState extends State { scaffoldBackgroundColor: AppColors.primaryColor, primarySwatch: Colors.green, ), + defaultTransition: Transition.noTransition, ); }, ); diff --git a/pubspec.lock b/pubspec.lock index c50d1f9..7d08f93 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,14 @@ packages: url: "https://pub.dev" source: hosted version: "72.0.0" + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + sha256: f5628cd9c92ed11083f425fd1f8f1bc60ecdda458c81d73b143aeda036c35fe7 + url: "https://pub.dev" + source: hosted + version: "1.3.16" _macros: dependency: transitive description: dart @@ -302,6 +310,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.10.0" + firebase_messaging: + dependency: "direct main" + description: + name: firebase_messaging + sha256: "980259425fa5e2afc03e533f33723335731d21a56fd255611083bceebf4373a8" + url: "https://pub.dev" + source: hosted + version: "14.7.10" + firebase_messaging_platform_interface: + dependency: transitive + description: + name: firebase_messaging_platform_interface + sha256: "54e283a0e41d81d854636ad0dad73066adc53407a60a7c3189c9656e2f1b6107" + url: "https://pub.dev" + source: hosted + version: "4.5.18" + firebase_messaging_web: + dependency: transitive + description: + name: firebase_messaging_web + sha256: "90dc7ed885e90a24bb0e56d661d4d2b5f84429697fd2cbb9e5890a0ca370e6f4" + url: "https://pub.dev" + source: hosted + version: "3.5.18" fixnum: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index fdaee37..d4964be 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -29,12 +29,13 @@ dependencies: # geolocator: ^11.1.0 flutter_widget_from_html: ^0.15.2 url_launcher: ^6.3.0 + # http: ^1.2.2 - # firebase_messaging: ^14.3.0 + firebase_messaging: ^14.3.0 # firebase_crashlytics: ^3.0.17