Files
daily_mobileapp_merchant/lib/mainlive.dart
2026-05-27 10:35:09 +05:30

427 lines
14 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:new_version_plus/new_version_plus.dart';
import 'package:http/http.dart' as http;
import 'Controller/Internetcheck/check_internet.dart';
import 'Globalwidgets/Localnotificationservice.dart';
import 'Globalwidgets/binding.dart';
import 'Helper/Constants/Apiconstants.dart';
import 'Helper/Constants/Colorconstants.dart';
import 'Helper/Constants/api_config.dart';
import 'Helper/Logger.dart';
import 'Helper/Locationservice/app_config_service.dart';
import 'View/Home/Homeview.dart';
import 'View/Introscreen/Introscreenview.dart';
import 'View/Update/Updateview.dart';
/// ---------------------------------------------------------------------------
/// 1. GLOBAL NOTIFICATION OBJECTS
/// ---------------------------------------------------------------------------
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
final AndroidNotificationChannel channel = AndroidNotificationChannel(
'Nearlexpress Business', // id
'Nearlexpress Business Notifications', // name
description: 'Nearlexpress Business',
importance: Importance.high,
sound: const RawResourceAndroidNotificationSound('ring'), // raw/ring.mp3
enableLights: true,
enableVibration: true,
playSound: true,
showBadge: true,
vibrationPattern: Int64List.fromList(const [500, 1000, 500]),
);
/// ---------------------------------------------------------------------------
/// 2. BACKGROUND MESSAGE HANDLER (must be top-level)
/// ---------------------------------------------------------------------------
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
// Initialize local notifications in background isolate
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
const DarwinInitializationSettings initializationSettingsIOS =
DarwinInitializationSettings();
const InitializationSettings initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
// Create notification channel
final AndroidNotificationChannel channel = AndroidNotificationChannel(
'Nearlexpress Business',
'Nearlexpress Business Notifications',
description: 'Nearlexpress Business',
importance: Importance.high,
sound: const RawResourceAndroidNotificationSound('ring'),
playSound: true,
enableVibration: true,
vibrationPattern: Int64List.fromList(const [500, 1000, 500]),
);
final androidPlugin = flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>();
await androidPlugin?.createNotificationChannel(channel);
// === LOAD LOGO FROM ASSETS IN BACKGROUND ===
final ByteData logoData = await rootBundle.load('assets/images/nearlebusiness.png');
final Uint8List logoBytes = logoData.buffer.asUint8List();
// Show notification if it has title/body
if (message.notification != null) {
await flutterLocalNotificationsPlugin.show(
message.hashCode,
message.notification!.title,
message.notification!.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
importance: Importance.high,
priority: Priority.high,
icon: '@mipmap/ic_launcher',
sound: const RawResourceAndroidNotificationSound('ring'),
enableVibration: true,
vibrationPattern: Int64List.fromList([500, 1000, 500]),
playSound: true,
color: const Color(0xFF662582),
largeIcon: ByteArrayAndroidBitmap(logoBytes), // LOGO ON RIGHT
styleInformation: BigPictureStyleInformation(
ByteArrayAndroidBitmap(logoBytes),
largeIcon: ByteArrayAndroidBitmap(logoBytes),
contentTitle: message.notification!.title,
htmlFormatContentTitle: true,
),
),
iOS: const DarwinNotificationDetails(
sound: 'ring.wav',
),
),
payload: jsonEncode(message.data.isNotEmpty ? message.data : {
"type": message.notification?.android?.tag ?? ""
}),
);
}
}
/// ---------------------------------------------------------------------------
/// 3. LOCAL NOTIFICATION HELPER (foreground + background)
/// ---------------------------------------------------------------------------
Future<void> _showLocalNotification(RemoteMessage message) async {
final notification = message.notification;
if (notification == null) return;
// === LOAD LOGO FROM ASSETS ===
final ByteData logoData = await rootBundle.load('assets/images/nearle_logo.jpeg');
final Uint8List logoBytes = logoData.buffer.asUint8List();
final AndroidNotificationDetails androidDetails = AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
importance: channel.importance,
priority: Priority.high,
sound: channel.sound,
enableVibration: channel.enableVibration,
vibrationPattern: channel.vibrationPattern,
playSound: channel.playSound,
enableLights: channel.enableLights,
icon: '@mipmap/ic_launcher',
color: const Color(0xFF662582),
largeIcon: ByteArrayAndroidBitmap(logoBytes), // LOGO ON RIGHT
styleInformation: BigPictureStyleInformation(
ByteArrayAndroidBitmap(logoBytes),
largeIcon: ByteArrayAndroidBitmap(logoBytes),
contentTitle: notification.title,
summaryText: notification.body,
htmlFormatContentTitle: true,
htmlFormatSummaryText: true,
),
);
const DarwinNotificationDetails iOSDetails = DarwinNotificationDetails(
sound: 'ring.mp3',
presentAlert: true,
presentBadge: true,
presentSound: true,
);
final NotificationDetails platformDetails =
NotificationDetails(android: androidDetails, iOS: iOSDetails);
await flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
platformDetails,
payload: jsonEncode(message.data.isNotEmpty ? message.data : {
"type": message.notification?.android?.tag ?? ""
}),
);
}
/// ---------------------------------------------------------------------------
/// 4. NOTIFICATION TAP HANDLER
/// ---------------------------------------------------------------------------
void _handleNotificationTap(Map<String, dynamic> data) {
final type = data['type']?.toString();
print('Notification tapped type: $type');
if (type == 'tojoin') {
Get.toNamed('/join');
}
}
/// ---------------------------------------------------------------------------
/// 5. HTTP OVERRIDE (dev only remove in production)
/// ---------------------------------------------------------------------------
class MyHttpOverrides extends HttpOverrides {
@override
HttpClient createHttpClient(SecurityContext? context) {
return super.createHttpClient(context)
..badCertificateCallback = (cert, host, port) => true;
}
}
/// ---------------------------------------------------------------------------
/// 6. MAIN
/// ---------------------------------------------------------------------------
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent, // or your color
statusBarIconBrightness: Brightness.dark, // Android icons
statusBarBrightness: Brightness.light, // iOS icons
),
);
// Allow self-signed certs (dev only)
HttpOverrides.global = MyHttpOverrides();
await Firebase.initializeApp();
// ---------- LOCAL NOTIFICATIONS INITIALISATION ----------
const AndroidInitializationSettings androidInit =
AndroidInitializationSettings('@mipmap/ic_launcher');
const DarwinInitializationSettings iOSInit = DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
const InitializationSettings initSettings =
InitializationSettings(android: androidInit, iOS: iOSInit);
await flutterLocalNotificationsPlugin.initialize(
initSettings,
);
// Create Android channel (mandatory for Android 8+)
final androidPlugin = flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>();
await androidPlugin?.createNotificationChannel(channel);
// ---------- FCM ----------
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
ApiConfig.setLive(); // 👈 clean call
// Dependency injection
Get.put(ConnectivityController());
runApp(const MyApp());
}
/// ---------------------------------------------------------------------------
/// 7. APP WIDGET
/// ---------------------------------------------------------------------------
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'Nearlexpress Business',
debugShowCheckedModeBanner: false,
initialBinding: GlobalBinding(),
navigatorKey: MyHomePageOne.mNavigationState,
theme: ThemeData(
primaryColor: ColorConstants.primaryColor,
useMaterial3: false,
scaffoldBackgroundColor: Colors.grey.shade200,
appBarTheme: AppBarTheme(
iconTheme:
IconThemeData(color: ColorConstants.secondaryColor),
color: ColorConstants.secondaryColor,
elevation: 0,
titleTextStyle: TextStyle(
color: ColorConstants.secondaryColor,
fontSize: 18,
),
),
fontFamily: 'Lato',
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: const SafeArea(top: false, child: MyHomePageOne()),
);
}
}
/// ---------------------------------------------------------------------------
/// 8. HOME PAGE (FCM + UI logic)
/// ---------------------------------------------------------------------------
class MyHomePageOne extends StatefulWidget {
static final GlobalKey<NavigatorState> mNavigationState =
GlobalKey<NavigatorState>();
const MyHomePageOne({Key? key}) : super(key: key);
@override
State<MyHomePageOne> createState() => _MyHomePageOneState();
}
class _MyHomePageOneState extends State<MyHomePageOne> {
final AppConfigurationService _appConfig = AppConfigurationService();
String? _tenantFcmToken;
String? _tenantContact;
int? _moduleId;
int? _tenantId;
@override
void initState() {
super.initState();
_initApp();
}
Future<void> _initApp() async {
await _loadPrefs();
await _setupFCM();
await _getAppVersion();
_checkForUpdate(context);
_fetchLocation();
_appConfig.getAppConfig("${ApiConstants.configUrl}?configid=1");
LocalNotificationService.initialize(context);
}
Future<void> _loadPrefs() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_tenantFcmToken = prefs.getString('tenantFcmToken');
_tenantContact = prefs.getString('tenantContactNo');
_moduleId = prefs.getInt('moduleId');
_tenantId = prefs.getInt('tenantId');
});
}
Future<void> _setupFCM() async {
final settings = await FirebaseMessaging.instance.requestPermission(
alert: true,
badge: true,
sound: true,
);
print('FCM permission: ${settings.authorizationStatus}');
final token = await FirebaseMessaging.instance.getToken();
print('=== FCM TOKEN ===\n$token\n=================');
final prefs = await SharedPreferences.getInstance();
await prefs.setString('fcmToken', token!);
FirebaseMessaging.onMessage.listen((RemoteMessage msg) async {
print('FOREGROUND: ${msg.notification?.title}');
await _showLocalNotification(msg);
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage msg) {
print('OPENED FROM NOTIFICATION');
_handleNotificationTap(msg.data);
});
}
String currentVersion = '';
Future<void> _getAppVersion() async {
final packageInfo = await PackageInfo.fromPlatform();
currentVersion = packageInfo.version;
final prefs = await SharedPreferences.getInstance();
await prefs.setString('CurrentVersion', currentVersion);
logger.i('Current version: $currentVersion');
}
Future<void> _checkForUpdate(BuildContext context) async {
final newVersion = NewVersionPlus(
iOSId: '284882215',
androidId: "com.nearle.bond",
);
final status = await newVersion.getVersionStatus();
if (status != null && status.canUpdate) {
Get.to(() => UpdateAppPage(
mCurrentVersion: status.localVersion,
mUpdateVersion: status.storeVersion,
));
}
}
Future<void> _fetchLocation() async {
final url = Uri.http('ip-api.com', '/json');
try {
final response = await http.get(url);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
final country = data['countryCode'].toString();
final city = data['city'].toString();
final prefs = await SharedPreferences.getInstance();
await prefs.setString('location_Country', country);
await prefs.setString('MainCity', city);
await prefs.setString('location_CountryCode', country);
}
} catch (e) {
print('Location error: $e');
}
}
@override
Widget build(BuildContext context) {
return (_tenantFcmToken == null && _tenantContact == null)
? IntroScreenView()
: HomeView(selectedIndex: 0);
}
}