implements notification

This commit is contained in:
2025-04-24 18:48:12 +05:30
parent 31cc1b9c15
commit 029b71a247
34 changed files with 1724 additions and 705 deletions

View File

@@ -1,7 +1,11 @@
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:grocery_app/src/core/network_services/service_locator.dart';
import 'package:grocery_app/src/core/routes/routes.dart';
import 'package:grocery_app/src/firebase_options.dart';
import 'package:grocery_app/src/logic/provider/addTocart_provider.dart';
import 'package:grocery_app/src/logic/provider/address_provider.dart';
import 'package:grocery_app/src/logic/provider/auth_provider.dart';
@@ -9,20 +13,70 @@ import 'package:grocery_app/src/logic/provider/bottom_navbar_provider.dart';
import 'package:grocery_app/src/logic/provider/home_provider.dart';
import 'package:grocery_app/src/logic/provider/order_provider.dart';
import 'package:grocery_app/src/logic/provider/profile_provider.dart';
import 'package:grocery_app/src/logic/services/notification_service.dart';
import 'package:grocery_app/src/ui/splash/splash_screen.dart';
import 'package:grocery_app/utils/constants/color_constant.dart';
import 'package:grocery_app/utils/constants/string_constant.dart';
import 'package:loader_overlay/loader_overlay.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';
//change the location and many tings
void main() {
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
print("💬 Background Message Received: ${message.notification?.title}");
if (message.notification != null) {
NotificationService.flutterLocalNotificationsPlugin.show(
message.hashCode,
message.notification!.title,
message.notification!.body,
const NotificationDetails(
android: AndroidNotificationDetails(
'high_importance_channel',
'High Importance Notifications',
channelDescription: 'Used for important notifications.',
importance: Importance.max,
priority: Priority.high,
),
),
);
}
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
await NotificationService.init();
ServiceLocator.setup();
await requestNotificationPermission();
runApp(const MyApplication());
}
Future<void> requestNotificationPermission() async {
PermissionStatus status = await Permission.notification.status;
if (status.isDenied || status.isPermanentlyDenied) {
status = await Permission.notification.request();
}
if (status.isGranted) {
print("✅ Notification permission granted");
} else if (status.isPermanentlyDenied) {
print("⚠️ Notification permission permanently denied. Open settings.");
openAppSettings();
} else {
print("❌ Notification permission denied.");
}
}
class MyApplication extends StatelessWidget {
const MyApplication({super.key});

View File

@@ -52,6 +52,8 @@ class APIURL {
static const String productReview = "${BASE_URL}products/";
static const String upDateDeviceToken = "${BASE_URL}devices/register";
}

View File

@@ -0,0 +1,70 @@
// File generated by FlutterFire CLI.
// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for web - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for macos - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.windows:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for windows - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.linux:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for linux - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyD2my5NEUm5almYwz_vUWgoMNMT4OMpGHM',
appId: '1:855851990714:android:6fb061e1f508cfe1818c83',
messagingSenderId: '855851990714',
projectId: 'frontshop-emporium-8f851',
storageBucket: 'frontshop-emporium-8f851.firebasestorage.app',
);
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyABDDHCwEU_Kd6ODtFDXw3tfOpCxteT1q8',
appId: '1:206755694561:ios:2a43094871ef7917d474a0',
messagingSenderId: '934018612864',
projectId: 'bestonehrms',
storageBucket: 'digitalhrm-7e9ae.appspot.com',
androidClientId: '',
iosClientId: '',
iosBundleId: 'com.erp.bestone',
);
}

View File

@@ -1,3 +1,4 @@
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:grocery_app/src/core/network_services/service_locator.dart';
import 'package:grocery_app/src/data/user_profile.dart';
@@ -32,4 +33,7 @@ class BottomNavProvider with ChangeNotifier {
},
);
}
}

View File

@@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:convert';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:geolocator/geolocator.dart';
@@ -9,7 +10,7 @@ import 'package:grocery_app/src/core/network_services/service_locator.dart';
import 'package:grocery_app/src/core/routes/routes.dart';
import 'package:grocery_app/src/data/ProductCategoryModel.dart';
import 'package:grocery_app/src/data/allProduct_model.dart';
import 'package:grocery_app/src/data/all_cart_items.dart';
import 'package:grocery_app/src/data/banners.dart';
import 'package:grocery_app/src/data/best_dealProduct.dart';
import 'package:grocery_app/src/data/product_category.dart';
@@ -20,8 +21,7 @@ import 'package:grocery_app/utils/constants/shared_pref_utils.dart';
import 'package:grocery_app/utils/extensions/extensions.dart';
import 'package:http/http.dart' as http;
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:provider/provider.dart';
class ProductProvider extends ChangeNotifier {
final _homeRepo = getIt<ProductRepo>();
@@ -109,6 +109,26 @@ class ProductProvider extends ChangeNotifier {
);
}
Future<bool> updateDeviceToken(BuildContext context) async {
var fcm = await FirebaseMessaging.instance.getToken();
var data = {"deviceToken": fcm, "deviceTpe": "android"};
print("fcm token ${"hjsdgffghhhh ${data}"}");
var result = await _homeRepo.updateDeviceToken(data, context);
return result.fold(
(error) {
return true;
},
(response) {
print("token update success");
return true;
},
);
}
bool isHomeLoadingg = false;
List<Product> homeproducts = [];

