diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 6a1c47e..4f7ef74 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -30,9 +30,6 @@
-
@@ -91,6 +88,12 @@
+
+
+
+
+
+
@@ -115,6 +118,7 @@
value == null);
- log("uri: ${Uri.parse(url.trim())}");
-
- log("body: ${json.encode(body)}");
final bool networkStatus = await Utils.checkConnection(bypassConnectionCheck: bypassConnectionCheck);
@@ -204,7 +200,7 @@ class ApiClientImp implements ApiClient {
final int statusCode = response.statusCode;
log("uri: ${Uri.parse(url.trim())}");
log("body: ${json.encode(body)}");
- log("response.body: ${response.body}");
+ // log("response.body: ${response.body}");
// log("response.body: ${response.body}");
if (statusCode < 200 || statusCode >= 400) {
onFailure('Error While Fetching data', statusCode, failureType: StatusCodeFailure("Error While Fetching data"));
diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart
index 417519f..b92461e 100644
--- a/lib/core/api_consts.dart
+++ b/lib/core/api_consts.dart
@@ -710,7 +710,7 @@ var GET_PRESCRIPTION_INSTRUCTIONS_PDF = 'Services/ChatBot_Service.svc/REST/Chatb
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
@@ -749,7 +749,7 @@ class ApiConsts {
baseUrl = "https://uat.hmgwebservices.com/";
payFortEnvironment = FortEnvironment.test;
applePayMerchantId = "merchant.com.hmgwebservices.uat";
- SERVICE_URL = 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx';
+ SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx';
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments";
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
@@ -759,7 +759,7 @@ class ApiConsts {
baseUrl = "https://uat.hmgwebservices.com/";
payFortEnvironment = FortEnvironment.test;
applePayMerchantId = "merchant.com.hmgwebservices.uat";
- SERVICE_URL = 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx';
+ SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx';
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments";
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
@@ -779,7 +779,7 @@ class ApiConsts {
baseUrl = "https://uat.hmgwebservices.com/";
payFortEnvironment = FortEnvironment.test;
applePayMerchantId = "merchant.com.hmgwebservices.uat";
- SERVICE_URL = 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx';
+ SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx';
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments";
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
@@ -789,7 +789,7 @@ class ApiConsts {
baseUrl = "https://uat.hmgwebservices.com/";
payFortEnvironment = FortEnvironment.test;
applePayMerchantId = "merchant.com.hmgwebservices.uat";
- SERVICE_URL = 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx';
+ SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx';
TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout";
GET_TAMARA_INSTALLMENTS_URL = "https://epharmacy.hmg.com/tamara/Home/getinstallments";
GET_TAMARA_PAYMENT_STATUS = 'https://epharmacy.hmg.com/tamara/api/OnlineTamara/order_status?orderid=';
diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart
index 5fccc6e..613fba1 100644
--- a/lib/core/app_assets.dart
+++ b/lib/core/app_assets.dart
@@ -175,6 +175,8 @@ class AppAssets {
static const String comprehensiveCheckup = '$svgBasePath/comprehensive_checkup.svg';
static const String all_payment_method = '$svgBasePath/all_payment_method.svg';
static const String ic_rrt_vehicle = '$svgBasePath/ic_rrt_vehicle.svg';
+ static const String doctor_profile_rating_icon = '$svgBasePath/doctor_profile_rating_icon.svg';
+ static const String doctor_profile_reviews_icon = '$svgBasePath/doctor_profile_reviews_icon.svg';
//bottom navigation//
diff --git a/lib/core/cache_consts.dart b/lib/core/cache_consts.dart
index 66b38d4..bcbb185 100644
--- a/lib/core/cache_consts.dart
+++ b/lib/core/cache_consts.dart
@@ -74,4 +74,7 @@ class CacheConst {
static const String patientOccupationList = 'patient-occupation-list';
static const String hasEnabledQuickLogin = 'has-enabled-quick-login';
static const String quickLoginEnabled = 'quick-login-enabled';
+
+ static const String zoomRoomID = 'zoom-room-id';
+ static String isAppOpenedFromCall = "is_app_opened_from_call";
}
diff --git a/lib/core/utils/jwt.dart b/lib/core/utils/jwt.dart
new file mode 100644
index 0000000..f82c4e1
--- /dev/null
+++ b/lib/core/utils/jwt.dart
@@ -0,0 +1,38 @@
+import 'dart:math';
+
+import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
+import 'package:hmg_patient_app_new/core/utils/zoom_config.dart';
+
+String makeId(int length) {
+ String result = "";
+ String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+ int charactersLength = characters.length;
+ for (var i = 0; i < length; i++) {
+ result += characters[Random().nextInt(charactersLength)];
+ }
+ return result;
+}
+
+String generateJwt(String sessionName, String roleType) {
+ try {
+ var iat = DateTime.now();
+ var exp = DateTime.now().add(Duration(days: 2));
+ final jwt = JWT(
+ {
+ 'app_key': configs["ZOOM_SDK_KEY"],
+ 'version': 1,
+ 'user_identity': makeId(10),
+ 'iat': (iat.millisecondsSinceEpoch / 1000).round(),
+ 'exp': (exp.millisecondsSinceEpoch / 1000).round(),
+ 'tpc': sessionName,
+ 'role_type': int.parse(roleType),
+ 'cloud_recording_option': 1,
+ },
+ );
+ var token = jwt.sign(SecretKey(configs["ZOOM_SDK_SECRET"]));
+ return token;
+ } catch (e) {
+ print(e);
+ return '';
+ }
+}
diff --git a/lib/core/utils/push_notification_handler.dart b/lib/core/utils/push_notification_handler.dart
index 2e0d7c3..ee05335 100644
--- a/lib/core/utils/push_notification_handler.dart
+++ b/lib/core/utils/push_notification_handler.dart
@@ -8,14 +8,22 @@ import 'package:firebase_messaging/firebase_messaging.dart' as fir;
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.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_ios_voip_kit_karmm/call_state_type.dart';
import 'package:flutter_ios_voip_kit_karmm/flutter_ios_voip_kit.dart';
// import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
+import 'package:get_it/get_it.dart';
import 'package:hmg_patient_app_new/core/utils/local_notifications.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
+import 'package:hmg_patient_app_new/services/cache_service.dart';
import 'package:permission_handler/permission_handler.dart';
+import 'package:uuid/uuid.dart';
import '../cache_consts.dart';
@@ -36,16 +44,83 @@ Future backgroundMessageHandler(dynamic message) async {
callPage(String sessionID, String token) async {}
_incomingCall(Map data) async {
+ print('the value of the _incomingCall remote message is $data');
+
// 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;
+
+ String roomID = data['session_id'] ?? '';
+
+ // GetIt.instance().saveString(key: CacheConst.zoomRoomID, value: roomID);
+ // GetIt.instance().saveBool(key: CacheConst.isAppOpenedFromCall, value: true);
+
+ Utils.saveStringFromPrefs(CacheConst.zoomRoomID, roomID);
+ Utils.saveBoolFromPrefs(CacheConst.isAppOpenedFromCall, true);
+
WidgetsFlutterBinding.ensureInitialized();
- // var _currentUuid = Uuid().v4();
- // await FlutterCallkitIncoming.showCallkitIncoming(callKitParams);
- // }
- // LandingPage.isOpenCallPage = false;
+
+ var _currentUuid = Uuid().v4();
+ CallKitParams callKitParams = CallKitParams(
+ id: _currentUuid,
+ nameCaller: "Dr Al Habib",
+ appName: 'Dr Al Habib',
+ avatar: 'https://play-lh.googleusercontent.com/FBNNpxb7m6eM6wtW7MV1Ffp6OXOGLI38q47zcvP29OCYA1yhYH5mZzl5itZi0TgOyZpG',
+ // handle: LandingPage.incomingCallData.name,
+ type: 1,
+ textAccept: 'Accept',
+ textDecline: 'Decline',
+ missedCallNotification: NotificationParams(
+ showNotification: true,
+ isShowCallback: false,
+ subtitle: 'Missed call',
+ callbackText: '',
+ ),
+ callingNotification: const NotificationParams(
+ showNotification: false,
+ isShowCallback: true,
+ subtitle: 'Calling...',
+ callbackText: 'Hang Up',
+ ),
+ duration: 30000,
+ extra: {'userId': '1a2b3c4d'},
+ headers: {'apiKey': 'Abc@123!', 'platform': 'flutter'},
+ android: const AndroidParams(
+ isImportant: true,
+ isShowFullLockedScreen: true,
+ isCustomNotification: true,
+ isShowLogo: false,
+ logoUrl: "https://play-lh.googleusercontent.com/FBNNpxb7m6eM6wtW7MV1Ffp6OXOGLI38q47zcvP29OCYA1yhYH5mZzl5itZi0TgOyZpG",
+ ringtonePath: 'system_ringtone_default',
+ backgroundColor: '#ED1C2B',
+ backgroundUrl: 'https://saudipedia.com/en/saudipediaen/uploads/images/2024/08/02/97358.jpg',
+ actionColor: '#4CAF50',
+ textColor: '#000000',
+ incomingCallNotificationChannelName: "Incoming Call",
+ missedCallNotificationChannelName: "Missed Call",
+ isShowCallID: false),
+ ios: IOSParams(
+ iconName: 'Meena Health',
+ 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',
+ ),
+ );
+ FlutterCallkitIncoming.unsilenceEvents();
+ await FlutterCallkitIncoming.showCallkitIncoming(callKitParams);
+
await Future.delayed(Duration(milliseconds: 500));
}
@@ -224,7 +299,9 @@ class PushNotificationHandler {
print('🎈 example: onDidAcceptIncomingCall $uuid - $callerId');
await voIPKit.acceptIncomingCall(callerState: CallStateType.calling);
await voIPKit.callConnected();
- await Future.delayed(Duration(seconds: 1));
+ await Future.delayed(Duration(seconds: 2)).then((val) async {
+ await voIPKit.endCall();
+ });
// Navigator.pushNamed(
// locator().navigatorKey.currentContext!,
@@ -232,8 +309,6 @@ class PushNotificationHandler {
// arguments: CallArguments("hoover-dam", "123", "Patient", "40", "1", false),
// );
- await voIPKit.endCall();
-
// Navigator.pushNamed(navigatorKey.currentContext!, VIDEO_CALL_SCREEN,
// arguments: VideoArgus(
// reservationId: int.parse(callerId), token: null, isVideo: true));
diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart
index e2c11d4..f1e1593 100644
--- a/lib/core/utils/utils.dart
+++ b/lib/core/utils/utils.dart
@@ -807,7 +807,11 @@ class Utils {
static Future checkConnection({bool bypassConnectionCheck = false}) async {
if (bypassConnectionCheck) return true;
List connectivityResult = await (Connectivity().checkConnectivity());
- if (connectivityResult.contains(ConnectivityResult.mobile) || connectivityResult.contains(ConnectivityResult.wifi)) {
+ if (connectivityResult.contains(ConnectivityResult.mobile) ||
+ connectivityResult.contains(ConnectivityResult.wifi) ||
+ connectivityResult.contains(ConnectivityResult.ethernet) ||
+ connectivityResult.contains(ConnectivityResult.bluetooth) ||
+ connectivityResult.contains(ConnectivityResult.vpn)) {
return true;
} else {
return false;
diff --git a/lib/core/utils/zoom_config.dart b/lib/core/utils/zoom_config.dart
new file mode 100644
index 0000000..09370c0
--- /dev/null
+++ b/lib/core/utils/zoom_config.dart
@@ -0,0 +1,4 @@
+const Map configs = {
+ 'ZOOM_SDK_KEY': 'b9T74nhfTg-ioP9urm970A',
+ 'ZOOM_SDK_SECRET': 'KOzmjBNXQ1f4IPHpnngfL29uZvJMufSy2Fk8',
+};
diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart
index 250453d..c2a4a87 100644
--- a/lib/extensions/string_extensions.dart
+++ b/lib/extensions/string_extensions.dart
@@ -301,14 +301,14 @@ extension EmailValidator on String {
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
);
- Widget toText28({Color? color, bool isBold = false, double? height, bool isCenter = false}) => Text(
+ Widget toText28({Color? color, bool isBold = false, double? height, bool isCenter = false, double? letterSpacing}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(
height: height ?? 23 / 28,
color: color ?? AppColors.blackColor,
fontSize: 28.f,
- letterSpacing: -1,
+ letterSpacing: letterSpacing ?? -1,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
diff --git a/lib/features/book_appointments/book_appointments_view_model.dart b/lib/features/book_appointments/book_appointments_view_model.dart
index 5d5fc71..bcc88ff 100644
--- a/lib/features/book_appointments/book_appointments_view_model.dart
+++ b/lib/features/book_appointments/book_appointments_view_model.dart
@@ -349,8 +349,8 @@ class BookAppointmentsViewModel extends ChangeNotifier {
result.fold(
(failure) async {
isDoctorsListLoading = false;
+ if (onError != null) onError("No doctors found for the search criteria".needTranslation);
- onError!("No doctors found for the search criteria".needTranslation);
notifyListeners();
},
(apiResponse) {
diff --git a/lib/features/immediate_livecare/immediate_livecare_view_model.dart b/lib/features/immediate_livecare/immediate_livecare_view_model.dart
index 7e2d7c9..1baa81b 100644
--- a/lib/features/immediate_livecare/immediate_livecare_view_model.dart
+++ b/lib/features/immediate_livecare/immediate_livecare_view_model.dart
@@ -151,18 +151,15 @@ class ImmediateLiveCareViewModel extends ChangeNotifier {
if (patientLiveCareHistoryList.isNotEmpty) {
if (patientLiveCareHistoryList[0].callStatus! < 4) {
countdownDuration = Duration(seconds: 0);
- durationNotifier.dispose();
patientHasPendingLiveCareRequest = true;
countdownDuration = Duration(minutes: patientLiveCareHistoryList.first.watingtimeInteger!, seconds: 0);
durationNotifier = ValueNotifier(countdownDuration);
startTimer();
} else {
patientHasPendingLiveCareRequest = false;
- timer.cancel();
}
} else {
patientHasPendingLiveCareRequest = false;
- timer.cancel();
}
notifyListeners();
if (onSuccess != null) {
diff --git a/lib/features/insurance/insurance_view_model.dart b/lib/features/insurance/insurance_view_model.dart
index 8460bd4..30f4c26 100644
--- a/lib/features/insurance/insurance_view_model.dart
+++ b/lib/features/insurance/insurance_view_model.dart
@@ -78,10 +78,12 @@ class InsuranceViewModel extends ChangeNotifier {
// (failure) async => await errorHandlerService.handleError(failure: failure),
(failure) async {
isInsuranceLoading = false;
+ isInsuranceDataToBeLoaded = false;
notifyListeners();
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
+ isInsuranceDataToBeLoaded = false;
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
patientInsuranceList = apiResponse.data!;
diff --git a/lib/features/lab/lab_view_model.dart b/lib/features/lab/lab_view_model.dart
index 079471c..24aa244 100644
--- a/lib/features/lab/lab_view_model.dart
+++ b/lib/features/lab/lab_view_model.dart
@@ -77,14 +77,14 @@ class LabViewModel extends ChangeNotifier {
required this.navigationService});
initLabProvider() {
- if (isLabNeedToLoad) {
+ // if (isLabNeedToLoad) {
patientLabOrders.clear();
filteredLabOrders.clear();
labOrderTests.clear();
isLabOrdersLoading = true;
isLabResultsLoading = true;
getPatientLabOrders();
- }
+ // }
notifyListeners();
}
@@ -94,7 +94,7 @@ class LabViewModel extends ChangeNotifier {
}
Future getPatientLabOrders({Function(dynamic)? onSuccess, Function(String)? onError}) async {
- if (!isLabNeedToLoad) return;
+ // if (!isLabNeedToLoad) return;
isLabOrdersLoading = true;
patientLabOrders.clear();
@@ -289,7 +289,7 @@ class LabViewModel extends ChangeNotifier {
);
}
- Future getPatientLabResult(PatientLabOrdersResponseModel laborder, String procedureName, String testDescription) async {
+ Future getPatientLabResult(PatientLabOrdersResponseModel laborder, String procedureName, String testDescription, String unitOfMeasure) async {
LoaderBottomSheet.showLoader();
mainLabResults.clear();
filteredGraphValues.clear();
@@ -339,6 +339,7 @@ class LabViewModel extends ChangeNotifier {
} catch (e) {}
});
LabResult recentResult = recentThree.first;
+ recentResult.uOM = unitOfMeasure;
checkIfGraphShouldBeDisplayed(recentResult);
recentResult.verifiedOn = resultDate(DateUtil.convertStringToDate(recentResult.verifiedOnDateTime!));
// filteredGraphValues = [filteredGraphValues.first];
diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart
index 5d2ae5c..7bc9c62 100644
--- a/lib/presentation/appointments/widgets/appointment_card.dart
+++ b/lib/presentation/appointments/widgets/appointment_card.dart
@@ -124,19 +124,47 @@ class AppointmentCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
- Image.network(
- isLoading ? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png' : patientAppointmentHistoryResponseModel.doctorImageURL!,
- width: 63.h,
- height: 63.h,
- fit: BoxFit.cover,
+ Stack(
+ children: [
+ Image.network(
+ isLoading ? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png' : patientAppointmentHistoryResponseModel.doctorImageURL!,
+ width: 63.w,
+ height: 63.h,
+ fit: BoxFit.cover,
+ ),
+ Positioned(
+ bottom: 0,
+ left: 0,
+ right: 0,
+ child: Container(
+ width: 63.w,
+ height: 20,
+ color: AppColors.textColorLight.withValues(alpha: 0.25),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Utils.buildSvgWithAssets(
+ icon: AppAssets.rating_icon,
+ width: 12.w,
+ height: 12.h,
+ fit: BoxFit.contain,
+ ),
+ SizedBox(width: 4.w),
+ isLoading ? "Rating".toText12() : patientAppointmentHistoryResponseModel.decimalDoctorRate.toString().toText12(),
+ ],
+ ),
+ ),
+ )
+ ],
).circle(100).toShimmer2(isShow: isLoading),
- SizedBox(height: 12.h),
- AppCustomChipWidget(
- icon: AppAssets.rating_icon,
- iconColor: AppColors.ratingColorYellow,
- labelText: isLoading ? "Rating" : "Rating: ${patientAppointmentHistoryResponseModel.decimalDoctorRate}".needTranslation)
- .toShimmer2(isShow: isLoading),
+ // SizedBox(height: 12.h),
+ // AppCustomChipWidget(
+ // icon: AppAssets.rating_icon,
+ // iconColor: AppColors.ratingColorYellow,
+ // labelText: isLoading ? "Rating" : "Rating: ${patientAppointmentHistoryResponseModel.decimalDoctorRate}".needTranslation)
+ // .toShimmer2(isShow: isLoading),
],
),
SizedBox(width: 16.h),
@@ -163,6 +191,12 @@ class AppointmentCard extends StatelessWidget {
? 'Cardiology'
: "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)}",
).toShimmer2(isShow: isLoading),
+ AppCustomChipWidget(
+ isIconPNG: true,
+ icon: getIt.get().getAuthenticatedUser()?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg,
+ iconSize: 18.h,
+ labelText: isLoading ? 'Cardiology' : "Patient: ${getIt.get().getAuthenticatedUser()!.firstName!}",
+ ).toShimmer2(isShow: isLoading),
// if (!isFromMedicalReport)
// AppCustomChipWidget(
// icon: AppAssets.appointment_time_icon,
@@ -278,7 +312,6 @@ class AppointmentCard extends StatelessWidget {
clinicId: patientAppointmentHistoryResponseModel.clinicID,
onSuccess: (value) async {
if (value) {
- print("Doctor is available");
await myAppointmentsViewModel.getAskDoctorRequestTypes(onSuccess: (val) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
diff --git a/lib/presentation/appointments/widgets/ask_doctor_request_type_select.dart b/lib/presentation/appointments/widgets/ask_doctor_request_type_select.dart
index 9f06a4d..69cdca3 100644
--- a/lib/presentation/appointments/widgets/ask_doctor_request_type_select.dart
+++ b/lib/presentation/appointments/widgets/ask_doctor_request_type_select.dart
@@ -79,15 +79,15 @@ class AskDoctorRequestTypeSelect extends StatelessWidget {
onPressed: () {
Navigator.pop(context);
},
- backgroundColor: AppColors.primaryRedColor,
- borderColor: AppColors.primaryRedColor,
- textColor: AppColors.whiteColor,
+ backgroundColor: AppColors.secondaryLightRedColor,
+ borderColor: AppColors.secondaryLightRedColor,
+ textColor: AppColors.primaryRedColor,
icon: AppAssets.cancel,
- iconColor: AppColors.whiteColor,
+ iconColor: AppColors.primaryRedColor,
borderRadius: 12.r,
- iconSize: 14.h,
- fontSize: 14.f,
- height: 40.h,
+ iconSize: 16.5.h,
+ fontSize: 16.f,
+ height: 56.h,
),
),
SizedBox(width: 8.h),
@@ -120,14 +120,15 @@ class AskDoctorRequestTypeSelect extends StatelessWidget {
LoaderBottomSheet.hideLoader();
});
},
- backgroundColor: AppColors.bgGreenColor,
- borderColor: AppColors.bgGreenColor,
- textColor: Colors.white,
+ backgroundColor: AppColors.bgGreenColor.withValues(alpha: 0.20),
+ borderColor: AppColors.bgGreenColor.withValues(alpha: 0.0),
+ textColor: AppColors.bgGreenColor,
+ iconColor: AppColors.bgGreenColor,
icon: AppAssets.confirm,
- iconSize: 14.h,
+ iconSize: 16.5.h,
borderRadius: 12.r,
- fontSize: 14.f,
- height: 40.h,
+ fontSize: 16.f,
+ height: 56.h,
),
),
],
diff --git a/lib/presentation/authentication/login.dart b/lib/presentation/authentication/login.dart
index 7e5f4a1..0fa995d 100644
--- a/lib/presentation/authentication/login.dart
+++ b/lib/presentation/authentication/login.dart
@@ -1,6 +1,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
@@ -154,7 +155,7 @@ class LoginScreenState extends State {
required BuildContext context,
required TextEditingController? phoneNumberController,
required AuthenticationViewModel authViewModel,
- }) {
+ }) async {
AppState appState = getIt();
context.showBottomSheet(
isScrollControlled: true,
diff --git a/lib/presentation/book_appointment/book_appointment_page.dart b/lib/presentation/book_appointment/book_appointment_page.dart
index a66ea4d..8a0f7e7 100644
--- a/lib/presentation/book_appointment/book_appointment_page.dart
+++ b/lib/presentation/book_appointment/book_appointment_page.dart
@@ -2,20 +2,25 @@ import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
+import 'package:hmg_patient_app_new/core/utils/size_config.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.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/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
+import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart';
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart';
+import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/faculity_selection/facility_type_selection_widget.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/region_bottomsheet/region_list_widget.dart' show RegionBottomSheetBody;
+import 'package:hmg_patient_app_new/presentation/book_appointment/doctor_profile_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/immediate_livecare_pending_request_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/select_immediate_livecare_clinic_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/search_doctor_by_name.dart';
@@ -86,6 +91,111 @@ class _BookAppointmentPageState extends State {
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 24.h),
getSelectedTabData(bookAppointmentsVM.selectedTabIndex),
+ SizedBox(height: 24.h),
+ "Recent Visits".needTranslation.toText18(isBold: true).paddingSymmetrical(24.w, 0.h),
+ SizedBox(height: 16.h),
+ Consumer(builder: (context, myAppointmentsVM, child) {
+ return myAppointmentsVM.isPatientMyDoctorsLoading
+ ? Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Image.network(
+ "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
+ width: 64.w,
+ height: 64.h,
+ fit: BoxFit.cover,
+ ).circle(100).toShimmer2(isShow: true, radius: 50.r),
+ SizedBox(height: 8.h),
+ ("Dr. John Smith Smith Smith")
+ .toString()
+ .toText12(fontWeight: FontWeight.w500, isCenter: true, maxLine: 2)
+ .toShimmer2(isShow: true),
+ ],
+ )
+ : myAppointmentsVM.patientMyDoctorsList.isEmpty
+ ? Container(
+ width: SizeConfig.screenWidth,
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 12.r,
+ hasShadow: false,
+ ),
+ child: Utils.getNoDataWidget(
+ context,
+ noDataText: "You don't have any completed visits yet".needTranslation,
+ isSmallWidget: true,
+ width: 62.w,
+ height: 62.h,
+ ),
+ ).paddingSymmetrical(24.w, 0.h)
+ : SizedBox(
+ height: 110.h,
+ child: ListView.separated(
+ scrollDirection: Axis.horizontal,
+ itemCount: myAppointmentsVM.patientMyDoctorsList.length,
+ shrinkWrap: true,
+ padding: EdgeInsets.only(left: 24.w, right: 24.w),
+ itemBuilder: (context, index) {
+ return AnimationConfiguration.staggeredList(
+ position: index,
+ duration: const Duration(milliseconds: 1000),
+ child: SlideAnimation(
+ horizontalOffset: 100.0,
+ child: FadeInAnimation(
+ child: SizedBox(
+ // width: 80.w,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Image.network(
+ myAppointmentsVM.patientMyDoctorsList[index].doctorImageURL!,
+ width: 64.w,
+ height: 64.h,
+ fit: BoxFit.cover,
+ ).circle(100).toShimmer2(isShow: false, radius: 50.r),
+ SizedBox(height: 8.h),
+ SizedBox(
+ width: 80.w,
+ child: (myAppointmentsVM.patientMyDoctorsList[index].doctorName)
+ .toString()
+ .toText12(fontWeight: FontWeight.w500, isCenter: true, maxLine: 2)
+ .toShimmer2(isShow: false),
+ ),
+ ],
+ ),
+ ).onPress(() async {
+ bookAppointmentsViewModel.setSelectedDoctor(DoctorsListResponseModel(
+ clinicID: myAppointmentsVM.patientMyDoctorsList[index].clinicID,
+ projectID: myAppointmentsVM.patientMyDoctorsList[index].projectID,
+ doctorID: myAppointmentsVM.patientMyDoctorsList[index].doctorID,
+ ));
+ LoaderBottomSheet.showLoader();
+ await bookAppointmentsViewModel.getDoctorProfile(onSuccess: (dynamic respData) {
+ LoaderBottomSheet.hideLoader();
+ Navigator.of(context).push(
+ CustomPageRoute(
+ page: DoctorProfilePage(),
+ ),
+ );
+ }, onError: (err) {
+ LoaderBottomSheet.hideLoader();
+ showCommonBottomSheetWithoutHeight(
+ context,
+ child: Utils.getErrorWidget(loadingText: err),
+ callBackFunc: () {},
+ isFullScreen: false,
+ isCloseButtonVisible: true,
+ );
+ });
+ }),
+ ),
+ ),
+ );
+ },
+ separatorBuilder: (BuildContext cxt, int index) => SizedBox(width: 8.h),
+ ),
+ );
+ }),
],
);
}),
diff --git a/lib/presentation/book_appointment/doctor_profile_page.dart b/lib/presentation/book_appointment/doctor_profile_page.dart
index 1223842..c3f4ad9 100644
--- a/lib/presentation/book_appointment/doctor_profile_page.dart
+++ b/lib/presentation/book_appointment/doctor_profile_page.dart
@@ -48,6 +48,7 @@ class DoctorProfilePage extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
bookAppointmentsViewModel.doctorsProfileResponseModel.doctorImageURL!,
@@ -59,9 +60,12 @@ class DoctorProfilePage extends StatelessWidget {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- ("${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorTitleForProfile} ${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName}")
- .toString()
- .toText28(isBold: true),
+ SizedBox(
+ width: 220.h,
+ child: ("${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorTitleForProfile} ${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName}")
+ .toString()
+ .toText24(isBold: true),
+ ),
(bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.isNotEmpty ? bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.first : "")
.toString()
.toText18(weight: FontWeight.w500, color: AppColors.primaryRedColor),
@@ -80,18 +84,49 @@ class DoctorProfilePage extends StatelessWidget {
SizedBox(height: 12.h),
Wrap(
direction: Axis.horizontal,
- spacing: 3.h,
+ spacing: 4.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(
- icon: AppAssets.rating_icon,
iconColor: AppColors.ratingColorYellow,
- labelText: "Rating: ${bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate}".needTranslation,
+ labelText: "Branch: ${bookAppointmentsViewModel.doctorsProfileResponseModel.projectName}".needTranslation,
),
AppCustomChipWidget(
- icon: AppAssets.rating_icon,
iconColor: AppColors.ratingColorYellow,
- labelText: "Reviews: ${bookAppointmentsViewModel.doctorsProfileResponseModel.noOfPatientsRate}".needTranslation,
+ labelText: "Clinic: ${bookAppointmentsViewModel.doctorsProfileResponseModel.clinicDescription}".needTranslation,
+ ),
+ ],
+ ),
+ SizedBox(height: 24.h),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Column(
+ children: [
+ Utils.buildSvgWithAssets(
+ icon: AppAssets.doctor_profile_rating_icon,
+ width: 48.w,
+ height: 48.h,
+ fit: BoxFit.contain,
+ ),
+ SizedBox(height: 16.h),
+ "Ratings".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
+ bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate.toString().toText16(isBold: true, color: AppColors.textColor),
+ ],
+ ),
+ SizedBox(width: 36.w),
+ Column(
+ children: [
+ Utils.buildSvgWithAssets(
+ icon: AppAssets.doctor_profile_reviews_icon,
+ width: 48.w,
+ height: 48.h,
+ fit: BoxFit.contain,
+ ),
+ SizedBox(height: 16.h),
+ "Reviews".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
+ bookAppointmentsViewModel.doctorsProfileResponseModel.noOfPatientsRate.toString().toText16(isBold: true, color: AppColors.textColor),
+ ],
),
],
),
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 af7d053..b586da1 100644
--- a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart
+++ b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart
@@ -13,13 +13,16 @@ import 'package:hmg_patient_app_new/features/book_appointments/book_appointments
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart';
+import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/immediate_livecare_pending_request_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/widgets/select_livecare_call_type.dart';
+import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
+import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';
@@ -71,37 +74,17 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
children: [
"${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText16(isBold: true),
SizedBox(height: 8.h),
- AppCustomChipWidget(labelText: "${appState.getAuthenticatedUser()!.age} Years Old"),
- ],
- ),
- ],
- ),
- ),
- ),
- SizedBox(height: 24.h),
- "Clinic Information".needTranslation.toText16(isBold: true),
- SizedBox(height: 16.h),
- Container(
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
- color: AppColors.whiteColor,
- borderRadius: 24.h,
- hasShadow: false,
- ),
- child: Padding(
- padding: EdgeInsets.all(16.h),
- child: Row(
- children: [
- Utils.buildSvgWithAssets(icon: AppAssets.generic_clinic_icon, width: 32.h, height: 32.h, fit: BoxFit.contain),
- SizedBox(width: 8.h),
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- (appState.isArabic()
- ? immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceNameN
- : immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceName)!
- .toText16(isBold: true),
- // SizedBox(height: 8.h),
- // AppCustomChipWidget(labelText: "${appState.getAuthenticatedUser()!.age} Years Old"),
+ Wrap(
+ direction: Axis.horizontal,
+ spacing: 3.h,
+ runSpacing: 4.h,
+ children: [
+ AppCustomChipWidget(labelText: "${appState.getAuthenticatedUser()!.age} Years Old".needTranslation),
+ AppCustomChipWidget(
+ labelText:
+ "${LocaleKeys.clinic.tr()}: ${(appState.isArabic() ? immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceNameN : immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceName)!}"),
+ ],
+ ),
],
),
],
@@ -220,15 +203,81 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
isSaudiCurrency: immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"),
],
).paddingSymmetrical(24.h, 0.h),
- CustomButton(
- text: LocaleKeys.payNow.tr(context: context),
- onPressed: () async {
- await askVideoCallPermission().then((val) {
- if (val) {
- Navigator.of(context).push(
- CustomPageRoute(
- page: ImmediateLiveCarePaymentPage(),
- ),
+ (immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total == "0" || immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total == "0.0")
+ ? CustomButton(
+ text: LocaleKeys.confirmLiveCare.tr(context: context),
+ onPressed: () async {
+ await askVideoCallPermission().then((val) async {
+ if (val) {
+ LoaderBottomSheet.showLoader(loadingText: "Confirming LiveCare request, Please wait...".needTranslation);
+
+ await immediateLiveCareViewModel.addNewCallRequestForImmediateLiveCare("${appState.getAuthenticatedUser()!.patientId}${DateTime.now().millisecondsSinceEpoch}");
+ await immediateLiveCareViewModel.getPatientLiveCareHistory();
+ LoaderBottomSheet.hideLoader();
+ if (immediateLiveCareViewModel.patientHasPendingLiveCareRequest) {
+ Navigator.pushAndRemoveUntil(
+ context,
+ CustomPageRoute(
+ page: LandingNavigation(),
+ ),
+ (r) => false);
+ Navigator.of(context).push(
+ CustomPageRoute(
+ page: ImmediateLiveCarePendingRequestPage(),
+ ),
+ );
+ } else {
+ showCommonBottomSheetWithoutHeight(
+ context,
+ child: Utils.getErrorWidget(loadingText: "Unknown error occurred...".needTranslation),
+ callBackFunc: () {},
+ isFullScreen: false,
+ isCloseButtonVisible: true,
+ );
+ }
+ } else {
+ showCommonBottomSheetWithoutHeight(
+ title: LocaleKeys.notice.tr(context: context),
+ context,
+ child: Utils.getWarningWidget(
+ loadingText:
+ "LiveCare requires Camera, Microphone, Location & Notifications permissions to enable virtual consultation between patient & doctor, Please allow these to proceed."
+ .needTranslation,
+ isShowActionButtons: true,
+ onCancelTap: () {
+ Navigator.pop(context);
+ },
+ onConfirmTap: () async {
+ openAppSettings();
+ }),
+ callBackFunc: () {},
+ isFullScreen: false,
+ isCloseButtonVisible: true,
+ );
+ }
+ });
+ },
+ backgroundColor: AppColors.successColor,
+ borderColor: AppColors.successColor,
+ textColor: AppColors.whiteColor,
+ fontSize: 16,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 50.h,
+ icon: AppAssets.livecare_book_icon,
+ iconColor: AppColors.whiteColor,
+ iconSize: 18.h,
+ ).paddingSymmetrical(24.h, 24.h)
+ : CustomButton(
+ text: LocaleKeys.payNow.tr(context: context),
+ onPressed: () async {
+ await askVideoCallPermission().then((val) {
+ if (val) {
+ Navigator.of(context).push(
+ CustomPageRoute(
+ page: ImmediateLiveCarePaymentPage(),
+ ),
);
} else {
showCommonBottomSheetWithoutHeight(
@@ -236,16 +285,17 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
context,
child: Utils.getWarningWidget(
loadingText:
- "LiveCare requires Camera, Microphone & Location permissions to enable virtual consultation between patient & doctor, Please allow these to proceed.".needTranslation,
- isShowActionButtons: true,
- onCancelTap: () {
- Navigator.pop(context);
- },
- onConfirmTap: () async {
- openAppSettings();
- }),
- callBackFunc: () {},
- isFullScreen: false,
+ "LiveCare requires Camera, Microphone, Location & Notifications permissions to enable virtual consultation between patient & doctor, Please allow these to proceed."
+ .needTranslation,
+ isShowActionButtons: true,
+ onCancelTap: () {
+ Navigator.pop(context);
+ },
+ onConfirmTap: () async {
+ openAppSettings();
+ }),
+ callBackFunc: () {},
+ isFullScreen: false,
isCloseButtonVisible: true,
);
}
@@ -272,12 +322,9 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
}
Future askVideoCallPermission() async {
- Map statuses = await [
- Permission.camera,
- Permission.microphone,
- ].request();
+ Map statuses = await [Permission.camera, Permission.microphone, Permission.notification].request();
- if (statuses[Permission.camera] == PermissionStatus.granted && statuses[Permission.microphone] == PermissionStatus.granted) {
+ if (statuses[Permission.camera] == PermissionStatus.granted && statuses[Permission.microphone] == PermissionStatus.granted && statuses[Permission.notification] == PermissionStatus.granted) {
// Camera permission granted
return true;
} else {
diff --git a/lib/presentation/book_appointment/livecare/select_immediate_livecare_clinic_page.dart b/lib/presentation/book_appointment/livecare/select_immediate_livecare_clinic_page.dart
index 8181d25..15598f3 100644
--- a/lib/presentation/book_appointment/livecare/select_immediate_livecare_clinic_page.dart
+++ b/lib/presentation/book_appointment/livecare/select_immediate_livecare_clinic_page.dart
@@ -66,35 +66,6 @@ class _SelectImmediateLiveCareClinicPageState extends State(builder: (context, immediateLiveCareVM, child) {
return Column(
children: [
- // SizedBox(height: 16.h),
- // TextInputWidget(
- // labelText: LocaleKeys.search.tr(context: context),
- // hintText: LocaleKeys.clinicName.tr(context: context),
- // controller: searchEditingController,
- // isEnable: true,
- // prefix: null,
- // autoFocus: false,
- // isBorderAllowed: false,
- // keyboardType: TextInputType.text,
- // focusNode: textFocusNode,
- // suffix: searchEditingController.text.isNotEmpty
- // ? GestureDetector(
- // onTap: () {
- // searchEditingController.clear();
- // bookAppointmentsViewModel.filterClinics("");
- // textFocusNode.unfocus();
- // },
- // child: Utils.buildSvgWithAssets(icon: AppAssets.close_bottom_sheet_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown),
- // )
- // : null,
- // onChange: (value) {
- // bookAppointmentsViewModel.filterClinics(value!);
- // },
- // padding: EdgeInsets.symmetric(
- // vertical: ResponsiveExtension(10).h,
- // horizontal: ResponsiveExtension(15).h,
- // ),
- // ),
ListView.separated(
padding: EdgeInsets.only(top: 16.h),
shrinkWrap: true,
diff --git a/lib/presentation/book_appointment/livecare/widgets/livecare_clinic_card.dart b/lib/presentation/book_appointment/livecare/widgets/livecare_clinic_card.dart
index 7385c6b..3913f10 100644
--- a/lib/presentation/book_appointment/livecare/widgets/livecare_clinic_card.dart
+++ b/lib/presentation/book_appointment/livecare/widgets/livecare_clinic_card.dart
@@ -12,6 +12,7 @@ import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_mode
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
+import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
class LiveCareClinicCard extends StatelessWidget {
LiveCareClinicCard({super.key, required this.liveCareClinicListResponseModel, required this.isLoading, required this.immediateLiveCareViewModel});
@@ -34,20 +35,12 @@ class LiveCareClinicCard extends StatelessWidget {
children: [
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Utils.buildSvgWithAssets(icon: AppAssets.generic_clinic_icon, width: 24.h, height: 24.h, fit: BoxFit.contain).toShimmer2(isShow: isLoading),
- Column(
- children: [
- Utils.buildSvgWithAssets(
- icon: AppAssets.livecare_online_icon,
- width: 16.h,
- height: 16.h,
- fit: BoxFit.contain,
- iconColor: liveCareClinicListResponseModel.isOnline == 1 ? AppColors.successColor : AppColors.primaryRedColor)
- .toShimmer2(isShow: isLoading),
- SizedBox(height: 4.h),
- liveCareClinicListResponseModel.isOnline == 1
- ? LocaleKeys.online.tr(context: context).toText10(isBold: true, color: AppColors.successColor).toShimmer2(isShow: isLoading)
- : "Offline".toText10(isBold: true, color: AppColors.primaryRedColor).toShimmer2(isShow: isLoading),
- ],
+ AppCustomChipWidget(
+ icon: AppAssets.livecare_online_icon,
+ iconColor: AppColors.whiteColor,
+ richText: (liveCareClinicListResponseModel.isOnline == 1 ? LocaleKeys.online.tr(context: context) : "Offline".needTranslation).toText10(isBold: true, color: AppColors.whiteColor),
+ backgroundColor: liveCareClinicListResponseModel.isOnline == 1 ? AppColors.successColor : AppColors.primaryRedColor,
+ textColor: AppColors.whiteColor,
),
]),
SizedBox(height: 8.h),
diff --git a/lib/presentation/book_appointment/livecare/widgets/select_livecare_call_type.dart b/lib/presentation/book_appointment/livecare/widgets/select_livecare_call_type.dart
index 226ac50..e4d69b1 100644
--- a/lib/presentation/book_appointment/livecare/widgets/select_livecare_call_type.dart
+++ b/lib/presentation/book_appointment/livecare/widgets/select_livecare_call_type.dart
@@ -1,10 +1,14 @@
import 'package:flutter/cupertino.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
+import 'package:hmg_patient_app_new/core/app_state.dart';
+import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.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/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart';
+import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/medical_file_card.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
@@ -16,46 +20,30 @@ class SelectLiveCareCallType extends StatelessWidget {
@override
Widget build(BuildContext context) {
//TODO: Replace with actual icons
- return GridView(
- gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
- crossAxisCount: 3,
- crossAxisSpacing: 16,
- mainAxisSpacing: 16,
- mainAxisExtent: 130,
- ),
- physics: NeverScrollableScrollPhysics(),
- padding: EdgeInsets.zero,
- shrinkWrap: true,
+ return Column(
children: [
- MedicalFileCard(
- label: "Video Call".needTranslation,
- textColor: AppColors.blackColor,
- backgroundColor: AppColors.whiteColor,
- svgIcon: AppAssets.eye_result_icon,
- isLargeText: true,
- iconSize: 36.h,
+ checkInOptionCard(
+ AppAssets.checkin_location_icon,
+ "Video Call".needTranslation,
+ "View your nearest HMG locations".needTranslation,
).onPress(() {
Navigator.of(context).pop();
immediateLiveCareViewModel.setLiveCareSelectedCallType(1);
}),
- MedicalFileCard(
- label: "Audio Call".needTranslation,
- textColor: AppColors.blackColor,
- backgroundColor: AppColors.whiteColor,
- svgIcon: AppAssets.allergy_info_icon,
- isLargeText: true,
- iconSize: 36.h,
+ SizedBox(height: 16.h),
+ checkInOptionCard(
+ AppAssets.checkin_location_icon,
+ "Audio Call".needTranslation,
+ "Provide your feedback on our services".needTranslation,
).onPress(() {
Navigator.of(context).pop();
immediateLiveCareViewModel.setLiveCareSelectedCallType(2);
}),
- MedicalFileCard(
- label: "Phone Call".needTranslation,
- textColor: AppColors.blackColor,
- backgroundColor: AppColors.whiteColor,
- svgIcon: AppAssets.vaccine_info_icon,
- isLargeText: true,
- iconSize: 36.h,
+ SizedBox(height: 16.h),
+ checkInOptionCard(
+ AppAssets.checkin_location_icon,
+ "Phone Call".needTranslation,
+ "Live chat option with HMG".needTranslation,
).onPress(() {
Navigator.of(context).pop();
immediateLiveCareViewModel.setLiveCareSelectedCallType(3);
@@ -63,4 +51,45 @@ class SelectLiveCareCallType extends StatelessWidget {
],
);
}
+
+ Widget checkInOptionCard(String icon, String title, String subTitle) {
+ return Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 20.r,
+ hasShadow: false,
+ ),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Utils.buildSvgWithAssets(icon: icon, width: 40.h, height: 40.h, fit: BoxFit.fill),
+ SizedBox(height: 16.h),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ title.toText16(isBold: true, color: AppColors.textColor),
+ subTitle.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
+ ],
+ ),
+ ),
+ Transform.flip(
+ flipX: getIt.get().isArabic(),
+ child: Utils.buildSvgWithAssets(
+ icon: AppAssets.forward_arrow_icon_small,
+ iconColor: AppColors.blackColor,
+ width: 18.h,
+ height: 13.h,
+ fit: BoxFit.contain,
+ ),
+ ),
+ ],
+ ),
+ ],
+ ).paddingAll(16.h),
+ );
+ }
}
diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart
index fe0268d..47f8118 100644
--- a/lib/presentation/home/landing_page.dart
+++ b/lib/presentation/home/landing_page.dart
@@ -40,6 +40,8 @@ import 'package:hmg_patient_app_new/presentation/home/widgets/small_service_card
import 'package:hmg_patient_app_new/presentation/home/widgets/welcome_widget.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart';
import 'package:hmg_patient_app_new/presentation/profile_settings/profile_settings.dart';
+import 'package:hmg_patient_app_new/presentation/tele_consultation/zoom/call_screen.dart';
+import 'package:hmg_patient_app_new/routes/app_routes.dart';
import 'package:hmg_patient_app_new/services/cache_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@@ -93,13 +95,13 @@ class _LandingPageState extends State {
if (appState.isAuthenticated) {
habibWalletVM.initHabibWalletProvider();
habibWalletVM.getPatientBalanceAmount();
+ immediateLiveCareViewModel.initImmediateLiveCare();
+ immediateLiveCareViewModel.getPatientLiveCareHistory();
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
myAppointmentsViewModel.getPatientMyDoctors();
prescriptionsViewModel.initPrescriptionsViewModel();
insuranceViewModel.initInsuranceProvider();
- immediateLiveCareViewModel.initImmediateLiveCare();
- immediateLiveCareViewModel.getPatientLiveCareHistory();
emergencyServicesViewModel.checkPatientERAdvanceBalance();
}
});
@@ -140,10 +142,19 @@ class _LandingPageState extends State {
text: LocaleKeys.loginOrRegister.tr(context: context),
onPressed: () async {
await authVM.onLoginPressed();
+
+ // Navigator.pushReplacementNamed(
+ // // context,
+ // context,
+ // AppRoutes.zoomCallPage,
+ // // arguments: CallArguments(appointmentID, "111", "Patient", "40", "1", true, 1),
+ // arguments: CallArguments("test123", "123", "Patient", "40", "0", true, 1),
+ // // arguments: CallArguments("SmallDailyStandup9875", "123", "Patient", "40", "0", false, int.parse(widget.incomingCallData!.appointmentNo!)),
+ // );
},
- backgroundColor: Color(0xffFEE9EA),
- borderColor: Color(0xffFEE9EA),
- textColor: Color(0xffED1C2B),
+ backgroundColor: AppColors.secondaryLightRedColor,
+ borderColor: AppColors.secondaryLightRedColor,
+ textColor: AppColors.primaryRedColor,
fontSize: 14.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
@@ -203,8 +214,8 @@ class _LandingPageState extends State {
Navigator.of(context).push(CustomPageRoute(page: MyAppointmentsPage()));
}),
SizedBox(height: 16.h),
- Consumer(
- builder: (context, myAppointmentsVM, child) {
+ Consumer2(
+ builder: (context, myAppointmentsVM, immediateLiveCareVM, child) {
return myAppointmentsVM.isMyAppointmentsLoading
? Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
@@ -248,14 +259,14 @@ class _LandingPageState extends State {
indicatorLayout: PageIndicatorLayout.COLOR,
axisDirection: AxisDirection.right,
controller: _controller,
- itemHeight: 270.h,
+ itemHeight: 255.h,
pagination: SwiperPagination(
alignment: Alignment.bottomCenter,
- margin: EdgeInsets.only(top: 250.h + 8 + 24),
+ margin: EdgeInsets.only(top: 240.h + 8 + 24),
builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor),
),
itemBuilder: (BuildContext context, int index) {
- return (immediateLiveCareViewModel.patientHasPendingLiveCareRequest && index == 0)
+ return (immediateLiveCareVM.patientHasPendingLiveCareRequest && index == 0)
? Column(
children: [
SizedBox(height: 12.h),
@@ -279,7 +290,7 @@ class _LandingPageState extends State {
Row(
children: [
AppCustomChipWidget(
- labelText: immediateLiveCareViewModel.patientLiveCareHistoryList[0].stringCallStatus,
+ labelText: immediateLiveCareVM.patientLiveCareHistoryList[0].stringCallStatus,
backgroundColor: AppColors.warningColorYellow.withValues(alpha: 0.20),
textColor: AppColors.alertColor,
),
@@ -287,7 +298,7 @@ class _LandingPageState extends State {
AppCustomChipWidget(
icon: AppAssets.appointment_calendar_icon,
labelText: DateUtil.formatDateToDate(
- DateUtil.convertStringToDate(immediateLiveCareViewModel.patientLiveCareHistoryList[0].arrivalTime), false)),
+ DateUtil.convertStringToDate(immediateLiveCareVM.patientLiveCareHistoryList[0].arrivalTime), false)),
],
),
Utils.buildSvgWithAssets(icon: AppAssets.waiting_icon, width: 24.h, height: 24.h),
@@ -297,7 +308,7 @@ class _LandingPageState extends State {
SizedBox(height: 10.h),
"Hala ${appState.getAuthenticatedUser()!.firstName}!!!".needTranslation.toText16(isBold: true),
SizedBox(height: 8.h),
- "Your turn is after ${immediateLiveCareViewModel.patientLiveCareHistoryList[0].patCount} patients.".toText14(isBold: true),
+ "Your turn is after ${immediateLiveCareVM.patientLiveCareHistoryList[0].patCount} patients.".toText14(isBold: true),
SizedBox(height: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -305,7 +316,7 @@ class _LandingPageState extends State {
"Expected waiting time: ".toText12(isBold: true),
SizedBox(height: 8.h),
ValueListenableBuilder(
- valueListenable: immediateLiveCareViewModel.durationNotifier,
+ valueListenable: immediateLiveCareVM.durationNotifier,
builder: (context, duration, child) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
@@ -561,7 +572,7 @@ class _LandingPageState extends State {
Navigator.of(context).push(CustomPageRoute(page: ServicesPage()));
}),
],
- ).paddingSymmetrical(24.h, 0.h),
+ ).paddingSymmetrical(24.w, 0.h),
SizedBox(
height: 340.h,
child: ListView.separated(
@@ -613,7 +624,7 @@ class _LandingPageState extends State {
cacheService.saveBool(key: CacheConst.quickLoginEnabled, value: true);
setState(() {});
await Future.delayed(Duration(milliseconds: 3000)).then((value) {
- Navigator.pop(context);
+ if (mounted) Navigator.pop(context);
});
});
},
diff --git a/lib/presentation/lab/lab_orders_page.dart b/lib/presentation/lab/lab_orders_page.dart
index 184f713..81c507f 100644
--- a/lib/presentation/lab/lab_orders_page.dart
+++ b/lib/presentation/lab/lab_orders_page.dart
@@ -1 +1 @@
-import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.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/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_order_by_test.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart';
import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:provider/provider.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
import '../../widgets/appbar/collapsing_list_view.dart';
class LabOrdersPage extends StatefulWidget {
const LabOrdersPage({super.key});
@override
State createState() => _LabOrdersPageState();
}
class _LabOrdersPageState extends State {
late LabViewModel labProvider;
late DateRangeSelectorRangeViewModel rangeViewModel;
late AppState _appState;
List?> labSuggestions = [];
int? expandedIndex;
String? selectedFilterText = '';
int activeIndex = 0;
@override
void initState() {
scheduleMicrotask(() {
// labProvider.initLabProvider();
});
super.initState();
}
@override
Widget build(BuildContext context) {
labProvider = Provider.of(context, listen: false);
rangeViewModel = Provider.of(context);
_appState = getIt();
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: LocaleKeys.labResults.tr(),
search: () async {
final lavVM = Provider.of(context, listen: false);
if (lavVM.isLabOrdersLoading) {
return;
} else {
String? value = await Navigator.of(context).push(
CustomPageRoute(
page: SearchLabResultsContent(labSuggestionsList: lavVM.labSuggestions),
fullScreenDialog: true,
direction: AxisDirection.down,
),
);
if (value != null) {
selectedFilterText = value;
lavVM.filterLabReports(value);
}
}
},
child: SingleChildScrollView(
padding: EdgeInsets.all(24.h),
physics: NeverScrollableScrollPhysics(),
child: Consumer(
builder: (context, model, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomTabBar(
activeTextColor: Color(0xffED1C2B),
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
tabs: [
CustomTabBarModel(null, "By Visit".needTranslation),
CustomTabBarModel(null, "By Test".needTranslation),
// CustomTabBarModel(null, "Completed".needTranslation),
],
onTabChange: (index) {
activeIndex = index;
setState(() {});
},
),
SizedBox(height: 8.h),
selectedFilterText!.isNotEmpty
? CustomChipWidget(
chipText: selectedFilterText!,
chipType: ChipTypeEnum.alert,
isSelected: true,
)
: SizedBox(),
activeIndex == 0
? ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: model.isLabOrdersLoading
? 5
: model.patientLabOrders.isNotEmpty
? model.patientLabOrders.length
: 1,
itemBuilder: (context, index) {
final isExpanded = expandedIndex == index;
return model.isLabOrdersLoading
? LabResultItemView(
onTap: () {},
labOrder: null,
index: index,
isLoading: true,
)
: model.patientLabOrders.isNotEmpty
? AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: LabResultItemView(
onTap: () {
model.currentlySelectedPatientOrder =
model.patientLabOrders[
index];
labProvider.getPatientLabResultByHospital(model.patientLabOrders[
index]);
labProvider
.getPatientSpecialResult(
model.patientLabOrders[
index]);
Navigator.push(
context,
CustomPageRoute(
page: LabResultByClinic(labOrder: model.patientLabOrders[index]),
));
},
labOrder: model.patientLabOrders[index],
index: index,
isExpanded: isExpanded),
),
),
)
: Utils.getNoDataWidget(context, noDataText: "You don't have any lab results yet.".needTranslation);
},
)
: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: model.isLabOrdersLoading
? 5
: model.uniqueTests.toList().isNotEmpty
? model.uniqueTests.toList().length
: 1,
itemBuilder: (context, index) {
final isExpanded = expandedIndex == index;
return model.isLabOrdersLoading
? LabResultItemView(
onTap: () {},
labOrder: null,
index: index,
isLoading: true,
)
: model.uniqueTests.toList().isNotEmpty
? AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: LabOrderByTest(
appState: _appState,
onTap: () {
if (model.uniqueTests.toList()[index].model != null) {
rangeViewModel.flush();
model.getPatientLabResult(model.uniqueTests.toList()[index].model!, model.uniqueTests.toList()[index].description!,
(_appState.isArabic() ? model.uniqueTests.toList()[index].testDescriptionAr! : model.uniqueTests.toList()[index].testDescriptionEn!));
}
},
tests: model.uniqueTests.toList()[index],
index: index,
isExpanded: isExpanded)),
),
)
: Utils.getNoDataWidget(context, noDataText: "You don't have any lab results yet.".needTranslation);
},
)
],
);
},
),
),
));
}
Color getLabOrderStatusColor(num status) {
switch (status) {
case 44:
return AppColors.warningColorYellow;
case 45:
return AppColors.warningColorYellow;
case 16:
return AppColors.successColor;
case 17:
return AppColors.successColor;
default:
return AppColors.greyColor;
}
}
String getLabOrderStatusText(num status) {
switch (status) {
case 44:
return LocaleKeys.resultsPending.tr(context: context);
case 45:
return LocaleKeys.resultsPending.tr(context: context);
case 16:
return LocaleKeys.resultsAvailable.tr(context: context);
case 17:
return LocaleKeys.resultsAvailable.tr(context: context);
default:
return "";
}
}
getLabSuggestions(LabViewModel model) {
if (model.patientLabOrders.isEmpty) {
return [];
}
return model.patientLabOrders.map((m) => m.testDetails).toList();
}
}
\ No newline at end of file
+import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.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/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_order_by_test.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_via_clinic/LabResultByClinic.dart';
import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_view_model.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:provider/provider.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
import '../../widgets/appbar/collapsing_list_view.dart';
class LabOrdersPage extends StatefulWidget {
const LabOrdersPage({super.key});
@override
State createState() => _LabOrdersPageState();
}
class _LabOrdersPageState extends State {
late LabViewModel labProvider;
late DateRangeSelectorRangeViewModel rangeViewModel;
late AppState _appState;
List?> labSuggestions = [];
int? expandedIndex;
String? selectedFilterText = '';
int activeIndex = 0;
@override
void initState() {
scheduleMicrotask(() {
labProvider.initLabProvider();
});
super.initState();
}
@override
Widget build(BuildContext context) {
labProvider = Provider.of(context, listen: false);
rangeViewModel = Provider.of(context);
_appState = getIt();
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: LocaleKeys.labResults.tr(),
search: () async {
final lavVM = Provider.of(context, listen: false);
if (lavVM.isLabOrdersLoading) {
return;
} else {
String? value = await Navigator.of(context).push(
CustomPageRoute(
page: SearchLabResultsContent(labSuggestionsList: lavVM.labSuggestions),
fullScreenDialog: true,
direction: AxisDirection.down,
),
);
if (value != null) {
selectedFilterText = value;
lavVM.filterLabReports(value);
}
}
},
child: SingleChildScrollView(
padding: EdgeInsets.all(24.h),
physics: NeverScrollableScrollPhysics(),
child: Consumer(
builder: (context, model, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomTabBar(
activeTextColor: Color(0xffED1C2B),
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
tabs: [
CustomTabBarModel(null, "By Visit".needTranslation),
CustomTabBarModel(null, "By Test".needTranslation),
// CustomTabBarModel(null, "Completed".needTranslation),
],
onTabChange: (index) {
activeIndex = index;
setState(() {});
},
),
SizedBox(height: 8.h),
selectedFilterText!.isNotEmpty
? CustomChipWidget(
chipText: selectedFilterText!,
chipType: ChipTypeEnum.alert,
isSelected: true,
)
: SizedBox(),
activeIndex == 0
? ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: model.isLabOrdersLoading
? 5
: model.patientLabOrders.isNotEmpty
? model.patientLabOrders.length
: 1,
itemBuilder: (context, index) {
final isExpanded = expandedIndex == index;
return model.isLabOrdersLoading
? LabResultItemView(
onTap: () {},
labOrder: null,
index: index,
isLoading: true,
)
: model.patientLabOrders.isNotEmpty
? AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: LabResultItemView(
onTap: () {
model.currentlySelectedPatientOrder =
model.patientLabOrders[
index];
labProvider.getPatientLabResultByHospital(model.patientLabOrders[
index]);
labProvider
.getPatientSpecialResult(
model.patientLabOrders[
index]);
Navigator.push(
context,
CustomPageRoute(
page: LabResultByClinic(labOrder: model.patientLabOrders[index]),
));
},
labOrder: model.patientLabOrders[index],
index: index,
isExpanded: isExpanded),
),
),
)
: Utils.getNoDataWidget(context, noDataText: "You don't have any lab results yet.".needTranslation);
},
)
: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: model.isLabOrdersLoading
? 5
: model.uniqueTests.toList().isNotEmpty
? model.uniqueTests.toList().length
: 1,
itemBuilder: (context, index) {
final isExpanded = expandedIndex == index;
return model.isLabOrdersLoading
? LabResultItemView(
onTap: () {},
labOrder: null,
index: index,
isLoading: true,
)
: model.uniqueTests.toList().isNotEmpty
? AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: LabOrderByTest(
appState: _appState,
onTap: () {
if (model.uniqueTests.toList()[index].model != null) {
rangeViewModel.flush();
model.getPatientLabResult(model.uniqueTests.toList()[index].model!, model.uniqueTests.toList()[index].description!,
(_appState.isArabic() ? model.uniqueTests.toList()[index].testDescriptionAr! : model.uniqueTests.toList()[index].testDescriptionEn!), "");
}
},
tests: model.uniqueTests.toList()[index],
index: index,
isExpanded: isExpanded)),
),
)
: Utils.getNoDataWidget(context, noDataText: "You don't have any lab results yet.".needTranslation);
},
)
],
);
},
),
),
));
}
Color getLabOrderStatusColor(num status) {
switch (status) {
case 44:
return AppColors.warningColorYellow;
case 45:
return AppColors.warningColorYellow;
case 16:
return AppColors.successColor;
case 17:
return AppColors.successColor;
default:
return AppColors.greyColor;
}
}
String getLabOrderStatusText(num status) {
switch (status) {
case 44:
return LocaleKeys.resultsPending.tr(context: context);
case 45:
return LocaleKeys.resultsPending.tr(context: context);
case 16:
return LocaleKeys.resultsAvailable.tr(context: context);
case 17:
return LocaleKeys.resultsAvailable.tr(context: context);
default:
return "";
}
}
getLabSuggestions(LabViewModel model) {
if (model.patientLabOrders.isEmpty) {
return [];
}
return model.patientLabOrders.map((m) => m.testDetails).toList();
}
}
\ No newline at end of file
diff --git a/lib/presentation/lab/lab_result_via_clinic/LabResultList.dart b/lib/presentation/lab/lab_result_via_clinic/LabResultList.dart
index 8893ffd..3f05443 100644
--- a/lib/presentation/lab/lab_result_via_clinic/LabResultList.dart
+++ b/lib/presentation/lab/lab_result_via_clinic/LabResultList.dart
@@ -26,7 +26,7 @@ class LabResultList extends StatelessWidget {
shrinkWrap: true,itemCount: list.length,itemBuilder: (____, index) {
var labItem = list[index];
return LabOrderResultItem(onTap: () {
- model.getPatientLabResult(model.currentlySelectedPatientOrder!, labItem.description ?? "", labItem.packageShortDescription!);
+ model.getPatientLabResult(model.currentlySelectedPatientOrder!, labItem.description ?? "", labItem.packageShortDescription!, labItem.uOM ?? "");
},
tests: labItem,
index: index,
diff --git a/lib/presentation/lab/lab_results/lab_result_details.dart b/lib/presentation/lab/lab_results/lab_result_details.dart
index 2330d0d..67eae63 100644
--- a/lib/presentation/lab/lab_results/lab_result_details.dart
+++ b/lib/presentation/lab/lab_results/lab_result_details.dart
@@ -59,115 +59,72 @@ class LabResultDetails extends StatelessWidget {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- Text(
- recentLabResult.testCode ?? "",
- style: TextStyle(
- fontSize: 32,
- fontFamily: 'Poppins',
- fontWeight: FontWeight.w600,
- color: AppColors.textColor,
- letterSpacing: -2),
- ),
- Text(
- "Result of ${recentLabResult.verifiedOn ?? ""}".needTranslation,
- style: TextStyle(
- fontSize: 12,
- fontFamily: 'Poppins',
- fontWeight: FontWeight.w500,
- color: AppColors.greyTextColor,
- ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ (recentLabResult.testCode ?? "").toText28(isBold: true, color: AppColors.textColor, letterSpacing: -2),
+ Visibility(
+ visible: recentLabResult.checkIfGraphShouldBeDisplayed() == true,
+ child: Column(
+ spacing: 6.h,
+ children: [
+ context
+ .read()
+ .getSeverityText(
+ recentLabResult.calculatedResultFlag ?? "",
+ )
+ .tr()
+ .toText10(weight: FontWeight.w500, color: AppColors.greyTextColor),
+ Utils.buildSvgWithAssets(
+ icon: AppAssets.lab_result_indicator,
+ width: 21,
+ height: 23,
+ iconColor: context.read().getColor(
+ recentLabResult.calculatedResultFlag ?? "",
+ )),
+ ],
+ ),
+ ),
+ ],
),
+ SizedBox(height: 4.h),
+ ("Result of ${recentLabResult.verifiedOn ?? ""}".needTranslation).toText11(weight: FontWeight.w500, color: AppColors.greyTextColor),
],
),
- //todo change the text color according to the provided test values
Row(
crossAxisAlignment: CrossAxisAlignment.center,
-
children: [
Expanded(
child: Row(
-
mainAxisSize: MainAxisSize.max,
children: [
Flexible(
- child: Text(
- "${recentLabResult.resultValue} ${recentLabResult.uOM}" ??
- "",
- style: TextStyle(
- fontSize: 24.f,
- fontWeight: FontWeight.w600,
- fontFamily: 'Poppins',
+ child: ("${recentLabResult.resultValue} ${recentLabResult.uOM}" ?? "").toText28(
+ isBold: true,
color: context.read().getColor(
recentLabResult.calculatedResultFlag ?? "",
- ),
- letterSpacing: -2,
- ),
- overflow: TextOverflow.ellipsis, // prevent overflow
- maxLines: 1,
- softWrap: false,
- ),
+ ),
+ letterSpacing: -2),
),
SizedBox(width: 4.h,),
- Expanded(
- flex: 2,
- child: Visibility(
- visible: recentLabResult.referanceRange != null,
- child: Text(
- "(Reference range ${recentLabResult.referanceRange})".needTranslation,
- style: TextStyle(
- fontSize: 12.f,
- fontWeight: FontWeight.w500,
- fontFamily: 'Poppins',
- color: AppColors.greyTextColor,
- ),
- // overflow: TextOverflow.ellipsis,
- // maxLines: 2,
- softWrap: true,
- ),
- ),
- ),
- ],
- ),
- ),
- Visibility(
- visible:
- recentLabResult.checkIfGraphShouldBeDisplayed() == true,
- child: Column(
- spacing: 6.h,
- children: [
- context
- .read()
- .getSeverityText(
- recentLabResult.calculatedResultFlag ?? "",
- )
- .tr()
- .toText10(
- weight: FontWeight.w500,
- color: AppColors.greyTextColor),
- Utils.buildSvgWithAssets(
- icon: AppAssets.lab_result_indicator,
- width: 21,
- height: 23,
- iconColor: context.read().getColor(
- recentLabResult.calculatedResultFlag ?? "",
- )),
],
),
),
- // SizedBox(
- // width: 21,
- // child: Utils.buildSvgWithAssets(
- // icon: AppAssets.lab_result_indicator,
- // width: 21,
- // height: 23,
- // iconColor: context.read().getColor(
- // recentLabResult.calculatedResultFlag ?? "",
- // ),
- // ),
- // ),
],
- )
-
+ ),
+ Visibility(
+ visible: recentLabResult.referanceRange != null,
+ child: Text(
+ "Reference range: \n${recentLabResult.referanceRange!.trim()}".needTranslation,
+ style: TextStyle(
+ fontSize: 12.f,
+ fontWeight: FontWeight.w500,
+ fontFamily: 'Poppins',
+ color: AppColors.greyTextColor,
+ ),
+ softWrap: true,
+ ),
+ ),
],
));
diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart
index 1652812..7b5341c 100644
--- a/lib/presentation/medical_file/medical_file_page.dart
+++ b/lib/presentation/medical_file/medical_file_page.dart
@@ -225,9 +225,9 @@ class _MedicalFilePageState extends State {
),
AppCustomChipWidget(
icon: AppAssets.blood_icon,
- labelText: "Blood: ${appState.getUserBloodGroup.isEmpty ? "N/A" : appState.getUserBloodGroup.isEmpty}",
+ labelText: "Blood: ${appState.getUserBloodGroup.isEmpty ? "N/A" : appState.getUserBloodGroup.isEmpty}".needTranslation,
iconColor: AppColors.primaryRedColor,
- labelPadding: EdgeInsetsDirectional.only(end: 8.w),
+ labelPadding: EdgeInsetsDirectional.only(end: 4.w, start: 0.w),
),
Consumer(builder: (context, insuranceVM, child) {
return AppCustomChipWidget(
@@ -390,6 +390,7 @@ class _MedicalFilePageState extends State {
: ListView.separated(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
+ padding: EdgeInsets.only(left: 24.w, right: 24.w),
itemCount: myAppointmentsVM.patientAppointmentsHistoryList.length,
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
@@ -440,9 +441,9 @@ class _MedicalFilePageState extends State {
),
);
},
- separatorBuilder: (BuildContext cxt, int index) => SizedBox(width: 12.h),
+ separatorBuilder: (BuildContext cxt, int index) => SizedBox(width: 16.w),
),
- ).paddingSymmetrical(24.w, 0);
+ );
}),
SizedBox(height: 24.h),
"Lab & Radiology".needTranslation.toText18(isBold: true).paddingSymmetrical(24.w, 0.h),
@@ -695,11 +696,12 @@ class _MedicalFilePageState extends State {
),
).paddingSymmetrical(24.w, 0.h)
: SizedBox(
- height: 100.h,
+ height: 110.h,
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: myAppointmentsVM.patientMyDoctorsList.length,
shrinkWrap: true,
+ padding: EdgeInsets.only(left: 24.w, right: 24.w),
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
position: index,
@@ -719,7 +721,8 @@ class _MedicalFilePageState extends State {
fit: BoxFit.cover,
).circle(100).toShimmer2(isShow: false, radius: 50.r),
SizedBox(height: 8.h),
- Expanded(
+ SizedBox(
+ width: 80.w,
child: (myAppointmentsVM.patientMyDoctorsList[index].doctorName)
.toString()
.toText12(fontWeight: FontWeight.w500, isCenter: true, maxLine: 2)
@@ -758,7 +761,7 @@ class _MedicalFilePageState extends State {
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(width: 8.h),
),
- ).paddingSymmetrical(24.w, 0);
+ );
}),
SizedBox(height: 24.h),
"Others".needTranslation.toText18(isBold: true).paddingSymmetrical(24.w, 0.h),
diff --git a/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart b/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart
index 037860f..1b09dd5 100644
--- a/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart
+++ b/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart
@@ -53,7 +53,7 @@ class MedicalFileAppointmentCard extends StatelessWidget {
).toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading),
SizedBox(height: 16.h),
Container(
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: false),
width: 200.w,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
diff --git a/lib/presentation/medical_file/widgets/medical_file_card.dart b/lib/presentation/medical_file/widgets/medical_file_card.dart
index 8c38363..6343e2a 100644
--- a/lib/presentation/medical_file/widgets/medical_file_card.dart
+++ b/lib/presentation/medical_file/widgets/medical_file_card.dart
@@ -29,7 +29,7 @@ class MedicalFileCard extends StatelessWidget {
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: backgroundColor,
borderRadius: 12.r,
- hasShadow: true
+ hasShadow: false
),
padding: EdgeInsets.all(12.w),
child: Column(
diff --git a/lib/presentation/tele_consultation/zoom/call_screen.dart b/lib/presentation/tele_consultation/zoom/call_screen.dart
new file mode 100644
index 0000000..21ad42f
--- /dev/null
+++ b/lib/presentation/tele_consultation/zoom/call_screen.dart
@@ -0,0 +1,1840 @@
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_hooks/flutter_hooks.dart';
+import 'package:flutter_ios_voip_kit_karmm/flutter_ios_voip_kit.dart';
+import 'package:flutter_zoom_videosdk/flutter_zoom_view.dart';
+import 'package:flutter_zoom_videosdk/native/zoom_videosdk.dart';
+import 'package:flutter_zoom_videosdk/native/zoom_videosdk_camera_device.dart';
+import 'package:flutter_zoom_videosdk/native/zoom_videosdk_cmd_channel.dart';
+import 'package:flutter_zoom_videosdk/native/zoom_videosdk_event_listener.dart';
+import 'package:flutter_zoom_videosdk/native/zoom_videosdk_live_transcription_message_info.dart';
+import 'package:flutter_zoom_videosdk/native/zoom_videosdk_share_action.dart';
+import 'package:flutter_zoom_videosdk/native/zoom_videosdk_user.dart';
+import 'package:get_it/get_it.dart';
+import 'package:hmg_patient_app_new/core/app_export.dart';
+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/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/cache_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';
+
+class CallScreen extends StatefulHookWidget {
+ const CallScreen({Key? key}) : super(key: key);
+
+ @override
+ State createState() => _CallScreenState();
+}
+
+class _CallScreenState extends State {
+ static TextEditingController changeNameController = TextEditingController();
+ double opacityLevel = 1.0;
+
+ final voIPKit = FlutterIOSVoIPKit.instance;
+
+ bool isScreenBeingShared = false;
+
+ void _changeOpacity() {
+ setState(() => opacityLevel = opacityLevel == 0 ? 1.0 : 0.0);
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ var zoom = ZoomVideoSdk();
+ var eventListener = ZoomVideoSdkEventListener();
+ var isInSession = useState(false);
+ var sessionName = useState('');
+ var sessionPassword = useState('');
+ var users = useState([]);
+ var fullScreenUser = useState(null);
+ var sharingUser = useState(null);
+ var videoInfo = useState('');
+ var isSharing = useState(false);
+ var isMuted = useState(true);
+ var isVideoOn = useState(false);
+ var isSpeakerOn = useState(false);
+ var isRenameModalVisible = useState(false);
+ var isRecordingStarted = useState(false);
+ var isMicOriginalOn = useState(false);
+ var isMounted = useIsMounted();
+ var audioStatusFlag = useState(false);
+ var videoStatusFlag = useState(false);
+ var userNameFlag = useState(false);
+ var userShareStatusFlag = useState(false);
+ var isReceiveSpokenLanguageContentEnabled = useState(false);
+ var isVideoMirrored = useState(false);
+ var isOriginalAspectRatio = useState(false);
+ var isPiPView = useState(false);
+ var isSharedCamera = useState(false);
+ CameraShareView cameraShareView = const CameraShareView(creationParams: {});
+
+ //hide status bar
+ SystemChrome.setEnabledSystemUIMode(SystemUiMode.leanBack);
+ var circleButtonSize = 65.0;
+ Color backgroundColor = const Color(0xFF232323);
+ Color buttonBackgroundColor = const Color.fromRGBO(0, 0, 0, 0.6);
+ Color chatTextColor = const Color(0xFFAAAAAA);
+ Widget changeNamePopup;
+ final args = ModalRoute.of(context)!.settings.arguments as CallArguments;
+
+ useEffect(() {
+ Future.microtask(() async {
+ var token = generateJwt(args.sessionName, args.role);
+
+ Utils.removeFromPrefs(CacheConst.isAppOpenedFromCall);
+
+ try {
+ Map SDKaudioOptions = {"connect": true, "mute": false, "autoAdjustSpeakerVolume": false};
+ Map SDKvideoOptions = {
+ "localVideoOn": true,
+ };
+ JoinSessionConfig joinSession = JoinSessionConfig(
+ sessionName: args.sessionName,
+ sessionPassword: args.sessionPwd,
+ token: token,
+ userName: args.displayName,
+ audioOptions: SDKaudioOptions,
+ videoOptions: SDKvideoOptions,
+ sessionIdleTimeoutMins: int.parse(args.sessionIdleTimeoutMins),
+ );
+ await zoom.joinSession(joinSession);
+ } catch (e) {
+ const AlertDialog(
+ title: Text("Error"),
+ content: Text("Failed to join the session"),
+ );
+ Future.delayed(const Duration(milliseconds: 1000)).asStream().listen((event) {
+ Navigator.pushAndRemoveUntil(
+ context,
+ CustomPageRoute(
+ page: LandingNavigation(),
+ ),
+ (r) => false);
+ });
+ }
+ });
+ return null;
+ }, []);
+
+ useEffect(() {
+ final sessionJoinListener = eventListener.addListener(EventType.onSessionJoin, (data) async {
+ data = data as Map;
+ isInSession.value = true;
+ zoom.session.getSessionName().then((value) => sessionName.value = value!);
+ sessionPassword.value = await zoom.session.getSessionPassword();
+ debugPrint("sessionPhonePasscode: ${await zoom.session.getSessionPhonePasscode()}");
+ ZoomVideoSdkUser mySelf = ZoomVideoSdkUser.fromJson(jsonDecode(data['sessionUser']));
+ List? remoteUsers = await zoom.session.getRemoteUsers();
+ var muted = await mySelf.audioStatus?.isMuted();
+ var videoOn = await mySelf.videoStatus?.isOn();
+ var speakerOn = await zoom.audioHelper.getSpeakerStatus();
+ fullScreenUser.value = mySelf;
+ remoteUsers?.insert(0, mySelf);
+ isMuted.value = muted!;
+ isSpeakerOn.value = speakerOn;
+ isVideoOn.value = videoOn!;
+ users.value = remoteUsers!;
+ isReceiveSpokenLanguageContentEnabled.value = await zoom.liveTranscriptionHelper.isReceiveSpokenLanguageContentEnabled();
+ });
+
+ final sessionLeaveListener = eventListener.addListener(EventType.onSessionLeave, (data) async {
+ data = data as Map;
+ debugPrint("onSessionLeave: ${data['reason']}");
+ isInSession.value = false;
+ users.value = [];
+ fullScreenUser.value = null;
+ // Navigator.popAndPushNamed(
+ // context,
+ // "Join",
+ // arguments: JoinArguments(args.isJoin, sessionName.value, sessionPassword.value, args.displayName, args.sessionIdleTimeoutMins, args.role),
+ // );
+ Navigator.pushAndRemoveUntil(
+ context,
+ CustomPageRoute(
+ page: LandingNavigation(),
+ ),
+ (r) => false);
+ });
+
+ final sessionNeedPasswordListener = eventListener.addListener(EventType.onSessionNeedPassword, (data) async {
+ showDialog(
+ context: context,
+ builder: (BuildContext context) => AlertDialog(
+ title: const Text('Session Need Password'),
+ content: const Text('Password is required'),
+ actions: [
+ TextButton(
+ onPressed: () async => {
+ Navigator.pushAndRemoveUntil(
+ context,
+ CustomPageRoute(
+ page: LandingNavigation(),
+ ),
+ (r) => false),
+ await zoom.leaveSession(false),
+ },
+ child: const Text('OK'),
+ ),
+ ],
+ ),
+ );
+ });
+
+ final sessionPasswordWrongListener = eventListener.addListener(EventType.onSessionPasswordWrong, (data) async {
+ showDialog(
+ context: context,
+ builder: (BuildContext context) => AlertDialog(
+ title: const Text('Session Password Incorrect'),
+ content: const Text('Password is wrong'),
+ actions: [
+ TextButton(
+ onPressed: () async => {
+ Navigator.popAndPushNamed(context, 'Join', arguments: JoinArguments(args.isJoin, args.sessionName, "", args.displayName, args.sessionIdleTimeoutMins, args.role)),
+ await zoom.leaveSession(false),
+ },
+ child: const Text('OK'),
+ ),
+ ],
+ ),
+ );
+ });
+
+ final userVideoStatusChangedListener = eventListener.addListener(EventType.onUserVideoStatusChanged, (data) async {
+ data = data as Map;
+ ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
+ var userListJson = jsonDecode(data['changedUsers']) as List;
+ List userList = userListJson.map((userJson) => ZoomVideoSdkUser.fromJson(userJson)).toList();
+ for (var user in userList) {
+ {
+ if (user.userId == mySelf?.userId) {
+ mySelf?.videoStatus?.isOn().then((on) => isVideoOn.value = on);
+ }
+ }
+ }
+ videoStatusFlag.value = !videoStatusFlag.value;
+ });
+
+ final userAudioStatusChangedListener = eventListener.addListener(EventType.onUserAudioStatusChanged, (data) async {
+ data = data as Map;
+ ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
+ var userListJson = jsonDecode(data['changedUsers']) as List;
+ List userList = userListJson.map((userJson) => ZoomVideoSdkUser.fromJson(userJson)).toList();
+ for (var user in userList) {
+ {
+ if (user.userId == mySelf?.userId) {
+ mySelf?.audioStatus?.isMuted().then((muted) => isMuted.value = muted);
+ }
+ }
+ }
+ audioStatusFlag.value = !audioStatusFlag.value;
+ });
+
+ final userShareStatusChangeListener = eventListener.addListener(EventType.onUserShareStatusChanged, (data) async {
+ data = data as Map;
+ ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
+ ZoomVideoSdkUser shareUser = ZoomVideoSdkUser.fromJson(jsonDecode(data['user'].toString()));
+ ZoomVideoSdkShareAction? shareAction = ZoomVideoSdkShareAction.fromJson(jsonDecode(data['shareAction']));
+
+ if (shareAction.shareStatus == ShareStatus.Start || shareAction.shareStatus == ShareStatus.Resume) {
+ sharingUser.value = shareUser;
+ fullScreenUser.value = shareUser;
+ isSharing.value = (shareUser.userId == mySelf?.userId);
+
+ setState(() {
+ isScreenBeingShared = true;
+ });
+ Future.delayed(const Duration(seconds: 2), () {
+ setState(() {
+ isScreenBeingShared = false;
+ });
+ });
+ } else {
+ sharingUser.value = null;
+ isSharing.value = false;
+ isSharedCamera.value = false;
+ fullScreenUser.value = mySelf;
+ isScreenBeingShared = false;
+ setState(() {
+ isScreenBeingShared = true;
+ });
+ Future.delayed(const Duration(seconds: 2), () {
+ setState(() {
+ isScreenBeingShared = false;
+ });
+ });
+ }
+ userShareStatusFlag.value = !userShareStatusFlag.value;
+ });
+
+ final shareContentChangedListener = eventListener.addListener(EventType.onShareContentChanged, (data) async {
+ data = data as Map;
+ ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
+ ZoomVideoSdkUser shareUser = ZoomVideoSdkUser.fromJson(jsonDecode(data['user'].toString()));
+ ZoomVideoSdkShareAction? shareAction = ZoomVideoSdkShareAction.fromJson(jsonDecode(data['shareAction']));
+ if (shareAction.shareType == ShareType.Camera) {
+ debugPrint("Camera share started");
+ isSharedCamera.value = (shareUser.userId == mySelf?.userId);
+ }
+ });
+
+ final userJoinListener = eventListener.addListener(EventType.onUserJoin, (data) async {
+ if (!isMounted()) return;
+ data = data as Map;
+ ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
+ var userListJson = jsonDecode(data['remoteUsers']) as List;
+ List remoteUserList = userListJson.map((userJson) => ZoomVideoSdkUser.fromJson(userJson)).toList();
+ remoteUserList.insert(0, mySelf!);
+ users.value = remoteUserList;
+ });
+
+ final userLeaveListener = eventListener.addListener(EventType.onUserLeave, (data) async {
+ if (!isMounted()) return;
+ ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
+ data = data as Map;
+ List? remoteUserList = await zoom.session.getRemoteUsers();
+ var leftUserListJson = jsonDecode(data['leftUsers']) as List;
+ List leftUserLis = leftUserListJson.map((userJson) => ZoomVideoSdkUser.fromJson(userJson)).toList();
+ if (fullScreenUser.value != null) {
+ for (var user in leftUserLis) {
+ {
+ if (fullScreenUser.value?.userId == user.userId) {
+ fullScreenUser.value = mySelf;
+ }
+ }
+ }
+ } else {
+ fullScreenUser.value = mySelf;
+ }
+ remoteUserList?.add(mySelf!);
+ users.value = remoteUserList!;
+ });
+
+ final userNameChangedListener = eventListener.addListener(EventType.onUserNameChanged, (data) async {
+ if (!isMounted()) return;
+ data = data as Map;
+ ZoomVideoSdkUser? changedUser = ZoomVideoSdkUser.fromJson(jsonDecode(data['changedUser']));
+ int index;
+ for (var user in users.value) {
+ if (user.userId == changedUser.userId) {
+ index = users.value.indexOf(user);
+ users.value[index] = changedUser;
+ }
+ }
+ userNameFlag.value = !userNameFlag.value;
+ });
+
+ final commandReceived = eventListener.addListener(EventType.onCommandReceived, (data) async {
+ data = data as Map;
+ debugPrint("sender: ${ZoomVideoSdkUser.fromJson(jsonDecode(data['sender']))}, command: ${data['command']}");
+ });
+
+ final liveStreamStatusChangeListener = eventListener.addListener(EventType.onLiveStreamStatusChanged, (data) async {
+ data = data as Map;
+ debugPrint("onLiveStreamStatusChanged: status: ${data['status']}");
+ });
+
+ final liveTranscriptionStatusChangeListener = eventListener.addListener(EventType.onLiveTranscriptionStatus, (data) async {
+ data = data as Map;
+ debugPrint("onLiveTranscriptionStatus: status: ${data['status']}");
+ });
+
+ final cloudRecordingStatusListener = eventListener.addListener(EventType.onCloudRecordingStatus, (data) async {
+ data = data as Map;
+ debugPrint("onCloudRecordingStatus: status: ${data['status']}");
+ ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
+ if (data['status'] == RecordingStatus.Start) {
+ if (mySelf != null && !mySelf.isHost!) {
+ showDialog(
+ context: context,
+ builder: (BuildContext context) => AlertDialog(
+ content: const Text('The session is being recorded.'),
+ actions: [
+ TextButton(
+ onPressed: () async {
+ await zoom.acceptRecordingConsent();
+ if (context.mounted) {
+ Navigator.pop(context);
+ }
+ ;
+ },
+ child: const Text('accept'),
+ ),
+ TextButton(
+ onPressed: () async {
+ String currentConsentType = await zoom.getRecordingConsentType();
+ if (currentConsentType == ConsentType.ConsentType_Individual) {
+ await zoom.declineRecordingConsent();
+ Navigator.pop(context);
+ } else {
+ await zoom.declineRecordingConsent();
+ zoom.leaveSession(false);
+ if (!context.mounted) return;
+ Navigator.popAndPushNamed(
+ context,
+ "Join",
+ arguments: JoinArguments(args.isJoin, sessionName.value, sessionPassword.value, args.displayName, args.sessionIdleTimeoutMins, args.role),
+ );
+ }
+ },
+ child: const Text('decline'),
+ ),
+ ],
+ ),
+ );
+ }
+ isRecordingStarted.value = true;
+ } else {
+ isRecordingStarted.value = false;
+ }
+ });
+
+ final liveTranscriptionMsgInfoReceivedListener = eventListener.addListener(EventType.onLiveTranscriptionMsgInfoReceived, (data) async {
+ data = data as Map;
+ ZoomVideoSdkLiveTranscriptionMessageInfo? messageInfo = ZoomVideoSdkLiveTranscriptionMessageInfo.fromJson(jsonDecode(data['messageInfo']));
+ debugPrint("onLiveTranscriptionMsgInfoReceived: content: ${messageInfo.messageContent}");
+ });
+
+ final inviteByPhoneStatusListener = eventListener.addListener(EventType.onInviteByPhoneStatus, (data) async {
+ data = data as Map;
+ debugPrint("onInviteByPhoneStatus: status: ${data['status']}, reason: ${data['reason']}");
+ });
+
+ final multiCameraStreamStatusChangedListener = eventListener.addListener(EventType.onMultiCameraStreamStatusChanged, (data) async {
+ data = data as Map;
+ ZoomVideoSdkUser? changedUser = ZoomVideoSdkUser.fromJson(jsonDecode(data['changedUser']));
+ var status = data['status'];
+ for (var user in users.value) {
+ {
+ if (changedUser.userId == user.userId) {
+ if (status == MultiCameraStreamStatus.Joined) {
+ user.hasMultiCamera = true;
+ } else if (status == MultiCameraStreamStatus.Left) {
+ user.hasMultiCamera = false;
+ }
+ }
+ }
+ }
+ });
+
+ final requireSystemPermission = eventListener.addListener(EventType.onRequireSystemPermission, (data) async {
+ data = data as Map;
+ ZoomVideoSdkUser? changedUser = ZoomVideoSdkUser.fromJson(jsonDecode(data['changedUser']));
+ var permissionType = data['permissionType'];
+ switch (permissionType) {
+ case SystemPermissionType.Camera:
+ showDialog(
+ context: context,
+ builder: (BuildContext context) => AlertDialog(
+ title: const Text("Can't Access Camera"),
+ content: const Text("please turn on the toggle in system settings to grant permission"),
+ actions: [
+ TextButton(
+ onPressed: () => Navigator.pop(context, 'OK'),
+ child: const Text('OK'),
+ ),
+ ],
+ ),
+ );
+ break;
+ case SystemPermissionType.Microphone:
+ showDialog(
+ context: context,
+ builder: (BuildContext context) => AlertDialog(
+ title: const Text("Can't Access Microphone"),
+ content: const Text("please turn on the toggle in system settings to grant permission"),
+ actions: [
+ TextButton(
+ onPressed: () => Navigator.pop(context, 'OK'),
+ child: const Text('OK'),
+ ),
+ ],
+ ),
+ );
+ break;
+ }
+ });
+
+ final networkStatusChangeListener = eventListener.addListener(EventType.onUserVideoNetworkStatusChanged, (data) async {
+ data = data as Map;
+ ZoomVideoSdkUser? networkUser = ZoomVideoSdkUser.fromJson(jsonDecode(data['user']));
+
+ if (data['status'] == NetworkStatus.Bad) {
+ debugPrint("onUserVideoNetworkStatusChanged: status: ${data['status']}, user: ${networkUser.userName}");
+ }
+ });
+
+ final eventErrorListener = eventListener.addListener(EventType.onError, (data) async {
+ data = data as Map;
+ String errorType = data['errorType'];
+ showDialog(
+ context: context,
+ builder: (BuildContext context) => AlertDialog(
+ title: const Text("Error"),
+ content: Text(errorType),
+ actions: [
+ TextButton(
+ onPressed: () => Navigator.pop(context, 'OK'),
+ child: const Text('OK'),
+ ),
+ ],
+ ),
+ );
+ if (errorType == Errors.SessionJoinFailed || errorType == Errors.SessionDisconnecting) {
+ Timer(
+ const Duration(milliseconds: 1000),
+ () => {
+ Navigator.popAndPushNamed(
+ context,
+ "Join",
+ arguments: JoinArguments(args.isJoin, sessionName.value, sessionPassword.value, args.displayName, args.sessionIdleTimeoutMins, args.role),
+ ),
+ });
+ }
+ });
+
+ final userRecordingConsentListener = eventListener.addListener(EventType.onUserRecordingConsent, (data) async {
+ data = data as Map;
+ ZoomVideoSdkUser? user = ZoomVideoSdkUser.fromJson(jsonDecode(data['user']));
+ debugPrint('userRecordingConsentListener: user= ${user.userName}');
+ });
+
+ final callCRCDeviceStatusListener = eventListener.addListener(EventType.onCallCRCDeviceStatusChanged, (data) async {
+ data = data as Map;
+ debugPrint('onCallCRCDeviceStatusChanged: status = ${data['status']}');
+ });
+
+ final originalLanguageMsgReceivedListener = eventListener.addListener(EventType.onOriginalLanguageMsgReceived, (data) async {
+ data = data as Map;
+ ZoomVideoSdkLiveTranscriptionMessageInfo? messageInfo = ZoomVideoSdkLiveTranscriptionMessageInfo.fromJson(jsonDecode(data['messageInfo']));
+ debugPrint("onOriginalLanguageMsgReceived: content: ${messageInfo.messageContent}");
+ });
+
+ final chatPrivilegeChangedListener = eventListener.addListener(EventType.onChatPrivilegeChanged, (data) async {
+ data = data as Map;
+ String type = data['privilege'];
+ debugPrint('chatPrivilegeChangedListener: type= $type');
+ });
+
+ final testMicStatusListener = eventListener.addListener(EventType.onTestMicStatusChanged, (data) async {
+ data = data as Map;
+ String status = data['status'];
+ debugPrint('testMicStatusListener: status= $status');
+ });
+
+ final micSpeakerVolumeChangedListener = eventListener.addListener(EventType.onMicSpeakerVolumeChanged, (data) async {
+ data = data as Map;
+ int type = data['micVolume'];
+ debugPrint('onMicSpeakerVolumeChanged: micVolume= $type, speakerVolume');
+ });
+
+ final cameraControlRequestResultListener = eventListener.addListener(EventType.onCameraControlRequestResult, (data) async {
+ data = data as Map;
+ bool approved = data['approved'];
+ debugPrint('onCameraControlRequestResult: approved= $approved');
+ });
+
+ final callOutUserJoinListener = eventListener.addListener(EventType.onCalloutJoinSuccess, (data) async {
+ data = data as Map;
+ String phoneNumber = data['phoneNumber'];
+ ZoomVideoSdkUser? user = ZoomVideoSdkUser.fromJson(jsonDecode(data['user']));
+ debugPrint('onCalloutJoinSuccess: phoneNumber= $phoneNumber, user= ${user.userName}');
+ });
+
+ return () => {
+ sessionJoinListener.cancel(),
+ sessionLeaveListener.cancel(),
+ sessionPasswordWrongListener.cancel(),
+ sessionNeedPasswordListener.cancel(),
+ userVideoStatusChangedListener.cancel(),
+ userAudioStatusChangedListener.cancel(),
+ userJoinListener.cancel(),
+ userLeaveListener.cancel(),
+ userNameChangedListener.cancel(),
+ userShareStatusChangeListener.cancel(),
+ liveStreamStatusChangeListener.cancel(),
+ cloudRecordingStatusListener.cancel(),
+ inviteByPhoneStatusListener.cancel(),
+ eventErrorListener.cancel(),
+ commandReceived.cancel(),
+ liveTranscriptionStatusChangeListener.cancel(),
+ liveTranscriptionMsgInfoReceivedListener.cancel(),
+ multiCameraStreamStatusChangedListener.cancel(),
+ requireSystemPermission.cancel(),
+ userRecordingConsentListener.cancel(),
+ networkStatusChangeListener.cancel(),
+ callCRCDeviceStatusListener.cancel(),
+ originalLanguageMsgReceivedListener.cancel(),
+ chatPrivilegeChangedListener.cancel(),
+ testMicStatusListener.cancel(),
+ micSpeakerVolumeChangedListener.cancel(),
+ cameraControlRequestResultListener.cancel(),
+ callOutUserJoinListener.cancel(),
+ shareContentChangedListener.cancel(),
+ };
+ }, [zoom, users.value, isMounted]);
+
+ void selectVirtualBackgroundItem() async {
+ final ImagePicker picker = ImagePicker();
+ // Pick an image.
+ final XFile? image = await picker.pickImage(source: ImageSource.gallery);
+ await zoom.virtualBackgroundHelper.addVirtualBackgroundItem(image!.path);
+ }
+
+ 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);
+ }
+ }
+ }
+ }
+
+ 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();
+ }
+ }
+ }
+ }
+
+ void onPressShare() async {
+ var isOtherSharing = await zoom.shareHelper.isOtherSharing();
+ var isShareLocked = await zoom.shareHelper.isShareLocked();
+ String? shareCameraViewResult = Errors.InternalError;
+
+ if (isOtherSharing) {
+ showDialog(
+ context: context,
+ builder: (BuildContext context) => AlertDialog(
+ title: const Text("Error"),
+ content: const Text('Other is sharing'),
+ actions: [
+ TextButton(
+ onPressed: () => Navigator.pop(context, 'OK'),
+ child: const Text('OK'),
+ ),
+ ],
+ ),
+ );
+ } else if (isShareLocked) {
+ showDialog(
+ context: context,
+ builder: (BuildContext context) => AlertDialog(
+ title: const Text("Error"),
+ content: const Text('Share is locked by host'),
+ actions: [
+ TextButton(
+ onPressed: () => Navigator.pop(context, 'OK'),
+ child: const Text('OK'),
+ ),
+ ],
+ ),
+ );
+ } else if (isSharing.value) {
+ zoom.shareHelper.stopShare();
+ } else {
+ List options = [
+ ListTile(
+ title: Text(
+ 'Share Device Screen',
+ style: TextStyle(
+ fontSize: 14,
+ fontWeight: FontWeight.normal,
+ color: Colors.black,
+ ),
+ ),
+ onTap: () async => {
+ zoom.shareHelper.shareScreen(),
+ Navigator.of(context).pop(),
+ },
+ ),
+ ListTile(
+ title: Text(
+ 'Share Camera',
+ style: TextStyle(
+ fontSize: 14,
+ fontWeight: FontWeight.normal,
+ color: Colors.black,
+ ),
+ ),
+ onTap: () async => {
+ shareCameraViewResult = await zoom.shareHelper.startShareCamera(cameraShareView),
+ debugPrint('start camera: $shareCameraViewResult'),
+ Navigator.of(context).pop(),
+ },
+ ),
+ ];
+ showDialog(
+ context: context,
+ builder: (context) {
+ return Dialog(
+ elevation: 0.0,
+ insetPadding: const EdgeInsets.symmetric(horizontal: 40),
+ shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
+ child: SizedBox(
+ height: options.length * 60,
+ child: Scrollbar(
+ child: ListView(
+ shrinkWrap: true,
+ scrollDirection: Axis.vertical,
+ children: ListTile.divideTiles(
+ context: context,
+ tiles: options,
+ ).toList(),
+ ),
+ ),
+ ),
+ );
+ });
+ }
+ }
+
+ void onSelectedUserVolume(ZoomVideoSdkUser user) async {
+ var isShareAudio = user.isSharing;
+ bool canSetVolume = await user.canSetUserVolume(user.userId, isShareAudio);
+ num userVolume;
+
+ List options = [
+ ListTile(
+ title: Text(
+ 'Adjust Volume',
+ style: const TextStyle(
+ fontSize: 18,
+ fontWeight: FontWeight.w600,
+ color: Colors.black,
+ ),
+ ),
+ ),
+ ListTile(
+ title: Text(
+ 'Current volume',
+ style: const TextStyle(
+ fontSize: 14,
+ fontWeight: FontWeight.normal,
+ color: Colors.black,
+ ),
+ ),
+ onTap: () async => {
+ debugPrint('user volume'),
+ userVolume = await user.getUserVolume(user.userId, isShareAudio),
+ debugPrint('user ${user.userName}\'s volume is ${userVolume!}'),
+ },
+ ),
+ ];
+ if (canSetVolume) {
+ options.add(
+ ListTile(
+ title: Text(
+ 'Volume up',
+ style: const TextStyle(
+ fontSize: 14,
+ fontWeight: FontWeight.normal,
+ color: Colors.black,
+ ),
+ ),
+ onTap: () async => {
+ userVolume = await user.getUserVolume(user.userId, isShareAudio),
+ if (userVolume < 10)
+ {
+ await user.setUserVolume(user.userId, userVolume + 1, isShareAudio),
+ }
+ else
+ {
+ debugPrint("Cannot volume up."),
+ }
+ },
+ ),
+ );
+ options.add(
+ ListTile(
+ title: Text(
+ 'Volume down',
+ style: const TextStyle(
+ fontSize: 14,
+ fontWeight: FontWeight.normal,
+ color: Colors.black,
+ ),
+ ),
+ onTap: () async => {
+ userVolume = await user.getUserVolume(user.userId, isShareAudio),
+ if (userVolume > 0)
+ {
+ await user.setUserVolume(user.userId, userVolume - 1, isShareAudio),
+ }
+ else
+ {
+ debugPrint("Cannot volume down."),
+ }
+ },
+ ),
+ );
+ }
+ showDialog(
+ context: context,
+ builder: (context) {
+ return Dialog(
+ elevation: 0.0,
+ insetPadding: const EdgeInsets.symmetric(horizontal: 40),
+ shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
+ child: SizedBox(
+ height: options.length * 58,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ ListView(
+ shrinkWrap: true,
+ children: ListTile.divideTiles(
+ context: context,
+ tiles: options,
+ ).toList(),
+ ),
+ ],
+ ),
+ ));
+ });
+ }
+
+ void onPressCameraList() async {
+ List options = [];
+ List cameraList = await zoom.videoHelper.getCameraList();
+ for (var camera in cameraList) {
+ options.add(
+ ListTile(
+ title: Text(
+ camera.deviceName,
+ style: const TextStyle(
+ fontSize: 14,
+ fontWeight: FontWeight.normal,
+ color: Colors.black,
+ ),
+ ),
+ onTap: () async => {
+ await zoom.videoHelper.switchCamera(camera.deviceId),
+ Navigator.of(context).pop(),
+ },
+ ),
+ );
+ }
+ options.add(
+ ListTile(
+ title: Text(
+ "Cancel",
+ style: const TextStyle(
+ fontSize: 14,
+ fontWeight: FontWeight.normal,
+ color: Colors.black,
+ ),
+ ),
+ onTap: () async => {
+ Navigator.of(context).pop(),
+ },
+ ),
+ );
+ showDialog(
+ context: context,
+ builder: (context) {
+ return Dialog(
+ elevation: 0.0,
+ insetPadding: const EdgeInsets.symmetric(horizontal: 40),
+ shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
+ child: SizedBox(
+ height: options.length * 60,
+ child: Scrollbar(
+ child: ListView(
+ shrinkWrap: true,
+ scrollDirection: Axis.vertical,
+ children: ListTile.divideTiles(
+ context: context,
+ tiles: options,
+ ).toList(),
+ ),
+ ),
+ ),
+ );
+ });
+ }
+
+ // Future onPressMore() async {
+ // ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
+ // bool isShareLocked = await zoom.shareHelper.isShareLocked();
+ // bool canSwitchSpeaker = await zoom.audioHelper.canSwitchSpeaker();
+ // bool canStartRecording = (await zoom.recordingHelper.canStartRecording()) == Errors.Success;
+ // debugPrint("canStartRecording ${await zoom.recordingHelper.canStartRecording()}");
+ // var startLiveTranscription = (await zoom.liveTranscriptionHelper.getLiveTranscriptionStatus()) == LiveTranscriptionStatus.Start;
+ // bool canStartLiveTranscription = await zoom.liveTranscriptionHelper.canStartLiveTranscription();
+ // bool isHost = (mySelf != null) ? (await mySelf.getIsHost()) : false;
+ // isOriginalAspectRatio.value = await zoom.videoHelper.isOriginalAspectRatioEnabled();
+ // bool canCallOutToCRC = await zoom.CRCHelper.isCRCEnabled();
+ // bool supportVB = await zoom.virtualBackgroundHelper.isSupportVirtualBackground();
+ // List? shareActionList = await mySelf?.getShareActionList();
+ //
+ // List options = [
+ // ListTile(
+ // title: Text(
+ // 'More',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 18,
+ // fontWeight: FontWeight.w600,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // ),
+ // ListTile(
+ // title: Text(
+ // 'Get Chat Privilege',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () async => {
+ // debugPrint("Chat Privilege = ${await zoom.chatHelper.getChatPrivilege()}"),
+ // Navigator.of(context).pop(),
+ // },
+ // ),
+ // ListTile(
+ // title: Text(
+ // 'Get Session Dial-in Number infos',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () async => {
+ // debugPrint("session number = ${await zoom.session.getSessionNumber()}"),
+ // Navigator.of(context).pop(),
+ // },
+ // ),
+ // ListTile(
+ // title: Text(
+ // 'Get Camera List',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () async => {
+ // debugPrint("camera list= ${await zoom.videoHelper.getCameraList()}"),
+ // onPressCameraList(),
+ // Navigator.of(context).pop(),
+ // },
+ // ),
+ // ListTile(
+ // title: Text(
+ // '${isMicOriginalOn.value ? 'Disable' : 'Enable'} Original Sound',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () async => {
+ // debugPrint("${isMicOriginalOn.value}"),
+ // await zoom.audioSettingHelper.enableMicOriginalInput(!isMicOriginalOn.value),
+ // isMicOriginalOn.value = await zoom.audioSettingHelper.isMicOriginalInputEnable(),
+ // debugPrint("Original sound ${isMicOriginalOn.value ? 'Enabled' : 'Disabled'}"),
+ // Navigator.of(context).pop(),
+ // },
+ // )
+ // ];
+ //
+ // if (supportVB) {
+ // options.add(
+ // ListTile(
+ // title: Text(
+ // 'Add Virtual Background',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () async => {
+ // selectVirtualBackgroundItem(),
+ // Navigator.of(context).pop(),
+ // },
+ // ),
+ // );
+ // }
+ //
+ // if (canCallOutToCRC) {
+ // options.add(ListTile(
+ // title: Text(
+ // 'Call-out to CRC devices',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () async => {
+ // debugPrint('CRC result = ${await zoom.CRCHelper.callCRCDevice("bjn.vc", ZoomVideoSdkCRCProtocolType.SIP)}'),
+ // Navigator.of(context).pop(),
+ // },
+ // ));
+ // options.add(ListTile(
+ // title: Text(
+ // 'Cancel call-out to CRC devices',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () async => {
+ // debugPrint('cancel result= ${await zoom.CRCHelper.cancelCallCRCDevice()}'),
+ // Navigator.of(context).pop(),
+ // },
+ // ));
+ // }
+ //
+ // if (canSwitchSpeaker) {
+ // options.add(ListTile(
+ // title: Text(
+ // 'Turn ${isSpeakerOn.value ? 'off' : 'on'} Speaker',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () async => {
+ // await zoom.audioHelper.setSpeaker(!isSpeakerOn.value),
+ // isSpeakerOn.value = await zoom.audioHelper.getSpeakerStatus(),
+ // debugPrint('Turned ${isSpeakerOn.value ? 'on' : 'off'} Speaker'),
+ // Navigator.of(context).pop(),
+ // },
+ // ));
+ // }
+ //
+ // if (isHost) {
+ // options.add(ListTile(
+ // title: Text(
+ // '${isShareLocked ? 'Unlock' : 'Lock'} Share',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () async => {
+ // debugPrint("isShareLocked = ${await zoom.shareHelper.lockShare(!isShareLocked)}"),
+ // Navigator.of(context).pop(),
+ // }));
+ // options.add(ListTile(
+ // title: Text(
+ // 'Change Name',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () => {
+ // isRenameModalVisible.value = true,
+ // Navigator.of(context).pop(),
+ // },
+ // ));
+ // }
+ //
+ // if (canStartLiveTranscription) {
+ // options.add(ListTile(
+ // title: Text(
+ // "${startLiveTranscription ? 'Stop' : 'Start'} Live Transcription",
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () async => {
+ // if (startLiveTranscription)
+ // {
+ // debugPrint('stopLiveTranscription= ${await zoom.liveTranscriptionHelper.stopLiveTranscription()}'),
+ // }
+ // else
+ // {
+ // debugPrint('startLiveTranscription= ${await zoom.liveTranscriptionHelper.startLiveTranscription()}'),
+ // },
+ // Navigator.of(context).pop(),
+ // },
+ // ));
+ // options.add(ListTile(
+ // title: Text(
+ // '${isReceiveSpokenLanguageContentEnabled.value ? 'Disable' : 'Enable'} receiving original caption',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () async => {
+ // await zoom.liveTranscriptionHelper.enableReceiveSpokenLanguageContent(!isReceiveSpokenLanguageContentEnabled.value),
+ // isReceiveSpokenLanguageContentEnabled.value = await zoom.liveTranscriptionHelper.isReceiveSpokenLanguageContentEnabled(),
+ // debugPrint("isReceiveSpokenLanguageContentEnabled = ${isReceiveSpokenLanguageContentEnabled.value}"),
+ // Navigator.of(context).pop(),
+ // }));
+ // }
+ //
+ // if (canStartRecording) {
+ // options.add(ListTile(
+ // title: Text(
+ // '${isRecordingStarted.value ? 'Stop' : 'Start'} Recording',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () async => {
+ // if (!isRecordingStarted.value)
+ // {
+ // debugPrint('isRecordingStarted = ${await zoom.recordingHelper.startCloudRecording()}'),
+ // }
+ // else
+ // {
+ // debugPrint('isRecordingStarted = ${await zoom.recordingHelper.stopCloudRecording()}'),
+ // },
+ // Navigator.of(context).pop(),
+ // }));
+ // }
+ //
+ // if (Platform.isAndroid) {
+ // bool isFlashlightSupported = await zoom.videoHelper.isSupportFlashlight();
+ // bool isFlashlightOn = await zoom.videoHelper.isFlashlightOn();
+ // if (isFlashlightSupported) {
+ // options.add(ListTile(
+ // title: Text(
+ // '${isFlashlightOn ? 'Turn Off' : 'Turn On'} Flashlight',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () async => {
+ // if (!isFlashlightOn)
+ // {
+ // await zoom.videoHelper.turnOnOrOffFlashlight(true),
+ // }
+ // else
+ // {
+ // await zoom.videoHelper.turnOnOrOffFlashlight(false),
+ // },
+ // Navigator.of(context).pop(),
+ // }));
+ // }
+ // }
+ //
+ // if (Platform.isIOS) {
+ // options.add(ListTile(
+ // title: Text(
+ // '${isPiPView.value ? 'Disable' : 'Enable'} picture in picture view',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () async => {
+ // isPiPView.value = !isPiPView.value,
+ // Navigator.of(context).pop(),
+ // }));
+ // }
+ //
+ // if (isVideoOn.value) {
+ // options.add(ListTile(
+ // title: Text(
+ // 'Mirror the video',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () async => {
+ // await zoom.videoHelper.mirrorMyVideo(!isVideoMirrored.value),
+ // isVideoMirrored.value = await zoom.videoHelper.isMyVideoMirrored(),
+ // Navigator.of(context).pop(),
+ // }));
+ // options.add(ListTile(
+ // title: Text(
+ // '${isOriginalAspectRatio.value ? 'Enable' : 'Disable'} original aspect ratio',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.normal,
+ // color: Colors.black,
+ // ),
+ // ),
+ // ),
+ // onTap: () async => {
+ // await zoom.videoHelper.enableOriginalAspectRatio(!isOriginalAspectRatio.value),
+ // isOriginalAspectRatio.value = await zoom.videoHelper.isOriginalAspectRatioEnabled(),
+ // debugPrint("isOriginalAspectRatio= ${isOriginalAspectRatio.value}"),
+ // Navigator.of(context).pop(),
+ // }));
+ // }
+ //
+ // showDialog(
+ // context: context,
+ // builder: (context) {
+ // return Dialog(
+ // elevation: 0.0,
+ // insetPadding: const EdgeInsets.symmetric(horizontal: 40),
+ // shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
+ // child: SizedBox(
+ // height: 500,
+ // child: Scrollbar(
+ // child: ListView(
+ // shrinkWrap: true,
+ // scrollDirection: Axis.vertical,
+ // children: ListTile.divideTiles(
+ // context: context,
+ // tiles: options,
+ // ).toList(),
+ // ),
+ // ),
+ // ),
+ // );
+ // });
+ // }
+
+ void onLeaveSession(bool isEndSession) async {
+ await zoom.leaveSession(isEndSession);
+ Navigator.pushAndRemoveUntil(
+ context,
+ CustomPageRoute(
+ page: LandingNavigation(),
+ ),
+ (r) => false);
+ }
+
+ void showLeaveOptions() async {
+ ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
+ bool isHost = await mySelf!.getIsHost();
+
+ Widget endSession;
+ Widget leaveSession;
+ Widget cancel = TextButton(
+ child: const Text('Cancel'),
+ onPressed: () {
+ Navigator.pop(context); //close Dialog
+ },
+ );
+
+ switch (defaultTargetPlatform) {
+ case TargetPlatform.android:
+ endSession = TextButton(
+ child: const Text('End Session'),
+ onPressed: () => onLeaveSession(true),
+ );
+ leaveSession = TextButton(
+ child: const Text('Leave Session'),
+ onPressed: () => onLeaveSession(false),
+ );
+ break;
+ default:
+ endSession = CupertinoActionSheetAction(
+ isDestructiveAction: true,
+ child: const Text('End Session'),
+ onPressed: () => onLeaveSession(true),
+ );
+ leaveSession = CupertinoActionSheetAction(
+ child: const Text('Leave Session'),
+ onPressed: () => onLeaveSession(false),
+ );
+ break;
+ }
+
+ List options = [
+ leaveSession,
+ cancel,
+ ];
+
+ if (Platform.isAndroid) {
+ if (isHost) {
+ options.removeAt(1);
+ options.insert(0, endSession);
+ }
+ showDialog(
+ context: context,
+ builder: (context) {
+ return AlertDialog(
+ content: const Text("Do you want to leave this session?"),
+ shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0))),
+ actions: options,
+ );
+ });
+ } else {
+ options.removeAt(1);
+ if (isHost) {
+ options.insert(1, endSession);
+ }
+ showCupertinoModalPopup(
+ context: context,
+ builder: (context) => CupertinoActionSheet(
+ message: const Text('Are you sure that you want to leave the session?'),
+ actions: options,
+ cancelButton: cancel,
+ ),
+ );
+ }
+ }
+
+ final chatMessageController = TextEditingController();
+
+ void sendChatMessage(String message) async {
+ await zoom.chatHelper.sendChatToAll(message);
+ ZoomVideoSdkUser? self = await zoom.session.getMySelf();
+ ZoomVideoSdkCmdChannel cmdChannel = zoom.cmdChannel;
+ for (var user in users.value) {
+ if (user.userId != self?.userId) {
+ await zoom.cmdChannel.sendCommand(user.userId, message);
+ }
+ }
+ chatMessageController.clear();
+ // send the chat as a command
+ }
+
+ void onSelectedUser(ZoomVideoSdkUser user) async {
+ setState(() {
+ fullScreenUser.value = user;
+ });
+ }
+
+ changeNamePopup = Center(
+ child: Stack(
+ children: [
+ Visibility(
+ visible: isRenameModalVisible.value,
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+ alignment: Alignment.bottomLeft,
+ decoration: const BoxDecoration(
+ borderRadius: BorderRadius.all(Radius.circular(10)),
+ color: Colors.white,
+ ),
+ width: MediaQuery.of(context).size.width - 130,
+ height: MediaQuery.of(context).size.height * 0.2,
+ child: Center(
+ child: (Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(top: 20, left: 20),
+ child: Text(
+ 'Change Name',
+ style: const TextStyle(
+ fontSize: 18,
+ fontWeight: FontWeight.w500,
+ ),
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(top: 10, left: 20),
+ child: SizedBox(
+ width: MediaQuery.of(context).size.width - 230,
+ child: TextField(
+ onEditingComplete: () {},
+ autofocus: true,
+ cursorColor: Colors.black,
+ controller: changeNameController,
+ decoration: InputDecoration(
+ isDense: true,
+ hintText: 'New name',
+ hintStyle: TextStyle(
+ fontSize: 14.0,
+ color: chatTextColor,
+ ),
+ ),
+ ),
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(top: 15),
+ child: Row(
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(left: 40),
+ child: InkWell(
+ child: Text(
+ 'Apply',
+ style: const TextStyle(
+ fontSize: 16,
+ ),
+ ),
+ onTap: () async {
+ if (fullScreenUser.value != null) {
+ ZoomVideoSdkUser? mySelf = await zoom.session.getMySelf();
+ await zoom.userHelper.changeName((mySelf?.userId)!, changeNameController.text);
+ changeNameController.clear();
+ }
+ isRenameModalVisible.value = false;
+ },
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(left: 40),
+ child: InkWell(
+ child: Text(
+ 'Cancel',
+ style: const TextStyle(
+ fontSize: 16,
+ ),
+ ),
+ onTap: () async {
+ isRenameModalVisible.value = false;
+ },
+ ),
+ )
+ ],
+ ),
+ )
+ ],
+ )),
+ ),
+ ),
+ ],
+ )),
+ ],
+ ),
+ );
+
+ Widget fullScreenView;
+ Widget smallView;
+ Widget cameraView;
+
+ if (isInSession.value && fullScreenUser.value != null && users.value.isNotEmpty) {
+ fullScreenView = AnimatedOpacity(
+ opacity: opacityLevel,
+ duration: const Duration(seconds: 3),
+ child: VideoView(
+ user: users.value.length > 1 ? users.value[1] : users.value[0],
+ hasMultiCamera: false,
+ isPiPView: isPiPView.value,
+ sharing: sharingUser.value == null ? false : (sharingUser.value?.userId == fullScreenUser.value?.userId),
+ preview: false,
+ focused: false,
+ multiCameraIndex: "0",
+ videoAspect: VideoAspect.Original,
+ fullScreen: true,
+ resolution: VideoResolution.Resolution360,
+ ),
+ );
+
+ smallView = Container(
+ height: 110,
+ margin: const EdgeInsets.only(left: 20, right: 20),
+ alignment: Alignment.center,
+ child: ListView.separated(
+ scrollDirection: Axis.horizontal,
+ itemCount: users.value.length,
+ itemBuilder: (BuildContext context, int index) {
+ return InkWell(
+ onTap: () async {
+ onSelectedUser(users.value[index]);
+ },
+ onDoubleTap: () async {
+ onSelectedUserVolume(users.value[index]);
+ },
+ child: Center(
+ child: VideoView(
+ user: users.value[index],
+ hasMultiCamera: false,
+ isPiPView: false,
+ sharing: false,
+ preview: false,
+ focused: false,
+ multiCameraIndex: "0",
+ videoAspect: VideoAspect.Original,
+ fullScreen: false,
+ resolution: VideoResolution.Resolution180,
+ ),
+ ),
+ );
+ },
+ separatorBuilder: (BuildContext context, int index) => const Divider(),
+ ),
+ );
+ } else {
+ fullScreenView = Container(
+ color: Colors.black,
+ child: const Center(
+ child: Text(
+ "Connecting...",
+ style: TextStyle(
+ fontSize: 20,
+ color: Colors.white,
+ ),
+ ),
+ ));
+ smallView = Container(
+ height: 110,
+ color: Colors.transparent,
+ );
+ }
+
+ cameraView = Offstage(
+ offstage: !isSharedCamera.value,
+ child: AnimatedOpacity(
+ opacity: isSharedCamera.value ? 1.0 : 0.0,
+ duration: const Duration(milliseconds: 300),
+ child: cameraShareView,
+ ),
+ );
+
+ _changeOpacity;
+ return Scaffold(
+ resizeToAvoidBottomInset: false,
+ backgroundColor: backgroundColor,
+ body: Stack(
+ children: [
+ // isScreenBeingShared ? fullScreenView : SizedBox.shrink(),
+ isScreenBeingShared ? SizedBox.shrink() : fullScreenView,
+ cameraView,
+ Container(
+ padding: const EdgeInsets.only(top: 35),
+ child: Stack(
+ children: [
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Container(
+ height: 80,
+ width: 180,
+ margin: const EdgeInsets.only(top: 16, left: 8),
+ padding: const EdgeInsets.all(8),
+ alignment: Alignment.topLeft,
+ decoration: BoxDecoration(
+ borderRadius: const BorderRadius.all(Radius.circular(8.0)),
+ // color: buttonBackgroundColor,
+ ),
+ // child: InkWell(
+ // onTap: () async {
+ // showDialog(
+ // context: context,
+ // builder: (context) {
+ // return Dialog(
+ // elevation: 0.0,
+ // insetPadding: const EdgeInsets.symmetric(horizontal: 40),
+ // shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
+ // child: FractionallySizedBox(
+ // heightFactor: 0.2,
+ // widthFactor: 0.3,
+ // child: Column(
+ // crossAxisAlignment: CrossAxisAlignment.stretch,
+ // children: [
+ // ListView(
+ // shrinkWrap: true,
+ // children: ListTile.divideTiles(
+ // context: context,
+ // tiles: [
+ // ListTile(
+ // title: Text(
+ // 'Session Information',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 18,
+ // fontWeight: FontWeight.w600,
+ // ),
+ // ),
+ // ),
+ // ),
+ // ListTile(
+ // title: Text(
+ // 'Session Name',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // ),
+ // ),
+ // ),
+ // subtitle: Text(
+ // sessionName.value,
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 12,
+ // ),
+ // ),
+ // ),
+ // ),
+ // ListTile(
+ // title: Text(
+ // 'Session Password',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // ),
+ // ),
+ // ),
+ // subtitle: Text(
+ // sessionPassword.value,
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 12,
+ // ),
+ // ),
+ // ),
+ // ),
+ // ListTile(
+ // title: Text(
+ // 'Participants',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // ),
+ // ),
+ // ),
+ // subtitle: Text(
+ // '${users.value.length}',
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 12,
+ // ),
+ // ),
+ // ),
+ // ),
+ // ],
+ // ).toList(),
+ // ),
+ // ],
+ // ),
+ // ));
+ // });
+ // },
+ // child: Stack(
+ // children: [
+ // Column(
+ // children: [
+ // const Padding(padding: EdgeInsets.symmetric(vertical: 4)),
+ // Align(
+ // alignment: Alignment.centerLeft,
+ // child: Text(
+ // sessionName.value,
+ // overflow: TextOverflow.ellipsis,
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.w600,
+ // color: Colors.white,
+ // ),
+ // ),
+ // ),
+ // ),
+ // const Padding(padding: EdgeInsets.symmetric(vertical: 5)),
+ // Align(
+ // alignment: Alignment.centerLeft,
+ // child: Text(
+ // "Participants: ${users.value.length}",
+ // style: GoogleFonts.lato(
+ // textStyle: const TextStyle(
+ // fontSize: 14,
+ // fontWeight: FontWeight.w600,
+ // color: Colors.white,
+ // ),
+ // ),
+ // ),
+ // )
+ // ],
+ // ),
+ // Container(
+ // alignment: Alignment.centerRight,
+ // child: Image.asset(
+ // "assets/icons/unlocked@2x.png",
+ // height: 22,
+ // )),
+ // ],
+ // ),
+ // ),
+ ),
+ TextButton(
+ onPressed: (showLeaveOptions),
+ child: Container(
+ alignment: Alignment.topRight,
+ margin: const EdgeInsets.only(top: 16, right: 8),
+ padding: const EdgeInsets.only(top: 5, bottom: 5, left: 16, right: 16),
+ height: 28,
+ decoration: BoxDecoration(
+ borderRadius: const BorderRadius.all(Radius.circular(20.0)),
+ color: buttonBackgroundColor,
+ ),
+ child: const Text(
+ "LEAVE",
+ style: TextStyle(
+ fontSize: 14,
+ fontWeight: FontWeight.bold,
+ color: Color(0xFFE02828),
+ ),
+ ),
+ )),
+ ],
+ ),
+ Align(
+ alignment: Alignment.centerRight,
+ child: FractionallySizedBox(
+ widthFactor: 0.2,
+ heightFactor: 0.6,
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ IconButton(
+ onPressed: onPressAudio,
+ icon: isMuted.value ? Image.asset("assets/images/png/zoom/unmute@2x.png") : Image.asset("assets/images/png/zoom/mute@2x.png"),
+ iconSize: circleButtonSize,
+ tooltip: isMuted.value == true ? "Unmute" : "Mute",
+ ),
+ IconButton(
+ onPressed: onPressShare,
+ icon: isSharing.value ? Image.asset("assets/images/png/zoom/share-off@2x.png") : Image.asset("assets/images/png/zoom/share-on@2x.png"),
+ iconSize: circleButtonSize,
+ ),
+ IconButton(
+ onPressed: onPressVideo,
+ iconSize: circleButtonSize,
+ icon: isVideoOn.value ? Image.asset("assets/images/png/zoom/video-off@2x.png") : Image.asset("assets/images/png/zoom/video-on@2x.png"),
+ ),
+ Column(
+ children: [
+ IconButton(
+ onPressed: () async {
+ onPressCameraList();
+ },
+ icon: Icon(Icons.cameraswitch, color: Colors.white),
+ color: Colors.white,
+ iconSize: 40.h,
+ ),
+ "Switch Camera".toText12(color: AppColors.whiteColor, isCenter: true, isBold: true)
+ ],
+ ),
+ ],
+ ),
+ )),
+ Container(
+ margin: const EdgeInsets.only(left: 16, right: 16, bottom: 40, top: 10),
+ alignment: Alignment.bottomCenter,
+ child: SizedBox(
+ height: MediaQuery.of(context).viewInsets.bottom == 0 ? 65 : MediaQuery.of(context).viewInsets.bottom + 18,
+ child: TextField(
+ maxLines: 1,
+ textAlign: TextAlign.left,
+ style: TextStyle(color: chatTextColor),
+ cursorColor: chatTextColor,
+ textAlignVertical: TextAlignVertical.center,
+ controller: chatMessageController,
+ decoration: InputDecoration(
+ contentPadding: const EdgeInsets.only(left: 16, top: 10, bottom: 10, right: 16),
+ enabledBorder: OutlineInputBorder(
+ borderSide: BorderSide(width: 1, color: chatTextColor), //<-- SEE HERE
+ ),
+ hintText: 'Type your message here...',
+ hintStyle: TextStyle(
+ fontSize: 14.0,
+ color: chatTextColor,
+ ),
+ ),
+ onSubmitted: (String str) {
+ sendChatMessage(str);
+ },
+ ),
+ ),
+ ),
+ Container(
+ alignment: Alignment.bottomLeft,
+ margin: const EdgeInsets.only(bottom: 120),
+ child: smallView,
+ ),
+ // CommentList(zoom: zoom, eventListener: eventListener),
+ changeNamePopup,
+ ],
+ )),
+ ],
+ ));
+ }
+}
+
+class CallArguments {
+ final bool isJoin;
+ final String sessionName;
+ final String sessionPwd;
+ final String displayName;
+ final String sessionIdleTimeoutMins;
+ final String role;
+ final int callType;
+
+ CallArguments(this.sessionName, this.sessionPwd, this.displayName, this.sessionIdleTimeoutMins, this.role, this.isJoin, this.callType);
+}
+
+class JoinArguments {
+ final bool isJoin;
+ final String sessionName;
+ final String sessionPwd;
+ final String displayName;
+ final String sessionTimeout;
+ final String roleType;
+
+ JoinArguments(this.isJoin, this.sessionName, this.sessionPwd, this.displayName, this.sessionTimeout, this.roleType);
+}
diff --git a/lib/presentation/tele_consultation/zoom/video_view.dart b/lib/presentation/tele_consultation/zoom/video_view.dart
new file mode 100644
index 0000000..4c1e049
--- /dev/null
+++ b/lib/presentation/tele_consultation/zoom/video_view.dart
@@ -0,0 +1,258 @@
+import 'dart:async';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_hooks/flutter_hooks.dart';
+import 'package:flutter_zoom_videosdk/flutter_zoom_view.dart' as FlutterZoomView;
+import 'package:flutter_zoom_videosdk/native/zoom_videosdk.dart';
+
+const SHOW_TALKING_ICON_DURATION = 2000;
+
+class VideoView extends FlutterZoomView.ZoomView {
+ const VideoView({
+ super.key,
+ required super.user,
+ required super.sharing,
+ required super.preview,
+ required super.focused,
+ required super.hasMultiCamera,
+ required super.multiCameraIndex,
+ required super.videoAspect,
+ required super.fullScreen,
+ required super.resolution,
+ required super.isPiPView,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ var isVideoOn = useState(false);
+ var isTalking = useState(false);
+ var isMuted = useState(false);
+ var isMounted = useIsMounted();
+ var zoom = ZoomVideoSdk();
+ var isSharing = useState(false);
+ user?.audioStatus?.isMuted().then((muted) => isMuted.value = muted);
+
+ useEffect(() {
+ updateVideoStatus() {
+ if (user == null) return;
+ Future.microtask(() async {
+ if (isMounted()) {
+ isVideoOn.value = (await user!.videoStatus!.isOn());
+ isSharing.value = sharing;
+ }
+ });
+ }
+
+ resetAudioStatus() {
+ isTalking.value = false;
+ isMuted.value = false;
+ }
+
+ updateAudioStatus() async {
+ if (!isMounted()) return;
+ var talking = await user?.audioStatus?.isTalking();
+ var muted = await user?.audioStatus?.isMuted();
+ isMuted.value = muted!;
+ isTalking.value = talking!;
+ if (talking) {
+ Timer(
+ const Duration(milliseconds: SHOW_TALKING_ICON_DURATION),
+ () => {
+ if (isMounted())
+ {
+ isTalking.value = false,
+ }
+ });
+ }
+ }
+
+ updateVideoStatus();
+ return null;
+ }, [zoom, user]);
+
+ ImageIcon audioStatusIcon;
+ if (isTalking.value) {
+ audioStatusIcon = const ImageIcon(
+ AssetImage("assets/images/png/zoom/talking@2x.png"),
+ );
+ } else if (isMuted.value) {
+ audioStatusIcon = const ImageIcon(
+ AssetImage("assets/images/png/zoom/muted@2x.png"),
+ );
+ }
+ // Pass parameters to the platform side.
+ final Map creationParams = {};
+ creationParams.putIfAbsent("userId", () => user?.userId);
+ creationParams.putIfAbsent("sharing", () => sharing);
+ creationParams.putIfAbsent("preview", () => preview);
+ creationParams.putIfAbsent("focused", () => focused);
+ creationParams.putIfAbsent("hasMultiCamera", () => hasMultiCamera);
+ if (videoAspect.isEmpty) {
+ creationParams.putIfAbsent("videoAspect", () => VideoAspect.PanAndScan);
+ } else {
+ creationParams.putIfAbsent("videoAspect", () => videoAspect);
+ }
+ creationParams.putIfAbsent("fullScreen", () => fullScreen);
+ if (resolution.isNotEmpty) {
+ creationParams.putIfAbsent("videoAspect", () => videoAspect);
+ }
+
+ if (fullScreen) {
+ if (sharing) {
+ return Container(
+ height: MediaQuery.of(context).size.height,
+ width: MediaQuery.of(context).size.width,
+ alignment: Alignment.center,
+ child: FlutterZoomView.View(creationParams: creationParams),
+ );
+ } else if (isVideoOn.value) {
+ return Container(
+ height: MediaQuery.of(context).size.height,
+ width: MediaQuery.of(context).size.width,
+ alignment: Alignment.center,
+ child: FlutterZoomView.View(creationParams: creationParams),
+ );
+ } else {
+ return Container(
+ margin: const EdgeInsets.symmetric(vertical: 0),
+ child: Container(
+ alignment: Alignment.center,
+ child: const Image(
+ image: AssetImage("assets/images/png/zoom/default-avatar.png"),
+ )),
+ );
+ }
+ } else {
+ if (isVideoOn.value || sharing) {
+ return Container(
+ padding: const EdgeInsets.symmetric(horizontal: 8),
+ height: 110,
+ width: 110,
+ child: Stack(
+ children: [
+ Container(
+ height: 110,
+ width: 110,
+ decoration: BoxDecoration(
+ color: const Color(0xff232323),
+ border: Border.all(
+ color: const Color(0xff666666),
+ width: 1,
+ ),
+ borderRadius: const BorderRadius.all(Radius.circular(8)),
+ ),
+ alignment: Alignment.center,
+ child: FlutterZoomView.View(creationParams: creationParams),
+ ),
+ Container(
+ height: 110,
+ width: 110,
+ decoration: const BoxDecoration(
+ borderRadius: BorderRadius.all(Radius.circular(8)),
+ ),
+ ),
+ Container(
+ alignment: Alignment.bottomCenter,
+ child: Container(
+ height: 20,
+ width: 110,
+ decoration: const BoxDecoration(
+ color: Colors.black26,
+ borderRadius: BorderRadius.all(Radius.circular(8)),
+ ),
+ ),
+ ),
+ Container(
+ alignment: Alignment.bottomLeft,
+ margin: const EdgeInsets.only(left: 5),
+ child: Text(
+ user!.userName,
+ textAlign: TextAlign.left,
+ style: const TextStyle(
+ color: Colors.white,
+ fontSize: 12,
+ ),
+ ),
+ ),
+ Container(
+ alignment: Alignment.bottomRight,
+ margin: const EdgeInsets.only(right: 5, bottom: 5),
+ // height: 110,
+ // width: 110,
+ child: Image(
+ height: 12,
+ width: 12,
+ image: isMuted.value ? const AssetImage("assets/images/png/zoom/muted@2x.png") : const AssetImage("assets/images/png/zoom/talking@2x.png"),
+ fit: BoxFit.cover,
+ ),
+ )
+ ],
+ ),
+ );
+ } else {
+ return Container(
+ padding: const EdgeInsets.symmetric(horizontal: 8),
+ height: 110,
+ width: 110,
+ child: Stack(
+ children: [
+ Container(
+ height: 110,
+ width: 110,
+ decoration: BoxDecoration(
+ color: const Color(0xff232323),
+ border: Border.all(
+ color: const Color(0xff666666),
+ width: 1,
+ ),
+ borderRadius: const BorderRadius.all(Radius.circular(8)),
+ ),
+ alignment: Alignment.center,
+ child: Container(
+ alignment: Alignment.center,
+ child: const Image(
+ height: 60,
+ width: 60,
+ image: AssetImage("assets/images/png/zoom/default-avatar.png"),
+ )),
+ ),
+ Align(
+ alignment: Alignment.bottomCenter,
+ child: Container(
+ height: 20,
+ width: 110,
+ decoration: const BoxDecoration(
+ color: Colors.black26,
+ borderRadius: BorderRadius.all(Radius.circular(8)),
+ ),
+ ),
+ ),
+ Container(
+ alignment: Alignment.bottomLeft,
+ margin: const EdgeInsets.only(left: 5),
+ child: Text(
+ user!.userName,
+ textAlign: TextAlign.left,
+ style: const TextStyle(
+ color: Colors.white,
+ fontSize: 12,
+ ),
+ ),
+ ),
+ Container(
+ alignment: Alignment.bottomRight,
+ margin: const EdgeInsets.only(right: 5, bottom: 5),
+ child: Image(
+ height: 12,
+ width: 12,
+ image: isMuted.value ? const AssetImage("assets/images/png/zoom/muted@2x.png") : const AssetImage("assets/images/png/zoom/talking@2x.png"),
+ fit: BoxFit.cover,
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+ }
+ }
+}
diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart
index b37ebfa..ed5c0db 100644
--- a/lib/routes/app_routes.dart
+++ b/lib/routes/app_routes.dart
@@ -7,6 +7,7 @@ import 'package:hmg_patient_app_new/presentation/e_referral/new_e_referral.dart'
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/presentation/home_health_care/hhc_procedures_page.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart';
+import 'package:hmg_patient_app_new/presentation/tele_consultation/zoom/call_screen.dart';
import 'package:hmg_patient_app_new/splashPage.dart';
class AppRoutes {
@@ -19,6 +20,7 @@ class AppRoutes {
static const String eReferralPage = '/erReferralPage';
static const String comprehensiveCheckupPage = '/comprehensiveCheckupPage';
static const String homeHealthCarePage = '/homeHealthCarePage';
+ static const String zoomCallPage = '/zoomCallPage';
static Map get routes => {
initialRoute: (context) => SplashPage(),
@@ -29,6 +31,7 @@ class AppRoutes {
medicalFilePage: (context) => MedicalFilePage(),
eReferralPage: (context) => NewReferralPage(),
comprehensiveCheckupPage: (context) => ComprehensiveCheckupPage(),
- homeHealthCarePage: (context) => HhcProceduresPage()
+ homeHealthCarePage: (context) => HhcProceduresPage(),
+ zoomCallPage: (context) => CallScreen()
};
}
diff --git a/lib/splashPage.dart b/lib/splashPage.dart
index ba7cefd..b5b752b 100644
--- a/lib/splashPage.dart
+++ b/lib/splashPage.dart
@@ -4,8 +4,11 @@ import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_callkit_incoming/entities/call_event.dart';
+import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_zoom_videosdk/native/zoom_videosdk.dart';
+import 'package:get_it/get_it.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_orders_page.dart';
import 'package:hmg_patient_app_new/presentation/onboarding/onboarding_screen.dart';
import 'package:hmg_patient_app_new/presentation/onboarding/splash_animation_screen.dart';
@@ -19,6 +22,9 @@ import 'package:hmg_patient_app_new/features/authentication/authentication_view_
// import 'package:hmg_patient_app_new/presentation/authantication/login.dart';
import 'package:hmg_patient_app_new/presentation/home/landing_page.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
+import 'package:hmg_patient_app_new/presentation/tele_consultation/zoom/call_screen.dart';
+import 'package:hmg_patient_app_new/services/cache_service.dart';
+import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:lottie/lottie.dart';
@@ -38,6 +44,7 @@ class _SplashScreenState extends State {
late AuthenticationViewModel authVm;
Future initializeStuff() async {
+ listenerEvent();
Timer(
Duration(milliseconds: 500),
() async {
@@ -47,22 +54,155 @@ class _SplashScreenState extends State {
);
await authVm.getServicePrivilege();
Timer(Duration(seconds: 2, milliseconds: 500), () async {
+ bool isAppOpenedFromCall = await GetIt.instance().getBool(key: CacheConst.isAppOpenedFromCall) ?? false;
+
LocalNotification.init(onNotificationClick: (payload) {});
- if (await Utils.getBoolFromPrefs(CacheConst.firstLaunch)) {
- Navigator.of(context).pushReplacement(FadePage(page: SplashAnimationScreen(routeWidget: OnboardingScreen())));
+ if (isAppOpenedFromCall) {
+ navigateToTeleConsult();
} else {
- Navigator.of(context).pushReplacement(FadePage(page: SplashAnimationScreen(routeWidget: LandingNavigation())));
+ if (await Utils.getBoolFromPrefs(CacheConst.firstLaunch)) {
+ // Navigator.of(context).pushReplacement(FadePage(page: SplashAnimationScreen(routeWidget: OnboardingScreen())));
+ Navigator.of(context).pushReplacement(FadePage(page: OnboardingScreen()));
+ } else {
+ // Navigator.of(context).pushReplacement(FadePage(page: SplashAnimationScreen(routeWidget: LandingNavigation())));
+ Navigator.of(context).pushReplacement(FadePage(page: LandingNavigation()));
+ }
}
});
var zoom = ZoomVideoSdk();
InitConfig initConfig = InitConfig(
domain: "zoom.us",
- enableLog: true,
+ enableLog: false,
);
zoom.initSdk(initConfig);
}
+ navigateToTeleConsult() async {
+ String roomID = await Utils.getStringFromPrefs(CacheConst.zoomRoomID);
+ print('RoomID: $roomID');
+
+ // GetIt.instance().remove(key: CacheConst.isAppOpenedFromCall);
+ Utils.removeFromPrefs(CacheConst.isAppOpenedFromCall);
+
+ Navigator.of(GetIt.instance().navigatorKey.currentContext!).pushReplacement(FadePage(page: SplashAnimationScreen(routeWidget: LandingNavigation())));
+ Navigator.pushReplacementNamed(
+ // context,
+ GetIt.instance().navigatorKey.currentContext!,
+ AppRoutes.zoomCallPage,
+ // arguments: CallArguments(appointmentID, "111", "Patient", "40", "1", true, 1),
+ arguments: CallArguments(roomID, "123", "Patient", "40", "0", true, 1),
+ // arguments: CallArguments("SmallDailyStandup9875", "123", "Patient", "40", "0", false, int.parse(widget.incomingCallData!.appointmentNo!)),
+ );
+ }
+
+ Future listenerEvent() async {
+ print('Call Canceled : ------->');
+
+ try {
+ FlutterCallkitIncoming.onEvent.listen((event) async {
+ switch (event!.event) {
+ case Event.actionCallIncoming:
+ print('actionCallIncoming Event Received: ------->');
+ break;
+ case Event.actionCallStart:
+ print('actionCallStart Event Received: ------->');
+ break;
+ case Event.actionCallAccept:
+ print('actionCallAccept Event Received: ------->');
+ FlutterCallkitIncoming.endAllCalls();
+ try {
+ navigateToTeleConsult();
+ // String roomID = await Utils.getStringFromPrefs(SharedPrefsConsts.ZOOM_ROOM_ID);
+ // String roomPass = await Utils.getStringFromPrefs(SharedPrefsConsts.ZOOM_ROOM_PASS);
+
+ // print('RoomID: $roomID');
+ // print('RoomPass: $roomPass');
+
+ // Future.delayed(const Duration(milliseconds: 3000), () async {
+ // // try {
+ // // String teleConsultURL = "https://teleconsult.meena-health.com/api/videocall/doVideoCall?roomid=";
+ // // await Utils.getStringFromPrefs(SharedPrefsConsts.PATIENT_MRN).then((value) {
+ // // teleConsultURL = teleConsultURL + value;
+ // // print("TeleConsult URL: $teleConsultURL");
+ // // Uri uri = Uri.parse(teleConsultURL);
+ // // launchUrl(uri, mode: LaunchMode.externalApplication, webOnlyWindowName: "TeleConsult");
+ // // });
+ //
+ // // var cameraStatus = await Permission.camera.request();
+ // // var micStatus = await Permission.microphone.request();
+ // // var permissionStatus = await [Permission.microphone, Permission.camera, Permission.notification].request();
+ // // if (permissionStatus[1]?.isDenied == true) {
+ // // await Permission.camera.request();
+ // // }
+ // // if (permissionStatus[0]?.isDenied == true) {
+ // // await Permission.microphone.request();
+ // // }
+ //
+ // Navigator.pushNamed(
+ // // context,
+ // navigatorKey.currentContext!,
+ // AppRoutes.zoomCallPage,
+ // // arguments: CallArguments(appointmentID, "111", "Patient", "40", "1", true, 1),
+ // arguments: CallArguments(roomID, roomPass, "Patient", "40", "0", true, 1),
+ // // arguments: CallArguments("SmallDailyStandup9875", "123", "Patient", "40", "0", false, int.parse(widget.incomingCallData!.appointmentNo!)),
+ // );
+ // // } catch (err) {
+ // // print(err);
+ // // }
+ // });
+ // String teleConsultURL = "https://teleconsult.meena-health.com/api/videocall/doVideoCall?roomid=";
+ // await Utils.getStringFromPrefs(SharedPrefsConsts.PATIENT_MRN).then((value) {
+ // teleConsultURL = teleConsultURL + value;
+ // print("TeleConsult URL: $teleConsultURL");
+ // Uri uri = Uri.parse(teleConsultURL);
+ // launchUrl(uri, mode: LaunchMode.inAppBrowserView, webOnlyWindowName: "Test");
+ // });
+ // navigatorKey.currentState!.pushNamed(AppRoutes.incomingCallScreenRoute);
+ // await Navigator.pushNamed(context, AppRoutes.incomingCallScreenRoute).then((value) {});
+ } catch (e) {
+ print("ERRORRRR!!! ${e.toString()}");
+ // await AppSharedPreferences().setObject('call_data', data);
+ // var data1 = await AppSharedPreferences().getObject('call_data');
+ }
+ break;
+ case Event.actionCallDecline:
+ print('actionCallConnected Event Received: ------->');
+ await FlutterCallkitIncoming.endAllCalls();
+ GetIt.instance().remove(key: CacheConst.isAppOpenedFromCall);
+ 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;
+ case Event.actionCallConnected:
+ print('actionCallConnected Event Received: ------->');
+ await FlutterCallkitIncoming.endAllCalls();
+ break;
+ }
+ });
+ } on Exception catch (e) {
+ print(e);
+ print("ERRORRRR!!! ${e.toString()}");
+ }
+ }
+
/// load the Privilege from service
Future loadPrivilege() async {
// ProjectViewModel projectProvider = Provider.of(context, listen: false);
diff --git a/lib/widgets/chip/app_custom_chip_widget.dart b/lib/widgets/chip/app_custom_chip_widget.dart
index 6904edc..8be16b7 100644
--- a/lib/widgets/chip/app_custom_chip_widget.dart
+++ b/lib/widgets/chip/app_custom_chip_widget.dart
@@ -22,6 +22,7 @@ class AppCustomChipWidget extends StatelessWidget {
this.deleteIconColor = AppColors.textColor,
this.deleteIconHasColor = false,
this.padding = EdgeInsets.zero,
+ this.isIconPNG = false,
this.onChipTap,
this.labelPadding,
this.onDeleteTap,
@@ -42,6 +43,7 @@ class AppCustomChipWidget extends StatelessWidget {
final OutlinedBorder? shape;
final EdgeInsets? padding;
final EdgeInsetsDirectional? labelPadding;
+ final bool isIconPNG;
final void Function()? onChipTap;
final void Function()? onDeleteTap;
@@ -66,8 +68,10 @@ class AppCustomChipWidget extends StatelessWidget {
child: icon.isNotEmpty
? Chip(
avatar: icon.isNotEmpty
- ? Utils.buildSvgWithAssets(
- icon: icon,
+ ? isIconPNG
+ ? Image.asset(icon, width: iconS, height: iconS)
+ : Utils.buildSvgWithAssets(
+ icon: icon,
width: iconS,
height: iconS,
iconColor: iconHasColor ? iconColor : null,
diff --git a/pubspec.yaml b/pubspec.yaml
index 3d6604c..6f014cb 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -59,7 +59,8 @@ dependencies:
geolocator: ^14.0.2
dropdown_search: ^6.0.2
google_maps_flutter: ^2.13.1
- flutter_zoom_videosdk: ^2.1.10
+ flutter_zoom_videosdk: 2.1.10
+ dart_jsonwebtoken: ^3.2.0
dartz: ^0.10.1
equatable: ^2.0.7
google_api_availability: ^5.0.1
@@ -79,6 +80,7 @@ dependencies:
path_provider: ^2.0.8
open_filex: ^4.7.0
flutter_swiper_view: ^1.1.8
+ flutter_callkit_incoming: ^3.0.0
location: ^8.0.1
gms_check: ^1.0.4
@@ -108,6 +110,7 @@ flutter:
- assets/images/png/body_parts/female/
- assets/images/svg/
- assets/images/png/
+ - assets/images/png/zoom/
- assets/animations/
- assets/animations/lottie/