second commit
This commit is contained in:
347
lib/main.dart
347
lib/main.dart
@@ -1,5 +1,7 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:alp_animated_splashscreen/alp_animated_splashscreen.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
@@ -8,13 +10,11 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:in_app_update/in_app_update.dart';
|
||||
import 'package:nearledaily/constants/color_constants.dart';
|
||||
import 'package:nearledaily/view/authentication/app_update_view.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
import 'package:webview_flutter_android/webview_flutter_android.dart';
|
||||
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:new_version_plus/new_version_plus.dart';
|
||||
|
||||
@@ -33,18 +33,28 @@ import 'service/device_info/device_info.dart';
|
||||
import 'view/home_view.dart';
|
||||
import 'view/splash_view/splash_view.dart';
|
||||
|
||||
// -------------------------
|
||||
// FIREBASE BACKGROUND HANDLER
|
||||
// -------------------------
|
||||
@pragma('vm:entry-point')
|
||||
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||
await Firebase.initializeApp();
|
||||
await Firebase.initializeApp(
|
||||
options: DefaultFirebaseOptions.currentPlatform,
|
||||
);
|
||||
|
||||
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
|
||||
FlutterLocalNotificationsPlugin();
|
||||
|
||||
const AndroidInitializationSettings androidSettings =
|
||||
AndroidInitializationSettings('@mipmap/ic_launcher');
|
||||
|
||||
await flutterLocalNotificationsPlugin.initialize(
|
||||
const InitializationSettings(android: androidSettings),
|
||||
);
|
||||
|
||||
final androidPlugin = flutterLocalNotificationsPlugin
|
||||
.resolvePlatformSpecificImplementation<
|
||||
AndroidFlutterLocalNotificationsPlugin>();
|
||||
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>();
|
||||
|
||||
await androidPlugin?.createNotificationChannel(
|
||||
const AndroidNotificationChannel(
|
||||
'nearle_channel',
|
||||
@@ -57,56 +67,81 @@ Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||
final title = data['title'] as String?;
|
||||
final body = data['body'] as String?;
|
||||
|
||||
if (title == null || title.isEmpty) return;
|
||||
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
999,
|
||||
title,
|
||||
body?.isNotEmpty == true ? body : null,
|
||||
NotificationDetails(
|
||||
android: AndroidNotificationDetails(
|
||||
'nearle_channel',
|
||||
'Nearle Notifications',
|
||||
importance: Importance.max,
|
||||
priority: Priority.high,
|
||||
fullScreenIntent: true,
|
||||
playSound: true,
|
||||
enableVibration: true,
|
||||
largeIcon: const DrawableResourceAndroidBitmap('nearle_logo.jpeg'),
|
||||
if (title != null && title.isNotEmpty) {
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
999,
|
||||
title,
|
||||
body?.isNotEmpty == true ? body : null,
|
||||
NotificationDetails(
|
||||
android: AndroidNotificationDetails(
|
||||
'nearle_channel',
|
||||
'Nearle Notifications',
|
||||
importance: Importance.max,
|
||||
priority: Priority.high,
|
||||
fullScreenIntent: true,
|
||||
playSound: true,
|
||||
enableVibration: true,
|
||||
largeIcon: const DrawableResourceAndroidBitmap('nearle_logo.jpeg'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// LOCAL NOTIFICATIONS SETUP
|
||||
// -------------------------
|
||||
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
|
||||
FlutterLocalNotificationsPlugin();
|
||||
|
||||
Future<void> _setupLocalNotifications() async {
|
||||
// Android settings
|
||||
const AndroidInitializationSettings initializationSettingsAndroid =
|
||||
AndroidInitializationSettings('@mipmap/ic_launcher');
|
||||
const InitializationSettings initializationSettings =
|
||||
InitializationSettings(android: initializationSettingsAndroid);
|
||||
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
|
||||
|
||||
const AndroidNotificationChannel channel = AndroidNotificationChannel(
|
||||
'nearle_channel',
|
||||
'Nearle Notifications',
|
||||
description: 'High priority notifications',
|
||||
importance: Importance.max,
|
||||
playSound: true,
|
||||
enableVibration: true,
|
||||
// iOS/macOS settings
|
||||
const DarwinInitializationSettings initializationSettingsIOS =
|
||||
DarwinInitializationSettings(
|
||||
requestSoundPermission: true,
|
||||
requestBadgePermission: true,
|
||||
requestAlertPermission: true,
|
||||
);
|
||||
|
||||
await flutterLocalNotificationsPlugin
|
||||
.resolvePlatformSpecificImplementation<
|
||||
AndroidFlutterLocalNotificationsPlugin>()
|
||||
?.createNotificationChannel(channel);
|
||||
// Combine all platforms
|
||||
const InitializationSettings initializationSettings = InitializationSettings(
|
||||
android: initializationSettingsAndroid,
|
||||
iOS: initializationSettingsIOS,
|
||||
macOS: initializationSettingsIOS,
|
||||
);
|
||||
|
||||
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
|
||||
|
||||
// Android-only notification channel
|
||||
if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) {
|
||||
const AndroidNotificationChannel channel = AndroidNotificationChannel(
|
||||
'nearle_channel',
|
||||
'Nearle Notifications',
|
||||
description: 'High priority notifications',
|
||||
importance: Importance.max,
|
||||
playSound: true,
|
||||
enableVibration: true,
|
||||
);
|
||||
|
||||
await flutterLocalNotificationsPlugin
|
||||
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
|
||||
?.createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// ROUTE OBSERVER
|
||||
// -------------------------
|
||||
final RouteObserver<ModalRoute<void>> routeObserver =
|
||||
RouteObserver<ModalRoute<void>>();
|
||||
|
||||
// PRINT CURRENT + STORE VERSION (unchanged)
|
||||
// -------------------------
|
||||
// APP VERSION CHECK
|
||||
// -------------------------
|
||||
Future<void> _printAndCheckAppVersions() async {
|
||||
try {
|
||||
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
@@ -124,10 +159,7 @@ Future<void> _printAndCheckAppVersions() async {
|
||||
await prefs.setString('currentAppVersion', currentVersion);
|
||||
|
||||
if (defaultTargetPlatform == TargetPlatform.android) {
|
||||
final newVersion = NewVersionPlus(
|
||||
androidId: "com.nearle.gear",
|
||||
);
|
||||
|
||||
final newVersion = NewVersionPlus(androidId: "com.nearle.gear");
|
||||
final status = await newVersion.getVersionStatus();
|
||||
if (status != null) {
|
||||
print("PLAY STORE VERSION: ${status.storeVersion}");
|
||||
@@ -147,7 +179,7 @@ Future<void> _printAndCheckAppVersions() async {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXED: Now correctly detects real update from Play Store
|
||||
// Returns true if update available
|
||||
Future<bool> _checkForAppUpdate() async {
|
||||
if (defaultTargetPlatform != TargetPlatform.android) return false;
|
||||
|
||||
@@ -158,18 +190,24 @@ Future<bool> _checkForAppUpdate() async {
|
||||
if (status != null && status.canUpdate) {
|
||||
print("UPDATE DETECTED! Redirecting to AppUpdateView");
|
||||
print("Current: ${status.localVersion} → Store: ${status.storeVersion}");
|
||||
return true; // This will now go to AppUpdateView
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
print("Version check failed (continuing anyway): $e");
|
||||
print("Version check failed: $e");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// HANDLE NOTIFICATION TAP
|
||||
// -------------------------
|
||||
void _handleMessage(RemoteMessage message) {
|
||||
print("Notification tapped: ${message.data}");
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// ANIMATED SPLASH
|
||||
// -------------------------
|
||||
class AnimatedSplashWithNavigation extends StatefulWidget {
|
||||
final Widget nextScreen;
|
||||
const AnimatedSplashWithNavigation({super.key, required this.nextScreen});
|
||||
@@ -199,127 +237,158 @@ class _AnimatedSplashWithNavigationState
|
||||
backgroundcolor: Colors.white,
|
||||
foregroundcolor: ColorConstants.primaryColor,
|
||||
brandnamecolor: ColorConstants.primaryColor,
|
||||
// companyname: 'Nearle Daily',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// MAIN ENTRY POINT
|
||||
// -------------------------
|
||||
Future<void> main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
FlutterError.onError = (details) => FlutterError.dumpErrorToConsole(details);
|
||||
// Firebase initialize with options (iOS/web safe)
|
||||
await Firebase.initializeApp(
|
||||
options: DefaultFirebaseOptions.currentPlatform,
|
||||
);
|
||||
|
||||
await runZonedGuarded(() async {
|
||||
await _printAndCheckAppVersions();
|
||||
await _setupLocalNotifications();
|
||||
|
||||
await Firebase.initializeApp();
|
||||
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
|
||||
|
||||
await _printAndCheckAppVersions();
|
||||
SystemChrome.setSystemUIOverlayStyle(
|
||||
SystemUiOverlayStyle(statusBarColor: Colors.grey[200]),
|
||||
);
|
||||
|
||||
SystemChrome.setSystemUIOverlayStyle(
|
||||
SystemUiOverlayStyle(statusBarColor: Colors.grey[200]),
|
||||
);
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
prefs.setBool("firstTime", true);
|
||||
|
||||
await _setupLocalNotifications();
|
||||
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
|
||||
|
||||
RemoteMessage? initialMessage =
|
||||
await FirebaseMessaging.instance.getInitialMessage();
|
||||
if (initialMessage != null) _handleMessage(initialMessage);
|
||||
|
||||
FirebaseMessaging.onMessageOpenedApp.listen(_handleMessage);
|
||||
|
||||
if (!kIsWeb) {
|
||||
// -------------------------
|
||||
// NOTIFICATION PERMISSIONS & FCM TOKEN
|
||||
// -------------------------
|
||||
if (!kIsWeb) {
|
||||
if (Platform.isIOS) {
|
||||
NotificationSettings settings =
|
||||
await FirebaseMessaging.instance.requestPermission(
|
||||
alert: true,
|
||||
badge: true,
|
||||
sound: true,
|
||||
);
|
||||
}
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
prefs.setBool("firstTime", true);
|
||||
|
||||
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
|
||||
final data = message.data;
|
||||
final title = data['title'] ?? message.notification?.title ?? 'Nearle';
|
||||
final body = data['body'] ?? message.notification?.body ?? '';
|
||||
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
|
||||
print('User granted permission');
|
||||
|
||||
final ByteData jpegData =
|
||||
await rootBundle.load('assets/images/nearledaily.png');
|
||||
final Uint8List jpegBytes = jpegData.buffer.asUint8List();
|
||||
// Listen for token refresh (APNs ready)
|
||||
FirebaseMessaging.instance.onTokenRefresh.listen((newToken) async {
|
||||
print('FCM Token (iOS APNs ready): $newToken');
|
||||
await prefs.setString('fcmToken', newToken);
|
||||
});
|
||||
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||
title,
|
||||
body,
|
||||
NotificationDetails(
|
||||
android: AndroidNotificationDetails(
|
||||
'nearle_channel',
|
||||
'Nearle Notifications',
|
||||
importance: Importance.max,
|
||||
priority: Priority.high,
|
||||
fullScreenIntent: true,
|
||||
playSound: true,
|
||||
enableVibration: true,
|
||||
largeIcon: ByteArrayAndroidBitmap(jpegBytes),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
String? fcmToken = await FirebaseMessaging.instance.getToken();
|
||||
await prefs.setString('fcmToken', fcmToken ?? '');
|
||||
|
||||
if (defaultTargetPlatform == TargetPlatform.android) {
|
||||
final params = PlatformWebViewControllerCreationParams();
|
||||
AndroidWebViewController(params);
|
||||
}
|
||||
|
||||
ApiConstants.tenantCustomers = ApiConstants.tenantCustomerLive;
|
||||
ApiConstants.orderedtenantCustomers = ApiConstants.orderedtenantCustomerLive;
|
||||
ApiConstants.login = ApiConstants.loginLive;
|
||||
|
||||
Get.put(TenantController(), permanent: true);
|
||||
Get.lazyPut(() => AuthController(), fenix: true);
|
||||
Get.lazyPut(() => DashboardController(), fenix: true);
|
||||
Get.lazyPut(() => CartController(), fenix: true);
|
||||
Get.lazyPut(() => BottomNavController(), fenix: true);
|
||||
Get.lazyPut(() => OrderedTenantController(), fenix: true);
|
||||
Get.lazyPut(() => OrderController(), fenix: true);
|
||||
Get.lazyPut(() => FaqController(), fenix: true);
|
||||
Get.lazyPut(() => IntroScreenController(), fenix: true);
|
||||
|
||||
DeviceInfo deviceInfo = DeviceInfo();
|
||||
await deviceInfo.getDeviceInfo();
|
||||
|
||||
await SystemChrome.setPreferredOrientations([
|
||||
DeviceOrientation.portraitUp,
|
||||
DeviceOrientation.portraitDown,
|
||||
]);
|
||||
|
||||
final int? customerId = prefs.getInt('customerId');
|
||||
final String? contactNo = prefs.getString('contactno');
|
||||
bool updateAvailable = await _checkForAppUpdate(); // Now works correctly!
|
||||
|
||||
Widget nextScreen;
|
||||
if (updateAvailable) {
|
||||
nextScreen = const AppUpdateView();
|
||||
} else if (customerId != null && contactNo != null && contactNo.isNotEmpty) {
|
||||
nextScreen = BottomNavigation();
|
||||
// Optional: small delay initial attempt
|
||||
Future.delayed(const Duration(seconds: 2), () async {
|
||||
String? token = await FirebaseMessaging.instance.getToken();
|
||||
print('FCM Token initial attempt (iOS): $token');
|
||||
if (token != null) await prefs.setString('fcmToken', token);
|
||||
});
|
||||
} else {
|
||||
print('User declined notification permission');
|
||||
}
|
||||
} else {
|
||||
nextScreen = const SplashScreenView();
|
||||
// Android: get token immediately
|
||||
String? token = await FirebaseMessaging.instance.getToken();
|
||||
print('FCM Token (Android): $token');
|
||||
if (token != null) await prefs.setString('fcmToken', token);
|
||||
}
|
||||
SystemChrome.setSystemUIOverlayStyle(
|
||||
const SystemUiOverlayStyle(
|
||||
statusBarColor: Colors.white, // or transparent
|
||||
statusBarIconBrightness: Brightness.dark, // Android
|
||||
statusBarBrightness: Brightness.light, // iOS
|
||||
}
|
||||
|
||||
// Foreground notifications
|
||||
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
|
||||
final data = message.data;
|
||||
final title = data['title'] ?? message.notification?.title ?? 'Nearle';
|
||||
final body = data['body'] ?? message.notification?.body ?? '';
|
||||
|
||||
final ByteData jpegData =
|
||||
await rootBundle.load('assets/images/nearledaily.png');
|
||||
final Uint8List jpegBytes = jpegData.buffer.asUint8List();
|
||||
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||
title,
|
||||
body,
|
||||
NotificationDetails(
|
||||
android: AndroidNotificationDetails(
|
||||
'nearle_channel',
|
||||
'Nearle Notifications',
|
||||
importance: Importance.max,
|
||||
priority: Priority.high,
|
||||
fullScreenIntent: true,
|
||||
playSound: true,
|
||||
enableVibration: true,
|
||||
largeIcon: ByteArrayAndroidBitmap(jpegBytes),
|
||||
),
|
||||
iOS: const DarwinNotificationDetails(),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
runApp(MyApp(startScreen: nextScreen));
|
||||
}, (error, stack) => print('Error: $error'));
|
||||
// Android WebView Controller
|
||||
if (defaultTargetPlatform == TargetPlatform.android) {
|
||||
final params = PlatformWebViewControllerCreationParams();
|
||||
AndroidWebViewController(params);
|
||||
}
|
||||
|
||||
// API constants
|
||||
ApiConstants.tenantCustomers = ApiConstants.tenantCustomerLive;
|
||||
ApiConstants.orderedtenantCustomers = ApiConstants.orderedtenantCustomerLive;
|
||||
ApiConstants.login = ApiConstants.loginLive;
|
||||
|
||||
// Controllers
|
||||
Get.put(TenantController(), permanent: true);
|
||||
Get.lazyPut(() => AuthController(), fenix: true);
|
||||
Get.lazyPut(() => DashboardController(), fenix: true);
|
||||
Get.lazyPut(() => CartController(), fenix: true);
|
||||
Get.lazyPut(() => BottomNavController(), fenix: true);
|
||||
Get.lazyPut(() => OrderedTenantController(), fenix: true);
|
||||
Get.lazyPut(() => OrderController(), fenix: true);
|
||||
Get.lazyPut(() => FaqController(), fenix: true);
|
||||
Get.lazyPut(() => IntroScreenController(), fenix: true);
|
||||
|
||||
DeviceInfo deviceInfo = DeviceInfo();
|
||||
await deviceInfo.getDeviceInfo();
|
||||
|
||||
await SystemChrome.setPreferredOrientations([
|
||||
DeviceOrientation.portraitUp,
|
||||
DeviceOrientation.portraitDown,
|
||||
]);
|
||||
|
||||
final int? customerId = prefs.getInt('customerId');
|
||||
final String? contactNo = prefs.getString('contactno');
|
||||
bool updateAvailable = await _checkForAppUpdate();
|
||||
|
||||
Widget nextScreen;
|
||||
if (updateAvailable) {
|
||||
nextScreen = const AppUpdateView();
|
||||
} else if (customerId != null && contactNo != null && contactNo.isNotEmpty) {
|
||||
nextScreen = BottomNavigation();
|
||||
} else {
|
||||
nextScreen = const SplashScreenView();
|
||||
}
|
||||
|
||||
SystemChrome.setSystemUIOverlayStyle(
|
||||
const SystemUiOverlayStyle(
|
||||
statusBarColor: Colors.white,
|
||||
statusBarIconBrightness: Brightness.dark,
|
||||
statusBarBrightness: Brightness.light,
|
||||
),
|
||||
);
|
||||
|
||||
runApp(MyApp(startScreen: nextScreen));
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// MAIN APP
|
||||
// -------------------------
|
||||
class MyApp extends StatelessWidget {
|
||||
final Widget startScreen;
|
||||
const MyApp({super.key, required this.startScreen});
|
||||
|
||||
Reference in New Issue
Block a user