View File

@@ -442,7 +442,8 @@ class ProductRepo {
}
}
FutureResult<String> refreshToken(data, BuildContext context) async {
FutureResult<String> refreshToken(data, BuildContext context) async
{
try {
var response = await _productService.refresh_token(data);
LoginResponse loginResponse = loginResponseFromJson(response.toString());
@@ -463,29 +464,15 @@ class ProductRepo {
}
}
// FutureResult<VendorModel> getMe(data) async {
// try {
// var response = await _homeService.getMe(data);
// final VendorModel vendorModel = vendorModelFromJson(response.toString());
// if (vendorModel != null)
// {
// SharedPrefUtils.USER_NAME =
// vendorModel.firstName + " " + vendorModel.lastName;
// SharedPrefUtils.PHONE = vendorModel.phone;
// print("dkfjhdkfhkfk ${SharedPrefUtils.USER_NAME}");
// await SharedPrefUtils.setStoreId(storeId: vendorModel.storeId ?? "");
// }
// final String model = response.toString();
// return right(vendorModel);
// } on DioException catch (e) {
// var error = CustomDioExceptions.handleError(e);
// return left(error);
// }
// }
FutureResult<String> updateDeviceToken(data, BuildContext context) async
{
try {
var response = await _productService.updateDeviceToken(data);
final String model = response.toString();
return right(model);
} on DioException catch (e) {
var error = CustomDioExceptions.handleError(e);
return left(error);
}
}
}

View File

@@ -19,6 +19,14 @@ class ProductService extends ApiService {
return response;
}
Future updateDeviceToken(data) async {
var response =
await api.post(APIURL.upDateDeviceToken, data: jsonEncode(data));
return response;
}
Future getAllProduct(data, id) async {
var response;
@@ -40,6 +48,8 @@ class ProductService extends ApiService {
return response;
}
//
Future getBestDealProduct(data) async {

View File

@@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
class NotificationService {
static final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
static Future<void> init() async {
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
const DarwinInitializationSettings initializationSettingsIOS =
DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
const InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: (NotificationResponse response) {
// Handle tap on notification
debugPrint("🔔 Notification clicked: ${response.payload}");
},
);
// Listen when app is in foreground
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
_showNotification(message);
});
// Optional: listen when user taps notification while app is in background/terminated
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
debugPrint(
"📲 App opened via notification: ${message.notification?.title}");
// Navigate to specific screen if needed
});
}
static Future<void> _showNotification(RemoteMessage message) async {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
if (notification != null && android != null) {
const AndroidNotificationDetails androidDetails =
AndroidNotificationDetails(
'high_importance_channel', // Match with AndroidManifest.xml
'High Importance Notifications',
channelDescription: 'Used for important notifications.',
importance: Importance.max,
priority: Priority.high,
);
const NotificationDetails platformDetails =
NotificationDetails(android: androidDetails);
await flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
platformDetails,
);
}
}
}

View File

@@ -85,13 +85,11 @@ class _FavouriteScreenState extends State<FavouriteScreen>
top: 0,
right: 0,
child: AppNetworkImage(
radius: 10,
imageUrl: wishListProvider
.productDatumlastImageurl ??
"https://5.imimg.com/data5/SELLER/Default/2024/2/385126988/OL/DA/VW/8627346/1l-fortune-sunflower-oil.jpg",
backGroundColor: Colors.white,
),
),
],
@@ -151,7 +149,7 @@ class _FavouriteScreenState extends State<FavouriteScreen>
return Expanded(
child: DataNotFound(
imagePath: 'assets/images/wishlist.jpg',
message: "Your Wish list is empty. Please add some items",
message: "Data Not Found",
width: 250.w,
height: 200.h,
));
@@ -213,7 +211,6 @@ class _FavouriteScreenState extends State<FavouriteScreen>
.product!.productImages!.first.url ??
"https://i.pinimg.com/originals/a5/f3/5f/a5f35fb23e942809da3df91b23718e8d.png",
backGroundColor: APPCOLOR.bgGrey,
radius: 10,
),
),

View File

