diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index f5b408d8..762c964d 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -42,8 +42,8 @@
tools:node="remove" />
-
-
+
+
diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json
index bdedca05..d079001a 100644
--- a/assets/langs/ar-SA.json
+++ b/assets/langs/ar-SA.json
@@ -1289,7 +1289,7 @@
"quickLinks": "روابط سريعة",
"viewMedicalFileLandingPage": "عرض الملف الطبي",
"immediateLiveCareRequest": "طلب لايف كير فوري",
- "yourTurnIsAfterPatients": "دورك بعد {count} مريض. يرجى الانتظار حتى يحين دورك، وسيناديك الطبيب قريباً.",
+ "yourTurnIsAfterPatients": "أمامك {count} مريض. سيقوم الطبيب بالتواصل معكً.",
"dontHaveHHCOrders": "ليس لديك أي أوامر رعاية صحية منزلية حتى الآن.",
"hhcOrders": "أوامر الرعاية الصحية المنزلية",
"requestedServices": "الخدمات المطلوبة",
@@ -1826,6 +1826,7 @@
"selectFamilyFile": "اختيار ",
"ancillaryOrdersListNew": "طلبات غير مكتملة",
"medicalReportNew": "التقارير الطبية",
+ "livecarePendingReuqestNew": "انتظار الطبيب"
"medicinesAnalysis": "تحليل الأدوية",
"importantWarnings": "تحذيرات مهمة",
"medicineInteractions": "تفاعلات الأدوية",
diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json
index 57a57956..4eb3df8e 100644
--- a/assets/langs/en-US.json
+++ b/assets/langs/en-US.json
@@ -1279,7 +1279,7 @@
"quickLinks": "Quick Links",
"viewMedicalFileLandingPage": "View medical file",
"immediateLiveCareRequest": "Immediate LiveCare Request",
- "yourTurnIsAfterPatients": "Your turn is after {count} patients. Please wait for your turn, The doctor will call you shortly.",
+ "yourTurnIsAfterPatients": "There are {count} patients ahead of you. The doctor will call you shortly.",
"dontHaveHHCOrders": "You don't have any Home Health Care orders yet.",
"hhcOrders": "HHC Orders",
"requestedServices": "Requested Services",
@@ -1816,6 +1816,7 @@
"selectFamilyFile": "Select",
"ancillaryOrdersListNew": "Ancillary Orders List",
"medicalReportNew": "Medical Report",
+ "livecarePendingReuqestNew": "Live Care Pending Request"
"medicinesAnalysis": "Medicines Analysis",
"importantWarnings": "Important Warnings",
"medicineInteractions": "Medicine Interactions",
diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart
index 29c690e1..b8213492 100644
--- a/lib/core/api_consts.dart
+++ b/lib/core/api_consts.dart
@@ -4,7 +4,7 @@ import 'package:hmg_patient_app_new/core/enums.dart';
class ApiConsts {
static const maxSmallScreen = 660;
- static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
+ static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT
diff --git a/lib/features/immediate_livecare/immediate_livecare_view_model.dart b/lib/features/immediate_livecare/immediate_livecare_view_model.dart
index e61292d6..8a30f154 100644
--- a/lib/features/immediate_livecare/immediate_livecare_view_model.dart
+++ b/lib/features/immediate_livecare/immediate_livecare_view_model.dart
@@ -53,8 +53,8 @@ class ImmediateLiveCareViewModel extends ChangeNotifier {
late AppState _appState;
Duration countdownDuration = Duration(minutes: 1, seconds: 0);
- late ValueNotifier durationNotifier;
- late Timer timer;
+ ValueNotifier durationNotifier = ValueNotifier(Duration(minutes: 1, seconds: 0));
+ Timer? timer;
bool isShowNotEligibleDialog = false;
String notEligibleErrorMsg = "";
@@ -264,16 +264,20 @@ class ImmediateLiveCareViewModel extends ChangeNotifier {
patientLiveCareHistoryList = apiResponse.data!;
if (patientLiveCareHistoryList.isNotEmpty) {
if (patientLiveCareHistoryList[0].callStatus! < 4) {
- countdownDuration = Duration(seconds: 0);
patientHasPendingLiveCareRequest = true;
countdownDuration = Duration(minutes: patientLiveCareHistoryList.first.watingtimeInteger!, seconds: 0);
- durationNotifier = ValueNotifier(countdownDuration);
- startTimer();
+ durationNotifier.value = countdownDuration;
+ // Start timer if not already running
+ if (timer == null || !timer!.isActive) {
+ startTimer();
+ }
} else {
patientHasPendingLiveCareRequest = false;
+ stopTimer(); // Stop timer if call status >= 4
}
} else {
patientHasPendingLiveCareRequest = false;
+ stopTimer(); // Stop timer if no history
}
notifyListeners();
if (onSuccess != null) {
@@ -312,18 +316,35 @@ class ImmediateLiveCareViewModel extends ChangeNotifier {
}
void startTimer() {
- timer = Timer.periodic(const Duration(seconds: 1), (_) => addTime());
- notifyListeners();
+ // Only start timer if it's not already active
+ if (timer == null || !timer!.isActive) {
+ timer = Timer.periodic(const Duration(seconds: 1), (_) {
+ addTime();
+ });
+ }
}
void addTime() {
- final seconds = durationNotifier.value.inSeconds - 1;
- if (seconds < 0) {
+ final currentSeconds = durationNotifier.value.inSeconds;
+
+ if (currentSeconds <= 0) {
+ // Timer has reached zero, stop it
timer?.cancel();
- // Handle end of timer here
- // showEndMessage();
+ durationNotifier.value = Duration.zero;
} else {
- durationNotifier.value = Duration(seconds: seconds);
+ // Decrease by 1 second and continue
+ durationNotifier.value = Duration(seconds: currentSeconds - 1);
}
}
+
+ void stopTimer() {
+ timer?.cancel();
+ }
+
+ @override
+ void dispose() {
+ timer?.cancel();
+ durationNotifier.dispose();
+ super.dispose();
+ }
}
diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart
index 0947fade..05b0bd20 100644
--- a/lib/generated/locale_keys.g.dart
+++ b/lib/generated/locale_keys.g.dart
@@ -1818,15 +1818,6 @@ abstract class LocaleKeys {
static const selectFamilyFile = 'selectFamilyFile';
static const ancillaryOrdersListNew = 'ancillaryOrdersListNew';
static const medicalReportNew = 'medicalReportNew';
- static const medicinesAnalysis = 'medicinesAnalysis';
- static const importantWarnings = 'importantWarnings';
- static const medicineInteractions = 'medicineInteractions';
- static const followUpNeeded = 'followUpNeeded';
- static const benefit = 'benefit';
- static const commonSideEffects = 'commonSideEffects';
- static const seriousWarnings = 'seriousWarnings';
- static const storage = 'storage';
- static const aiDisclaimerPrescription = 'aiDisclaimerPrescription';
- static const generateAiAnalysisPrescription = 'generateAiAnalysisPrescription';
+ static const livecarePendingReuqestNew = 'livecarePendingReuqestNew';
}
diff --git a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart
index d3c0d682..81d232fa 100644
--- a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart
+++ b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart
@@ -240,7 +240,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
],
).paddingSymmetrical(24.h, 0.h),
(immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total == "0" || immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total == "0.0")
- // (true)
+ // (true)
? CustomButton(
text: LocaleKeys.confirmLiveCare.tr(context: context),
onPressed: () async {
@@ -357,24 +357,25 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
}
Future askVideoCallPermission(BuildContext context) async {
- final statuses = await LiveCarePermissionService.instance.requestCameraMicAndNotification(context);
+ final statuses = await LiveCarePermissionService.instance.requestCameraMicAndNotification(false, context);
// If service returned nothing (error), treat as not granted
if (statuses.isEmpty) return false;
- bool cameraGranted = statuses[Permission.camera]?.isGranted ?? false;
- bool micGranted = statuses[Permission.microphone]?.isGranted ?? false;
+ // bool cameraGranted = statuses[Permission.camera]?.isGranted ?? false;
+ // bool micGranted = statuses[Permission.microphone]?.isGranted ?? false;
bool notifGranted = statuses[Permission.notification]?.isGranted ?? false;
// bool alertWindowGranted = Platform.isAndroid ? (statuses[Permission.systemAlertWindow]?.isGranted ?? false) : true;
bool alertWindowGranted = true;
// If all required permissions are already granted
- if (cameraGranted && micGranted && notifGranted && alertWindowGranted) return true;
+ // if (cameraGranted && micGranted && notifGranted && alertWindowGranted) return true;
+ if (notifGranted && alertWindowGranted) return true;
// Collect only the missing permissions
final missing = [];
- if (!cameraGranted) missing.add(Permission.camera);
- if (!micGranted) missing.add(Permission.microphone);
+ // if (!cameraGranted) missing.add(Permission.camera);
+ // if (!micGranted) missing.add(Permission.microphone);
if (!notifGranted) missing.add(Permission.notification);
if (Platform.isAndroid && !alertWindowGranted) missing.add(Permission.systemAlertWindow);
@@ -415,8 +416,8 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
}
// Update grant state (preserve previously granted ones)
- cameraGranted = newStatuses[Permission.camera]?.isGranted ?? cameraGranted;
- micGranted = newStatuses[Permission.microphone]?.isGranted ?? micGranted;
+ // cameraGranted = newStatuses[Permission.camera]?.isGranted ?? cameraGranted;
+ // micGranted = newStatuses[Permission.microphone]?.isGranted ?? micGranted;
notifGranted = newStatuses[Permission.notification]?.isGranted ?? notifGranted;
alertWindowGranted = newStatuses[Permission.systemAlertWindow]?.isGranted ?? alertWindowGranted;
@@ -435,7 +436,8 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
}
// return cameraGranted && micGranted && notifGranted && alertWindowGranted;
- return cameraGranted && micGranted && notifGranted;
+ // return cameraGranted && micGranted && notifGranted;
+ return notifGranted;
}
// Future askVideoCallPermission() async {
diff --git a/lib/presentation/book_appointment/livecare/immediate_livecare_pending_request_page.dart b/lib/presentation/book_appointment/livecare/immediate_livecare_pending_request_page.dart
index 23c0c07b..0d42f7e5 100644
--- a/lib/presentation/book_appointment/livecare/immediate_livecare_pending_request_page.dart
+++ b/lib/presentation/book_appointment/livecare/immediate_livecare_pending_request_page.dart
@@ -1,5 +1,4 @@
-import 'dart:async';
-
+import 'dart:ui' as ui;
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
@@ -33,24 +32,19 @@ class _ImmediateLiveCarePendingRequestPageState extends State durationNotifier = ValueNotifier(immediateLiveCareViewModel.countdownDuration);
- // Timer? timer;
-
@override
void initState() {
super.initState();
- scheduleMicrotask(() {
- // countdownDuration = Duration(minutes: immediateLiveCareViewModel.patientLiveCareHistoryList[0].watingtimeInteger!, seconds: 0);
- // durationNotifier = ValueNotifier(immediateLiveCareViewModel.countdownDuration);
- // startTimer();
- });
}
@override
void dispose() {
- // timer?.cancel();
- // durationNotifier.dispose();
+ // Cancel the timer when leaving the page
+ try {
+ immediateLiveCareViewModel.stopTimer();
+ } catch (e) {
+ // Handle case where viewModel might not be initialized
+ }
super.dispose();
}
@@ -65,7 +59,7 @@ class _ImmediateLiveCarePendingRequestPageState extends State addTime());
- // // setState(() {});
- // }
- //
- // void addTime() {
- // final seconds = durationNotifier.value.inSeconds - 1;
- // if (seconds < 0) {
- // timer?.cancel();
- // // Handle end of timer here
- // // showEndMessage();
- // } else {
- // durationNotifier.value = Duration(seconds: seconds);
- // }
- // }
- //
- // Future _onWillPop() async {
- // timer?.cancel();
- // Navigator.of(context).pop();
- // return true;
- // }
- //
- // Widget buildTime(Duration duration) {
- // String twoDigits(int n) => n.toString().padLeft(2, '0');
- // final hours = twoDigits(duration.inHours);
- // final minutes = twoDigits(duration.inMinutes.remainder(60));
- // final seconds = twoDigits(duration.inSeconds.remainder(60));
- //
- // return Row(
- // mainAxisAlignment: MainAxisAlignment.center,
- // children: [
- // buildTimeColumn(hours, "Hours".needTranslation),
- // buildTimeColumn(minutes, "Mins".needTranslation),
- // buildTimeColumn(seconds, "Secs".needTranslation, isLast: true),
- // ],
- // );
- // }
- //
- // Widget buildTimeColumn(String time, String label, {bool isLast = false}) {
- // return Column(
- // mainAxisAlignment: MainAxisAlignment.center,
- // children: [
- // Row(
- // children: [
- // buildDigit(time[0]),
- // buildDigit(time[1]),
- // if (!isLast) buildTimeSeparator(),
- // ],
- // ),
- // buildLabel(label),
- // ],
- // );
- // }
- //
- // Widget buildDigit(String digit) {
- // return Container(
- // padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
- // // margin: const EdgeInsets.symmetric(horizontal: 2),
- // decoration: BoxDecoration(
- // color: Colors.white,
- // borderRadius: BorderRadius.circular(8),
- // ),
- // child: ClipRect(
- // child: AnimatedSwitcher(
- // duration: const Duration(milliseconds: 600),
- // switchInCurve: Curves.easeOutExpo,
- // switchOutCurve: Curves.easeInExpo,
- // transitionBuilder: (Widget child, Animation animation) {
- // return Stack(
- // children: [
- // SlideTransition(
- // position: Tween(
- // begin: const Offset(0, -1),
- // end: const Offset(0, 1),
- // ).animate(CurvedAnimation(
- // parent: animation,
- // curve: Curves.easeOutCubic,
- // )),
- // child: FadeTransition(
- // opacity: animation,
- // child: child,
- // ),
- // ),
- // SlideTransition(
- // position: Tween(
- // begin: const Offset(0, -1),
- // end: const Offset(0, 0),
- // ).animate(CurvedAnimation(
- // parent: animation,
- // curve: Curves.bounceIn,
- // )),
- // child: FadeTransition(
- // opacity: animation,
- // child: child,
- // ),
- // ),
- // ],
- // );
- // },
- // child: Text(
- // digit,
- // key: ValueKey(digit),
- // style: TextStyle(
- // fontWeight: FontWeight.bold,
- // color: Colors.black,
- // fontSize: 20.f,
- // ),
- // ),
- // ),
- // ),
- // );
- // }
- //
- // Widget buildLabel(String label) {
- // return label.toText14(isBold: true);
- // }
- //
- // Widget buildTimeSeparator() {
- // return const Padding(
- // padding: EdgeInsets.symmetric(horizontal: 2.0),
- // child: Text(
- // ":",
- // style: TextStyle(
- // color: Colors.black,
- // fontSize: 20,
- // ),
- // ),
- // );
- // }
+// void startTimer() {
+// // timer = Timer.periodic(const Duration(seconds: 1), (_) => addTime());
+// // setState(() {});
+// }
+//
+// void addTime() {
+// final seconds = durationNotifier.value.inSeconds - 1;
+// if (seconds < 0) {
+// timer?.cancel();
+// // Handle end of timer here
+// // showEndMessage();
+// } else {
+// durationNotifier.value = Duration(seconds: seconds);
+// }
+// }
+//
+// Future _onWillPop() async {
+// timer?.cancel();
+// Navigator.of(context).pop();
+// return true;
+// }
+//
+// Widget buildTime(Duration duration) {
+// String twoDigits(int n) => n.toString().padLeft(2, '0');
+// final hours = twoDigits(duration.inHours);
+// final minutes = twoDigits(duration.inMinutes.remainder(60));
+// final seconds = twoDigits(duration.inSeconds.remainder(60));
+//
+// return Row(
+// mainAxisAlignment: MainAxisAlignment.center,
+// children: [
+// buildTimeColumn(hours, "Hours".needTranslation),
+// buildTimeColumn(minutes, "Mins".needTranslation),
+// buildTimeColumn(seconds, "Secs".needTranslation, isLast: true),
+// ],
+// );
+// }
+//
+// Widget buildTimeColumn(String time, String label, {bool isLast = false}) {
+// return Column(
+// mainAxisAlignment: MainAxisAlignment.center,
+// children: [
+// Row(
+// children: [
+// buildDigit(time[0]),
+// buildDigit(time[1]),
+// if (!isLast) buildTimeSeparator(),
+// ],
+// ),
+// buildLabel(label),
+// ],
+// );
+// }
+//
+// Widget buildDigit(String digit) {
+// return Container(
+// padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
+// // margin: const EdgeInsets.symmetric(horizontal: 2),
+// decoration: BoxDecoration(
+// color: Colors.white,
+// borderRadius: BorderRadius.circular(8),
+// ),
+// child: ClipRect(
+// child: AnimatedSwitcher(
+// duration: const Duration(milliseconds: 600),
+// switchInCurve: Curves.easeOutExpo,
+// switchOutCurve: Curves.easeInExpo,
+// transitionBuilder: (Widget child, Animation animation) {
+// return Stack(
+// children: [
+// SlideTransition(
+// position: Tween(
+// begin: const Offset(0, -1),
+// end: const Offset(0, 1),
+// ).animate(CurvedAnimation(
+// parent: animation,
+// curve: Curves.easeOutCubic,
+// )),
+// child: FadeTransition(
+// opacity: animation,
+// child: child,
+// ),
+// ),
+// SlideTransition(
+// position: Tween(
+// begin: const Offset(0, -1),
+// end: const Offset(0, 0),
+// ).animate(CurvedAnimation(
+// parent: animation,
+// curve: Curves.bounceIn,
+// )),
+// child: FadeTransition(
+// opacity: animation,
+// child: child,
+// ),
+// ),
+// ],
+// );
+// },
+// child: Text(
+// digit,
+// key: ValueKey(digit),
+// style: TextStyle(
+// fontWeight: FontWeight.bold,
+// color: Colors.black,
+// fontSize: 20.f,
+// ),
+// ),
+// ),
+// ),
+// );
+// }
+//
+// Widget buildLabel(String label) {
+// return label.toText14(isBold: true);
+// }
+//
+// Widget buildTimeSeparator() {
+// return const Padding(
+// padding: EdgeInsets.symmetric(horizontal: 2.0),
+// child: Text(
+// ":",
+// style: TextStyle(
+// color: Colors.black,
+// fontSize: 20,
+// ),
+// ),
+// );
+// }
}
diff --git a/lib/presentation/profile_settings/widgets/profile_picture_widget.dart b/lib/presentation/profile_settings/widgets/profile_picture_widget.dart
index e7abcb12..6b30c0fc 100644
--- a/lib/presentation/profile_settings/widgets/profile_picture_widget.dart
+++ b/lib/presentation/profile_settings/widgets/profile_picture_widget.dart
@@ -135,13 +135,13 @@ class _ProfilePictureWidgetState extends State {
print('✅ Profile image loaded successfully for user: $currentPatientId');
if (mounted) {
_tryCacheExistingImage();
- setState(() {}); // Force rebuild to show new data
+ setState(() {}); // Force rebuild to show new data
}
},
onError: (error) {
print('❌ Error loading profile image: $error');
if (mounted) {
- setState(() {}); // Force rebuild to show default avatar
+ setState(() {}); // Force rebuild to show default avatar
}
},
);
@@ -365,16 +365,16 @@ class _ProfilePictureWidgetState extends State {
try {
print('=== Checking gallery permission ===');
- // Determine which permission to check based on platform and Android version
- Permission galleryPermission;
-
- if (Platform.isIOS) {
- galleryPermission = Permission.photos;
- } else {
- // Android: use photos permission which handles API level differences automatically
- galleryPermission = Permission.photos;
+ // For Android 13+ (API 33+), the Android Photo Picker handles permissions internally
+ // No need to request READ_MEDIA_IMAGES or READ_EXTERNAL_STORAGE permissions
+ if (Platform.isAndroid) {
+ print('✅ Android Photo Picker will handle permissions internally');
+ return true;
}
+ // iOS: Check photos permission
+ Permission galleryPermission = Permission.photos;
+
// First check current status
PermissionStatus currentStatus = await galleryPermission.status;
print('Current gallery permission status: $currentStatus');
@@ -520,9 +520,7 @@ class _ProfilePictureWidgetState extends State {
// Use cached decoded bytes — update cache if source data changed
final String? imageData = GetIt.instance().getProfileImageData;
- final String? currentHash = (imageData != null && imageData.isNotEmpty)
- ? '${imageData.length}_${imageData.hashCode}'
- : null;
+ final String? currentHash = (imageData != null && imageData.isNotEmpty) ? '${imageData.length}_${imageData.hashCode}' : null;
// Re-decode only if the underlying data actually changed
if (currentHash != null && currentHash != _cachedImageDataHash) {
@@ -574,9 +572,7 @@ class _ProfilePictureWidgetState extends State {
builder: (context, profileVm, _) {
// If we already have cached bytes, show the image even while "loading"
// to prevent the shimmer→image blink on page open
- final bool showShimmer = profileVm.isProfileImageLoading &&
- _cachedImageBytes == null &&
- _selectedImage == null;
+ final bool showShimmer = profileVm.isProfileImageLoading && _cachedImageBytes == null && _selectedImage == null;
return Center(
child: Stack(
@@ -644,4 +640,3 @@ class _ProfilePictureWidgetState extends State {
);
}
}
-
diff --git a/lib/presentation/tele_consultation/zoom/call_screen.dart b/lib/presentation/tele_consultation/zoom/call_screen.dart
index a2721aba..2d3e9dbf 100644
--- a/lib/presentation/tele_consultation/zoom/call_screen.dart
+++ b/lib/presentation/tele_consultation/zoom/call_screen.dart
@@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert';
import 'dart:io';
+import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@@ -21,11 +22,14 @@ import 'package:hmg_patient_app_new/core/cache_consts.dart';
import 'package:hmg_patient_app_new/core/utils/jwt.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
+import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/presentation/tele_consultation/zoom/video_view.dart';
+import 'package:hmg_patient_app_new/services/livecare_permission_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:image_picker/image_picker.dart';
+import 'package:permission_handler/permission_handler.dart';
class CallScreen extends StatefulHookWidget {
const CallScreen({Key? key}) : super(key: key);
@@ -88,6 +92,18 @@ class _CallScreenState extends State {
useEffect(() {
Future.microtask(() async {
+ final statuses = await LiveCarePermissionService.instance.requestCameraMicAndNotification(true, context);
+ bool cameraGranted = statuses[Permission.camera]?.isGranted ?? false;
+ bool micGranted = statuses[Permission.microphone]?.isGranted ?? false;
+ if (cameraGranted && micGranted) {
+ } else {
+ await LiveCarePermissionService.instance.showOpenSettingsDialog(
+ context,
+ title: LocaleKeys.permissionsProfile.tr(),
+ message: LocaleKeys.liveCarePermissions.tr(),
+ );
+ }
+
var token = generateJwt(args.sessionName, args.role);
Utils.removeFromPrefs(CacheConst.isAppOpenedFromCall);
@@ -607,32 +623,56 @@ class _CallScreenState extends State {
}
void onPressAudio() async {
- ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
- if (mySelf != null) {
- final audioStatus = mySelf.audioStatus;
- if (audioStatus != null) {
- var muted = await audioStatus.isMuted();
- if (muted) {
- await zoom.audioHelper.unMuteAudio(mySelf.userId);
- } else {
- await zoom.audioHelper.muteAudio(mySelf.userId);
+ final statuses = await LiveCarePermissionService.instance.requestCameraMicAndNotification(true, context);
+ bool cameraGranted = statuses[Permission.camera]?.isGranted ?? false;
+ bool micGranted = statuses[Permission.microphone]?.isGranted ?? false;
+
+ if (cameraGranted && micGranted) {
+ ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
+ if (mySelf != null) {
+ final audioStatus = mySelf.audioStatus;
+ if (audioStatus != null) {
+ var muted = await audioStatus.isMuted();
+ if (muted) {
+ await zoom.audioHelper.unMuteAudio(mySelf.userId);
+ } else {
+ await zoom.audioHelper.muteAudio(mySelf.userId);
+ }
}
}
+ } else {
+ await LiveCarePermissionService.instance.showOpenSettingsDialog(
+ context,
+ title: LocaleKeys.permissionsProfile.tr(),
+ message: LocaleKeys.liveCarePermissions.tr(),
+ );
}
}
void onPressVideo() async {
- ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
- if (mySelf != null) {
- final videoStatus = mySelf.videoStatus;
- if (videoStatus != null) {
- var videoOn = await videoStatus.isOn();
- if (videoOn) {
- await zoom.videoHelper.stopVideo();
- } else {
- await zoom.videoHelper.startVideo();
+ final statuses = await LiveCarePermissionService.instance.requestCameraMicAndNotification(true, context);
+ bool cameraGranted = statuses[Permission.camera]?.isGranted ?? false;
+ bool micGranted = statuses[Permission.microphone]?.isGranted ?? false;
+
+ if (cameraGranted && micGranted) {
+ ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
+ if (mySelf != null) {
+ final videoStatus = mySelf.videoStatus;
+ if (videoStatus != null) {
+ var videoOn = await videoStatus.isOn();
+ if (videoOn) {
+ await zoom.videoHelper.stopVideo();
+ } else {
+ await zoom.videoHelper.startVideo();
+ }
}
}
+ } else {
+ await LiveCarePermissionService.instance.showOpenSettingsDialog(
+ context,
+ title: LocaleKeys.permissionsProfile.tr(),
+ message: LocaleKeys.liveCarePermissions.tr(),
+ );
}
}
diff --git a/lib/services/livecare_permission_service.dart b/lib/services/livecare_permission_service.dart
index b8d71ff1..bc5f2eef 100644
--- a/lib/services/livecare_permission_service.dart
+++ b/lib/services/livecare_permission_service.dart
@@ -18,7 +18,7 @@ class LiveCarePermissionService {
/// Requests camera, microphone and notification permissions together and
/// returns the final map of permission statuses.
/// This method does NOT show any dialogs — UI decisions must be done by caller.
- Future