diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index e326d8f..e7b7e3b 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -50,6 +50,7 @@ This app requires photo library access to select image as document & upload it. UIBackgroundModes + fetch remote-notification FirebaseAppDelegateProxyEnabled diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 731a45e..2b05306 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/request_detail_model.dart'; import 'package:mohem_flutter_app/models/member_information_list_model.dart'; @@ -180,12 +181,4 @@ class AppState { bool cancelRequestTrancsection = true; - - String? _deviceNotificationToken; - - String? get deviceNotificationToken => _deviceNotificationToken; - - set deviceNotificationToken(String? deviceNotificationToken) { - _deviceNotificationToken = deviceNotificationToken; - } } diff --git a/lib/classes/notifications.dart b/lib/classes/notifications.dart index 336b87c..cebf76d 100644 --- a/lib/classes/notifications.dart +++ b/lib/classes/notifications.dart @@ -1,12 +1,15 @@ import 'dart:convert'; import 'dart:io'; import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:permission_handler/permission_handler.dart'; +import 'package:firebase_core/firebase_core.dart'; -//final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); - +final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); class AppNotifications { static final AppNotifications _instance = AppNotifications._internal(); @@ -15,45 +18,66 @@ class AppNotifications { factory AppNotifications() => _instance; - // Future requestPermissions() async { - // if (Platform.isIOS) { - // await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions(alert: true, badge: true, sound: true); - // } else if (Platform.isAndroid) { - // AndroidFlutterLocalNotificationsPlugin? androidImplementation = flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation(); - // bool? granted = await androidImplementation?.requestPermission(); - // if (granted == false) { - // print("-------------------- Permission Granted ------------------------"); - // print(granted); - // await Permission.notification.request(); - // } - // } - // } - - // Future isAndroidPermGranted() async { - // if (Platform.isAndroid) { - // bool granted = await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.areNotificationsEnabled() ?? false; - // } - // } - - void initNotification(String? firebaseToken) async { - // await requestPermissions(); + Future requestPermissions() async { + if (Platform.isIOS) { + await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions(alert: true, badge: true, sound: true); + } else if (Platform.isAndroid) { + AndroidFlutterLocalNotificationsPlugin? androidImplementation = flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation(); + bool? granted = await androidImplementation?.requestPermission(); + if (granted == false) { + if (kDebugMode) { + print("-------------------- Permission Granted ------------------------"); + print(granted); + } + await Permission.notification.request(); + } + } + } + + void init(String? firebaseToken) async { + await requestPermissions(); AppState().setDeviceToken = firebaseToken; - // await Permission.notification.isDenied.then((value) { - // if (value) { - // Permission.notification.request(); - // } - // }); + await Permission.notification.isDenied.then((bool value) { + if (value) { + Permission.notification.request(); + } + }); RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage(); + if (initialMessage != null) _handleMessage(initialMessage); FirebaseMessaging.onMessage.listen((RemoteMessage message) { if (message.notification != null) _handleMessage(message); }); - FirebaseMessaging.onMessageOpenedApp.listen(_handleMessage); + + FirebaseMessaging.onMessageOpenedApp.listen(_handleOpenApp); + + FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler); + + FirebaseMessaging.instance.onTokenRefresh.listen((String token) { + AppState().setDeviceToken = token; + }); } void _handleMessage(RemoteMessage message) { - print("Handle Message"); - logger.w(json.encode(message)); + Utils.saveStringFromPrefs("isAppOpendByChat", "true"); + } + + void _handleOpenApp(RemoteMessage message) { + Utils.saveStringFromPrefs("isAppOpendByChat", "true"); + Utils.saveStringFromPrefs("notificationData", message.data["user_chat_history_response"].toString()); } } + +AndroidNotificationChannel channel = const AndroidNotificationChannel( + "high_importance_channel", + "High Importance Notifications", + importance: Importance.high, +); + +Future backgroundMessageHandler(RemoteMessage message) async { + await Firebase.initializeApp(); + Utils.saveStringFromPrefs("isAppOpendByChat", "true"); + logger.w(message.data["user_chat_history_response"]); + Utils.saveStringFromPrefs("notificationData", message.data["user_chat_history_response"].toString()); +} diff --git a/lib/classes/push-notification-handler.dart b/lib/classes/push-notification-handler.dart deleted file mode 100644 index b95ceb2..0000000 --- a/lib/classes/push-notification-handler.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:firebase_messaging/firebase_messaging.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:mohem_flutter_app/app_state/app_state.dart'; - -// |--> Push Notification Background -Future backgroundMessageHandler(message) async { - print("Firebase backgroundMessageHandler!!!"); -} - -class PushNotificationHandler { - final BuildContext context; - static PushNotificationHandler? _instance; - - PushNotificationHandler(this.context) { - PushNotificationHandler._instance = this; - } - - static PushNotificationHandler getInstance() => _instance!; - - void init() async { - FirebaseMessaging.onMessage.listen((RemoteMessage message) async { - if (Platform.isIOS) { - await Future.delayed(Duration(milliseconds: 3000)).then((value) { - newMessage(message); - }); - } else { - newMessage(message); - } - }); - - FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async { - if (Platform.isIOS) { - await Future.delayed(Duration(milliseconds: 3000)).then((value) { - newMessage(message); - }); - } else { - newMessage(message); - } - }); - - FirebaseMessaging.instance.onTokenRefresh.listen((fcm_token) { - print("Push Notification onTokenRefresh: " + fcm_token); - AppState().setDeviceToken = fcm_token; - }); - - FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler); - } - - void newMessage(RemoteMessage remoteMessage) async { - print("Remote Message: " + remoteMessage.data.toString()); - if (remoteMessage.data.isEmpty) { - return; - } - } -} diff --git a/lib/provider/chat_provider_model.dart b/lib/provider/chat_provider_model.dart index 71d7ccb..08b148d 100644 --- a/lib/provider/chat_provider_model.dart +++ b/lib/provider/chat_provider_model.dart @@ -16,6 +16,7 @@ import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/encryption.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/chat/chat_user_image_model.dart'; import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; @@ -23,6 +24,7 @@ import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.da import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as userLoginToken; import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav; import 'package:mohem_flutter_app/models/my_team/get_employee_subordinates_list.dart'; +import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart'; import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; import 'package:mohem_flutter_app/widgets/image_picker.dart'; import 'package:open_file/open_file.dart'; @@ -120,14 +122,12 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } - void getUserRecentChats() async { + Future getUserRecentChats() async { ChatUserModel recentChat = await ChatApiClient().getRecentChats(); ChatUserModel favUList = await ChatApiClient().getFavUsers(); if (favUList.response != null && recentChat.response != null) { favUsersList = favUList.response!; - favUsersList.sort( - (ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase()), - ); + favUsersList.sort((ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase())); for (dynamic user in recentChat.response!) { for (dynamic favUser in favUList.response!) { if (user.id == favUser.id) { @@ -137,16 +137,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } pChatHistory = recentChat.response ?? []; - pChatHistory!.sort( - (ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase()), - ); + pChatHistory!.sort((ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase())); searchedChats = pChatHistory; isLoading = false; - await invokeUserChatHistoryNotDeliveredAsync( - userId: int.parse( - AppState().chatDetails!.response!.id.toString(), - ), - ); + await invokeUserChatHistoryNotDeliveredAsync(userId: int.parse(AppState().chatDetails!.response!.id.toString())); sort(); notifyListeners(); if (searchedChats!.isNotEmpty || favUsersList.isNotEmpty) { @@ -325,12 +319,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { user.userStatus = items.first["userStatus"]; } } - if (teamMembersList != null) { - if (teamMembersList.isNotEmpty) { - for (ChatUser user in teamMembersList!) { - if (user.id == items.first["id"]) { - user.userStatus = items.first["userStatus"]; - } + if (teamMembersList.isNotEmpty) { + for (ChatUser user in teamMembersList!) { + if (user.id == items.first["id"]) { + user.userStatus = items.first["userStatus"]; } } } @@ -1457,4 +1449,21 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } return Material.TextDirection.ltr; } + + void openChatByNoti(BuildContext context) async { + SingleUserChatModel nUser = SingleUserChatModel.fromJson( + jsonDecode(await Utils.getStringFromPrefs("notificationData")), + ); + Utils.saveStringFromPrefs("isAppOpendByChat", "false"); + Utils.saveStringFromPrefs("notificationData", "null"); + Future.delayed(const Duration(seconds: 1)); + for (ChatUser user in searchedChats!) { + if (user.id == nUser.targetUserId) { + Navigator.pushNamed(context, AppRoutes.chatDetailed, arguments: ChatDetailedScreenParams(user, false)); + return; + } else { + openChatByNoti(context); + } + } + } } diff --git a/lib/ui/chat/chat_home.dart b/lib/ui/chat/chat_home.dart index bbb3048..2e23254 100644 --- a/lib/ui/chat/chat_home.dart +++ b/lib/ui/chat/chat_home.dart @@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; @@ -50,7 +51,13 @@ class _ChatHomeState extends State { } if (data.searchedChats == null || data.searchedChats!.isEmpty) { data.isLoading = true; - data.getUserRecentChats(); + data.getUserRecentChats().whenComplete(() async { + String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat"); + String notificationData = await Utils.getStringFromPrefs("notificationData"); + if (isAppOpendByChat != "null" || isAppOpendByChat == "true" && notificationData != "null") { + data.openChatByNoti(context); + } + }); } } diff --git a/lib/ui/chat/chat_home_screen.dart b/lib/ui/chat/chat_home_screen.dart index aa47053..04d7c2e 100644 --- a/lib/ui/chat/chat_home_screen.dart +++ b/lib/ui/chat/chat_home_screen.dart @@ -26,14 +26,10 @@ class ChatHomeScreen extends StatefulWidget { class _ChatHomeScreenState extends State { TextEditingController search = TextEditingController(); - late ChatProviderModel data; - - final RefreshController _rc = RefreshController(initialRefresh: false); @override void initState() { super.initState(); - data = Provider.of(context, listen: false); } @override diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 8f12a4e..af6f903 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'dart:ui' as ui; import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_countdown_timer/flutter_countdown_timer.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -15,6 +16,7 @@ import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; @@ -61,7 +63,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb marathonProvider = Provider.of(context, listen: false); cProvider = Provider.of(context, listen: false); _bHubCon(); - _onRefresh(); + _onRefresh(true); }); } @@ -91,15 +93,41 @@ class _DashboardScreenState extends State with WidgetsBindingOb } void _bHubCon() { - cProvider.getUserAutoLoginToken().whenComplete(() { - cProvider.buildHubConnection(); - Future.delayed(const Duration(seconds: 2), () { - cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!); - }); + cProvider.getUserAutoLoginToken().whenComplete(() async { + String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat"); + if (isAppOpendByChat != null && isAppOpendByChat == "true") { + Utils.showLoading(context); + cProvider.buildHubConnection(); + Future.delayed(const Duration(seconds: 2), () async { + cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!); + gotoChat(context); + }); + } else { + cProvider.buildHubConnection(); + Future.delayed(const Duration(seconds: 2), () { + cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!); + }); + } }); } - void _onRefresh() async { + Future checkHubCon() async { + if (chatHubConnection.state == HubConnectionState.Connected) { + await chatHubConnection.stop(); + await chatHubConnection.start(); + } else if (chatHubConnection.state != HubConnectionState.Connected) { + await chatHubConnection.start(); + } + } + + void gotoChat(BuildContext context) async { + if (chatHubConnection.state == HubConnectionState.Connected) { + Utils.hideLoading(context); + Navigator.pushNamed(context, AppRoutes.chat); + } + } + + void _onRefresh(bool isFromInit) async { data.initProvider(); // data.getITGNotification().then((value) { // print("--------------------detail_1-----------------"); @@ -114,6 +142,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb data.fetchMenuEntries(); data.getCategoryOffersListAPI(context); marathonProvider.getMarathonDetailsFromApi(); + if (!isFromInit) checkHubCon(); _refreshController.refreshCompleted(); } @@ -213,7 +242,9 @@ class _DashboardScreenState extends State with WidgetsBindingOb color: MyColors.gradiantEndColor, ), controller: _refreshController, - onRefresh: _onRefresh, + onRefresh: () { + _onRefresh(false); + }, child: SingleChildScrollView( child: Column( children: [ diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index 2dfd63a..470a57d 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -13,7 +13,6 @@ import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/notifications.dart'; -import 'package:mohem_flutter_app/classes/push-notification-handler.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; @@ -98,7 +97,7 @@ class _LoginScreenState extends State { await Firebase.initializeApp(); _firebaseMessaging = FirebaseMessaging.instance; firebaseToken = await _firebaseMessaging.getToken(); - AppNotifications().initNotification(firebaseToken); + AppNotifications().init(firebaseToken); loginInfo = await LoginApiClient().getMobileLoginInfoNEW(firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); if (loginInfo == null) { await checkPrefs(); diff --git a/pubspec.yaml b/pubspec.yaml index e78da23..def761b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -92,7 +92,8 @@ dependencies: swipe_to: ^1.0.2 flutter_webrtc: ^0.9.16 camera: ^0.10.0+4 - #flutter_local_notifications: any + flutter_local_notifications: any + firebase_analytics: any #Chat Voice Message Recoding & Play audio_waveforms: ^0.1.5+1