@@ -38,6 +38,8 @@ class _HomeScreenState extends State<HomeScreen> {
productProvider.getHomeProduct(context, "", '', '', '', '');
productProvider.getBestDealProduct(context, '');
productProvider.getAllcategory(context);
productProvider.updateDeviceToken(context);
// productProvider.getCategoryByLevel();
getUserDetails();
@@ -602,7 +604,6 @@ class _HomeScreenState extends State<HomeScreen> {
enlargeFactor: 0.3,
),
items: provider.banner.map((banner) {
return Builder(
builder: (BuildContext context) {
return Container(
@@ -661,6 +662,7 @@ class _HomeScreenState extends State<HomeScreen> {
imageUrl: banner.imageUrl ??
'https://e7.pngegg.com/pngimages/742/816/png-clipart-coca-cola-can-illustration-coca-cola-soft-drink-surge-pepsi-coke-sweetness-cola-thumbnail.png',
backGroundColor: Colors.transparent,
// boxFit: BoxFit.contain,
),
),
),

View File

@@ -35,11 +35,18 @@ class _ProfileScreenState extends State<ProfileScreen> {
super.initState();
}
Future<String> getToken() async {
return await SharedPrefUtils.getToken() ?? "";
}
getUserDetails() async {
print("dkjfghlfkgh ${await SharedPrefUtils.getToken()}");
APPSTRING.userName = (await SharedPrefUtils.getFirstName())!;
APPSTRING.emailName = (await SharedPrefUtils.getUserEmail())!;
APPSTRING.userProfile = (await SharedPrefUtils.getUserProfile())!;
APPSTRING.userLastName = (await SharedPrefUtils.getLastName())!;
setState(() async {});
}
final _formKey = GlobalKey<FormState>();
@@ -59,7 +66,6 @@ class _ProfileScreenState extends State<ProfileScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
@@ -88,11 +94,9 @@ class _ProfileScreenState extends State<ProfileScreen> {
context.customExtraBold(Colors.white, 14),
)
: const SizedBox(),
const SizedBox(
height: 30,
),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@@ -194,26 +198,6 @@ class _ProfileScreenState extends State<ProfileScreen> {
title: const Text('Edit Profile'),
trailing: Icon(MdiIcons.chevronRight),
),
// ListTile(
// onTap: () {
// _showBottomSheet(context);
// },
// leading: Icon(MdiIcons.lockOutline),
// title: const Text('Change Password'),
// trailing: Icon(MdiIcons.chevronRight),
// ),
// ListTile(
// onTap: () {
// // Navigator.of(context).push(MaterialPageRoute(
// // builder: (context) {
// // return const CardCheckoutScreen();
// // },
// // ));
// },
// leading: Icon(MdiIcons.cardOutline),
// title: const Text('Payment Method'),
// trailing: Icon(MdiIcons.chevronRight),
// ),
ListTile(
onTap: () {
context.push(MyRoutes.MYORDER);
@@ -222,43 +206,6 @@ class _ProfileScreenState extends State<ProfileScreen> {
title: const Text('My Order'),
trailing: Icon(MdiIcons.chevronRight),
),
// ListTile(
// onTap: () {
// Navigator.of(context).push(MaterialPageRoute(
// builder: (context) {
// return const NotificationScreen();
// },
// ));
// },
// leading: Icon(MdiIcons.bellOutline),
// title: const Text('Notifications'),
// trailing: Icon(MdiIcons.chevronRight),
// ),
// ListTile(
// onTap: () {
// Navigator.of(context).push(MaterialPageRoute(
// builder: (context) {
// return const RatingReviewScreen();
// },
// ));
// },
// leading: Icon(MdiIcons.starOutline),
// title: const Text('Rating & Review'),
// trailing: Icon(MdiIcons.chevronRight),
// ),
// ListTile(
// onTap: () {
// Navigator.of(context).push(MaterialPageRoute(
// builder: (context) {
// return const MessageScreen();
// },
// ));
// },
// leading: Icon(MdiIcons.messageOutline),
// title: const Text('Driver Message'),
// trailing: Icon(MdiIcons.chevronRight),
// ),
ListTile(
onTap: () {
context.push(MyRoutes.PRIVACY);
@@ -275,7 +222,6 @@ class _ProfileScreenState extends State<ProfileScreen> {
title: const Text('Term & Conditions'),
trailing: Icon(MdiIcons.chevronRight),
),
],
),
),
@@ -304,10 +250,18 @@ class _ProfileScreenState extends State<ProfileScreen> {
const SizedBox(
width: 10,
),
Text(
"Logout",
style: context.customMedium(Colors.white, 16),
),
if (APPSTRING.isToken == null ||
APPSTRING.isToken == "") ...{
Text(
"login",
style: context.customMedium(Colors.white, 16),
),
} else ...{
Text(
"Logout",
style: context.customMedium(Colors.white, 16),
),
}
],
),
),

View File

@@ -33,6 +33,7 @@ class _SplashScreenState extends State<SplashScreen> {
{
Provider.of<BottomNavProvider>(context, listen: false) .refreshToken(context);
if (await SharedPrefUtils.isFreshInstall())
{
context.clearAndPush(routePath: MyRoutes.ONBOARDING);

View File

@@ -27,4 +27,5 @@ class APPSTRING {
static String userLastName = "user_name";
static String emailName = "user_email";
static String userProfile = "user_profile";
static String isToken = "isToken";
}