diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index e9bc7171..6168f9ce 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -31,8 +31,7 @@
android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE"
tools:node="remove" />
+ android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" />
@@ -84,6 +83,10 @@
+
+
+
+
+
+
diff --git a/lib/locator.dart b/lib/locator.dart
index 61ed983b..a85a5a9d 100644
--- a/lib/locator.dart
+++ b/lib/locator.dart
@@ -151,8 +151,13 @@ import 'services/pharmacy_services/product_detail_service.dart';
GetIt locator = GetIt.instance;
+void setupNavigator(){
+ locator.registerSingleton( NavigationService());
+}
///di
void setupLocator() {
+ setupNavigator();
+
/// Others
locator.registerLazySingleton(() => FlutterLocalNotificationsPlugin());
@@ -168,7 +173,6 @@ void setupLocator() {
locator.registerLazySingleton(() => InsuranceCardService());
locator.registerLazySingleton(() => VitalSignService());
locator.registerLazySingleton(() => MedicalService());
- locator.registerLazySingleton(() => NavigationService());
locator.registerLazySingleton(() => ReportsService());
locator.registerLazySingleton(() => DashboardService());
locator.registerLazySingleton(() => AppointmentRateService());
diff --git a/lib/main.dart b/lib/main.dart
index 03ac65fc..01a4f21b 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -6,6 +6,10 @@ import 'package:diplomaticquarterapp/config/config.dart';
import 'package:diplomaticquarterapp/core/viewModels/PharmacyPagesViewModel.dart';
import 'package:diplomaticquarterapp/core/viewModels/dashboard_view_model.dart';
import 'package:diplomaticquarterapp/models/Appointments/toDoCountProviderModel.dart';
+import 'package:diplomaticquarterapp/pages/conference/widgets/platform_exception_alert_dialog.dart';
+import 'package:diplomaticquarterapp/pages/conference/zoom/call_screen.dart';
+import 'package:diplomaticquarterapp/pages/landing/landing_page.dart';
+import 'package:diplomaticquarterapp/pages/webRTC/OpenTok/OpenTok.dart';
import 'package:diplomaticquarterapp/routes.dart';
import 'package:diplomaticquarterapp/services/payfort_services/payfort_view_model.dart';
import 'package:diplomaticquarterapp/services/robo_search/event_provider.dart';
@@ -14,6 +18,7 @@ import 'package:diplomaticquarterapp/theme/theme_notifier.dart';
import 'package:diplomaticquarterapp/theme/theme_value.dart';
import 'package:diplomaticquarterapp/uitl/DeepLinkHandler.dart';
import 'package:diplomaticquarterapp/uitl/PlatformBridge.dart';
+import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart';
import 'package:diplomaticquarterapp/uitl/navigation_service.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:firebase_core/firebase_core.dart';
@@ -25,6 +30,7 @@ import 'config/size_config.dart';
import 'core/viewModels/pharmacyModule/OrderPreviewViewModel.dart';
import 'core/viewModels/project_view_model.dart';
import 'locator.dart';
+import 'models/LiveCare/IncomingCallData.dart';
import 'pages/pharmacies/compare-list.dart';
void main() async {
@@ -102,13 +108,67 @@ class _MyApp extends State {
super.dispose();
}
-
+ late final AppLifecycleListener _listener;
Future initDeepLinks() async {
// Handle links
_linkSubscription = AppLinks().uriLinkStream.listen((uri) {
debugPrint('onAppLink: $uri');
openAppLink(uri);
});
+ _listener = AppLifecycleListener(
+ onShow: () => {},
+ onResume: () =>{},
+ onHide: () => {},
+ onInactive: () => {},
+ onPause: () => {},
+ onDetach: () => {},
+ onRestart: () => {},
+ onStateChange: (state) async {
+ if(state == AppLifecycleState.resumed) {
+ await Future.delayed(Duration(seconds: 5));
+ _handleTransition();
+ }
+ },
+ );
+ _handleTransition(shouldApplyDelay: true);
+ }
+ void _handleTransition({bool shouldApplyDelay = false}) async {
+ var data = await AppSharedPreferences().getObject('call_data');
+ if(data == null) return;
+ await AppSharedPreferences().remove('call_data');
+ if(shouldApplyDelay)
+ await Future.delayed(Duration(seconds: 5));
+ var incomingcallData= IncomingCallData.fromJson(data);
+ openCallPage(incomingcallData);
+ }
+ Future openCallPage(IncomingCallData incomingCallData) async {
+ try {
+ LandingPage.isOpenCallPage = false;
+
+ if (incomingCallData!.background == "0") {
+ // Zoom Call Page
+ // Navigator.of(context).pop();
+ Navigator.pushNamed(
+ locator().navigatorKey.currentContext!,
+ "zoom_call_page",
+ arguments: CallArguments(incomingCallData!.sessionId!, "123", "Patient", "40", "0", false, int.parse(incomingCallData!.appointmentNo!)),
+ );
+ } else {
+ // OpenTok Call Page
+ await Navigator.of(locator().navigatorKey.currentContext!).push(
+ MaterialPageRoute(
+ builder: (BuildContext context) {
+ return OpenTokConnectCallPage(apiKey: OPENTOK_API_KEY, sessionId: incomingCallData!.sessionId!, token: incomingCallData!.token!);
+ },
+ ),
+ );
+ }
+ } catch (err) {
+ print(err);
+ await PlatformExceptionAlertDialog(
+ exception: Exception(err),
+ ).show(context);
+ }
}
void openAppLink(Uri uri) {
diff --git a/lib/pages/landing/landing_page.dart b/lib/pages/landing/landing_page.dart
index ffc9fec5..9b839ad8 100644
--- a/lib/pages/landing/landing_page.dart
+++ b/lib/pages/landing/landing_page.dart
@@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:io';
+import 'package:device_info_plus/device_info_plus.dart';
import 'package:diplomaticquarterapp/config/config.dart';
import 'package:diplomaticquarterapp/config/shared_pref_kay.dart';
import 'package:diplomaticquarterapp/core/model/ImagesInfo.dart';
@@ -37,6 +38,7 @@ import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart';
import 'package:diplomaticquarterapp/widgets/others/not_auh_page.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
// import 'package:flutter_app_icon_badge/flutter_app_icon_badge.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_svg/flutter_svg.dart';
@@ -647,6 +649,15 @@ class _LandingPageState extends State with WidgetsBindingObserver {
void checkUserStatus(token) async {
await PushNotificationHandler.getInstance().requestPermissions();
+ if (Platform.isAndroid) {
+ final deviceInfo = DeviceInfoPlugin();
+ final androidInfo = await deviceInfo.androidInfo;
+
+ int sdkInt = androidInfo.version.sdkInt ?? 0;
+ if(sdkInt>= 33){
+ await FlutterCallkitIncoming.requestFullIntentPermission();
+ }
+ }
// authService.selectDeviceImei(token).then((SelectDeviceIMEIRES? value) => setUserValues(value));
if (authenticatedUserObject.isLogin) {
var data = AuthenticatedUser.fromJson(await sharedPref.getObject(USER_PROFILE));
diff --git a/lib/splashPage.dart b/lib/splashPage.dart
index 3d9b2927..ba98c3c0 100644
--- a/lib/splashPage.dart
+++ b/lib/splashPage.dart
@@ -81,9 +81,11 @@ class _SplashScreenState extends State {
projectProvider.setProjectsDetailList(_privilegeService.projectDetailListModel);
double lat = await AppSharedPreferences().getDouble(USER_LAT) ?? 0.0;
double long = await AppSharedPreferences().getDouble(USER_LONG) ?? 0.0;
+ var callData = await AppSharedPreferences().getObject('call_data');
AppSharedPreferences().clear(); // Clearing Shared Preferences On App Launch
await AppSharedPreferences().setDouble(USER_LAT, lat);
await AppSharedPreferences().setDouble(USER_LONG, long);
+ await AppSharedPreferences().setObject('call_data', callData);
AppSharedPreferences().setString(APP_LANGUAGE, projectProvider.isArabic ? "ar" : "en");
var themeNotifier = Provider.of(context, listen: false);
themeNotifier.setTheme(defaultTheme(fontName: projectProvider.isArabic ? 'Cairo' : 'Poppins'));
diff --git a/lib/uitl/push-notification-handler.dart b/lib/uitl/push-notification-handler.dart
index c6ae36d3..c89ede14 100644
--- a/lib/uitl/push-notification-handler.dart
+++ b/lib/uitl/push-notification-handler.dart
@@ -1,7 +1,8 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
-
+import 'package:flutter_callkit_incoming/entities/call_event.dart';
+import 'package:uuid/uuid.dart';
import 'package:diplomaticquarterapp/config/config.dart';
import 'package:diplomaticquarterapp/config/shared_pref_kay.dart';
import 'package:diplomaticquarterapp/core/model/notifications/get_notifications_response_model.dart';
@@ -22,6 +23,12 @@ import 'package:firebase_messaging/firebase_messaging.dart' as fir;
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_callkit_incoming/entities/android_params.dart';
+import 'package:flutter_callkit_incoming/entities/call_kit_params.dart';
+import 'package:flutter_callkit_incoming/entities/ios_params.dart';
+import 'package:flutter_callkit_incoming/entities/notification_params.dart';
+import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
+import 'package:flutter_incoming_call/flutter_incoming_call.dart';
// import 'package:flutter_ios_voip_kit/call_state_type.dart';
// import 'package:flutter_ios_voip_kit/flutter_ios_voip_kit.dart';
@@ -31,6 +38,7 @@ import 'package:huawei_hmsavailability/huawei_hmsavailability.dart';
import 'package:huawei_push/huawei_push.dart' as h_push;
import 'package:permission_handler/permission_handler.dart';
+import '../pages/conference/widgets/platform_exception_alert_dialog.dart';
import 'app_shared_preferences.dart';
import 'navigation_service.dart';
@@ -44,7 +52,6 @@ Future backgroundMessageHandler(dynamic message) async {
message_ = toFirebaseRemoteMessage(message);
h_push.Push.localNotification({h_push.HMSLocalNotificationAttr.TITLE: 'Background Message', h_push.HMSLocalNotificationAttr.MESSAGE: "By: BackgroundMessageHandler"});
}
-
if (message.data != null && (message.data['is_call'] == 'true' || message.data['is_call'] == true)) {
// showCallkitIncoming(message);
_incomingCall(message.data);
@@ -162,18 +169,159 @@ callPage(String sessionID, String token) async {
_incomingCall(Map data) async {
LandingPage.incomingCallData = IncomingCallData.fromJson(data);
+ var dataItem = await AppSharedPreferences().getObject('call_data');
+ if(dataItem != null ) return; // to stop repeated attempt to invoke the call
if (LandingPage.isOpenCallPage == false) {
LandingPage.isOpenCallPage = true;
- final bool permited = await AppPermission.askVideoCallPermission(currentContext!);
- if (permited)
- await NavigationService.navigateToPage(
- IncomingCall(incomingCallData: LandingPage.incomingCallData),
- );
+ WidgetsFlutterBinding.ensureInitialized();
+ var _currentUuid = Uuid().v4();
+ CallKitParams callKitParams = CallKitParams(
+ id: _currentUuid,
+ nameCaller: "${LandingPage.incomingCallData.doctorname}"
+ "\n Dr Sulaiman Al Habib \n ${LandingPage.incomingCallData.clinicname}",
+ appName: 'Dr Sulaiman Al Habib',
+ avatar: '',
+ handle: LandingPage.incomingCallData.name,
+ type: 0,
+ textAccept: 'Accept',
+ textDecline: 'Decline',
+ missedCallNotification: NotificationParams(
+ showNotification: true,
+ isShowCallback: false,
+ subtitle: 'Missed call',
+ callbackText: '',
+ ),
+ callingNotification: const NotificationParams(
+ showNotification: true,
+ isShowCallback: true,
+ subtitle: 'Calling...',
+ callbackText: 'Hang Up',
+ ),
+ duration: 30000,
+ extra: {'userId': '1a2b3c4d'},
+ headers: {'apiKey': 'Abc@123!', 'platform': 'flutter'},
+ android: const AndroidParams(
+ isCustomNotification: true,
+ isShowLogo: false,
+ logoUrl: '',
+ ringtonePath: 'system_ringtone_default',
+ backgroundColor: '#D02127',
+ backgroundUrl: '',
+ actionColor: '#4CAF50',
+ textColor: '#ffffff',
+ incomingCallNotificationChannelName: "Incoming Call",
+ missedCallNotificationChannelName: "Missed Call",
+ isShowCallID: false
+ ),
+ ios: IOSParams(
+ iconName: 'Dr Sulaiman Al Habib',
+ handleType: 'generic',
+ supportsVideo: true,
+ maximumCallGroups: 2,
+ maximumCallsPerCallGroup: 1,
+ audioSessionMode: 'default',
+ audioSessionActive: true,
+ audioSessionPreferredSampleRate: 44100.0,
+ audioSessionPreferredIOBufferDuration: 0.005,
+ supportsDTMF: true,
+ supportsHolding: true,
+ supportsGrouping: false,
+ supportsUngrouping: false,
+ ringtonePath: 'system_ringtone_default',
+ ),
+ );
+ await FlutterCallkitIncoming.showCallkitIncoming(callKitParams);
+ try {
+ FlutterCallkitIncoming.onEvent.listen((event) async {
+ switch (event!.event) {
+ case Event.actionCallIncoming:
+
+ break;
+ case Event.actionCallStart:
+
+ break;
+ case Event.actionCallAccept:
+ await FlutterCallkitIncoming.endAllCalls();
+ try {
+ openCallPage(LandingPage.incomingCallData,
+ locator().navigatorKey
+ .currentContext!);
+ } catch (e) {
+ await AppSharedPreferences().setObject('call_data', data);
+ var data1 = await AppSharedPreferences().getObject('call_data');
+ }
+
+ break;
+ case Event.actionCallDecline:
+
+ break;
+ case Event.actionCallEnded:
+
+ break;
+ case Event.actionCallTimeout:
+
+ break;
+ case Event.actionCallCallback:
+ break;
+ case Event.actionCallToggleHold:
+ break;
+ case Event.actionCallToggleMute:
+ break;
+ case Event.actionCallToggleDmtf:
+ break;
+ case Event.actionCallToggleGroup:
+ break;
+ case Event.actionCallToggleAudioSession:
+ break;
+ case Event.actionDidUpdateDevicePushTokenVoip:
+ break;
+ case Event.actionCallCustom:
+ break;
+ }
+ });
+ } on Exception catch (e) {
+ print(e);
+ }
+ }
+ LandingPage.isOpenCallPage = false;
+ await Future.delayed(Duration(milliseconds: 500));
+}
+Future openCallPage(IncomingCallData incomingCallData, BuildContext context) async {
+ try {
LandingPage.isOpenCallPage = false;
+
+ if (incomingCallData!.background == "0") {
+ // Zoom Call Page
+ // Navigator.of(context).pop();
+ Navigator.pushReplacementNamed(
+ context,
+ "zoom_call_page",
+ arguments: CallArguments(incomingCallData!.sessionId!, "123", "Patient", "40", "0", false, int.parse(incomingCallData!.appointmentNo!)),
+ );
+ } else {
+ // OpenTok Call Page
+ await Navigator.of(context).pushReplacement(
+ MaterialPageRoute(
+ // fullscreenDialog: true,
+ builder: (BuildContext context) {
+ // final caller = widget.incomingCallData.callerID;
+ // final receiver = widget.incomingCallData.receiverID;
+ // final host = widget.incomingCallData.server;
+ // if(widget.incomingCallData.isWebRTC == "true"){
+ // return StartVideoCall(caller: caller, receiver: receiver, iAmCaller: false, host: host);
+ // }else{
+ return OpenTokConnectCallPage(apiKey: OPENTOK_API_KEY, sessionId: incomingCallData!.sessionId!, token: incomingCallData!.token!);
+ },
+ ),
+ );
+ }
+ } catch (err) {
+ print(err);
+ await PlatformExceptionAlertDialog(
+ exception: Exception(err),
+ ).show(context);
}
- await Future.delayed(Duration(milliseconds: 500));
- await AppSharedPreferences().remove('call_data');
}
class PushNotificationHandler {
@@ -382,7 +530,6 @@ class PushNotificationHandler {
// });
// }
- FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler);
}
newMessage(RemoteMessage remoteMessage) async {
@@ -440,10 +587,6 @@ class PushNotificationHandler {
}
onResume() async {
- var call_data = await AppSharedPreferences().getObject('call_data');
- if (call_data != null) {
- _incomingCall(call_data);
- }
}
Future requestPermissions() async {
diff --git a/pubspec.yaml b/pubspec.yaml
index dc3da8dc..9986d6a3 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -66,7 +66,7 @@ dependencies:
shared_preferences: ^2.0.0
# flutter_flexible_toast: ^0.1.4
fluttertoast: ^8.0.8
- firebase_messaging: 14.1.0
+ firebase_messaging: 14.7.7
firebase_analytics: ^10.0.5
# Progress bar
flutter_progress_hud: ^2.0.2
@@ -75,6 +75,7 @@ dependencies:
# Icons
font_awesome_flutter: any
cupertino_icons: ^1.0.0
+ flutter_callkit_incoming: ^2.5.3-alpha
# Image Attachments
image_picker: ^1.0.4
@@ -88,6 +89,7 @@ dependencies:
# UI Reqs
expandable: ^5.0.1
+ uuid: ^3.0.7
# charts
flutter_charts: ^0.5.2